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-06-01 21:56:30 +08:00
parent 5a015d7944
commit 0f7ec4afb4
31 changed files with 12 additions and 1032 deletions

View File

@@ -43,7 +43,7 @@ tasks.withType<JavaCompile> {
bukkit {
load = net.minecrell.pluginyml.bukkit.BukkitPluginDescription.PluginLoadOrder.POSTWORLD
main = "net.momirealms.craftengine.bukkit.BukkitCraftEnginePlugin"
main = "net.momirealms.craftengine.bukkit.plugin.BukkitCraftEnginePlugin"
version = rootProject.properties["project_version"] as String
name = "CraftEngine"
apiVersion = "1.20"

View File

@@ -1,6 +1,5 @@
package net.momirealms.craftengine.bukkit;
package net.momirealms.craftengine.bukkit.plugin;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import org.bukkit.plugin.java.JavaPlugin;
public class BukkitCraftEnginePlugin extends JavaPlugin {

View File

@@ -45,8 +45,8 @@ tasks.withType<JavaCompile> {
paper {
load = net.minecrell.pluginyml.bukkit.BukkitPluginDescription.PluginLoadOrder.POSTWORLD
main = "net.momirealms.craftengine.bukkit.PaperCraftEnginePlugin"
bootstrapper = "net.momirealms.craftengine.bukkit.PaperCraftEngineBootstrap"
main = "net.momirealms.craftengine.bukkit.plugin.PaperCraftEnginePlugin"
bootstrapper = "net.momirealms.craftengine.bukkit.plugin.PaperCraftEngineBootstrap"
version = rootProject.properties["project_version"] as String
name = "CraftEngine"
apiVersion = "1.20"

View File

@@ -1,13 +1,9 @@
package net.momirealms.craftengine.bukkit;
package net.momirealms.craftengine.bukkit.plugin;
import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.plugin.bootstrap.BootstrapContext;
import io.papermc.paper.plugin.bootstrap.PluginBootstrap;
import io.papermc.paper.plugin.bootstrap.PluginProviderContext;
import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler;
import io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent;
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.classpath.PaperClassPathAppender;
import net.momirealms.craftengine.core.plugin.logger.PluginLogger;
import net.momirealms.craftengine.core.plugin.logger.Slf4jPluginLogger;

View File

@@ -1,4 +1,4 @@
package net.momirealms.craftengine.bukkit;
package net.momirealms.craftengine.bukkit.plugin;
import org.bukkit.plugin.java.JavaPlugin;

View File

@@ -110,16 +110,16 @@ public class BukkitCraftEngine extends CraftEngine {
}
}
public void setJavaPlugin(JavaPlugin javaPlugin) {
protected void setJavaPlugin(JavaPlugin javaPlugin) {
this.javaPlugin = javaPlugin;
}
public void setUpConfig() {
protected void setUpConfig() {
this.translationManager = new TranslationManagerImpl(this);
this.config = new Config(this);
}
public void injectRegistries() {
protected void injectRegistries() {
try {
BlockGenerator.init();
super.blockManager = new BukkitBlockManager(this);

View File

@@ -1,109 +0,0 @@
plugins {
id("fabric-loom") version "1.10-SNAPSHOT"
id("com.gradleup.shadow") version "9.0.0-beta13"
}
version = property("project_version")!!
group = property("project_group")!!
val project_version: String by project
val latest_minecraft_version: String by project
val loader_version: String by project
var modmenu_version = property("modmenu_version")
var cloth_version = property("cloth_version")
base {
archivesName.set("craft-engine-fabric-mod")
}
sourceSets {
create("client") {
compileClasspath += sourceSets.main.get().compileClasspath
runtimeClasspath += sourceSets.main.get().runtimeClasspath
}
main {
compileClasspath += sourceSets["client"].output
runtimeClasspath += sourceSets["client"].output
output.dir(sourceSets["client"].output)
}
}
tasks.shadowJar {
relocate("org.yaml", "net.momirealms.craftengine.libraries.org.yaml")
configurations = listOf(project.configurations.getByName("shadow"))
archiveFileName.set("${base.archivesName.get()}-${project.version}-shadow.jar")
from(sourceSets.main.get().output)
from(sourceSets["client"].output)
}
tasks.remapJar {
dependsOn(tasks.shadowJar)
inputFile.set(tasks.shadowJar.get().archiveFile)
destinationDirectory.set(file("$rootDir/target"))
archiveFileName.set("${base.archivesName.get()}-${project.version}+mc${rootProject.properties["latest_minecraft_version"]}.jar")
}
loom {
mods {
create("craft-engine-fabric-mod") {
sourceSet(sourceSets.main.get())
sourceSet(sourceSets["client"])
}
}
}
repositories {
maven("https://maven.shedaniel.me/")
maven("https://maven.terraformersmc.com/releases/")
}
dependencies {
minecraft("com.mojang:minecraft:${property("latest_minecraft_version")}")
mappings("net.fabricmc:yarn:${property("yarn_mappings")}:v2")
modImplementation("net.fabricmc:fabric-loader:${property("loader_version")}")
modImplementation("net.fabricmc.fabric-api:fabric-api:${property("fabric_version")}")
modApi("me.shedaniel.cloth:cloth-config-fabric:${property("cloth_version")}")
modApi("com.terraformersmc:modmenu:${property("modmenu_version")}")
add("shadow", "org.yaml:snakeyaml:2.4")
}
tasks.processResources {
inputs.property("version", project_version)
inputs.property("minecraft_version", latest_minecraft_version)
inputs.property("loader_version", loader_version)
filteringCharset = "UTF-8"
filesMatching("fabric.mod.json") {
expand(
"version" to project_version,
"minecraft_version" to latest_minecraft_version,
"loader_version" to loader_version,
"modmenu_version" to modmenu_version,
"cloth_version" to cloth_version
)
}
}
val targetJavaVersion = 21
tasks.withType<JavaCompile>().configureEach {
options.encoding = "UTF-8"
if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible) {
options.release.set(targetJavaVersion)
}
}
java {
val javaVersion = JavaVersion.toVersion(targetJavaVersion)
if (JavaVersion.current() < javaVersion) {
toolchain {
languageVersion.set(JavaLanguageVersion.of(targetJavaVersion))
}
}
withSourcesJar()
}
tasks.build {
dependsOn(tasks.clean)
dependsOn(tasks.shadowJar)
}

View File

@@ -1,97 +0,0 @@
package net.momirealms.craftengine.fabric.client;
import io.netty.buffer.Unpooled;
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;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.color.world.BiomeColors;
import net.minecraft.client.network.ClientConfigurationNetworkHandler;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.registry.Registries;
import net.minecraft.util.Identifier;
import net.minecraft.world.biome.FoliageColors;
import net.momirealms.craftengine.fabric.client.blocks.CustomBlock;
import net.momirealms.craftengine.fabric.client.config.ModConfig;
import net.momirealms.craftengine.fabric.client.network.CraftEnginePayload;
import net.momirealms.craftengine.fabric.client.util.NetWorkDataTypes;
@Environment(EnvType.CLIENT)
public class CraftEngineFabricModClient implements ClientModInitializer {
public static final String MOD_ID = "craftengine";
public static boolean serverInstalled = false;
@Override
public void onInitializeClient() {
PayloadTypeRegistry.configurationS2C().register(CraftEnginePayload.ID, CraftEnginePayload.CODEC);
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() {
Registries.BLOCK.forEach(block -> {
Identifier id = Registries.BLOCK.getId(block);
if (block instanceof CustomBlock customBlock) {
if (customBlock.isTransparent()) {
BlockRenderLayerMap.INSTANCE.putBlock(customBlock, RenderLayer.getCutoutMipped());
}
if (id.getPath().contains("leaves")) {
registerColor(block);
}
}
});
}
public static void registerColor(Block block) {
ColorProviderRegistry.BLOCK.register(
(state, world, pos, tintIndex) -> {
if (world != null && pos != null) {
return BiomeColors.getFoliageColor(world, pos);
}
return FoliageColors.DEFAULT;
},
block
);
}
private static void initChannel(ClientConfigurationNetworkHandler handler, MinecraftClient client) {
if (!ModConfig.enableNetwork && !ModConfig.enableCancelBlockUpdate) {
ClientConfigurationNetworking.unregisterGlobalReceiver(CraftEnginePayload.ID);
return;
}
PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer());
if (ModConfig.enableNetwork) {
NetWorkDataTypes<Integer> type = NetWorkDataTypes.CLIENT_CUSTOM_BLOCK;
type.writeType(buf);
type.encode(buf, Block.STATE_IDS.size());
} else if (ModConfig.enableCancelBlockUpdate) {
NetWorkDataTypes<Boolean> type = NetWorkDataTypes.CANCEL_BLOCK_UPDATE;
type.writeType(buf);
type.encode(buf, true);
}
ClientConfigurationNetworking.send(new CraftEnginePayload(buf.array()));
}
private static void handleReceiver(CraftEnginePayload payload, ClientConfigurationNetworking.Context context) {
byte[] data = payload.data();
PacketByteBuf buf = new PacketByteBuf(Unpooled.wrappedBuffer(data));
NetWorkDataTypes<?> type = NetWorkDataTypes.readType(buf);
if (type == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) {
serverInstalled = type.as(Boolean.class).decode(buf);
}
}
}

View File

@@ -1,35 +0,0 @@
package net.momirealms.craftengine.fabric.client.blocks;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.world.BlockView;
public class CustomBlock extends Block {
private final VoxelShape outlineShape;
private final VoxelShape collisionShape;
private final boolean isTransparent;
public CustomBlock(Settings settings, VoxelShape outlineShape, VoxelShape collisionShape, boolean isTransparent) {
super(settings);
this.outlineShape = outlineShape;
this.collisionShape = collisionShape;
this.isTransparent = isTransparent;
}
@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;
}
public boolean isTransparent() {
return this.isTransparent;
}
}

View File

@@ -1,69 +0,0 @@
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 net.momirealms.craftengine.fabric.client.CraftEngineFabricModClient;
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 = false;
public static boolean enableCancelBlockUpdate = true;
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),
enableNetwork)
.setDefaultValue(false)
.setSaveConsumer(newValue -> enableNetwork = newValue)
.setTooltip(
Text.translatable("tooltip.craftengine.enable_network")
.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<String, Object>();
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();
}
}
}

View File

@@ -1,12 +0,0 @@
package net.momirealms.craftengine.fabric.client.config;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
public class ModMenuIntegration implements ModMenuApi {
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory() {
return ModConfig::getConfigScreen;
}
}

View File

@@ -1,20 +0,0 @@
package net.momirealms.craftengine.fabric.client.network;
import net.minecraft.network.RegistryByteBuf;
import net.minecraft.network.codec.PacketCodec;
public class ByteArrayCodec implements PacketCodec<RegistryByteBuf, byte[]> {
@Override
public void encode(RegistryByteBuf buf, byte[] value) {
buf.writeBytes(value);
}
@Override
public byte[] decode(RegistryByteBuf buf) {
int length = buf.readableBytes();
byte[] data = new byte[length];
buf.readBytes(data);
return data;
}
}

View File

@@ -1,24 +0,0 @@
package net.momirealms.craftengine.fabric.client.network;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.network.packet.CustomPayload;
import net.minecraft.util.Identifier;
public record CraftEnginePayload(byte[] data) implements CustomPayload {
public static final Identifier CRAFTENGINE_PAYLOAD = Identifier.of("craftengine", "payload");
public static final Id<CraftEnginePayload> ID = new Id<>(CraftEnginePayload.CRAFTENGINE_PAYLOAD);
public static final PacketCodec<PacketByteBuf, CraftEnginePayload> CODEC = PacketCodec.of(
(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<? extends CustomPayload> getId() {
return ID;
}
}

View File

@@ -1,63 +0,0 @@
package net.momirealms.craftengine.fabric.client.util;
import net.minecraft.network.PacketByteBuf;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;
public class NetWorkDataTypes<T> {
private static final Map<Integer, NetWorkDataTypes<?>> id2NetWorkDataTypes = new HashMap<>();
public static final NetWorkDataTypes<Integer> CLIENT_CUSTOM_BLOCK =
new NetWorkDataTypes<>(0, PacketByteBuf::readInt, PacketByteBuf::writeInt);
public static final NetWorkDataTypes<Boolean> CANCEL_BLOCK_UPDATE =
new NetWorkDataTypes<>(1, PacketByteBuf::readBoolean, PacketByteBuf::writeBoolean);
static {
register(CLIENT_CUSTOM_BLOCK);
register(CANCEL_BLOCK_UPDATE);
}
private static void register(NetWorkDataTypes<?> type) {
id2NetWorkDataTypes.put(type.id, type);
}
private final int id;
private final Function<PacketByteBuf, T> decoder;
private final BiConsumer<PacketByteBuf, T> encoder;
public NetWorkDataTypes(int id, Function<PacketByteBuf, T> decoder, BiConsumer<PacketByteBuf, T> encoder) {
this.id = id;
this.decoder = decoder;
this.encoder = encoder;
}
public T decode(PacketByteBuf buf) {
return decoder.apply(buf);
}
public void encode(PacketByteBuf buf, T data) {
encoder.accept(buf, data);
}
public int id() {
return id;
}
public void writeType(PacketByteBuf buf) {
buf.writeVarInt(id);
}
public static NetWorkDataTypes<?> readType(PacketByteBuf buf) {
int id = buf.readVarInt();
return id2NetWorkDataTypes.get(id);
}
@SuppressWarnings({"unchecked", "unused"})
public <R> NetWorkDataTypes<R> as(Class<R> clazz) {
return (NetWorkDataTypes<R>) this;
}
}

View File

@@ -1,76 +0,0 @@
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;
import net.minecraft.util.Identifier;
import net.momirealms.craftengine.fabric.client.config.ModConfig;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml;
import java.io.IOException;
import java.io.InputStream;
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";
public static final Logger LOGGER = LoggerFactory.getLogger("craftengine");
@Override
public void onInitialize() {
loadConfig();
LoggerFilter.filter();
try {
YamlUtils.saveDefaultResource();
Map<Identifier, Integer> map = YamlUtils.loadMappingsAndAdditionalBlocks();
for (Map.Entry<Identifier, Integer> entry : map.entrySet()) {
Identifier replacedBlockId = entry.getKey();
for (int i = 0; i < entry.getValue(); i++) {
BlockState blockState = YamlUtils.createBlockData("minecraft:" + replacedBlockId.getPath());
RegisterBlocks.register(
replacedBlockId.getPath() + "_" + i,
BlockUtils.canPassThrough(blockState),
BlockUtils.getShape(blockState),
BlockUtils.isTransparent(blockState),
BlockUtils.canPush(blockState)
);
}
}
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
}
@SuppressWarnings("unchecked")
private void loadConfig() {
if (!Files.exists(CONFIG_PATH)) {
ModConfig.enableNetwork = false;
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 = false;
ModConfig.enableCancelBlockUpdate = false;
return;
}
ModConfig.enableNetwork = (Boolean) config.getOrDefault("enable-network", false);
ModConfig.enableCancelBlockUpdate = (Boolean) config.getOrDefault("enable-cancel-block-update", false);
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
}
}

View File

@@ -1,65 +0,0 @@
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<AbstractBlockStateMixin> 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<Boolean> 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();
}
}

View File

@@ -1,26 +0,0 @@
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<BlockState> cir) {
if (!enableCancelBlockUpdate || !serverInstalled) return;
cir.setReturnValue(state);
}
}

View File

@@ -1,30 +0,0 @@
package net.momirealms.craftengine.fabric.mixin;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
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;
@Environment(EnvType.CLIENT)
@Mixin(BlockItem.class)
public class BlockItemMixin {
@Inject(method = "place*", at = @At("HEAD"), cancellable = true)
private void onPlace(ItemPlacementContext context, CallbackInfoReturnable<ActionResult> 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();
}
}
}

