mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-25 09:59:20 +00:00
feat(client-mod): 更新客户端模组
- 添加取消方块更新功能 - 修复保存配置文件问题 - 修复网络通讯打包解包
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<CraftEnginePayload> ID = new Id<>(CraftEnginePayload.CRAFTENGINE_PAYLOAD);
|
||||
public static final PacketCodec<PacketByteBuf, CraftEnginePayload> 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<? extends CustomPayload> getId() {
|
||||
|
||||
@@ -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<String, Object>();
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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<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();
|
||||
}
|
||||
}
|
||||
@@ -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<BlockState> cir) {
|
||||
if (!enableCancelBlockUpdate || !serverInstalled) return;
|
||||
cir.setReturnValue(state);
|
||||
}
|
||||
}
|
||||
@@ -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<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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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."
|
||||
}
|
||||
@@ -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."
|
||||
}
|
||||
14
client-mod/src/main/resources/craftengine.mixins.json
Normal file
14
client-mod/src/main/resources/craftengine.mixins.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "net.momirealms.craftengine.fabric.mixin",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"mixins": [
|
||||
"AbstractBlockStateMixin",
|
||||
"AbstractRailBlockMixin",
|
||||
"BlockItemMixin",
|
||||
"FluidStateMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,10 @@
|
||||
"modmenu": ["net.momirealms.craftengine.fabric.client.config.ModMenuIntegration"]
|
||||
},
|
||||
|
||||
"mixins": [
|
||||
"craftengine.mixins.json"
|
||||
],
|
||||
|
||||
"depends": {
|
||||
"fabricloader": ">=${loader_version}",
|
||||
"fabric": "*",
|
||||
|
||||
Reference in New Issue
Block a user