diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index c60fb6f0b..d7f9b23f9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -163,7 +163,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener { } // for mod - @EventHandler + @EventHandler(priority = EventPriority.LOWEST) public void onPlayerRegisterChannel(PlayerRegisterChannelEvent event) { if (!event.getChannel().equals(MOD_CHANNEL)) return; Player player = event.getPlayer(); 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 04198be2a..db505bfef 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 @@ -2,24 +2,27 @@ package net.momirealms.craftengine.fabric.client; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +import net.fabricmc.loader.api.FabricLoader; import net.minecraft.block.Block; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.color.world.BiomeColors; -import net.minecraft.client.gui.screen.DisconnectedScreen; +import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.render.RenderLayer; +import net.minecraft.network.DisconnectionInfo; import net.minecraft.registry.Registries; import net.minecraft.text.Text; import net.minecraft.util.Identifier; -import net.minecraft.util.crash.CrashReport; import net.minecraft.world.biome.FoliageColors; import net.momirealms.craftengine.fabric.client.config.ModConfig; import net.momirealms.craftengine.fabric.client.network.CraftEnginePayload; +import java.net.URI; import java.nio.charset.StandardCharsets; +import java.util.Optional; public class CraftEngineFabricModClient implements ClientModInitializer { public static final String MOD_ID = "craftengine"; @@ -27,6 +30,12 @@ public class CraftEngineFabricModClient implements ClientModInitializer { @Override public void onInitializeClient() { PayloadTypeRegistry.playS2C().register(CraftEnginePayload.ID, CraftEnginePayload.CODEC); + initChannel(MinecraftClient.getInstance().getNetworkHandler()); + registerRenderLayer(); + ClientPlayConnectionEvents.INIT.register((handler, client) -> initChannel(handler)); + } + + public static void registerRenderLayer() { Registries.BLOCK.forEach(block -> { Identifier id = Registries.BLOCK.getId(block); if (id.getNamespace().equals(CraftEngineFabricModClient.MOD_ID)) { @@ -36,26 +45,6 @@ public class CraftEngineFabricModClient implements ClientModInitializer { } } }); - ClientTickEvents.START_CLIENT_TICK.register(client -> { - if (!ModConfig.enableNetwork) { - ClientPlayNetworking.unregisterGlobalReceiver(CraftEnginePayload.ID.id()); - return; - } - ClientPlayNetworking.registerGlobalReceiver(CraftEnginePayload.ID, (payload, context) -> { - byte[] data = payload.data(); - String decoded = new String(data, StandardCharsets.UTF_8); - if (decoded.startsWith("cp:")) { - int blockRegistrySize = Integer.parseInt(decoded.substring(3)); - if (Block.STATE_IDS.size() != blockRegistrySize) { - client.disconnect(new DisconnectedScreen( - client.currentScreen, - Text.translatable("disconnect.craftengine.title"), - Text.translatable("disconnect.craftengine.block_registry_mismatch", Block.STATE_IDS.size(), blockRegistrySize)) - ); - } - } - }); - }); } public static void registerColor(Block block) { @@ -69,4 +58,31 @@ public class CraftEngineFabricModClient implements ClientModInitializer { block ); } + + private static void initChannel(ClientPlayNetworkHandler handler) { + if (ModConfig.enableNetwork) { + registerChannel(handler); + } else { + ClientPlayNetworking.unregisterGlobalReceiver(CraftEnginePayload.ID.id()); + } + } + + private static void registerChannel(ClientPlayNetworkHandler handler) { + ClientPlayNetworking.registerGlobalReceiver(CraftEnginePayload.ID, (payload, context) -> { + byte[] data = payload.data(); + String decoded = new String(data, StandardCharsets.UTF_8); + if (decoded.startsWith("cp:")) { + int blockRegistrySize = Integer.parseInt(decoded.substring(3)); + if (Block.STATE_IDS.size() != blockRegistrySize) { + handler.getConnection().disconnect( + new DisconnectionInfo( + Text.translatable("disconnect.craftengine.block_registry_mismatch", Block.STATE_IDS.size(), blockRegistrySize), + Optional.of(FabricLoader.getInstance().getConfigDir().resolve("craft-engine-fabric-mod/mappings.yml")), + Optional.of(URI.create("https://github.com/Xiao-MoMi/craft-engine")) + ) + ); + } + } + }); + } } 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 b8b27ff44..eb8e5add2 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 @@ -6,8 +6,8 @@ import net.minecraft.network.packet.CustomPayload; import net.minecraft.util.Identifier; public record CraftEnginePayload(byte[] data) implements CustomPayload { - public static final Identifier ADD_CRAFTENGINE_BLOCK = Identifier.of("craftengine", "payload"); - public static final Id ID = new Id<>(CraftEnginePayload.ADD_CRAFTENGINE_BLOCK); + 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.tuple( new ByteArrayCodec(), CraftEnginePayload::data, CraftEnginePayload::new 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 1b599bc5d..c83839921 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 @@ -4,6 +4,8 @@ import net.fabricmc.api.ModInitializer; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.block.BlockState; import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.shape.VoxelShape; import net.momirealms.craftengine.fabric.client.config.ModConfig; import net.momirealms.craftengine.fabric.util.BlockUtils; import net.momirealms.craftengine.fabric.util.LoggerFilter; @@ -37,7 +39,8 @@ public class CraftEngineFabricMod implements ModInitializer { BlockState blockState = YamlUtils.createBlockData("minecraft:" + replacedBlockId.getPath()); RegisterBlocks.register( replacedBlockId.getPath() + "_" + i, - BlockUtils.canPassThrough(blockState) + BlockUtils.canPassThrough(blockState), + BlockUtils.getShape(blockState) ); } } diff --git a/client-mod/src/main/java/net/momirealms/craftengine/fabric/util/BlockUtils.java b/client-mod/src/main/java/net/momirealms/craftengine/fabric/util/BlockUtils.java index 3dc205eae..70b6ee011 100644 --- a/client-mod/src/main/java/net/momirealms/craftengine/fabric/util/BlockUtils.java +++ b/client-mod/src/main/java/net/momirealms/craftengine/fabric/util/BlockUtils.java @@ -1,7 +1,12 @@ package net.momirealms.craftengine.fabric.util; import net.minecraft.block.AbstractBlock; +import net.minecraft.block.Block; import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.util.shape.VoxelShapes; +import net.minecraft.world.BlockView; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -43,4 +48,20 @@ public class BlockUtils { throw new RuntimeException("Failed to access 'collidable' field", e); } } + + + public static VoxelShape getShape(BlockState state) { + if (state == null) return VoxelShapes.fullCube(); + Block block = state.getBlock(); + VoxelShape combinedShape = VoxelShapes.empty(); + try { + for (BlockState possibleState : block.getStateManager().getStates()) { + VoxelShape currentShape = possibleState.getOutlineShape(null, BlockPos.ORIGIN); + combinedShape = VoxelShapes.union(combinedShape, currentShape); + } + return combinedShape.isEmpty() ? VoxelShapes.fullCube() : combinedShape; + } catch (Throwable ignored) { + return VoxelShapes.fullCube(); + } + } } diff --git a/client-mod/src/main/java/net/momirealms/craftengine/fabric/util/RegisterBlocks.java b/client-mod/src/main/java/net/momirealms/craftengine/fabric/util/RegisterBlocks.java index f53152557..33234b3aa 100644 --- a/client-mod/src/main/java/net/momirealms/craftengine/fabric/util/RegisterBlocks.java +++ b/client-mod/src/main/java/net/momirealms/craftengine/fabric/util/RegisterBlocks.java @@ -2,21 +2,33 @@ package net.momirealms.craftengine.fabric.util; import net.minecraft.block.AbstractBlock; import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.ShapeContext; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryKeys; import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.util.shape.VoxelShapes; +import net.minecraft.world.BlockView; import net.momirealms.craftengine.fabric.CraftEngineFabricMod; import java.util.function.Function; public class RegisterBlocks { @SuppressWarnings("UnusedReturnValue") - public static Block register(String name, boolean canPassThrough) { + public static Block register(String name, boolean canPassThrough, VoxelShape outlineShape) { AbstractBlock.Settings settings = Block.Settings.create().nonOpaque().strength(-1.0F, 3600000.0F); - if (canPassThrough) settings.noCollision(); - return register(name, Block::new, settings); + VoxelShape collisionShape; + if (canPassThrough) { + collisionShape = VoxelShapes.empty(); + settings.noCollision(); + } else { + collisionShape = outlineShape; + } + return register(name, (settingsParam) -> new CustomBlock(settingsParam, outlineShape, collisionShape), settings); } public static Block register(String name, Function blockFactory, AbstractBlock.Settings settings) { @@ -31,3 +43,24 @@ public class RegisterBlocks { } } + +class CustomBlock extends Block { + private final VoxelShape outlineShape; + private final VoxelShape collisionShape; + + public CustomBlock(Settings settings, VoxelShape outlineShape, VoxelShape collisionShape) { + super(settings); + this.outlineShape = outlineShape; + this.collisionShape = collisionShape; + } + + @Override + public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + return this.outlineShape; + } + + @Override + public VoxelShape getCollisionShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + return this.collisionShape; + } +} 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 56313e2df..711d5c3ca 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 @@ -3,6 +3,5 @@ "category.craftengine.general": "General", "option.craftengine.enable_network": "Enable custom blocks in server", "tooltip.craftengine.enable_network": "Changes requires re-entering the server to take effect", - "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.", - "disconnect.craftengine.title": "CraftEngine Connection Error" + "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 4dd4bbc4e..c16c77c9d 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 @@ -3,6 +3,5 @@ "category.craftengine.general": "通用", "option.craftengine.enable_network": "启用服务器内自定义方块", "tooltip.craftengine.enable_network": "需要重新进入服务器以应用更改", - "disconnect.craftengine.block_registry_mismatch": "方块注册表大小不匹配. 当前: %s. 预期: %s \n 1. 确保客户端mod配置与服务端配置一致. \n 2. 不要安装任何会注册新方块的mod. \n 3. 不要使用ViaVersion.", - "disconnect.craftengine.title": "CraftEngine连接错误" + "disconnect.craftengine.block_registry_mismatch": "方块注册表大小不匹配. 当前: %s. 预期: %s \n 1. 确保客户端mod配置与服务端配置一致. \n 2. 不要安装任何会注册新方块的mod. \n 3. 不要使用ViaVersion." } \ No newline at end of file