9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

Merge pull request #61 from jhqwqmc/dev

feat: 优化客户端注册及服务端同步客户端方块及修复方块谓词刷物品
This commit is contained in:
XiaoMoMi
2025-03-26 22:56:36 +08:00
committed by GitHub
28 changed files with 430 additions and 92 deletions

View File

@@ -8,6 +8,8 @@ metrics: true
update-checker: true update-checker: true
# Forces a specific locale (e.g., zh_cn) # Forces a specific locale (e.g., zh_cn)
forced-locale: '' forced-locale: ''
# Filter configuration phase player disconnection logs
filter-configuration-phase-disconnect: false
resource-pack: resource-pack:
# Should those images in minecraft:default font also work in minecraft:uniform # Should those images in minecraft:default font also work in minecraft:uniform

View File

@@ -12,6 +12,7 @@ items#misc:
behavior: behavior:
type: block_item type: block_item
block: block:
name: "i18n:item.chinese_lantern"
loot: loot:
template: "default:loot_table/basic" template: "default:loot_table/basic"
arguments: arguments:
@@ -53,6 +54,7 @@ items#misc:
behavior: behavior:
type: block_item type: block_item
block: block:
name: "i18n:item.netherite_anvil"
loot: loot:
template: "default:loot_table/basic" template: "default:loot_table/basic"
arguments: arguments:

View File

@@ -42,6 +42,7 @@ items:
blocks: blocks:
default:topaz_ore: default:topaz_ore:
name: "i18n:item.topaz_ore"
loot: loot:
template: "default:loot_table/ore" template: "default:loot_table/ore"
arguments: arguments:
@@ -63,6 +64,7 @@ blocks:
arguments: arguments:
path: "minecraft:block/custom/topaz_ore" path: "minecraft:block/custom/topaz_ore"
default:deepslate_topaz_ore: default:deepslate_topaz_ore:
name: "i18n:item.deepslate_topaz_ore"
loot: loot:
template: "default:loot_table/ore" template: "default:loot_table/ore"
arguments: arguments:

View File

@@ -18,6 +18,7 @@ items:
behavior: behavior:
type: block_item type: block_item
block: block:
name: "i18n:item.palm_log"
behavior: behavior:
type: strippable_block type: strippable_block
stripped: default:stripped_palm_log stripped: default:stripped_palm_log
@@ -64,6 +65,7 @@ items:
behavior: behavior:
type: block_item type: block_item
block: block:
name: "i18n:item.stripped_palm_log"
loot: loot:
template: "default:loot_table/basic" template: "default:loot_table/basic"
arguments: arguments:
@@ -107,6 +109,7 @@ items:
behavior: behavior:
type: block_item type: block_item
block: block:
name: "i18n:item.palm_wood"
behavior: behavior:
type: strippable_block type: strippable_block
stripped: default:stripped_palm_wood stripped: default:stripped_palm_wood
@@ -153,6 +156,7 @@ items:
behavior: behavior:
type: block_item type: block_item
block: block:
name: "i18n:item.stripped_palm_wood"
loot: loot:
template: "default:loot_table/basic" template: "default:loot_table/basic"
arguments: arguments:
@@ -195,6 +199,7 @@ items:
behavior: behavior:
type: block_item type: block_item
block: block:
name: "i18n:item.palm_planks"
settings: settings:
template: "default:settings/planks" template: "default:settings/planks"
overrides: overrides:
@@ -225,6 +230,7 @@ items:
behavior: behavior:
type: block_item type: block_item
block: block:
name: "i18n:item.palm_sapling"
settings: settings:
template: "default:settings/sapling" template: "default:settings/sapling"
overrides: overrides:
@@ -287,6 +293,7 @@ items:
behavior: behavior:
type: block_item type: block_item
block: block:
name: "i18n:item.palm_leaves"
behavior: behavior:
type: leaves_block type: leaves_block
loot: loot:

View File

@@ -25,6 +25,7 @@ items:
block: default:reed block: default:reed
blocks: blocks:
default:fairy_flower: default:fairy_flower:
name: "i18n:item.fairy_flower"
settings: settings:
template: template:
- default:hardness/none - default:hardness/none
@@ -64,6 +65,7 @@ blocks:
"0": "minecraft:block/custom/fairy_flower_4" "0": "minecraft:block/custom/fairy_flower_4"
default:reed: default:reed:
settings: settings:
name: "i18n:item.reed"
template: template:
- default:hardness/none - default:hardness/none
- default:sound/grass - default:sound/grass

View File

