Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 14 additions & 21 deletions src/main/java/tk/shanebee/hg/HG.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.inventory.ItemStack;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.java.JavaPlugin;
import tk.shanebee.hg.commands.*;
import tk.shanebee.hg.data.*;
import tk.shanebee.hg.data.loot.LootTable;
import tk.shanebee.hg.game.Game;
import tk.shanebee.hg.listeners.*;
import tk.shanebee.hg.managers.*;
Expand All @@ -30,13 +30,9 @@ public class HG extends JavaPlugin {
private Map<String, BaseCmd> cmds;
private Map<UUID, PlayerSession> playerSession;

private Map<ItemStack, Integer> itemRarityMap;
private LootTable itemLootTable;

private Map<ItemStack, Integer> itemCostMap;

private Map<ItemStack, Integer> bonusRarityMap;

private Map<ItemStack, Integer> bonusCostMap;
private LootTable bonusLootTable;

//Lists
private List<Game> games;
Expand Down Expand Up @@ -84,10 +80,6 @@ public void loadPlugin(boolean load) {
}
games = new ArrayList<>();
playerSession = new HashMap<>();
itemCostMap = new HashMap<>();
itemRarityMap = new HashMap<>();
bonusCostMap = new HashMap<>();
bonusRarityMap = new HashMap<>();

config = new Config(this);
Bukkit.getLogger().info("Loading HungerGames by JT122406");
Expand Down Expand Up @@ -191,8 +183,8 @@ private void unloadPlugin(boolean reload) {
stopAll();
games = null;
playerSession = null;
itemRarityMap = null;
itemCostMap = null;
itemLootTable = null;
bonusLootTable = null;
plugin = null;
config = null;
nbtApi = null;
Expand Down Expand Up @@ -421,19 +413,20 @@ public NBTApi getNbtApi() {
public MobExecutor getMmMobManager() {
return this.mmMobManager;
}
public Map<ItemStack, Integer> getItemRarityMap() {
return itemRarityMap;
public LootTable getItemLootTable() {
return itemLootTable;
}

public Map<ItemStack, Integer> getItemCostMap() {
return itemCostMap;
public void setItemLootTable(LootTable itemLootTable) {
this.itemLootTable = itemLootTable;
}
public Map<ItemStack, Integer> getBonusRarityMap() {
return bonusRarityMap;

public LootTable getBonusLootTable() {
return bonusLootTable;
}

public Map<ItemStack, Integer> getBonusCostMap() {
return bonusCostMap;
public void setBonusLootTable(LootTable bonusLootTable) {
this.bonusLootTable = bonusLootTable;
}

}
28 changes: 11 additions & 17 deletions src/main/java/tk/shanebee/hg/data/ArenaConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;
import tk.shanebee.hg.*;
import tk.shanebee.hg.data.loot.LootTable;
import tk.shanebee.hg.game.Bound;
import tk.shanebee.hg.game.Game;
import tk.shanebee.hg.game.GameArenaData;
Expand Down Expand Up @@ -174,23 +174,17 @@ public void load() {
if (kit != null)
game.setKitManager(kit);

if (!arenadat.getStringList(path + ".items").isEmpty()) {
List<String> itemList = arenadat.getStringList(path + ".items");
Map<ItemStack, Integer> itemCostMap = HG.getPlugin().getItemCostMap();
Map<ItemStack, Integer> itemRarityMap = HG.getPlugin().getItemRarityMap();
plugin.getRandomItems().loadItems(itemList, itemCostMap, itemRarityMap);
game.getGameItemData().setItemCostMap(itemCostMap);
game.getGameItemData().setItemRarityMap(itemRarityMap);
Util.log(itemCostMap.keySet().size() + " Random items have been loaded for arena: &b" + arenaName);
ConfigurationSection itemsSection = arenadat.getConfigurationSection(path + ".items");
if (itemsSection != null) {
LootTable itemTable = plugin.getRandomItems().loadTable(itemsSection, 1);
game.getGameItemData().setItemLootTable(itemTable);
Util.log(itemTable.size() + " Random item entries have been loaded for arena: &b" + arenaName);
}
if (!arenadat.getStringList(path + ".bonus").isEmpty()) {
List<String> itemList = arenadat.getStringList(path + ".bonus");
Map<ItemStack, Integer> itemCostMap = HG.getPlugin().getBonusCostMap();
Map<ItemStack, Integer> itemRarityMap = HG.getPlugin().getBonusRarityMap();
plugin.getRandomItems().loadItems(itemList, itemCostMap, itemRarityMap);
game.getGameItemData().setBonusCostMap(itemCostMap);
game.getGameItemData().setBonusRarityMap(itemRarityMap);
Util.log(itemCostMap.keySet().size() + " Random items have been loaded for arena: &b" + arenaName);
ConfigurationSection bonusSection = arenadat.getConfigurationSection(path + ".bonus");
if (bonusSection != null) {
LootTable bonusTable = plugin.getRandomItems().loadTable(bonusSection, 1);
game.getGameItemData().setBonusLootTable(bonusTable);
Util.log(bonusTable.size() + " Random bonus item entries have been loaded for arena: &b" + arenaName);
}

if (arenadat.isSet(path + ".border.center")) {
Expand Down
94 changes: 55 additions & 39 deletions src/main/java/tk/shanebee/hg/data/RandomItems.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package tk.shanebee.hg.data;

import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;
import tk.shanebee.hg.HG;
import tk.shanebee.hg.data.loot.LootItem;
import tk.shanebee.hg.data.loot.LootTable;
import tk.shanebee.hg.util.Util;

import java.io.File;
import java.util.List;
import java.util.Map;

/**
Expand All @@ -17,7 +19,6 @@ public class RandomItems {

private FileConfiguration item = null;
private File customConfigFile = null;
public int size = 0;
private final HG plugin;

public RandomItems(HG plugin) {
Expand All @@ -39,48 +40,63 @@ private void reloadCustomConfig() {
}

public void load() {
loadItems(item.getStringList("items"), plugin.getItemCostMap(), plugin.getItemRarityMap());
loadItems(item.getStringList("bonus"), plugin.getBonusCostMap(), plugin.getBonusRarityMap());
Util.log(plugin.getItemRarityMap().keySet().size() + " Random items have been &aloaded!");
Util.log(plugin.getBonusRarityMap().keySet().size() + " Random bonus items have been &aloaded!");
ConfigurationSection itemsSection = item.getConfigurationSection("items");
LootTable itemTable = itemsSection != null ? loadTable(itemsSection, 1) : new LootTable(1);
plugin.setItemLootTable(itemTable);

ConfigurationSection bonusSection = item.getConfigurationSection("bonus");
LootTable bonusTable = bonusSection != null ? loadTable(bonusSection, 1) : new LootTable(1);
plugin.setBonusLootTable(bonusTable);

Util.log(itemTable.size() + " Random item entries have been &aloaded!");
Util.log(bonusTable.size() + " Random bonus item entries have been &aloaded!");
}

void loadItems(List<String> itemDefinitions, Map<ItemStack, Integer> costMap, Map<ItemStack, Integer> rarityMap) {
for (String s : itemDefinitions) {
int cost = 1;
int rarity = 1;
if (s.contains("cost:") && s.contains("rarity:")) {
int costStartIndex = s.indexOf("cost:") + 5;
int costEndIndex = s.indexOf(' ', costStartIndex) == -1 ? s.length() : s.indexOf(' ', costStartIndex);
String costStr = s.substring(costStartIndex, costEndIndex);
cost = Integer.parseInt(costStr);
int rarityStartIndex = s.indexOf("rarity:") + 7;
int rarityEndIndex = s.indexOf(' ', rarityStartIndex) == -1 ? s.length() : s.indexOf(' ', rarityStartIndex);
String rarityStr = s.substring(rarityStartIndex, rarityEndIndex);
rarity = Integer.parseInt(rarityStr);
}
else if (s.contains("cost:")) {
Util.log("Item definition %s doesn't contain a rarity! Defaulting to 1...", s);
int costStartIndex = s.indexOf("cost:") + 5;
int costEndIndex = s.indexOf(' ', costStartIndex) == -1 ? s.length() : s.indexOf(' ', costStartIndex);
String costStr = s.substring(costStartIndex, costEndIndex);
cost = Integer.parseInt(costStr);
}
else if (s.contains("rarity:")) {
Util.log("Item definition %s doesn't contain a cost! Defaulting to 1...", s);
int rarityStartIndex = s.indexOf("rarity:") + 7;
int rarityEndIndex = s.indexOf(' ', rarityStartIndex) == -1 ? s.length() : s.indexOf(' ', rarityStartIndex);
String rarityStr = s.substring(rarityStartIndex, rarityEndIndex);
rarity = Integer.parseInt(rarityStr);
/**
* Recursively build a {@link LootTable} from a configuration section. A section may contain an
* {@code items} list (rollable items) and/or a {@code tables} map of weighted sub-tables.
*
* @param section The section describing this table
* @param weight The weight of this table relative to its siblings
* @return The built loot table
*/
public LootTable loadTable(ConfigurationSection section, int weight) {
LootTable table = new LootTable(weight);

for (Map<?, ?> map : section.getMapList("items")) {
Object itemSpec = map.get("item");
if (itemSpec == null) {
Util.warning("Loot item is missing an 'item' field, skipping: &c%s", map);
continue;
}
else {
Util.log("Item definition %s doesn't contain a cost or a rarity! Defaulting to 1...", s);
int quantity = getInt(map.get("quantity"), 1);
int itemWeight = getInt(map.get("weight"), 1);
int cost = getInt(map.get("cost"), 1);
ItemStack stack = plugin.getItemStackManager().getItem(String.valueOf(itemSpec), true);
if (stack == null) continue; // getItem already warns on invalid materials
stack.setAmount(quantity);
table.add(new LootItem(stack, itemWeight, cost));
}

ConfigurationSection tables = section.getConfigurationSection("tables");
if (tables != null) {
for (String key : tables.getKeys(false)) {
ConfigurationSection sub = tables.getConfigurationSection(key);
if (sub == null) continue;
table.add(loadTable(sub, sub.getInt("weight", 1)));
}
String itemStackStr = s.replaceAll("cost:", "").replaceAll("rarity:", "");
ItemStack readItem = plugin.getItemStackManager().getItem(itemStackStr, true);
costMap.put(readItem, cost);
rarityMap.put(readItem, rarity);
}
return table;
}

private int getInt(Object value, int def) {
if (value instanceof Number number) {
return number.intValue();
}
if (value != null && Util.isInt(value.toString())) {
return Integer.parseInt(value.toString());
}
return def;
}

}
14 changes: 14 additions & 0 deletions src/main/java/tk/shanebee/hg/data/loot/LootEntry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package tk.shanebee.hg.data.loot;

/**
* A weighted entry within a {@link LootTable}. Either a {@link LootItem} (a leaf) or a
* nested {@link LootTable}.
*/
public interface LootEntry {

/**
* @return The weight of this entry relative to its siblings (higher = more likely)
*/
int getWeight();

}
40 changes: 40 additions & 0 deletions src/main/java/tk/shanebee/hg/data/loot/LootItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package tk.shanebee.hg.data.loot;

import org.bukkit.inventory.ItemStack;

/**
* A single rollable item in a {@link LootTable}, with its own weight and chest cost.
* The quantity is baked into the {@link ItemStack}.
*/
public class LootItem implements LootEntry {

private final ItemStack item;
private final int weight;
private final int cost;

public LootItem(ItemStack item, int weight, int cost) {
this.item = item;
this.weight = weight;
this.cost = cost;
}

/**
* @return The item stack (quantity included) this entry hands out
*/
public ItemStack getItem() {
return item;
}

@Override
public int getWeight() {
return weight;
}

/**
* @return How much of a chest's cost budget this item consumes
*/
public int getCost() {
return cost;
}

}
76 changes: 76 additions & 0 deletions src/main/java/tk/shanebee/hg/data/loot/LootTable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package tk.shanebee.hg.data.loot;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
* A weighted collection of {@link LootEntry LootEntries}. Children may be {@link LootItem items}
* or nested {@link LootTable tables}, allowing arbitrarily deep loot trees. Rolling picks a
* child weighted by its {@link LootEntry#getWeight() weight} and descends into sub-tables until
* it reaches a concrete {@link LootItem}.
*/
public class LootTable implements LootEntry {

private final int weight;
private final List<LootEntry> children = new ArrayList<>();

public LootTable(int weight) {
this.weight = weight;
}

/**
* Add a child entry (item or sub-table) to this table.
*
* @param entry The entry to add
*/
public void add(LootEntry entry) {
children.add(entry);
}

/**
* @return Whether this table has no entries
*/
public boolean isEmpty() {
return children.isEmpty();
}

/**
* @return The number of direct children in this table
*/
public int size() {
return children.size();
}

@Override
public int getWeight() {
return weight;
}

/**
* Roll a single item from this table, descending into any nested tables.
*
* @param rand Random source to use
* @return A rolled {@link LootItem}, or null if this (sub)tree yields nothing
*/
public LootItem roll(Random rand) {
if (children.isEmpty()) return null;
int total = 0;
for (LootEntry e : children) {
total += e.getWeight();
}
if (total <= 0) return null;
int r = rand.nextInt(total);
for (LootEntry e : children) {
r -= e.getWeight();
if (r < 0) {
if (e instanceof LootItem li) {
return li;
}
return ((LootTable) e).roll(rand);
}
}
return null;
}

}
Loading
Loading