Skip to content

Commit

Permalink
Optimized sortings of top islands to only be done when necessary
Browse files Browse the repository at this point in the history
  • Loading branch information
OmerBenGera committed Jun 24, 2022
1 parent fb5b0fd commit 144a215
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 26 deletions.
@@ -1,16 +1,18 @@
package com.bgsoftware.superiorskyblock.api.island;

import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI;
import com.bgsoftware.superiorskyblock.api.objects.Enumerable;
import com.google.common.base.Preconditions;

import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

public class SortingType implements Comparator<Island> {
public class SortingType implements Comparator<Island>, Enumerable {

private static final Map<String, SortingType> sortingTypes = new HashMap<>();
private static int ordinalCounter = 0;

private static final Comparator<Island> ISLAND_NAMES_COMPARATOR = (o1, o2) -> {
String firstName = o1.getName().isEmpty() ? o1.getOwner() == null ? "null" : o1.getOwner().getName() : o1.getName();
Expand All @@ -20,13 +22,20 @@ public class SortingType implements Comparator<Island> {

private final String name;
private final Comparator<Island> comparator;
private final int ordinal;

private SortingType(String name, Comparator<Island> comparator, boolean handleEqualsIslands) {
this.name = name;
this.comparator = !handleEqualsIslands ? comparator : (o1, o2) -> {
int compare = comparator.compare(o1, o2);
return compare == 0 ? ISLAND_NAMES_COMPARATOR.compare(o1, o2) : compare;
};
this.ordinal = ordinalCounter++;
}

@Override
public int ordinal() {
return this.ordinal;
}

/**
Expand Down
Expand Up @@ -92,7 +92,8 @@ default void transferIsland(UUID oldLeader, UUID newLeader) {

/**
* Sort islands for the top-islands.
* The islands will not get sorted if only one island exists.
* The islands will not get sorted if only one island exists, or no changes
* were tracked by {@link #notifyChange(SortingType, Island)}
*
* @param sortingType The type of sorting to use.
* @param onFinish Callback method
Expand All @@ -109,6 +110,14 @@ default void transferIsland(UUID oldLeader, UUID newLeader) {
*/
void sortIslands(SortingType sortingType, boolean forceSort, @Nullable Runnable onFinish);

/**
* Notify about a change of a value for a specific sorting type for an island.
*
* @param sortingType The sorting-type.
* @param island The island that had its value changed.
*/
void notifyChange(SortingType sortingType, Island island);

/**
* Get all islands sorted by a specific sorting-type.
*
Expand Down
@@ -0,0 +1,77 @@
package com.bgsoftware.superiorskyblock.core.collections;

import com.bgsoftware.superiorskyblock.api.objects.Enumerable;

import java.util.Arrays;
import java.util.Collection;

public class EnumerateSet<K extends Enumerable> {

private boolean[] values;
private int size = 0;

public EnumerateSet(Collection<K> enumerables) {
this.values = new boolean[enumerables.size()];
}

public EnumerateSet(EnumerateSet<K> other) {
this.values = other.values.clone();
this.size = other.size;
}

public int size() {
return this.size;
}

public boolean isEmpty() {
return size() <= 0;
}

public boolean contains(K key) {
return isValidKey(key) && this.values[key.ordinal()];
}

public boolean add(K key) {
this.ensureCapacity(key.ordinal() + 1);

boolean containedBefore = this.values[key.ordinal()];
this.values[key.ordinal()] = true;

if (!containedBefore)
++this.size;

return !containedBefore;
}

public boolean remove(K key) {
if (!isValidKey(key))
return false;

boolean containedBefore = this.values[key.ordinal()];
this.values[key.ordinal()] = false;

--this.size;

return containedBefore;
}

public void clear() {
this.values = new boolean[this.values.length];
this.size = 0;
}

@Override
public String toString() {
return "EnumerateSet{" + Arrays.toString(values) + '}';
}

private boolean isValidKey(K key) {
return key.ordinal() >= 0 && key.ordinal() < this.values.length;
}

private void ensureCapacity(int capacity) {
if (capacity > this.values.length)
this.values = Arrays.copyOf(this.values, capacity);
}

}
18 changes: 18 additions & 0 deletions src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java
Expand Up @@ -670,6 +670,8 @@ public void setPlayerInside(SuperiorPlayer superiorPlayer, boolean inside) {
if (!changePlayers)
return;

plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_PLAYERS, this);

if (!isMember(superiorPlayer) && superiorPlayer.isShownAsOnline()) {
Optional<UniqueVisitor> uniqueVisitorOptional = uniqueVisitors.readAndGet(uniqueVisitors ->
uniqueVisitors.stream().filter(pair -> pair.getSuperiorPlayer().equals(superiorPlayer)).findFirst());
Expand Down Expand Up @@ -1840,10 +1842,14 @@ public void handleBlockPlace(Key key, BigInteger amount, boolean save, boolean u

if (blockValue.compareTo(BigDecimal.ZERO) != 0) {
islandWorth.updateAndGet(islandWorth -> islandWorth.add(blockValue.multiply(new BigDecimal(amount))));
if (save)
plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_WORTH, this);
}

if (blockLevel.compareTo(BigDecimal.ZERO) != 0) {
islandLevel.updateAndGet(islandLevel -> islandLevel.add(blockLevel.multiply(new BigDecimal(amount))));
if (save)
plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_LEVEL, this);
}

if (updateLastTimeStatus)
Expand Down Expand Up @@ -1910,10 +1916,14 @@ public void handleBlockBreak(Key key, BigInteger amount, boolean save) {

if (blockValue.compareTo(BigDecimal.ZERO) != 0) {
this.islandWorth.updateAndGet(islandWorth -> islandWorth.subtract(blockValue.multiply(new BigDecimal(amount))));
if (save)
plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_WORTH, this);
}

if (blockLevel.compareTo(BigDecimal.ZERO) != 0) {
this.islandLevel.updateAndGet(islandLevel -> islandLevel.subtract(blockLevel.multiply(new BigDecimal(amount))));
if (save)
plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_LEVEL, this);
}

boolean hasBlockLimit = blockLimits.containsKey(key),
Expand Down Expand Up @@ -1945,6 +1955,8 @@ public void clearBlockCounts() {
blocksTracker.clearBlockCounts();
islandWorth.set(BigDecimal.ZERO);
islandLevel.set(BigDecimal.ZERO);
plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_WORTH, this);
plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_LEVEL, this);
}

@Override
Expand Down Expand Up @@ -2738,6 +2750,8 @@ public void setRating(SuperiorPlayer superiorPlayer, Rating rating) {

ratings.put(superiorPlayer.getUniqueId(), rating);

plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_RATING, this);

IslandsDatabaseBridge.saveRating(this, superiorPlayer, rating, System.currentTimeMillis());

plugin.getMenus().refreshIslandRatings(this);
Expand All @@ -2751,6 +2765,8 @@ public void removeRating(SuperiorPlayer superiorPlayer) {

ratings.remove(superiorPlayer.getUniqueId());

plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_RATING, this);

IslandsDatabaseBridge.removeRating(this, superiorPlayer);

plugin.getMenus().refreshIslandRatings(this);
Expand Down Expand Up @@ -2781,6 +2797,8 @@ public void removeRatings() {
PluginDebugger.debug("Action: Remove Ratings, Island: " + owner.getName());
ratings.clear();

plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_RATING, this);

IslandsDatabaseBridge.clearRatings(this);

plugin.getMenus().refreshIslandRatings(this);
Expand Down
Expand Up @@ -6,18 +6,18 @@
import com.bgsoftware.superiorskyblock.api.island.container.IslandsContainer;
import com.bgsoftware.superiorskyblock.core.IslandPosition;
import com.bgsoftware.superiorskyblock.core.SequentialListBuilder;
import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet;
import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor;
import com.bgsoftware.superiorskyblock.core.threads.Synchronized;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
Expand All @@ -27,12 +27,15 @@ public class DefaultIslandsContainer implements IslandsContainer {
private final Map<IslandPosition, Island> islandsByPositions = new ConcurrentHashMap<>();
private final Map<UUID, Island> islandsByUUID = new ConcurrentHashMap<>();

private final Map<SortingType, Set<Island>> sortedIslands = new ConcurrentHashMap<>();
private final Map<SortingType, Synchronized<List<Island>>> sortedIslands = new ConcurrentHashMap<>();

private final EnumerateSet<SortingType> notifiedValues = new EnumerateSet<>(SortingType.values());

private final SuperiorSkyblockPlugin plugin;

public DefaultIslandsContainer(SuperiorSkyblockPlugin plugin) {
this.plugin = plugin;

}

@Override
Expand All @@ -51,7 +54,9 @@ public void addIsland(Island island) {

this.islandsByUUID.put(island.getUniqueId(), island);

sortedIslands.values().forEach(sortedIslands -> sortedIslands.add(island));
sortedIslands.values().forEach(sortedIslands -> {
sortedIslands.write(_sortedIslands -> _sortedIslands.add(island));
});
}

@Override
Expand All @@ -61,7 +66,9 @@ public void removeIsland(Island island) {
islandsByUUID.remove(island.getUniqueId());
islandsByPositions.remove(IslandPosition.of(islandLocation));

sortedIslands.values().forEach(sortedIslands -> sortedIslands.remove(island));
sortedIslands.values().forEach(sortedIslands -> {
sortedIslands.write(_sortedIslands -> _sortedIslands.remove(island));
});

if (plugin.getProviders().hasCustomWorldsSupport()) {
runWithCustomWorld(islandLocation, island, World.Environment.NORMAL,
Expand All @@ -83,19 +90,17 @@ public Island getIslandByUUID(UUID uuid) {
@Override
public Island getIslandAtPosition(int position, SortingType sortingType) {
ensureSortingType(sortingType);

Set<Island> sortedIslands = this.sortedIslands.get(sortingType);

return position < 0 || position > sortedIslands.size() ? null : Iterables.get(sortedIslands, position);
return this.sortedIslands.get(sortingType).readAndGet(sortedIslands -> {
return position < 0 || position > sortedIslands.size() ? null : sortedIslands.get(position);
});
}

@Override
public int getIslandPosition(Island island, SortingType sortingType) {
ensureSortingType(sortingType);

Set<Island> sortedIslands = this.sortedIslands.get(sortingType);

return Iterables.indexOf(sortedIslands, island::equals);
return this.sortedIslands.get(sortingType).readAndGet(sortedIslands -> {
return sortedIslands.indexOf(island);
});
}

@Override
Expand All @@ -119,9 +124,9 @@ public void sortIslands(SortingType sortingType, Runnable onFinish) {
public void sortIslands(SortingType sortingType, boolean forceSort, Runnable onFinish) {
ensureSortingType(sortingType);

Set<Island> sortedIslands = this.sortedIslands.get(sortingType);
Synchronized<List<Island>> sortedIslands = this.sortedIslands.get(sortingType);

if (!forceSort && sortedIslands.size() <= 1) {
if (!forceSort && (sortedIslands.readAndGet(List::size) <= 1 || !notifiedValues.remove(sortingType))) {
if (onFinish != null)
onFinish.run();
return;
Expand All @@ -134,11 +139,16 @@ public void sortIslands(SortingType sortingType, boolean forceSort, Runnable onF
}
}

@Override
public void notifyChange(SortingType sortingType, Island island) {
notifiedValues.add(sortingType);
}

@Override
public List<Island> getSortedIslands(SortingType sortingType) {
ensureSortingType(sortingType);
return new SequentialListBuilder<Island>()
.build(this.sortedIslands.get(sortingType));
return this.sortedIslands.get(sortingType).readAndGet(sortedIslands ->
new SequentialListBuilder<Island>().build(sortedIslands));
}

@Override
Expand Down Expand Up @@ -166,14 +176,12 @@ private void ensureSortingType(SortingType sortingType) {
}

private void sortIslandsInternal(SortingType sortingType, Runnable onFinish) {
Set<Island> newSortedTree = new TreeSet<>(sortingType);
List<Island> newIslandsList = new ArrayList<>(islandsByUUID.values());
newIslandsList.removeIf(Island::isIgnored);

for (Island island : islandsByUUID.values()) {
if (!island.isIgnored())
newSortedTree.add(island);
}
newIslandsList.sort(sortingType);

this.sortedIslands.put(sortingType, newSortedTree);
this.sortedIslands.put(sortingType, Synchronized.of(newIslandsList));

if (onFinish != null)
onFinish.run();
Expand Down

0 comments on commit 144a215

Please sign in to comment.