@@ -452,7 +452,18 @@ public class BukkitBlockManager extends AbstractBlockManager {
// create block // create block
Map<String, Object> behaviorSection = MiscUtils.castToMap(section.getOrDefault("behavior", Map.of()), false); Map<String, Object> behaviorSection = MiscUtils.castToMap(section.getOrDefault("behavior", Map.of()), false);
CustomBlock block = new BukkitCustomBlock(id, holder, properties, appearances, variants, settings, behaviorSection, lootTable); BukkitCustomBlock block = new BukkitCustomBlock(id, holder, properties, appearances, variants, settings, behaviorSection, lootTable);
// read block name
String blockName = (String) section.getOrDefault("name", null);
if (blockName != null && blockName.startsWith("i18n:")) {
plugin.translationManager().i18nData().forEach((locale, i18nData) -> {
plugin.debug(() -> "locale: " + toMinecraftLocale(locale) + ": " + i18nData.translate(blockName.substring(5)));
block.addBlockName(toMinecraftLocale(locale), i18nData.translate(blockName.substring(5)));
}
);
} else {
block.addBlockName(blockName);
}
// bind appearance // bind appearance
bindAppearance(block); bindAppearance(block);
@@ -467,6 +478,18 @@ public class BukkitBlockManager extends AbstractBlockManager {
} }
} }
public static String toMinecraftLocale(Locale locale) {
String language = locale.getLanguage().toLowerCase();
String country = locale.getCountry().toLowerCase();
if ("en".equals(language) && country.isEmpty()) {
return "en_us";
}
if (country.isEmpty()) {
return language;
}
return language + "_" + country;
}
private void bindAppearance(CustomBlock block) { private void bindAppearance(CustomBlock block) {
for (ImmutableBlockState state : block.variantProvider().states()) { for (ImmutableBlockState state : block.variantProvider().states()) {
ImmutableBlockState previous = this.stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()]; ImmutableBlockState previous = this.stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()];

View File

@@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.block.*;
import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.loot.LootTable;
import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.locale.I18NData;
import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.Tristate; import net.momirealms.craftengine.core.util.Tristate;
@@ -137,4 +138,24 @@ public class BukkitCustomBlock extends CustomBlock {
CraftEngine.instance().logger().warn("Failed to init block settings", e); CraftEngine.instance().logger().warn("Failed to init block settings", e);
} }
} }
public void addBlockName(String lang, String blockName) {
I18NData i18nData = new I18NData();
for (ImmutableBlockState state : this.variantProvider().states()) {
try {
Object blockState = state.customBlockState().handle();
Object block = Reflections.method$BlockStateBase$getBlock.invoke(blockState);
String translationKey = (String) Reflections.method$BlockBehaviour$getDescriptionId.invoke(block);
i18nData.addTranslation(translationKey, blockName);
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to get the " + state.owner().value().id() + " translationKey");
}
}
this.addBlockName(lang, i18nData);
}
public void addBlockName(String blockName) {
if (blockName == null) return;
addBlockName("en_us", blockName);
}
} }

View File

