9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00
This commit is contained in:
XiaoMoMi
2025-03-25 16:57:52 +08:00
8 changed files with 105 additions and 34 deletions

View File

@@ -163,7 +163,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener {
} }
// for mod // for mod
@EventHandler @EventHandler(priority = EventPriority.LOWEST)
public void onPlayerRegisterChannel(PlayerRegisterChannelEvent event) { public void onPlayerRegisterChannel(PlayerRegisterChannelEvent event) {
if (!event.getChannel().equals(MOD_CHANNEL)) return; if (!event.getChannel().equals(MOD_CHANNEL)) return;
Player player = event.getPlayer(); Player player = event.getPlayer();

View File

@@ -2,24 +2,27 @@ package net.momirealms.craftengine.fabric.client;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; 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.ClientPlayConnectionEvents;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry;
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.color.world.BiomeColors; 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.client.render.RenderLayer;
import net.minecraft.network.DisconnectionInfo;
import net.minecraft.registry.Registries; import net.minecraft.registry.Registries;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.crash.CrashReport;
import net.minecraft.world.biome.FoliageColors; import net.minecraft.world.biome.FoliageColors;
import net.momirealms.craftengine.fabric.client.config.ModConfig; import net.momirealms.craftengine.fabric.client.config.ModConfig;
import net.momirealms.craftengine.fabric.client.network.CraftEnginePayload; import net.momirealms.craftengine.fabric.client.network.CraftEnginePayload;
import java.net.URI;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Optional;
public class CraftEngineFabricModClient implements ClientModInitializer { public class CraftEngineFabricModClient implements ClientModInitializer {
public static final String MOD_ID = "craftengine"; public static final String MOD_ID = "craftengine";
@@ -27,6 +30,12 @@ public class CraftEngineFabricModClient implements ClientModInitializer {
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
PayloadTypeRegistry.playS2C().register(CraftEnginePayload.ID, CraftEnginePayload.CODEC); 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 -> { Registries.BLOCK.forEach(block -> {
Identifier id = Registries.BLOCK.getId(block); Identifier id = Registries.BLOCK.getId(block);
if (id.getNamespace().equals(CraftEngineFabricModClient.MOD_ID)) { 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) { public static void registerColor(Block block) {
@@ -69,4 +58,31 @@ public class CraftEngineFabricModClient implements ClientModInitializer {
block 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"))
)
);
}
}
});
}
} }

View File

@@ -6,8 +6,8 @@ import net.minecraft.network.packet.CustomPayload;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public record CraftEnginePayload(byte[] data) implements CustomPayload { public record CraftEnginePayload(byte[] data) implements CustomPayload {
public static final Identifier ADD_CRAFTENGINE_BLOCK = Identifier.of("craftengine", "payload"); public static final Identifier CRAFTENGINE_PAYLOAD = Identifier.of("craftengine", "payload");
public static final Id<CraftEnginePayload> ID = new Id<>(CraftEnginePayload.ADD_CRAFTENGINE_BLOCK); public static final Id<CraftEnginePayload> ID = new Id<>(CraftEnginePayload.CRAFTENGINE_PAYLOAD);
public static final PacketCodec<RegistryByteBuf, CraftEnginePayload> CODEC = PacketCodec.tuple( public static final PacketCodec<RegistryByteBuf, CraftEnginePayload> CODEC = PacketCodec.tuple(
new ByteArrayCodec(), CraftEnginePayload::data, new ByteArrayCodec(), CraftEnginePayload::data,
CraftEnginePayload::new CraftEnginePayload::new

View File

@@ -4,6 +4,8 @@ import net.fabricmc.api.ModInitializer;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.util.Identifier; 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.client.config.ModConfig;
import net.momirealms.craftengine.fabric.util.BlockUtils; import net.momirealms.craftengine.fabric.util.BlockUtils;
import net.momirealms.craftengine.fabric.util.LoggerFilter; import net.momirealms.craftengine.fabric.util.LoggerFilter;
@@ -37,7 +39,8 @@ public class CraftEngineFabricMod implements ModInitializer {
BlockState blockState = YamlUtils.createBlockData("minecraft:" + replacedBlockId.getPath()); BlockState blockState = YamlUtils.createBlockData("minecraft:" + replacedBlockId.getPath());
RegisterBlocks.register( RegisterBlocks.register(
replacedBlockId.getPath() + "_" + i, replacedBlockId.getPath() + "_" + i,
BlockUtils.canPassThrough(blockState) BlockUtils.canPassThrough(blockState),
BlockUtils.getShape(blockState)
); );
} }
} }

View File

@@ -1,7 +1,12 @@
package net.momirealms.craftengine.fabric.util; package net.momirealms.craftengine.fabric.util;
import net.minecraft.block.AbstractBlock; import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState; 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.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -43,4 +48,20 @@ public class BlockUtils {
throw new RuntimeException("Failed to access 'collidable' field", e); 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();
}
}
} }

View File

@@ -2,21 +2,33 @@ package net.momirealms.craftengine.fabric.util;
import net.minecraft.block.AbstractBlock; import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext;
import net.minecraft.registry.Registries; import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry; import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.RegistryKeys;
import net.minecraft.util.Identifier; 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 net.momirealms.craftengine.fabric.CraftEngineFabricMod;
import java.util.function.Function; import java.util.function.Function;
public class RegisterBlocks { public class RegisterBlocks {
@SuppressWarnings("UnusedReturnValue") @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); AbstractBlock.Settings settings = Block.Settings.create().nonOpaque().strength(-1.0F, 3600000.0F);
if (canPassThrough) settings.noCollision(); VoxelShape collisionShape;
return register(name, Block::new, settings); 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<AbstractBlock.Settings, Block> blockFactory, AbstractBlock.Settings settings) { public static Block register(String name, Function<AbstractBlock.Settings, Block> 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;
}
}

View File

@@ -3,6 +3,5 @@
"category.craftengine.general": "General", "category.craftengine.general": "General",
"option.craftengine.enable_network": "Enable custom blocks in server", "option.craftengine.enable_network": "Enable custom blocks in server",
"tooltip.craftengine.enable_network": "Changes requires re-entering the server to take effect", "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.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"
} }

View File

@@ -3,6 +3,5 @@
"category.craftengine.general": "通用", "category.craftengine.general": "通用",
"option.craftengine.enable_network": "启用服务器内自定义方块", "option.craftengine.enable_network": "启用服务器内自定义方块",
"tooltip.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.block_registry_mismatch": "方块注册表大小不匹配. 当前: %s. 预期: %s \n 1. 确保客户端mod配置与服务端配置一致. \n 2. 不要安装任何会注册新方块的mod. \n 3. 不要使用ViaVersion."
"disconnect.craftengine.title": "CraftEngine连接错误"
} }