Skip to content

Commit 66e79f6

Browse files
committed
Add more pos-sync data values, and iron out some bugs
1 parent 7b0f9cd commit 66e79f6

6 files changed

Lines changed: 115 additions & 44 deletions

File tree

src/main/java/net/evmodder/evmod/Main.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ public class Main{
9696
public final RemoteServerSender remoteSender; // MixinClientPlayNetworkHandler
9797
public final EpearlLookupFabric epearlLookup; // MixinEntityRenderer
9898
public final KeybindCraftingRestock kbCraftRestock; // MixinClientPlayerInteractionManager
99+
public final SyncPlayerPos syncPlayerPos; // ClientPlayNetworkHandler
99100

100101
Main(){
101102
Main.LOGGER.info("Loading "+MOD_NAME+" "+MOD_VERSION);
@@ -124,7 +125,9 @@ public class Main{
124125
final GameMessageFilter gameMessageFilter;
125126
final KeybindInventoryOrganize[] kbInvOrgs;
126127
final KeybindInventoryRestock kbInvRestock;
127-
if(mapArtFeaturesOnly){whisperPlaySound = null; gameMessageFilter = null; kbInvOrgs = null; kbInvRestock = null; kbCraftRestock = null;}
128+
if(mapArtFeaturesOnly){
129+
whisperPlaySound = null; gameMessageFilter = null; kbInvOrgs = null; kbInvRestock = null; kbCraftRestock = null; syncPlayerPos = null;
130+
}
128131
else{
129132
whisperPlaySound = new WhisperPlaySound();
130133
if(settings.gameMessageListener) new GameMessageListener(remoteSender, epearlLookup, whisperPlaySound);
@@ -139,6 +142,8 @@ public class Main{
139142

140143
if(settings.broadcaster) ChatBroadcaster.refreshBroadcast();
141144
if(settings.tooltipRepairCost) Tooltip.register(new TooltipRepairCost());
145+
if(settings.playerMoveListener) TickListener.register(syncPlayerPos = new SyncPlayerPos());
146+
else syncPlayerPos = null;
142147
}
143148

144149
if(settings.placementHelperIframeAutoPlace) new AutoPlaceItemFrames();
@@ -158,7 +163,6 @@ public class Main{
158163
if(settings.onTickContainer) TickListener.register(new UpdateContainerContents());
159164
if(settings.containerOpenCloseListener) TickListener.register(new ContainerOpenCloseListener(kbInvRestock));
160165
if(settings.mapLoaderBot) TickListener.register(new MapLoaderBot());
161-
if(settings.playerMoveListener) TickListener.register(new SyncPlayerPos());
162166

163167
if(settings.tooltipMapHighlights) Tooltip.register(new TooltipMapNameColor());
164168
if(settings.tooltipMapMetadata) Tooltip.register(new TooltipMapLoreMetadata());

src/main/java/net/evmodder/evmod/Settings.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ private final HashMap<String, Boolean> loadSettings(){
3737
String configContents = FileIO.loadFile("settings.txt", getClass().getResourceAsStream("/assets/"+Main.MOD_ID+"/"+internalSettingsFile));
3838
{//==================================================
3939
// TODO: remove these legacy-patches in a future version
40-
if(configContents.contains("map_highlights:")){
40+
if(configContents.contains("map_highlights.in_gui:")){
4141
Main.LOGGER.info("EvModConfig: Deleting unusable old settings.txt file (due to name changes; resetting to defaults)");
4242
FileIO.deleteFile("settings.txt");
4343
configContents = FileIO.loadFile("settings.txt", getClass().getResourceAsStream("/assets/"+Main.MOD_ID+"/"+internalSettingsFile));
@@ -81,7 +81,7 @@ private final boolean extractConfigValue(final HashMap<String, Boolean> config,
8181
playerMoveListener = extractConfigValue(settings, "listener.player_move");
8282
serverJoinListener = extractConfigValue(settings, "listener.server_join");
8383
serverQuitListener = extractConfigValue(settings, "listener.server_quit");
84-
blockClickListener = extractConfigValue(settings, "listener.block_click");
84+
blockClickListener = extractConfigValue(settings, "listener.click_block");
8585
gameMessageListener = extractConfigValue(settings, "listener.game_message.read");
8686
gameMessageFilter = extractConfigValue(settings, "listener.game_message.filter");
8787
tooltipMapHighlights = (onTickInventory || onTickIframes) && extractConfigValue(settings, "tooltip.map_highlights");

src/main/java/net/evmodder/evmod/apis/PlayerPosIPC.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,20 @@
99
import java.nio.MappedByteBuffer;
1010
import java.nio.channels.FileChannel;
1111
import java.util.function.Consumer;
12+
import net.evmodder.evmod.Main;
1213

1314
public final class PlayerPosIPC{
1415
private static final class Holder{private static final PlayerPosIPC INSTANCE = new PlayerPosIPC();}
1516
public static final PlayerPosIPC getInstance(){return Holder.INSTANCE;}
1617

1718
// Hopefully nobody is running more than this many Minecraft accounts on 1 device...
1819
private static final int MAX_SLOTS = 64;
19-
// UUID + serverHashCode + worldHashCode + x + y + z
20-
public static final int DATA_SIZE = 16 + 8 + 8 + 8 + 4 + 4; //=48
2120
// PID + TS + version + data
22-
private static final int SLOT_SIZE = 8 + 8 + 8 + DATA_SIZE;
21+
public static final int METADATA_SIZE = 8 + 8 + 8; //=24
22+
// UUID + serverHashCode + worldHashCode + x + y + z + yaw + pitch + headYaw + velX + velY + velZ + pose (+ health?)
23+
public static final int DATA_SIZE = 16 + 4 + 4 + 8 + 8 + 8 + 4 + 4 + 4 + 8 + 8 + 8 + 4; //=92
24+
public static final int CPU_CACHE_LINE_SIZE = 128;
25+
private static final int SLOT_SIZE = Math.ceilDiv(METADATA_SIZE + DATA_SIZE, CPU_CACHE_LINE_SIZE) * CPU_CACHE_LINE_SIZE;
2326
// Treat PID as "dead" if no update for > 15s
2427
private static final long TIMEOUT_NS = 15_000l * 1000000l;
2528

@@ -75,7 +78,10 @@ private final int claimSlot(){
7578
final long owner = (long)LONG_HANDLE.getVolatile(buffer, base);
7679
if(owner > 0l && now - (long)LONG_HANDLE.getVolatile(buffer, base + TIME_OFFSET) < TIMEOUT_NS) continue;
7780
LONG_HANDLE.setVolatile(buffer, base + TIME_OFFSET, now); // Update ts (reduces contention fighting for this slot)
78-
if(LONG_HANDLE.compareAndSet(buffer, base, owner, myPID)) return i; // Nice, we snagged this slot!
81+
if(LONG_HANDLE.compareAndSet(buffer, base, owner, myPID)){
82+
Main.LOGGER.info("[EvMod] Claimed IPC slot "+i);
83+
return i; // Nice, we snagged this slot!
84+
}
7985
// i=-1; // Another PID grabbed the slot before us; start again from i=0.
8086
}
8187
}

src/main/java/net/evmodder/evmod/mixin/MixinClientPlayNetworkHandler.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
import net.minecraft.client.network.ClientPlayNetworkHandler;
1515
import net.minecraft.client.world.ClientWorld;
1616
import net.minecraft.component.type.MapIdComponent;
17+
import net.minecraft.entity.EntityType;
1718
import net.minecraft.item.map.MapState;
19+
import net.minecraft.network.packet.s2c.play.EntitySpawnS2CPacket;
1820
import net.minecraft.network.packet.s2c.play.MapUpdateS2CPacket;
1921
import java.nio.ByteBuffer;
2022
import java.util.HashMap;
@@ -30,6 +32,13 @@
3032

3133
@Mixin(ClientPlayNetworkHandler.class)
3234
abstract class MixinClientPlayNetworkHandler{
35+
@Inject(method="onEntitySpawn", at=@At("HEAD"))
36+
private final void onSpawn(final EntitySpawnS2CPacket packet, final CallbackInfo _ci){
37+
// If the incoming entity is a player and matches your target's UUID
38+
if(packet.getEntityType() == EntityType.PLAYER && AccessorMain.getInstance().syncPlayerPos.removeFakePlayer(packet.getUuid())){
39+
Main.LOGGER.info("[EvMod] Removed dummy player (real player spawned): "+packet.getUuid());
40+
}
41+
}
3342

3443
// Saw this in https://github.com/red-stoned/client_maps/, and realized it's probably good to incorporate
3544
@Redirect(method="onMapUpdate", at=@At(value="INVOKE",

src/main/java/net/evmodder/evmod/onTick/SyncPlayerPos.java

Lines changed: 87 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,70 +3,122 @@
33
import java.nio.ByteBuffer;
44
import java.util.HashMap;
55
import java.util.UUID;
6+
import net.evmodder.evmod.Main;
67
import net.evmodder.evmod.apis.MiscUtils;
78
import net.evmodder.evmod.apis.PlayerPosIPC;
89
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;
1012
import net.minecraft.client.MinecraftClient;
1113
import net.minecraft.client.network.OtherClientPlayerEntity;
1214
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;
1717

1818
public final class SyncPlayerPos implements TickListener{
1919
private final static boolean ONLY_SHOW_PLAYERS_IN_LOADED_CHUNKS = true;
2020
private final static ByteBuffer bb = ByteBuffer.allocate(PlayerPosIPC.DATA_SIZE);
2121
private final MinecraftClient client = MinecraftClient.getInstance();
2222

23+
private boolean wasNull = true;
2324
@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());}
2528
bb.putInt(MiscUtils.getServerAddressHashCode());
2629
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());
2936
PlayerPosIPC.getInstance().postData(bb.array());
3037
bb.rewind();
3138
}
3239

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+
}
3746

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);
3953
PlayerPosIPC.getInstance().readData(b -> {
54+
// if(client.getNetworkHandler() == null) return;
4055
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();
4357
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+
}
4562
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+
}*/
4777
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+
}
5383
}
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();
5686
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
59101
return d;
60102
});
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();
70122
});
71123
});
72124
}

src/main/resources/assets/evmod/settings.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ database: true
3434
#
3535
listener.game_message.read: true # registers: listener, allows: share_ignores, whisper_sound, whisper_pearl_pull
3636
listener.game_message.filter: true # registers: listener, allows: borrow_ignores
37-
listener.player_move: true # registers: onTick(), listener.worldRender, allows: player_pos_sync
37+
listener.player_move: true # registers: onTick(), listener.worldTick, listener.disconnect, allows: player_pos_sync
3838
map_bot.loader: true # registers: onTick()
3939
broadcaster: false # registers: onTimer()
4040
epearl_owners: true # registers: onTick(), listener.chunkLoad, listener.chunkUnload, allows: uuid/xz

0 commit comments

Comments
 (0)