View File

@@ -1,26 +0,0 @@
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();
}
}

View File

@@ -1,82 +0,0 @@
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.TransparentBlock;
import net.minecraft.block.piston.PistonBehavior;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import static java.util.Objects.requireNonNull;
public class BlockUtils {
private final static Field COLLIDABLE_FIELD = requireNonNull(getDeclaredField(AbstractBlock.Settings.class, boolean.class, 0));
@Nullable
public static Field getDeclaredField(final Class<?> clazz, final Class<?> type, int index) {
int i = 0;
for (final Field field : clazz.getDeclaredFields()) {
if (field.getType() == type) {
if (index == i) {
return setAccessible(field);
}
i++;
}
}
return null;
}
@NotNull
public static <T extends AccessibleObject> T setAccessible(@NotNull final T o) {
o.setAccessible(true);
return o;
}
public static boolean canPassThrough(BlockState state) {
try {
if (state == null) return false;
AbstractBlock.Settings settings = state.getBlock().getSettings();
return !COLLIDABLE_FIELD.getBoolean(settings);
} catch (IllegalAccessException 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();
}
}
public static boolean isTransparent(BlockState state) {
if (state == null) return true;
Block block = state.getBlock();
if (block instanceof TransparentBlock) {
return true;
}
return !state.isOpaque();
}
public static int canPush(BlockState state) {
if (state == null) return 0;
if (state.getPistonBehavior() == PistonBehavior.NORMAL) return 1;
if (state.getPistonBehavior() == PistonBehavior.PUSH_ONLY) return 2;
return 0;
}
}

