Fix shop limits

This commit is contained in:
Eric 2020-02-20 13:23:53 +01:00
parent 2512d90fef
commit 8717a282c2
4 changed files with 141 additions and 14 deletions

View File

@ -63,6 +63,7 @@ import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
@ -446,6 +447,20 @@ public class ShopChest extends JavaPlugin {
Chunk[] loadedChunks = getServer().getWorlds().stream().map(World::getLoadedChunks) Chunk[] loadedChunks = getServer().getWorlds().stream().map(World::getLoadedChunks)
.flatMap(Stream::of).toArray(Chunk[]::new); .flatMap(Stream::of).toArray(Chunk[]::new);
shopUtils.loadShopAmounts(new Callback<Map<UUID,Integer>>(ShopChest.this) {
@Override
public void onResult(Map<UUID, Integer> result) {
getLogger().info("Loaded shop amounts");
debug("Loaded shop amounts");
}
@Override
public void onError(Throwable throwable) {
getLogger().severe("Failed to load shop amounts. Shop limits will not be working correctly!");
if (throwable != null) getLogger().severe(throwable.getMessage());
}
});
shopUtils.loadShops(loadedChunks, new Callback<Integer>(ShopChest.this) { shopUtils.loadShops(loadedChunks, new Callback<Integer>(ShopChest.this) {
@Override @Override
public void onResult(Integer result) { public void onResult(Integer result) {

View File

@ -366,6 +366,43 @@ public abstract class Database {
}.runTaskAsynchronously(plugin); }.runTaskAsynchronously(plugin);
} }
/**
* Get shop amounts for each player
*
* @param callback Callback that returns a map of each player's shop amount
*/
public void getShopAmounts(final Callback<Map<UUID, Integer>> callback) {
new BukkitRunnable(){
@Override
public void run() {
try (Connection con = dataSource.getConnection();
Statement s = con.createStatement()) {
ResultSet rs = s.executeQuery("SELECT vendor, COUNT(*) AS count FROM " + tableShops + " WHERE shoptype = 'NORMAL' GROUP BY vendor");
plugin.debug("Getting shop amounts from database");
Map<UUID, Integer> result = new HashMap<>();
while (rs.next()) {
UUID uuid = UUID.fromString(rs.getString("vendor"));
result.put(uuid, rs.getInt("count"));
}
if (callback != null) {
callback.callSyncResult(result);
}
} catch (SQLException ex) {
if (callback != null) {
callback.callSyncError(ex);
}
plugin.getLogger().severe("Failed to get shop amounts from database");
plugin.debug("Failed to get shop amounts from database");
plugin.debug(ex);
}
}
}.runTaskAsynchronously(plugin);
}
/** /**
* Get all shops from the database that are located in the given chunks * Get all shops from the database that are located in the given chunks
* *

View File

@ -0,0 +1,55 @@
package de.epiceric.shopchest.utils;
/**
* Represents a counter for integers greather than or equal to zero.
*/
public final class Counter {
private int value;
/**
* Creates a counter with a starting value of zero
*/
public Counter() {
this(0);
}
/**
* Creates a counter with the given starting value
* @param value the starting value of this counter
*/
public Counter(int value) {
set(value);
}
/**
* Increments the counter by one and returns itself
*/
public final Counter increment() {
this.value++;
return this;
}
/**
* Decrements the counter by one if its value is greater than zero and returns itself
*/
public final Counter decrement() {
this.value = Math.max(0, this.value - 1);
return this;
}
/**
* Sets the counter's value to the given value or zero if the given value is negative
* @param value the value to set the counter to
*/
public final Counter set(int value) {
this.value = Math.max(0, value);
return this;
}
/**
* Returns the current value
*/
public final int get() {
return value;
}
}

View File

@ -5,6 +5,7 @@ import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.event.ShopsLoadedEvent; import de.epiceric.shopchest.event.ShopsLoadedEvent;
import de.epiceric.shopchest.event.ShopsUnloadedEvent; import de.epiceric.shopchest.event.ShopsUnloadedEvent;
import de.epiceric.shopchest.shop.Shop; import de.epiceric.shopchest.shop.Shop;
import de.epiceric.shopchest.shop.Shop.ShopType;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Chunk; import org.bukkit.Chunk;
@ -23,6 +24,8 @@ import java.util.stream.Collectors;
public class ShopUtils { public class ShopUtils {
private final Map<UUID, Counter> playerShopAmount = new HashMap<>();
// concurrent since it is updated in async task // concurrent since it is updated in async task
private final Map<UUID, Location> playerLocation = new ConcurrentHashMap<>(); private final Map<UUID, Location> playerLocation = new ConcurrentHashMap<>();
private final Map<Location, Shop> shopLocation = new ConcurrentHashMap<>(); private final Map<Location, Shop> shopLocation = new ConcurrentHashMap<>();
@ -103,6 +106,9 @@ public class ShopUtils {
} }
if (addToDatabase) { if (addToDatabase) {
if (shop.getShopType() != ShopType.ADMIN) {
playerShopAmount.compute(shop.getVendor().getUniqueId(), (uuid, amount) -> amount == null ? new Counter(1) : amount.increment());
}
plugin.getShopDatabase().addShop(shop, callback); plugin.getShopDatabase().addShop(shop, callback);
} else { } else {
if (callback != null) callback.callSyncResult(shop.getID()); if (callback != null) callback.callSyncResult(shop.getID());
@ -145,6 +151,9 @@ public class ShopUtils {
shop.removeHologram(); shop.removeHologram();
if (removeFromDatabase) { if (removeFromDatabase) {
if (shop.getShopType() != ShopType.ADMIN) {
playerShopAmount.compute(shop.getVendor().getUniqueId(), (uuid, amount) -> amount == null ? new Counter() : amount.decrement());
}
plugin.getShopDatabase().removeShop(shop, callback); plugin.getShopDatabase().removeShop(shop, callback);
} else { } else {
if (callback != null) callback.callSyncResult(null); if (callback != null) callback.callSyncResult(null);
@ -186,8 +195,15 @@ public class ShopUtils {
shop.removeHologram(); shop.removeHologram();
}); });
Shop first = toRemove.values().iterator().next();
boolean isAdmin = first.getShopType() == ShopType.ADMIN;
UUID vendorUuid = first.getVendor().getUniqueId();
// Database#removeShop removes shop by ID so this only needs to be called once // Database#removeShop removes shop by ID so this only needs to be called once
if (removeFromDatabase) { if (removeFromDatabase) {
if (!isAdmin) {
playerShopAmount.compute(vendorUuid, (uuid, amount) -> amount == null ? new Counter() : amount.decrement());
}
plugin.getShopDatabase().removeShop(toRemove.values().iterator().next(), callback); plugin.getShopDatabase().removeShop(toRemove.values().iterator().next(), callback);
} else { } else {
if (callback != null) callback.callSyncResult(null); if (callback != null) callback.callSyncResult(null);
@ -250,23 +266,27 @@ public class ShopUtils {
* @return The amount of a shops a player has (if {@link Config#excludeAdminShops} is true, admin shops won't be counted) * @return The amount of a shops a player has (if {@link Config#excludeAdminShops} is true, admin shops won't be counted)
*/ */
public int getShopAmount(OfflinePlayer p) { public int getShopAmount(OfflinePlayer p) {
// FIXME: currently only showing loaded shops return playerShopAmount.getOrDefault(p.getUniqueId(), new Counter()).get();
float shopCount = 0;
for (Shop shop : getShops()) {
if (shop.getVendor().equals(p)) {
if (shop.getShopType() != Shop.ShopType.ADMIN) {
shopCount++;
InventoryHolder ih = shop.getInventoryHolder();
if (ih instanceof DoubleChest)
shopCount -= 0.5;
}
}
} }
return Math.round(shopCount); /**
* Loads the amount of shops for each player
* @param callback Callback that returns the amount of shops for each player
*/
public void loadShopAmounts(final Callback<Map<UUID, Integer>> callback) {
plugin.getShopDatabase().getShopAmounts(new Callback<Map<UUID,Integer>>(plugin) {
@Override
public void onResult(Map<UUID, Integer> result) {
playerShopAmount.clear();
result.forEach((uuid, amount) -> playerShopAmount.put(uuid, new Counter(amount)));
if (callback != null) callback.onResult(result);
}
@Override
public void onError(Throwable throwable) {
if (callback != null) callback.onError(throwable);
}
});
} }
/** /**