@@ -10,7 +10,6 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.network.impl.*; import net.momirealms.craftengine.bukkit.plugin.network.impl.*;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.bukkit.util.RegistryUtils;
import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.ConnectionState;
import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
@@ -27,16 +26,15 @@ import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerRegisterChannelEvent; import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
public class BukkitNetworkManager implements NetworkManager, Listener { public class BukkitNetworkManager implements NetworkManager, Listener, PluginMessageListener {
private static BukkitNetworkManager instance; private static BukkitNetworkManager instance;
private static final Map<Class<?>, TriConsumer<NetWorkUser, NMSPacketEvent, Object>> nmsPacketFunctions = new HashMap<>(); private static final Map<Class<?>, TriConsumer<NetWorkUser, NMSPacketEvent, Object>> nmsPacketFunctions = new HashMap<>();
private static final Map<Integer, BiConsumer<NetWorkUser, ByteBufPacketEvent>> byteBufPacketFunctions = new HashMap<>(); private static final Map<Integer, BiConsumer<NetWorkUser, ByteBufPacketEvent>> byteBufPacketFunctions = new HashMap<>();
@@ -131,6 +129,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener {
registerNMSPacketConsumer(PacketConsumers.RENAME_ITEM, Reflections.clazz$ServerboundRenameItemPacket); registerNMSPacketConsumer(PacketConsumers.RENAME_ITEM, Reflections.clazz$ServerboundRenameItemPacket);
registerNMSPacketConsumer(PacketConsumers.SIGN_UPDATE, Reflections.clazz$ServerboundSignUpdatePacket); registerNMSPacketConsumer(PacketConsumers.SIGN_UPDATE, Reflections.clazz$ServerboundSignUpdatePacket);
registerNMSPacketConsumer(PacketConsumers.EDIT_BOOK, Reflections.clazz$ServerboundEditBookPacket); registerNMSPacketConsumer(PacketConsumers.EDIT_BOOK, Reflections.clazz$ServerboundEditBookPacket);
registerNMSPacketConsumer(PacketConsumers.CUSTOM_PAYLOAD, Reflections.clazz$ServerboundCustomPayloadPacket);
registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket());
registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket());
registerByteBufPacketConsumer(PacketConsumers.LEVEL_PARTICLE, this.packetIds.clientboundLevelParticlesPacket()); registerByteBufPacketConsumer(PacketConsumers.LEVEL_PARTICLE, this.packetIds.clientboundLevelParticlesPacket());
@@ -161,29 +160,21 @@ public class BukkitNetworkManager implements NetworkManager, Listener {
this.onlineUsers.remove(player.getUniqueId()); this.onlineUsers.remove(player.getUniqueId());
} }
// for mod
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerRegisterChannel(PlayerRegisterChannelEvent event) {
if (!event.getChannel().equals(MOD_CHANNEL)) return;
Player player = event.getPlayer();
NetWorkUser user = getUser(player);
if (user == null) return;
user.setClientModState(true);
int blockRegistrySize = RegistryUtils.currentBlockRegistrySize();
byte[] payload = ("cp:" + blockRegistrySize).getBytes(StandardCharsets.UTF_8);
player.sendPluginMessage(plugin.bootstrap(), MOD_CHANNEL, payload);
}
@Override @Override
public Collection<BukkitServerPlayer> onlineUsers() { public Collection<BukkitServerPlayer> onlineUsers() {
return onlineUsers.values(); return onlineUsers.values();
} }
@Override
// 保留仅注册入频道用
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte @NotNull [] message) {}
@Override @Override
public void init() { public void init() {
if (init) return; if (init) return;
try { try {
plugin.bootstrap().getServer().getMessenger().registerOutgoingPluginChannel(plugin.bootstrap(), "craftengine:payload"); plugin.bootstrap().getServer().getMessenger().registerIncomingPluginChannel(plugin.bootstrap(), MOD_CHANNEL, this);
plugin.bootstrap().getServer().getMessenger().registerOutgoingPluginChannel(plugin.bootstrap(), MOD_CHANNEL);
Object server = Reflections.method$MinecraftServer$getServer.invoke(null); Object server = Reflections.method$MinecraftServer$getServer.invoke(null);
Object serverConnection = Reflections.field$MinecraftServer$connection.get(server); Object serverConnection = Reflections.field$MinecraftServer$connection.get(server);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@@ -3,6 +3,8 @@ package net.momirealms.craftengine.bukkit.plugin.network;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntList;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TranslationArgument;
import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture;
import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent;
import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent;
@@ -19,6 +21,7 @@ import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.plugin.config.ConfigManager;
import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.ConnectionState;
import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
import net.momirealms.craftengine.core.plugin.network.NetworkManager;
import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.util.*;
import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.chunk.Palette; import net.momirealms.craftengine.core.world.chunk.Palette;
@@ -33,6 +36,7 @@ import org.bukkit.util.RayTraceResult;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -286,7 +290,6 @@ public class PacketConsumers {
}; };
private static void handlePlayerActionPacketOnMainThread(BukkitServerPlayer player, World world, BlockPos pos, Object packet) throws Exception { private static void handlePlayerActionPacketOnMainThread(BukkitServerPlayer player, World world, BlockPos pos, Object packet) throws Exception {
Object action = Reflections.field$ServerboundPlayerActionPacket$action.get(packet); Object action = Reflections.field$ServerboundPlayerActionPacket$action.get(packet);
if (action == Reflections.instance$ServerboundPlayerActionPacket$Action$START_DESTROY_BLOCK) { if (action == Reflections.instance$ServerboundPlayerActionPacket$Action$START_DESTROY_BLOCK) {
Object serverLevel = Reflections.field$CraftWorld$ServerLevel.get(world); Object serverLevel = Reflections.field$CraftWorld$ServerLevel.get(world);
@@ -306,6 +309,28 @@ public class PacketConsumers {
} }
return; return;
} }
if (player.isAdventureMode()) {
Object itemStack = Reflections.method$CraftItemStack$asNMSCopy.invoke(null, player.platformPlayer().getInventory().getItemInMainHand());
Object blockPos = Reflections.constructor$BlockPos.newInstance(pos.x(), pos.y(), pos.z());
Object blockInWorld = Reflections.constructor$BlockInWorld.newInstance(serverLevel, blockPos, false);
if (VersionHelper.isVersionNewerThan1_20_5()) {
if (Reflections.method$ItemStack$canBreakBlockInAdventureMode != null
&& !(boolean) Reflections.method$ItemStack$canBreakBlockInAdventureMode.invoke(
itemStack, blockInWorld
)) {
player.preventMiningBlock();
return;
}
} else {
if (Reflections.method$ItemStack$canDestroy != null
&& !(boolean) Reflections.method$ItemStack$canDestroy.invoke(
itemStack, Reflections.instance$BuiltInRegistries$BLOCK, blockInWorld
)) {
player.preventMiningBlock();
return;
}
}
}
player.startMiningBlock(world, pos, blockState, true, BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId)); player.startMiningBlock(world, pos, blockState, true, BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId));
} else if (action == Reflections.instance$ServerboundPlayerActionPacket$Action$ABORT_DESTROY_BLOCK) { } else if (action == Reflections.instance$ServerboundPlayerActionPacket$Action$ABORT_DESTROY_BLOCK) {
if (player.isMiningBlock()) { if (player.isMiningBlock()) {
@@ -875,4 +900,43 @@ public class PacketConsumers {
callback.accept(new String(newCodepoints, 0, newCodepoints.length)); callback.accept(new String(newCodepoints, 0, newCodepoints.length));
} }
} }
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> CUSTOM_PAYLOAD = (user, event, packet) -> {
try {
if (!VersionHelper.isVersionNewerThan1_20_5()) return;
Object payload = Reflections.field$ServerboundCustomPayloadPacket$payload.get(packet);
if (payload.getClass().equals(Reflections.clazz$DiscardedPayload)) {
Object type = Reflections.method$CustomPacketPayload$type.invoke(payload);
Object id = Reflections.method$CustomPacketPayload$Type$id.invoke(type);
String channel = id.toString();
if (!channel.equals(NetworkManager.MOD_CHANNEL)) return;
ByteBuf buf = (ByteBuf) Reflections.method$DiscardedPayload$data.invoke(payload);
byte[] data = new byte[buf.readableBytes()];
buf.readBytes(data);
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();
}
user.setClientModState(true);
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundCustomPayloadPacket", e);
}
};
} }