View File

@@ -1,22 +0,0 @@
package net.momirealms.craftengine.fabric.util;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.filter.AbstractFilter;
public class LoggerFilter {
public static void filter() {
Logger rootLogger = (Logger) LogManager.getRootLogger();
rootLogger.addFilter(new AbstractFilter() {
@Override
public Result filter(LogEvent event) {
if (event.getMessage().getFormattedMessage().contains("Missing model for variant: 'craftengine:")) {
return Result.DENY;
}
return Result.NEUTRAL;
}
});
}
}

View File

@@ -1,50 +0,0 @@
package net.momirealms.craftengine.fabric.util;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block;
import net.minecraft.block.piston.PistonBehavior;
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.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.momirealms.craftengine.fabric.CraftEngineFabricMod;
import net.momirealms.craftengine.fabric.client.blocks.CustomBlock;
import java.util.function.Function;
public class RegisterBlocks {
@SuppressWarnings("UnusedReturnValue")
public static Block register(String name, boolean canPassThrough,
VoxelShape outlineShape, boolean isTransparent,
int canPush) {
AbstractBlock.Settings settings = Block.Settings.create()
.strength(canPush != 0 ? 3600000.0F : -1.0F, 3600000.0F);
if (canPush == 1) settings.pistonBehavior(PistonBehavior.NORMAL);
if (canPush == 2) settings.pistonBehavior(PistonBehavior.PUSH_ONLY);
VoxelShape collisionShape;
if (isTransparent) settings.nonOpaque();
if (canPassThrough) {
collisionShape = VoxelShapes.empty();
settings.noCollision();
} else {
collisionShape = outlineShape;
}
return register(name, (settingsParam) -> new CustomBlock(settingsParam, outlineShape, collisionShape, isTransparent), settings);
}
public static Block register(String name, Function<AbstractBlock.Settings, Block> blockFactory, AbstractBlock.Settings settings) {
RegistryKey<Block> blockKey = keyOfBlock(name);
Block block = blockFactory.apply(settings.registryKey(blockKey));
return Registry.register(Registries.BLOCK, blockKey, block);
}
private static RegistryKey<Block> keyOfBlock(String name) {
return RegistryKey.of(RegistryKeys.BLOCK, Identifier.of(CraftEngineFabricMod.MOD_ID, name));
}
}

