Skip to content

Commit

Permalink
Added entities tracker (#994)
Browse files Browse the repository at this point in the history
* Changed entity limits to be based on integers instead of bigintegers

* Added implementation to the entities tracker

* Changed check for reaching of entity limits to work with the new entities tracker

* Fixed incorrect naming of the entity limits listener

* Added an option to recalculate the entity counts

* Added getter for entities tracker

* Fixed usage of Integer instead of primitive type

* Added support for tracking of spawned entities

* Moved tracking logic to another listener & separate class, alongside of support for untracking entities

* Added missing debug message for untracking entities

* Fixed entities listener not being registered

* Fixed issues with detection of reaching limits

* Added recalculation for entities when island chunks are loaded

* Added support for stacking plugins with the entity counts

* Fixed detection of reaching entity limits

* Added support for stacking of entities with WildStacker and RoseStacker

* Fixed a null issue with UltimateStacker when trying to get entity amounts

* Fixed errors when trying to get stack sizes of entities that are not stackable

* Added entity count placeholder

* Removed support for stacked entities

* Fixed an issue with hangings getting duplicated when their limit is reached

* Fixed amount of entities cannot be the same as the limit

* Merged dev branch
  • Loading branch information
OmerBenGera committed Mar 11, 2022
1 parent 38195fe commit 94befd4
Show file tree
Hide file tree
Showing 12 changed files with 335 additions and 56 deletions.
Expand Up @@ -5,6 +5,7 @@
import com.bgsoftware.superiorskyblock.api.enums.Rating;
import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm;
import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm;
import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm;
import com.bgsoftware.superiorskyblock.api.island.bank.IslandBank;
import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;
import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;
Expand Down Expand Up @@ -1322,6 +1323,11 @@ public interface Island extends Comparable<Island>, IMissionsHolder {
*/
CompletableFuture<Boolean> hasReachedEntityLimit(Key key, int amount);

/**
* Get the entities tracker used by the island.
*/
IslandEntitiesTrackerAlgorithm getEntitiesTracker();

/**
* Get the team limit of the island.
*/
Expand Down
Expand Up @@ -2,7 +2,6 @@

import com.bgsoftware.superiorskyblock.api.key.Key;

import java.math.BigInteger;
import java.util.Map;

public interface IslandEntitiesTrackerAlgorithm {
Expand All @@ -14,7 +13,7 @@ public interface IslandEntitiesTrackerAlgorithm {
* @param amount The amount of the entity.
* @return Whether the entity was successfully tracked.
*/
boolean trackEntity(Key key, BigInteger amount);
boolean trackEntity(Key key, int amount);

/**
* Untrack a entity with a specific amount.
Expand All @@ -23,23 +22,28 @@ public interface IslandEntitiesTrackerAlgorithm {
* @param amount The amount of the entity.
* @return Whether the entity was successfully untracked.
*/
boolean untrackEntity(Key key, BigInteger amount);
boolean untrackEntity(Key key, int amount);

/**
* Get the amount of entities that are on the island.
*
* @param key The entity's key to check.
*/
BigInteger getEntityCount(Key key);
int getEntityCount(Key key);

/**
* Get all the entities that are on the island.
*/
Map<Key, BigInteger> getEntitiesCounts();
Map<Key, Integer> getEntitiesCounts();

/**
* Clear all the entity counts of the island.
*/
void clearEntityCounts();

/**
* Recalculate entity counts on the island.
*/
void recalculateEntityCounts();

}
Expand Up @@ -29,6 +29,7 @@
import com.bgsoftware.superiorskyblock.listeners.ChunksListener;
import com.bgsoftware.superiorskyblock.listeners.CustomEventsListener;
import com.bgsoftware.superiorskyblock.listeners.DragonListener;
import com.bgsoftware.superiorskyblock.listeners.EntitiesListener;
import com.bgsoftware.superiorskyblock.listeners.MenusListener;
import com.bgsoftware.superiorskyblock.listeners.PlayersListener;
import com.bgsoftware.superiorskyblock.listeners.ProtectionListener;
Expand Down Expand Up @@ -247,6 +248,7 @@ public void onEnable() {
safeEventsRegister(new CustomEventsListener(this));
if (settingsHandler.getWorlds().getEnd().isDragonFight())
safeEventsRegister(new DragonListener(this));
safeEventsRegister(new EntitiesListener(this));
safeEventsRegister(new MenusListener(this));
safeEventsRegister(new PlayersListener(this));
safeEventsRegister(new ProtectionListener(this));
Expand Down
Expand Up @@ -40,6 +40,7 @@ public abstract class PlaceholderHook {
private static final Pattern COUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_count_(.+)");
private static final Pattern BLOCK_LIMIT_PLACEHOLDER_PATTERN = Pattern.compile("island_block_limit_(.+)");
private static final Pattern ENTITY_LIMIT_PLACEHOLDER_PATTERN = Pattern.compile("island_entity_limit_(.+)");
private static final Pattern ENTITY_COUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_entity_count_(.+)");
private static final Pattern TOP_PLACEHOLDER_PATTERN = Pattern.compile("island_top_(.+)");
private static final Pattern TOP_WORTH_PLACEHOLDER_PATTERN = Pattern.compile("worth_(.+)");
private static final Pattern TOP_LEVEL_PLACEHOLDER_PATTERN = Pattern.compile("level_(.+)");
Expand Down Expand Up @@ -268,6 +269,9 @@ private static Optional<String> parsePlaceholdersForIsland(Island island, Superi
} else if ((matcher = ENTITY_LIMIT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {
String keyName = matcher.group(1).toUpperCase();
return Optional.of(island.getEntityLimit(EntityType.valueOf(keyName)) + "");
} else if ((matcher = ENTITY_COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {
String keyName = matcher.group(1).toUpperCase();
return Optional.of(StringUtils.format(island.getEntitiesTracker().getEntityCount(Key.of(keyName))));
} else if ((matcher = TOP_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) {
return handleTopIslandsPlaceholder(island, superiorPlayer, matcher.group(1));
} else if ((matcher = MEMBER_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) {
Expand Down
29 changes: 6 additions & 23 deletions src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java
Expand Up @@ -54,7 +54,6 @@
import com.bgsoftware.superiorskyblock.utils.ServerVersion;
import com.bgsoftware.superiorskyblock.utils.StringUtils;
import com.bgsoftware.superiorskyblock.utils.debug.PluginDebugger;
import com.bgsoftware.superiorskyblock.utils.entities.EntityUtils;
import com.bgsoftware.superiorskyblock.utils.events.EventsCaller;
import com.bgsoftware.superiorskyblock.utils.islands.IslandUtils;
import com.bgsoftware.superiorskyblock.utils.islands.SortingComparators;
Expand Down Expand Up @@ -218,6 +217,7 @@ public SIsland(@Nullable SuperiorPlayer owner, UUID uuid, Location location, Str
updateDatesFormatter();
assignIslandChest();
updateUpgrades();
this.entitiesTracker.recalculateEntityCounts();

databaseBridge.setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA);
}
Expand Down Expand Up @@ -2275,29 +2275,12 @@ public CompletableFuture<Boolean> hasReachedEntityLimit(com.bgsoftware.superiors
if (entityLimit <= IslandUtils.NO_LIMIT.get())
return CompletableFuture.completedFuture(false);

AtomicInteger amountOfEntities = new AtomicInteger(0);

for (World.Environment environment : World.Environment.values()) {
try {
chunks.addAll(getAllChunksAsync(environment, true, true, chunk ->
amountOfEntities.set(amountOfEntities.get() + (int) Arrays.stream(chunk.getEntities())
.filter(entity -> key.equals(EntityUtils.getLimitEntityType(entity)) &&
!EntityUtils.canBypassEntityLimit(entity)).count())));
} catch (Exception ignored) {
}
}

CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();

Executor.async(() -> {
//Waiting for all the chunks to load
chunks.forEachCompleted(chunk -> {
}, error -> {
});
completableFuture.complete(amountOfEntities.get() + amount - 1 > entityLimit);
});
return CompletableFuture.completedFuture(this.entitiesTracker.getEntityCount(key) + amount > entityLimit);
}

return completableFuture;
@Override
public IslandEntitiesTrackerAlgorithm getEntitiesTracker() {
return this.entitiesTracker;
}

@Override
Expand Down
@@ -1,49 +1,152 @@
package com.bgsoftware.superiorskyblock.island.algorithms;

import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin;
import com.bgsoftware.superiorskyblock.api.island.Island;
import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm;
import com.bgsoftware.superiorskyblock.api.key.Key;
import com.bgsoftware.superiorskyblock.key.dataset.KeyMap;
import com.bgsoftware.superiorskyblock.structure.CompletableFutureList;
import com.bgsoftware.superiorskyblock.threads.Executor;
import com.bgsoftware.superiorskyblock.utils.debug.PluginDebugger;
import com.bgsoftware.superiorskyblock.utils.entities.EntityUtils;
import com.bgsoftware.superiorskyblock.utils.islands.IslandUtils;
import com.google.common.base.Preconditions;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.entity.Entity;

import java.math.BigInteger;
import java.util.Collections;
import java.util.Map;

public final class DefaultIslandEntitiesTrackerAlgorithm implements IslandEntitiesTrackerAlgorithm {

private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin();

private final KeyMap<BigInteger> entityCounts = new KeyMap<>();
private final KeyMap<Integer> entityCounts = new KeyMap<>();

private final Island island;

private volatile boolean beingRecalculated = false;

public DefaultIslandEntitiesTrackerAlgorithm(Island island) {
this.island = island;
}

@Override
public boolean trackEntity(Key key, BigInteger amount) {
return false;
public boolean trackEntity(Key key, int amount) {
Preconditions.checkNotNull(key, "key parameter cannot be null.");

if (amount <= 0)
return false;

if (!canTrackEntity(key))
return false;

PluginDebugger.debug("Action: Entity Spawn, Island: " + island.getOwner().getName() +
", Entity: " + key + ", Amount: " + amount);

int currentAmount = entityCounts.getOrDefault(key, 0);
entityCounts.put(key, currentAmount + amount);

return true;
}

@Override
public boolean untrackEntity(Key key, BigInteger amount) {
return false;
public boolean untrackEntity(Key key, int amount) {
Preconditions.checkNotNull(key, "key parameter cannot be null.");

if (amount <= 0)
return false;

if (!canTrackEntity(key))
return false;

PluginDebugger.debug("Action: Entity Despawn, Island: " + island.getOwner().getName() +
", Entity: " + key + ", Amount: " + amount);

int currentAmount = entityCounts.getOrDefault(key, -1);

if (currentAmount != -1) {
if (currentAmount > amount) {
entityCounts.put(key, currentAmount - amount);
} else {
entityCounts.remove(key);
}
}

return true;
}

@Override
public BigInteger getEntityCount(Key key) {
return null;
public int getEntityCount(Key key) {
return entityCounts.getOrDefault(key, 0);
}

@Override
public Map<Key, BigInteger> getEntitiesCounts() {
return null;
public Map<Key, Integer> getEntitiesCounts() {
return Collections.unmodifiableMap(entityCounts);
}

@Override
public void clearEntityCounts() {
this.entityCounts.clear();
}

@Override
public void recalculateEntityCounts() {
if (beingRecalculated)
return;

beingRecalculated = true;

clearEntityCounts();

KeyMap<Integer> recalculatedEntityCounts = new KeyMap<>();
CompletableFutureList<Chunk> chunks = new CompletableFutureList<>();

for (World.Environment environment : World.Environment.values()) {
try {
chunks.addAll(island.getAllChunksAsync(environment, true, true, chunk -> {
for (Entity entity : chunk.getEntities()) {
if (EntityUtils.canBypassEntityLimit(entity))
continue;

Key key = EntityUtils.getLimitEntityType(entity);

if (!canTrackEntity(key))
continue;

int currentEntityAmount = recalculatedEntityCounts.getOrDefault(key, 0);
recalculatedEntityCounts.put(key, currentEntityAmount + 1);
}
}));
} catch (Exception ignored) {
}
}

Executor.async(() -> {
try {
//Waiting for all the chunks to load
chunks.forEachCompleted(chunk -> {
}, error -> {
});

if (!this.entityCounts.isEmpty()) {
for (Map.Entry<Key, Integer> entry : this.entityCounts.entrySet()) {
Integer currentAmount = recalculatedEntityCounts.remove(entry.getKey());
if (currentAmount != null)
entry.setValue(entry.getValue() + currentAmount);
}
}

if (!recalculatedEntityCounts.isEmpty()) {
this.entityCounts.putAll(recalculatedEntityCounts);
}
} finally {
beingRecalculated = false;
}
});
}

private boolean canTrackEntity(Key key) {
return island.getEntityLimit(key) != IslandUtils.NO_LIMIT.get();
}

}
Expand Up @@ -13,6 +13,7 @@
import com.bgsoftware.superiorskyblock.api.island.SortingType;
import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm;
import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm;
import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm;
import com.bgsoftware.superiorskyblock.api.island.bank.IslandBank;
import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp;
import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory;
Expand All @@ -31,6 +32,7 @@
import com.bgsoftware.superiorskyblock.island.permissions.PlayerPermissionNode;
import com.bgsoftware.superiorskyblock.island.spawn.algorithm.SpawnIslandBlocksTrackerAlgorithm;
import com.bgsoftware.superiorskyblock.island.spawn.algorithm.SpawnIslandCalculationAlgorithm;
import com.bgsoftware.superiorskyblock.island.spawn.algorithm.SpawnIslandEntitiesTrackerAlgorithm;
import com.bgsoftware.superiorskyblock.player.SSuperiorPlayer;
import com.bgsoftware.superiorskyblock.threads.Executor;
import com.bgsoftware.superiorskyblock.utils.LocationUtils;
Expand Down Expand Up @@ -1109,6 +1111,11 @@ public CompletableFuture<Boolean> hasReachedEntityLimit(Key key, int amount) {
return CompletableFuture.completedFuture(false);
}

@Override
public IslandEntitiesTrackerAlgorithm getEntitiesTracker() {
return SpawnIslandEntitiesTrackerAlgorithm.getInstance();
}

@Override
public int getTeamLimit() {
return IslandUtils.NO_LIMIT.get();
Expand Down

0 comments on commit 94befd4

Please sign in to comment.