Skip to content

Commit

Permalink
Fixes Valkyrien Skies 2 incompatibility with `use_optimized_entity_tr…
Browse files Browse the repository at this point in the history
…acking`
  • Loading branch information
ishland committed Feb 4, 2023
1 parent a14f208 commit cc4901f
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 6 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Expand Up @@ -55,6 +55,9 @@ dependencies {

shadowInclude implementation("com.ibm.async:asyncutil:${async_util_version}")

// https://mvnrepository.com/artifact/org.joml/joml-primitives
compileOnly 'org.joml:joml-primitives:1.10.0'


// Fabric API. This is technically optional, but you probably want it anyway.
// modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/ishland/vmp/VMPMod.java
@@ -1,6 +1,8 @@
package com.ishland.vmp;

import com.ishland.raknetify.fabric.common.connection.RakNetMultiChannel;
import com.ishland.vmp.common.config.Config;
import com.ishland.vmp.common.playerwatching.NearbyEntityTracking;
import com.ishland.vmp.mixins.access.INetworkState;
import com.ishland.vmp.mixins.access.INetworkStatePacketHandler;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
Expand All @@ -21,5 +23,9 @@ public void onInitialize() {
RakNetMultiChannel.getPacketChannelOverride(type.getKey());
}
}

if (Config.USE_OPTIMIZED_ENTITY_TRACKING) {
NearbyEntityTracking.init();
}
}
}
@@ -1,6 +1,7 @@
package com.ishland.vmp.common.playerwatching;

import com.ishland.vmp.common.maps.AreaMap;
import com.ishland.vmp.common.playerwatching.compat.EntityPositionTransformer;
import com.ishland.vmp.common.util.SimpleObjectPool;
import com.ishland.vmp.mixins.access.IThreadedAnvilChunkStorageEntityTracker;
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction;
Expand All @@ -13,15 +14,42 @@
import it.unimi.dsi.fastutil.objects.ReferenceArrayList;
import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet;
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.entity.Entity;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ThreadedAnvilChunkStorage;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.ChunkSectionPos;
import net.minecraft.util.math.Vec3d;

import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;

