mirror of
				https://github.com/mcMMO-Dev/mcMMO.git
				synced 2025-11-04 11:03:43 +01:00 
			
		
		
		
	Fix infinite recursion caused by inadvertent chunk loading/unloading Fixes #5112
This commit is contained in:
		@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user