View File

@@ -1,31 +0,0 @@
package net.momirealms.craftengine.fabric.util;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.NodeTuple;
import org.yaml.snakeyaml.nodes.ScalarNode;
import java.util.LinkedHashMap;
import java.util.Map;
public class StringKeyConstructor extends SafeConstructor {
public StringKeyConstructor(LoaderOptions loaderOptions) {
super(loaderOptions);
}
@Override
protected Map<Object, Object> constructMapping(MappingNode node) {
Map<Object, Object> map = new LinkedHashMap<>();
for (NodeTuple tuple : node.getValue()) {
Node keyNode = tuple.getKeyNode();
Node valueNode = tuple.getValueNode();
String key = constructScalar((ScalarNode) keyNode);
Object value = constructObject(valueNode);
map.put(key, value);
}
return map;
}
}

View File

@@ -1,112 +0,0 @@
package net.momirealms.craftengine.fabric.util;
import com.mojang.brigadier.StringReader;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.command.argument.BlockArgumentParser;
import net.minecraft.registry.BuiltinRegistries;
import net.minecraft.registry.Registries;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.util.Identifier;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class YamlUtils {
public static final Path CONFIG_DIR = Path.of("config/craft-engine-fabric-mod/");
private static final RegistryWrapper<Block> registryWrapper = BuiltinRegistries.createWrapperLookup().getOrThrow(RegistryKeys.BLOCK);
public static <T> T loadConfig(Path filePath) throws IOException {
if (!Files.exists(filePath)) {
throw new FileNotFoundException(filePath.toString());
}
try (InputStream inputStream = Files.newInputStream(filePath)) {
Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions()));
return yaml.load(inputStream);
}
}
public static void saveDefaultResource() throws IOException {
if (!Files.exists(CONFIG_DIR)) {
Files.createDirectories(CONFIG_DIR);
Path readme = CONFIG_DIR.resolve("README.text");
Files.writeString(readme, "Please copy 'mappings.yml' & 'additional-real-blocks.yml' to this folder to apply the configs.");
}
}
public static Map<Identifier, Integer> loadMappingsAndAdditionalBlocks() throws IOException {
Path mappingPath = CONFIG_DIR.resolve("mappings.yml");
Path additionalYamlPath = CONFIG_DIR.resolve("additional-real-blocks.yml");
if (!Files.exists(additionalYamlPath) || !Files.exists(mappingPath)) return Map.of();
Map<String, String> blockStateMappings = loadConfig(mappingPath);
validateBlockStateMappings(blockStateMappings);
Map<Identifier, Integer> blockTypeCounter = new LinkedHashMap<>();
Map<Integer, Integer> appearanceMapper = new HashMap<>();
for (Map.Entry<String, String> entry : blockStateMappings.entrySet()) {
processBlockStateMapping(entry, appearanceMapper, blockTypeCounter);
}
Map<String, Integer> additionalYaml = loadConfig(additionalYamlPath);
return buildRegisteredRealBlockSlots(blockTypeCounter, additionalYaml);
}
private static void validateBlockStateMappings(Map<String, String> blockStateMappings) {
Map<String, String> temp = new HashMap<>(blockStateMappings);
for (Map.Entry<String, String> entry : temp.entrySet()) {
String state = entry.getValue();
blockStateMappings.remove(state);
}
}
private static void processBlockStateMapping(
Map.Entry<String, String> entry,
Map<Integer, Integer> stateIdMapper,
Map<Identifier, Integer> blockUsageCounter
) {
final BlockState sourceState = createBlockData(entry.getKey());
final BlockState targetState = createBlockData(entry.getValue());
if (sourceState == null || targetState == null) {
return;
}
final int sourceStateId = Block.STATE_IDS.getRawId(sourceState);
final int targetStateId = Block.STATE_IDS.getRawId(targetState);
if (stateIdMapper.putIfAbsent(sourceStateId, targetStateId) == null) {
final Block sourceBlock = sourceState.getBlock();
final Identifier blockId = Registries.BLOCK.getId(sourceBlock);
blockUsageCounter.merge(blockId, 1, Integer::sum);
}
}
public static BlockState createBlockData(String blockState) {
try {
StringReader reader = new StringReader(blockState);
BlockArgumentParser.BlockResult arg = BlockArgumentParser.block(registryWrapper, reader, true);
return arg.blockState();
} catch (Exception e) {
return null;
}
}
private static LinkedHashMap<Identifier, Integer> buildRegisteredRealBlockSlots(Map<Identifier, Integer> counter, Map<String, Integer> additionalYaml) {
LinkedHashMap<Identifier, Integer> map = new LinkedHashMap<>();
for (Map.Entry<Identifier, Integer> entry : counter.entrySet()) {
String id = entry.getKey().toString();
Integer additionalStates = additionalYaml.get(id);
int internalIds = entry.getValue() + (additionalStates != null ? additionalStates : 0);
map.put(entry.getKey(), internalIds);
}
return map;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -1,9 +0,0 @@
{
"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."
}

View File

@@ -1,9 +0,0 @@
{
"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."
}

View File

@@ -1,14 +0,0 @@
{
"required": true,
"package": "net.momirealms.craftengine.fabric.mixin",
"compatibilityLevel": "JAVA_21",
"client": [
"AbstractBlockStateMixin",
"AbstractRailBlockMixin",
"BlockItemMixin",
"FluidStateMixin"
],
"injectors": {
"defaultRequire": 1
}
}

View File

@@ -1,33 +0,0 @@
{
"schemaVersion": 1,
"id": "craft-engine-fabric-mod",
"version": "${version}",
"name": "CraftEngine Fabric Mod",
"description": "CraftEngine Fabric Mod",
"authors": [
"jhqwqmc"
],
"contact": {
"name": "CraftEngine",
"homepage": "https://github.com/Xiao-MoMi/craft-engine",
"issues": "https://github.com/Xiao-MoMi/craft-engine/issues"
},
"license": "GPL-3.0",
"icon": "assets/craft-engine-fabric-mod/icon.png",
"environment": "client",
"entrypoints": {
"client": ["net.momirealms.craftengine.fabric.client.CraftEngineFabricModClient"],
"main": ["net.momirealms.craftengine.fabric.CraftEngineFabricMod"],
"modmenu": ["net.momirealms.craftengine.fabric.client.config.ModMenuIntegration"]
},
"mixins": [
"craftengine.mixins.json"
],
"depends": {
"fabricloader": ">=${loader_version}",
"fabric": "*",
"minecraft": ">=${minecraft_version}",
"modmenu": ">=${modmenu_version}",
"cloth-config": ">=${cloth_version}"
}
}

View File

@@ -96,7 +96,7 @@ public abstract class CraftEngine implements Plugin {
return instance;
}
public void onPluginLoad() {
protected void onPluginLoad() {
((Logger) LogManager.getRootLogger()).addFilter(new LogFilter());
((Logger) LogManager.getRootLogger()).addFilter(new DisconnectLogFilter());
}
@@ -194,7 +194,7 @@ public abstract class CraftEngine implements Plugin {
return future;
}
public void onPluginEnable() {
protected void onPluginEnable() {
this.isInitializing = true;
this.networkManager.init();
this.templateManager = new TemplateManagerImpl();
@@ -232,7 +232,7 @@ public abstract class CraftEngine implements Plugin {
});
}
public void onPluginDisable() {
protected void onPluginDisable() {
if (this.networkManager != null) this.networkManager.disable();
if (this.fontManager != null) this.fontManager.disable();
if (this.advancementManager != null) this.advancementManager.disable();

View File

@@ -6,7 +6,6 @@ include(":bukkit:compatibility")
include(":bukkit:compatibility:legacy")
include(":bukkit:loader")
include(":bukkit:paper-loader")
include(":client-mod")
include(":common-files")
pluginManagement {
plugins {