public class NearbyEntityTracking {

private static final EntityPositionTransformer[] transformers;

static {
List<EntityPositionTransformer> list = new ArrayList<>();
if (FabricLoader.getInstance().isModLoaded("valkyrienskies")) {
System.out.println("ValkyrienSkies detected, applying compatibility patch");
try {
list.add((EntityPositionTransformer)
Class.forName("com.ishland.vmp.common.playerwatching.compat.ValkyrienSkies2ShipPositionTransformer")
.getDeclaredConstructor().newInstance());
} catch (Throwable t) {
t.printStackTrace();
}
}
transformers = list.toArray(EntityPositionTransformer[]::new);
}

public static void init() {
// intentionally empty
}

private final SimpleObjectPool<ReferenceLinkedOpenHashSet<?>> pooledHashSets =
new SimpleObjectPool<>(unused -> new ReferenceLinkedOpenHashSet<>(),
ReferenceLinkedOpenHashSet::clear,
Expand All @@ -44,14 +72,14 @@ public class NearbyEntityTracking {
private final Reference2LongOpenHashMap<ThreadedAnvilChunkStorage.EntityTracker> tracker2ChunkPos = new Reference2LongOpenHashMap<>();

public void addEntityTracker(ThreadedAnvilChunkStorage.EntityTracker tracker) {
final ChunkSectionPos trackedSection = ((IThreadedAnvilChunkStorageEntityTracker) tracker).getTrackedSection();
final ChunkPos pos = getEntityChunkPos(((IThreadedAnvilChunkStorageEntityTracker) tracker).getEntity());
this.areaMap.add(
tracker,
trackedSection.getX(),
trackedSection.getZ(),
pos.x,
pos.z,
getChunkViewDistance(tracker)
);
this.tracker2ChunkPos.put(tracker, ((IThreadedAnvilChunkStorageEntityTracker) tracker).getEntity().getChunkPos().toLong());
this.tracker2ChunkPos.put(tracker, pos.toLong());
}

public void removeEntityTracker(ThreadedAnvilChunkStorage.EntityTracker tracker) {
Expand Down Expand Up @@ -82,9 +110,17 @@ protected void rehash(int newN) {
}
};

private static ChunkPos getEntityChunkPos(Entity entity) {
Vec3d pos = entity.getPos();
for (EntityPositionTransformer transformer : transformers) {
pos = transformer.transform(entity, pos);
}
return new ChunkPos(ChunkSectionPos.getSectionCoord(pos.x), ChunkSectionPos.getSectionCoord(pos.z));
}

public void tick() {
for (Reference2LongMap.Entry<ThreadedAnvilChunkStorage.EntityTracker> entry : this.tracker2ChunkPos.reference2LongEntrySet()) {
final ChunkPos pos = ((IThreadedAnvilChunkStorageEntityTracker) entry.getKey()).getEntity().getChunkPos();
final ChunkPos pos = getEntityChunkPos(((IThreadedAnvilChunkStorageEntityTracker) entry.getKey()).getEntity());
if (pos.toLong() != entry.getLongValue()) {
this.areaMap.update(entry.getKey(), pos.x, pos.z, getChunkViewDistance(entry.getKey()));
entry.setValue(pos.toLong());
Expand All @@ -94,7 +130,7 @@ public void tick() {
trackerTickList.clear();

for (var entry : this.playerTrackers.entrySet()) {
final Set<ThreadedAnvilChunkStorage.EntityTracker> currentTrackers = this.areaMap.getObjectsInRange(entry.getKey().getChunkPos().toLong());
final Set<ThreadedAnvilChunkStorage.EntityTracker> currentTrackers = this.areaMap.getObjectsInRange(getEntityChunkPos(entry.getKey()).toLong());

boolean isPlayerPositionUpdated = ((ServerPlayerEntityExtension) entry.getKey()).vmpTracking$isPositionUpdated();
((ServerPlayerEntityExtension) entry.getKey()).vmpTracking$updatePosition();
Expand Down
@@ -0,0 +1,27 @@
package com.ishland.vmp.common.playerwatching.compat;

import net.minecraft.entity.Entity;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.Vec3d;

public abstract class EntityPositionTransformer {

protected abstract Vec3d transform0(Entity entity, Vec3d pos);

public final Vec3d transform(Entity entity, Vec3d pos) {
final Vec3d pos1;
try {
pos1 = transform0(entity, pos);
} catch (Throwable t) {
System.err.println("EntityPositionTransformer %s threw an exception for %s at %s".formatted(getClass().getName(), entity, pos));
t.printStackTrace();
return pos;
}
if (pos1 == null) {
System.err.println("EntityPositionTransformer %s returned null for %s at %s".formatted(getClass().getName(), entity, pos));
return pos;
}
return pos1;
}

}
@@ -0,0 +1,47 @@
package com.ishland.vmp.common.playerwatching.compat;

import net.minecraft.entity.Entity;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.ChunkSectionPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import org.joml.Matrix4dc;
import org.joml.Vector3d;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class ValkyrienSkies2ShipPositionTransformer extends EntityPositionTransformer {

private static final MethodHandle methodVSGameUtilsKt$getShipManagingPos;
private static final MethodHandle methodShip$getShipToWorld;

static {
try {
final Class<?> clazzVSGameUtilsKt = Class.forName("org.valkyrienskies.mod.common.VSGameUtilsKt");
final Class<?> clazzShip = Class.forName("org.valkyrienskies.core.api.ships.Ship");
methodVSGameUtilsKt$getShipManagingPos = MethodHandles.lookup().findStatic(clazzVSGameUtilsKt,
"getShipManagingPos", MethodType.methodType(clazzShip, World.class, int.class, int.class));
methodShip$getShipToWorld = MethodHandles.lookup().findVirtual(clazzShip,
"getShipToWorld", MethodType.methodType(Matrix4dc.class));
} catch (Throwable t) {
throw new RuntimeException(t);
}
}

@Override
public Vec3d transform0(Entity entity, Vec3d pos) {
try {
final Object ship = methodVSGameUtilsKt$getShipManagingPos.invoke(entity.world, ChunkSectionPos.getSectionCoord(pos.x), ChunkSectionPos.getSectionCoord(pos.z));
if (ship != null) {
final Matrix4dc shipToWorld = (Matrix4dc) methodShip$getShipToWorld.invoke(ship);
final Vector3d transformedPosition = shipToWorld.transformPosition(new Vector3d(pos.x, pos.y, pos.z));
return new Vec3d(transformedPosition.x, transformedPosition.y, transformedPosition.z);
}
} catch (Throwable t) {
throw new RuntimeException(t);
}
return pos;
}
}

0 comments on commit cc4901f

Please sign in to comment.