View File

@@ -8,6 +8,7 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.bukkit.util.*;
import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.bukkit.world.BukkitWorld;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.PackedBlockState;
import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.Item;
@@ -310,7 +311,8 @@ public class BukkitServerPlayer extends Player {
if (custom && getDestroyProgress(state, pos) >= 1f) { if (custom && getDestroyProgress(state, pos) >= 1f) {
assert immutableBlockState != null; assert immutableBlockState != null;
// not an instant break on client side // not an instant break on client side
if (getDestroyProgress(immutableBlockState.vanillaBlockState().handle(), pos) < 1f) { PackedBlockState vanillaBlockState = immutableBlockState.vanillaBlockState();
if (vanillaBlockState != null && getDestroyProgress(vanillaBlockState.handle(), pos) < 1f) {
try { try {
Object levelEventPacket = Reflections.constructor$ClientboundLevelEventPacket.newInstance(2001, LocationUtils.toBlockPos(pos), BlockStateUtils.blockStateToId(this.destroyedState), false); Object levelEventPacket = Reflections.constructor$ClientboundLevelEventPacket.newInstance(2001, LocationUtils.toBlockPos(pos), BlockStateUtils.blockStateToId(this.destroyedState), false);
sendPacket(levelEventPacket, false); sendPacket(levelEventPacket, false);
@@ -365,6 +367,13 @@ public class BukkitServerPlayer extends Player {
setIsDestroyingBlock(false, false); setIsDestroyingBlock(false, false);
} }
@Override
public void preventMiningBlock() {
setCanBreakBlock(false);
setIsDestroyingBlock(false, false);
abortMiningBlock();
}
private void resetEffect(Object mobEffect) throws ReflectiveOperationException { private void resetEffect(Object mobEffect) throws ReflectiveOperationException {
Object effectInstance = Reflections.method$ServerPlayer$getEffect.invoke(serverPlayer(), mobEffect); Object effectInstance = Reflections.method$ServerPlayer$getEffect.invoke(serverPlayer(), mobEffect);
Object packet; Object packet;

View File

@@ -5572,4 +5572,106 @@ public class Reflections {
clazz$CraftEventFactory, boolean.class, new String[] { "handleBlockFormEvent" }, clazz$Level, clazz$BlockPos, clazz$BlockState, int.class clazz$CraftEventFactory, boolean.class, new String[] { "handleBlockFormEvent" }, clazz$Level, clazz$BlockPos, clazz$BlockState, int.class
) )
); );
public static final Constructor<?> constructor$ClientboundLevelChunkWithLightPacket = requireNonNull(
ReflectionUtils.getConstructor(
clazz$ClientboundLevelChunkWithLightPacket, clazz$LevelChunk, clazz$LevelLightEngine, BitSet.class, BitSet.class
)
);
public static final Class<?> clazz$BlockInWorld = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("world.level.block.state.pattern.BlockInWorld"),
BukkitReflectionUtils.assembleMCClass("world.level.block.state.pattern.ShapeDetectorBlock")
)
);
public static final Constructor<?> constructor$BlockInWorld = requireNonNull(
ReflectionUtils.getConstructor(
clazz$BlockInWorld, 0
)
);
// 1.20.5+
public static final Method method$ItemStack$canBreakBlockInAdventureMode =
ReflectionUtils.getMethod(
clazz$ItemStack, new String[]{"canBreakBlockInAdventureMode"}, clazz$BlockInWorld
);
// 1.20 ~ 1.20.4
// instance$BuiltInRegistries$BLOCK
public static final Method method$ItemStack$canDestroy =
ReflectionUtils.getMethod(
clazz$ItemStack,new String[]{"b"}, clazz$Registry, clazz$BlockInWorld
);
public static final Method method$BlockStateBase$getBlock = requireNonNull(
ReflectionUtils.getMethod(
clazz$BlockStateBase, clazz$Block
)
);
public static final Method method$BlockBehaviour$getDescriptionId = requireNonNull(
VersionHelper.isVersionNewerThan1_21_2()
? ReflectionUtils.getMethod(clazz$BlockBehaviour, String.class)
: ReflectionUtils.getMethod(clazz$Block, String.class)
);
public static final Class<?> clazz$ServerboundCustomPayloadPacket = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.common.ServerboundCustomPayloadPacket"),
BukkitReflectionUtils.assembleMCClass("network.protocol.game.PacketPlayInCustomPayload")
)
);
// 1.20.2+
public static final Class<?> clazz$CustomPacketPayload =
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.common.custom.CustomPacketPayload")
);
// 1.20.5+
public static final Class<?> clazz$CustomPacketPayload$Type =
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.common.custom.CustomPacketPayload$Type")
);
// 1.20.2+
public static final Field field$ServerboundCustomPayloadPacket$payload = Optional.ofNullable(clazz$CustomPacketPayload)
.map(it -> ReflectionUtils.getDeclaredField(clazz$ServerboundCustomPayloadPacket, it, 0))
.orElse(null);
// 1.20.2+
public static final Class<?> clazz$DiscardedPayload =
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.common.custom.DiscardedPayload")
);
// 1.20.5+
public static final Method method$CustomPacketPayload$type = Optional.ofNullable(clazz$CustomPacketPayload$Type)
.map(it -> ReflectionUtils.getMethod(clazz$CustomPacketPayload, it))
.orElse(null);
// 1.20.5+
public static final Method method$CustomPacketPayload$Type$id = Optional.ofNullable(clazz$CustomPacketPayload$Type)
.map(it -> ReflectionUtils.getMethod(it, clazz$ResourceLocation))
.orElse(null);
// 1.20.5+
public static final Method method$DiscardedPayload$data = Optional.ofNullable(clazz$DiscardedPayload)
.map(it -> ReflectionUtils.getMethod(it, ByteBuf.class))
.orElse(null);
public static final Class<?> clazz$ClientboundDisconnectPacket = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.common.ClientboundDisconnectPacket"),
BukkitReflectionUtils.assembleMCClass("network.protocol.game.PacketPlayOutKickDisconnect")
)
);
public static final Constructor<?> constructor$ClientboundDisconnectPacket = requireNonNull(
ReflectionUtils.getConstructor(
clazz$ClientboundDisconnectPacket, clazz$Component
)
);
} }

