Skip to content

Commit

Permalink
fix: prevent entity from moving into unloaded chunk
Browse files Browse the repository at this point in the history
  • Loading branch information
smartcmd committed Oct 15, 2024
1 parent 0381d42 commit 7e623a0
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -321,18 +321,28 @@ public boolean willBeSpawnedNextTick() {
return willBeSpawnedNextTick;
}

public void setLocationAndCheckChunk(Location3fc newLoc) {
checkChunk(this.location, newLoc);
setLocation(newLoc, true);
public boolean setLocationAndCheckChunk(Location3fc newLoc) {
if (checkChunk(this.location, newLoc)) {
setLocation(newLoc, true);
return true;
}
return false;
}

protected void checkChunk(Location3fc oldLoc, Location3fc newLoc) {
protected boolean checkChunk(Location3fc oldLoc, Location3fc newLoc) {
var oldChunkX = (int) oldLoc.x() >> 4;
var oldChunkZ = (int) oldLoc.z() >> 4;
var newChunkX = (int) newLoc.x() >> 4;
var newChunkZ = (int) newLoc.z() >> 4;
if (oldChunkX != newChunkX || oldChunkZ != newChunkZ) {
// Current chunk changed
var newChunk = newLoc.dimension().getChunkService().getChunk(newChunkX, newChunkZ);
if (newChunk == null) {
// Moving into an unloaded chunk is not allowed. Because the chunk holds the entity,
// moving to an unloaded chunk will result in the loss of the entity
log.warn("New chunk {} {} is null while moving entity!", newChunkX, newChunkZ);
return false;
}

Chunk oldChunk = null;
if (this.location.dimension != null) {
oldChunk = this.location.dimension().getChunkService().getChunk(oldChunkX, oldChunkZ);
Expand All @@ -343,28 +353,22 @@ protected void checkChunk(Location3fc oldLoc, Location3fc newLoc) {
}
}

var newChunk = newLoc.dimension().getChunkService().getChunk(newChunkX, newChunkZ);
if (newChunk != null) {
((AllayChunk) newChunk).addEntity(thisEntity);
Set<EntityPlayer> oldChunkPlayers = oldChunk != null ? oldChunk.getPlayerChunkLoaders() : Collections.emptySet();
Set<EntityPlayer> samePlayers = new HashSet<>(newChunk.getPlayerChunkLoaders());
samePlayers.retainAll(oldChunkPlayers);
for (var player : oldChunkPlayers) {
if (!samePlayers.contains(player) && player != thisEntity) {
despawnFrom(player);
}
((AllayChunk) newChunk).addEntity(thisEntity);
Set<EntityPlayer> oldChunkPlayers = oldChunk != null ? oldChunk.getPlayerChunkLoaders() : Collections.emptySet();
Set<EntityPlayer> samePlayers = new HashSet<>(newChunk.getPlayerChunkLoaders());
samePlayers.retainAll(oldChunkPlayers);
for (var player : oldChunkPlayers) {
if (!samePlayers.contains(player) && player != thisEntity) {
despawnFrom(player);
}
for (var player : newChunk.getPlayerChunkLoaders()) {
if (!samePlayers.contains(player) && player != thisEntity) {
spawnTo(player);
}
}
for (var player : newChunk.getPlayerChunkLoaders()) {
if (!samePlayers.contains(player) && player != thisEntity) {
spawnTo(player);
}
} else {
// Moving into an unloaded chunk is not allowed. Because the chunk holds the entity,
// moving to an unloaded chunk will result in the loss of the entity
log.warn("New chunk {} {} is null while moving entity!", newChunkX, newChunkZ);
}
}
return true;
}


Expand Down Expand Up @@ -398,6 +402,7 @@ public void teleport(Location3fc target) {
protected void teleportInDimension(Location3fc target) {
// Ensure that the new chunk is loaded
target.dimension().getChunkService().getOrLoadChunkSync((int) target.x() >> 4, (int) target.z() >> 4);
// This method should always return true because we have loaded the chunk
setLocationAndCheckChunk(target);
broadcastMoveToViewers(target, true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -496,9 +496,13 @@ protected boolean updateEntityLocation(Entity entity, Location3fc newLoc) {
}
newLoc = event.getTo();

entity.getManager().<EntityBaseComponentImpl>getComponent(EntityBaseComponentImpl.IDENTIFIER).broadcastMoveToViewers(newLoc, false);
entity.getManager().<EntityBaseComponentImpl>getComponent(EntityBaseComponentImpl.IDENTIFIER).setLocationAndCheckChunk(newLoc);
return true;
var baseComponent = entity.getManager().<EntityBaseComponentImpl>getComponent(EntityBaseComponentImpl.IDENTIFIER);
if (baseComponent.setLocationAndCheckChunk(newLoc)) {
baseComponent.broadcastMoveToViewers(newLoc, false);
return true;
} else {
return false;
}
}

/**
Expand Down

0 comments on commit 7e623a0

Please sign in to comment.