mirror of
https://github.com/mcMMO-Dev/mcMMO.git
synced 2024-11-24 06:06:45 +01:00
Fix infinite recursion caused by inadvertent chunk loading/unloading Fixes #5112
This commit is contained in:
parent
4cb3d3181b
commit
79ad86ff29
@ -1,3 +1,6 @@
|
||||
Version 2.2.028
|
||||
Fix stack overflow during ChunkUnloadEvent
|
||||
|
||||
Version 2.2.027
|
||||
Added Tridents / Crossbows to salvage.vanilla.yml config (see notes)
|
||||
Fixed an issue where Folia could have all of its threads lock up effectively killing the server
|
||||
|
2
pom.xml
2
pom.xml
@ -2,7 +2,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.gmail.nossr50.mcMMO</groupId>
|
||||
<artifactId>mcMMO</artifactId>
|
||||
<version>2.2.027</version>
|
||||
<version>2.2.028-SNAPSHOT</version>
|
||||
<name>mcMMO</name>
|
||||
<url>https://github.com/mcMMO-Dev/mcMMO</url>
|
||||
<scm>
|
||||
|
@ -1,21 +1,23 @@
|
||||
package com.gmail.nossr50.listeners;
|
||||
|
||||
import com.gmail.nossr50.mcMMO;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class ChunkListener implements Listener {
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onChunkUnload(ChunkUnloadEvent event) {
|
||||
List<LivingEntity> matchingEntities
|
||||
= mcMMO.getTransientEntityTracker().getAllTransientEntitiesInChunk(event.getChunk());
|
||||
for(LivingEntity livingEntity : matchingEntities) {
|
||||
mcMMO.getTransientEntityTracker().killSummonAndCleanMobFlags(livingEntity, null, false);
|
||||
}
|
||||
final Chunk unloadingChunk = event.getChunk();
|
||||
Arrays.stream(unloadingChunk.getEntities())
|
||||
.filter(entity -> entity instanceof LivingEntity)
|
||||
.map(entity -> (LivingEntity) entity)
|
||||
.forEach(livingEntity -> mcMMO.getTransientEntityTracker().removeTrackedEntity(livingEntity));
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import com.gmail.nossr50.skills.taming.TrackedTamingEntity;
|
||||
import com.gmail.nossr50.util.player.NotificationManager;
|
||||
import com.gmail.nossr50.util.skills.ParticleEffectUtils;
|
||||
import com.gmail.nossr50.util.text.StringUtils;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
@ -19,10 +18,13 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
public class TransientEntityTracker {
|
||||
private final @NotNull Map<UUID, Set<TrackedTamingEntity>> playerSummonedEntityTracker;
|
||||
final @NotNull Map<UUID, Set<TrackedTamingEntity>> playerSummonedEntityTracker;
|
||||
// used for fast lookups during chunk unload events
|
||||
final @NotNull Set<LivingEntity> entityLookupCache;
|
||||
|
||||
public TransientEntityTracker() {
|
||||
playerSummonedEntityTracker = new ConcurrentHashMap<>();
|
||||
this.playerSummonedEntityTracker = new ConcurrentHashMap<>();
|
||||
this.entityLookupCache = ConcurrentHashMap.newKeySet();
|
||||
}
|
||||
|
||||
public void initPlayer(@NotNull Player player) {
|
||||
@ -33,14 +35,6 @@ public class TransientEntityTracker {
|
||||
cleanPlayer(player, player.getUniqueId());
|
||||
}
|
||||
|
||||
public @NotNull List<LivingEntity> getAllTransientEntitiesInChunk(@NotNull Chunk chunk) {
|
||||
return playerSummonedEntityTracker.values().stream()
|
||||
.flatMap(Collection::stream)
|
||||
.map(TrackedTamingEntity::getLivingEntity)
|
||||
.filter(livingEntity -> livingEntity.getLocation().getChunk() == chunk)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public int summonCountForPlayerOfType(@NotNull UUID playerUUID, @NotNull CallOfTheWildType callOfTheWildType) {
|
||||
return getTrackedEntities(playerUUID, callOfTheWildType).size();
|
||||
}
|
||||
@ -48,6 +42,7 @@ public class TransientEntityTracker {
|
||||
public void addSummon(@NotNull UUID playerUUID, @NotNull TrackedTamingEntity trackedTamingEntity) {
|
||||
playerSummonedEntityTracker.computeIfAbsent(playerUUID, __ -> ConcurrentHashMap.newKeySet())
|
||||
.add(trackedTamingEntity);
|
||||
entityLookupCache.add(trackedTamingEntity.getLivingEntity());
|
||||
}
|
||||
|
||||
public void killSummonAndCleanMobFlags(@NotNull LivingEntity livingEntity, @Nullable Player player,
|
||||
@ -77,9 +72,7 @@ public class TransientEntityTracker {
|
||||
}
|
||||
|
||||
public boolean isTransient(@NotNull LivingEntity livingEntity) {
|
||||
return playerSummonedEntityTracker.values().stream().anyMatch(
|
||||
trackedEntities -> trackedEntities.stream()
|
||||
.anyMatch(trackedTamingEntity -> trackedTamingEntity.getLivingEntity().equals(livingEntity)));
|
||||
return entityLookupCache.contains(livingEntity);
|
||||
}
|
||||
|
||||
private @NotNull Set<TrackedTamingEntity> getTrackedEntities(@NotNull UUID playerUUID,
|
||||
@ -117,7 +110,29 @@ public class TransientEntityTracker {
|
||||
}
|
||||
|
||||
public void removeSummonFromTracker(@NotNull UUID playerUUID, @NotNull TrackedTamingEntity trackedTamingEntity) {
|
||||
playerSummonedEntityTracker.computeIfAbsent(playerUUID, __ -> ConcurrentHashMap.newKeySet())
|
||||
.remove(trackedTamingEntity);
|
||||
if (playerSummonedEntityTracker.containsKey(playerUUID)) {
|
||||
playerSummonedEntityTracker.get(playerUUID).remove(trackedTamingEntity);
|
||||
entityLookupCache.remove(trackedTamingEntity.getLivingEntity());
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTrackedEntity(@NotNull LivingEntity livingEntity) {
|
||||
// Fail fast if the entity isn't being tracked
|
||||
if (!entityLookupCache.contains(livingEntity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<TrackedTamingEntity> matchingEntities = new ArrayList<>();
|
||||
|
||||
// Collect matching entities without copying each set
|
||||
playerSummonedEntityTracker.values().forEach(trackedEntitiesPerPlayer ->
|
||||
trackedEntitiesPerPlayer.stream()
|
||||
.filter(trackedTamingEntity -> trackedTamingEntity.getLivingEntity() == livingEntity)
|
||||
.forEach(matchingEntities::add)
|
||||
);
|
||||
|
||||
// Iterate over the collected list to handle removal and cleanup
|
||||
matchingEntities.forEach(TrackedTamingEntity::run);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user