|
3 | 3 | import java.nio.ByteBuffer; |
4 | 4 | import java.util.HashMap; |
5 | 5 | import java.util.UUID; |
| 6 | +import net.evmodder.evmod.Main; |
6 | 7 | import net.evmodder.evmod.apis.MiscUtils; |
7 | 8 | import net.evmodder.evmod.apis.PlayerPosIPC; |
8 | 9 | import net.evmodder.evmod.apis.TickListener; |
9 | | -import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; |
| 10 | +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; |
| 11 | +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; |
10 | 12 | import net.minecraft.client.MinecraftClient; |
11 | 13 | import net.minecraft.client.network.OtherClientPlayerEntity; |
12 | 14 | import net.minecraft.client.network.PlayerListEntry; |
13 | | -import net.minecraft.client.render.WorldRenderer; |
14 | | -import net.minecraft.client.util.math.MatrixStack; |
15 | | -import net.minecraft.util.math.BlockPos; |
16 | | -import net.minecraft.util.math.Vec3d; |
| 15 | +import net.minecraft.entity.EntityPose; |
| 16 | +import net.minecraft.entity.player.PlayerEntity; |
17 | 17 |
|
18 | 18 | public final class SyncPlayerPos implements TickListener{ |
19 | 19 | private final static boolean ONLY_SHOW_PLAYERS_IN_LOADED_CHUNKS = true; |
20 | 20 | private final static ByteBuffer bb = ByteBuffer.allocate(PlayerPosIPC.DATA_SIZE); |
21 | 21 | private final MinecraftClient client = MinecraftClient.getInstance(); |
22 | 22 |
|
| 23 | + private boolean wasNull = true; |
23 | 24 | @Override public final void onTickEnd(final MinecraftClient client){ |
24 | | - if(client.player == null || client.world == null) return; |
| 25 | + final PlayerEntity player = client.player; |
| 26 | + if(player == null || client.world == null){wasNull = true; return;} |
| 27 | + if(wasNull){wasNull = false; Main.LOGGER.info("[EvMod] Registered SyncPlayerPos for player: "+client.player.getName().getString());} |
25 | 28 | bb.putInt(MiscUtils.getServerAddressHashCode()); |
26 | 29 | bb.putInt(MiscUtils.getDimensionId(client.world)); |
27 | | - bb.putLong(client.player.getUuid().getMostSignificantBits()).putLong(client.player.getUuid().getLeastSignificantBits()); |
28 | | - bb.putDouble(client.player.getX()).putDouble(client.player.getY()).putDouble(client.player.getZ()); |
| 30 | + bb.putLong(player.getUuid().getMostSignificantBits()).putLong(player.getUuid().getLeastSignificantBits()); |
| 31 | + bb.putDouble(player.getX()).putDouble(player.getY()).putDouble(player.getZ()); |
| 32 | + bb.putFloat(player.getYaw()).putFloat(player.getPitch()).putFloat(player.getHeadYaw()); |
| 33 | + bb.putDouble(player.getVelocity().getX()).putDouble(player.getVelocity().getY()).putDouble(player.getVelocity().getZ()); |
| 34 | + bb.putInt(player.getPose().getIndex()); |
| 35 | +// bb.putFloat(player.getHealth()); |
29 | 36 | PlayerPosIPC.getInstance().postData(bb.array()); |
30 | 37 | bb.rewind(); |
31 | 38 | } |
32 | 39 |
|
33 | | - public SyncPlayerPos(){ |
34 | | - final HashMap<UUID, OtherClientPlayerEntity> fakePlayers = new HashMap<>(); |
35 | | - WorldRenderEvents.AFTER_ENTITIES.register(context -> { |
36 | | - if (client.world == null || client.getNetworkHandler() == null) return; |
| 40 | + private final HashMap<UUID, OtherClientPlayerEntity> fakePlayers = new HashMap<>(); |
| 41 | + public final boolean removeFakePlayer(final UUID uuid){ // Accessor: MixinClientPlayNetworkHandler |
| 42 | + final OtherClientPlayerEntity dummy = fakePlayers.remove(uuid); |
| 43 | + if(dummy != null) dummy.discard(); |
| 44 | + return dummy != null; |
| 45 | + } |
37 | 46 |
|
38 | | - final int myServer = MiscUtils.getServerAddressHashCode(), myWorld = MiscUtils.getDimensionId(client.world); |
| 47 | + private int NEXT_DUMMY_ID = -1000; // Custom ID for the client-side entity |
| 48 | + public SyncPlayerPos(){ |
| 49 | + ClientPlayConnectionEvents.DISCONNECT.register((_handler, _client) -> fakePlayers.clear()); |
| 50 | + //WorldRenderEvents.AFTER_ENTITIES.register(context -> { |
| 51 | + ClientTickEvents.END_WORLD_TICK.register(world -> { |
| 52 | + final int myServerHash = MiscUtils.getServerAddressHashCode(), myWorldHash = MiscUtils.getDimensionId(world); |
39 | 53 | PlayerPosIPC.getInstance().readData(b -> { |
| 54 | +// if(client.getNetworkHandler() == null) return; |
40 | 55 | final ByteBuffer bb = ByteBuffer.wrap(b); |
41 | | - final int server = bb.getInt(), world = bb.getInt(); |
42 | | - if(server != myServer || world != myWorld) return; |
| 56 | + final int serverHash = bb.getInt(), worldHash = bb.getInt(); |
43 | 57 | final UUID uuid = new UUID(bb.getLong(), bb.getLong()); |
44 | | - if(client.world.getPlayerByUuid(uuid) != null) return; // Already loaded |
| 58 | + if(serverHash != myServerHash || worldHash != myWorldHash){ |
| 59 | + if(removeFakePlayer(uuid)) Main.LOGGER.info("[EvMod] Removed dummy player (different world): "+uuid); |
| 60 | + return; |
| 61 | + } |
45 | 62 | final PlayerListEntry entry = client.getNetworkHandler().getPlayerListEntry(uuid); |
46 | | - if(entry == null) return; // Not online! |
| 63 | + if(entry == null){ // Not online! |
| 64 | + if(removeFakePlayer(uuid)) Main.LOGGER.info("[EvMod] Removed dummy player (not online): "+uuid); |
| 65 | + return; |
| 66 | + } |
| 67 | + final PlayerEntity existingPlayer1 = world.getPlayerByUuid(uuid); |
| 68 | + if(existingPlayer1 != null && existingPlayer1.getId() >= 0){ // Already loaded 1 |
| 69 | + if(removeFakePlayer(uuid)) Main.LOGGER.info("[EvMod] Removed dummy player (real player loaded 1): "+existingPlayer1.getName().getString()); |
| 70 | + return; |
| 71 | + } |
| 72 | + /*final PlayerEntity existingPlayer2 = world.getPlayers().stream().filter(p -> p.getUuid().equals(uuid) && p.getId() >= 0).findAny().orElse(null); |
| 73 | + if(existingPlayer2 != null){ // Already loaded 2 |
| 74 | + if(removeFakePlayer(uuid)) Main.LOGGER.info("[EvMod] Removed dummy player (real player loaded 2): "+existingPlayer2.getName().getString()); |
| 75 | + return; |
| 76 | + }*/ |
47 | 77 | final double x = bb.getDouble(), y = bb.getDouble(), z = bb.getDouble(); |
48 | | - final BlockPos bp = BlockPos.ofFloored(x, y, z); |
49 | | - final int light; |
50 | | - if(!client.world.getChunkManager().isChunkLoaded(bp.getX() >> 4, bp.getZ() >> 4)){ |
51 | | - if(ONLY_SHOW_PLAYERS_IN_LOADED_CHUNKS) return; |
52 | | - light = 0xF000F0; // Full brightness lightmap |
| 78 | + if(!world.getChunkManager().isChunkLoaded(((int)x) >> 4, ((int)z) >> 4)){ |
| 79 | + if(ONLY_SHOW_PLAYERS_IN_LOADED_CHUNKS){ |
| 80 | + if(removeFakePlayer(uuid)) Main.LOGGER.info("[EvMod] Removed dummy player (unloaded chunks): "+entry.getProfile().getName()); |
| 81 | + return; |
| 82 | + } |
53 | 83 | } |
54 | | - else light = WorldRenderer.getLightmapCoordinates(client.world, bp); |
55 | | - |
| 84 | + final float yaw = bb.getFloat(), pitch = bb.getFloat(); |
| 85 | +// final double velX = bb.getDouble(), velY = bb.getDouble(), velZ = bb.getDouble(); |
56 | 86 | final OtherClientPlayerEntity dummy = fakePlayers.computeIfAbsent(uuid, _0->{ |
57 | | - OtherClientPlayerEntity d = new OtherClientPlayerEntity(client.world, entry.getProfile()); |
58 | | - d.prevX = x; d.prevY = y; d.prevZ = z; |
| 87 | + final OtherClientPlayerEntity d = new OtherClientPlayerEntity(world, entry.getProfile()); |
| 88 | + d.setId(--NEXT_DUMMY_ID); |
| 89 | + Main.LOGGER.info(String.format("[EvMod] Adding dummy player '%s' at %d %d %d", d.getName().getString(), (int)x, (int)y, (int)z)); |
| 90 | +// d.getDataTracker().set(net.minecraft.entity.player.PlayerEntity.PLAYER_MODEL_PARTS, (byte)0x7F); |
| 91 | + d.setInvisible(false); |
| 92 | +// d.unsetRemoved(); |
| 93 | +// d.revive(); |
| 94 | +// final SkinTextures textures = entry.getSkinTextures(); |
| 95 | +// final boolean skinHasHat = textures.secure() && textures.texture() != null; |
| 96 | +// d.getSkinTextures() |
| 97 | +// d.getDataTracker().set(PlayerEntity., modelParts); |
| 98 | + d.refreshPositionAndAngles(x, y, z, yaw, pitch); |
| 99 | +// d.resetPosition(); // Sets prev X,Y,Z,yaw,pitch - already called by refreshPositionAndAngles() |
| 100 | + world.addEntity(d); // Inject into world |
59 | 101 | return d; |
60 | 102 | }); |
61 | | - dummy.setPos(x, y, z); |
62 | | - |
63 | | - final float tickDelta = context.tickCounter().getTickDelta(true); |
64 | | - final MatrixStack matrices = context.matrixStack(); |
65 | | - final Vec3d cameraPos = context.camera().getPos(); |
66 | | - matrices.push(); |
67 | | - matrices.translate(x - cameraPos.x, y - cameraPos.y, z - cameraPos.z); |
68 | | - client.getEntityRenderDispatcher().render(dummy, 0d, 0d, 0d, tickDelta, matrices, context.consumers(), light); |
69 | | - matrices.pop(); |
| 103 | + dummy.setHeadYaw(bb.getFloat()); |
| 104 | + dummy.setVelocity(bb.getDouble(), bb.getDouble(), bb.getDouble()); |
| 105 | + dummy.setPose(EntityPose.INDEX_TO_VALUE.apply(bb.getInt())); |
| 106 | + dummy.updateTrackedPositionAndAngles(x, y, z, yaw, pitch, 0); |
| 107 | + dummy.updatePositionAndAngles(x, y, z, yaw, pitch); |
| 108 | +// dummy.setHealth(bb.getFloat()); |
| 109 | + dummy.tick(); |
| 110 | +// final int light; |
| 111 | +// if(client.world.getChunkManager().isChunkLoaded(bp.getX() >> 4, bp.getZ() >> 4)){ |
| 112 | +// light = WorldRenderer.getLightmapCoordinates(client.world, bp); |
| 113 | +// } |
| 114 | +// else light = 0xF000F0; // Full brightness lightmap |
| 115 | +// final float tickDelta = context.tickCounter().getTickDelta(true); |
| 116 | +// final MatrixStack matrices = context.matrixStack(); |
| 117 | +// final Vec3d cameraPos = context.camera().getPos(); |
| 118 | +// matrices.push(); |
| 119 | +// matrices.translate(x - cameraPos.x, y - cameraPos.y, z - cameraPos.z); |
| 120 | +// client.getEntityRenderDispatcher().render(dummy, 0d, 0d, 0d, tickDelta, matrices, context.consumers(), light); |
| 121 | +// matrices.pop(); |
70 | 122 | }); |
71 | 123 | }); |
72 | 124 | } |
|
0 commit comments