From fb35f19c3d5e13533f57c80fe86131ea36651c8f Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 30 Jan 2017 19:09:07 +0000 Subject: [PATCH] Add Villager Properties support --- .../mineplex/gemhunters/shop/ShopModule.java | 131 +++++++++++++++--- .../mineplex/gemhunters/shop/TraderNPC.java | 53 ++++--- .../gemhunters/shop/VillagerProperties.java | 59 ++++++++ .../VillagerPropertiesDeserialiser.java | 23 +++ 4 files changed, 227 insertions(+), 39 deletions(-) create mode 100644 Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/VillagerProperties.java create mode 100644 Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/deserialisers/VillagerPropertiesDeserialiser.java diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/ShopModule.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/ShopModule.java index 7428c26bf..fb36a9a75 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/ShopModule.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/ShopModule.java @@ -1,24 +1,30 @@ package mineplex.gemhunters.shop; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Villager; import org.bukkit.event.EventHandler; -import org.bukkit.event.player.PlayerJoinEvent; import mineplex.core.MiniPlugin; import mineplex.core.ReflectivelyCreateMiniPlugin; import mineplex.core.common.util.UtilAlg; import mineplex.core.common.util.UtilMath; +import mineplex.core.common.util.UtilTime; +import mineplex.core.common.util.UtilWorld; import mineplex.core.google.GoogleSheetsManager; import mineplex.core.google.SheetObjectDeserialiser; +import mineplex.core.updater.UpdateType; +import mineplex.core.updater.event.UpdateEvent; import mineplex.gemhunters.loot.deserialisers.LootItemDeserialiser; import mineplex.gemhunters.safezone.SafezoneModule; +import mineplex.gemhunters.shop.deserialisers.VillagerPropertiesDeserialiser; import mineplex.gemhunters.util.SlackSheetsBot; import mineplex.gemhunters.world.WorldDataModule; @@ -27,6 +33,8 @@ public class ShopModule extends MiniPlugin { private static final String SHEET_FILE_NAME = "GEM_HUNTERS_SHOP"; + private static final String VILLAGER_MASTER_SHEET_NAME = "VILLAGER_MASTER"; + private static final VillagerPropertiesDeserialiser VILLAGER_PROPERTIES_DESERIALISER = new VillagerPropertiesDeserialiser(); private static final LootItemDeserialiser DESERIALISER = new LootItemDeserialiser(); private static final SheetObjectDeserialiser COST_DESERIALISER = new SheetObjectDeserialiser() { @@ -36,18 +44,26 @@ public class ShopModule extends MiniPlugin { return Integer.parseInt(values[10]); } - + }; + private static final int MINIMUM_ITEMS = 1; private static final int MAXIMUM_ITEMS = 5; + private static final int MAX_SEARCH_ATTEMPTS = 40; + + private static final String[] NAMES = { + + }; private final GoogleSheetsManager _sheets; private final SafezoneModule _safezone; private final WorldDataModule _worldData; private final Map> _trades; + private final Map _properties; - private boolean _npcsSpawned; + private final List _npcs; + private final Map> _spawnedIndexes; private ShopModule() { @@ -58,6 +74,10 @@ public class ShopModule extends MiniPlugin _worldData = require(WorldDataModule.class); _trades = new HashMap<>(); + _properties = new HashMap<>(); + + _npcs = new ArrayList<>(); + _spawnedIndexes = new HashMap<>(); runSyncLater(() -> updateVillagerTrades(), 20); } @@ -69,6 +89,32 @@ public class ShopModule extends MiniPlugin for (String key : map.keySet()) { + if (key.equals(VILLAGER_MASTER_SHEET_NAME)) + { + int row = 0; + + for (List rows : map.get(key)) + { + row++; + try + { + VillagerProperties properties = VILLAGER_PROPERTIES_DESERIALISER.deserialise(rows.toArray(new String[0])); + _properties.put(properties.getDataKey(), properties); + } + catch (Exception e) + { + if (row != 1) + { + SlackSheetsBot.reportParsingError(e, "Villager Trades", key, row); + } + + continue; + } + + continue; + } + } + Set items = new HashSet<>(); int row = 0; @@ -98,37 +144,90 @@ public class ShopModule extends MiniPlugin } @EventHandler - public void playerJoin(PlayerJoinEvent event) + public void updateSpawnedVillagers(UpdateEvent event) { - if (_npcsSpawned) + if (event.getType() != UpdateType.SEC) { return; } - _npcsSpawned = true; - - for (String key : _trades.keySet()) + for (String key : _properties.keySet()) { - for (Location location : _worldData.getSpawnLocation(key)) + List locations = _worldData.getDataLocation(key); + VillagerProperties properties = _properties.get(key); + + if (!UtilTime.elapsed(properties.getLastSpawn(), properties.getSpawnRate())) { - boolean vegetated = _safezone.isInSafeZone(location); - Set items = getRandomItemSet(_trades.get(key)); - - new TraderNPC(_plugin, location, Villager.class, "Sam", vegetated, items); + continue; } + + properties.setLastSpawn(); + + // Only spawn more chests if we need to + int max = properties.getMax(); + int spawned = 0; + + for (TraderNPC npc : _npcs) + { + if (npc.getProperties().getDataKey().equals(key)) + { + spawned++; + } + } + + // If there are too many chests of this type we can ignore it + if (spawned > max) + { + continue; + } + + Set usedIndexes = _spawnedIndexes.get(key); + + if (usedIndexes == null) + { + _spawnedIndexes.put(key, new HashSet<>()); + usedIndexes = _spawnedIndexes.get(key); + } + + if (locations.size() == usedIndexes.size()) + { + return; + } + + Location randomLocation = null; + int attempts = 0; + int index = -1; + + while (index == -1 || usedIndexes.contains(index) && attempts < MAX_SEARCH_ATTEMPTS) + { + index = UtilMath.r(locations.size()); + + attempts++; + } + + if (index == -1) + { + continue; + } + + usedIndexes.add(index); + randomLocation = locations.get(index); + + Bukkit.broadcastMessage("Trader at " + UtilWorld.locToStrClean(randomLocation) + " with key=" + key + " and index=" + index + " and max=" + max); + _npcs.add(new TraderNPC(_plugin, randomLocation, Villager.class, NAMES[UtilMath.r(NAMES.length)], _safezone.isInSafeZone(randomLocation), properties, getRandomItemSet(_trades.get(key)))); } } - + public Set getRandomItemSet(Set items) { int size = UtilMath.rRange(MINIMUM_ITEMS, MAXIMUM_ITEMS); Set items2 = new HashSet<>(size); - + for (int i = 0; i < size; i++) { items2.add(UtilAlg.Random(items)); } - + return items2; } diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/TraderNPC.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/TraderNPC.java index 05f42fef6..7d0f7845b 100644 --- a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/TraderNPC.java +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/TraderNPC.java @@ -19,41 +19,43 @@ import mineplex.gemhunters.util.SimpleNPC; public class TraderNPC extends SimpleNPC { - + private final EconomyModule _economy; - + + private final VillagerProperties _properties; private final Set _selling; private final Inventory _inv; - - public TraderNPC(JavaPlugin plugin, Location spawn, Class type, String name, boolean vegetated, Set selling) + + public TraderNPC(JavaPlugin plugin, Location spawn, Class type, String name, boolean vegetated, VillagerProperties properties, Set selling) { super(plugin, spawn, type, name, null, vegetated); - + _economy = Managers.require(EconomyModule.class); - + + _properties = properties; _selling = selling; _inv = plugin.getServer().createInventory(null, 9, name); - + int index = 1; - + for (TradeableItem item : _selling) { _inv.setItem(index++, item.getLootItem().getItemStack()); } } - + @Override @EventHandler public void npcClick(PlayerInteractEntityEvent event) { super.npcClick(event); - + if (event.getRightClicked().equals(_entity)) { event.getPlayer().openInventory(_inv); } } - + @EventHandler public void inventoryClick(InventoryClickEvent event) { @@ -61,43 +63,43 @@ public class TraderNPC extends SimpleNPC { return; } - + if (!event.getInventory().equals(_inv)) { return; } - + ItemStack itemStack = event.getCurrentItem(); - + if (itemStack == null) { return; } - + Player player = (Player) event.getWhoClicked(); int gems = _economy.getGems(player); int cost = fromItemStack(itemStack); - + if (cost == 0) { return; } - + event.setCancelled(true); - + if (cost > gems) { player.playSound(player.getLocation(), Sound.ITEM_BREAK, 1, 0.6F); return; } - + _economy.removeFromStore(player, cost); - + player.playSound(player.getLocation(), Sound.NOTE_PLING, 1, 1.2F); player.getInventory().addItem(itemStack); player.closeInventory(); } - + public int fromItemStack(ItemStack itemStack) { for (TradeableItem item : _selling) @@ -107,8 +109,13 @@ public class TraderNPC extends SimpleNPC return item.getCost(); } } - + return 0; } - + + public final VillagerProperties getProperties() + { + return _properties; + } + } diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/VillagerProperties.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/VillagerProperties.java new file mode 100644 index 000000000..bb94751ea --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/VillagerProperties.java @@ -0,0 +1,59 @@ +package mineplex.gemhunters.shop; + +public class VillagerProperties +{ + + private final String _name; + private final String _dataKey; + private final int _spawnRate; + private final int _expireRate; + private final int _max; + + private long _lastSpawn; + + public VillagerProperties(String name, String dataKey, int spawnRate, int expireRate, int max) + { + _name = name; + _dataKey = dataKey; + _spawnRate = spawnRate; + _expireRate = expireRate; + _max = max; + + setLastSpawn(); + } + + public final String getName() + { + return _name; + } + + public final String getDataKey() + { + return _dataKey; + } + + public final int getSpawnRate() + { + return _spawnRate; + } + + public final int getExpireRate() + { + return _expireRate; + } + + public final int getMax() + { + return _max; + } + + public void setLastSpawn() + { + _lastSpawn = System.currentTimeMillis(); + } + + public long getLastSpawn() + { + return _lastSpawn; + } +} diff --git a/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/deserialisers/VillagerPropertiesDeserialiser.java b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/deserialisers/VillagerPropertiesDeserialiser.java new file mode 100644 index 000000000..683564b1e --- /dev/null +++ b/Plugins/mineplex-game-gemhunters/src/mineplex/gemhunters/shop/deserialisers/VillagerPropertiesDeserialiser.java @@ -0,0 +1,23 @@ +package mineplex.gemhunters.shop.deserialisers; + +import mineplex.core.google.SheetObjectDeserialiser; +import mineplex.gemhunters.shop.VillagerProperties; + +public class VillagerPropertiesDeserialiser implements SheetObjectDeserialiser +{ + + @Override + public VillagerProperties deserialise(String[] values) throws ArrayIndexOutOfBoundsException + { + String name = values[0]; + String dataKey = values[1]; + + int spawnRate = Integer.parseInt(values[2]); + int expireRate = Integer.parseInt(values[3]); + + int max = Integer.parseInt(values[4]); + + return new VillagerProperties(name, dataKey, spawnRate, expireRate, max); + } + +}