View File

@@ -2,44 +2,42 @@ 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.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationConnectionEvents;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking;
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.MinecraftClient;
import net.minecraft.client.color.world.BiomeColors; import net.minecraft.client.color.world.BiomeColors;
import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.ClientConfigurationNetworkHandler;
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.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.world.biome.FoliageColors; 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.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";
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
PayloadTypeRegistry.playS2C().register(CraftEnginePayload.ID, CraftEnginePayload.CODEC); PayloadTypeRegistry.configurationS2C().register(CraftEnginePayload.ID, CraftEnginePayload.CODEC);
initChannel(MinecraftClient.getInstance().getNetworkHandler()); PayloadTypeRegistry.configurationC2S().register(CraftEnginePayload.ID, CraftEnginePayload.CODEC);
registerRenderLayer(); registerRenderLayer();
ClientPlayConnectionEvents.INIT.register((handler, client) -> initChannel(handler)); ClientConfigurationConnectionEvents.START.register(CraftEngineFabricModClient::initChannel);
} }
public static void registerRenderLayer() { 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 (block instanceof CustomBlock customBlock) {
BlockRenderLayerMap.INSTANCE.putBlock(block, RenderLayer.getCutoutMipped()); if (customBlock.isTransparent()) {
BlockRenderLayerMap.INSTANCE.putBlock(customBlock, RenderLayer.getCutoutMipped());
}
if (id.getPath().contains("leaves")) { if (id.getPath().contains("leaves")) {
registerColor(block); registerColor(block);
} }
@@ -59,30 +57,15 @@ public class CraftEngineFabricModClient implements ClientModInitializer {
); );
} }
private static void initChannel(ClientPlayNetworkHandler handler) { private static void initChannel(ClientConfigurationNetworkHandler handler, MinecraftClient client) {
if (ModConfig.enableNetwork) { if (ModConfig.enableNetwork) {
registerChannel(handler); registerChannel(handler);
} else { } else {
ClientPlayNetworking.unregisterGlobalReceiver(CraftEnginePayload.ID.id()); ClientConfigurationNetworking.unregisterGlobalReceiver(CraftEnginePayload.ID);
} }
} }
private static void registerChannel(ClientPlayNetworkHandler handler) { private static void registerChannel(ClientConfigurationNetworkHandler handler) {
ClientPlayNetworking.registerGlobalReceiver(CraftEnginePayload.ID, (payload, context) -> { ClientConfigurationNetworking.send(new CraftEnginePayload((":" + Block.STATE_IDS.size() + ":init").getBytes(StandardCharsets.UTF_8)));
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

@@ -0,0 +1,35 @@
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,6 +1,6 @@
package net.momirealms.craftengine.fabric.client.network; package net.momirealms.craftengine.fabric.client.network;
import net.minecraft.network.RegistryByteBuf; import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.codec.PacketCodec; import net.minecraft.network.codec.PacketCodec;
import net.minecraft.network.packet.CustomPayload; import net.minecraft.network.packet.CustomPayload;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
@@ -8,10 +8,9 @@ import net.minecraft.util.Identifier;
public record CraftEnginePayload(byte[] data) implements CustomPayload { public record CraftEnginePayload(byte[] data) implements CustomPayload {
public static final Identifier CRAFTENGINE_PAYLOAD = Identifier.of("craftengine", "payload"); public static final Identifier CRAFTENGINE_PAYLOAD = Identifier.of("craftengine", "payload");
public static final Id<CraftEnginePayload> ID = new Id<>(CraftEnginePayload.CRAFTENGINE_PAYLOAD); public static final Id<CraftEnginePayload> ID = new Id<>(CraftEnginePayload.CRAFTENGINE_PAYLOAD);
public static final PacketCodec<RegistryByteBuf, CraftEnginePayload> CODEC = PacketCodec.tuple( public static final PacketCodec<PacketByteBuf, CraftEnginePayload> CODEC = PacketCodec.of(
new ByteArrayCodec(), CraftEnginePayload::data, (payload, byteBuf) -> byteBuf.writeByteArray(payload.data()),
CraftEnginePayload::new buf -> new CraftEnginePayload(buf.readByteArray()));
);
@Override @Override
public Id<? extends CustomPayload> getId() { public Id<? extends CustomPayload> getId() {

View File

@@ -3,6 +3,7 @@ package net.momirealms.craftengine.fabric;
import net.fabricmc.api.ModInitializer; 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.block.piston.PistonBehavior;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
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;
@@ -38,7 +39,9 @@ public class CraftEngineFabricMod implements ModInitializer {
RegisterBlocks.register( RegisterBlocks.register(
replacedBlockId.getPath() + "_" + i, replacedBlockId.getPath() + "_" + i,
BlockUtils.canPassThrough(blockState), BlockUtils.canPassThrough(blockState),
BlockUtils.getShape(blockState) BlockUtils.getShape(blockState),
BlockUtils.isTransparent(blockState),
BlockUtils.canPush(blockState)
); );
} }
} }

View File

@@ -3,6 +3,8 @@ 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.BlockState;
import net.minecraft.block.TransparentBlock;
import net.minecraft.block.piston.PistonBehavior;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.shape.VoxelShape; import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes; import net.minecraft.util.shape.VoxelShapes;
@@ -63,4 +65,20 @@ public class BlockUtils {
return VoxelShapes.fullCube(); 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

@@ -2,25 +2,29 @@ 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.piston.PistonBehavior;
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.VoxelShape;
import net.minecraft.util.shape.VoxelShapes; import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import net.momirealms.craftengine.fabric.CraftEngineFabricMod; import net.momirealms.craftengine.fabric.CraftEngineFabricMod;
import net.momirealms.craftengine.fabric.client.blocks.CustomBlock;
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, VoxelShape outlineShape) { public static Block register(String name, boolean canPassThrough,
AbstractBlock.Settings settings = Block.Settings.create().nonOpaque().strength(-1.0F, 3600000.0F); VoxelShape outlineShape, boolean isTransparent,
int canPush) {
AbstractBlock.Settings settings = Block.Settings.create()
.nonOpaque()
.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; VoxelShape collisionShape;
if (canPassThrough) { if (canPassThrough) {
collisionShape = VoxelShapes.empty(); collisionShape = VoxelShapes.empty();
@@ -28,7 +32,7 @@ public class RegisterBlocks {
} else { } else {
collisionShape = outlineShape; collisionShape = outlineShape;
} }
return register(name, (settingsParam) -> new CustomBlock(settingsParam, outlineShape, collisionShape), settings); 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) { public static Block register(String name, Function<AbstractBlock.Settings, Block> blockFactory, AbstractBlock.Settings settings) {
@@ -44,23 +48,3 @@ 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

@@ -27,7 +27,7 @@
"depends": { "depends": {
"fabricloader": ">=${loader_version}", "fabricloader": ">=${loader_version}",
"fabric": "*", "fabric": "*",
"minecraft": "${minecraft_version}", "minecraft": ">=${minecraft_version}",
"modmenu": ">=${modmenu_version}", "modmenu": ">=${modmenu_version}",
"cloth-config": ">=${cloth_version}" "cloth-config": ">=${cloth_version}"
} }

View File

@@ -6,6 +6,7 @@ import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.loot.LootTable;
import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.locale.I18NData;
import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.shared.block.BlockBehavior; import net.momirealms.craftengine.shared.block.BlockBehavior;
@@ -14,10 +15,7 @@ import net.momirealms.sparrow.nbt.Tag;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction; import java.util.function.BiFunction;
public abstract class CustomBlock { public abstract class CustomBlock {
@@ -30,6 +28,8 @@ public abstract class CustomBlock {
protected final ImmutableBlockState defaultState; protected final ImmutableBlockState defaultState;
@Nullable @Nullable
protected final LootTable<?> lootTable; protected final LootTable<?> lootTable;
private Map<String, I18NData> blockName = new HashMap<>();
public CustomBlock( public CustomBlock(
@NotNull Key id, @NotNull Key id,
@@ -159,4 +159,19 @@ public abstract class CustomBlock {
} }
return state; return state;
} }
public Map<String, I18NData> blockName() {
return blockName;
}
public void addBlockName(String lang, I18NData i18NData) {
if (this.blockName == null) {
this.blockName = new HashMap<>();
}
this.blockName.put(lang, i18NData);
}
public void setBlockName(Map<String, I18NData> blockName) {
this.blockName = blockName;
}
} }

View File

@@ -27,6 +27,8 @@ public abstract class Player extends Entity implements NetWorkUser {
public abstract void stopMiningBlock(); public abstract void stopMiningBlock();
public abstract void preventMiningBlock();
public abstract void abortMiningBlock(); public abstract void abortMiningBlock();
public abstract double getInteractionRange(); public abstract double getInteractionRange();

View File

@@ -24,6 +24,7 @@ import net.momirealms.craftengine.core.plugin.gui.category.ItemBrowserManagerImp
import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.plugin.locale.TranslationManager;
import net.momirealms.craftengine.core.plugin.locale.TranslationManagerImpl; import net.momirealms.craftengine.core.plugin.locale.TranslationManagerImpl;
import net.momirealms.craftengine.core.plugin.logger.PluginLogger; import net.momirealms.craftengine.core.plugin.logger.PluginLogger;
import net.momirealms.craftengine.core.plugin.logger.filter.DisconnectLogFilter;
import net.momirealms.craftengine.core.plugin.logger.filter.LogFilter; import net.momirealms.craftengine.core.plugin.logger.filter.LogFilter;
import net.momirealms.craftengine.core.plugin.network.NetworkManager; import net.momirealms.craftengine.core.plugin.network.NetworkManager;
import net.momirealms.craftengine.core.plugin.scheduler.SchedulerAdapter; import net.momirealms.craftengine.core.plugin.scheduler.SchedulerAdapter;
@@ -72,6 +73,7 @@ public abstract class CraftEngine implements Plugin {
@Override @Override
public void load() { public void load() {
((org.apache.logging.log4j.core.Logger) LogManager.getRootLogger()).addFilter(new LogFilter()); ((org.apache.logging.log4j.core.Logger) LogManager.getRootLogger()).addFilter(new LogFilter());
((org.apache.logging.log4j.core.Logger) LogManager.getRootLogger()).addFilter(new DisconnectLogFilter());
this.dependencyManager = new DependencyManagerImpl(this); this.dependencyManager = new DependencyManagerImpl(this);
ArrayList<Dependency> dependenciesToLoad = new ArrayList<>(); ArrayList<Dependency> dependenciesToLoad = new ArrayList<>();
dependenciesToLoad.addAll(commonDependencies()); dependenciesToLoad.addAll(commonDependencies());

View File

@@ -41,6 +41,7 @@ public class ConfigManager implements Reloadable {
protected boolean debug; protected boolean debug;
protected boolean checkUpdate; protected boolean checkUpdate;
protected boolean metrics; protected boolean metrics;
protected boolean filterConfigurationPhaseDisconnect;
protected boolean resource_pack$generate_mod_assets; protected boolean resource_pack$generate_mod_assets;
protected boolean resource_pack$override_uniform_font; protected boolean resource_pack$override_uniform_font;
@@ -181,6 +182,7 @@ public class ConfigManager implements Reloadable {
debug = config.getBoolean("debug", false); debug = config.getBoolean("debug", false);
metrics = config.getBoolean("metrics", false); metrics = config.getBoolean("metrics", false);
checkUpdate = config.getBoolean("update-checker", false); checkUpdate = config.getBoolean("update-checker", false);
filterConfigurationPhaseDisconnect = config.getBoolean("filter-configuration-phase-disconnect", false);
// resource pack // resource pack
resource_pack$override_uniform_font = config.getBoolean("resource-pack.override-uniform-font", false); resource_pack$override_uniform_font = config.getBoolean("resource-pack.override-uniform-font", false);
@@ -309,6 +311,10 @@ public class ConfigManager implements Reloadable {
return instance.metrics; return instance.metrics;
} }
public static boolean filterConfigurationPhaseDisconnect() {
return instance.filterConfigurationPhaseDisconnect;
}
public static boolean resourcePack$overrideUniform() { public static boolean resourcePack$overrideUniform() {
return instance.resource_pack$override_uniform_font; return instance.resource_pack$override_uniform_font;
} }

View File

@@ -67,6 +67,12 @@ public class ClientLangMangerImpl implements ClientLangManager {
@Override @Override
public Map<String, I18NData> langData() { public Map<String, I18NData> langData() {
this.plugin.blockManager().blocks().forEach((key, block) -> {
Map<String, I18NData> blockName = block.blockName();
if (blockName != null) {
I18NData.merge(i18nData, blockName);
}
});
return Collections.unmodifiableMap(i18nData); return Collections.unmodifiableMap(i18nData);
} }
} }

View File

@@ -20,4 +20,20 @@ public class I18NData {
public String translate(String key) { public String translate(String key) {
return this.translations.get(key); return this.translations.get(key);
} }
@Override
public String toString() {
return "I18NData{" + translations + "}";
}
public static void merge(Map<String, I18NData> target, Map<String, I18NData> source) {
source.forEach((key, value) -> {
I18NData copy = new I18NData();
copy.addTranslations(value.translations);
target.merge(key, copy, (existing, newData) -> {
existing.addTranslations(newData.translations);
return existing;
});
});
}
} }

View File

@@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
public interface TranslationManager extends Reloadable, ConfigSectionParser { public interface TranslationManager extends Reloadable, ConfigSectionParser {
String CONFIG_SECTION_NAME = "i18n"; String CONFIG_SECTION_NAME = "i18n";
@@ -38,6 +39,8 @@ public interface TranslationManager extends Reloadable, ConfigSectionParser {
return locale == null || locale.isEmpty() ? null : Translator.parseLocale(locale); return locale == null || locale.isEmpty() ? null : Translator.parseLocale(locale);
} }
Map<Locale, I18NData> i18nData();
@Override @Override
default int loadingSequence() { default int loadingSequence() {
return LoadingSequence.TRANSLATION; return LoadingSequence.TRANSLATION;

View File

@@ -277,4 +277,9 @@ public class TranslationManagerImpl implements TranslationManager {
return newFileContents; return newFileContents;
} }
} }
@Override
public Map<Locale, I18NData> i18nData() {
return Collections.unmodifiableMap(this.i18nData);
}
} }

View File

@@ -0,0 +1,36 @@
package net.momirealms.craftengine.core.plugin.logger.filter;
import net.momirealms.craftengine.core.plugin.config.ConfigManager;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Node;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.filter.AbstractFilter;
import org.apache.logging.log4j.core.impl.MutableLogEvent;
@Plugin(name = "DisconnectLogFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE)
public class DisconnectLogFilter extends AbstractFilter {
private static final String TARGET_LOGGER = "net.minecraft.server.network.ServerConfigurationPacketListenerImpl";
private static final String TARGET_MESSAGE_PATTERN = "{} lost connection: {}";
@Override
public Result filter(LogEvent event) {
if (!ConfigManager.filterConfigurationPhaseDisconnect()) {
return Result.NEUTRAL;
}
if (!event.getLoggerName().equals(TARGET_LOGGER)) {
return Result.NEUTRAL;
}
if (event.getMessage() instanceof MutableLogEvent msg) {
String format = msg.getFormat();
if (TARGET_MESSAGE_PATTERN.equals(format)) {
return Result.DENY;
}
}
return Result.NEUTRAL;
}
}

View File

@@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G
# Project settings # Project settings
# Rule: [major update].[feature update].[bug fix] # Rule: [major update].[feature update].[bug fix]
project_version=0.0.39 project_version=0.0.39
config_version=17 config_version=18
lang_version=3 lang_version=3
project_group=net.momirealms project_group=net.momirealms
latest_minecraft_version=1.21.4 latest_minecraft_version=1.21.4