diff --git a/src/main/java/io/ib67/sfcraft/mixin/server/subserver/EntityMixin.java b/src/main/java/io/ib67/sfcraft/mixin/server/subserver/EntityMixin.java index 5680548..346d0ef 100644 --- a/src/main/java/io/ib67/sfcraft/mixin/server/subserver/EntityMixin.java +++ b/src/main/java/io/ib67/sfcraft/mixin/server/subserver/EntityMixin.java @@ -1,6 +1,7 @@ package io.ib67.sfcraft.mixin.server.subserver; import io.ib67.sfcraft.SFCraft; +import io.ib67.sfcraft.module.RoomModule; import io.ib67.sfcraft.registry.RoomRegistry; import io.ib67.sfcraft.util.Helper; import net.minecraft.entity.Entity; @@ -21,7 +22,7 @@ public abstract class EntityMixin { @Inject(at = @At("HEAD"), method = "teleportTo", cancellable = true) private void sf$redirectTeleport(TeleportTarget teleportTarget, CallbackInfoReturnable cir) { - if (Helper.isVirtual(this.getUuid())) { + if (RoomModule.isVirtual(this.getUuid())) { cir.setReturnValue((Entity) (Object) this); } } diff --git a/src/main/java/io/ib67/sfcraft/mixin/server/subserver/PlayerListS2CPacket$EntryMixin.java b/src/main/java/io/ib67/sfcraft/mixin/server/subserver/PlayerListS2CPacket$EntryMixin.java new file mode 100644 index 0000000..90ac8f4 --- /dev/null +++ b/src/main/java/io/ib67/sfcraft/mixin/server/subserver/PlayerListS2CPacket$EntryMixin.java @@ -0,0 +1,41 @@ +package io.ib67.sfcraft.mixin.server.subserver; + +import com.mojang.authlib.GameProfile; +import io.ib67.sfcraft.SFCraft; +import io.ib67.sfcraft.module.RoomModule; +import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; +import net.minecraft.server.network.ServerPlayerEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.UUID; + +@Mixin(PlayerListS2CPacket.Entry.class) +public class PlayerListS2CPacket$EntryMixin { + @Unique + private static final byte[] lock = new byte[0]; + @Unique + private static volatile RoomModule module; + + @Unique + private static RoomModule getModule() { + if (module == null) { + synchronized (lock) { + if (module == null) { + module = SFCraft.getInjector().getInstance(RoomModule.class); + } + } + } + return module; + } + + @Redirect(method = "(Lnet/minecraft/server/network/ServerPlayerEntity;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayerEntity;getGameProfile()Lcom/mojang/authlib/GameProfile;")) + private static GameProfile sf$redirectGameProfileForRoom(ServerPlayerEntity instance) { + if (!RoomModule.isVirtual(instance.getUuid())) { + return instance.getGameProfile(); + } + return getModule().devirtualize(instance.getUuid()); + } +} diff --git a/src/main/java/io/ib67/sfcraft/mixin/server/subserver/PlayerSaveHandlerMixin.java b/src/main/java/io/ib67/sfcraft/mixin/server/subserver/PlayerSaveHandlerMixin.java index 97e6491..a58ec5c 100644 --- a/src/main/java/io/ib67/sfcraft/mixin/server/subserver/PlayerSaveHandlerMixin.java +++ b/src/main/java/io/ib67/sfcraft/mixin/server/subserver/PlayerSaveHandlerMixin.java @@ -1,6 +1,7 @@ package io.ib67.sfcraft.mixin.server.subserver; import com.mojang.datafixers.DataFixer; +import io.ib67.sfcraft.module.RoomModule; import io.ib67.sfcraft.util.Helper; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.WorldSavePath; @@ -33,7 +34,7 @@ public class PlayerSaveHandlerMixin { @Redirect(at = @At(value = "FIELD", target = "Lnet/minecraft/world/PlayerSaveHandler;playerDataDir:Ljava/io/File;"), method = "savePlayerData") private File sf$getPlayerDataFolder(PlayerSaveHandler instance, PlayerEntity entity) { - if (Helper.isVirtual(entity.getUuid())) { + if (RoomModule.isVirtual(entity.getUuid())) { return virtualPlayerFolder; } else { return this.playerDataDir; @@ -42,7 +43,7 @@ public class PlayerSaveHandlerMixin { @Redirect(at = @At(value = "FIELD", target = "Lnet/minecraft/world/PlayerSaveHandler;playerDataDir:Ljava/io/File;"), method = "loadPlayerData(Lnet/minecraft/entity/player/PlayerEntity;Ljava/lang/String;)Ljava/util/Optional;") private File sf$saveGetPlayerFolder(PlayerSaveHandler instance, PlayerEntity player) { - if (Helper.isVirtual(player.getUuid())) { + if (RoomModule.isVirtual(player.getUuid())) { return virtualPlayerFolder; } else { return this.playerDataDir; diff --git a/src/main/java/io/ib67/sfcraft/module/RoomModule.java b/src/main/java/io/ib67/sfcraft/module/RoomModule.java index ad7a675..d350a00 100644 --- a/src/main/java/io/ib67/sfcraft/module/RoomModule.java +++ b/src/main/java/io/ib67/sfcraft/module/RoomModule.java @@ -10,7 +10,6 @@ import io.ib67.sfcraft.config.SFConfig; import io.ib67.sfcraft.inject.MinecraftServerSupplier; import io.ib67.sfcraft.room.RequestedRoom; import io.ib67.sfcraft.registry.RoomRegistry; -import io.ib67.sfcraft.util.Helper; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import lombok.SneakyThrows; @@ -24,7 +23,6 @@ import net.minecraft.network.packet.s2c.common.StoreCookieS2CPacket; import net.minecraft.registry.RegistryKey; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.world.ChunkTicket; import net.minecraft.server.world.ChunkTicketType; import net.minecraft.text.Text; import net.minecraft.util.Identifier; @@ -40,10 +38,11 @@ import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; import java.security.Key; import java.security.spec.KeySpec; -import java.util.ArrayList; -import java.util.List; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import static io.ib67.sfcraft.room.RoomTeleporter.ROOM_COOKIE; import static io.ib67.sfcraft.util.SFConsts.COMMAND_RECO; @@ -59,6 +58,7 @@ public class RoomModule extends ServerModule { private SFConfig config; private Key key; private final List, BlockPos>> pregenQueue = new ArrayList<>(); + private final Map uuidMapper = new ConcurrentHashMap<>(); @Override public void onInitialize() { @@ -70,11 +70,11 @@ public class RoomModule extends ServerModule { public void onEnable() { for (Pair, BlockPos> registryKeyBlockPosPair : pregenQueue) { var world = serverSupplier.get().getWorld(registryKeyBlockPosPair.getLeft()); - if(world == null){ - log.warn("Cannot find world "+registryKeyBlockPosPair.getLeft()); + if (world == null) { + log.warn("Cannot find world " + registryKeyBlockPosPair.getLeft()); continue; } - world.getChunkManager().addTicket(ChunkTicketType.START,new ChunkPos(registryKeyBlockPosPair.getRight()),64, Unit.INSTANCE); + world.getChunkManager().addTicket(ChunkTicketType.START, new ChunkPos(registryKeyBlockPosPair.getRight()), 64, Unit.INSTANCE); } } @@ -88,7 +88,7 @@ public class RoomModule extends ServerModule { private int onCleanReconnect(CommandContext serverCommandSourceCommandContext) { var player = serverCommandSourceCommandContext.getSource().getPlayer(); - if (!Helper.isVirtual(player.getUuid())) { + if (!isVirtual(player.getUuid())) { player.sendMessage(Text.literal("你不在任何 \"房间\" 内。")); return 0; } @@ -161,4 +161,19 @@ public class RoomModule extends ServerModule { public void enqueuePregen(RegistryKey world, BlockPos spawnPos) { pregenQueue.add(new Pair<>(world, spawnPos)); } + + public UUID generateIdForRoom(GameProfile issuer, String name, Identifier room) { + var uuid = UUID.nameUUIDFromBytes((name + "@" + room.toString()).getBytes(StandardCharsets.UTF_8)); + var result = new UUID(uuid.getMostSignificantBits(), 0); + if (issuer != null) uuidMapper.put(result, issuer); + return result; + } + + public static boolean isVirtual(UUID uuid) { + return uuid.getLeastSignificantBits() == 0; + } + + public GameProfile devirtualize(UUID virtual) { + return uuidMapper.get(virtual); + } } diff --git a/src/main/java/io/ib67/sfcraft/room/RoomTeleporter.java b/src/main/java/io/ib67/sfcraft/room/RoomTeleporter.java index 01bc09d..bd42baf 100644 --- a/src/main/java/io/ib67/sfcraft/room/RoomTeleporter.java +++ b/src/main/java/io/ib67/sfcraft/room/RoomTeleporter.java @@ -28,13 +28,13 @@ public class RoomTeleporter { public static final Identifier ROOM_COOKIE = Identifier.of("sfcraft", "room"); public void teleportTo(Room room, ServerPlayerEntity player) { - if (Helper.isVirtual(player.getUuid())) { + if (roomModule.isVirtual(player.getUuid())) { player.sendMessage(Text.literal("您已经在某个房间里了").withColor(Colors.LIGHT_RED)); return; } - var finalUuid = Helper.generateIdForRoom(player.getName().getLiteralString(), room.getServerIdentifier()); + var finalUuid = roomModule.generateIdForRoom(player.getGameProfile(), player.getName().getLiteralString(), room.getServerIdentifier()); var sess = room.getPlayerManager().createSessionFor(finalUuid); - if(player.getServer().getWorld(sess.getSpawnPosition().dimension()) == null){ + if (player.getServer().getWorld(sess.getSpawnPosition().dimension()) == null) { throw new IllegalStateException("world isn't exist"); } var networkHandler = player.networkHandler; diff --git a/src/main/java/io/ib67/sfcraft/util/Helper.java b/src/main/java/io/ib67/sfcraft/util/Helper.java index e69d289..2e751b0 100644 --- a/src/main/java/io/ib67/sfcraft/util/Helper.java +++ b/src/main/java/io/ib67/sfcraft/util/Helper.java @@ -117,13 +117,4 @@ public class Helper { } return q[0] + "." + q[1] + ".*.*"; } - - public static UUID generateIdForRoom(String name, Identifier room) { - var uuid = UUID.nameUUIDFromBytes((name + "@" + room.toString()).getBytes(StandardCharsets.UTF_8)); - return new UUID(uuid.getMostSignificantBits(), 0); - } - - public static boolean isVirtual(UUID uuid) { - return uuid.getLeastSignificantBits() == 0; - } } diff --git a/src/main/resources/sfcraft.mixins.json b/src/main/resources/sfcraft.mixins.json index d135131..0e373c2 100644 --- a/src/main/resources/sfcraft.mixins.json +++ b/src/main/resources/sfcraft.mixins.json @@ -31,7 +31,8 @@ "server.subserver.EntityMixin", "server.subserver.PlayerManagerMixin", "server.subserver.PlayerSaveHandlerMixin", - "server.subserver.ServerPlayerEntityMixin" + "server.subserver.ServerPlayerEntityMixin", + "server.subserver.PlayerListS2CPacket$EntryMixin" ], "injectors": { "defaultRequire": 1