diff --git a/gradle.properties b/gradle.properties index 8c18db7..effc8c3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,7 +17,7 @@ authors=jaskarth, unascribed contributors=Patbox, IThundxr license=AGPL-3.0-or-later # Mod Version -baseVersion=0.6.1 +baseVersion=0.6.2 # Branch Metadata branch=1.21 tagBranch=1.21 diff --git a/src/main/java/net/modfest/fireblanket/Fireblanket.java b/src/main/java/net/modfest/fireblanket/Fireblanket.java index 221d639..f22b4a2 100644 --- a/src/main/java/net/modfest/fireblanket/Fireblanket.java +++ b/src/main/java/net/modfest/fireblanket/Fireblanket.java @@ -7,8 +7,9 @@ import net.fabricmc.fabric.api.entity.event.v1.ServerEntityWorldChangeEvents; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents; -import net.fabricmc.fabric.api.event.player.UseBlockCallback; import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback; +import net.fabricmc.fabric.api.gamerule.v1.GameRuleFactory; +import net.fabricmc.fabric.api.gamerule.v1.GameRuleRegistry; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerLoginConnectionEvents; @@ -28,6 +29,7 @@ import net.minecraft.server.world.ServerWorld; import net.minecraft.util.Identifier; import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.GameRules; import net.modfest.fireblanket.command.CmdFindReplaceCommand; import net.modfest.fireblanket.command.DumpCommand; import net.modfest.fireblanket.command.RegionCommand; @@ -49,9 +51,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -61,6 +60,13 @@ public class Fireblanket implements ModInitializer { public static final Identifier FULL_STREAM_COMPRESSION = Identifier.of("fireblanket", "full_stream_compression"); public static final Identifier REGIONS_UPDATE = Identifier.of("fireblanket", "regions_update"); + /** + * Whether new entities will be fixed. + * @see net.modfest.fireblanket.mixin.entity_immutability + */ + public static final GameRules.Key NEW_ENTITIES_IMMUTABLE = + GameRuleRegistry.register("newEntitiesImmutable", GameRules.Category.MOBS, GameRuleFactory.createBooleanRule(true)); + public static final Logger LOGGER = LoggerFactory.getLogger("Fireblanket"); public record QueuedPacket(ClientConnection conn, Packet packet, PacketCallbacks listener) { diff --git a/src/main/java/net/modfest/fireblanket/mixin/accessor/ArmorStandEntityAccessor.java b/src/main/java/net/modfest/fireblanket/mixin/accessor/ArmorStandEntityAccessor.java new file mode 100644 index 0000000..a5fe3fd --- /dev/null +++ b/src/main/java/net/modfest/fireblanket/mixin/accessor/ArmorStandEntityAccessor.java @@ -0,0 +1,11 @@ +package net.modfest.fireblanket.mixin.accessor; + +import net.minecraft.entity.decoration.ArmorStandEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ArmorStandEntity.class) +public interface ArmorStandEntityAccessor { + @Accessor + void setDisabledSlots(int d); +} diff --git a/src/main/java/net/modfest/fireblanket/mixin/accessor/ItemFrameAccessor.java b/src/main/java/net/modfest/fireblanket/mixin/accessor/ItemFrameAccessor.java new file mode 100644 index 0000000..c8c8c80 --- /dev/null +++ b/src/main/java/net/modfest/fireblanket/mixin/accessor/ItemFrameAccessor.java @@ -0,0 +1,11 @@ +package net.modfest.fireblanket.mixin.accessor; + +import net.minecraft.entity.decoration.ItemFrameEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ItemFrameEntity.class) +public interface ItemFrameAccessor { + @Accessor + void setFixed(boolean v); +} diff --git a/src/main/java/net/modfest/fireblanket/mixin/adventure_fix/MixinFarmlandBlock.java b/src/main/java/net/modfest/fireblanket/mixin/adventure_fix/MixinFarmlandBlock.java new file mode 100644 index 0000000..01c915e --- /dev/null +++ b/src/main/java/net/modfest/fireblanket/mixin/adventure_fix/MixinFarmlandBlock.java @@ -0,0 +1,27 @@ +package net.modfest.fireblanket.mixin.adventure_fix; + +import net.minecraft.block.BlockState; +import net.minecraft.block.FarmlandBlock; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(FarmlandBlock.class) +public class MixinFarmlandBlock { + @Inject( + method = "setToDirt", + at = @At("HEAD"), + cancellable = true + ) + private static void doNotSetToDirt(@Nullable Entity entity, BlockState state, World world, BlockPos pos, CallbackInfo ci) { + if (entity instanceof PlayerEntity player && !player.canModifyBlocks()) { + ci.cancel(); + } + } +} diff --git a/src/main/java/net/modfest/fireblanket/mixin/entity_immutability/MixinDecorationItem.java b/src/main/java/net/modfest/fireblanket/mixin/entity_immutability/MixinDecorationItem.java new file mode 100644 index 0000000..4a98789 --- /dev/null +++ b/src/main/java/net/modfest/fireblanket/mixin/entity_immutability/MixinDecorationItem.java @@ -0,0 +1,23 @@ +package net.modfest.fireblanket.mixin.entity_immutability; + +import com.llamalad7.mixinextras.sugar.Local; +import net.minecraft.entity.decoration.AbstractDecorationEntity; +import net.minecraft.item.DecorationItem; +import net.minecraft.item.ItemUsageContext; +import net.minecraft.util.ActionResult; +import net.modfest.fireblanket.Fireblanket; +import net.modfest.fireblanket.util.ImmutableEntities; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(DecorationItem.class) +public class MixinDecorationItem { + @Inject(method = "useOnBlock(Lnet/minecraft/item/ItemUsageContext;)Lnet/minecraft/util/ActionResult;", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getOrDefault(Lnet/minecraft/component/ComponentType;Ljava/lang/Object;)Ljava/lang/Object;")) + private void onInitSpawnedEntity(ItemUsageContext context, CallbackInfoReturnable cir, @Local AbstractDecorationEntity entity) { + if (context.getWorld().getGameRules().getBoolean(Fireblanket.NEW_ENTITIES_IMMUTABLE)) { + ImmutableEntities.makeImmutable(entity); + } + } +} diff --git a/src/main/java/net/modfest/fireblanket/mixin/entity_immutability/MixinEntityType.java b/src/main/java/net/modfest/fireblanket/mixin/entity_immutability/MixinEntityType.java new file mode 100644 index 0000000..301f7b3 --- /dev/null +++ b/src/main/java/net/modfest/fireblanket/mixin/entity_immutability/MixinEntityType.java @@ -0,0 +1,31 @@ +package net.modfest.fireblanket.mixin.entity_immutability; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.SpawnReason; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.modfest.fireblanket.Fireblanket; +import net.modfest.fireblanket.util.ImmutableEntities; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import java.util.function.Consumer; + +@Mixin(EntityType.class) +public class MixinEntityType { + @WrapOperation(method = "create(Lnet/minecraft/server/world/ServerWorld;Ljava/util/function/Consumer;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/entity/SpawnReason;ZZ)Lnet/minecraft/entity/Entity;", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/EntityType;create(Lnet/minecraft/world/World;)Lnet/minecraft/entity/Entity;")) + private Entity afterCreated(EntityType instance, World world, Operation original, ServerWorld world2, @Nullable Consumer afterConsumer, BlockPos pos, SpawnReason reason, boolean alignPosition, boolean invertY) { + var entity = original.call(instance, world); + if (world.getGameRules().getBoolean(Fireblanket.NEW_ENTITIES_IMMUTABLE) && reason == SpawnReason.SPAWN_EGG) { + if (entity != null) { + ImmutableEntities.makeImmutable(entity); + } + } + return entity; + } +} diff --git a/src/main/java/net/modfest/fireblanket/util/ImmutableEntities.java b/src/main/java/net/modfest/fireblanket/util/ImmutableEntities.java new file mode 100644 index 0000000..b2cf27d --- /dev/null +++ b/src/main/java/net/modfest/fireblanket/util/ImmutableEntities.java @@ -0,0 +1,27 @@ +package net.modfest.fireblanket.util; + +import net.minecraft.entity.Entity; +import net.modfest.fireblanket.mixin.accessor.ArmorStandEntityAccessor; +import net.modfest.fireblanket.mixin.accessor.ItemFrameAccessor; +import net.modfest.fireblanket.mixinsupport.ImmmovableLivingEntity; + +public class ImmutableEntities { + public static void makeImmutable(Entity entity) { + // Set invulnerability + entity.setInvulnerable(true); + + if (entity instanceof ArmorStandEntityAccessor ae) { + // Disable all slots + ae.setDisabledSlots(4144959); + // Disable movement (prevents abuse of fishing rods) + if (entity instanceof ImmmovableLivingEntity im) { + im.setNoMovement(true); + } + } + + if (entity instanceof ItemFrameAccessor ie) { + // Make item frames fixed + ie.setFixed(true); + } + } +} diff --git a/src/main/resources/assets/fireblanket/lang/en_us.json b/src/main/resources/assets/fireblanket/lang/en_us.json index 861f722..b15e4a4 100644 --- a/src/main/resources/assets/fireblanket/lang/en_us.json +++ b/src/main/resources/assets/fireblanket/lang/en_us.json @@ -1,4 +1,5 @@ { "argument.entity.selector.limit.unforced": "Targeting too many entities with no distance filter; add `force=true` to the selector to bypass", - "argument.entity.options.force.description": "Force-allow more than 50 entities targeted with no distance filter" -} \ No newline at end of file + "argument.entity.options.force.description": "Force-allow more than 50 entities targeted with no distance filter", + "gamerule.newEntitiesImmutable": "Whether newly spawned entities should be immutable. (Item frames will be fixed for example" +} diff --git a/src/main/resources/fireblanket.mixins.json b/src/main/resources/fireblanket.mixins.json index 822e8aa..6c8f2ed 100644 --- a/src/main/resources/fireblanket.mixins.json +++ b/src/main/resources/fireblanket.mixins.json @@ -4,26 +4,30 @@ "compatibilityLevel": "JAVA_17", "plugin": "net.modfest.fireblanket.FireblanketMixin", "mixins": [ + "accessor.ArmorStandEntityAccessor", "accessor.BlockEntityTypeAccessor", "accessor.ClientConnectionAccessor", "accessor.EntityTypeAccessor", + "accessor.ItemFrameAccessor", "accessor.ServerChunkManagerAccessor", "accessor.ServerLoginNetworkHandlerAccessor", - "adventure_fix.MixinItemStack", + "adventure_fix.MixinItemStack", "adventure_fix.MixinPlayerInteractEntityC2SPacketHandler", "adventure_fix.MixinServerPlayerInteractionManager", + "adventure_fix.MixinFarmlandBlock", "ai.MixinTemptGoal", "be_sync.MixinBlockEntity", "be_sync.MixinChunkHolder", "block.MixinCommandBlock", "block_format.MixinChunkSection", + "entity_immutability.MixinDecorationItem", + "entity_immutability.MixinEntityType", "entity_ticking.MixinDebugStickItem", "entity_ticking.MixinEntity", "entity_ticking.MixinItemGroups", "entity_ticking.MixinLivingEntity", "entity_ticking.MixinMinecraftServer", "entity_ticking.MixinServerChunkLoadingManager", - "mods.create.MixinSuperGlueEntity", "footgun.MixinEntitySelectorOptions", "footgun.MixinEntitySelectorReader", "fsc.MixinClientConnection", @@ -32,6 +36,7 @@ "io_uring.MixinServerNetworkIo", "mods.create.AccessorSmartBlockEntity", "mods.create.MixinMechanicalBearingBlockEntity", + "mods.create.MixinSuperGlueEntity", "mods.mythicmetals.MixinCarmotShield", "mods.pehkui.MixinScaleUtils", "mods.pswg.MixinComplexCollisionManager", @@ -61,7 +66,6 @@ "client.adventure_fix.MixinClientPlayerInteractionManager", "client.be_masking.MixinBlockEntityRenderDispatcher", "client.be_masking.MixinRebuildTask", - "mods.masking.sodium.MixinChunkRenderRebuildTask", "client.bufferbuilder_opto.MixinBufferBuilder", "client.bufferbuilder_opto.MixinVertexFormat", "client.entity_masking.MixinEntityRenderer", @@ -79,6 +83,7 @@ "client.vbo_opto.MixinShaderProgram", "client.vbo_opto.MixinVertexBuffer", "gamemode_selection.MixinKeyboard", - "gamemode_selection.MixinSelectionScreen" + "gamemode_selection.MixinSelectionScreen", + "mods.masking.sodium.MixinChunkRenderRebuildTask" ] }