Skip to content

Commit

Permalink
Replicate vanilla iteration order, primarily for performing entity hi…
Browse files Browse the repository at this point in the history
…tbox blocking checks
  • Loading branch information
Axionize committed Dec 17, 2024
1 parent 9b89905 commit c6d1dab
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -441,10 +441,12 @@ private void handleMoveEntity(PacketSendEvent event, int entityId, double deltaX
return;
}

player.compensatedEntities.entityMap.updateEntityPosition(player.compensatedEntities.entityMap.get(entityId), new Vector3d(data.getX() + deltaX, data.getY() + deltaY, data.getZ() + deltaZ));
data.setX(data.getX() + deltaX);
data.setY(data.getY() + deltaY);
data.setZ(data.getZ() + deltaZ);
} else {
player.compensatedEntities.entityMap.updateEntityPosition(player.compensatedEntities.entityMap.get(entityId), new Vector3d(deltaX, deltaY, deltaZ));
data.setX(deltaX);
data.setY(deltaY);
data.setZ(deltaZ);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
import ac.grim.grimac.utils.latency.SectionedEntityMap;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -15,7 +15,7 @@ public final class PacketEntityEnderDragon extends PacketEntity {

public PacketEntityEnderDragon(GrimPlayer player, UUID uuid, int entityID, double x, double y, double z) {
super(player, uuid, EntityTypes.ENDER_DRAGON, x, y, z);
final Int2ObjectOpenHashMap<PacketEntity> entityMap = player.compensatedEntities.entityMap;
final SectionedEntityMap entityMap = player.compensatedEntities.entityMap;
parts.add(new PacketEntityEnderDragonPart(player, DragonPart.HEAD, x, y, z, 1.0F, 1.0F));
parts.add(new PacketEntityEnderDragonPart(player, DragonPart.NECK, x, y, z, 3.0F, 3.0F));
parts.add(new PacketEntityEnderDragonPart(player, DragonPart.BODY, x, y, z, 5.0F, 3.0F));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ public class CompensatedEntities {
public static final UUID SPRINTING_MODIFIER_UUID = UUID.fromString("662A6B8D-DA3E-4C1C-8813-96EA6097278D");
public static final UUID SNOW_MODIFIER_UUID = UUID.fromString("1eaf83ff-7207-4596-b37a-d7a07b3ec4ce");

public final Int2ObjectOpenHashMap<PacketEntity> entityMap = new Int2ObjectOpenHashMap<>(40, 0.7f);
public final Int2ObjectOpenHashMap<TrackerData> serverPositionsMap = new Int2ObjectOpenHashMap<>(40, 0.7f);
public final SectionedEntityMap entityMap = new SectionedEntityMap();
// public final Int2ObjectLinkedOpenHashMap<PacketEntity> entityMap = new Int2ObjectLinkedOpenHashMap<>(40, 0.7f); // needs to be linked to replicate vanilla iteration order!
public final Int2ObjectOpenHashMap<TrackerData> serverPositionsMap = new Int2ObjectOpenHashMap<>(40, 0.7f); // never iterate over, so iteration order does not matter
public final Object2ObjectOpenHashMap<UUID, UserProfile> profiles = new Object2ObjectOpenHashMap<>();
public Integer serverPlayerVehicle = null;
public boolean hasSprintingAttributeEnabled = false;
Expand Down Expand Up @@ -70,13 +71,15 @@ public void tick() {
}

public void removeEntity(int entityID) {
PacketEntity entity = entityMap.remove(entityID);
PacketEntity entity = entityMap.get(entityID);
if (entity == null) return;

entityMap.removeEntity(entityID);

if (entity instanceof PacketEntityEnderDragon) {
PacketEntityEnderDragon dragon = (PacketEntityEnderDragon) entity;
for (int i = 1; i < dragon.getParts().size() + 1; i++) {
entityMap.remove(entityID + i);
entityMap.removeEntity(entityID + i);
}
}

Expand Down
140 changes: 136 additions & 4 deletions src/main/java/ac/grim/grimac/utils/latency/SectionedEntityMap.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
package ac.grim.grimac.utils.latency;

import java.util.ArrayList;
import java.util.List;
import java.util.*;
import java.util.function.Consumer;

import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
import ac.grim.grimac.utils.math.GrimMath;
import com.github.retrooper.packetevents.util.Vector3d;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongAVLTreeSet;
import it.unimi.dsi.fastutil.longs.LongSortedSet;

public class SectionedEntityMap {

// exists to make porting over the legacy entity handling easier, will remove later
private final Int2ObjectOpenHashMap<PacketEntity> idToEntity = new Int2ObjectOpenHashMap<>();

private final Long2ObjectOpenHashMap<EntitySection> sections = new Long2ObjectOpenHashMap<>();
private final LongSortedSet trackedSections = new LongAVLTreeSet();

public void addEntity(PacketEntity entity) {
private final EntityCollection entityCollection = new EntityCollection();

public PacketEntity get(int entityId) {
return idToEntity.get(entityId);
}

public void addEntity(int entityID, PacketEntity entity) {
idToEntity.put(entityID, entity);
Vector3d entityLocation = entity.trackedServerPosition.getPos();
long sectionPos = GrimMath.asLong(
GrimMath.getSectionCoord(entityLocation.getX()),
Expand All @@ -30,6 +40,13 @@ public void addEntity(PacketEntity entity) {
trackedSections.add(sectionPos);
}

public void removeEntity(int entityId) {
PacketEntity entity = idToEntity.remove(entityId);
if (entity != null) {
removeEntity(entity);
}
}

public void removeEntity(PacketEntity entity) {
Vector3d entityLocation = entity.trackedServerPosition.getPos();
long sectionPos = GrimMath.asLong(
Expand All @@ -48,6 +65,26 @@ public void removeEntity(PacketEntity entity) {
}
}

public Collection<PacketEntity> values() {
return entityCollection;
}

public boolean containsKey(int entityId) {
return idToEntity.containsKey(entityId);
}

public void forEachEntity(Consumer<PacketEntity> action) {
long minPacked = Long.MIN_VALUE;
long maxPacked = Long.MAX_VALUE;

for (long sectionPos : trackedSections.subSet(minPacked, maxPacked)) {
EntitySection section = sections.get(sectionPos);
if (section != null) {
section.forEachEntity(action);
}
}
}

public void forEachInBox(SimpleCollisionBox box, Consumer<PacketEntity> action) {
int minX = GrimMath.getSectionCoord(box.minX - 2.0);
int minY = GrimMath.getSectionCoord(box.minY - 4.0);
Expand Down Expand Up @@ -75,10 +112,63 @@ public void forEachInBox(SimpleCollisionBox box, Consumer<PacketEntity> action)
}
}

public void updateEntityPosition(PacketEntity entity, Vector3d newPosition) {
if (entity == null) return; // is null on startup at first
// Get old and new section positions
Vector3d oldPosition = entity.trackedServerPosition.getPos();
long oldSectionPos = GrimMath.asLong(
GrimMath.getSectionCoord(oldPosition.getX()),
GrimMath.getSectionCoord(oldPosition.getY()),
GrimMath.getSectionCoord(oldPosition.getZ())
);

long newSectionPos = GrimMath.asLong(
GrimMath.getSectionCoord(newPosition.getX()),
GrimMath.getSectionCoord(newPosition.getY()),
GrimMath.getSectionCoord(newPosition.getZ())
);

// If section changed
if (oldSectionPos != newSectionPos) {
// Remove from old section
EntitySection oldSection = sections.get(oldSectionPos);
if (oldSection != null) {
oldSection.removeEntity(entity);
if (oldSection.isEmpty()) {
sections.remove(oldSectionPos);
trackedSections.remove(oldSectionPos);
}
}

// Add to new section
EntitySection newSection = sections.computeIfAbsent(newSectionPos, this::createSection);
newSection.addEntity(entity);
trackedSections.add(newSectionPos);
}
}

private EntitySection createSection(long pos) {
return new EntitySection();
}

public Iterable<? extends Map.Entry<Integer, PacketEntity>> int2ObjectEntrySet() {
return idToEntity.entrySet();
}

public void put(int entityID, PacketEntity packetEntity) {
addEntity(entityID, packetEntity);
}

public boolean containsValue(PacketEntity entity) {
return idToEntity.containsValue(entity);
}

public void clear() {
idToEntity.clear();
sections.clear();
trackedSections.clear();
}

private static class EntitySection {
private final List<PacketEntity> entities = new ArrayList<>();

Expand All @@ -104,4 +194,46 @@ public List<PacketEntity> getEntities() {
return entities;
}
}
}

private class EntityCollection extends AbstractCollection<PacketEntity> {
@Override
public Iterator<PacketEntity> iterator() {
return new EntityIterator();
}

@Override
public int size() {
return idToEntity.size();
}

@Override
public boolean contains(Object o) {
return o instanceof PacketEntity && containsValue((PacketEntity) o);
}
}

private class EntityIterator implements Iterator<PacketEntity> {
private final Iterator<Long> sectionIterator = trackedSections.iterator();
private Iterator<PacketEntity> currentSectionIterator = Collections.emptyIterator();

@Override
public boolean hasNext() {
while (!currentSectionIterator.hasNext() && sectionIterator.hasNext()) {
long sectionPos = sectionIterator.next();
EntitySection section = sections.get(sectionPos);
if (section != null) {
currentSectionIterator = section.getEntities().iterator();
}
}
return currentSectionIterator.hasNext();
}

@Override
public PacketEntity next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return currentSectionIterator.next();
}
}
}

0 comments on commit c6d1dab

Please sign in to comment.