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:
@@ -8,6 +8,8 @@ metrics: true
|
||||
update-checker: true
|
||||
# Forces a specific locale (e.g., zh_cn)
|
||||
forced-locale: ''
|
||||
# Filter configuration phase player disconnection logs
|
||||
filter-configuration-phase-disconnect: false
|
||||
|
||||
resource-pack:
|
||||
# Should those images in minecraft:default font also work in minecraft:uniform
|
||||
|
||||
@@ -12,6 +12,7 @@ items#misc:
|
||||
behavior:
|
||||
type: block_item
|
||||
block:
|
||||
name: "i18n:item.chinese_lantern"
|
||||
loot:
|
||||
template: "default:loot_table/basic"
|
||||
arguments:
|
||||
@@ -53,6 +54,7 @@ items#misc:
|
||||
behavior:
|
||||
type: block_item
|
||||
block:
|
||||
name: "i18n:item.netherite_anvil"
|
||||
loot:
|
||||
template: "default:loot_table/basic"
|
||||
arguments:
|
||||
|
||||
@@ -42,6 +42,7 @@ items:
|
||||
|
||||
blocks:
|
||||
default:topaz_ore:
|
||||
name: "i18n:item.topaz_ore"
|
||||
loot:
|
||||
template: "default:loot_table/ore"
|
||||
arguments:
|
||||
@@ -63,6 +64,7 @@ blocks:
|
||||
arguments:
|
||||
path: "minecraft:block/custom/topaz_ore"
|
||||
default:deepslate_topaz_ore:
|
||||
name: "i18n:item.deepslate_topaz_ore"
|
||||
loot:
|
||||
template: "default:loot_table/ore"
|
||||
arguments:
|
||||
|
||||
@@ -18,6 +18,7 @@ items:
|
||||
behavior:
|
||||
type: block_item
|
||||
block:
|
||||
name: "i18n:item.palm_log"
|
||||
behavior:
|
||||
type: strippable_block
|
||||
stripped: default:stripped_palm_log
|
||||
@@ -64,6 +65,7 @@ items:
|
||||
behavior:
|
||||
type: block_item
|
||||
block:
|
||||
name: "i18n:item.stripped_palm_log"
|
||||
loot:
|
||||
template: "default:loot_table/basic"
|
||||
arguments:
|
||||
@@ -107,6 +109,7 @@ items:
|
||||
behavior:
|
||||
type: block_item
|
||||
block:
|
||||
name: "i18n:item.palm_wood"
|
||||
behavior:
|
||||
type: strippable_block
|
||||
stripped: default:stripped_palm_wood
|
||||
@@ -153,6 +156,7 @@ items:
|
||||
behavior:
|
||||
type: block_item
|
||||
block:
|
||||
name: "i18n:item.stripped_palm_wood"
|
||||
loot:
|
||||
template: "default:loot_table/basic"
|
||||
arguments:
|
||||
@@ -195,6 +199,7 @@ items:
|
||||
behavior:
|
||||
type: block_item
|
||||
block:
|
||||
name: "i18n:item.palm_planks"
|
||||
settings:
|
||||
template: "default:settings/planks"
|
||||
overrides:
|
||||
@@ -225,6 +230,7 @@ items:
|
||||
behavior:
|
||||
type: block_item
|
||||
block:
|
||||
name: "i18n:item.palm_sapling"
|
||||
settings:
|
||||
template: "default:settings/sapling"
|
||||
overrides:
|
||||
@@ -287,6 +293,7 @@ items:
|
||||
behavior:
|
||||
type: block_item
|
||||
block:
|
||||
name: "i18n:item.palm_leaves"
|
||||
behavior:
|
||||
type: leaves_block
|
||||
loot:
|
||||
|
||||
@@ -25,6 +25,7 @@ items:
|
||||
block: default:reed
|
||||
blocks:
|
||||
default:fairy_flower:
|
||||
name: "i18n:item.fairy_flower"
|
||||
settings:
|
||||
template:
|
||||
- default:hardness/none
|
||||
@@ -64,6 +65,7 @@ blocks:
|
||||
"0": "minecraft:block/custom/fairy_flower_4"
|
||||
default:reed:
|
||||
settings:
|
||||
name: "i18n:item.reed"
|
||||
template:
|
||||
- default:hardness/none
|
||||
- default:sound/grass
|
||||
|
||||
@@ -452,7 +452,18 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
// create block
|
||||
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
|
||||
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) {
|
||||
for (ImmutableBlockState state : block.variantProvider().states()) {
|
||||
ImmutableBlockState previous = this.stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()];
|
||||
|
||||
@@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.block.*;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.loot.LootTable;
|
||||
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.util.Key;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.user.BukkitServerPlayer;
|
||||
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.network.ConnectionState;
|
||||
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.player.PlayerJoinEvent;
|
||||
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.Nullable;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class BukkitNetworkManager implements NetworkManager, Listener {
|
||||
public class BukkitNetworkManager implements NetworkManager, Listener, PluginMessageListener {
|
||||
private static BukkitNetworkManager instance;
|
||||
private static final Map<Class<?>, TriConsumer<NetWorkUser, NMSPacketEvent, Object>> nmsPacketFunctions = 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.SIGN_UPDATE, Reflections.clazz$ServerboundSignUpdatePacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.EDIT_BOOK, Reflections.clazz$ServerboundEditBookPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.CUSTOM_PAYLOAD, Reflections.clazz$ServerboundCustomPayloadPacket);
|
||||
registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket());
|
||||
registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket());
|
||||
registerByteBufPacketConsumer(PacketConsumers.LEVEL_PARTICLE, this.packetIds.clientboundLevelParticlesPacket());
|
||||
@@ -161,29 +160,21 @@ public class BukkitNetworkManager implements NetworkManager, Listener {
|
||||
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
|
||||
public Collection<BukkitServerPlayer> onlineUsers() {
|
||||
return onlineUsers.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
// 保留仅注册入频道用
|
||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte @NotNull [] message) {}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
if (init) return;
|
||||
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 serverConnection = Reflections.field$MinecraftServer$connection.get(server);
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -3,6 +3,8 @@ package net.momirealms.craftengine.bukkit.plugin.network;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
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.event.FurnitureBreakEvent;
|
||||
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.network.ConnectionState;
|
||||
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.world.BlockPos;
|
||||
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.Method;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
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 {
|
||||
|
||||
Object action = Reflections.field$ServerboundPlayerActionPacket$action.get(packet);
|
||||
if (action == Reflections.instance$ServerboundPlayerActionPacket$Action$START_DESTROY_BLOCK) {
|
||||
Object serverLevel = Reflections.field$CraftWorld$ServerLevel.get(world);
|
||||
@@ -306,6 +309,28 @@ public class PacketConsumers {
|
||||
}
|
||||
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));
|
||||
} else if (action == Reflections.instance$ServerboundPlayerActionPacket$Action$ABORT_DESTROY_BLOCK) {
|
||||
if (player.isMiningBlock()) {
|
||||
@@ -875,4 +900,43 @@ public class PacketConsumers {
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.util.*;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
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.Player;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
@@ -310,7 +311,8 @@ public class BukkitServerPlayer extends Player {
|
||||
if (custom && getDestroyProgress(state, pos) >= 1f) {
|
||||
assert immutableBlockState != null;
|
||||
// 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 {
|
||||
Object levelEventPacket = Reflections.constructor$ClientboundLevelEventPacket.newInstance(2001, LocationUtils.toBlockPos(pos), BlockStateUtils.blockStateToId(this.destroyedState), false);
|
||||
sendPacket(levelEventPacket, false);
|
||||
@@ -365,6 +367,13 @@ public class BukkitServerPlayer extends Player {
|
||||
setIsDestroyingBlock(false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preventMiningBlock() {
|
||||
setCanBreakBlock(false);
|
||||
setIsDestroyingBlock(false, false);
|
||||
abortMiningBlock();
|
||||
}
|
||||
|
||||
private void resetEffect(Object mobEffect) throws ReflectiveOperationException {
|
||||
Object effectInstance = Reflections.method$ServerPlayer$getEffect.invoke(serverPlayer(), mobEffect);
|
||||
Object packet;
|
||||
|
||||
@@ -5572,4 +5572,106 @@ public class Reflections {
|
||||
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
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,44 +2,42 @@ package net.momirealms.craftengine.fabric.client;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationConnectionEvents;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry;
|
||||
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.color.world.BiomeColors;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.ClientConfigurationNetworkHandler;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.network.DisconnectionInfo;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.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 java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Optional;
|
||||
|
||||
public class CraftEngineFabricModClient implements ClientModInitializer {
|
||||
public static final String MOD_ID = "craftengine";
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
PayloadTypeRegistry.playS2C().register(CraftEnginePayload.ID, CraftEnginePayload.CODEC);
|
||||
initChannel(MinecraftClient.getInstance().getNetworkHandler());
|
||||
PayloadTypeRegistry.configurationS2C().register(CraftEnginePayload.ID, CraftEnginePayload.CODEC);
|
||||
PayloadTypeRegistry.configurationC2S().register(CraftEnginePayload.ID, CraftEnginePayload.CODEC);
|
||||
registerRenderLayer();
|
||||
ClientPlayConnectionEvents.INIT.register((handler, client) -> initChannel(handler));
|
||||
ClientConfigurationConnectionEvents.START.register(CraftEngineFabricModClient::initChannel);
|
||||
}
|
||||
|
||||
public static void registerRenderLayer() {
|
||||
Registries.BLOCK.forEach(block -> {
|
||||
Identifier id = Registries.BLOCK.getId(block);
|
||||
if (id.getNamespace().equals(CraftEngineFabricModClient.MOD_ID)) {
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(block, RenderLayer.getCutoutMipped());
|
||||
if (block instanceof CustomBlock customBlock) {
|
||||
if (customBlock.isTransparent()) {
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(customBlock, RenderLayer.getCutoutMipped());
|
||||
}
|
||||
if (id.getPath().contains("leaves")) {
|
||||
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) {
|
||||
registerChannel(handler);
|
||||
} else {
|
||||
ClientPlayNetworking.unregisterGlobalReceiver(CraftEnginePayload.ID.id());
|
||||
ClientConfigurationNetworking.unregisterGlobalReceiver(CraftEnginePayload.ID);
|
||||
}
|
||||
}
|
||||
|
||||
private static void registerChannel(ClientPlayNetworkHandler handler) {
|
||||
ClientPlayNetworking.registerGlobalReceiver(CraftEnginePayload.ID, (payload, context) -> {
|
||||
byte[] data = payload.data();
|
||||
String decoded = new String(data, StandardCharsets.UTF_8);
|
||||
if (decoded.startsWith("cp:")) {
|
||||
int blockRegistrySize = Integer.parseInt(decoded.substring(3));
|
||||
if (Block.STATE_IDS.size() != blockRegistrySize) {
|
||||
handler.getConnection().disconnect(
|
||||
new DisconnectionInfo(
|
||||
Text.translatable("disconnect.craftengine.block_registry_mismatch", Block.STATE_IDS.size(), blockRegistrySize),
|
||||
Optional.of(FabricLoader.getInstance().getConfigDir().resolve("craft-engine-fabric-mod/mappings.yml")),
|
||||
Optional.of(URI.create("https://github.com/Xiao-MoMi/craft-engine"))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
private static void registerChannel(ClientConfigurationNetworkHandler handler) {
|
||||
ClientConfigurationNetworking.send(new CraftEnginePayload((":" + Block.STATE_IDS.size() + ":init").getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
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.packet.CustomPayload;
|
||||
import net.minecraft.util.Identifier;
|
||||
@@ -8,10 +8,9 @@ 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<RegistryByteBuf, CraftEnginePayload> CODEC = PacketCodec.tuple(
|
||||
new ByteArrayCodec(), CraftEnginePayload::data,
|
||||
CraftEnginePayload::new
|
||||
);
|
||||
public static final PacketCodec<PacketByteBuf, CraftEnginePayload> CODEC = PacketCodec.of(
|
||||
(payload, byteBuf) -> byteBuf.writeByteArray(payload.data()),
|
||||
buf -> new CraftEnginePayload(buf.readByteArray()));
|
||||
|
||||
@Override
|
||||
public Id<? extends CustomPayload> getId() {
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.momirealms.craftengine.fabric;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.piston.PistonBehavior;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.momirealms.craftengine.fabric.client.config.ModConfig;
|
||||
import net.momirealms.craftengine.fabric.util.BlockUtils;
|
||||
@@ -38,7 +39,9 @@ public class CraftEngineFabricMod implements ModInitializer {
|
||||
RegisterBlocks.register(
|
||||
replacedBlockId.getPath() + "_" + i,
|
||||
BlockUtils.canPassThrough(blockState),
|
||||
BlockUtils.getShape(blockState)
|
||||
BlockUtils.getShape(blockState),
|
||||
BlockUtils.isTransparent(blockState),
|
||||
BlockUtils.canPush(blockState)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ 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;
|
||||
@@ -63,4 +65,20 @@ public class BlockUtils {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,25 +2,29 @@ package net.momirealms.craftengine.fabric.util;
|
||||
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.ShapeContext;
|
||||
import net.minecraft.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.math.BlockPos;
|
||||
import net.minecraft.util.shape.VoxelShape;
|
||||
import net.minecraft.util.shape.VoxelShapes;
|
||||
import net.minecraft.world.BlockView;
|
||||
import net.momirealms.craftengine.fabric.CraftEngineFabricMod;
|
||||
import net.momirealms.craftengine.fabric.client.blocks.CustomBlock;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class RegisterBlocks {
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public static Block register(String name, boolean canPassThrough, VoxelShape outlineShape) {
|
||||
AbstractBlock.Settings settings = Block.Settings.create().nonOpaque().strength(-1.0F, 3600000.0F);
|
||||
public static Block register(String name, boolean canPassThrough,
|
||||
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;
|
||||
if (canPassThrough) {
|
||||
collisionShape = VoxelShapes.empty();
|
||||
@@ -28,7 +32,7 @@ public class RegisterBlocks {
|
||||
} else {
|
||||
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) {
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"depends": {
|
||||
"fabricloader": ">=${loader_version}",
|
||||
"fabric": "*",
|
||||
"minecraft": "${minecraft_version}",
|
||||
"minecraft": ">=${minecraft_version}",
|
||||
"modmenu": ">=${modmenu_version}",
|
||||
"cloth-config": ">=${cloth_version}"
|
||||
}
|
||||
|
||||
@@ -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.loot.LootTable;
|
||||
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.util.Key;
|
||||
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.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public abstract class CustomBlock {
|
||||
@@ -30,6 +28,8 @@ public abstract class CustomBlock {
|
||||
protected final ImmutableBlockState defaultState;
|
||||
@Nullable
|
||||
protected final LootTable<?> lootTable;
|
||||
private Map<String, I18NData> blockName = new HashMap<>();
|
||||
|
||||
|
||||
public CustomBlock(
|
||||
@NotNull Key id,
|
||||
@@ -159,4 +159,19 @@ public abstract class CustomBlock {
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ public abstract class Player extends Entity implements NetWorkUser {
|
||||
|
||||
public abstract void stopMiningBlock();
|
||||
|
||||
public abstract void preventMiningBlock();
|
||||
|
||||
public abstract void abortMiningBlock();
|
||||
|
||||
public abstract double getInteractionRange();
|
||||
|
||||
@@ -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.TranslationManagerImpl;
|
||||
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.network.NetworkManager;
|
||||
import net.momirealms.craftengine.core.plugin.scheduler.SchedulerAdapter;
|
||||
@@ -72,6 +73,7 @@ public abstract class CraftEngine implements Plugin {
|
||||
@Override
|
||||
public void load() {
|
||||
((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);
|
||||
ArrayList<Dependency> dependenciesToLoad = new ArrayList<>();
|
||||
dependenciesToLoad.addAll(commonDependencies());
|
||||
|
||||
@@ -41,6 +41,7 @@ public class ConfigManager implements Reloadable {
|
||||
protected boolean debug;
|
||||
protected boolean checkUpdate;
|
||||
protected boolean metrics;
|
||||
protected boolean filterConfigurationPhaseDisconnect;
|
||||
|
||||
protected boolean resource_pack$generate_mod_assets;
|
||||
protected boolean resource_pack$override_uniform_font;
|
||||
@@ -181,6 +182,7 @@ public class ConfigManager implements Reloadable {
|
||||
debug = config.getBoolean("debug", false);
|
||||
metrics = config.getBoolean("metrics", false);
|
||||
checkUpdate = config.getBoolean("update-checker", false);
|
||||
filterConfigurationPhaseDisconnect = config.getBoolean("filter-configuration-phase-disconnect", false);
|
||||
|
||||
// resource pack
|
||||
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;
|
||||
}
|
||||
|
||||
public static boolean filterConfigurationPhaseDisconnect() {
|
||||
return instance.filterConfigurationPhaseDisconnect;
|
||||
}
|
||||
|
||||
public static boolean resourcePack$overrideUniform() {
|
||||
return instance.resource_pack$override_uniform_font;
|
||||
}
|
||||
|
||||
@@ -67,6 +67,12 @@ public class ClientLangMangerImpl implements ClientLangManager {
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,4 +20,20 @@ public class I18NData {
|
||||
public String translate(String 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;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public interface TranslationManager extends Reloadable, ConfigSectionParser {
|
||||
String CONFIG_SECTION_NAME = "i18n";
|
||||
@@ -38,6 +39,8 @@ public interface TranslationManager extends Reloadable, ConfigSectionParser {
|
||||
return locale == null || locale.isEmpty() ? null : Translator.parseLocale(locale);
|
||||
}
|
||||
|
||||
Map<Locale, I18NData> i18nData();
|
||||
|
||||
@Override
|
||||
default int loadingSequence() {
|
||||
return LoadingSequence.TRANSLATION;
|
||||
|
||||
@@ -277,4 +277,9 @@ public class TranslationManagerImpl implements TranslationManager {
|
||||
return newFileContents;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Locale, I18NData> i18nData() {
|
||||
return Collections.unmodifiableMap(this.i18nData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G
|
||||
# Project settings
|
||||
# Rule: [major update].[feature update].[bug fix]
|
||||
project_version=0.0.39
|
||||
config_version=17
|
||||
config_version=18
|
||||
lang_version=3
|
||||
project_group=net.momirealms
|
||||
latest_minecraft_version=1.21.4
|
||||
|
||||
Reference in New Issue
Block a user