尝试修复配置不同步问题
This commit is contained in:
parent
790c55c4c0
commit
e5e46b3ee9
|
|
@ -71,6 +71,10 @@ legacyForge {
|
|||
server()
|
||||
systemProperty 'forge.enabledGameTestNamespaces', mod_id
|
||||
}
|
||||
gameTestServer {
|
||||
type = "gameTestServer"
|
||||
systemProperty 'forge.enabledGameTestNamespaces', mod_id
|
||||
}
|
||||
}
|
||||
mods {
|
||||
"${mod_id}" {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ mod_name=Leisure Time Dock Mod
|
|||
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
|
||||
mod_license=MIT
|
||||
# The mod version. See https://semver.org/
|
||||
mod_version=0.0.1.3
|
||||
mod_version=1.0.0
|
||||
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
|
||||
# This should match the base package used for the mod sources.
|
||||
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import com.leisuretimedock.crossmod.config.CrossServerConfigManager;
|
|||
import com.leisuretimedock.crossmod.command.PingCommand;
|
||||
import com.leisuretimedock.crossmod.network.NetworkHandler;
|
||||
import com.leisuretimedock.crossmod.network.PingRequestManager;
|
||||
import com.leisuretimedock.crossmod.network.toClient.GotoServerPayload;
|
||||
import com.leisuretimedock.crossmod.reset.ClientResetManager;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
|
@ -84,6 +83,7 @@ public class CrossTeleportMod {
|
|||
}
|
||||
@SubscribeEvent
|
||||
public static void onServerStop(ServerStoppedEvent event) {
|
||||
PingRequestManager.close();
|
||||
server = null;
|
||||
}
|
||||
public static ServerPlayer getPlayerByUUID(UUID uuid) {
|
||||
|
|
|
|||
|
|
@ -5,16 +5,12 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
|||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.renderer.entity.ItemRenderer;
|
||||
import net.minecraft.client.resources.language.I18n;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraftforge.client.gui.overlay.ForgeGui;
|
||||
import net.minecraftforge.client.gui.overlay.IGuiOverlay;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public class CrossServerTipOverLay implements IGuiOverlay {
|
||||
public static final CrossServerTipOverLay INSTANCE = new CrossServerTipOverLay();
|
||||
private static boolean showOverlay = false;
|
||||
|
|
@ -27,11 +23,10 @@ public class CrossServerTipOverLay implements IGuiOverlay {
|
|||
}
|
||||
@Override
|
||||
public void render(ForgeGui forgeGui, GuiGraphics guiGraphics, float v, int i, int i1) {
|
||||
if ( !showOverlay || mc.player == null || mc.level == null) return;
|
||||
if (isShowOverlay()) return;
|
||||
int x = 10;
|
||||
int y = 10;
|
||||
Font font = mc.font;
|
||||
ItemRenderer itemRenderer = mc.getItemRenderer();
|
||||
|
||||
// 1. 原版钟物品
|
||||
ItemStack clockStack = new ItemStack(Items.CLOCK);
|
||||
|
|
|
|||
|
|
@ -10,13 +10,12 @@ import net.minecraft.commands.Commands;
|
|||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class GotoServerCommand {
|
||||
public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
||||
LiteralArgumentBuilder<CommandSourceStack> main = Commands.literal("server")
|
||||
LiteralArgumentBuilder<CommandSourceStack> main = Commands.literal("cross")
|
||||
.requires(cs -> cs.hasPermission(2))
|
||||
.then(Commands.argument("players", EntityArgument.players())
|
||||
.then(Commands.literal("goto")
|
||||
|
|
|
|||
|
|
@ -53,7 +53,9 @@ public class CrossServerConfigManager {
|
|||
try {
|
||||
clear();
|
||||
servers.putAll(parseServer(CrossServerConfig.SERVER_LIST.get()));
|
||||
cacheHash = -1;
|
||||
cacheTag = serializeToNBT();
|
||||
log.debug("Configs reloaded");
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to reload configs", e);
|
||||
cacheHash = -1;
|
||||
|
|
@ -67,10 +69,15 @@ public class CrossServerConfigManager {
|
|||
*/
|
||||
public void clear() {
|
||||
servers.clear();
|
||||
cacheHash = -1;
|
||||
cacheTag = null;
|
||||
}
|
||||
|
||||
public synchronized CompoundTag serializeToNBT() {
|
||||
if (cacheHash == calculateConfigHash() && cacheTag != null) return cacheTag;
|
||||
int currentHash = calculateConfigHash();
|
||||
if (cacheTag != null && cacheHash == currentHash) {
|
||||
return cacheTag;
|
||||
}
|
||||
CompoundTag tag = new CompoundTag();
|
||||
serializeMap(tag, "servers", this.servers);
|
||||
cacheHash = calculateConfigHash();
|
||||
|
|
@ -80,7 +87,8 @@ public class CrossServerConfigManager {
|
|||
|
||||
private void serializeMap(CompoundTag parent, String key, @NotNull Map<String, String> map) {
|
||||
CompoundTag mapTag = new CompoundTag();
|
||||
for (Map.Entry<String,String> entry : map.entrySet()) {
|
||||
TreeMap<String, String> sortedMap = new TreeMap<>(map);
|
||||
for (Map.Entry<String, String> entry : sortedMap.entrySet()) {
|
||||
mapTag.putString(entry.getKey(), entry.getValue());
|
||||
}
|
||||
parent.put(key, mapTag);
|
||||
|
|
@ -93,16 +101,22 @@ public class CrossServerConfigManager {
|
|||
* @param tag the tag
|
||||
*/
|
||||
public void deserializeFromNBT(@NotNull CompoundTag tag) {
|
||||
cacheHash = -1;
|
||||
cacheTag = null;
|
||||
clear();
|
||||
deserializeMap(tag, "servers", servers);
|
||||
cacheTag = serializeToNBT();
|
||||
}
|
||||
|
||||
private void deserializeMap(@NotNull CompoundTag parent, String key, Map<String, String> map) {
|
||||
if (parent.contains(key)) {
|
||||
CompoundTag mapTag = parent.getCompound(key);
|
||||
TreeMap<String, String> tempMap = new TreeMap<>();
|
||||
for (String key_ : mapTag.getAllKeys()) {
|
||||
map.put(key_, mapTag.getString(key_));
|
||||
tempMap.put(key_, mapTag.getString(key_));
|
||||
}
|
||||
map.clear();
|
||||
map.putAll(tempMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -136,7 +150,8 @@ public class CrossServerConfigManager {
|
|||
public int calculateConfigHash() {
|
||||
// 使用FNV-1a哈希算法
|
||||
int hash = 0x811c9dc5; // FNV偏移基础值
|
||||
hash = fnv1aHashMap(hash, servers);
|
||||
TreeMap<String, String> sortedMap = new TreeMap<>(servers);
|
||||
hash = fnv1aHashMap(hash, sortedMap);
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
|
@ -155,6 +170,7 @@ public class CrossServerConfigManager {
|
|||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Broad hash packet.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -376,6 +376,11 @@ public final class PingRequestManager {
|
|||
}
|
||||
}
|
||||
|
||||
public static void close() {
|
||||
pingScheduler.shutdownNow();
|
||||
scheduler.shutdownNow();
|
||||
}
|
||||
|
||||
// ========== 数据结构 ==========
|
||||
|
||||
private static class PlayerPingData {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,11 @@ import lombok.extern.slf4j.Slf4j;
|
|||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
|
|
@ -19,7 +23,7 @@ public record SyncCommonConfigPacket(CompoundTag config, int hash) {
|
|||
* @param msg the msg
|
||||
* @param buf the buf
|
||||
*/
|
||||
public static void encode(SyncCommonConfigPacket msg, FriendlyByteBuf buf) {
|
||||
public static void encode(@NotNull SyncCommonConfigPacket msg, @NotNull FriendlyByteBuf buf) {
|
||||
buf.writeNbt(msg.config);
|
||||
buf.writeInt(msg.hash);
|
||||
}
|
||||
|
|
@ -30,7 +34,8 @@ public record SyncCommonConfigPacket(CompoundTag config, int hash) {
|
|||
* @param buf the buf
|
||||
* @return the packet eternal potato remove packet
|
||||
*/
|
||||
public static SyncCommonConfigPacket decode(FriendlyByteBuf buf) {
|
||||
@Contract("_ -> new")
|
||||
public static @NotNull SyncCommonConfigPacket decode(@NotNull FriendlyByteBuf buf) {
|
||||
return new SyncCommonConfigPacket(buf.readNbt(), buf.readInt());
|
||||
}
|
||||
|
||||
|
|
@ -40,16 +45,68 @@ public record SyncCommonConfigPacket(CompoundTag config, int hash) {
|
|||
* @param msg the msg
|
||||
* @param ctx the ctx
|
||||
*/
|
||||
public static void handle(SyncCommonConfigPacket msg, Supplier<NetworkEvent.Context> ctx) {
|
||||
public static void handle(SyncCommonConfigPacket msg, @NotNull Supplier<NetworkEvent.Context> ctx) {
|
||||
ctx.get().enqueueWork(() -> {
|
||||
CompoundTag old = CrossServerConfigManager.INSTANCE.serializeToNBT();
|
||||
CrossServerConfigManager.INSTANCE.deserializeFromNBT(msg.config);
|
||||
int newHashCode = CrossServerConfigManager.INSTANCE.calculateConfigHash();
|
||||
if (newHashCode != msg.hash) { //BACK
|
||||
log.error("Hash mismatch! Except:{}, Actual:{}", msg.hash, newHashCode);
|
||||
CrossServerConfigManager.INSTANCE.deserializeFromNBT(old);
|
||||
CrossServerConfigManager manager = CrossServerConfigManager.INSTANCE;
|
||||
|
||||
// 1. 保存当前配置(强制重新序列化,不使用缓存)
|
||||
CompoundTag currentConfig = manager.serializeToNBT();
|
||||
int currentHash = manager.calculateConfigHash();
|
||||
|
||||
// 2. 应用新配置
|
||||
manager.deserializeFromNBT(msg.config);
|
||||
|
||||
// 3. 验证哈希
|
||||
int newHash = manager.calculateConfigHash();
|
||||
if (newHash != msg.hash) {
|
||||
log.error("Hash mismatch! Expected: {}, Actual: {}", msg.hash, newHash);
|
||||
log.error("Current hash before deserialization: {}", currentHash);
|
||||
|
||||
// 打印差异详情
|
||||
if (currentConfig != null) {
|
||||
compareConfigs(currentConfig, msg.config);
|
||||
manager.deserializeFromNBT(currentConfig);
|
||||
}
|
||||
|
||||
// 验证恢复是否成功
|
||||
int restoredHash = manager.calculateConfigHash();
|
||||
if (restoredHash != currentHash) {
|
||||
log.error("Failed to restore config! Hash mismatch after rollback!");
|
||||
} else {
|
||||
log.info("Successfully rolled back to previous config");
|
||||
}
|
||||
} else {
|
||||
log.debug("Config sync successful, hash: {}", msg.hash);
|
||||
}
|
||||
});
|
||||
ctx.get().setPacketHandled(true);
|
||||
}
|
||||
|
||||
private static void compareConfigs(@NotNull CompoundTag oldConfig, @NotNull CompoundTag newConfig) {
|
||||
Set<String> oldKeys = oldConfig.getAllKeys();
|
||||
Set<String> newKeys = newConfig.getAllKeys();
|
||||
|
||||
// 找出只存在于旧配置的键
|
||||
for (String key : oldKeys) {
|
||||
if (!newConfig.contains(key)) {
|
||||
log.warn("Key only in old config: {}", key);
|
||||
}
|
||||
}
|
||||
|
||||
// 找出只存在于新配置的键
|
||||
for (String key : newKeys) {
|
||||
if (!oldConfig.contains(key)) {
|
||||
log.warn("Key only in new config: {}", key);
|
||||
}
|
||||
}
|
||||
|
||||
// 比较共同键的值
|
||||
for (String key : oldKeys) {
|
||||
if (newConfig.contains(key) && !Objects.equals(oldConfig.get(key), newConfig.get(key))) {
|
||||
log.warn("Value mismatch for key: {}", key);
|
||||
log.warn(" Old: {}", oldConfig.get(key));
|
||||
log.warn(" New: {}", newConfig.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user