diff --git a/src/main/java/com/manwe/dsl/config/DSLServerConfigs.java b/src/main/java/com/manwe/dsl/config/DSLServerConfigs.java index b7755e4..685cde6 100644 --- a/src/main/java/com/manwe/dsl/config/DSLServerConfigs.java +++ b/src/main/java/com/manwe/dsl/config/DSLServerConfigs.java @@ -2,6 +2,9 @@ import net.neoforged.neoforge.common.ModConfigSpec; +import java.net.InetAddress; +import java.util.List; + public class DSLServerConfigs { private static final ModConfigSpec.Builder BUILDER = new ModConfigSpec.Builder(); @@ -13,19 +16,28 @@ public class DSLServerConfigs { public static final ModConfigSpec.ConfigValue REGION_SIZE; public static final ModConfigSpec.ConfigValue WORKER_SIZE; + public static final ModConfigSpec.ConfigValue USE_ARBITER; + //public static final ModConfigSpec.ConfigValue> CONNECTIONS; static { - BUILDER.push("server"); - ARBITER_ADDR = BUILDER.comment("Complete address of the arbiter").define("arbiter_addr","http://localhost:8080"); + BUILDER.push("Server"); IS_PROXY = BUILDER.comment("Is this node a proxy? (only one can be the proxy)").define("is_proxy",true); WORKER_ID = BUILDER.comment("If false which worker id?").define("worker_id",1); BUILDER.pop(); - BUILDER.push("topology").comment("This values need to be equal in all nodes"); + BUILDER.push("Nodes").comment("This values need to be equal in all nodes"); WORKER_SIZE = BUILDER.comment("Number of workers").define("worker_size",1); REGION_SIZE = BUILDER.comment("Size of the smallest server in region cords. (1 Region = 32x32 chunks)").define("region_size",4); BUILDER.pop(); + BUILDER.push("Auto start").comment("Address assignment for workers"); + USE_ARBITER = BUILDER.comment("Use the arbiter").define("use_arbiter",true); + ARBITER_ADDR = BUILDER.comment("Complete address of the arbiter, This is ignored if use_arbiter = false").define("arbiter_addr","http://localhost:8080"); + //BUILDER.push("If proxy").comment("Connections to the workers"); + //CONNECTIONS = BUILDER.comment("").define("arbiter_addr","http://localhost:8080"); + //BUILDER.pop(); + BUILDER.pop(); + /* BUILDER.push("Into Pattern").comment( """ diff --git a/src/main/java/com/manwe/dsl/connectionRouting/Region.java b/src/main/java/com/manwe/dsl/connectionRouting/Region.java deleted file mode 100644 index d672418..0000000 --- a/src/main/java/com/manwe/dsl/connectionRouting/Region.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.manwe.dsl.connectionRouting; - -public class Region { - int region1X; - int region1Z; - - int region2X; - int region2Z; -} diff --git a/src/main/java/com/manwe/dsl/connectionRouting/RegionRouter.java b/src/main/java/com/manwe/dsl/connectionRouting/RegionRouter.java index 561d712..268de30 100644 --- a/src/main/java/com/manwe/dsl/connectionRouting/RegionRouter.java +++ b/src/main/java/com/manwe/dsl/connectionRouting/RegionRouter.java @@ -38,8 +38,9 @@ public class RegionRouter { private final EventLoopGroup ioGroup; //Topology information - private final int workerSize = DSLServerConfigs.WORKER_SIZE.get(); - private final int regionSize = DSLServerConfigs.REGION_SIZE.get(); + private static final int nWorkers = DSLServerConfigs.WORKER_SIZE.get(); + private static final int regionSize = DSLServerConfigs.REGION_SIZE.get(); + private static final int workerId = DSLServerConfigs.WORKER_ID.get(); public RegionRouter(ProxyDedicatedServer server){ this.ioGroup = new NioEventLoopGroup(1); //TODO especificar numero correcto de hilos @@ -48,7 +49,7 @@ public RegionRouter(ProxyDedicatedServer server){ //Create a tunnel for each worker for(ConnectionInfo connection : workers){ - WorkerTunnel tunnel = new WorkerTunnel(new InetSocketAddress(connection.ip(),connection.port()),this); + WorkerTunnel tunnel = new WorkerTunnel(new InetSocketAddress(connection.ip(),connection.port()),this,server); workerTunnels.put(connection.id(),tunnel); } } @@ -139,7 +140,9 @@ public static int computeWorkerId(double x, double z, int nWorkers, int regionSi } /** - * @return The ID of the server allocated to this position (in block coordinates) + * @param x block coordinates + * @param z block coordinates + * @return The ID of the server allocated to this position */ public static int computeWorkerId(int x, int z, int nWorkers, int regionSize){ if(nWorkers == 1) return 1; @@ -163,6 +166,59 @@ public static int computeWorkerId(int x, int z, int nWorkers, int regionSize){ return base + offset; } + /** + * @param x chunk coordinates + * @param z chunk coordinates + * @return The ID of the server allocated to this position + */ + public static boolean isChunkInWorkerDomain(int x, int z){ + if(nWorkers == 1) return true; + if (nWorkers == 2) return z >= 0 ? workerId == 1 : workerId == 2; + if (nWorkers % 4 != 0) throw new RuntimeException("Invalid number of workers n:"+nWorkers+". Valid numbers are 1, 2 or any other number divisible by 4"); + + //To file region cords 512*512 + int regionX = x >> 5; + int regionZ = z >> 5; + + int nWorkersCuad = nWorkers/4; + int quad = (regionX >= 0 ? 0 : 2) + (regionZ < 0 ? 1 : 0); + int base = quad * nWorkersCuad; //base id of the quad + + //Longest cord in abs + int maxSide = Math.max(Math.abs(regionX),Math.abs(regionZ)); + + int nRegions = maxSide / regionSize; + int offset = (nRegions == 0) ? 1 : (int) Math.floor(Math.log(nRegions) / Math.log(2)) + 2; + + return workerId == base + offset; + } + + /** + * @param pChunkPos long format of chunk coordinates + * @return The ID of the server allocated to this position + */ + public static boolean isChunkInWorkerDomain(long pChunkPos){ + //To file region cords 512*512 + int x = ((int) (pChunkPos)) >> 5; + int z = ((int) (pChunkPos >>> 32)) >> 5; + + if(nWorkers == 1) return true; + if (nWorkers == 2) return z >= 0 ? workerId == 1 : workerId == 2; + if (nWorkers % 4 != 0) throw new RuntimeException("Invalid number of workers n:"+nWorkers+". Valid numbers are 1, 2 or any other number divisible by 4"); + + int nWorkersCuad = nWorkers/4; + int quad = (x >= 0 ? 0 : 2) + (z < 0 ? 1 : 0); + int base = quad * nWorkersCuad; //base id of the quad + + //Longest cord in abs + int maxSide = Math.max(Math.abs(x),Math.abs(z)); + + int nRegions = maxSide / regionSize; + int offset = (nRegions == 0) ? 1 : (int) Math.floor(Math.log(nRegions) / Math.log(2)) + 2; + + return workerId == base + offset; + } + /** * @return The ID of the server that manages the spawn area */ diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/InternalGameProtocols.java b/src/main/java/com/manwe/dsl/dedicatedServer/InternalGameProtocols.java index a2f5104..139edaf 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/InternalGameProtocols.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/InternalGameProtocols.java @@ -1,14 +1,9 @@ package com.manwe.dsl.dedicatedServer; import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListener; -import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundPlayerTransferACKPacket; -import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundPlayerTransferPacket; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerInitPacket; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerDisconnectPacket; -import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundContainerPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.*; +import com.manwe.dsl.dedicatedServer.worker.packets.*; import com.manwe.dsl.dedicatedServer.worker.listeners.WorkerListener; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundContainerPacket; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerTransferPacket; import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.ProtocolInfo; @@ -21,6 +16,7 @@ public class InternalGameProtocols { .addPacket(InternalPacketTypes.PROXY_WORKER_CLIENT_LOGIN, WorkerBoundPlayerInitPacket.STREAM_CODEC) .addPacket(InternalPacketTypes.PROXY_WORKER_CLIENT_DISCONNECT, WorkerBoundPlayerDisconnectPacket.STREAM_CODEC) .addPacket(InternalPacketTypes.PROXY_WORKER_PLAYER_TRANSFER, WorkerBoundPlayerTransferPacket.STREAM_CODEC) + .addPacket(InternalPacketTypes.PROXY_WORKER_PLAYER_INIT_ACK, WorkerBoundPlayerInitACKPacket.STREAM_CODEC) ); public static final ProtocolInfo SERVERBOUND = SERVERBOUND_TEMPLATE.bind(FriendlyByteBuf::new); @@ -30,6 +26,8 @@ public class InternalGameProtocols { consumer.addPacket(InternalPacketTypes.WORKER_PROXY_PACKET_CONTAINER, ProxyBoundContainerPacket.STREAM_CODEC) .addPacket(InternalPacketTypes.WORKER_PROXY_PLAYER_TRANSFER, ProxyBoundPlayerTransferPacket.STREAM_CODEC) .addPacket(InternalPacketTypes.WORKER_PROXY_PLAYER_TRANSFER_ACK, ProxyBoundPlayerTransferACKPacket.STREAM_CODEC) + .addPacket(InternalPacketTypes.WORKER_PROXY_SAVE_PLAYER_STATE, ProxyBoundSavePlayerStatePacket.STREAM_CODEC) + .addPacket(InternalPacketTypes.WORKER_PROXY_PLAYER_INIT_ACK, ProxyBoundPlayerInitACKPacket.STREAM_CODEC) ); public static final ProtocolInfo CLIENTBOUND = CLIENTBOUND_TEMPLATE.bind(FriendlyByteBuf::new); diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/InternalPacketTypes.java b/src/main/java/com/manwe/dsl/dedicatedServer/InternalPacketTypes.java index dde54eb..3f2c930 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/InternalPacketTypes.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/InternalPacketTypes.java @@ -1,14 +1,9 @@ package com.manwe.dsl.dedicatedServer; import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListener; -import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundContainerPacket; -import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundPlayerTransferACKPacket; -import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundPlayerTransferPacket; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerInitPacket; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerDisconnectPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.*; +import com.manwe.dsl.dedicatedServer.worker.packets.*; import com.manwe.dsl.dedicatedServer.worker.listeners.WorkerListener; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundContainerPacket; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerTransferPacket; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.PacketFlow; import net.minecraft.network.protocol.PacketType; @@ -16,6 +11,7 @@ public class InternalPacketTypes { public static final PacketType PROXY_WORKER_CLIENT_LOGIN = createServerbound("worker_player_login"); + public static final PacketType PROXY_WORKER_PLAYER_INIT_ACK = createServerbound("worker_player_init_ack"); public static final PacketType PROXY_WORKER_CLIENT_DISCONNECT = createServerbound("worker_player_disconnect"); public static final PacketType PROXY_WORKER_PACKET_CONTAINER = createServerbound("worker_packet_container"); public static final PacketType PROXY_WORKER_PLAYER_TRANSFER = createServerbound("worker_player_transfer"); @@ -28,6 +24,8 @@ private static > PacketType createServerboun public static final PacketType WORKER_PROXY_PACKET_CONTAINER = createClientbound("proxy_packet_container"); public static final PacketType WORKER_PROXY_PLAYER_TRANSFER = createClientbound("proxy_player_transfer"); public static final PacketType WORKER_PROXY_PLAYER_TRANSFER_ACK = createClientbound("proxy_player_transfer_ack"); + public static final PacketType WORKER_PROXY_SAVE_PLAYER_STATE = createClientbound("proxy_save_player_state"); + public static final PacketType WORKER_PROXY_PLAYER_INIT_ACK = createClientbound("proxy_player_init_ack"); private static > PacketType createClientbound(String pId) { return new PacketType<>(PacketFlow.CLIENTBOUND, ResourceLocation.withDefaultNamespace(pId)); diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/ProxyDedicatedServer.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/ProxyDedicatedServer.java index faddd8d..1e8e3f5 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/ProxyDedicatedServer.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/ProxyDedicatedServer.java @@ -7,10 +7,12 @@ import com.manwe.dsl.config.DSLServerConfigs; import com.manwe.dsl.dedicatedServer.worker.LocalPlayerList; import com.manwe.dsl.mixin.accessors.DedicatedServerAccessor; +import com.manwe.dsl.mixin.accessors.EntityAccessor; import com.mojang.datafixers.DataFixer; import net.minecraft.*; import net.minecraft.server.*; import net.minecraft.server.dedicated.*; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.progress.ChunkProgressListenerFactory; import net.minecraft.server.packs.repository.PackRepository; import net.minecraft.server.players.GameProfileCache; @@ -39,9 +41,13 @@ public class ProxyDedicatedServer extends DedicatedServer { URI arbiterUri = URI.create(DSLServerConfigs.ARBITER_ADDR.get()); + boolean isProxy = DSLServerConfigs.IS_PROXY.get(); + int workerSize = DSLServerConfigs.WORKER_SIZE.get(); + int workerId = DSLServerConfigs.WORKER_ID.get(); ArbiterClient arbiterClient = new ArbiterClient(arbiterUri); private DedicatedPlayerList localRemotePlayerListRef; private ArbiterClient.ArbiterRes topology; + private static final int SHARD_MAX_ENTITIES = 1_000_000; public ProxyDedicatedServer(Thread pServerThread, LevelStorageSource.LevelStorageAccess pStorageSource, PackRepository pPackRepository, WorldStem pWorldStem, DedicatedServerSettings pSettings, DataFixer pFixerUpper, Services pServices, ChunkProgressListenerFactory pProgressListenerFactory) { super(pServerThread, pStorageSource, pPackRepository, pWorldStem, pSettings, pFixerUpper, pServices, pProgressListenerFactory); @@ -53,6 +59,18 @@ public ProxyDedicatedServer(Thread pServerThread, LevelStorageSource.LevelStorag @Override public boolean initServer() throws IOException { + try { + topology = arbiterClient.fetch(); + System.out.println("Port from Arbiter: "+topology.port); + } catch (Exception ex) { + DistributedServerLevels.LOGGER.error("Unexpected Error",ex); + throw new RuntimeException("Arbiter unavailable cannot fetch port and role"); + } + + if(!isProxy){ + EntityAccessor.getEntityCounter().set((workerId - 1) * SHARD_MAX_ENTITIES); //Set exclusive entity ids for each worker + } + Thread thread = new Thread("Server console handler") { @Override public void run() { @@ -100,16 +118,8 @@ public void run() { inetaddress = InetAddress.getByName(this.getLocalIp()); } - - try { - topology = arbiterClient.fetch(); - this.setPort(topology.port); - System.out.println("From Arbiter: "+topology.port); - } catch (Exception ex) { - DistributedServerLevels.LOGGER.error("Unexpected Error",ex); - throw new RuntimeException("Arbiter unavailable cannot fetch port and role"); - } - + //SET PORT + this.setPort(topology.port); this.initializeKeyPair(); DistributedServerLevels.LOGGER.info("Starting Minecraft server on {}:{}", this.getLocalIp().isEmpty() ? "*" : this.getLocalIp(), this.getPort()); @@ -146,7 +156,7 @@ public void run() { if (!OldUsersConverter.serverReadyAfterUserconversion(this)) { return false; } else { - if(DSLServerConfigs.IS_PROXY.get()){ + if(isProxy){ //Set RemotePlayerList localRemotePlayerListRef = new RemotePlayerList(this, this.registries(), this.playerDataStorage); }else { @@ -210,6 +220,12 @@ public void tickServer(BooleanSupplier pHasTimeLeft) { super.tickServer(pHasTimeLeft); } + @Override + public void tickChildren(BooleanSupplier pHasTimeLeft) { + //System.out.println("TICK CHILDREN"); + super.tickChildren(pHasTimeLeft); + } + public boolean isProxy(){ return DSLServerConfigs.IS_PROXY.get(); } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/RemotePlayerList.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/RemotePlayerList.java index 4b033d4..ab157aa 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/RemotePlayerList.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/RemotePlayerList.java @@ -11,7 +11,9 @@ import net.minecraft.ChatFormatting; import net.minecraft.core.LayeredRegistryAccess; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; import net.minecraft.network.Connection; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.chat.Component; @@ -31,8 +33,10 @@ import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.storage.LevelData; import net.minecraft.world.level.storage.PlayerDataStorage; +import net.minecraft.world.phys.Vec3; import java.util.*; +import java.util.concurrent.CompletableFuture; /** * Modified PlaceNewPlayer, set up RemoteServerGamePacketListenerImpl instead of ServerGamePacketListenerImpl @@ -51,6 +55,8 @@ public RemotePlayerList(DedicatedServer pServer, LayeredRegistryAccess optional1 = this.load(pPlayer); - ResourceKey resourcekey = optional1.>flatMap( - p_337568_ -> DimensionType.parseLegacy(new Dynamic<>(NbtOps.INSTANCE, p_337568_.get("Dimension"))).resultOrPartial(DistributedServerLevels.LOGGER::error) - ) - .orElse(Level.OVERWORLD); - ServerLevel serverlevel = proxyDedicatedServer.getLevel(resourcekey); - ServerLevel serverlevel1; - if (serverlevel == null) { - DistributedServerLevels.LOGGER.warn("Unknown respawn dimension {}, defaulting to overworld", resourcekey); - serverlevel1 = proxyDedicatedServer.overworld(); - } else { - serverlevel1 = serverlevel; + //System.out.println("placeNewPlayer Gameprofile: "+ gameprofile); + //System.out.println("placeNewPlayer player.Gameprofile: "+ pPlayer.getGameProfile()); + + //LOAD CUSTOM SAVE STATE IN PROXY + ResourceKey dim = null; + int workerId = 0; + Vec3 position = null; + + Optional nbtOpt = this.load(pPlayer); + if (nbtOpt.isPresent()) { + CompoundTag nbt = nbtOpt.get(); + + /* dimensión ----------------------------------------------------- */ + dim = DimensionType.parseLegacy(new Dynamic<>(NbtOps.INSTANCE, nbt.get("Dimension"))) + .resultOrPartial(DistributedServerLevels.LOGGER::error) + .orElse(Level.OVERWORLD); + + /* posición ------------------------------------------------------ */ + ListTag pos = nbt.getList("Pos", Tag.TAG_DOUBLE); + if (pos.size() == 3) { + double x = pos.getDouble(0); + double y = pos.getDouble(1); + double z = pos.getDouble(2); + position = new Vec3(x,y,z); + } + + /* worker -------------------------------------------------------- */ + if (nbt.contains("WorkerId", Tag.TAG_INT)) { + workerId = nbt.getInt("WorkerId"); + } } - /* - pPlayer.setServerLevel(serverlevel1); - String s1 = pConnection.getLoggableAddress(proxyDedicatedServer.logIPs()); - DistributedServerLevels.LOGGER.info( - "{}[{}] logged in with entity id {} at ({}, {}, {})", - pPlayer.getName().getString(), - s1, - pPlayer.getId(), - pPlayer.getX(), - pPlayer.getY(), - pPlayer.getZ() - ); - */ + //CUSTOM STATE LOADED + + ServerLevel serverlevel1 = dim != null ? proxyDedicatedServer.getLevel(dim) : proxyDedicatedServer.overworld(); LevelData leveldata = serverlevel1.getLevelData(); //pPlayer.loadGameTypes(optional1.orElse(null)); - if(!proxyDedicatedServer.isProxy())throw new RuntimeException("Worker cannot have a remotePlayerList"); + pPlayer.setServerLevel(serverlevel1); + if(position != null) { + pPlayer.setPos(position); + System.out.println("Loaded old position at "+ position); + } //Register this Client<->Proxy connection to be used by outgoing client packets from workers to clients. The proxy redirects these packets to the client. this.router.addOutgoingConnection(pPlayer.getUUID(),pConnection); //Create init message WorkerBoundPlayerInitPacket initPacket = new WorkerBoundPlayerInitPacket(pPlayer.getGameProfile(), pPlayer.clientInformation()); - //TODO guardar la posición de los jugadores al desconectarse para enrutarlos con el servidor correcto en caso de reinicio - //If this player has no worker set - if(!this.router.hasTunnel(pPlayer.getUUID())){ - //Set tunnel worker in default spawn position - System.out.println("This player has no tunnel set defaulting to server spawn"); + //Set worker for player if saved in disk + if(workerId != 0) this.router.transferClientToWorker(pPlayer.getUUID(),workerId); + + //If not Saved in memory + if(!this.router.hasTunnel(pPlayer.getUUID())){ //Default spawn position this.router.transferClientToWorker(pPlayer.getUUID(), RegionRouter.defaultSpawnWorkerId(getServer(), DSLServerConfigs.WORKER_SIZE.get(),DSLServerConfigs.REGION_SIZE.get())); + System.out.println("This player has no tunnel set defaulting to server spawn"); } - this.router.route(pPlayer.getUUID()).send(initPacket); //Send init to worker - - DistributedServerLevels.LOGGER.info("Broadcast player login to all workers"); + System.out.println("Has ["+pPlayer.getUUID()+"] tunnel "+this.router.hasTunnel(pPlayer.getUUID())); ProxyServerGameListener servergamepacketlistenerimpl = new ProxyServerGameListener(proxyDedicatedServer, pConnection, pPlayer, pCookie, this.router); - System.out.println("Proxy: ProxyServerGameListener"); pConnection.setupInboundProtocol( GameProtocols.SERVERBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(proxyDedicatedServer.registryAccess(), servergamepacketlistenerimpl.getConnectionType())), servergamepacketlistenerimpl ); - GameRules gamerules = serverlevel1.getGameRules(); - boolean flag = gamerules.getBoolean(GameRules.RULE_DO_IMMEDIATE_RESPAWN); - boolean flag1 = gamerules.getBoolean(GameRules.RULE_REDUCEDDEBUGINFO); - boolean flag2 = gamerules.getBoolean(GameRules.RULE_LIMITED_CRAFTING); - servergamepacketlistenerimpl.send( - new ClientboundLoginPacket( - pPlayer.getId(), - leveldata.isHardcore(), - proxyDedicatedServer.levelKeys(), - this.getMaxPlayers(), - this.getViewDistance(), - this.getSimulationDistance(), - flag1, - !flag, - flag2, - pPlayer.createCommonSpawnInfo(serverlevel1), - proxyDedicatedServer.enforceSecureProfile() - ) - ); - - //servergamepacketlistenerimpl.send(new ClientboundChangeDifficultyPacket(leveldata.getDifficulty(), leveldata.isDifficultyLocked())); - //servergamepacketlistenerimpl.send(new ClientboundPlayerAbilitiesPacket(pPlayer.getAbilities())); - //servergamepacketlistenerimpl.send(new ClientboundSetCarriedItemPacket(pPlayer.getInventory().selected)); - - net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.OnDatapackSyncEvent(this, pPlayer)); - //servergamepacketlistenerimpl.send(new ClientboundUpdateRecipesPacket(proxyDedicatedServer.getRecipeManager().getOrderedRecipes())); - //this.sendPlayerPermissionLevel(pPlayer); + //net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.OnDatapackSyncEvent(this, pPlayer)); pPlayer.getStats().markAllDirty(); - //pPlayer.getRecipeBook().sendInitialRecipeBook(pPlayer); - //this.updateEntireScoreboard(serverlevel1.getScoreboard(), pPlayer); proxyDedicatedServer.invalidateStatus(); - MutableComponent mutablecomponent; - if (pPlayer.getGameProfile().getName().equalsIgnoreCase(s)) { - mutablecomponent = Component.translatable("multiplayer.player.joined", pPlayer.getDisplayName()); - } else { - mutablecomponent = Component.translatable("multiplayer.player.joined.renamed", pPlayer.getDisplayName(), s); - } - this.broadcastSystemMessage(mutablecomponent.withStyle(ChatFormatting.YELLOW), false); - //servergamepacketlistenerimpl.teleport(pPlayer.getX(), pPlayer.getY(), pPlayer.getZ(), pPlayer.getYRot(), pPlayer.getXRot()); - ServerStatus serverstatus = proxyDedicatedServer.getStatus(); - if (serverstatus != null && !pCookie.transferred()) { - pPlayer.sendServerStatus(serverstatus); - } - - //pPlayer.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(((PlayerListAccessor) this).getPlayers())); - //((PlayerListAccessor) this).getPlayers().add(pPlayer); - //((PlayerListAccessor) this).getPlayersByUUID().put(pPlayer.getUUID(), pPlayer); - //this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(pPlayer))); - //this.sendLevelInfo(pPlayer, serverlevel1); - //serverlevel1.addNewPlayer(pPlayer); - //proxyDedicatedServer.getCustomBossEvents().onPlayerConnect(pPlayer); - //this.sendActivePlayerEffects(pPlayer); - /* - if (optional1.isPresent() && optional1.get().contains("RootVehicle", 10)) { - CompoundTag compoundtag = optional1.get().getCompound("RootVehicle"); - Entity entity = EntityType.loadEntityRecursive( - compoundtag.getCompound("Entity"), serverlevel1, p_215603_ -> !serverlevel1.addWithUUID(p_215603_) ? null : p_215603_ - ); - if (entity != null) { - UUID uuid; - if (compoundtag.hasUUID("Attach")) { - uuid = compoundtag.getUUID("Attach"); - } else { - uuid = null; - } - - if (entity.getUUID().equals(uuid)) { - pPlayer.startRiding(entity, true); - } else { - for (Entity entity1 : entity.getIndirectPassengers()) { - if (entity1.getUUID().equals(uuid)) { - pPlayer.startRiding(entity1, true); - break; - } - } - } - - if (!pPlayer.isPassenger()) { - DistributedServerLevels.LOGGER.warn("Couldn't reattach entity to player"); - entity.discard(); - - for (Entity entity2 : entity.getIndirectPassengers()) { - entity2.discard(); - } - } - } - } - pPlayer.initInventoryMenu(); - net.neoforged.neoforge.event.EventHooks.firePlayerLoggedIn( pPlayer ); - */ + this.router.route(pPlayer.getUUID()).send(initPacket); //Send init to worker } - } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/TeleportSyncHelper.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/TeleportSyncHelper.java new file mode 100644 index 0000000..a66f16b --- /dev/null +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/TeleportSyncHelper.java @@ -0,0 +1,47 @@ +package com.manwe.dsl.dedicatedServer.proxy; + +import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public final class TeleportSyncHelper { + + private TeleportSyncHelper() {} + + private static final Set UNSYNCED = ConcurrentHashMap.newKeySet(); + private static final Map PENDING_TPS = new ConcurrentHashMap<>(); + private static final Map> MOVES = new ConcurrentHashMap<>(); + + /* ----------- login ----------- */ + public static void markUnsynced(UUID p) { UNSYNCED.add(p); } + + /* ----------- worker ⇒ cliente (cada ClientboundPlayerPositionPacket) ----------- */ + public static void incPendingTeleports(UUID p) { + PENDING_TPS.merge(p, 1, Integer::sum); + } + + /* ----------- cliente ⇒ proxy (cada AcceptTeleport) ----------- */ + public static void ackTeleport(UUID p) { + PENDING_TPS.compute(p, (k,v) -> (v==null || v<=1) ? null : v-1); + // **NO** tocamos UNSYNCED aquí + } + + /* ----------- cliente ⇒ proxy (cada MovePlayer) ----------- */ + public static boolean mustQueue(UUID p) { + return UNSYNCED.contains(p) || PENDING_TPS.containsKey(p); + } + public static void queueMove(UUID p, ServerboundMovePlayerPacket pkt) { + MOVES.computeIfAbsent(p, k -> new ArrayDeque<>()).add(pkt); + } + + /** Llamar justo antes de reenviar un MovePlayer cuando `mustQueue==false`. */ + public static Deque drainMoves(UUID p) { + UNSYNCED.remove(p); // 1. salimos del modo inicial + return MOVES.remove(p); // 2. devuelve cola (puede ser null) + } + + public static void clear(UUID p){ + UNSYNCED.remove(p); PENDING_TPS.remove(p); MOVES.remove(p); + } +} \ No newline at end of file diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/WorkerTunnel.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/WorkerTunnel.java index 5525cea..f9dbf28 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/WorkerTunnel.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/WorkerTunnel.java @@ -1,6 +1,7 @@ package com.manwe.dsl.dedicatedServer.proxy; import com.manwe.dsl.connectionRouting.RegionRouter; +import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListener; import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListenerImpl; import com.manwe.dsl.dedicatedServer.InternalGameProtocols; import com.manwe.dsl.mixin.accessors.ConnectionAccessor; @@ -11,8 +12,11 @@ import io.netty.handler.flow.FlowControlHandler; import net.minecraft.network.*; import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.storage.LevelResource; import java.net.InetSocketAddress; +import java.nio.file.Path; /** * Cliente del Proxy hacia los workers @@ -22,10 +26,12 @@ public class WorkerTunnel { private final Connection connection; private final Channel channel; - public WorkerTunnel(InetSocketAddress workerAddress, RegionRouter router) { // para mandar C→S←W + public WorkerTunnel(InetSocketAddress workerAddress, RegionRouter router, MinecraftServer server) { // para mandar C→S←W System.out.println("WorkerTunnel Iniciado Cliente: Proxy -> Worker"); - this.workerAddress = workerAddress; + Path playerDir = server.getWorldPath(LevelResource.PLAYER_DATA_DIR); + + this.workerAddress = workerAddress; this.connection = new Connection(PacketFlow.CLIENTBOUND); this.channel = new Bootstrap() // Inicialización del cliente .group(router.getEventLoopGroup()) @@ -44,7 +50,7 @@ public WorkerTunnel(InetSocketAddress workerAddress, RegionRouter router) { pipeline.addLast("encoder", new PacketEncoder<>(InternalGameProtocols.SERVERBOUND)); connection.configurePacketHandler(pipeline); - ProxyListenerImpl listener = new ProxyListenerImpl(pipeline, router); + ProxyListenerImpl listener = new ProxyListenerImpl(pipeline, router,playerDir); ((ConnectionAccessor) connection).setPacketListener(listener); } @@ -79,6 +85,14 @@ public void setUpVannillaPlayProtocol(){ //connection.configurePacketHandler(connection.channel().pipeline()); } + /** + * Returns the packetListener for the incoming packets to this tunnel + */ + public ProxyListener getPacketListener(){ + if(!(connection.getPacketListener() instanceof ProxyListener conn)) throw new RuntimeException("PacketListener associated to this tunnel is not a ProxyListener"); + return conn; + } + public void sendDisconect(){ //TODO debería intentar mandar un paquete con la infraestructura de NeoForge } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/listeners/ProxyListener.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/listeners/ProxyListener.java index 5373aee..ceb9019 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/listeners/ProxyListener.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/listeners/ProxyListener.java @@ -1,17 +1,19 @@ package com.manwe.dsl.dedicatedServer.proxy.back.listeners; -import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundContainerPacket; -import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundPlayerTransferACKPacket; -import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundPlayerTransferPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.*; import net.minecraft.network.ClientboundPacketListener; import net.minecraft.network.ConnectionProtocol; +import java.util.UUID; + public interface ProxyListener extends ClientboundPacketListener { @Override default ConnectionProtocol protocol() { return ConnectionProtocol.PLAY; } + void addPendingLogin(UUID uuid, Runnable runnable); + /** * handle packets sent by workers * @param packet @@ -21,4 +23,8 @@ default ConnectionProtocol protocol() { void handlePlayerTransfer(ProxyBoundPlayerTransferPacket packet); void handlePlayerTransferACK(ProxyBoundPlayerTransferACKPacket packet); + + void handleSavePlayerState(ProxyBoundSavePlayerStatePacket packet); + + void handlePlayerInitACK(ProxyBoundPlayerInitACKPacket packet); } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/listeners/ProxyListenerImpl.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/listeners/ProxyListenerImpl.java index ce2675c..e5e75b0 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/listeners/ProxyListenerImpl.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/listeners/ProxyListenerImpl.java @@ -1,15 +1,29 @@ package com.manwe.dsl.dedicatedServer.proxy.back.listeners; +import com.manwe.dsl.DistributedServerLevels; import com.manwe.dsl.connectionRouting.RegionRouter; -import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundContainerPacket; -import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundPlayerTransferACKPacket; -import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundPlayerTransferPacket; +import com.manwe.dsl.dedicatedServer.proxy.TeleportSyncHelper; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.*; import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerDisconnectPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerInitACKPacket; import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerTransferPacket; import io.netty.channel.ChannelPipeline; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.DoubleTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtIo; import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.DisconnectionDetails; +import net.minecraft.network.protocol.common.CommonPacketTypes; +import net.minecraft.network.protocol.game.ClientboundPlayerPositionPacket; +import net.minecraft.network.protocol.game.GamePacketTypes; +import net.minecraft.world.phys.Vec3; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -22,13 +36,16 @@ public class ProxyListenerImpl implements ProxyListener { //Players transferring waiting for the handlePlayerTransferACK from the receiving worker private final Set pendingTransfers = ConcurrentHashMap.newKeySet(); + private final Map pendingLogin = new HashMap<>(); private final ChannelPipeline pipeline; //Proxy <-> Worker pipeline private final RegionRouter router; + private final Path playerDir; - public ProxyListenerImpl(ChannelPipeline pipeline, RegionRouter router) { + public ProxyListenerImpl(ChannelPipeline pipeline, RegionRouter router, Path playerDir) { this.pipeline = pipeline; this.router = router; + this.playerDir = playerDir; } @Override @@ -46,6 +63,16 @@ public ConnectionProtocol protocol() { return ProxyListener.super.protocol(); } + /** + * Delays this login code until the proxy receives the worker confirmation that it has created the player + * @param uuid Owner + * @param runnable Code + */ + @Override + public void addPendingLogin(UUID uuid, Runnable runnable){ + pendingLogin.put(uuid,runnable); + } + //////////////////////////////////////////////////// /// Internal message Listener Client Side /// /// These are the packets sent by the workers /// @@ -61,6 +88,9 @@ public void handleWorkerProxyPacket(ProxyBoundContainerPacket packet) { //System.out.println("Proxy - Handle - Paquete recibido en el Proxy"); //Obtener la connexion con el cliente //Mandar por esa conexión el paquete + if(packet.getPayload().type() == CommonPacketTypes.CLIENTBOUND_DISCONNECT){ + System.out.println("Client Bound Disconnect"); + } router.returnToClient(packet.getPlayerId(),packet.getPayload()); } @@ -86,4 +116,47 @@ public void handlePlayerTransferACK(ProxyBoundPlayerTransferACKPacket packet) { router.transferClientToWorker(packet.getPlayerId(),packet.getWorkerId());//Change to the new worker } + @Override + public void handleSavePlayerState(ProxyBoundSavePlayerStatePacket packet) { + Vec3 position = packet.getPosition(); + UUID playerId = packet.getPlayerId(); + + CompoundTag tag = new CompoundTag(); + + // dimensión + tag.putString("Dimension", packet.getDimension()); + + // posición (ListTag [X, Y, Z]) + ListTag posTag = new ListTag(); + posTag.add(DoubleTag.valueOf(position.x)); + posTag.add(DoubleTag.valueOf(position.y)); + posTag.add(DoubleTag.valueOf(position.z)); + tag.put("Pos", posTag); + + // campo extra (no vanilla) para el sistema distribuido + tag.putInt("WorkerId", packet.getWorkerId()); + + try { + Files.createDirectories(this.playerDir); + Path file = playerDir.resolve(playerId + ".dat"); + + // ¡Formato vanilla! (gzip + NBT sin envoltorio) + NbtIo.writeCompressed(tag, file); + + } catch (IOException ex) { + DistributedServerLevels.LOGGER.error("Couldn't save player-data for {}", playerId, ex); + } + + System.out.println("SAVED PLAYER STATE IN PROXY AFTER DISCONNECTION"); + } + + @Override + public void handlePlayerInitACK(ProxyBoundPlayerInitACKPacket packet) { + System.out.println("Received init ACK, sending ClientboundLoginPacket"); + pendingLogin.get(packet.getPlayerId()).run(); + + router.route(packet.getPlayerId()).send(new WorkerBoundPlayerInitACKPacket(packet.getPlayerId())); //Send ack proxy has sent the login packet + System.out.println("proxy has sent the login packet"); + } + } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundPlayerInitACKPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundPlayerInitACKPacket.java new file mode 100644 index 0000000..f077946 --- /dev/null +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundPlayerInitACKPacket.java @@ -0,0 +1,48 @@ +package com.manwe.dsl.dedicatedServer.proxy.back.packets; + +import com.manwe.dsl.dedicatedServer.InternalPacketTypes; +import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListener; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketType; + +import java.util.UUID; + +public class ProxyBoundPlayerInitACKPacket implements Packet { + + private final UUID playerId; //Player successfully transferred + + public static final StreamCodec STREAM_CODEC = + Packet.codec(ProxyBoundPlayerInitACKPacket::write, ProxyBoundPlayerInitACKPacket::new); + + public ProxyBoundPlayerInitACKPacket(UUID playerId) { + this.playerId = playerId; + } + + public ProxyBoundPlayerInitACKPacket(FriendlyByteBuf buf) { + this.playerId = buf.readUUID(); + } + private void write(FriendlyByteBuf buf) { + buf.writeUUID(this.playerId); + } + + public UUID getPlayerId() { + return playerId; + } + + /** + * Passes this Packet on to the PacketListener for processing. + * + * @param pHandler + */ + @Override + public void handle(ProxyListener pHandler) { + pHandler.handlePlayerInitACK(this); + } + + @Override + public PacketType> type() { + return InternalPacketTypes.WORKER_PROXY_PLAYER_INIT_ACK; + } +} diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundPlayerTransferPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundPlayerTransferPacket.java index 97ac51e..4fc601e 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundPlayerTransferPacket.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundPlayerTransferPacket.java @@ -24,6 +24,7 @@ public class ProxyBoundPlayerTransferPacket implements Packet { private final GameProfile gameProfile; private final ClientInformation clientInformation; private final TransientEntityInformation entityInformation; + private final int entityId; public static final StreamCodec STREAM_CODEC = Packet.codec(ProxyBoundPlayerTransferPacket::write, ProxyBoundPlayerTransferPacket::new); @@ -36,6 +37,7 @@ public ProxyBoundPlayerTransferPacket(ServerPlayer player, int workerId){ System.out.println("Player being transferred to position X:"+ player.getX()+" Z:"+player.getZ()); player.saveWithoutId(this.playerNbt); this.entityInformation = new TransientEntityInformation(player.getYRot(),player.getXRot()); + this.entityId = player.getId(); } public ProxyBoundPlayerTransferPacket(FriendlyByteBuf buf) { @@ -46,6 +48,7 @@ public ProxyBoundPlayerTransferPacket(FriendlyByteBuf buf) { this.gameProfile = new GameProfile(uuid,name); this.clientInformation = new ClientInformation(buf); this.entityInformation = new TransientEntityInformation(buf); + this.entityId = buf.readInt(); } private void write(FriendlyByteBuf buf) { buf.writeInt(this.workerId); @@ -54,6 +57,7 @@ private void write(FriendlyByteBuf buf) { buf.writeUtf(this.gameProfile.getName(),255); this.clientInformation.write(buf); this.entityInformation.write(buf); + buf.writeInt(this.entityId); } public ClientInformation getClientInformation() { @@ -76,6 +80,10 @@ public TransientEntityInformation getEntityInformation() { return entityInformation; } + public int getEntityId() { + return this.entityId; + } + /** * Passes this Packet on to the PacketListener for processing. * diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundSavePlayerStatePacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundSavePlayerStatePacket.java new file mode 100644 index 0000000..af78fe7 --- /dev/null +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundSavePlayerStatePacket.java @@ -0,0 +1,76 @@ +package com.manwe.dsl.dedicatedServer.proxy.back.packets; + +import com.manwe.dsl.dedicatedServer.InternalPacketTypes; +import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListener; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketType; +import net.minecraft.world.phys.Vec3; + +import java.util.UUID; + +public class ProxyBoundSavePlayerStatePacket implements Packet { + + private final UUID playerId; + private final int workerId; + private final Vec3 position; + private final String dimension; + + public static final StreamCodec STREAM_CODEC = + Packet.codec(ProxyBoundSavePlayerStatePacket::write, ProxyBoundSavePlayerStatePacket::new); + + public ProxyBoundSavePlayerStatePacket(UUID playerId, int workerId, Vec3 position, String dimension){ + this.playerId = playerId; + this.workerId = workerId; + this.position = position; + this.dimension = dimension; + } + + public ProxyBoundSavePlayerStatePacket(FriendlyByteBuf buf){ + this.playerId = buf.readUUID(); + this.workerId = buf.readInt(); + this.position = new Vec3(buf.readDouble(),buf.readDouble(),buf.readDouble()); + this.dimension = buf.readUtf(); + } + + private void write(FriendlyByteBuf buf) { + buf.writeUUID(this.playerId); + buf.writeInt(this.workerId); + buf.writeDouble(this.position.x); + buf.writeDouble(this.position.y); + buf.writeDouble(this.position.z); + buf.writeUtf(this.dimension); + } + + public Vec3 getPosition() { + return position; + } + + public UUID getPlayerId() { + return playerId; + } + + public int getWorkerId() { + return workerId; + } + + public String getDimension() { + return dimension; + } + + /** + * Passes this Packet on to the PacketListener for processing. + * + * @param pHandler + */ + @Override + public void handle(ProxyListener pHandler) { + pHandler.handleSavePlayerState(this); + } + + @Override + public PacketType> type() { + return InternalPacketTypes.WORKER_PROXY_SAVE_PLAYER_STATE; + } +} diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/front/ProxyFrontendInit.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/front/ProxyFrontendInit.java index b862a06..a04f968 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/front/ProxyFrontendInit.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/front/ProxyFrontendInit.java @@ -34,7 +34,7 @@ protected void initChannel(Channel ch) { Connection.configureSerialization(pl, PacketFlow.SERVERBOUND, false, null); Connection conn = new Connection(PacketFlow.SERVERBOUND); - listener.getConnections().add(conn); + listener.getConnections().add(conn); //Add this connection to the connection list for ticking, this ticks the packet listener conn.configurePacketHandler(pl); conn.setListenerForServerboundHandshake(new ProxyServerHandshakeListener(server, conn)); diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/front/listeners/ProxyServerConfigurationListener.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/front/listeners/ProxyServerConfigurationListener.java index fe44c01..35c6f9c 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/front/listeners/ProxyServerConfigurationListener.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/front/listeners/ProxyServerConfigurationListener.java @@ -28,49 +28,15 @@ public class ProxyServerConfigurationListener extends ServerConfigurationPacketL private static final Component DISCONNECT_REASON_INVALID_DATA = Component.translatable("multiplayer.disconnect.invalid_player_data"); - private final GameProfile localGameProfile; //Read only - private final ClientInformation localClientInformation; //Read only - public ProxyServerConfigurationListener(MinecraftServer pServer, Connection pConnection, CommonListenerCookie pCookie) { super(pServer, pConnection, pCookie); - localGameProfile = pCookie.gameProfile(); - localClientInformation = pCookie.clientInformation(); System.out.println("ProxyServerConfigurationListener Created"); } + @Override public void handleConfigurationFinished(ServerboundFinishConfigurationPacket pPacket){ - PacketUtils.ensureRunningOnSameThread(pPacket, this, this.server); - this.finishCurrentTask(JoinWorldTask.TYPE); - this.connection.setupOutboundProtocol(GameProtocols.CLIENTBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess(), this.connectionType))); - // Packets can only be sent after the outbound protocol is set up again - if (this.connectionType == net.neoforged.neoforge.network.connection.ConnectionType.OTHER) { - //We need to also initialize this here, as the client may have sent the packet before we have finished our configuration. - net.neoforged.neoforge.network.registration.NetworkRegistry.initializeNeoForgeConnection(this, java.util.Map.of()); - } - net.neoforged.neoforge.network.registration.NetworkRegistry.onConfigurationFinished(this); - - try { - //this.server es un ProxyDedicatedServer - PlayerList playerlist = this.server.getPlayerList(); - if (playerlist.getPlayer(this.localGameProfile.getId()) != null) { - this.disconnect(PlayerList.DUPLICATE_LOGIN_DISCONNECT_MESSAGE); - return; - } - - Component component = playerlist.canPlayerLogin(this.connection.getRemoteAddress(), this.localGameProfile); - if (component != null) { - this.disconnect(component); - return; - } - - ServerPlayer serverplayer = playerlist.getPlayerForLogin(localGameProfile, localClientInformation); - playerlist.placeNewPlayer(this.connection, serverplayer, this.createCookie(localClientInformation, this.connectionType)); - - } catch (Exception exception) { - DistributedServerLevels.LOGGER.error("Couldn't place player in world", exception); - this.connection.send(new ClientboundDisconnectPacket(DISCONNECT_REASON_INVALID_DATA)); - this.connection.disconnect(DISCONNECT_REASON_INVALID_DATA); - } + System.out.println("handleConfigurationFinished"); + super.handleConfigurationFinished(pPacket); } } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/front/listeners/ProxyServerGameListener.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/front/listeners/ProxyServerGameListener.java index ab74163..f7f21fe 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/front/listeners/ProxyServerGameListener.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/front/listeners/ProxyServerGameListener.java @@ -6,8 +6,11 @@ import com.manwe.dsl.dedicatedServer.proxy.ProxyDedicatedServer; import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerDisconnectPacket; import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundContainerPacket; +import io.netty.channel.ChannelFuture; +import net.minecraft.Util; import net.minecraft.network.Connection; import net.minecraft.network.DisconnectionDetails; +import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.common.ServerboundClientInformationPacket; import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; import net.minecraft.network.protocol.common.ServerboundKeepAlivePacket; @@ -24,6 +27,7 @@ public class ProxyServerGameListener extends ServerGamePacketListenerImpl { ProxyDedicatedServer server; RegionRouter router; + //boolean blockClientMovementBeforeACK = true; public ProxyServerGameListener(MinecraftServer pServer, Connection pConnection, ServerPlayer pPlayer, CommonListenerCookie pCookie, RegionRouter router) { super(pServer, pConnection, pPlayer, pCookie); if(pServer instanceof ProxyDedicatedServer server1){ @@ -49,6 +53,14 @@ public void handleKeepAlive(ServerboundKeepAlivePacket pPacket) { ///ServerGamePacketListenerImpl/// ////////////////////////////////// + @Override + public void tick() { + + this.keepConnectionAlive(); //Only tick keepConnectionAlive + + //Cancel all ticking for this ServerPlayer in the proxy, ticking is done by the workers + } + /** * Processes player movement input. Includes walking, strafing, jumping, and sneaking. Excludes riding and toggling flying/sprinting. */ @@ -66,9 +78,11 @@ public void handleMoveVehicle(@NotNull ServerboundMoveVehiclePacket pPacket) { @Override public void handleAcceptTeleportPacket(@NotNull ServerboundAcceptTeleportationPacket pPacket) { - System.out.println("Proxy: handleAcceptTeleportPacket ID:" + pPacket.getId() + " sending to -> worker"); + //blockClientMovementBeforeACK = false; + //System.out.println("ACK desbloqueado movement"); + WorkerTunnel tunnel = router.route(player.getUUID()); //Select tunnel - tunnel.send(new WorkerBoundContainerPacket(player.getUUID(),pPacket)); + ChannelFuture future = tunnel.send(new WorkerBoundContainerPacket(player.getUUID(),pPacket)); } @Override @@ -178,7 +192,7 @@ public void handleBlockEntityTagQuery(@NotNull ServerboundBlockEntityTagQueryPac @Override public void handleMovePlayer(@NotNull ServerboundMovePlayerPacket pPacket) { - //System.out.println("handleMovePlayer: " + pPacket.getX(0) + ":" + pPacket.getY(0) + ":" + pPacket.getZ(0)); + //System.out.println("Send Movement"); WorkerTunnel tunnel = router.route(player.getUUID()); //Select tunnel tunnel.send(new WorkerBoundContainerPacket(player.getUUID(), pPacket)); //Send wrapped movement packet } @@ -224,9 +238,6 @@ public void onDisconnect(DisconnectionDetails pDetails) { DistributedServerLevels.LOGGER.info("{} lost connection: {}", this.player.getName().getString(), pDetails.reason().getString()); WorkerTunnel tunnel = router.route(player.getUUID()); //Select tunnel tunnel.send(new WorkerBoundPlayerDisconnectPacket(this.player.getUUID())); - - //this.removePlayerFromWorld(); - //super.onDisconnect(pDetails); } /** diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/LocalPlayerList.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/LocalPlayerList.java index 4337fa0..88a2cc7 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/worker/LocalPlayerList.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/LocalPlayerList.java @@ -1,16 +1,26 @@ package com.manwe.dsl.dedicatedServer.worker; import com.manwe.dsl.DistributedServerLevels; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundPlayerInitACKPacket; import com.manwe.dsl.dedicatedServer.worker.listeners.WorkerGamePacketListenerImpl; import com.manwe.dsl.mixin.accessors.PlayerListAccessor; +import com.manwe.dsl.mixin.accessors.SynchedEntityDataAccessor; import com.mojang.authlib.GameProfile; import com.mojang.serialization.Dynamic; +import io.netty.channel.ChannelPipeline; +import net.minecraft.ChatFormatting; import net.minecraft.core.LayeredRegistryAccess; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.network.Connection; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.protocol.game.*; +import net.minecraft.network.protocol.status.ServerStatus; +import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.resources.ResourceKey; import net.minecraft.server.RegistryLayer; import net.minecraft.server.dedicated.DedicatedPlayerList; @@ -18,26 +28,24 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.server.network.ServerGamePacketListenerImpl; import net.minecraft.server.players.GameProfileCache; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.GameRules; import net.minecraft.world.level.Level; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.storage.LevelData; import net.minecraft.world.level.storage.PlayerDataStorage; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.UUID; +import java.util.*; public class LocalPlayerList extends DedicatedPlayerList { public LocalPlayerList(DedicatedServer pServer, LayeredRegistryAccess pRegistries, PlayerDataStorage pPlayerIo) { super(pServer, pRegistries, pPlayerIo); } - @Override - public void placeNewPlayer(Connection pConnection, ServerPlayer pPlayer, CommonListenerCookie pCookie) { + public void placeNewPlayer(Connection pConnection, ServerPlayer pPlayer, CommonListenerCookie pCookie, ChannelPipeline sharedPipeline) { GameProfile gameprofile = pPlayer.getGameProfile(); GameProfileCache gameprofilecache = this.getServer().getProfileCache(); if (gameprofilecache != null) gameprofilecache.add(gameprofile); @@ -70,31 +78,36 @@ public void placeNewPlayer(Connection pConnection, ServerPlayer pPlayer, CommonL LevelData leveldata = serverlevel1.getLevelData(); pPlayer.loadGameTypes(optional1.orElse(null)); - /* + //System.out.println("Sending player init ack"); //Tell proxy to send LoginPacket + //sharedPipeline.writeAndFlush(new ProxyBoundPlayerInitACKPacket(pPlayer.getUUID())); + + + ///////////////////////////////////////////////////////////// GameRules gamerules = serverlevel1.getGameRules(); boolean flag = gamerules.getBoolean(GameRules.RULE_DO_IMMEDIATE_RESPAWN); boolean flag1 = gamerules.getBoolean(GameRules.RULE_REDUCEDDEBUGINFO); boolean flag2 = gamerules.getBoolean(GameRules.RULE_LIMITED_CRAFTING); pConnection.send( - new ClientboundLoginPacket( - pPlayer.getId(), - leveldata.isHardcore(), - getServer().levelKeys(), - this.getMaxPlayers(), - this.getViewDistance(), - this.getSimulationDistance(), - flag1, - !flag, - flag2, - pPlayer.createCommonSpawnInfo(serverlevel1), - getServer().enforceSecureProfile() - ) - );*/ //TODO de momento el ClientboundLoginPacket lo maneja el proxy + new ClientboundLoginPacket( + pPlayer.getId(), + leveldata.isHardcore(), + getServer().levelKeys(), + this.getMaxPlayers(), + this.getViewDistance(), + this.getSimulationDistance(), + flag1, + !flag, + flag2, + pPlayer.createCommonSpawnInfo(serverlevel1), + getServer().enforceSecureProfile() + ) + ); + ///////////////////////////////////////////////////////////// + System.out.println("Sending rest of client bound packets"); pConnection.send(new ClientboundChangeDifficultyPacket(leveldata.getDifficulty(), leveldata.isDifficultyLocked())); pConnection.send(new ClientboundPlayerAbilitiesPacket(pPlayer.getAbilities())); pConnection.send(new ClientboundSetCarriedItemPacket(pPlayer.getInventory().selected)); - net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.OnDatapackSyncEvent(this, pPlayer)); pConnection.send(new ClientboundUpdateRecipesPacket(this.getServer().getRecipeManager().getOrderedRecipes())); this.sendPlayerPermissionLevel(pPlayer); //TODO Hay que mandar esto? @@ -102,23 +115,37 @@ public void placeNewPlayer(Connection pConnection, ServerPlayer pPlayer, CommonL pPlayer.getRecipeBook().sendInitialRecipeBook(pPlayer); //TODO Hay que mandar esta información? this.updateEntireScoreboard(serverlevel1.getScoreboard(), pPlayer); this.getServer().invalidateStatus(); + //MutableComponent mutablecomponent; + //if (pPlayer.getGameProfile().getName().equalsIgnoreCase(s)) { + // mutablecomponent = Component.translatable("multiplayer.player.joined", pPlayer.getDisplayName()); + //} else { + // mutablecomponent = Component.translatable("multiplayer.player.joined.renamed", pPlayer.getDisplayName(), s); + //} + // + //this.broadcastSystemMessage(mutablecomponent.withStyle(ChatFormatting.YELLOW), false); + if(pConnection.getPacketListener() instanceof WorkerGamePacketListenerImpl serverGamePacketListener){ serverGamePacketListener.teleport(pPlayer.getX(), pPlayer.getY(), pPlayer.getZ(), pPlayer.getYRot(), pPlayer.getXRot()); + System.out.println("Mandado el ClientboundPlayerPositionPacket //TELEPORT INICIAL// el cliente tiene que responder con un ack"); + System.out.println("Con la posición inicial: "+pPlayer.position().toString()); } - /* + ServerStatus serverstatus = this.getServer().getStatus(); if (serverstatus != null && !pCookie.transferred()) { - pPlayer.sendServerStatus(serverstatus); //TODO Hay que mandar el server status? - }*/ + pPlayer.sendServerStatus(serverstatus); + } - pPlayer.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(this.getPlayers())); //TODO Hay que mandar esta información? + pPlayer.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(this.getPlayers())); ((PlayerListAccessor) this).getPlayers().add(pPlayer); ((PlayerListAccessor) this).getPlayersByUUID().put(pPlayer.getUUID(), pPlayer); this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(pPlayer))); - this.sendLevelInfo(pPlayer, serverlevel1); //TODO Mandar? + this.sendLevelInfo(pPlayer, serverlevel1); + + //Should this be deferred? -> + serverlevel1.addNewPlayer(pPlayer); this.getServer().getCustomBossEvents().onPlayerConnect(pPlayer); - this.sendActivePlayerEffects(pPlayer); //TODO Hay que manejar los efectos en el worker? + this.sendActivePlayerEffects(pPlayer); if (optional1.isPresent() && optional1.get().contains("RootVehicle", 10)) { CompoundTag compoundtag = optional1.get().getCompound("RootVehicle"); Entity entity = EntityType.loadEntityRecursive( @@ -155,11 +182,13 @@ public void placeNewPlayer(Connection pConnection, ServerPlayer pPlayer, CommonL } pPlayer.initInventoryMenu(); //TODO Hay que gestionar el inventario en el worker? - net.neoforged.neoforge.event.EventHooks.firePlayerLoggedIn( pPlayer ); + net.neoforged.neoforge.event.EventHooks.firePlayerLoggedIn(pPlayer); } public void transferExistingPlayer(ServerPlayer pPlayer, CompoundTag nbt){ + System.out.println("TRANSFER PLAYER"); + /* ---------- 1. Determinar el mundo destino ---------- */ ResourceKey key = DimensionType .parseLegacy(new Dynamic<>(NbtOps.INSTANCE, nbt.get("Dimension"))) @@ -169,12 +198,27 @@ public void transferExistingPlayer(ServerPlayer pPlayer, CompoundTag nbt){ ServerLevel level = Objects.requireNonNullElseGet(this.getServer().getLevel(key), this.getServer()::overworld); // fallback → overworld pPlayer.setServerLevel(level); // vincula la entidad al Level correcto + pPlayer.loadGameTypes(nbt); //Set gameMode + + if(pPlayer.connection instanceof WorkerGamePacketListenerImpl serverGamePacketListener){ + //System.out.println("Transfer Teleport"); NO PARECE QUE SOLUCIONE NADA + //serverGamePacketListener.teleport(pPlayer.getX(), pPlayer.getY(), pPlayer.getZ(), pPlayer.getYRot(), pPlayer.getXRot()); + } ((PlayerListAccessor) this).getPlayers().add(pPlayer); ((PlayerListAccessor) this).getPlayersByUUID().put(pPlayer.getUUID(), pPlayer); level.addNewPlayer(pPlayer); - pPlayer.initInventoryMenu(); //TODO Hay que gestionar el inventario en el worker? + + /* + //SynchedEntityData + for(SynchedEntityData.DataItem item :((SynchedEntityDataAccessor) pPlayer.getEntityData()).getItemsById()){ + item.setDirty(true); + } + ((SynchedEntityDataAccessor) pPlayer.getEntityData()).setDirty(true); + */ + + pPlayer.initInventoryMenu(); /* ---------- 3. Restaurar montura, si la hubiera ---------- */ if (nbt.contains("RootVehicle", Tag.TAG_COMPOUND)) { @@ -204,5 +248,6 @@ public void transferExistingPlayer(ServerPlayer pPlayer, CompoundTag nbt){ } } this.sendPlayerPermissionLevel(pPlayer);// TODO ver esto + } } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerGamePacketListenerImpl.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerGamePacketListenerImpl.java index 47b4911..2ee73e2 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerGamePacketListenerImpl.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerGamePacketListenerImpl.java @@ -1,42 +1,78 @@ package com.manwe.dsl.dedicatedServer.worker.listeners; +import com.manwe.dsl.mixin.accessors.ServerGamePacketListenerImplAccessor; import net.minecraft.network.Connection; +import net.minecraft.network.protocol.PacketUtils; +import net.minecraft.network.protocol.common.ServerboundClientInformationPacket; import net.minecraft.network.protocol.common.ServerboundKeepAlivePacket; -import net.minecraft.network.protocol.game.ServerboundAcceptTeleportationPacket; -import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; +import net.minecraft.network.protocol.game.*; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.CommonListenerCookie; import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.HasCustomInventoryScreen; +import net.minecraft.world.entity.PlayerRideableJumping; +import net.minecraft.world.item.ItemStack; public class WorkerGamePacketListenerImpl extends ServerGamePacketListenerImpl { + public WorkerGamePacketListenerImpl(MinecraftServer pServer, Connection pConnection, ServerPlayer pPlayer, CommonListenerCookie pCookie) { super(pServer, pConnection, pPlayer, pCookie); } + @Override + public void handlePlayerCommand(ServerboundPlayerCommandPacket pPacket) { + System.out.println("ServerboundPlayerCommandPacket: " + pPacket.getAction().name()); + if(pPacket.getAction() == ServerboundPlayerCommandPacket.Action.START_FALL_FLYING){ + System.out.println("tryToStartFallFlying: "+ (!player.onGround() && !player.isFallFlying() && !player.isInWater() && !player.hasEffect(MobEffects.LEVITATION)) ); + System.out.println("onGround: "+ player.onGround()); + System.out.println("isFallFlying: "+ player.isFallFlying()); + System.out.println("isInWater: "+ player.isInWater()); + System.out.println("has Levitation: "+ player.hasEffect(MobEffects.LEVITATION)); + + ItemStack itemstack = player.getItemBySlot(EquipmentSlot.CHEST); + System.out.println("equipped item: "+itemstack.getItem()); + if (itemstack.canElytraFly(player)) { + System.out.println("START FLYING"); + } + } + super.handlePlayerCommand(pPacket); + } + + @Override + public void handleClientInformation(ServerboundClientInformationPacket pPacket) { + System.out.println("recibe handleClientInformation"); + super.handleClientInformation(pPacket); + } + @Override public void handleAcceptTeleportPacket(ServerboundAcceptTeleportationPacket pPacket) { - System.out.println("Client accepted Teleport"); + System.out.println("ACK -> Packet Id:" + pPacket.getId() + " AwaitingTeleport: " + ((ServerGamePacketListenerImplAccessor)this).getAwaitingTeleport() + " AwaitingPos: " + ((ServerGamePacketListenerImplAccessor)this).getAwaitingPositionFromClient()); super.handleAcceptTeleportPacket(pPacket); + System.out.println("Post ACK -> Packet Id:" + pPacket.getId() + " AwaitingTeleport: " + ((ServerGamePacketListenerImplAccessor)this).getAwaitingTeleport() + " AwaitingPos: " + ((ServerGamePacketListenerImplAccessor)this).getAwaitingPositionFromClient()); } @Override public void handleMovePlayer(ServerboundMovePlayerPacket pPacket) { + //System.out.println("handleMovePlayer: "+pPacket.getX(0)+":"+pPacket.getY(0)+":"+pPacket.getZ(0) + "AwaitingTeleport: " + ((ServerGamePacketListenerImplAccessor)this).getAwaitingTeleport() + " AwaitingPos: " + ((ServerGamePacketListenerImplAccessor)this).getAwaitingPositionFromClient()); + //System.out.println(player.getX() + ":" + player.getY() + ":" + player.getZ() + " tickCount=" + player.tickCount + " isAlive=" + player.isAlive() + " isSleeping=" + player.isSleeping() + " noPhysics=" + player.noPhysics); super.handleMovePlayer(pPacket); } - @Override - public void teleport(double pX, double pY, double pZ, float pYaw, float pPitch) { - System.out.println("Sent Teleport"); - super.teleport(pX, pY, pZ, pYaw, pPitch); - } - @Override public void handleKeepAlive(ServerboundKeepAlivePacket pPacket) { super.handleKeepAlive(pPacket); System.out.println("(NO debería) keep alive recibido en el worker"); } + @Override + public void handleChunkBatchReceived(ServerboundChunkBatchReceivedPacket pPacket) { + //System.out.println("handleChunkBatchReceived"); + super.handleChunkBatchReceived(pPacket); + } + @Override protected void keepConnectionAlive() { //Desactiva el keep alive del worker, esto lo maneja solo el proxy diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerListener.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerListener.java index be0f3d7..56803f4 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerListener.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerListener.java @@ -1,9 +1,6 @@ package com.manwe.dsl.dedicatedServer.worker.listeners; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerInitPacket; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerDisconnectPacket; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundContainerPacket; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerTransferPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.*; import net.minecraft.network.Connection; import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.protocol.game.ServerPacketListener; @@ -21,6 +18,8 @@ default ConnectionProtocol protocol() { void handlePlayerLogin(WorkerBoundPlayerInitPacket packet); + void handlePlayerLoginACK(WorkerBoundPlayerInitACKPacket packet); + void handlePlayerTransfer(WorkerBoundPlayerTransferPacket packet); void handlePlayerDisconnect(WorkerBoundPlayerDisconnectPacket packet); diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerListenerImpl.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerListenerImpl.java index bdc09f8..c11234b 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerListenerImpl.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerListenerImpl.java @@ -4,14 +4,13 @@ import com.manwe.dsl.config.DSLServerConfigs; import com.manwe.dsl.connectionRouting.RegionRouter; import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundPlayerTransferACKPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundSavePlayerStatePacket; import com.manwe.dsl.dedicatedServer.worker.LocalPlayerList; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerInitPacket; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerDisconnectPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.*; import com.manwe.dsl.dedicatedServer.worker.ProxyPlayerConnection; import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundPlayerTransferPacket; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundContainerPacket; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerTransferPacket; import com.manwe.dsl.mixin.accessors.ConnectionAccessor; +import com.manwe.dsl.mixin.accessors.ServerLevelAccessor; import io.netty.channel.ChannelPipeline; import net.minecraft.nbt.ListTag; import net.minecraft.network.Connection; @@ -23,15 +22,13 @@ import net.minecraft.network.protocol.common.*; import net.minecraft.network.protocol.game.*; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.CommonListenerCookie; import net.minecraft.util.Mth; import org.jetbrains.annotations.NotNull; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class WorkerListenerImpl implements WorkerListener { @@ -41,6 +38,10 @@ public class WorkerListenerImpl implements WorkerListener { private final Map playerConnections = new ConcurrentHashMap<>(); private final Set transferring = new HashSet<>(); //All player that are currently being transferred to another worker + private final Map pendingLogin = new HashMap<>(); + + private final Map> earlyPackets = new ConcurrentHashMap<>(); + int workerId = DSLServerConfigs.WORKER_ID.get(); int workerSize = DSLServerConfigs.WORKER_SIZE.get(); int regionSize = DSLServerConfigs.REGION_SIZE.get(); @@ -68,11 +69,20 @@ public boolean isAcceptingMessages() { @Override public void handleProxyWorkerPacket(WorkerBoundContainerPacket packet) { + + UUID uuid = packet.getPlayerId(); + + if (!playerConnections.containsKey(uuid)) { + earlyPackets.computeIfAbsent(uuid, k -> new LinkedList<>()).add(packet); + System.out.println("Packet Received before login finished - Stored"); + return; + } + //Ejecuta el paquete interno con el listener asociado al UUID - Connection connection = playerConnections.get(packet.getPlayerId()); + Connection connection = playerConnections.get(uuid); if(connection == null) { - DistributedServerLevels.LOGGER.warn("ServerPlayer with UUID ["+packet.getPlayerId()+"] does not have a listener. (skipped player login?)"); - } else if (transferring.contains(packet.getPlayerId())) { + DistributedServerLevels.LOGGER.warn("ServerPlayer with UUID ["+uuid+"] does not have a listener"); + } else if (transferring.contains(uuid)) { DistributedServerLevels.LOGGER.info("This player is being transferred to another worker"); } else if(connection.getPacketListener() instanceof WorkerGamePacketListenerImpl serverGamePacketListener) { server.execute(()->{ //Run on the minecraft main thread instead of the I/O thread @@ -80,6 +90,7 @@ public void handleProxyWorkerPacket(WorkerBoundContainerPacket packet) { handleOutsideWorkerBounds(packet,server); //TODO ver si puede darse el caso de que entren varios paquetes de movimiento antes de que se marque como transferring }); } else { + System.out.println("ERROR inesperado"); Component component = Component.translatable("disconnect.genericReason", "Internal Exception"); //TODO código de prueba connection.send(new ClientboundDisconnectPacket(component)); } @@ -110,37 +121,22 @@ private void handleOutsideWorkerBounds(WorkerBoundContainerPacket packet, Minecr @Override public void handlePlayerLogin(WorkerBoundPlayerInitPacket packet) { - //TODO hay que ver esto de las dimensiones + System.out.println("Worker: handlePlayerLogin"); + ServerPlayer player = packet.rebuildServerPlayer(server); CommonListenerCookie cookie = packet.rebuildCookie(); DistributedServerLevels.LOGGER.info("New player ["+player.getDisplayName().getString()+"] logged into worker ["+ DSLServerConfigs.WORKER_ID.get()+"]"); - Connection connection = generateConnection(player, cookie); + Connection proxyConnection = generateConnection(player, cookie); - server.getPlayerList().placeNewPlayer(connection,player,cookie); - DistributedServerLevels.LOGGER.info("Player ["+player.getDisplayName().getString()+"] placed in world"); - } + server.execute(()-> { + if(!(server.getPlayerList() instanceof LocalPlayerList localPlayerList)) throw new RuntimeException("PlayerList is not an instance of LocalPlayerList"); - /** - * Creates the fake connection with the proxy - * Creates the ServerGameListener for this player - * @return - */ - @NotNull - private Connection generateConnection(ServerPlayer player, CommonListenerCookie cookie) { - //Create new connection and listener - Connection connection = new ProxyPlayerConnection(PacketFlow.CLIENTBOUND, player.getUUID(),server.registryAccess()); - WorkerGamePacketListenerImpl playerListener = new WorkerGamePacketListenerImpl(server,connection, player, cookie); - try { - ((ConnectionAccessor) connection).setChannel(sharedPipeline.channel()); - ((ConnectionAccessor) connection).setPacketListener(playerListener); - this.playerConnections.put(player.getUUID(),connection); //Hold in map - }catch (Exception e){ - DistributedServerLevels.LOGGER.error("Error setting channelActive"); - } + localPlayerList.placeNewPlayer(proxyConnection, player, cookie, sharedPipeline); + registerPlayerAndConnection(player, proxyConnection); - server.getConnection().getConnections().add(connection); //Añadir las fake connections a la lista de conexiones del servidor para que hagan tick() - return connection; + System.out.println("Player ["+player.getDisplayName().getString()+"] placed in world"); + }); } /** @@ -150,50 +146,92 @@ private Connection generateConnection(ServerPlayer player, CommonListenerCookie @Override public void handlePlayerTransfer(WorkerBoundPlayerTransferPacket packet) { System.out.println("Worker: handlePlayerTransfer"); - // 2. Crear un ServerPlayer “vacío” con el mismo GameProfile + ServerPlayer clonePlayer = packet.rebuildServerPlayer(server); CommonListenerCookie cookie = packet.rebuildCookie(); - // 3. Cargar estado + DistributedServerLevels.LOGGER.info("New player [" + clonePlayer.getDisplayName().getString() + "] transferred into worker [" + DSLServerConfigs.WORKER_ID.get() + "]"); + clonePlayer.load(packet.getPlayerNbt()); - //LOG - ListTag listtag = packet.getPlayerNbt().getList("Pos", 6); - System.out.print( - "Tag information position: \n"+ - "X:" + Mth.clamp(listtag.getDouble(0), -3.0000512E7, 3.0000512E7) + "\n" + - "Y:" + Mth.clamp(listtag.getDouble(1), -2.0E7, 2.0E7) + "\n" + - "Z:" + Mth.clamp(listtag.getDouble(2), -3.0000512E7, 3.0000512E7) + "\n" - ); - //LOG + Connection proxyConnection = generateConnection(clonePlayer, cookie); - DistributedServerLevels.LOGGER.info("New player [" + clonePlayer.getDisplayName().getString() + "] transferred into worker [" + DSLServerConfigs.WORKER_ID.get() + "]"); + server.execute(()-> { + if (!(server.getPlayerList() instanceof LocalPlayerList localPlayerList)) throw new RuntimeException("Worker must have a localPlayerList"); + + localPlayerList.transferExistingPlayer(clonePlayer, packet.getPlayerNbt()); + DistributedServerLevels.LOGGER.info("Player [" + clonePlayer.getDisplayName().getString() + "] placed in world at X:" + clonePlayer.getX() + " Z:" + clonePlayer.getZ()); - //Añadir el player al mundo - Connection connection = generateConnection(clonePlayer, cookie); + sharedPipeline.writeAndFlush(new ProxyBoundPlayerTransferACKPacket(this.workerId, clonePlayer.getUUID())); //Send Setup to proxy router for the new worker redirection + registerPlayerAndConnection(clonePlayer, proxyConnection); + }); + } - if (!(server.getPlayerList() instanceof LocalPlayerList localPlayerList)) throw new RuntimeException("Worker must have a localPlayerList"); + private void registerPlayerAndConnection(ServerPlayer player, Connection proxyConnection) { + playerConnections.put(player.getUUID(), proxyConnection); //Set this connection as a player connection only after player is placed in world + server.getConnection().getConnections().add(proxyConnection); //Add listener for ticking + } + + @Override + public void handlePlayerLoginACK(WorkerBoundPlayerInitACKPacket packet) { + System.out.println("RUNNING REST OF placeNewPlayer()"); + UUID uuid = packet.getPlayerId(); + if(!(playerConnections.get(uuid).getPacketListener() instanceof WorkerGamePacketListenerImpl serverGamePacketListener)) throw new RuntimeException("listener is not instance of WorkerGamePacketListenerImpl"); + server.execute(()-> { + pendingLogin.get(uuid).run(); //Run pending login + if(earlyPackets.containsKey(uuid)){ + System.out.println("Running stored packets"); + earlyPackets.get(uuid).forEach(workerBoundContainerPacket -> { //Run pending packets before login completed + ((Packet) workerBoundContainerPacket.getPayload()).handle(serverGamePacketListener); + }); + } else { + System.out.println("No stored packets"); + } + }); + } - localPlayerList.transferExistingPlayer(clonePlayer,packet.getPlayerNbt()); - DistributedServerLevels.LOGGER.info("Player [" + clonePlayer.getDisplayName().getString() + "] placed in world at X:"+clonePlayer.getX()+" Z:"+clonePlayer.getZ()); - //Mandar un ACK - sharedPipeline.writeAndFlush(new ProxyBoundPlayerTransferACKPacket(this.workerId, clonePlayer.getUUID())); + /** + * Creates the fake connection with the proxy + * Creates the ServerGameListener for this player + * @return + */ + @NotNull + private Connection generateConnection(ServerPlayer player, CommonListenerCookie cookie) { + //Create new connection and listener + Connection connection = new ProxyPlayerConnection(PacketFlow.CLIENTBOUND, player.getUUID(),server.registryAccess()); + WorkerGamePacketListenerImpl playerListener = new WorkerGamePacketListenerImpl(server,connection, player, cookie); + try { + ((ConnectionAccessor) connection).setChannel(sharedPipeline.channel()); + ((ConnectionAccessor) connection).setPacketListener(playerListener); + }catch (Exception e){ + DistributedServerLevels.LOGGER.error("Error setting channelActive"); + } - //server.execute(()-> { //Run on the minecraft main thread instead of the I/O thread - //}); + player.connection = playerListener; //Set this players listener + //TODO hay que estudiar esto + //server.getConnection().getConnections().add(connection); //Añadir las fake connections a la lista de conexiones del servidor para que hagan tick() + return connection; } + //Proxy detected a player disconnection @Override public void handlePlayerDisconnect(WorkerBoundPlayerDisconnectPacket packet) { + System.out.println("handlePlayerDisconnect"); + UUID playerId = packet.getPlayerID(); server.execute(()->{ //Run on the minecraft main thread instead of the I/O thread + ServerPlayer disconnectedPlayer = server.getPlayerList().getPlayer(playerId); + if(disconnectedPlayer == null) throw new RuntimeException("handlePlayerDisconnect: Player is null"); + //Send last player position + sharedPipeline.writeAndFlush(new ProxyBoundSavePlayerStatePacket(playerId,workerId,disconnectedPlayer.position(),disconnectedPlayer.level().dimension().location().toString())); + //Disconnect (gamelogic) call to this player gameListener - PacketListener gameListener = getDedicatedPlayerListener(packet.getPlayerID()); + PacketListener gameListener = getDedicatedPlayerListener(playerId); gameListener.onDisconnect(packet.getDefaultDisconnectionDetails()); //TODO hay que ver si todo este método hay que ejecutarlo o solo partes de el //Remove from map - Connection removed = playerConnections.remove(packet.getPlayerID()); + Connection removed = playerConnections.remove(playerId); //Remove from ServerConnectionListener to stop tick() and avoid duplicates server.getConnection().getConnections().remove(removed); //Remove form transferring - transferring.remove(packet.getPlayerID()); + transferring.remove(playerId); }); } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerInitACKPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerInitACKPacket.java new file mode 100644 index 0000000..f11cb87 --- /dev/null +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerInitACKPacket.java @@ -0,0 +1,48 @@ +package com.manwe.dsl.dedicatedServer.worker.packets; + +import com.manwe.dsl.dedicatedServer.InternalPacketTypes; +import com.manwe.dsl.dedicatedServer.worker.listeners.WorkerListener; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketType; + +import java.util.UUID; + +public class WorkerBoundPlayerInitACKPacket implements Packet { + + private final UUID playerId; + + public static final StreamCodec STREAM_CODEC = Packet.codec( + WorkerBoundPlayerInitACKPacket::write, WorkerBoundPlayerInitACKPacket::new + ); + + public WorkerBoundPlayerInitACKPacket(UUID playerId) { + this.playerId = playerId; + } + + public WorkerBoundPlayerInitACKPacket(FriendlyByteBuf buf) { + this.playerId = buf.readUUID(); + } + + private void write(FriendlyByteBuf buf) { + buf.writeUUID(this.playerId); + } + + public UUID getPlayerId() { + return playerId; + } + + @Override + public PacketType> type() { + return InternalPacketTypes.PROXY_WORKER_PLAYER_INIT_ACK; + } + + /** + * Passes this Packet on to the PacketListener for processing. + */ + @Override + public void handle(WorkerListener pHandler) { + pHandler.handlePlayerLoginACK(this); + } +} diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerInitPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerInitPacket.java index a4db58a..53b0970 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerInitPacket.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerInitPacket.java @@ -3,6 +3,7 @@ import com.manwe.dsl.dedicatedServer.InternalPacketTypes; import com.manwe.dsl.dedicatedServer.worker.listeners.WorkerListener; import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.PropertyMap; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.Packet; @@ -31,6 +32,8 @@ public WorkerBoundPlayerInitPacket(GameProfile gameProfile, ClientInformation cl private void write(FriendlyByteBuf buf) { buf.writeUUID(this.gameProfile.getId()); buf.writeUtf(this.gameProfile.getName(),255); + writePropertyMap(buf, gameProfile.getProperties()); + this.clientInformation.write(buf); } @@ -38,9 +41,35 @@ public WorkerBoundPlayerInitPacket(FriendlyByteBuf buf) { UUID uuid = buf.readUUID(); String name = buf.readUtf(255); this.gameProfile = new GameProfile(uuid,name); + gameProfile.getProperties().putAll(readPropertyMap(buf)); + this.clientInformation = new ClientInformation(buf); } + private static void writePropertyMap(FriendlyByteBuf buf, PropertyMap map) { + buf.writeVarInt(map.size()); + map.values().forEach(prop -> { + buf.writeUtf(prop.name()); + buf.writeUtf(prop.value()); + buf.writeBoolean(prop.hasSignature()); + if (prop.hasSignature()) { + buf.writeUtf(prop.signature()); + } + }); + } + + private static PropertyMap readPropertyMap(FriendlyByteBuf buf) { + PropertyMap map = new PropertyMap(); + int total = buf.readVarInt(); + for (int i = 0; i < total; i++) { + String name = buf.readUtf(); + String value = buf.readUtf(); + String sig = buf.readBoolean() ? buf.readUtf() : null; + map.put(name, new com.mojang.authlib.properties.Property(name, value, sig)); + } + return map; + } + public ServerPlayer rebuildServerPlayer(MinecraftServer server) { return new ServerPlayer(server, server.overworld(), this.gameProfile, this.clientInformation); } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerTransferPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerTransferPacket.java index aaaec27..51f095a 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerTransferPacket.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerTransferPacket.java @@ -28,6 +28,7 @@ public class WorkerBoundPlayerTransferPacket implements Packet { private final GameProfile gameProfile; private final ClientInformation clientInformation; private final TransientEntityInformation entityInformation; + private final int entityId; public static final StreamCodec STREAM_CODEC = Packet.codec(WorkerBoundPlayerTransferPacket::write, WorkerBoundPlayerTransferPacket::new); @@ -38,6 +39,7 @@ public WorkerBoundPlayerTransferPacket(ProxyBoundPlayerTransferPacket packet){ this.clientInformation = packet.getClientInformation(); this.playerNbt = packet.getPlayerNbt(); this.entityInformation = packet.getEntityInformation(); + this.entityId = packet.getEntityId(); } public WorkerBoundPlayerTransferPacket(FriendlyByteBuf buf) { @@ -51,6 +53,7 @@ public WorkerBoundPlayerTransferPacket(FriendlyByteBuf buf) { this.clientInformation = new ClientInformation(buf); //TransientEntityInformation this.entityInformation = new TransientEntityInformation(buf); + this.entityId = buf.readInt(); } private void write(FriendlyByteBuf buf) { buf.writeInt(this.workerId); @@ -62,6 +65,7 @@ private void write(FriendlyByteBuf buf) { this.clientInformation.write(buf); //TransientEntityInformation this.entityInformation.write(buf); + buf.writeInt(this.entityId); } public ClientInformation getClientInformation() { @@ -85,7 +89,9 @@ public TransientEntityInformation getEntityInformation() { } public ServerPlayer rebuildServerPlayer(MinecraftServer server) { - return new ServerPlayer(server, server.overworld(), this.gameProfile, this.clientInformation); + ServerPlayer clone = new ServerPlayer(server, server.overworld(), this.gameProfile, this.clientInformation); + clone.setId(this.entityId); //Clone the id assigned by its source worker, entity id do not collide between workers each worker has its own id range + return clone; } public CommonListenerCookie rebuildCookie(){ diff --git a/src/main/java/com/manwe/dsl/mixin/ServerLevelMixin.java b/src/main/java/com/manwe/dsl/mixin/ServerLevelMixin.java new file mode 100644 index 0000000..9c95caf --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/ServerLevelMixin.java @@ -0,0 +1,25 @@ +package com.manwe.dsl.mixin; + +import com.manwe.dsl.config.DSLServerConfigs; +import net.minecraft.server.level.ServerLevel; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.function.BooleanSupplier; + +@Mixin(ServerLevel.class) +public class ServerLevelMixin { + + //TODO puede que se utilize esto para manejar estados globales como el daytime + + /** + * @author Manwe + * @reason No ticking for the ServerLevels in the proxy + */ + @Inject(method = "tick", at=@At("HEAD"), cancellable = true) + public void tick(BooleanSupplier pHasTimeLeft, CallbackInfo ci){ + if(DSLServerConfigs.IS_PROXY.get()) ci.cancel(); + } +} diff --git a/src/main/java/com/manwe/dsl/mixin/accessors/EntityAccessor.java b/src/main/java/com/manwe/dsl/mixin/accessors/EntityAccessor.java new file mode 100644 index 0000000..4fc0933 --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/accessors/EntityAccessor.java @@ -0,0 +1,15 @@ +package com.manwe.dsl.mixin.accessors; + +import net.minecraft.world.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.concurrent.atomic.AtomicInteger; + +@Mixin(Entity.class) +public interface EntityAccessor { + @Accessor("ENTITY_COUNTER") + static AtomicInteger getEntityCounter(){ + throw new IllegalStateException("Accessor not transformed!"); + } +} diff --git a/src/main/java/com/manwe/dsl/mixin/accessors/PlayerAccessor.java b/src/main/java/com/manwe/dsl/mixin/accessors/PlayerAccessor.java new file mode 100644 index 0000000..d617c69 --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/accessors/PlayerAccessor.java @@ -0,0 +1,13 @@ +package com.manwe.dsl.mixin.accessors; + +import net.minecraft.world.entity.player.Abilities; +import net.minecraft.world.entity.player.Player; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(Player.class) +public interface PlayerAccessor { + @Accessor("abilities") + Abilities getAbilities(); +} diff --git a/src/main/java/com/manwe/dsl/mixin/accessors/ServerGamePacketListenerImplAccessor.java b/src/main/java/com/manwe/dsl/mixin/accessors/ServerGamePacketListenerImplAccessor.java index feb1a8c..78c8277 100644 --- a/src/main/java/com/manwe/dsl/mixin/accessors/ServerGamePacketListenerImplAccessor.java +++ b/src/main/java/com/manwe/dsl/mixin/accessors/ServerGamePacketListenerImplAccessor.java @@ -13,4 +13,58 @@ public interface ServerGamePacketListenerImplAccessor { @Accessor("awaitingPositionFromClient") Vec3 getAwaitingPositionFromClient(); + + @Accessor("awaitingTeleport") + int getAwaitingTeleport(); + + @Accessor("awaitingTeleport") + void setAwaitingTeleport(int a); + + @Accessor("firstGoodX") + double getFirstGoodX(); + + @Accessor("firstGoodY") + double getFirstGoodY(); + + @Accessor("firstGoodZ") + double getFirstGoodZ(); + + @Accessor("firstGoodX") + void setFirstGoodX(double a); + + @Accessor("firstGoodY") + void setFirstGoodY(double a); + + @Accessor("firstGoodZ") + void setFirstGoodZ(double a); + + @Accessor("lastGoodX") + double getLastGoodX(); + + @Accessor("lastGoodY") + double getLastGoodY(); + + @Accessor("lastGoodZ") + double getLastGoodZ(); + + @Accessor("lastGoodX") + void setLastGoodX(double a); + + @Accessor("lastGoodY") + void setLastGoodY(double a); + + @Accessor("lastGoodZ") + void setLastGoodZ(double a); + + @Accessor("receivedMovePacketCount") + int getReceivedMovePacketCount(); + + @Accessor("receivedMovePacketCount") + void setReceivedMovePacketCount(int i); + + @Accessor("knownMovePacketCount") + int getKnownMovePacketCount(); + + @Accessor("clientIsFloating") + void setClientIsFloating(boolean a); } diff --git a/src/main/java/com/manwe/dsl/mixin/accessors/ServerLevelAccessor.java b/src/main/java/com/manwe/dsl/mixin/accessors/ServerLevelAccessor.java new file mode 100644 index 0000000..5ca4e6f --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/accessors/ServerLevelAccessor.java @@ -0,0 +1,13 @@ +package com.manwe.dsl.mixin.accessors; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.entity.EntityTickList; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ServerLevel.class) +public interface ServerLevelAccessor { + + @Accessor("entityTickList") + EntityTickList getEntityTickList(); +} diff --git a/src/main/java/com/manwe/dsl/mixin/accessors/SynchedEntityDataAccessor.java b/src/main/java/com/manwe/dsl/mixin/accessors/SynchedEntityDataAccessor.java new file mode 100644 index 0000000..cf07597 --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/accessors/SynchedEntityDataAccessor.java @@ -0,0 +1,14 @@ +package com.manwe.dsl.mixin.accessors; + +import net.minecraft.network.syncher.SynchedEntityData; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(SynchedEntityData.class) +public interface SynchedEntityDataAccessor { + @Accessor("isDirty") + void setDirty(boolean dirty); + + @Accessor("itemsById") + SynchedEntityData.DataItem[] getItemsById(); +} diff --git a/src/main/java/com/manwe/dsl/mixin/chunk/ChunkTrackingViewMixin.java b/src/main/java/com/manwe/dsl/mixin/chunk/ChunkTrackingViewMixin.java new file mode 100644 index 0000000..f7c9670 --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/chunk/ChunkTrackingViewMixin.java @@ -0,0 +1,20 @@ +package com.manwe.dsl.mixin.chunk; + +import com.manwe.dsl.connectionRouting.RegionRouter; +import net.minecraft.server.level.ChunkTrackingView; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ChunkTrackingView.class) +public interface ChunkTrackingViewMixin { + + @Inject(method = "isWithinDistance", at = @At("RETURN"), cancellable = true) + private static void isWithinDistance(int pCenterX, int pCenterZ, int pViewDistance, int pX, int pZ, boolean pIncludeOuterChunksAdjacentToViewBorder, CallbackInfoReturnable cir) { + //In chunk cords, pX pZ + if(!RegionRouter.isChunkInWorkerDomain(pX,pZ)) { + cir.setReturnValue(false); //Set false if outside worker bounds + } + } +} diff --git a/src/main/java/com/manwe/dsl/mixin/chunk/DistanceManagerMixin.java b/src/main/java/com/manwe/dsl/mixin/chunk/DistanceManagerMixin.java new file mode 100644 index 0000000..da1083f --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/chunk/DistanceManagerMixin.java @@ -0,0 +1,24 @@ +package com.manwe.dsl.mixin.chunk; + +import com.manwe.dsl.connectionRouting.RegionRouter; +import net.minecraft.server.level.*; +import net.minecraft.world.level.ChunkPos; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(DistanceManager.class) +public class DistanceManagerMixin { + /* + @Redirect( + method = "addPlayer", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/server/level/TickingTracker;addTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V") + ) + public void redirectAddTicket(TickingTracker instance, TicketType pType, ChunkPos pChunkPos, int pTicketLevel, T pKey){ + if(RegionRouter.isChunkInWorkerDomain(pChunkPos.x,pChunkPos.z)){ + instance.addTicket(pType,pChunkPos,pTicketLevel,pKey); + } + }*/ +} diff --git a/src/main/java/com/manwe/dsl/mixin/chunk/TickingTrackerMixin.java b/src/main/java/com/manwe/dsl/mixin/chunk/TickingTrackerMixin.java new file mode 100644 index 0000000..11498cd --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/chunk/TickingTrackerMixin.java @@ -0,0 +1,28 @@ +package com.manwe.dsl.mixin.chunk; + +import com.manwe.dsl.connectionRouting.RegionRouter; +import it.unimi.dsi.fastutil.longs.Long2ByteMap; +import net.minecraft.server.level.TickingTracker; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(TickingTracker.class) +public class TickingTrackerMixin { + + @Shadow @Final protected Long2ByteMap chunks; + + /** + * @author Manwe + * @reason Return unloaded level for chunks outside this worker + */ + @Overwrite + protected int getLevel(long pChunkPos) { + if(RegionRouter.isChunkInWorkerDomain(pChunkPos)){ + return this.chunks.get(pChunkPos); + } else { + return this.chunks.defaultReturnValue(); + } + } +} diff --git a/src/main/java/com/manwe/dsl/mixin/invokers/ServerGamePacketListenerImplInvoker.java b/src/main/java/com/manwe/dsl/mixin/invokers/ServerGamePacketListenerImplInvoker.java new file mode 100644 index 0000000..8f05af1 --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/invokers/ServerGamePacketListenerImplInvoker.java @@ -0,0 +1,21 @@ +package com.manwe.dsl.mixin.invokers; + +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.phys.AABB; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(ServerGamePacketListenerImpl.class) +public interface ServerGamePacketListenerImplInvoker { + + @Invoker("updateAwaitingTeleport") + boolean invokeUpdateAwaitingTeleport(); + + @Invoker("isPlayerCollidingWithAnythingNew") + boolean invokeIsPlayerCollidingWithAnythingNew(LevelReader pLevel, AABB pBox, double pX, double pY, double pZ); + + @Invoker("noBlocksAround") + boolean invokeNoBlocksAround(Entity pEntity); +} diff --git a/src/main/java/com/manwe/dsl/mixin/log/ClientLevelInvoker.java b/src/main/java/com/manwe/dsl/mixin/log/ClientLevelInvoker.java new file mode 100644 index 0000000..f1c4032 --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/log/ClientLevelInvoker.java @@ -0,0 +1,13 @@ +package com.manwe.dsl.mixin.log; + +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.entity.LevelEntityGetter; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(ClientLevel.class) +public interface ClientLevelInvoker { + @Invoker("getEntities") + LevelEntityGetter invokeGetEntities(); +} diff --git a/src/main/java/com/manwe/dsl/mixin/log/ClientLevelMixin.java b/src/main/java/com/manwe/dsl/mixin/log/ClientLevelMixin.java new file mode 100644 index 0000000..f0fc8a3 --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/log/ClientLevelMixin.java @@ -0,0 +1,41 @@ +package com.manwe.dsl.mixin.log; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.entity.EntityTickList; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ClientLevel.class) +public class ClientLevelMixin { + + @Shadow @Final private EntityTickList tickingEntities; + + @Inject(method = "tickEntities",at = @At("HEAD")) + public void tickEntities(CallbackInfo ci){ + //System.out.println("Tick entities"); + //this.tickingEntities.forEach(System.out::println); + } + + @Inject(method = "addEntity",at = @At("HEAD")) + public void addEntity(Entity pEntity, CallbackInfo ci){ + //System.out.println("addEntity: "+ pEntity.getName().getString() + " id:" + pEntity.getId()); + } + + @Inject(method = "removeEntity",at = @At("HEAD")) + public void removeEntity(int pEntityId, Entity.RemovalReason pReason, CallbackInfo ci){ + /* + if(Minecraft.getInstance().player == null) return; + int me = Minecraft.getInstance().player.getId(); + + if(pEntityId == me) { + System.out.println("ELIMINADO JUGADOR "+ pReason.name()); + Thread.dumpStack(); + }*/ + } +} diff --git a/src/main/java/com/manwe/dsl/mixin/log/ClientPacketListenerMixin.java b/src/main/java/com/manwe/dsl/mixin/log/ClientPacketListenerMixin.java new file mode 100644 index 0000000..327353e --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/log/ClientPacketListenerMixin.java @@ -0,0 +1,163 @@ +package com.manwe.dsl.mixin.log; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.protocol.game.*; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import org.checkerframework.checker.units.qual.A; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * ONLY FOR DEBUG THIS MOD DOES NOT AIM TO CHANGE THE CLIENT IN ANY WAY + */ +@Mixin(ClientPacketListener.class) +public class ClientPacketListenerMixin { + + @Inject(method = "handleChangeDifficulty",at = @At("HEAD")) + public void handleChangeDifficulty(ClientboundChangeDifficultyPacket par1, CallbackInfo ci){ + //System.out.println("handleChangeDifficulty"); + } + @Inject(method = "handlePlayerAbilities",at = @At("HEAD")) + public void handlePlayerAbilities(ClientboundPlayerAbilitiesPacket pPacket, CallbackInfo ci){ + //System.out.println("handlePlayerAbilities"); + } + @Inject(method = "handleSetCarriedItem",at = @At("HEAD")) + public void handleSetCarriedItem(ClientboundSetCarriedItemPacket pPacket, CallbackInfo ci){ + //System.out.println("handleSetCarriedItem"); + } + @Inject(method = "handleUpdateRecipes",at = @At("HEAD")) + public void handleUpdateRecipes(ClientboundUpdateRecipesPacket pPacket, CallbackInfo ci){ + //System.out.println("handleUpdateRecipes"); + } + @Inject(method = "handleEntityEvent",at = @At("HEAD")) + public void handleEntityEvent(ClientboundEntityEventPacket pPacket, CallbackInfo ci){ + //System.out.println("handleEntityEvent id:" + pPacket.getEventId()); + } + @Inject(method = "handleAddOrRemoveRecipes",at = @At("HEAD")) + public void handleAddOrRemoveRecipes(ClientboundRecipePacket pPacket, CallbackInfo ci){ + //System.out.println("handleAddOrRemoveRecipes"); + } + @Inject(method = "handleAddObjective",at = @At("HEAD")) + public void handleAddObjective(ClientboundSetObjectivePacket pPacket, CallbackInfo ci){ + //System.out.println("handleAddObjective"); + } + @Inject(method = "handleSetDisplayObjective",at = @At("HEAD")) + public void handleSetDisplayObjective(ClientboundSetDisplayObjectivePacket pPacket, CallbackInfo ci){ + //System.out.println("handleSetDisplayObjective"); + } + @Inject(method = "handleSetScore",at = @At("HEAD")) + public void handleSetScore(ClientboundSetScorePacket pPacket, CallbackInfo ci){ + //System.out.println("handleSetScore"); + } + @Inject(method = "handleMovePlayer",at = @At("HEAD")) + public void handleMovePlayer(ClientboundPlayerPositionPacket pPacket, CallbackInfo ci){ + //System.out.println("handleMovePlayer"); + } + @Inject(method = "handleServerData",at = @At("HEAD")) + public void handleServerData(ClientboundServerDataPacket pPacket, CallbackInfo ci){ + //System.out.println("handleServerData"); + } + @Inject(method = "handlePlayerInfoUpdate",at = @At("HEAD")) + public void handlePlayerInfoUpdate(ClientboundPlayerInfoUpdatePacket pPacket, CallbackInfo ci){ + //System.out.println("handlePlayerInfoUpdate"); + //pPacket.actions().forEach(action -> System.out.println(action)); + + } + @Inject(method = "handleInitializeBorder",at = @At("HEAD")) + public void handleInitializeBorder(ClientboundInitializeBorderPacket pPacket, CallbackInfo ci){ + //System.out.println("handleInitializeBorder"); + } + @Inject(method = "handleSetTime",at = @At("HEAD")) + public void handleSetTime(ClientboundSetTimePacket pPacket, CallbackInfo ci){ + //System.out.println("handleSetTime"); + } + @Inject(method = "handleSetSpawn",at = @At("HEAD")) + public void handleSetSpawn(ClientboundSetDefaultSpawnPositionPacket pPacket, CallbackInfo ci){ + //System.out.println("handleSetSpawn"); + } + @Inject(method = "handleGameEvent",at = @At("HEAD")) + public void handleGameEvent(ClientboundGameEventPacket pPacket, CallbackInfo ci){ + //System.out.println("handleGameEvent"); + } + @Inject(method = "handleBossUpdate",at = @At("HEAD")) + public void handleBossUpdate(ClientboundBossEventPacket pPacket, CallbackInfo ci){ + //System.out.println("handleBossUpdate"); + } + @Inject(method = "handleUpdateMobEffect",at = @At("HEAD")) + public void handleUpdateMobEffect(ClientboundUpdateMobEffectPacket pPacket, CallbackInfo ci){ + //System.out.println("handleUpdateMobEffect"); + } + @Inject(method = "handleLogin",at = @At("HEAD")) + public void handleLogin(ClientboundLoginPacket pPacket, CallbackInfo ci){ + //System.out.println("handleLogin"); + } + @Inject(method = "handleSetHealth", at = @At("HEAD")) + public void handleSetHealth(ClientboundSetHealthPacket pPacket, CallbackInfo ci){ + //System.out.println("handleSetHealth"); + } + @Inject(method = "handleLevelChunkWithLight", at = @At("HEAD")) + public void handleLevelChunkWithLight(ClientboundLevelChunkWithLightPacket pPacket, CallbackInfo ci){ + //System.out.printf("chunk %d,%d arrived (player %d,%d)%n", + // pPacket.getX(), pPacket.getZ(), + // Minecraft.getInstance().player.getBlockX() >> 4, + // Minecraft.getInstance().player.getBlockZ() >> 4); + } + @Inject(method = "handleChunkBatchFinished", at = @At("HEAD")) + public void handleChunkBatchFinished(ClientboundChunkBatchFinishedPacket pPacket, CallbackInfo ci){ + //System.out.println("handleChunkBatchFinished size: "+pPacket.batchSize()); + } + @Inject(method = "handleChunkBatchStart", at = @At("HEAD")) + public void handleChunkBatchStart(ClientboundChunkBatchStartPacket pPacket, CallbackInfo ci){ + //System.out.println("handleChunkBatchStart"); + } + + @Inject(method = "handleForgetLevelChunk", at = @At("HEAD")) + public void handleForgetLevelChunk(ClientboundForgetLevelChunkPacket pPacket, CallbackInfo ci){ + //System.out.printf("chunk %d,%d UNLOADED%n", pPacket.pos().x, pPacket.pos().z); + } + + @Inject(method = "handleRemoveEntities", at = @At("HEAD")) + public void handleRemoveEntities(ClientboundRemoveEntitiesPacket pPacket, CallbackInfo ci){ + /* + int me = Minecraft.getInstance().player.getId(); + System.out.println("handleRemoveEntities player id " + me); + + if(Minecraft.getInstance().level == null) { + System.out.println("level == null"); + } else { + for(Integer id : pPacket.getEntityIds()){ + Entity entity = ((ClientLevelInvoker) Minecraft.getInstance().level).invokeGetEntities().get(id); + if(entity != null){ + System.out.println("Removed entity: " + entity.getName().getString()); + } else { + System.out.println("Removed unknown with id: " +id); + } + } + } + */ + } + @Inject(method = "handleRespawn", at = @At("HEAD")) + public void handleRespawn(ClientboundRespawnPacket pPacket, CallbackInfo ci){ + //System.out.println("handleRespawn"); + } + @Inject(method = "handlePlayerInfoRemove", at = @At("HEAD")) + public void handlePlayerInfoRemove(ClientboundPlayerInfoRemovePacket pPacket, CallbackInfo ci){ + //System.out.println("handlePlayerInfoRemove UUIDS:"); + //pPacket.profileIds().forEach(System.out::println); + } + + @Inject(method = "handleSetEntityData", at=@At("HEAD")) + public void handleSetEntityData(ClientboundSetEntityDataPacket pPacket, CallbackInfo ci){ + for(SynchedEntityData.DataValue data : pPacket.packedItems()){ + System.out.println("ID: " + data.id() + " DATA: " + data.value()); + } + } + +} diff --git a/src/main/java/com/manwe/dsl/mixin/log/ClientboundLoginPacketMixin.java b/src/main/java/com/manwe/dsl/mixin/log/ClientboundLoginPacketMixin.java new file mode 100644 index 0000000..c1b9ccc --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/log/ClientboundLoginPacketMixin.java @@ -0,0 +1,20 @@ +package com.manwe.dsl.mixin.log; + +import net.minecraft.network.protocol.game.ClientboundLoginPacket; +import net.minecraft.network.protocol.game.CommonPlayerSpawnInfo; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Set; + +@Mixin(ClientboundLoginPacket.class) +public class ClientboundLoginPacketMixin { + + @Inject(method = "(IZLjava/util/Set;IIIZZZLnet/minecraft/network/protocol/game/CommonPlayerSpawnInfo;Z)V",at = @At("RETURN")) + public void onConstruct(int playerId, boolean hardcore, Set levels, int maxPlayers, int chunkRadius, int simulationDistance, boolean reducedDebugInfo, boolean showDeathScreen, boolean doLimitedCrafting, CommonPlayerSpawnInfo commonPlayerSpawnInfo, boolean enforcesSecureChat, CallbackInfo ci){ + //System.out.println("CONSTRUCT ClientboundLoginPacket "+playerId); + //Thread.dumpStack(); + } +} diff --git a/src/main/java/com/manwe/dsl/mixin/log/LocalPlayerMixin.java b/src/main/java/com/manwe/dsl/mixin/log/LocalPlayerMixin.java new file mode 100644 index 0000000..65225da --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/log/LocalPlayerMixin.java @@ -0,0 +1,45 @@ +package com.manwe.dsl.mixin.log; + +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.resources.sounds.AmbientSoundHandler; +import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; +import net.minecraft.network.protocol.game.ServerboundMoveVehiclePacket; +import net.minecraft.network.protocol.game.ServerboundPlayerInputPacket; +import net.minecraft.world.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(LocalPlayer.class) +public abstract class LocalPlayerMixin { + + @Shadow protected abstract boolean isControlledCamera(); + + @Inject(method = "tick",at = @At("HEAD")) + private void tick(CallbackInfo ci){ + System.out.println("TICK"); + /* + if (((Entity)(Object)this).level().hasChunkAt(((Entity)(Object)this).getBlockX(), ((Entity)(Object)this).getBlockZ())) { + + if (((Entity)(Object)this).isPassenger()) { + System.out.println("IsPassenger"); + } else { + System.out.println("SendPosition"); + } + } else { + System.out.println("Not send Position"); + }*/ + } + + @Inject(method = "sendPosition", at = @At("HEAD")) + private void sendPosition(CallbackInfo ci){ + /* + if (this.isControlledCamera()) { + System.out.println("Send Movement"); + }else { + System.out.println("Not Send Movement, isControlledCamera false"); + }*/ + } +} diff --git a/src/main/java/com/manwe/dsl/mixin/log/PlayerListMixin.java b/src/main/java/com/manwe/dsl/mixin/log/PlayerListMixin.java new file mode 100644 index 0000000..7ba5e7d --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/log/PlayerListMixin.java @@ -0,0 +1,19 @@ +package com.manwe.dsl.mixin.log; + +import net.minecraft.network.Connection; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.server.players.PlayerList; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(PlayerList.class) +public class PlayerListMixin { + + @Inject(method = "placeNewPlayer",at = @At("HEAD")) + public void placeNewPlayer(Connection pConnection, ServerPlayer pPlayer, CommonListenerCookie pCookie, CallbackInfo ci) { + System.out.println("placeNewPlayer VANILLA ESTO NO DEBERA APARECER EN NINGÚN CASO"); + } +} diff --git a/src/main/java/com/manwe/dsl/mixin/log/PlayerMixin.java b/src/main/java/com/manwe/dsl/mixin/log/PlayerMixin.java new file mode 100644 index 0000000..994c076 --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/log/PlayerMixin.java @@ -0,0 +1,25 @@ +package com.manwe.dsl.mixin.log; + +import com.manwe.dsl.mixin.accessors.PlayerAccessor; +import net.minecraft.world.entity.Pose; +import net.minecraft.world.entity.player.Player; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import javax.annotation.Nullable; + +@Mixin(Player.class) +public abstract class PlayerMixin { + @Shadow @Nullable private Pose forcedPose; + + @Shadow protected abstract boolean canPlayerFitWithinBlocksAndEntitiesWhen(Pose pPose); + + @Inject(method = "tick",at= @At("HEAD")) + public void tick(CallbackInfo ci){ + //System.out.println("TICK - POSE: " + ((Player) (Object)this).getPose().name()); + } +} diff --git a/src/main/java/com/manwe/dsl/mixin/log/ServerPlayerMixin.java b/src/main/java/com/manwe/dsl/mixin/log/ServerPlayerMixin.java new file mode 100644 index 0000000..36dffba --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/log/ServerPlayerMixin.java @@ -0,0 +1,24 @@ +package com.manwe.dsl.mixin.log; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ServerPlayer.class) +public class ServerPlayerMixin { + + @Inject(method = "tick", at = @At("HEAD")) + public void tick(CallbackInfo ci){ + //System.out.println("tick()" + ((Player) (Object) this).getName()); + //System.out.flush(); + } + + @Inject(method = "doTick", at = @At("HEAD")) + public void doTick(CallbackInfo ci) { + //System.out.println("doTick" + ((Player) (Object) this).getName()); + //System.out.flush(); + } +} diff --git a/src/main/resources/dsl.mixins.json b/src/main/resources/dsl.mixins.json index ddc316b..8e70840 100644 --- a/src/main/resources/dsl.mixins.json +++ b/src/main/resources/dsl.mixins.json @@ -6,13 +6,29 @@ "mixins": [ "MainMixin", "MinecraftServerInvoker", + "ServerLevelMixin", "accessors.ConnectionAccessor", "accessors.DedicatedServerAccessor", + "accessors.EntityAccessor", "accessors.MinecraftServerAccessor", "accessors.PlayerListAccessor", "accessors.ServerConnectionListenerAccessor", - "accessors.ServerGamePacketListenerImplAccessor" + "accessors.ServerGamePacketListenerImplAccessor", + "accessors.ServerLevelAccessor", + "accessors.SynchedEntityDataAccessor", + "chunk.ChunkTrackingViewMixin", + "chunk.DistanceManagerMixin", + "chunk.TickingTrackerMixin", + "invokers.ServerGamePacketListenerImplInvoker", + "log.ClientboundLoginPacketMixin", + "log.PlayerListMixin", + "log.PlayerMixin", + "log.ServerPlayerMixin" ], "client": [ + "log.ClientLevelInvoker", + "log.ClientLevelMixin", + "log.ClientPacketListenerMixin", + "log.LocalPlayerMixin" ] } \ No newline at end of file