diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index c35ecd914..755a10375 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -1962,28 +1962,48 @@ public class PacketConsumers { data = (byte[]) Reflections.method$DiscardedPayload$dataByteArray.invoke(payload); } String decodeData = new String(data, StandardCharsets.UTF_8); - if (!decodeData.endsWith("init")) return; - int firstColon = decodeData.indexOf(':'); - if (firstColon == -1) return; - int secondColon = decodeData.indexOf(':', firstColon + 1); - if (secondColon == -1) return; - int clientBlockRegistrySize = Integer.parseInt(decodeData.substring(firstColon + 1, secondColon)); - int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); - if (clientBlockRegistrySize != serverBlockRegistrySize) { - Object kickPacket = Reflections.constructor$ClientboundDisconnectPacket.newInstance( - ComponentUtils.adventureToMinecraft( - Component.translatable( - "disconnect.craftengine.block_registry_mismatch", - TranslationArgument.numeric(clientBlockRegistrySize), - TranslationArgument.numeric(serverBlockRegistrySize) - ) - ) - ); - user.nettyChannel().writeAndFlush(kickPacket); - user.nettyChannel().disconnect(); - return; + if (decodeData.endsWith("init")) { + int firstColon = decodeData.indexOf(':'); + if (firstColon == -1) return; + int secondColon = decodeData.indexOf(':', firstColon + 1); + if (secondColon == -1) return; + String payloadData = decodeData.substring(firstColon + 1, secondColon); + int clientBlockRegistrySize = Integer.parseInt(payloadData); + int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize(); + if (clientBlockRegistrySize != serverBlockRegistrySize) { + Object kickPacket = Reflections.constructor$ClientboundDisconnectPacket.newInstance( + ComponentUtils.adventureToMinecraft( + Component.translatable( + "disconnect.craftengine.block_registry_mismatch", + TranslationArgument.numeric(clientBlockRegistrySize), + TranslationArgument.numeric(serverBlockRegistrySize) + ) + ) + ); + user.nettyChannel().writeAndFlush(kickPacket); + user.nettyChannel().disconnect(); + return; + } + user.setClientModState(true); + } else if (decodeData.endsWith("cancel")) { + if (!VersionHelper.isOrAbove1_20_2()) return; + int firstColon = decodeData.indexOf(':'); + if (firstColon == -1) return; + int secondColon = decodeData.indexOf(':', firstColon + 1); + if (secondColon == -1) return; + String payloadData = decodeData.substring(firstColon + 1, secondColon); + boolean cancel = Boolean.parseBoolean(payloadData); + if (cancel) { + user.nettyChannel().writeAndFlush( + Reflections.constructor$ClientboundCustomPayloadPacket.newInstance( + Reflections.constructor$DiscardedPayload.newInstance( + KeyUtils.toResourceLocation(Key.of(NetworkManager.MOD_CHANNEL)), + (":true:cancel").getBytes(StandardCharsets.UTF_8) + ) + ) + ); + } } - user.setClientModState(true); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundCustomPayloadPacket", e); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index b12714cee..679a26279 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -6659,4 +6659,20 @@ public class Reflections { "world.entity.projectile.AbstractArrow" ) ); + + public static final Class clazz$ClientboundCustomPayloadPacket = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + List.of("network.protocol.game.PacketPlayOutCustomPayload", "network.protocol.common.ClientboundCustomPayloadPacket"), + List.of("network.protocol.game.ClientboundCustomPayloadPacket", "network.protocol.common.ClientboundCustomPayloadPacket") + ) + ); + + public static final Constructor constructor$ClientboundCustomPayloadPacket = requireNonNull( + ReflectionUtils.getTheOnlyConstructor(clazz$ClientboundCustomPayloadPacket) + ); + + // 1.20.2+ + public static final Constructor constructor$DiscardedPayload = Optional.ofNullable(clazz$DiscardedPayload) + .map(clazz -> ReflectionUtils.getTheOnlyConstructor(clazz)) + .orElse(null); } diff --git a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/CraftEngineFabricModClient.java b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/CraftEngineFabricModClient.java index d3bdbf562..9dc5e6b27 100644 --- a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/CraftEngineFabricModClient.java +++ b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/CraftEngineFabricModClient.java @@ -1,9 +1,12 @@ package net.momirealms.craftengine.fabric.client; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.minecraft.block.Block; @@ -20,8 +23,10 @@ import net.momirealms.craftengine.fabric.client.network.CraftEnginePayload; import java.nio.charset.StandardCharsets; +@Environment(EnvType.CLIENT) public class CraftEngineFabricModClient implements ClientModInitializer { public static final String MOD_ID = "craftengine"; + public static boolean serverInstalled = false; @Override public void onInitializeClient() { @@ -29,6 +34,8 @@ public class CraftEngineFabricModClient implements ClientModInitializer { PayloadTypeRegistry.configurationC2S().register(CraftEnginePayload.ID, CraftEnginePayload.CODEC); registerRenderLayer(); ClientConfigurationConnectionEvents.START.register(CraftEngineFabricModClient::initChannel); + ClientConfigurationNetworking.registerGlobalReceiver(CraftEnginePayload.ID, CraftEngineFabricModClient::handleReceiver); + ClientPlayConnectionEvents.DISCONNECT.register((client, handler) -> serverInstalled = false); } public static void registerRenderLayer() { @@ -60,12 +67,32 @@ public class CraftEngineFabricModClient implements ClientModInitializer { private static void initChannel(ClientConfigurationNetworkHandler handler, MinecraftClient client) { if (ModConfig.enableNetwork) { registerChannel(handler); + } else if (ModConfig.enableCancelBlockUpdate) { + registerCancelBlockUpdateChannel(handler); } else { ClientConfigurationNetworking.unregisterGlobalReceiver(CraftEnginePayload.ID); } } + private static void handleReceiver(CraftEnginePayload payload, ClientConfigurationNetworking.Context context) { + byte[] data = payload.data(); + String decodeData = new String(data, StandardCharsets.UTF_8); + if (decodeData.endsWith("cancel")) { + int firstColon = decodeData.indexOf(':'); + if (firstColon == -1) return; + int secondColon = decodeData.indexOf(':', firstColon + 1); + if (secondColon == -1) return; + String payloadData = decodeData.substring(firstColon + 1, secondColon); + serverInstalled = Boolean.parseBoolean(payloadData); + } + } + private static void registerChannel(ClientConfigurationNetworkHandler handler) { ClientConfigurationNetworking.send(new CraftEnginePayload((":" + Block.STATE_IDS.size() + ":init").getBytes(StandardCharsets.UTF_8))); } + + private static void registerCancelBlockUpdateChannel(ClientConfigurationNetworkHandler handler) { + ClientConfigurationNetworking.send(new CraftEnginePayload((":true:cancel").getBytes(StandardCharsets.UTF_8))); + + } } diff --git a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/config/ModConfig.java b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/config/ModConfig.java index 6546896d6..6287d4e81 100644 --- a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/config/ModConfig.java +++ b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/config/ModConfig.java @@ -3,24 +3,35 @@ package net.momirealms.craftengine.fabric.client.config; import me.shedaniel.clothconfig2.api.ConfigBuilder; import me.shedaniel.clothconfig2.api.ConfigCategory; import me.shedaniel.clothconfig2.api.ConfigEntryBuilder; +import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.gui.screen.Screen; import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; + +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; public class ModConfig { + private static final Path CONFIG_PATH = FabricLoader.getInstance().getConfigDir().resolve("craft-engine-fabric-mod/config.yml"); public static boolean enableNetwork = true; + public static boolean enableCancelBlockUpdate = false; public static Screen getConfigScreen(Screen parent) { ConfigBuilder builder = ConfigBuilder.create() .setParentScreen(parent) + .setSavingRunnable(ModConfig::saveConfig) .setTitle(Text.translatable("title.craftengine.config")); ConfigCategory general = builder.getOrCreateCategory(Text.translatable("category.craftengine.general")); ConfigEntryBuilder entryBuilder = builder.entryBuilder(); general.addEntry(entryBuilder.startBooleanToggle( - Text.translatable("option.craftengine.enable_network") - .formatted(Formatting.WHITE), + Text.translatable("option.craftengine.enable_network") + .formatted(Formatting.WHITE), enableNetwork) .setDefaultValue(true) .setSaveConsumer(newValue -> enableNetwork = newValue) @@ -29,7 +40,32 @@ public class ModConfig { .formatted(Formatting.GRAY) ) .build()); + general.addEntry(entryBuilder.startBooleanToggle( + Text.translatable("option.craftengine.enable_cancel_block_update") + .formatted(Formatting.WHITE), + enableCancelBlockUpdate) + .setDefaultValue(false) + .setSaveConsumer(newValue -> enableCancelBlockUpdate = newValue) + .setTooltip( + Text.translatable("tooltip.craftengine.enable_cancel_block_update") + ) + .build() + ); return builder.build(); } + + private static void saveConfig() { + DumperOptions options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + Yaml yaml = new Yaml(options); + var data = new java.util.HashMap(); + data.put("enable-network", ModConfig.enableNetwork); + data.put("enable-cancel-block-update", ModConfig.enableCancelBlockUpdate); + try (Writer writer = Files.newBufferedWriter(CONFIG_PATH)) { + yaml.dump(data, writer); + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/network/CraftEnginePayload.java b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/network/CraftEnginePayload.java index c975c1f7f..f55495fea 100644 --- a/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/network/CraftEnginePayload.java +++ b/client-mod/src/client/java/net/momirealms/craftengine/fabric/client/network/CraftEnginePayload.java @@ -9,8 +9,13 @@ public record CraftEnginePayload(byte[] data) implements CustomPayload { public static final Identifier CRAFTENGINE_PAYLOAD = Identifier.of("craftengine", "payload"); public static final Id ID = new Id<>(CraftEnginePayload.CRAFTENGINE_PAYLOAD); public static final PacketCodec CODEC = PacketCodec.of( - (payload, byteBuf) -> byteBuf.writeByteArray(payload.data()), - buf -> new CraftEnginePayload(buf.readByteArray())); + (payload, byteBuf) -> byteBuf.writeBytes(payload.data()), + buf -> { + int i = buf.readableBytes(); + byte[] data = new byte[i]; + buf.readBytes(data); + return new CraftEnginePayload(data); + }); @Override public Id getId() { diff --git a/client-mod/src/main/java/net/momirealms/craftengine/fabric/CraftEngineFabricMod.java b/client-mod/src/main/java/net/momirealms/craftengine/fabric/CraftEngineFabricMod.java index 90a2b995d..faf3c8e0e 100644 --- a/client-mod/src/main/java/net/momirealms/craftengine/fabric/CraftEngineFabricMod.java +++ b/client-mod/src/main/java/net/momirealms/craftengine/fabric/CraftEngineFabricMod.java @@ -1,5 +1,7 @@ package net.momirealms.craftengine.fabric; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.fabricmc.api.ModInitializer; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.block.BlockState; @@ -9,16 +11,15 @@ import net.momirealms.craftengine.fabric.util.BlockUtils; import net.momirealms.craftengine.fabric.util.LoggerFilter; import net.momirealms.craftengine.fabric.util.RegisterBlocks; import net.momirealms.craftengine.fabric.util.YamlUtils; -import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; import java.io.IOException; import java.io.InputStream; -import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; +@Environment(EnvType.CLIENT) public class CraftEngineFabricMod implements ModInitializer { private static final Path CONFIG_PATH = FabricLoader.getInstance().getConfigDir().resolve("craft-engine-fabric-mod/config.yml"); public static final String MOD_ID = "craftengine"; @@ -47,32 +48,25 @@ public class CraftEngineFabricMod implements ModInitializer { } catch (IOException e) { e.printStackTrace(); } - Runtime.getRuntime().addShutdownHook(new Thread(this::saveConfig)); } @SuppressWarnings("unchecked") private void loadConfig() { if (!Files.exists(CONFIG_PATH)) { ModConfig.enableNetwork = true; + ModConfig.enableCancelBlockUpdate = false; return; } try (InputStream inputStream = Files.newInputStream(CONFIG_PATH)) { Yaml yaml = new Yaml(); var config = yaml.loadAs(inputStream, java.util.Map.class); + if (config == null) { + ModConfig.enableNetwork = true; + ModConfig.enableCancelBlockUpdate = false; + return; + } ModConfig.enableNetwork = (Boolean) config.getOrDefault("enable-network", true); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private void saveConfig() { - DumperOptions options = new DumperOptions(); - options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); - Yaml yaml = new Yaml(options); - var data = new java.util.HashMap(); - data.put("enable-network", ModConfig.enableNetwork); - try (Writer writer = Files.newBufferedWriter(CONFIG_PATH)) { - yaml.dump(data, writer); + ModConfig.enableCancelBlockUpdate = (Boolean) config.getOrDefault("enable-cancel-block-update", false); } catch (IOException e) { e.printStackTrace(); } diff --git a/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/AbstractBlockStateMixin.java b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/AbstractBlockStateMixin.java new file mode 100644 index 000000000..014869e0f --- /dev/null +++ b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/AbstractBlockStateMixin.java @@ -0,0 +1,65 @@ +package net.momirealms.craftengine.fabric.mixin; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.block.AbstractBlock; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.World; +import net.minecraft.world.WorldAccess; +import net.minecraft.world.WorldView; +import net.minecraft.world.block.WireOrientation; +import net.minecraft.world.tick.ScheduledTickView; +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; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import static net.momirealms.craftengine.fabric.client.CraftEngineFabricModClient.serverInstalled; +import static net.momirealms.craftengine.fabric.client.config.ModConfig.enableCancelBlockUpdate; + +@Environment(EnvType.CLIENT) +@Mixin(AbstractBlock.AbstractBlockState.class) +public abstract class AbstractBlockStateMixin { + + @Inject(method = "getStateForNeighborUpdate", at = @At("HEAD"), cancellable = true) + private void cancelGetStateForNeighborUpdate(WorldView world, ScheduledTickView tickView, BlockPos pos, Direction direction, BlockPos neighborPos, BlockState neighborState, Random random, CallbackInfoReturnable cir) { + if (!enableCancelBlockUpdate || !serverInstalled) return; + cir.setReturnValue(this); + } + + @Inject(method = "neighborUpdate", at = @At("HEAD"), cancellable = true) + private void cancelNeighborUpdate(World world, BlockPos pos, Block sourceBlock, WireOrientation wireOrientation, boolean notify, CallbackInfo ci) { + if (!enableCancelBlockUpdate || !serverInstalled) return; + ci.cancel(); + } + + @Inject(method = "updateNeighbors*", at = @At("HEAD"), cancellable = true) + private void cancelUpdateNeighbors(WorldAccess world, BlockPos pos, int flags, CallbackInfo ci) { + if (!enableCancelBlockUpdate || !serverInstalled) return; + ci.cancel(); + } + + @Inject(method = "scheduledTick", at = @At("HEAD"), cancellable = true) + private void cancelScheduledTick(ServerWorld world, BlockPos pos, Random random, CallbackInfo ci) { + if (!enableCancelBlockUpdate || !serverInstalled) return; + ci.cancel(); + } + + @Inject(method = "canPlaceAt", at = @At("HEAD"), cancellable = true) + private void passCanPlaceAt(WorldView world, BlockPos pos, CallbackInfoReturnable cir) { + if (!enableCancelBlockUpdate || !serverInstalled) return; + cir.setReturnValue(true); + } + + @Inject(method = "randomTick", at = @At("HEAD"), cancellable = true) + private void cancelRandomTick(ServerWorld world, BlockPos pos, Random random, CallbackInfo ci) { + if (!enableCancelBlockUpdate || !serverInstalled) return; + ci.cancel(); + } +} diff --git a/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/AbstractRailBlockMixin.java b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/AbstractRailBlockMixin.java new file mode 100644 index 000000000..1699baa52 --- /dev/null +++ b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/AbstractRailBlockMixin.java @@ -0,0 +1,26 @@ +package net.momirealms.craftengine.fabric.mixin; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.block.AbstractRailBlock; +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +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; + +import static net.momirealms.craftengine.fabric.client.CraftEngineFabricModClient.serverInstalled; +import static net.momirealms.craftengine.fabric.client.config.ModConfig.enableCancelBlockUpdate; + +@Environment(EnvType.CLIENT) +@Mixin(AbstractRailBlock.class) +public abstract class AbstractRailBlockMixin { + + @Inject(method = "updateCurves", at = @At("HEAD"), cancellable = true) + private void cancelUpdateCurves(BlockState state, World world, BlockPos pos, boolean notify, CallbackInfoReturnable cir) { + if (!enableCancelBlockUpdate || !serverInstalled) return; + cir.setReturnValue(state); + } +} diff --git a/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/BlockItemMixin.java b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/BlockItemMixin.java new file mode 100644 index 000000000..ba4c89546 --- /dev/null +++ b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/BlockItemMixin.java @@ -0,0 +1,27 @@ +package net.momirealms.craftengine.fabric.mixin; + +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.NbtComponent; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +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(BlockItem.class) +public class BlockItemMixin { + + @Inject(method = "place*", at = @At("HEAD"), cancellable = true) + private void onPlace(ItemPlacementContext context, CallbackInfoReturnable cir) { + ItemStack stack = context.getStack(); + NbtComponent customData = stack.getComponents().get(DataComponentTypes.CUSTOM_DATA); + if (customData == null) return; + if (customData.contains("craftengine:id")) { + cir.setReturnValue(ActionResult.FAIL); + cir.cancel(); + } + } +} diff --git a/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/FluidStateMixin.java b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/FluidStateMixin.java new file mode 100644 index 000000000..695c89085 --- /dev/null +++ b/client-mod/src/main/java/net/momirealms/craftengine/fabric/mixin/FluidStateMixin.java @@ -0,0 +1,26 @@ +package net.momirealms.craftengine.fabric.mixin; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.block.BlockState; +import net.minecraft.fluid.FluidState; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +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; + +import static net.momirealms.craftengine.fabric.client.CraftEngineFabricModClient.serverInstalled; +import static net.momirealms.craftengine.fabric.client.config.ModConfig.enableCancelBlockUpdate; + +@Environment(EnvType.CLIENT) +@Mixin(FluidState.class) +public class FluidStateMixin { + + @Inject(method = "onScheduledTick", at = @At("HEAD"), cancellable = true) + private void cancelScheduledTick(ServerWorld world, BlockPos pos, BlockState state, CallbackInfo ci) { + if (!enableCancelBlockUpdate || !serverInstalled) return; + ci.cancel(); + } +} diff --git a/client-mod/src/main/resources/assets/craft-engine-fabric-mod/lang/en_us.json b/client-mod/src/main/resources/assets/craft-engine-fabric-mod/lang/en_us.json index 711d5c3ca..2eb9b4deb 100644 --- a/client-mod/src/main/resources/assets/craft-engine-fabric-mod/lang/en_us.json +++ b/client-mod/src/main/resources/assets/craft-engine-fabric-mod/lang/en_us.json @@ -2,6 +2,8 @@ "title.craftengine.config": "CraftEngine Settings", "category.craftengine.general": "General", "option.craftengine.enable_network": "Enable custom blocks in server", + "option.craftengine.enable_cancel_block_update": "Enable cancelling block updates in the server", "tooltip.craftengine.enable_network": "Changes requires re-entering the server to take effect", + "tooltip.craftengine.enable_cancel_block_update": "Only works on servers with CraftEngine installed.", "disconnect.craftengine.block_registry_mismatch": "Block registry size mismatch. Current: %s. Expected: %s. \n 1. Make sure that the configs are the same as the server's. \n 2. Do not use any mod that might register new block. \n 3. Do not install ViaVersion." } \ No newline at end of file diff --git a/client-mod/src/main/resources/assets/craft-engine-fabric-mod/lang/zh_cn.json b/client-mod/src/main/resources/assets/craft-engine-fabric-mod/lang/zh_cn.json index c16c77c9d..e65e46887 100644 --- a/client-mod/src/main/resources/assets/craft-engine-fabric-mod/lang/zh_cn.json +++ b/client-mod/src/main/resources/assets/craft-engine-fabric-mod/lang/zh_cn.json @@ -2,6 +2,8 @@ "title.craftengine.config": "CraftEngine设置", "category.craftengine.general": "通用", "option.craftengine.enable_network": "启用服务器内自定义方块", + "option.craftengine.enable_cancel_block_update": "启用服务器内取消方块更新", "tooltip.craftengine.enable_network": "需要重新进入服务器以应用更改", + "tooltip.craftengine.enable_cancel_block_update": "仅在安装了CraftEngine的服务器内生效", "disconnect.craftengine.block_registry_mismatch": "方块注册表大小不匹配. 当前: %s. 预期: %s \n 1. 确保客户端mod配置与服务端配置一致. \n 2. 不要安装任何会注册新方块的mod. \n 3. 不要使用ViaVersion." } \ No newline at end of file diff --git a/client-mod/src/main/resources/craftengine.mixins.json b/client-mod/src/main/resources/craftengine.mixins.json new file mode 100644 index 000000000..be9dbe408 --- /dev/null +++ b/client-mod/src/main/resources/craftengine.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "package": "net.momirealms.craftengine.fabric.mixin", + "compatibilityLevel": "JAVA_21", + "mixins": [ + "AbstractBlockStateMixin", + "AbstractRailBlockMixin", + "BlockItemMixin", + "FluidStateMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/client-mod/src/main/resources/fabric.mod.json b/client-mod/src/main/resources/fabric.mod.json index fc6261618..785f8ed0d 100644 --- a/client-mod/src/main/resources/fabric.mod.json +++ b/client-mod/src/main/resources/fabric.mod.json @@ -24,6 +24,10 @@ "modmenu": ["net.momirealms.craftengine.fabric.client.config.ModMenuIntegration"] }, + "mixins": [ + "craftengine.mixins.json" + ], + "depends": { "fabricloader": ">=${loader_version}", "fabric": "*",