From 9f2a8c1a3df39c2d205fcf48c74761521caa3055 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 11:46:31 +0100 Subject: [PATCH 01/31] Update TextMode.java --- src/me/ryanhamshire/AutomaticInventory/TextMode.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/me/ryanhamshire/AutomaticInventory/TextMode.java b/src/me/ryanhamshire/AutomaticInventory/TextMode.java index 68c29ca..96b2d26 100644 --- a/src/me/ryanhamshire/AutomaticInventory/TextMode.java +++ b/src/me/ryanhamshire/AutomaticInventory/TextMode.java @@ -5,11 +5,11 @@ import org.bukkit.ChatColor; //just a few constants for chat color codes -class TextMode +public class TextMode { - final static ChatColor Info = ChatColor.AQUA; - final static ChatColor Instr = ChatColor.YELLOW; - final static ChatColor Warn = ChatColor.GOLD; - final static ChatColor Err = ChatColor.RED; - final static ChatColor Success = ChatColor.GREEN; + public final static ChatColor Info = ChatColor.AQUA; + public final static ChatColor Instr = ChatColor.YELLOW; + public final static ChatColor Warn = ChatColor.GOLD; + public final static ChatColor Err = ChatColor.RED; + public final static ChatColor Success = ChatColor.GREEN; } From 0528b2d14d02b46e048ee57ce8e453b208b13892 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 11:47:10 +0100 Subject: [PATCH 02/31] Update SendPlayerMessageTask.java --- .../ryanhamshire/AutomaticInventory/SendPlayerMessageTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/me/ryanhamshire/AutomaticInventory/SendPlayerMessageTask.java b/src/me/ryanhamshire/AutomaticInventory/SendPlayerMessageTask.java index 1ebe963..5ee4335 100644 --- a/src/me/ryanhamshire/AutomaticInventory/SendPlayerMessageTask.java +++ b/src/me/ryanhamshire/AutomaticInventory/SendPlayerMessageTask.java @@ -7,7 +7,7 @@ //sends a message to a player //used to send delayed messages, for example help text triggered by a player's chat -class SendPlayerMessageTask implements Runnable +public class SendPlayerMessageTask implements Runnable { private Player player; private ChatColor color; From 4d79c33b9c91ae4867cdc053725a8751ce924a4a Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 11:51:36 +0100 Subject: [PATCH 03/31] Update PlayerData.java --- .../AutomaticInventory/PlayerData.java | 68 +++++++++---------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/src/me/ryanhamshire/AutomaticInventory/PlayerData.java b/src/me/ryanhamshire/AutomaticInventory/PlayerData.java index 48cfae7..5c2a500 100644 --- a/src/me/ryanhamshire/AutomaticInventory/PlayerData.java +++ b/src/me/ryanhamshire/AutomaticInventory/PlayerData.java @@ -14,7 +14,7 @@ import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.MetadataValue; -class PlayerData +public class PlayerData { private final static String METADATA_TAG = "AI_PlayerData"; private Thread loadingThread; @@ -28,70 +28,74 @@ class PlayerData private boolean gotQuickDepositInfo = false; private boolean gotDepositAllInfo = false; private boolean usedDepositAll = false; + private UUID playerID; + private boolean isDirty = false; + private boolean sortChests = true; + int firstEmptySlot = -1; + private boolean sortInventory = true; - boolean isUsedQuickDeposit() + + public boolean isUsedQuickDeposit() { return usedQuickDeposit; } - void setUsedQuickDeposit(boolean usedQuickDeposit) + public void setUsedQuickDeposit(boolean usedQuickDeposit) { this.usedQuickDeposit = usedQuickDeposit; this.isDirty = true; } - boolean isUsedDepositAll() + public boolean isUsedDepositAll() { return usedDepositAll; } - void setUsedDepositAll(boolean usedDepositAll) + public void setUsedDepositAll(boolean usedDepositAll) { this.usedDepositAll = usedDepositAll; this.isDirty = true; } - boolean isGotChestSortInfo() + public boolean isGotChestSortInfo() { return gotChestSortInfo; } - void setGotChestSortInfo(boolean gotChestSortInfo) + public void setGotChestSortInfo(boolean gotChestSortInfo) { this.gotChestSortInfo = gotChestSortInfo; this.isDirty = true; } - boolean isGotInventorySortInfo() + public boolean isGotInventorySortInfo() { return gotInventorySortInfo; } - void setGotInventorySortInfo(boolean gotInventorySortInfo) + public void setGotInventorySortInfo(boolean gotInventorySortInfo) { this.gotInventorySortInfo = gotInventorySortInfo; this.isDirty = true; } - boolean isGotRestackInfo() + public boolean isGotRestackInfo() { return gotRestackInfo; } - void setGotRestackInfo(boolean gotRestackInfo) + public void setGotRestackInfo(boolean gotRestackInfo) { this.gotRestackInfo = gotRestackInfo; this.isDirty = true; } - - private UUID playerID; - static void Preload(Player player) + public static void Preload(Player player) { new PlayerData(player); } - static PlayerData FromPlayer(Player player) + public static PlayerData FromPlayer(Player player) { List data = player.getMetadata(METADATA_TAG); if(data == null || data.isEmpty()) @@ -113,57 +117,49 @@ private PlayerData(Player player) this.loadingThread.start(); player.setMetadata(METADATA_TAG, new FixedMetadataValue(AutomaticInventory.instance, this)); } - - int firstEmptySlot = -1; - - private boolean isDirty = false; - - private boolean sortChests = true; - boolean isSortChests() + + public boolean isSortChests() { this.waitForLoadComplete(); return sortChests; } - void setSortChests(boolean sortChests) + public void setSortChests(boolean sortChests) { this.isDirty = true; this.sortChests = sortChests; } - - private boolean sortInventory = true; - - boolean isSortInventory() + public boolean isSortInventory() { this.waitForLoadComplete(); return sortInventory; } - void setSortInventory(boolean sortInventory) + public void setSortInventory(boolean sortInventory) { this.isDirty = true; this.sortInventory = sortInventory; } - void incrementManualDeposits() + public void incrementManualDeposits() { this.manualDepositsThisSession++; } - int getManualDeposits() + public int getManualDeposits() { return this.manualDepositsThisSession; } - boolean isGotQuickDepositInfo() + public boolean isGotQuickDepositInfo() { return gotQuickDepositInfo; } - void setGotQuickDepositInfo(boolean newValue) + public void setGotQuickDepositInfo(boolean newValue) { this.gotQuickDepositInfo = newValue; } - void saveChanges() + public void saveChanges() { if(!this.isDirty) return; @@ -185,7 +181,7 @@ private void waitForLoadComplete() } } - void waitForSaveComplete() + public void waitForSaveComplete() { if(this.savingThread != null) { @@ -293,7 +289,7 @@ public void run() } } - boolean isGotDepositAllInfo() + public boolean isGotDepositAllInfo() { return this.gotDepositAllInfo; } @@ -303,4 +299,4 @@ public void setGotDepositAllInfo(boolean status) this.gotDepositAllInfo = status; this.isDirty = true; } -} \ No newline at end of file +} From ade183c3b4264a9cfa78cce594104e361e2a7525 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 11:54:18 +0100 Subject: [PATCH 04/31] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 0337239..b69c533 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,6 @@ I created this Minecraft server plugin using the Bukkit API to minimize the pain of inventory management. It automatically sorts player and chest inventories, intelligently deposits player loot into correct containers, and auto-refills hotbar slots when players use the last item in a stack (or break a tool!) but have more of the same in their backpacks. I stopped working on this project after Minecraft 1.10. Anyone may use my source code to continue the project, but see the LICENSE file for restrictions. + +# The future of this project +Actually, me (crazyhoorse961) i want to continue this project with a fork. Ill try update it, i won't publish it on spigot or bukkit but feel free to build it, soon ill leave releases here on github. From 15a5986dbff7eb158ea6707f54987d99b2db76e2 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:01:53 +0100 Subject: [PATCH 05/31] Updated plugin.yml with additional infos --- plugin.yml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/plugin.yml b/plugin.yml index e2ff124..86e02b7 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,17 +1,17 @@ +main: me.ryanhamshire.automaticinventory.AutomaticInventory name: AutomaticInventory -main: me.ryanhamshire.AutomaticInventory.AutomaticInventory -version: 2.7.1 +version: 2.7.2 Fork commands: debugai: - description: Debug command for AutomaticInventory. + description: The debug command for AutomaticInventory usage: /debugai permission: automaticinventory.debug autosort: description: Toggles auto-sorting options. - usage: /AutoSort + usage: /autosort depositall: description: Deposits your non-hotbar inventory into any nearby chests containing matching items. - usage: /DepositAll + usage: /depositall aliases: [da, dumpitems, dumploot, depositloot] permission: automaticinventory.depositall permissions: @@ -44,4 +44,8 @@ permissions: default: true automaticinventory.depositall: description: Grants permission to use /DepositAll. - default: true \ No newline at end of file + default: true +load: STARTUP +authors: [ryanhamshire,crazyhoorse961] +website: https://github.com/crazyhorse961/AutomaticInventory +database: false From a36767d956a6396f925228ac4ab37869792964b0 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:04:11 +0100 Subject: [PATCH 06/31] Create pom.xml --- pom.xml | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 pom.xml diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..c148703 --- /dev/null +++ b/pom.xml @@ -0,0 +1,49 @@ + + 4.0.0 + com.crazyhoorse961 + auto-inv + 0.0.1-SNAPSHOT + AutomaticInventory + + src + + + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + + + + org.spigotmc + spigot-api + 1.11-R0.1-SNAPSHOT + provided + + + + org.bukkit + bukkit + 1.11-R0.1-SNAPSHOT + provided + + + + org.bukkit + craftbukkit + 1.11-R0.1-SNAPSHOT + provided + + + From 7670b4a75e2189ab78f0dfd3b85b282b2a544741 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:06:22 +0100 Subject: [PATCH 07/31] Delete PlayerData.java --- .../AutomaticInventory/PlayerData.java | 302 ------------------ 1 file changed, 302 deletions(-) delete mode 100644 src/me/ryanhamshire/AutomaticInventory/PlayerData.java diff --git a/src/me/ryanhamshire/AutomaticInventory/PlayerData.java b/src/me/ryanhamshire/AutomaticInventory/PlayerData.java deleted file mode 100644 index 5c2a500..0000000 --- a/src/me/ryanhamshire/AutomaticInventory/PlayerData.java +++ /dev/null @@ -1,302 +0,0 @@ -//Copyright 2015 Ryan Hamshire - -package me.ryanhamshire.AutomaticInventory; - -import java.io.File; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.List; -import java.util.UUID; - -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; -import org.bukkit.metadata.FixedMetadataValue; -import org.bukkit.metadata.MetadataValue; - -public class PlayerData -{ - private final static String METADATA_TAG = "AI_PlayerData"; - private Thread loadingThread; - private Thread savingThread; - private String playerName; - private boolean gotChestSortInfo = false; - private boolean gotInventorySortInfo = false; - private boolean gotRestackInfo = false; - private boolean usedQuickDeposit = false; - private int manualDepositsThisSession = 0; - private boolean gotQuickDepositInfo = false; - private boolean gotDepositAllInfo = false; - private boolean usedDepositAll = false; - private UUID playerID; - private boolean isDirty = false; - private boolean sortChests = true; - int firstEmptySlot = -1; - private boolean sortInventory = true; - - - public boolean isUsedQuickDeposit() - { - return usedQuickDeposit; - } - - public void setUsedQuickDeposit(boolean usedQuickDeposit) - { - this.usedQuickDeposit = usedQuickDeposit; - this.isDirty = true; - } - - public boolean isUsedDepositAll() - { - return usedDepositAll; - } - - public void setUsedDepositAll(boolean usedDepositAll) - { - this.usedDepositAll = usedDepositAll; - this.isDirty = true; - } - - public boolean isGotChestSortInfo() - { - return gotChestSortInfo; - } - - public void setGotChestSortInfo(boolean gotChestSortInfo) - { - this.gotChestSortInfo = gotChestSortInfo; - this.isDirty = true; - } - - public boolean isGotInventorySortInfo() - { - return gotInventorySortInfo; - } - - public void setGotInventorySortInfo(boolean gotInventorySortInfo) - { - this.gotInventorySortInfo = gotInventorySortInfo; - this.isDirty = true; - } - - public boolean isGotRestackInfo() - { - return gotRestackInfo; - } - - public void setGotRestackInfo(boolean gotRestackInfo) - { - this.gotRestackInfo = gotRestackInfo; - this.isDirty = true; - } - - public static void Preload(Player player) - { - new PlayerData(player); - } - - public static PlayerData FromPlayer(Player player) - { - List data = player.getMetadata(METADATA_TAG); - if(data == null || data.isEmpty()) - { - return new PlayerData(player); - } - else - { - PlayerData playerData = (PlayerData)(data.get(0).value()); - return playerData; - } - } - - private PlayerData(Player player) - { - this.playerName = player.getName(); - this.playerID = player.getUniqueId(); - this.loadingThread = new Thread(new DataLoader()); - this.loadingThread.start(); - player.setMetadata(METADATA_TAG, new FixedMetadataValue(AutomaticInventory.instance, this)); - } - - public boolean isSortChests() - { - this.waitForLoadComplete(); - return sortChests; - } - public void setSortChests(boolean sortChests) - { - this.isDirty = true; - this.sortChests = sortChests; - } - public boolean isSortInventory() - { - this.waitForLoadComplete(); - return sortInventory; - } - public void setSortInventory(boolean sortInventory) - { - this.isDirty = true; - this.sortInventory = sortInventory; - } - - public void incrementManualDeposits() - { - this.manualDepositsThisSession++; - } - - public int getManualDeposits() - { - return this.manualDepositsThisSession; - } - - public boolean isGotQuickDepositInfo() - { - return gotQuickDepositInfo; - } - - public void setGotQuickDepositInfo(boolean newValue) - { - this.gotQuickDepositInfo = newValue; - } - - public void saveChanges() - { - if(!this.isDirty) return; - - this.waitForLoadComplete(); - this.savingThread = new Thread(new DataSaver()); - this.savingThread.start(); - } - - private void waitForLoadComplete() - { - if(this.loadingThread != null) - { - try - { - this.loadingThread.join(); - } - catch(InterruptedException e){} - this.loadingThread = null; - } - } - - public void waitForSaveComplete() - { - if(this.savingThread != null) - { - try - { - this.savingThread.join(); - } - catch(InterruptedException e){} - } - } - - private void writeDataToFile() - { - try - { - FileConfiguration config = new YamlConfiguration(); - config.set("Player Name", this.playerName); - config.set("Sort Chests", this.sortChests); - config.set("Sort Personal Inventory", this.sortInventory); - config.set("Used Quick Deposit", this.usedQuickDeposit); - config.set("Received Messages.Personal Inventory", this.gotInventorySortInfo); - config.set("Received Messages.Chest Inventory", this.gotChestSortInfo); - config.set("Received Messages.Restacker", this.gotRestackInfo); - config.set("Received Messages.Deposit All", this.gotDepositAllInfo); - File playerFile = new File(DataStore.playerDataFolderPath + File.separator + this.playerID.toString()); - config.save(playerFile); - } - catch(Exception e) - { - StringWriter errors = new StringWriter(); - e.printStackTrace(new PrintWriter(errors)); - AutomaticInventory.AddLogEntry("Failed to save player data for " + playerID + " " + errors.toString()); - } - - this.savingThread = null; - this.isDirty = false; - } - - private void readDataFromFile() - { - File playerFile = new File(DataStore.playerDataFolderPath + File.separator + this.playerID.toString()); - - //if it exists as a file, read the file - if(playerFile.exists()) - { - boolean needRetry = false; - int retriesRemaining = 5; - Exception latestException = null; - do - { - try - { - needRetry = false; - FileConfiguration config = YamlConfiguration.loadConfiguration(playerFile); - this.sortChests = config.getBoolean("Sort Chests", true); - this.sortInventory = config.getBoolean("Sort Personal Inventory", true); - this.usedQuickDeposit = config.getBoolean("Used Quick Deposit", false); - this.gotChestSortInfo = config.getBoolean("Received Messages.Chest Inventory", false); - this.gotInventorySortInfo = config.getBoolean("Received Messages.Personal Inventory", false); - this.gotRestackInfo = config.getBoolean("Received Messages.Restacker", false); - this.gotDepositAllInfo = config.getBoolean("Received Messages.Deposit All", false); - } - - //if there's any problem with the file's content, retry up to 5 times with 5 milliseconds between - catch(Exception e) - { - latestException = e; - needRetry = true; - retriesRemaining--; - } - - try - { - if(needRetry) Thread.sleep(5); - } - catch(InterruptedException exception) {} - - }while(needRetry && retriesRemaining >= 0); - - //if last attempt failed, log information about the problem - if(needRetry) - { - StringWriter errors = new StringWriter(); - latestException.printStackTrace(new PrintWriter(errors)); - AutomaticInventory.AddLogEntry("Failed to load data for " + playerID + " " + errors.toString()); - } - } - } - - private class DataSaver implements Runnable - { - @Override - public void run() - { - writeDataToFile(); - } - } - - private class DataLoader implements Runnable - { - @Override - public void run() - { - readDataFromFile(); - } - } - - public boolean isGotDepositAllInfo() - { - return this.gotDepositAllInfo; - } - - public void setGotDepositAllInfo(boolean status) - { - this.gotDepositAllInfo = status; - this.isDirty = true; - } -} From de3ae2fa6f1df560f389a2e47f7bafd13c097295 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:06:33 +0100 Subject: [PATCH 08/31] Delete FindChestsThread.java --- .../AutomaticInventory/FindChestsThread.java | 223 ------------------ 1 file changed, 223 deletions(-) delete mode 100644 src/me/ryanhamshire/AutomaticInventory/FindChestsThread.java diff --git a/src/me/ryanhamshire/AutomaticInventory/FindChestsThread.java b/src/me/ryanhamshire/AutomaticInventory/FindChestsThread.java deleted file mode 100644 index a1e0fbc..0000000 --- a/src/me/ryanhamshire/AutomaticInventory/FindChestsThread.java +++ /dev/null @@ -1,223 +0,0 @@ -package me.ryanhamshire.AutomaticInventory; - -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; - -import org.bukkit.Bukkit; -import org.bukkit.ChunkSnapshot; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.BlockState; -import org.bukkit.entity.Player; -import org.bukkit.event.block.Action; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.InventoryHolder; -import org.bukkit.inventory.PlayerInventory; -import org.bukkit.util.Vector; - -public class FindChestsThread extends Thread -{ - private World world; - private ChunkSnapshot[][] snapshots; - private int minY; - private int maxY; - private int startX; - private int startY; - private int startZ; - private Player player; - private ChunkSnapshot smallestChunk; - - private boolean [][][] seen; - - public FindChestsThread(World world, ChunkSnapshot[][] snapshots, int minY, int maxY, int startX, int startY, int startZ, Player player) - { - this.world = world; - this.snapshots = snapshots; - this.minY = minY; - this.maxY = maxY; - this.smallestChunk = this.snapshots[0][0]; - this.startX = startX - this.smallestChunk.getX() * 16; - this.startY = startY; - this.startZ = startZ - this.smallestChunk.getZ() * 16; - if(this.maxY >= world.getMaxHeight()) this.maxY = world.getMaxHeight() - 1; - this.player = player; - this.seen = new boolean[48][this.maxY - this.minY + 1][48]; - } - - @Override - public void run() - { - Queue chestLocations = new ConcurrentLinkedQueue(); - Queue leftToVisit = new ConcurrentLinkedQueue(); - Vector start = new Vector(this.startX, this.startY, this.startZ); - leftToVisit.add(start); - this.markSeen(start); - while(!leftToVisit.isEmpty()) - { - Vector current = leftToVisit.remove(); - - int typeID = this.getTypeID(current); - if(isChestID(typeID)) - { - int overTypeID = this.getTypeID(new Vector(current.getBlockX(), current.getBlockY() + 1, current.getBlockZ())); - if(!AutomaticInventory.preventsChestOpen(overTypeID)) - { - chestLocations.add(this.makeLocation(current)); - } - } - - if(this.isPassableID(typeID)) - { - Vector [] adjacents = new Vector [] { - new Vector(current.getBlockX() + 1, current.getBlockY(), current.getBlockZ()), - new Vector(current.getBlockX() - 1, current.getBlockY(), current.getBlockZ()), - new Vector(current.getBlockX(), current.getBlockY() + 1, current.getBlockZ()), - new Vector(current.getBlockX(), current.getBlockY() - 1, current.getBlockZ()), - new Vector(current.getBlockX(), current.getBlockY(), current.getBlockZ() + 1), - new Vector(current.getBlockX(), current.getBlockY(), current.getBlockZ() - 1), - }; - - for(Vector adjacent : adjacents) - { - if(!this.alreadySeen(adjacent)) - { - leftToVisit.add(adjacent); - this.markSeen(adjacent); - } - } - } - } - - QuickDepositChain chain = new QuickDepositChain(chestLocations, new DepositRecord(), player, true); - Bukkit.getScheduler().runTaskLater(AutomaticInventory.instance, chain, 1L); - } - - private Location makeLocation(Vector location) - { - return new Location( - this.world, - this.smallestChunk.getX() * 16 + location.getBlockX(), - location.getBlockY(), - this.smallestChunk.getZ() * 16 + location.getBlockZ()); - } - - @SuppressWarnings("deprecation") - private int getTypeID(Vector location) - { - if(this.outOfBounds(location)) return -1; - int chunkx = location.getBlockX() / 16; - int chunkz = location.getBlockZ() / 16; - ChunkSnapshot chunk = this.snapshots[chunkx][chunkz]; - int x = location.getBlockX() % 16; - int z = location.getBlockZ() % 16; - return chunk.getBlockTypeId(x, location.getBlockY(), z); - } - - private boolean alreadySeen(Vector location) - { - if(this.outOfBounds(location)) return true; - int y = location.getBlockY() - this.minY; - return this.seen[location.getBlockX()][y][location.getBlockZ()]; - } - - private void markSeen(Vector location) - { - if(this.outOfBounds(location)) return; - int y = location.getBlockY() - this.minY; - this.seen[location.getBlockX()][y][location.getBlockZ()] = true; - } - - private boolean outOfBounds(Vector location) - { - if(location.getBlockY() > this.maxY) return true; - if(location.getBlockY() < this.minY) return true; - if(location.getBlockX() >= 48) return true; - if(location.getBlockX() < 0) return true; - if(location.getBlockZ() >= 48) return true; - if(location.getBlockZ() < 0) return true; - return false; - } - - private boolean isChestID(int id) - { - return (id == 54 || id == 146); - } - - private boolean isPassableID(int id) - { - switch(id) - { - case 0: //air - case 54: //chest - case 146: //trapped chest - case 154: //hopper - case 68: //wall sign - case 389: //item frame - return true; - default: - return false; - } - } - - class QuickDepositChain implements Runnable - { - private Queue remainingChestLocations; - private DepositRecord runningDepositRecord; - private Player player; - private boolean respectExclusions; - - QuickDepositChain(Queue remainingChestLocations, DepositRecord runningDepositRecord, Player player, boolean respectExclusions) - { - super(); - this.remainingChestLocations = remainingChestLocations; - this.runningDepositRecord = runningDepositRecord; - this.player = player; - this.respectExclusions = respectExclusions; - } - - @Override - public void run() - { - Location chestLocation = this.remainingChestLocations.poll(); - if(chestLocation == null) - { - AutomaticInventory.sendMessage(this.player, TextMode.Success, Messages.SuccessfulDepositAll2, String.valueOf(this.runningDepositRecord.totalItems)); - PlayerData playerData = PlayerData.FromPlayer(player); - if(Math.random() < .1 && !playerData.isGotQuickDepositInfo() && AIEventHandler.featureEnabled(Features.QuickDeposit, player)) - { - AutomaticInventory.sendMessage(player, TextMode.Instr, Messages.QuickDepositAdvertisement3); - playerData.setGotQuickDepositInfo(true); - } - } - else - { - Block block = chestLocation.getBlock(); - PlayerInteractEvent fakeEvent = AutomaticInventory.instance.new FakePlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, player.getInventory().getItemInMainHand(), block, BlockFace.UP); - Bukkit.getServer().getPluginManager().callEvent(fakeEvent); - if(!fakeEvent.isCancelled()) - { - BlockState state = block.getState(); - if(state instanceof InventoryHolder) - { - InventoryHolder chest = (InventoryHolder)state; - Inventory chestInventory = chest.getInventory(); - if(!this.respectExclusions || AIEventHandler.isSortableChestInventory(chestInventory)) - { - PlayerInventory playerInventory = player.getInventory(); - - DepositRecord deposits = AutomaticInventory.depositMatching(playerInventory, chestInventory, false); - - this.runningDepositRecord.totalItems += deposits.totalItems; - } - } - } - - QuickDepositChain chain = new QuickDepositChain(this.remainingChestLocations, this.runningDepositRecord, this.player, this.respectExclusions); - Bukkit.getScheduler().runTaskLater(AutomaticInventory.instance, chain, 1L); - } - } - } -} From 5505185b5f696c7787ea3d4b1cecf7ea9cf3c35b Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:06:40 +0100 Subject: [PATCH 09/31] Delete TextMode.java --- .../ryanhamshire/AutomaticInventory/TextMode.java | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 src/me/ryanhamshire/AutomaticInventory/TextMode.java diff --git a/src/me/ryanhamshire/AutomaticInventory/TextMode.java b/src/me/ryanhamshire/AutomaticInventory/TextMode.java deleted file mode 100644 index 96b2d26..0000000 --- a/src/me/ryanhamshire/AutomaticInventory/TextMode.java +++ /dev/null @@ -1,15 +0,0 @@ -//Copyright 2015 Ryan Hamshire - -package me.ryanhamshire.AutomaticInventory; - -import org.bukkit.ChatColor; - -//just a few constants for chat color codes -public class TextMode -{ - public final static ChatColor Info = ChatColor.AQUA; - public final static ChatColor Instr = ChatColor.YELLOW; - public final static ChatColor Warn = ChatColor.GOLD; - public final static ChatColor Err = ChatColor.RED; - public final static ChatColor Success = ChatColor.GREEN; -} From fbf93a2e50caaad142257fa1c5d4487a9070b9f8 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:06:46 +0100 Subject: [PATCH 10/31] Delete SendPlayerMessageTask.java --- .../SendPlayerMessageTask.java | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 src/me/ryanhamshire/AutomaticInventory/SendPlayerMessageTask.java diff --git a/src/me/ryanhamshire/AutomaticInventory/SendPlayerMessageTask.java b/src/me/ryanhamshire/AutomaticInventory/SendPlayerMessageTask.java deleted file mode 100644 index 5ee4335..0000000 --- a/src/me/ryanhamshire/AutomaticInventory/SendPlayerMessageTask.java +++ /dev/null @@ -1,34 +0,0 @@ -//Copyright 2015 Ryan Hamshire - -package me.ryanhamshire.AutomaticInventory; - -import org.bukkit.ChatColor; -import org.bukkit.entity.Player; - -//sends a message to a player -//used to send delayed messages, for example help text triggered by a player's chat -public class SendPlayerMessageTask implements Runnable -{ - private Player player; - private ChatColor color; - private String message; - - public SendPlayerMessageTask(Player player, ChatColor color, String message) - { - this.player = player; - this.color = color; - this.message = message; - } - - @Override - public void run() - { - if(player == null) - { - AutomaticInventory.AddLogEntry(color + message); - return; - } - - AutomaticInventory.sendMessage(this.player, this.color, this.message); - } -} From f163b6b49a3150142e2c518059b354e38fae5081 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:06:54 +0100 Subject: [PATCH 11/31] Delete Messages.java --- .../AutomaticInventory/Messages.java | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 src/me/ryanhamshire/AutomaticInventory/Messages.java diff --git a/src/me/ryanhamshire/AutomaticInventory/Messages.java b/src/me/ryanhamshire/AutomaticInventory/Messages.java deleted file mode 100644 index a8328ae..0000000 --- a/src/me/ryanhamshire/AutomaticInventory/Messages.java +++ /dev/null @@ -1,23 +0,0 @@ -//Copyright 2015 Ryan Hamshire - -package me.ryanhamshire.AutomaticInventory; - -public enum Messages -{ - AutoSortHelp, - NoPermissionForFeature, - ChestSortEnabled, - ChestSortDisabled, - InventorySortEnabled, - InventorySortDisabled, - AutoRefillEducation, - InventorySortEducation, - ChestSortEducation3, - SuccessfulDeposit2, - FailedDepositNoMatch, - FailedDepositChestFull2, - SuccessfulDepositAll2, - ChestLidBlocked, - DepositAllAdvertisement, - QuickDepositAdvertisement3 -} From b1071414c273a45b722b076a29d02cf97ac0c1d6 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:07:00 +0100 Subject: [PATCH 12/31] Delete Features.java --- src/me/ryanhamshire/AutomaticInventory/Features.java | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 src/me/ryanhamshire/AutomaticInventory/Features.java diff --git a/src/me/ryanhamshire/AutomaticInventory/Features.java b/src/me/ryanhamshire/AutomaticInventory/Features.java deleted file mode 100644 index b96dd14..0000000 --- a/src/me/ryanhamshire/AutomaticInventory/Features.java +++ /dev/null @@ -1,10 +0,0 @@ -package me.ryanhamshire.AutomaticInventory; - -enum Features -{ - RefillStacks, - SortInventory, - SortChests, - QuickDeposit, - DepositAll -} From edf4eb1aa104e229d078400a4abcf4abf5cfbf10 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:07:05 +0100 Subject: [PATCH 13/31] Delete DepositRecord.java --- src/me/ryanhamshire/AutomaticInventory/DepositRecord.java | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 src/me/ryanhamshire/AutomaticInventory/DepositRecord.java diff --git a/src/me/ryanhamshire/AutomaticInventory/DepositRecord.java b/src/me/ryanhamshire/AutomaticInventory/DepositRecord.java deleted file mode 100644 index a405073..0000000 --- a/src/me/ryanhamshire/AutomaticInventory/DepositRecord.java +++ /dev/null @@ -1,8 +0,0 @@ -package me.ryanhamshire.AutomaticInventory; - -class DepositRecord -{ - DepositRecord() {} - int totalItems = 0; - boolean destinationFull = false; -} From 80e6bb7b02106559cfa0c17965635e1224532f44 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:07:12 +0100 Subject: [PATCH 14/31] Delete DataStore.java --- .../AutomaticInventory/DataStore.java | 122 ------------------ 1 file changed, 122 deletions(-) delete mode 100644 src/me/ryanhamshire/AutomaticInventory/DataStore.java diff --git a/src/me/ryanhamshire/AutomaticInventory/DataStore.java b/src/me/ryanhamshire/AutomaticInventory/DataStore.java deleted file mode 100644 index 72dd22c..0000000 --- a/src/me/ryanhamshire/AutomaticInventory/DataStore.java +++ /dev/null @@ -1,122 +0,0 @@ -//Copyright 2015 Ryan Hamshire -package me.ryanhamshire.AutomaticInventory; - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; - -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; - -public class DataStore -{ - //in-memory cache for messages - private String [] messages; - - private final static String dataLayerFolderPath = "plugins" + File.separator + "AutomaticInventory"; - final static String playerDataFolderPath = dataLayerFolderPath + File.separator + "PlayerData"; - final static String messagesFilePath = dataLayerFolderPath + File.separator + "messages.yml"; - - public DataStore() - { - //ensure data folders exist - File playerDataFolder = new File(playerDataFolderPath); - if(!playerDataFolder.exists()) - { - playerDataFolder.mkdirs(); - } - - this.loadMessages(); - } - - private void loadMessages() - { - Messages [] messageIDs = Messages.values(); - this.messages = new String[Messages.values().length]; - - HashMap defaults = new HashMap(); - - //initialize defaults - //this.addDefault(defaults, Messages.NoManagedWorld, "The PopulationDensity plugin has not been properly configured. Please update your config.yml to specify a world to manage.", null); - this.addDefault(defaults, Messages.NoPermissionForFeature, "You don't have permission to use that feature.", null); - this.addDefault(defaults, Messages.ChestSortEnabled, "Now auto-sorting any chests you use.", null); - this.addDefault(defaults, Messages.ChestSortDisabled, "Stopped auto-sorting chests you use.", null); - this.addDefault(defaults, Messages.InventorySortEnabled, "Now auto-sorting your personal inventory.", null); - this.addDefault(defaults, Messages.InventorySortDisabled, "Stopped auto-sorting your personal inventory.", null); - this.addDefault(defaults, Messages.AutoSortHelp, "Options are /AutoSort Chests and /AutoSort Inventory.", null); - this.addDefault(defaults, Messages.AutoRefillEducation, "AutomaticInventory(AI) will auto-replace broken tools and depleted hotbar stacks from your inventory.", null); - this.addDefault(defaults, Messages.InventorySortEducation, "AutomaticInventory(AI) will keep your inventory sorted. Use /AutoSort to disable.", null); - this.addDefault(defaults, Messages.ChestSortEducation3, "AutomaticInventory(AI) will sort the contents of chests you access. Use /AutoSort to toggle. TIP: Want some chests sorted but not others? Chests with names including an asterisk (*) won't auto-sort. You can rename any chest using an anvil.", null); - this.addDefault(defaults, Messages.SuccessfulDeposit2, "Deposited {0} items.", null); - this.addDefault(defaults, Messages.FailedDepositNoMatch, "No items deposited - none of your inventory items match items in that chest.", null); - this.addDefault(defaults, Messages.QuickDepositAdvertisement3, "Want to deposit quickly from your hotbar? Just pick a specific chest and sneak (hold shift) while hitting it.", null); - this.addDefault(defaults, Messages.FailedDepositChestFull2, "That chest is full.", null); - this.addDefault(defaults, Messages.SuccessfulDepositAll2, "Deposited {0} items into nearby chests.", null); - this.addDefault(defaults, Messages.ChestLidBlocked, "That chest isn't accessible.", null); - this.addDefault(defaults, Messages.DepositAllAdvertisement, "TIP: Instantly deposit all items from your inventory into all the right nearby boxes with /DepositAll!", null); - - //load the config file - FileConfiguration config = YamlConfiguration.loadConfiguration(new File(messagesFilePath)); - FileConfiguration outConfig = new YamlConfiguration(); - - //for each message ID - for(int i = 0; i < messageIDs.length; i++) - { - //get default for this message - Messages messageID = messageIDs[i]; - CustomizableMessage messageData = defaults.get(messageID.name()); - - //if default is missing, log an error and use some fake data for now so that the plugin can run - if(messageData == null) - { - AutomaticInventory.AddLogEntry("Missing message for " + messageID.name() + ". Please contact the developer."); - messageData = new CustomizableMessage(messageID, "Missing message! ID: " + messageID.name() + ". Please contact a server admin.", null); - } - - //read the message from the file, use default if necessary - this.messages[messageID.ordinal()] = config.getString("Messages." + messageID.name() + ".Text", messageData.text); - outConfig.set("Messages." + messageID.name() + ".Text", this.messages[messageID.ordinal()]); - - //support formatting codes - this.messages[messageID.ordinal()] = this.messages[messageID.ordinal()].replace('&', (char)0x00A7); - - if(messageData.notes != null) - { - messageData.notes = config.getString("Messages." + messageID.name() + ".Notes", messageData.notes); - outConfig.set("Messages." + messageID.name() + ".Notes", messageData.notes); - } - } - - //save any changes - try - { - outConfig.options().header("Use a YAML editor like NotepadPlusPlus to edit this file. \nAfter editing, back up your changes before reloading the server in case you made a syntax error. \nUse ampersands (&) for formatting codes, which are documented here: http://minecraft.gamepedia.com/Formatting_codes"); - outConfig.save(DataStore.messagesFilePath); - } - catch(IOException exception) - { - AutomaticInventory.AddLogEntry("Unable to write to the configuration file at \"" + DataStore.messagesFilePath + "\""); - } - - defaults.clear(); - } - - private void addDefault(HashMap defaults, Messages id, String text, String notes) - { - CustomizableMessage message = new CustomizableMessage(id, text, notes); - defaults.put(id.name(), message); - } - - synchronized public String getMessage(Messages messageID, String... args) - { - String message = messages[messageID.ordinal()]; - - for(int i = 0; i < args.length; i++) - { - String param = args[i]; - message = message.replace("{" + i + "}", param); - } - - return message; - } -} From 9d8dd27d649d49359f12de326777dff1ba9c961b Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:07:48 +0100 Subject: [PATCH 15/31] Delete CustomizableMessage.java --- .../AutomaticInventory/CustomizableMessage.java | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 src/me/ryanhamshire/AutomaticInventory/CustomizableMessage.java diff --git a/src/me/ryanhamshire/AutomaticInventory/CustomizableMessage.java b/src/me/ryanhamshire/AutomaticInventory/CustomizableMessage.java deleted file mode 100644 index 4031f48..0000000 --- a/src/me/ryanhamshire/AutomaticInventory/CustomizableMessage.java +++ /dev/null @@ -1,17 +0,0 @@ -//Copyright 2015 Ryan Hamshire - -package me.ryanhamshire.AutomaticInventory; - -public class CustomizableMessage -{ - public Messages id; - public String text; - public String notes; - - public CustomizableMessage(Messages id, String text, String notes) - { - this.id = id; - this.text = text; - this.notes = notes; - } -} \ No newline at end of file From f0df35a8368f11318b537a0340a29ed20a5cbd99 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:07:55 +0100 Subject: [PATCH 16/31] Delete AutomaticInventory.java --- .../AutomaticInventory.java | 450 ------------------ 1 file changed, 450 deletions(-) delete mode 100644 src/me/ryanhamshire/AutomaticInventory/AutomaticInventory.java diff --git a/src/me/ryanhamshire/AutomaticInventory/AutomaticInventory.java b/src/me/ryanhamshire/AutomaticInventory/AutomaticInventory.java deleted file mode 100644 index 8c2fb6e..0000000 --- a/src/me/ryanhamshire/AutomaticInventory/AutomaticInventory.java +++ /dev/null @@ -1,450 +0,0 @@ -//Copyright 2015 Ryan Hamshire - -package me.ryanhamshire.AutomaticInventory; -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.logging.Logger; - -import org.bukkit.ChatColor; -import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; -import org.bukkit.event.block.Action; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.PlayerInventory; -import org.bukkit.plugin.PluginManager; -import org.bukkit.plugin.java.JavaPlugin; - -public class AutomaticInventory extends JavaPlugin -{ - //for convenience, a reference to the instance of this plugin - public static AutomaticInventory instance; - - //for logging to the console and log file - private static Logger log = Logger.getLogger("Minecraft"); - - Set config_noAutoRefillIDs = new HashSet(); - Set config_noAutoDepositIDs = new HashSet(); - - //this handles data storage, like player and region data - public DataStore dataStore; - - public synchronized static void AddLogEntry(String entry) - { - log.info("AutomaticInventory: " + entry); - } - - public void onEnable() - { - AddLogEntry("AutomaticInventory enabled."); - - instance = this; - - this.dataStore = new DataStore(); - - //read configuration settings (note defaults) - this.getDataFolder().mkdirs(); - File configFile = new File(this.getDataFolder().getPath() + File.separatorChar + "config.yml"); - FileConfiguration config = YamlConfiguration.loadConfiguration(configFile); - FileConfiguration outConfig = new YamlConfiguration(); - - List noAutoRefillIDs_string = config.getStringList("Auto Refill.Excluded Items"); - if(noAutoRefillIDs_string.size() == 0) - { - noAutoRefillIDs_string.add("0"); - noAutoRefillIDs_string.add("373"); - } - - for(String idString : noAutoRefillIDs_string) - { - try - { - int id = Integer.parseInt(idString); - this.config_noAutoRefillIDs.add(id); - } - catch(NumberFormatException e){ } - } - - outConfig.set("Auto Refill.Excluded Items", noAutoRefillIDs_string); - - List noAutoDepositIDs_string = config.getStringList("Auto Deposit.Excluded Items"); - if(noAutoDepositIDs_string.size() == 0) - { - noAutoDepositIDs_string.add("0"); - noAutoDepositIDs_string.add("262"); - noAutoDepositIDs_string.add("439"); - noAutoDepositIDs_string.add("440"); - } - - for(String idString : noAutoDepositIDs_string) - { - try - { - int id = Integer.parseInt(idString); - this.config_noAutoDepositIDs.add(id); - } - catch(NumberFormatException e){ } - } - - outConfig.set("Auto Deposit.Excluded Items", noAutoDepositIDs_string); - - try - { - outConfig.save(configFile); - } - catch(IOException e) - { - AddLogEntry("Encountered an issue while writing to the config file."); - e.printStackTrace(); - } - - //register for events - PluginManager pluginManager = this.getServer().getPluginManager(); - - AIEventHandler aIEventHandler = new AIEventHandler(); - pluginManager.registerEvents(aIEventHandler, this); - - @SuppressWarnings("unchecked") - Collection players = (Collection)this.getServer().getOnlinePlayers(); - for(Player player : players) - { - PlayerData.Preload(player); - } - } - - public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) - { - Player player = null; - PlayerData playerData = null; - if (sender instanceof Player) - { - player = (Player) sender; - playerData = PlayerData.FromPlayer(player); - } - - if(cmd.getName().equalsIgnoreCase("debugai") && player != null) - { - PlayerInventory inventory = player.getInventory(); - inventory.getItemInMainHand().setDurability(Short.MAX_VALUE); - /* - for(int i = 0; i < inventory.getSize(); i++) - { - ItemStack stack = inventory.getItem(i); - if(stack != null) - AutomaticInventory.AddLogEntry(String.valueOf(i) + " : " + stack.getType().name()); - }*/ - - return true; - } - - else if(cmd.getName().equalsIgnoreCase("autosort") && player != null) - { - if(args.length < 1) - { - sendMessage(player, TextMode.Instr, Messages.AutoSortHelp); - return true; - } - - String optionName = args[0].toLowerCase(); - if(optionName.startsWith("chest")) - { - if(!hasPermission(Features.SortChests, player)) - { - sendMessage(player, TextMode.Err, Messages.NoPermissionForFeature); - return true; - } - - playerData.setSortChests(!playerData.isSortChests()); - - if(playerData.isSortChests()) - sendMessage(player, TextMode.Success, Messages.ChestSortEnabled); - else - sendMessage(player, TextMode.Success, Messages.ChestSortDisabled); - } - else if(optionName.startsWith("inv")) - { - if(!hasPermission(Features.SortInventory, player)) - { - sendMessage(player, TextMode.Err, Messages.NoPermissionForFeature); - return true; - } - - playerData.setSortInventory(!playerData.isSortInventory()); - - if(playerData.isSortInventory()) - sendMessage(player, TextMode.Success, Messages.InventorySortEnabled); - else - sendMessage(player, TextMode.Success, Messages.InventorySortDisabled); - } - else - { - sendMessage(player, TextMode.Err, Messages.AutoSortHelp); - return true; - } - - DeliverTutorialHyperlink(player); - - return true; - } - - else if(cmd.getName().equalsIgnoreCase("depositall") && player != null) - { - //ensure player has feature enabled - if(!AIEventHandler.featureEnabled(Features.DepositAll, player)) - { - AutomaticInventory.sendMessage(player, TextMode.Err, Messages.NoPermissionForFeature); - return true; - } - - //gather snapshots of adjacent chunks - Location location = player.getLocation(); - Chunk centerChunk = location.getChunk(); - World world = location.getWorld(); - ChunkSnapshot [][] snapshots = new ChunkSnapshot[3][3]; - for(int x = -1; x <= 1; x++) - { - for(int z = -1; z <= 1; z++) - { - Chunk chunk = world.getChunkAt(centerChunk.getX() + x, centerChunk.getZ() + z); - snapshots[x + 1][z + 1] = chunk.getChunkSnapshot(); - } - } - - //create a thread to search those snapshots and create a chain of quick deposit attempts - int minY = Math.max(0, player.getEyeLocation().getBlockY() - 10); - int maxY = Math.min(world.getMaxHeight(), player.getEyeLocation().getBlockY() + 10); - int startY = player.getEyeLocation().getBlockY(); - int startX = player.getEyeLocation().getBlockX(); - int startZ = player.getEyeLocation().getBlockZ(); - Thread thread = new FindChestsThread(world, snapshots, minY, maxY, startX, startY, startZ, player); - thread.setPriority(Thread.MIN_PRIORITY); - thread.start(); - - playerData.setUsedDepositAll(true); - return true; - } - - return false; - } - - void DeliverTutorialHyperlink(Player player) - { - //todo: deliver tutorial link to player - } - - public void onDisable() - { - @SuppressWarnings("unchecked") - Collection players = (Collection)this.getServer().getOnlinePlayers(); - for(Player player : players) - { - PlayerData data = PlayerData.FromPlayer(player); - data.saveChanges(); - data.waitForSaveComplete(); - } - - AddLogEntry("AutomaticInventory disabled."); - } - - static boolean hasPermission(Features feature, Player player) - { - boolean hasPermission = false; - switch(feature) - { - case SortInventory: - hasPermission = player.hasPermission("automaticinventory.sortinventory"); - break; - case SortChests: - hasPermission = player.hasPermission("automaticinventory.sortchests"); - break; - case RefillStacks: - hasPermission = player.hasPermission("automaticinventory.refillstacks"); - break; - case QuickDeposit: - hasPermission = player.hasPermission("automaticinventory.quickdeposit"); - break; - case DepositAll: - hasPermission = player.hasPermission("automaticinventory.depositall"); - break; - } - - return hasPermission; - } - - @SuppressWarnings("unused") - private static void sendMessage(Player player, String message) - { - if(player != null) - { - player.sendMessage(message); - } - else - { - AutomaticInventory.AddLogEntry(message); - } - } - - static void sendMessage(Player player, ChatColor color, Messages messageID, String... args) - { - sendMessage(player, color, messageID, 0, args); - } - - static void sendMessage(Player player, ChatColor color, Messages messageID, long delayInTicks, String... args) - { - String message = AutomaticInventory.instance.dataStore.getMessage(messageID, args); - sendMessage(player, color, message, delayInTicks); - } - - static void sendMessage(Player player, ChatColor color, String message) - { - if(message == null || message.length() == 0) return; - - if(player == null) - { - AutomaticInventory.AddLogEntry(color + message); - } - else - { - player.sendMessage(color + message); - } - } - - static void sendMessage(Player player, ChatColor color, String message, long delayInTicks) - { - SendPlayerMessageTask task = new SendPlayerMessageTask(player, color, message); - if(delayInTicks > 0) - { - AutomaticInventory.instance.getServer().getScheduler().runTaskLater(AutomaticInventory.instance, task, delayInTicks); - } - else - { - task.run(); - } - } - - @SuppressWarnings("deprecation") - static DepositRecord depositMatching(PlayerInventory source, Inventory destination, boolean depositHotbar) - { - HashSet eligibleSignatures = new HashSet(); - DepositRecord deposits = new DepositRecord(); - for(int i = 0; i < destination.getSize(); i++) - { - ItemStack destinationStack = destination.getItem(i); - if(destinationStack == null) continue; - - String signature = getSignature(destinationStack); - eligibleSignatures.add(signature); - } - int sourceStartIndex = depositHotbar ? 0 : 9; - int sourceSize = Math.min(source.getSize(), 36); - for(int i = sourceStartIndex; i < sourceSize; i++) - { - ItemStack sourceStack = source.getItem(i); - if(sourceStack == null) continue; - - if(AutomaticInventory.instance.config_noAutoDepositIDs.contains(sourceStack.getTypeId())) continue; - - String signature = getSignature(sourceStack); - int sourceStackSize = sourceStack.getAmount(); - if(eligibleSignatures.contains(signature)) - { - HashMap notMoved = destination.addItem(sourceStack); - if(notMoved.isEmpty()) - { - source.clear(i); - deposits.totalItems += sourceStackSize; - } - else - { - int notMovedCount = notMoved.values().iterator().next().getAmount(); - int movedCount = sourceStackSize - notMovedCount; - if(movedCount == 0) - { - eligibleSignatures.remove(signature); - } - else - { - int newAmount = sourceStackSize - movedCount; - sourceStack.setAmount(newAmount); - deposits.totalItems += movedCount; - } - } - } - } - - if(destination.firstEmpty() == -1) - { - deposits.destinationFull = true; - } - - return deposits; - } - - @SuppressWarnings("deprecation") - private static String getSignature(ItemStack stack) - { - int sourceID = stack.getTypeId(); - String signature = String.valueOf(sourceID); - boolean dataValueMatters = stack.getMaxStackSize() > 1; - if(dataValueMatters) - { - signature += "." + String.valueOf(stack.getData().getData()); - } - - return signature; - } - - public class FakePlayerInteractEvent extends PlayerInteractEvent - { - public FakePlayerInteractEvent(Player player, Action rightClickBlock, ItemStack itemInHand, Block clickedBlock, BlockFace blockFace) - { - super(player, rightClickBlock, itemInHand, clickedBlock, blockFace); - } - } - - static boolean preventsChestOpen(int aboveBlockID) - { - switch(aboveBlockID) - { - case 0: //air - case 54: //chest - case 146: //trapped chest - case 154: //hopper - case 68: //wall sign - case 389: //item frame - case 44: //slabs - case 126: //more slabs - case 53: //so many stairs... - case 67: - case 108: - case 109: - case 114: - case 128: - case 134: - case 135: - case 136: - case 156: - case 163: - case 164: - case 180: - return false; - default: - return true; - } - } -} \ No newline at end of file From 6343871e01b7463f5cc3ea30f9dcc964c76f7393 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:08:04 +0100 Subject: [PATCH 17/31] Delete AIEventHandler.java --- .../AutomaticInventory/AIEventHandler.java | 531 ------------------ 1 file changed, 531 deletions(-) delete mode 100644 src/me/ryanhamshire/AutomaticInventory/AIEventHandler.java diff --git a/src/me/ryanhamshire/AutomaticInventory/AIEventHandler.java b/src/me/ryanhamshire/AutomaticInventory/AIEventHandler.java deleted file mode 100644 index bd8a9c6..0000000 --- a/src/me/ryanhamshire/AutomaticInventory/AIEventHandler.java +++ /dev/null @@ -1,531 +0,0 @@ -//Copyright 2015 Ryan Hamshire - -package me.ryanhamshire.AutomaticInventory; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; - -import org.bukkit.Bukkit; -import org.bukkit.GameMode; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.Chest; -import org.bukkit.block.DoubleChest; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.HumanEntity; -import org.bukkit.entity.Player; -import org.bukkit.entity.minecart.StorageMinecart; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.block.BlockDamageEvent; -import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.entity.ProjectileLaunchEvent; -import org.bukkit.event.inventory.InventoryCloseEvent; -import org.bukkit.event.inventory.InventoryOpenEvent; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerItemBreakEvent; -import org.bukkit.event.player.PlayerItemConsumeEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerPickupItemEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.inventory.EquipmentSlot; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.InventoryHolder; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.PlayerInventory; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.projectiles.ProjectileSource; - -public class AIEventHandler implements Listener -{ - private EquipmentSlot getSlotWithItemStack(PlayerInventory inventory, ItemStack brokenItem) - { - if(itemsAreSimilar(inventory.getItemInMainHand(), brokenItem, false)) - { - return EquipmentSlot.HAND; - } - if(itemsAreSimilar(inventory.getItemInOffHand(), brokenItem, false)) - { - return EquipmentSlot.OFF_HAND; - } - - return null; - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - public void onToolBreak(PlayerItemBreakEvent event) - { - Player player = event.getPlayer(); - PlayerInventory inventory = player.getInventory(); - EquipmentSlot slot = this.getSlotWithItemStack(inventory, event.getBrokenItem()); - - tryRefillStackInHand(player, slot, false); - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - public void onBlockPlace(BlockPlaceEvent event) - { - Player player = event.getPlayer(); - tryRefillStackInHand(player, event.getHand(), true); - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - public void onConsumeItem(PlayerItemConsumeEvent event) - { - Player player = event.getPlayer(); - PlayerInventory inventory = player.getInventory(); - EquipmentSlot slot = this.getSlotWithItemStack(inventory, event.getItem()); - tryRefillStackInHand(player, slot, true); - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - public void onProjectileLaunch(ProjectileLaunchEvent event) - { - ProjectileSource source = event.getEntity().getShooter(); - if(source == null || !(source instanceof Player)) return; - - Player player = (Player)source; - tryRefillStackInHand(player, EquipmentSlot.HAND, false); - } - - @SuppressWarnings("deprecation") - private void tryRefillStackInHand(Player player, EquipmentSlot slot, boolean dataValueMatters) - { - if(slot == null) return; - - if(!featureEnabled(Features.RefillStacks, player)) return; - - ItemStack stack = null; - int slotIndex = 0; - if(slot == EquipmentSlot.HAND) - { - stack = player.getInventory().getItemInMainHand(); - slotIndex = player.getInventory().getHeldItemSlot(); - } - else if(slot == EquipmentSlot.OFF_HAND) - { - stack = player.getInventory().getItemInOffHand(); - slotIndex = 40; - } - else - { - return; - } - - if(AutomaticInventory.instance.config_noAutoRefillIDs.contains(stack.getTypeId())) return; - if(!dataValueMatters || stack.getAmount() == 1) - { - PlayerInventory inventory = player.getInventory(); - AutomaticInventory.instance.getServer().getScheduler().scheduleSyncDelayedTask( - AutomaticInventory.instance, - new AutoRefillHotBarTask(player, inventory, slotIndex, stack.clone(), dataValueMatters), - 2L); - } - } - - static boolean featureEnabled(Features feature, Player player) - { - if(!AutomaticInventory.hasPermission(feature, player)) return false; - - PlayerData data = PlayerData.FromPlayer(player); - - switch(feature) - { - case SortInventory: - if(data.isSortInventory()) return true; - break; - case SortChests: - if(data.isSortChests()) return true; - break; - case RefillStacks: - return true; - case QuickDeposit: - return true; - case DepositAll: - return true; - } - - return false; - } - - @SuppressWarnings("deprecation") - private static boolean itemsAreSimilar(ItemStack a, ItemStack b, boolean dataValueMatters) - { - if(a.getType() == b.getType() && (!dataValueMatters || a.getData().getData() == b.getData().getData())) - { - if(a.containsEnchantment(Enchantment.LOOT_BONUS_BLOCKS) || a.containsEnchantment(Enchantment.SILK_TOUCH) || a.containsEnchantment(Enchantment.LOOT_BONUS_MOBS)) return false; - - if(a.hasItemMeta() != b.hasItemMeta()) return false; - - //compare metadata - if(a.hasItemMeta()) - { - if(!b.hasItemMeta()) return false; - - ItemMeta meta1 = a.getItemMeta(); - ItemMeta meta2 = b.getItemMeta(); - - //compare names - if(meta1.hasDisplayName()) - { - if(!meta2.hasDisplayName()) return false; - - return meta1.getDisplayName().equals(meta2.getDisplayName()); - } - } - - return true; - } - - return false; - } - - class AutoRefillHotBarTask implements Runnable - { - private Player player; - private PlayerInventory targetInventory; - private int slotToRefill; - private ItemStack stackToReplace; - private boolean dataValueMatters; - - public AutoRefillHotBarTask(Player player, PlayerInventory targetInventory, int slotToRefill, ItemStack stackToReplace, boolean dataValueMatters) - { - this.player = player; - this.targetInventory = targetInventory; - this.slotToRefill = slotToRefill; - this.stackToReplace = stackToReplace; - this.dataValueMatters = dataValueMatters; - } - - @Override - public void run() - { - ItemStack currentStack = this.targetInventory.getItem(this.slotToRefill); - if(currentStack != null) return; - - ItemStack bestMatchStack = null; - int bestMatchSlot = -1; - int bestMatchStackSize = Integer.MAX_VALUE; - for(int i = 0; i < 36; i++) - { - ItemStack itemInSlot = this.targetInventory.getItem(i); - if(itemInSlot == null) continue; - if(itemsAreSimilar(itemInSlot, this.stackToReplace, dataValueMatters)) - { - int stackSize = itemInSlot.getAmount(); - if(stackSize < bestMatchStackSize) - { - bestMatchStack = itemInSlot; - bestMatchSlot = i; - bestMatchStackSize = stackSize; - } - - if(bestMatchStackSize == 1) break; - } - } - - if(bestMatchStack == null) return; - - this.targetInventory.setItem(this.slotToRefill, bestMatchStack); - this.targetInventory.clear(bestMatchSlot); - - PlayerData playerData = PlayerData.FromPlayer(player); - if(!playerData.isGotRestackInfo()) - { - AutomaticInventory.sendMessage(player, TextMode.Info, Messages.AutoRefillEducation); - playerData.setGotRestackInfo(true); - } - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - public void onBlockDamage(BlockDamageEvent event) - { - Player player = event.getPlayer(); - if(!player.isSneaking()) return; - - if(!featureEnabled(Features.QuickDeposit, player)) return; - - Block clickedBlock = event.getBlock(); - if(clickedBlock == null) return; - Material clickedMaterial = clickedBlock.getType(); - - if(clickedMaterial != Material.CHEST && clickedMaterial != Material.TRAPPED_CHEST) return; - - @SuppressWarnings("deprecation") - PlayerInteractEvent fakeEvent = AutomaticInventory.instance.new FakePlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, player.getItemInHand(), clickedBlock, BlockFace.EAST); - Bukkit.getServer().getPluginManager().callEvent(fakeEvent); - if(fakeEvent.isCancelled()) return; - - InventoryHolder chest = (InventoryHolder)clickedBlock.getState(); - Inventory chestInventory = chest.getInventory(); - PlayerInventory playerInventory = player.getInventory(); - - event.setCancelled(true); - - @SuppressWarnings("deprecation") - int aboveBlockID = clickedBlock.getRelative(BlockFace.UP).getTypeId(); - if(AutomaticInventory.preventsChestOpen(aboveBlockID)) - { - AutomaticInventory.sendMessage(player, TextMode.Err, Messages.ChestLidBlocked); - return; - } - - DepositRecord deposits = AutomaticInventory.depositMatching(playerInventory, chestInventory, true); - - //send confirmation message to player with counts deposited. if none deposited, give instructions on how to set up the chest. - if(deposits.destinationFull && deposits.totalItems == 0) - { - AutomaticInventory.sendMessage(player, TextMode.Err, Messages.FailedDepositChestFull2); - } - else if(deposits.totalItems == 0) - { - AutomaticInventory.sendMessage(player, TextMode.Info, Messages.FailedDepositNoMatch); - } - else - { - AutomaticInventory.sendMessage(player, TextMode.Success, Messages.SuccessfulDeposit2, String.valueOf(deposits.totalItems)); - - //make a note that quick deposit was used so that player will not be bothered with advertisement messages again. - PlayerData playerData = PlayerData.FromPlayer(player); - if(!playerData.isUsedQuickDeposit()) - { - playerData.setUsedQuickDeposit(true); - } - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - public void onInventoryOpen(InventoryOpenEvent event) - { - Inventory bottomInventory = event.getView().getBottomInventory(); - if(bottomInventory == null) return; - if(bottomInventory.getType() != InventoryType.PLAYER) return; - - HumanEntity holder = ((PlayerInventory)bottomInventory).getHolder(); - if(!(holder instanceof Player)) return; - - Player player = (Player)holder; - PlayerData playerData = PlayerData.FromPlayer(player); - sortPlayerIfEnabled(player, playerData, bottomInventory); - - if(!player.isSneaking() && featureEnabled(Features.SortChests, player)) - { - Inventory topInventory = event.getView().getTopInventory(); - if(!isSortableChestInventory(topInventory)) return; - - InventorySorter sorter = new InventorySorter(topInventory, 0); - Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(AutomaticInventory.instance, sorter, 1L); - - if(!playerData.isGotChestSortInfo()) - { - AutomaticInventory.sendMessage(player, TextMode.Info, Messages.ChestSortEducation3); - playerData.setGotChestSortInfo(true); - } - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - public void onInventoryClose(InventoryCloseEvent event) - { - Inventory bottomInventory = event.getView().getBottomInventory(); - if(bottomInventory == null) return; - if(bottomInventory.getType() != InventoryType.PLAYER) return; - - HumanEntity holder = ((PlayerInventory)bottomInventory).getHolder(); - if(!(holder instanceof Player)) return; - - Player player = (Player)holder; - PlayerData playerData = PlayerData.FromPlayer(player); - - sortPlayerIfEnabled(player, playerData, bottomInventory); - - if(player.getGameMode() != GameMode.CREATIVE && Math.random() < .1 && !playerData.isGotDepositAllInfo() && featureEnabled(Features.DepositAll, player)) - { - Inventory topInventory = event.getView().getTopInventory(); - if(topInventory != null && topInventory.getType() == InventoryType.CHEST) - { - AutomaticInventory.sendMessage(player, TextMode.Instr, Messages.DepositAllAdvertisement); - playerData.setGotDepositAllInfo(true); - } - } - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - public void onPickupItem(PlayerPickupItemEvent event) - { - Player player = event.getPlayer(); - if(featureEnabled(Features.SortInventory, player)) - { - PlayerData playerData = PlayerData.FromPlayer(player); - if(playerData.firstEmptySlot >= 0) return; - - PlayerInventory inventory = player.getInventory(); - int firstEmpty = inventory.firstEmpty(); - if(firstEmpty < 9) return; - playerData.firstEmptySlot = firstEmpty; - PickupSortTask task = new PickupSortTask(player, playerData, inventory); - Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(AutomaticInventory.instance, task, 100L); - } - } - - static void sortPlayerIfEnabled(Player player, PlayerData playerData, Inventory inventory) - { - if(featureEnabled(Features.SortInventory, player)) - { - new InventorySorter(inventory, 9).run(); - - if(!playerData.isGotInventorySortInfo()) - { - AutomaticInventory.sendMessage(player, TextMode.Info, Messages.InventorySortEducation); - playerData.setGotInventorySortInfo(true); - } - } - } - - static boolean isSortableChestInventory(Inventory inventory) - { - if(inventory == null) return false; - - InventoryType inventoryType = inventory.getType(); - if(inventoryType != InventoryType.CHEST && inventoryType != InventoryType.ENDER_CHEST) return false; - - String name = inventory.getName(); - if(name != null && name.contains("*")) return false; - - InventoryHolder holder = inventory.getHolder(); - if(holder == null || !(holder instanceof Chest || holder instanceof DoubleChest || holder instanceof StorageMinecart)) return false; - - return true; - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - void onPlayerJoin(PlayerJoinEvent event) - { - Player player = event.getPlayer(); - PlayerData.Preload(player); - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - void onPlayerQuit(PlayerQuitEvent event) - { - Player player = event.getPlayer(); - PlayerData.FromPlayer(player).saveChanges(); - } -} - -class PickupSortTask implements Runnable -{ - private Player player; - private PlayerData playerData; - private Inventory playerInventory; - - PickupSortTask(Player player, PlayerData playerData, Inventory playerInventory) - { - this.player = player; - this.playerData = playerData; - this.playerInventory = playerInventory; - } - - @Override - public void run() - { - if(this.playerData.firstEmptySlot == playerInventory.firstEmpty()) - { - this.playerData.firstEmptySlot = -1; - return; - } - - AIEventHandler.sortPlayerIfEnabled(this.player, this.playerData, this.playerInventory); - - this.playerData.firstEmptySlot = -1; - } -} - -class InventorySorter implements Runnable -{ - private Inventory inventory; - private int startIndex; - - InventorySorter(Inventory inventory, int startIndex) - { - this.inventory = inventory; - this.startIndex = startIndex; - } - - @Override - public void run() - { - ArrayList stacks = new ArrayList(); - ItemStack [] contents = this.inventory.getContents(); - int inventorySize = contents.length; - if(this.inventory.getType() == InventoryType.PLAYER) inventorySize = Math.min(contents.length, 36); - for(int i = this.startIndex; i < inventorySize; i++) - { - ItemStack stack = contents[i]; - if(stack != null) - { - stacks.add(stack); - } - } - - Collections.sort(stacks, new StackComparator()); - for(int i = 1; i < stacks.size(); i++) - { - ItemStack prevStack = stacks.get(i - 1); - ItemStack thisStack = stacks.get(i); - if(prevStack.isSimilar(thisStack)) - { - if(prevStack.getAmount() < prevStack.getMaxStackSize()) - { - int moveCount = Math.min(prevStack.getMaxStackSize() - prevStack.getAmount(), thisStack.getAmount()); - prevStack.setAmount(prevStack.getAmount() + moveCount); - thisStack.setAmount(thisStack.getAmount() - moveCount); - if(thisStack.getAmount() == 0) - { - stacks.remove(i); - i--; - }; - } - } - } - - int i; - for(i = 0; i < stacks.size(); i++) - { - this.inventory.setItem(i + this.startIndex, stacks.get(i)); - } - - for(i = i + this.startIndex; i < inventorySize; i++) - { - this.inventory.clear(i); - } - } - - private class StackComparator implements Comparator - { - @SuppressWarnings("deprecation") - @Override - public int compare(ItemStack a, ItemStack b) - { - int result = new Integer(b.getMaxStackSize()).compareTo(a.getMaxStackSize()); - if(result != 0) return result; - - result = new Integer(b.getTypeId()).compareTo(a.getTypeId()); - if(result != 0) return result; - - result = new Byte(b.getData().getData()).compareTo(a.getData().getData()); - if(result != 0) return result; - - result = new Integer(b.getAmount()).compareTo(a.getAmount()); - return result; - } - } -} - - From 270f37f18b30be10bb5fefa9835dcd3f5a824d82 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:10:25 +0100 Subject: [PATCH 18/31] Create plugin.yml --- src/plugin.yml | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/plugin.yml diff --git a/src/plugin.yml b/src/plugin.yml new file mode 100644 index 0000000..86e02b7 --- /dev/null +++ b/src/plugin.yml @@ -0,0 +1,51 @@ +main: me.ryanhamshire.automaticinventory.AutomaticInventory +name: AutomaticInventory +version: 2.7.2 Fork +commands: + debugai: + description: The debug command for AutomaticInventory + usage: /debugai + permission: automaticinventory.debug + autosort: + description: Toggles auto-sorting options. + usage: /autosort + depositall: + description: Deposits your non-hotbar inventory into any nearby chests containing matching items. + usage: /depositall + aliases: [da, dumpitems, dumploot, depositloot] + permission: automaticinventory.depositall +permissions: + automaticinventory.admin.*: + description: Grants all administrative privileges. + children: + automaticinventory.debugai: true + automaticinventory.user.*: + description: Grants all user privileges. + children: + automaticinventory.sortinventory: true + automaticinventory.sortchests: true + automaticinventory.refillstacks: true + automaticinventory.quickdeposit: true + automaticinventory.depositall: true + automaticinventory.debugai: + description: Grants permission to use /DebugAI. + default: op + automaticinventory.sortinventory: + description: Grants permission to auto-sort personal inventory. + default: true + automaticinventory.sortchests: + description: Grants permission to auto-sort chest content. + default: true + automaticinventory.refillstacks: + description: Grants permission to auto-refill depleted hotbar stacks. + default: true + automaticinventory.quickdeposit: + description: Grants permission to auto-deposit matching items into a chest with shift-right-click. + default: true + automaticinventory.depositall: + description: Grants permission to use /DepositAll. + default: true +load: STARTUP +authors: [ryanhamshire,crazyhoorse961] +website: https://github.com/crazyhorse961/AutomaticInventory +database: false From 2861f5f73f7a63d583e90902c98b7073ac9c5cc0 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:11:36 +0100 Subject: [PATCH 19/31] Create TextMode --- src/me/ryanhamshire/automaticinventory/TextMode | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/me/ryanhamshire/automaticinventory/TextMode diff --git a/src/me/ryanhamshire/automaticinventory/TextMode b/src/me/ryanhamshire/automaticinventory/TextMode new file mode 100644 index 0000000..e2e102a --- /dev/null +++ b/src/me/ryanhamshire/automaticinventory/TextMode @@ -0,0 +1,15 @@ +//Copyright 2015 Ryan Hamshire + +package me.ryanhamshire.automaticinventory; + +import org.bukkit.ChatColor; + +//just a few constants for chat color codes +public class TextMode +{ + public final static ChatColor INFO = ChatColor.AQUA; + public final static ChatColor INSTR = ChatColor.YELLOW; + public final static ChatColor WARN = ChatColor.GOLD; + public final static ChatColor ERR = ChatColor.RED; + public final static ChatColor SUCCESS = ChatColor.GREEN; +} From 5db065412d8294bd25379e73364eacda06271493 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:12:28 +0100 Subject: [PATCH 20/31] Create SendPlayerMessageTask --- .../automaticinventory/SendPlayerMessageTask | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/me/ryanhamshire/automaticinventory/SendPlayerMessageTask diff --git a/src/me/ryanhamshire/automaticinventory/SendPlayerMessageTask b/src/me/ryanhamshire/automaticinventory/SendPlayerMessageTask new file mode 100644 index 0000000..8c15432 --- /dev/null +++ b/src/me/ryanhamshire/automaticinventory/SendPlayerMessageTask @@ -0,0 +1,34 @@ +//Copyright 2015 Ryan Hamshire + +package me.ryanhamshire.automaticinventory; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +//sends a message to a player +//used to send delayed messages, for example help text triggered by a player's chat +public class SendPlayerMessageTask implements Runnable +{ + private Player player; + private ChatColor color; + private String message; + + public SendPlayerMessageTask(Player player, ChatColor color, String message) + { + this.player = player; + this.color = color; + this.message = message; + } + + @Override + public void run() + { + if(player == null) + { + AutomaticInventory.addLogEntry(color + message); + return; + } + + AutomaticInventory.getInstance().sendMessage(this.player, this.color, this.message); + } +} From c89c7511c124f3b6331b69e0eb609c0cc5338519 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:12:48 +0100 Subject: [PATCH 21/31] Create PlayerData --- .../automaticinventory/PlayerData | 302 ++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 src/me/ryanhamshire/automaticinventory/PlayerData diff --git a/src/me/ryanhamshire/automaticinventory/PlayerData b/src/me/ryanhamshire/automaticinventory/PlayerData new file mode 100644 index 0000000..99ef0a2 --- /dev/null +++ b/src/me/ryanhamshire/automaticinventory/PlayerData @@ -0,0 +1,302 @@ +//Copyright 2015 Ryan Hamshire + +package me.ryanhamshire.automaticinventory; + +import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.List; +import java.util.UUID; + +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.metadata.MetadataValue; + +public class PlayerData +{ + private final static String METADATA_TAG = "AI_PlayerData"; + private Thread loadingThread; + private Thread savingThread; + private String playerName; + private boolean gotChestSortInfo = false; + private boolean gotInventorySortInfo = false; + private boolean gotRestackInfo = false; + private boolean usedQuickDeposit = false; + private int manualDepositsThisSession = 0; + private boolean gotQuickDepositInfo = false; + private boolean gotDepositAllInfo = false; + private boolean usedDepositAll = false; + private UUID playerID; + private boolean isDirty = false; + private boolean sortChests = true; + public int firstEmptySlot = -1; + private boolean sortInventory = true; + + + public boolean isUsedQuickDeposit() + { + return usedQuickDeposit; + } + + public void setUsedQuickDeposit(boolean usedQuickDeposit) + { + this.usedQuickDeposit = usedQuickDeposit; + this.isDirty = true; + } + + public boolean isUsedDepositAll() + { + return usedDepositAll; + } + + public void setUsedDepositAll(boolean usedDepositAll) + { + this.usedDepositAll = usedDepositAll; + this.isDirty = true; + } + + public boolean isGotChestSortInfo() + { + return gotChestSortInfo; + } + + public void setGotChestSortInfo(boolean gotChestSortInfo) + { + this.gotChestSortInfo = gotChestSortInfo; + this.isDirty = true; + } + + public boolean isGotInventorySortInfo() + { + return gotInventorySortInfo; + } + + public void setGotInventorySortInfo(boolean gotInventorySortInfo) + { + this.gotInventorySortInfo = gotInventorySortInfo; + this.isDirty = true; + } + + public boolean isGotRestackInfo() + { + return gotRestackInfo; + } + + public void setGotRestackInfo(boolean gotRestackInfo) + { + this.gotRestackInfo = gotRestackInfo; + this.isDirty = true; + } + + public static void Preload(Player player) + { + new PlayerData(player); + } + + public static PlayerData FromPlayer(Player player) + { + List data = player.getMetadata(METADATA_TAG); + if(data == null || data.isEmpty()) + { + return new PlayerData(player); + } + else + { + PlayerData playerData = (PlayerData)(data.get(0).value()); + return playerData; + } + } + + private PlayerData(Player player) + { + this.playerName = player.getName(); + this.playerID = player.getUniqueId(); + this.loadingThread = new Thread(new DataLoader()); + this.loadingThread.start(); + player.setMetadata(METADATA_TAG, new FixedMetadataValue(AutomaticInventory.getInstance(), this)); + } + + public boolean isSortChests() + { + this.waitForLoadComplete(); + return sortChests; + } + public void setSortChests(boolean sortChests) + { + this.isDirty = true; + this.sortChests = sortChests; + } + public boolean isSortInventory() + { + this.waitForLoadComplete(); + return sortInventory; + } + public void setSortInventory(boolean sortInventory) + { + this.isDirty = true; + this.sortInventory = sortInventory; + } + + public void incrementManualDeposits() + { + this.manualDepositsThisSession++; + } + + public int getManualDeposits() + { + return this.manualDepositsThisSession; + } + + public boolean isGotQuickDepositInfo() + { + return gotQuickDepositInfo; + } + + public void setGotQuickDepositInfo(boolean newValue) + { + this.gotQuickDepositInfo = newValue; + } + + public void saveChanges() + { + if(!this.isDirty){ return; } + + this.waitForLoadComplete(); + this.savingThread = new Thread(new DataSaver()); + this.savingThread.start(); + } + + private void waitForLoadComplete() + { + if(this.loadingThread != null) + { + try + { + this.loadingThread.join(); + } + catch(InterruptedException e){} + this.loadingThread = null; + } + } + + public void waitForSaveComplete() + { + if(this.savingThread != null) + { + try + { + this.savingThread.join(); + } + catch(InterruptedException e){} + } + } + + private void writeDataToFile() + { + try + { + FileConfiguration config = new YamlConfiguration(); + config.set("Player Name", this.playerName); + config.set("Sort Chests", this.sortChests); + config.set("Sort Personal Inventory", this.sortInventory); + config.set("Used Quick Deposit", this.usedQuickDeposit); + config.set("Received Messages.Personal Inventory", this.gotInventorySortInfo); + config.set("Received Messages.Chest Inventory", this.gotChestSortInfo); + config.set("Received Messages.Restacker", this.gotRestackInfo); + config.set("Received Messages.Deposit All", this.gotDepositAllInfo); + File playerFile = new File(DataStore.playerDataFolderPath + File.separator + this.playerID.toString()); + config.save(playerFile); + } + catch(Exception e) + { + StringWriter errors = new StringWriter(); + e.printStackTrace(new PrintWriter(errors)); + AutomaticInventory.addLogEntry("Failed to save player data for " + playerID + " " + errors.toString()); + } + + this.savingThread = null; + this.isDirty = false; + } + + private void readDataFromFile() + { + File playerFile = new File(DataStore.playerDataFolderPath + File.separator + this.playerID.toString()); + + //if it exists as a file, read the file + if(playerFile.exists()) + { + boolean needRetry = false; + int retriesRemaining = 5; + Exception latestException = null; + do + { + try + { + needRetry = false; + FileConfiguration config = YamlConfiguration.loadConfiguration(playerFile); + this.sortChests = config.getBoolean("Sort Chests", true); + this.sortInventory = config.getBoolean("Sort Personal Inventory", true); + this.usedQuickDeposit = config.getBoolean("Used Quick Deposit", false); + this.gotChestSortInfo = config.getBoolean("Received Messages.Chest Inventory", false); + this.gotInventorySortInfo = config.getBoolean("Received Messages.Personal Inventory", false); + this.gotRestackInfo = config.getBoolean("Received Messages.Restacker", false); + this.gotDepositAllInfo = config.getBoolean("Received Messages.Deposit All", false); + } + + //if there's any problem with the file's content, retry up to 5 times with 5 milliseconds between + catch(Exception e) + { + latestException = e; + needRetry = true; + retriesRemaining--; + } + + try + { + if(needRetry) Thread.sleep(5); + } + catch(InterruptedException exception) {} + + }while(needRetry && retriesRemaining >= 0); + + //if last attempt failed, log information about the problem + if(needRetry) + { + StringWriter errors = new StringWriter(); + latestException.printStackTrace(new PrintWriter(errors)); + AutomaticInventory.addLogEntry("Failed to load data for " + playerID + " " + errors.toString()); + } + } + } + + private class DataSaver implements Runnable + { + @Override + public void run() + { + writeDataToFile(); + } + } + + private class DataLoader implements Runnable + { + @Override + public void run() + { + readDataFromFile(); + } + } + + public boolean isGotDepositAllInfo() + { + return this.gotDepositAllInfo; + } + + public void setGotDepositAllInfo(boolean status) + { + this.gotDepositAllInfo = status; + this.isDirty = true; + } +} From ffaff5f806f1ade56a5b2f08e42c7f25c3ad31c2 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:13:06 +0100 Subject: [PATCH 22/31] Create Messages --- .../ryanhamshire/automaticinventory/Messages | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/me/ryanhamshire/automaticinventory/Messages diff --git a/src/me/ryanhamshire/automaticinventory/Messages b/src/me/ryanhamshire/automaticinventory/Messages new file mode 100644 index 0000000..dff61dc --- /dev/null +++ b/src/me/ryanhamshire/automaticinventory/Messages @@ -0,0 +1,23 @@ +//Copyright 2015 Ryan Hamshire + +package me.ryanhamshire.automaticinventory; + +public enum Messages +{ + AUTOSORTHELP, + NOPERMISSIONFORFEATURE, + CHESTSORTENABLED, + CHESTSORTDISABLED, + INVENTORYSORTENABLED, + INVENTORYSORTDISABLED, + AUTOREFILLEDUCATION, + INVENTORYSORTEDUCATION, + CHESTSORTEDUCATION3, + SUCCESSFULDEPOSIT2, + FAILEDDEPOSITNOMATCH, + FAILEDDEPOSITCHESTFULL2, + SUCCESSFULDEPOSITALL2, + CHESTLIDBLOCKED, + DEPOSITALLADVERTISEMENT, + QUICKDEPOSITADVERTISEMENT3 +} From 9bfc6f3ce94febcfde89673633c39fdd6984f628 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:13:27 +0100 Subject: [PATCH 23/31] Create FindChestsThread --- .../automaticinventory/FindChestsThread | 223 ++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 src/me/ryanhamshire/automaticinventory/FindChestsThread diff --git a/src/me/ryanhamshire/automaticinventory/FindChestsThread b/src/me/ryanhamshire/automaticinventory/FindChestsThread new file mode 100644 index 0000000..b4bad89 --- /dev/null +++ b/src/me/ryanhamshire/automaticinventory/FindChestsThread @@ -0,0 +1,223 @@ +package me.ryanhamshire.automaticinventory; + +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +import org.bukkit.Bukkit; +import org.bukkit.ChunkSnapshot; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.entity.Player; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.util.Vector; + +public class FindChestsThread extends Thread +{ + private World world; + private ChunkSnapshot[][] snapshots; + private int minY; + private int maxY; + private int startX; + private int startY; + private int startZ; + private Player player; + private ChunkSnapshot smallestChunk; + + private boolean [][][] seen; + + public FindChestsThread(World world, ChunkSnapshot[][] snapshots, int minY, int maxY, int startX, int startY, int startZ, Player player) + { + this.world = world; + this.snapshots = snapshots; + this.minY = minY; + this.maxY = maxY; + this.smallestChunk = this.snapshots[0][0]; + this.startX = startX - this.smallestChunk.getX() * 16; + this.startY = startY; + this.startZ = startZ - this.smallestChunk.getZ() * 16; + if(this.maxY >= world.getMaxHeight()) this.maxY = world.getMaxHeight() - 1; + this.player = player; + this.seen = new boolean[48][this.maxY - this.minY + 1][48]; + } + + @Override + public void run() + { + Queue chestLocations = new ConcurrentLinkedQueue(); + Queue leftToVisit = new ConcurrentLinkedQueue(); + Vector start = new Vector(this.startX, this.startY, this.startZ); + leftToVisit.add(start); + this.markSeen(start); + while(!leftToVisit.isEmpty()) + { + Vector current = leftToVisit.remove(); + + int typeID = this.getTypeID(current); + if(isChestID(typeID)) + { + int overTypeID = this.getTypeID(new Vector(current.getBlockX(), current.getBlockY() + 1, current.getBlockZ())); + if(!AutomaticInventory.getInstance().preventsChestOpen(overTypeID)) + { + chestLocations.add(this.makeLocation(current)); + } + } + + if(this.isPassableID(typeID)) + { + Vector [] adjacents = new Vector [] { + new Vector(current.getBlockX() + 1, current.getBlockY(), current.getBlockZ()), + new Vector(current.getBlockX() - 1, current.getBlockY(), current.getBlockZ()), + new Vector(current.getBlockX(), current.getBlockY() + 1, current.getBlockZ()), + new Vector(current.getBlockX(), current.getBlockY() - 1, current.getBlockZ()), + new Vector(current.getBlockX(), current.getBlockY(), current.getBlockZ() + 1), + new Vector(current.getBlockX(), current.getBlockY(), current.getBlockZ() - 1), + }; + + for(Vector adjacent : adjacents) + { + if(!this.alreadySeen(adjacent)) + { + leftToVisit.add(adjacent); + this.markSeen(adjacent); + } + } + } + } + + QuickDepositChain chain = new QuickDepositChain(chestLocations, new DepositRecord(), player, true); + Bukkit.getScheduler().runTaskLater(AutomaticInventory.getInstance(), chain, 1L); + } + + private Location makeLocation(Vector location) + { + return new Location( + this.world, + this.smallestChunk.getX() * 16 + location.getBlockX(), + location.getBlockY(), + this.smallestChunk.getZ() * 16 + location.getBlockZ()); + } + + @SuppressWarnings("deprecation") + private int getTypeID(Vector location) + { + if(this.outOfBounds(location)) return -1; + int chunkx = location.getBlockX() / 16; + int chunkz = location.getBlockZ() / 16; + ChunkSnapshot chunk = this.snapshots[chunkx][chunkz]; + int x = location.getBlockX() % 16; + int z = location.getBlockZ() % 16; + return chunk.getBlockTypeId(x, location.getBlockY(), z); + } + + private boolean alreadySeen(Vector location) + { + if(this.outOfBounds(location)) return true; + int y = location.getBlockY() - this.minY; + return this.seen[location.getBlockX()][y][location.getBlockZ()]; + } + + private void markSeen(Vector location) + { + if(this.outOfBounds(location)) return; + int y = location.getBlockY() - this.minY; + this.seen[location.getBlockX()][y][location.getBlockZ()] = true; + } + + private boolean outOfBounds(Vector location) + { + if(location.getBlockY() > this.maxY) return true; + if(location.getBlockY() < this.minY) return true; + if(location.getBlockX() >= 48) return true; + if(location.getBlockX() < 0) return true; + if(location.getBlockZ() >= 48) return true; + if(location.getBlockZ() < 0) return true; + return false; + } + + private boolean isChestID(int id) + { + return (id == 54 || id == 146); + } + + private boolean isPassableID(int id) + { + switch(id) + { + case 0: //air + case 54: //chest + case 146: //trapped chest + case 154: //hopper + case 68: //wall sign + case 389: //item frame + return true; + default: + return false; + } + } + + class QuickDepositChain implements Runnable + { + private Queue remainingChestLocations; + private DepositRecord runningDepositRecord; + private Player player; + private boolean respectExclusions; + + QuickDepositChain(Queue remainingChestLocations, DepositRecord runningDepositRecord, Player player, boolean respectExclusions) + { + super(); + this.remainingChestLocations = remainingChestLocations; + this.runningDepositRecord = runningDepositRecord; + this.player = player; + this.respectExclusions = respectExclusions; + } + + @Override + public void run() + { + Location chestLocation = this.remainingChestLocations.poll(); + if(chestLocation == null) + { + AutomaticInventory.getInstance().sendMessage(this.player, TextMode.SUCCESS, Messages.SUCCESSFULDEPOSITALL2, String.valueOf(this.runningDepositRecord.totalItems)); + PlayerData playerData = PlayerData.FromPlayer(player); + if(Math.random() < .1 && !playerData.isGotQuickDepositInfo() && AIEventHandler.featureEnabled(Features.QUICKDEPOSIT, player)) + { + AutomaticInventory.getInstance().sendMessage(player, TextMode.INSTR, Messages.QUICKDEPOSITADVERTISEMENT3); + playerData.setGotQuickDepositInfo(true); + } + } + else + { + Block block = chestLocation.getBlock(); + PlayerInteractEvent fakeEvent = AutomaticInventory.getInstance().new FakePlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, player.getInventory().getItemInMainHand(), block, BlockFace.UP); + Bukkit.getServer().getPluginManager().callEvent(fakeEvent); + if(!fakeEvent.isCancelled()) + { + BlockState state = block.getState(); + if(state instanceof InventoryHolder) + { + InventoryHolder chest = (InventoryHolder)state; + Inventory chestInventory = chest.getInventory(); + if(!this.respectExclusions || AIEventHandler.isSortableChestInventory(chestInventory)) + { + PlayerInventory playerInventory = player.getInventory(); + + DepositRecord deposits = AutomaticInventory.depositMatching(playerInventory, chestInventory, false); + + this.runningDepositRecord.totalItems += deposits.totalItems; + } + } + } + + QuickDepositChain chain = new QuickDepositChain(this.remainingChestLocations, this.runningDepositRecord, this.player, this.respectExclusions); + Bukkit.getScheduler().runTaskLater(AutomaticInventory.getInstance(), chain, 1L); + } + } + } +} From 5b58603761794d3f34f1dc412538c4eb9bdb4301 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:13:48 +0100 Subject: [PATCH 24/31] Create Features --- src/me/ryanhamshire/automaticinventory/Features | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/me/ryanhamshire/automaticinventory/Features diff --git a/src/me/ryanhamshire/automaticinventory/Features b/src/me/ryanhamshire/automaticinventory/Features new file mode 100644 index 0000000..38dbe68 --- /dev/null +++ b/src/me/ryanhamshire/automaticinventory/Features @@ -0,0 +1,10 @@ +package me.ryanhamshire.automaticinventory; + +public enum Features +{ + REFILLSTACKS, + SORTINVENTORY, + SORTCHESTS, + QUICKDEPOSIT, + DEPOSITALL +} From 5c926e90ce34de795e674e064dc9d3e26fe564de Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:14:20 +0100 Subject: [PATCH 25/31] Create DepositRecord --- src/me/ryanhamshire/automaticinventory/DepositRecord | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/me/ryanhamshire/automaticinventory/DepositRecord diff --git a/src/me/ryanhamshire/automaticinventory/DepositRecord b/src/me/ryanhamshire/automaticinventory/DepositRecord new file mode 100644 index 0000000..009c055 --- /dev/null +++ b/src/me/ryanhamshire/automaticinventory/DepositRecord @@ -0,0 +1,8 @@ +package me.ryanhamshire.automaticinventory; + +public class DepositRecord +{ + DepositRecord() {} + int totalItems = 0; + boolean destinationFull = false; +} From 0fab365c7f6fb3bf8421fc8843fe1b3fba609ed0 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:14:41 +0100 Subject: [PATCH 26/31] Create DataStore --- .../ryanhamshire/automaticinventory/DataStore | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 src/me/ryanhamshire/automaticinventory/DataStore diff --git a/src/me/ryanhamshire/automaticinventory/DataStore b/src/me/ryanhamshire/automaticinventory/DataStore new file mode 100644 index 0000000..4b4d1cd --- /dev/null +++ b/src/me/ryanhamshire/automaticinventory/DataStore @@ -0,0 +1,122 @@ +//Copyright 2015 Ryan Hamshire +package me.ryanhamshire.automaticinventory; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; + +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; + +public class DataStore +{ + //in-memory cache for messages + private String [] messages; + + private final static String dataLayerFolderPath = "plugins" + File.separator + "AutomaticInventory"; + final static String playerDataFolderPath = dataLayerFolderPath + File.separator + "PlayerData"; + final static String messagesFilePath = dataLayerFolderPath + File.separator + "messages.yml"; + + public DataStore() + { + //ensure data folders exist + File playerDataFolder = new File(playerDataFolderPath); + if(!playerDataFolder.exists()) + { + playerDataFolder.mkdirs(); + } + + this.loadMessages(); + } + + private void loadMessages() + { + Messages [] messageIDs = Messages.values(); + this.messages = new String[Messages.values().length]; + + HashMap defaults = new HashMap(); + + //initialize defaults + //this.addDefault(defaults, Messages.NoManagedWorld, "The PopulationDensity plugin has not been properly configured. Please update your config.yml to specify a world to manage.", null); + this.addDefault(defaults, Messages.NOPERMISSIONFORFEATURE, "You don't have permission to use that feature.", null); + this.addDefault(defaults, Messages.CHESTSORTENABLED, "Now auto-sorting any chests you use.", null); + this.addDefault(defaults, Messages.CHESTSORTDISABLED, "Stopped auto-sorting chests you use.", null); + this.addDefault(defaults, Messages.INVENTORYSORTENABLED, "Now auto-sorting your personal inventory.", null); + this.addDefault(defaults, Messages.INVENTORYSORTDISABLED, "Stopped auto-sorting your personal inventory.", null); + this.addDefault(defaults, Messages.AUTOSORTHELP, "Options are /AutoSort Chests and /AutoSort Inventory.", null); + this.addDefault(defaults, Messages.AUTOREFILLEDUCATION, "AutomaticInventory(AI) will auto-replace broken tools and depleted hotbar stacks from your inventory.", null); + this.addDefault(defaults, Messages.INVENTORYSORTEDUCATION, "AutomaticInventory(AI) will keep your inventory sorted. Use /AutoSort to disable.", null); + this.addDefault(defaults, Messages.CHESTSORTEDUCATION3, "AutomaticInventory(AI) will sort the contents of chests you access. Use /AutoSort to toggle. TIP: Want some chests sorted but not others? Chests with names including an asterisk (*) won't auto-sort. You can rename any chest using an anvil.", null); + this.addDefault(defaults, Messages.SUCCESSFULDEPOSIT2, "Deposited {0} items.", null); + this.addDefault(defaults, Messages.FAILEDDEPOSITNOMATCH, "No items deposited - none of your inventory items match items in that chest.", null); + this.addDefault(defaults, Messages.QUICKDEPOSITADVERTISEMENT3, "Want to deposit quickly from your hotbar? Just pick a specific chest and sneak (hold shift) while hitting it.", null); + this.addDefault(defaults, Messages.FAILEDDEPOSITCHESTFULL2, "That chest is full.", null); + this.addDefault(defaults, Messages.SUCCESSFULDEPOSITALL2, "Deposited {0} items into nearby chests.", null); + this.addDefault(defaults, Messages.CHESTLIDBLOCKED, "That chest isn't accessible.", null); + this.addDefault(defaults, Messages.DEPOSITALLADVERTISEMENT, "TIP: Instantly deposit all items from your inventory into all the right nearby boxes with /DepositAll!", null); + + //load the config file + FileConfiguration config = YamlConfiguration.loadConfiguration(new File(messagesFilePath)); + FileConfiguration outConfig = new YamlConfiguration(); + + //for each message ID + for(int i = 0; i < messageIDs.length; i++) + { + //get default for this message + Messages messageID = messageIDs[i]; + CustomizableMessage messageData = defaults.get(messageID.name()); + + //if default is missing, log an error and use some fake data for now so that the plugin can run + if(messageData == null) + { + AutomaticInventory.addLogEntry("Missing message for " + messageID.name() + ". Please contact the developer."); + messageData = new CustomizableMessage(messageID, "Missing message! ID: " + messageID.name() + ". Please contact a server admin.", null); + } + + //read the message from the file, use default if necessary + this.messages[messageID.ordinal()] = config.getString("Messages." + messageID.name() + ".Text", messageData.text); + outConfig.set("Messages." + messageID.name() + ".Text", this.messages[messageID.ordinal()]); + + //support formatting codes + this.messages[messageID.ordinal()] = this.messages[messageID.ordinal()].replace('&', (char)0x00A7); + + if(messageData.notes != null) + { + messageData.notes = config.getString("Messages." + messageID.name() + ".Notes", messageData.notes); + outConfig.set("Messages." + messageID.name() + ".Notes", messageData.notes); + } + } + + //save any changes + try + { + outConfig.options().header("Use a YAML editor like NotepadPlusPlus to edit this file. \nAfter editing, back up your changes before reloading the server in case you made a syntax error. \nUse ampersands (&) for formatting codes, which are documented here: http://minecraft.gamepedia.com/Formatting_codes"); + outConfig.save(DataStore.messagesFilePath); + } + catch(IOException exception) + { + AutomaticInventory.addLogEntry("Unable to write to the configuration file at \"" + DataStore.messagesFilePath + "\""); + } + + defaults.clear(); + } + + private void addDefault(HashMap defaults, Messages id, String text, String notes) + { + CustomizableMessage message = new CustomizableMessage(id, text, notes); + defaults.put(id.name(), message); + } + + synchronized public String getMessage(Messages messageID, String... args) + { + String message = messages[messageID.ordinal()]; + + for(int i = 0; i < args.length; i++) + { + String param = args[i]; + message = message.replace("{" + i + "}", param); + } + + return message; + } +} From 779f28c23a81af55e26dce3f9770040e052df655 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:15:04 +0100 Subject: [PATCH 27/31] Create CustomizableMessage --- .../automaticinventory/CustomizableMessage | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/me/ryanhamshire/automaticinventory/CustomizableMessage diff --git a/src/me/ryanhamshire/automaticinventory/CustomizableMessage b/src/me/ryanhamshire/automaticinventory/CustomizableMessage new file mode 100644 index 0000000..bb4d991 --- /dev/null +++ b/src/me/ryanhamshire/automaticinventory/CustomizableMessage @@ -0,0 +1,17 @@ +//Copyright 2015 Ryan Hamshire + +package me.ryanhamshire.automaticinventory; + +public class CustomizableMessage +{ + public Messages id; + public String text; + public String notes; + + public CustomizableMessage(Messages id, String text, String notes) + { + this.id = id; + this.text = text; + this.notes = notes; + } +} From 0455b2d0f01bedc69ddc65805cb1f57fbe4b9729 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:15:23 +0100 Subject: [PATCH 28/31] Create AutomaticInventory --- .../automaticinventory/AutomaticInventory | 453 ++++++++++++++++++ 1 file changed, 453 insertions(+) create mode 100644 src/me/ryanhamshire/automaticinventory/AutomaticInventory diff --git a/src/me/ryanhamshire/automaticinventory/AutomaticInventory b/src/me/ryanhamshire/automaticinventory/AutomaticInventory new file mode 100644 index 0000000..72501b6 --- /dev/null +++ b/src/me/ryanhamshire/automaticinventory/AutomaticInventory @@ -0,0 +1,453 @@ +//Copyright 2015 Ryan Hamshire + +package me.ryanhamshire.automaticinventory; +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Logger; + +import org.bukkit.ChatColor; +import org.bukkit.Chunk; +import org.bukkit.ChunkSnapshot; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; + +public class AutomaticInventory extends JavaPlugin +{ + //for convenience, a reference to the instance of this plugin + private static AutomaticInventory instance; + + //for logging to the console and log file + private static Logger log = Logger.getLogger("Minecraft"); + + Set config_noAutoRefillIDs = new HashSet(); + Set config_noAutoDepositIDs = new HashSet(); + + //this handles data storage, like player and region data + public DataStore dataStore; + + public synchronized static void addLogEntry(String entry) + { + log.info("AutomaticInventory: " + entry); + } + + public void onEnable() + { + addLogEntry("AutomaticInventory enabled."); + + instance = this; + + this.dataStore = new DataStore(); + + //read configuration settings (note defaults) + this.getDataFolder().mkdirs(); + File configFile = new File(this.getDataFolder().getPath() + File.separatorChar + "config.yml"); + FileConfiguration config = YamlConfiguration.loadConfiguration(configFile); + FileConfiguration outConfig = new YamlConfiguration(); + + List noAutoRefillIDs_string = config.getStringList("Auto Refill.Excluded Items"); + if(noAutoRefillIDs_string.size() == 0) + { + noAutoRefillIDs_string.add("0"); + noAutoRefillIDs_string.add("373"); + } + + for(String idString : noAutoRefillIDs_string) + { + try + { + int id = Integer.parseInt(idString); + this.config_noAutoRefillIDs.add(id); + } + catch(NumberFormatException e){ } + } + + outConfig.set("Auto Refill.Excluded Items", noAutoRefillIDs_string); + + List noAutoDepositIDs_string = config.getStringList("Auto Deposit.Excluded Items"); + if(noAutoDepositIDs_string.size() == 0) + { + noAutoDepositIDs_string.add("0"); + noAutoDepositIDs_string.add("262"); + noAutoDepositIDs_string.add("439"); + noAutoDepositIDs_string.add("440"); + } + + for(String idString : noAutoDepositIDs_string) + { + try + { + int id = Integer.parseInt(idString); + this.config_noAutoDepositIDs.add(id); + } + catch(NumberFormatException e){ } + } + + outConfig.set("Auto Deposit.Excluded Items", noAutoDepositIDs_string); + + try + { + outConfig.save(configFile); + } + catch(IOException e) + { + addLogEntry("Encountered an issue while writing to the config file."); + e.printStackTrace(); + } + + //register for events + PluginManager pluginManager = this.getServer().getPluginManager(); + + AIEventHandler aIEventHandler = new AIEventHandler(); + pluginManager.registerEvents(aIEventHandler, this); + + @SuppressWarnings("unchecked") + Collection players = (Collection)this.getServer().getOnlinePlayers(); + for(Player player : players) + { + PlayerData.Preload(player); + } + } + + public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) + { + Player player = null; + PlayerData playerData = null; + if (sender instanceof Player) + { + player = (Player) sender; + playerData = PlayerData.FromPlayer(player); + } + + if(cmd.getName().equalsIgnoreCase("debugai") && player != null) + { + PlayerInventory inventory = player.getInventory(); + inventory.getItemInMainHand().setDurability(Short.MAX_VALUE); + /* + for(int i = 0; i < inventory.getSize(); i++) + { + ItemStack stack = inventory.getItem(i); + if(stack != null) + AutomaticInventory.AddLogEntry(String.valueOf(i) + " : " + stack.getType().name()); + }*/ + + return true; + } + + else if(cmd.getName().equalsIgnoreCase("autosort") && player != null) + { + if(args.length < 1) + { + sendMessage(player, TextMode.INSTR, Messages.AUTOSORTHELP); + return true; + } + + String optionName = args[0].toLowerCase(); + if(optionName.startsWith("chest")) + { + if(!hasPermission(Features.SORTCHESTS, player)) + { + sendMessage(player, TextMode.ERR, Messages.NOPERMISSIONFORFEATURE); + return true; + } + + playerData.setSortChests(!playerData.isSortChests()); + + if(playerData.isSortChests()) + sendMessage(player, TextMode.SUCCESS, Messages.CHESTSORTENABLED); + else + sendMessage(player, TextMode.SUCCESS, Messages.CHESTSORTDISABLED); + } + else if(optionName.startsWith("inv")) + { + if(!hasPermission(Features.SORTINVENTORY, player)) + { + sendMessage(player, TextMode.ERR, Messages.NOPERMISSIONFORFEATURE); + return true; + } + + playerData.setSortInventory(!playerData.isSortInventory()); + + if(playerData.isSortInventory()) + sendMessage(player, TextMode.SUCCESS, Messages.INVENTORYSORTENABLED); + else + sendMessage(player, TextMode.SUCCESS, Messages.INVENTORYSORTDISABLED); + } + else + { + sendMessage(player, TextMode.ERR, Messages.AUTOSORTHELP); + return true; + } + + DeliverTutorialHyperlink(player); + + return true; + } + + else if(cmd.getName().equalsIgnoreCase("depositall") && player != null) + { + //ensure player has feature enabled + if(!AIEventHandler.featureEnabled(Features.DEPOSITALL, player)) + { + AutomaticInventory.getInstance().sendMessage(player, TextMode.ERR, Messages.NOPERMISSIONFORFEATURE); + return true; + } + + //gather snapshots of adjacent chunks + Location location = player.getLocation(); + Chunk centerChunk = location.getChunk(); + World world = location.getWorld(); + ChunkSnapshot [][] snapshots = new ChunkSnapshot[3][3]; + for(int x = -1; x <= 1; x++) + { + for(int z = -1; z <= 1; z++) + { + Chunk chunk = world.getChunkAt(centerChunk.getX() + x, centerChunk.getZ() + z); + snapshots[x + 1][z + 1] = chunk.getChunkSnapshot(); + } + } + + //create a thread to search those snapshots and create a chain of quick deposit attempts + int minY = Math.max(0, player.getEyeLocation().getBlockY() - 10); + int maxY = Math.min(world.getMaxHeight(), player.getEyeLocation().getBlockY() + 10); + int startY = player.getEyeLocation().getBlockY(); + int startX = player.getEyeLocation().getBlockX(); + int startZ = player.getEyeLocation().getBlockZ(); + Thread thread = new FindChestsThread(world, snapshots, minY, maxY, startX, startY, startZ, player); + thread.setPriority(Thread.MIN_PRIORITY); + thread.start(); + + playerData.setUsedDepositAll(true); + return true; + } + + return false; + } + + void DeliverTutorialHyperlink(Player player) + { + //todo: deliver tutorial link to player + } + + public void onDisable() + { + @SuppressWarnings("unchecked") + Collection players = (Collection)this.getServer().getOnlinePlayers(); + for(Player player : players) + { + PlayerData data = PlayerData.FromPlayer(player); + data.saveChanges(); + data.waitForSaveComplete(); + } + + addLogEntry("AutomaticInventory disabled."); + } + + static boolean hasPermission(Features feature, Player player) + { + boolean hasPermission = false; + switch(feature) + { + case SORTINVENTORY: + hasPermission = player.hasPermission("automaticinventory.sortinventory"); + break; + case SORTCHESTS: + hasPermission = player.hasPermission("automaticinventory.sortchests"); + break; + case REFILLSTACKS: + hasPermission = player.hasPermission("automaticinventory.refillstacks"); + break; + case QUICKDEPOSIT: + hasPermission = player.hasPermission("automaticinventory.quickdeposit"); + break; + case DEPOSITALL: + hasPermission = player.hasPermission("automaticinventory.depositall"); + break; + } + + return hasPermission; + } + + @SuppressWarnings("unused") + private void sendMessage(Player player, String message) + { + if(player != null) + { + player.sendMessage(message); + } + else + { + AutomaticInventory.addLogEntry(message); + } + } + + public void sendMessage(Player player, ChatColor color, Messages messageID, String... args) + { + sendMessage(player, color, messageID, 0, args); + } + + public void sendMessage(Player player, ChatColor color, Messages messageID, long delayInTicks, String... args) + { + String message = AutomaticInventory.instance.dataStore.getMessage(messageID, args); + sendMessage(player, color, message, delayInTicks); + } + + public void sendMessage(Player player, ChatColor color, String message) + { + if(message == null || message.length() == 0) return; + + if(player == null) + { + AutomaticInventory.addLogEntry(color + message); + } + else + { + player.sendMessage(color + message); + } + } + + public void sendMessage(Player player, ChatColor color, String message, long delayInTicks) + { + SendPlayerMessageTask task = new SendPlayerMessageTask(player, color, message); + if(delayInTicks > 0) + { + AutomaticInventory.instance.getServer().getScheduler().runTaskLater(AutomaticInventory.instance, task, delayInTicks); + } + else + { + task.run(); + } + } + + @SuppressWarnings("deprecation") + public static DepositRecord depositMatching(PlayerInventory source, Inventory destination, boolean depositHotbar) + { + HashSet eligibleSignatures = new HashSet(); + DepositRecord deposits = new DepositRecord(); + for(int i = 0; i < destination.getSize(); i++) + { + ItemStack destinationStack = destination.getItem(i); + if(destinationStack == null) continue; + + String signature = getSignature(destinationStack); + eligibleSignatures.add(signature); + } + int sourceStartIndex = depositHotbar ? 0 : 9; + int sourceSize = Math.min(source.getSize(), 36); + for(int i = sourceStartIndex; i < sourceSize; i++) + { + ItemStack sourceStack = source.getItem(i); + if(sourceStack == null) continue; + + if(AutomaticInventory.instance.config_noAutoDepositIDs.contains(sourceStack.getTypeId())) continue; + + String signature = getSignature(sourceStack); + int sourceStackSize = sourceStack.getAmount(); + if(eligibleSignatures.contains(signature)) + { + HashMap notMoved = destination.addItem(sourceStack); + if(notMoved.isEmpty()) + { + source.clear(i); + deposits.totalItems += sourceStackSize; + } + else + { + int notMovedCount = notMoved.values().iterator().next().getAmount(); + int movedCount = sourceStackSize - notMovedCount; + if(movedCount == 0) + { + eligibleSignatures.remove(signature); + } + else + { + int newAmount = sourceStackSize - movedCount; + sourceStack.setAmount(newAmount); + deposits.totalItems += movedCount; + } + } + } + } + + if(destination.firstEmpty() == -1) + { + deposits.destinationFull = true; + } + + return deposits; + } + + @SuppressWarnings("deprecation") + private static String getSignature(ItemStack stack) + { + int sourceID = stack.getTypeId(); + String signature = String.valueOf(sourceID); + boolean dataValueMatters = stack.getMaxStackSize() > 1; + if(dataValueMatters) + { + signature += "." + String.valueOf(stack.getData().getData()); + } + + return signature; + } + + public class FakePlayerInteractEvent extends PlayerInteractEvent + { + public FakePlayerInteractEvent(Player player, Action rightClickBlock, ItemStack itemInHand, Block clickedBlock, BlockFace blockFace) + { + super(player, rightClickBlock, itemInHand, clickedBlock, blockFace); + } + } + + public boolean preventsChestOpen(int aboveBlockID) + { + switch(aboveBlockID) + { + case 0: //air + case 54: //chest + case 146: //trapped chest + case 154: //hopper + case 68: //wall sign + case 389: //item frame + case 44: //slabs + case 126: //more slabs + case 53: //so many stairs... + case 67: + case 108: + case 109: + case 114: + case 128: + case 134: + case 135: + case 136: + case 156: + case 163: + case 164: + case 180: + return false; + default: + return true; + } + } + public static AutomaticInventory getInstance() { + return instance; + } +} From aa8ffa8c1cef4bea5a111bf68fb1b81e7cdc91bf Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Thu, 8 Dec 2016 13:15:40 +0100 Subject: [PATCH 29/31] Create AIEventHandler --- .../automaticinventory/AIEventHandler | 532 ++++++++++++++++++ 1 file changed, 532 insertions(+) create mode 100644 src/me/ryanhamshire/automaticinventory/AIEventHandler diff --git a/src/me/ryanhamshire/automaticinventory/AIEventHandler b/src/me/ryanhamshire/automaticinventory/AIEventHandler new file mode 100644 index 0000000..cf69c0a --- /dev/null +++ b/src/me/ryanhamshire/automaticinventory/AIEventHandler @@ -0,0 +1,532 @@ +//Copyright 2015 Ryan Hamshire + +package me.ryanhamshire.automaticinventory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.Chest; +import org.bukkit.block.DoubleChest; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.minecart.StorageMinecart; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockDamageEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.ProjectileLaunchEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.inventory.InventoryOpenEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerItemBreakEvent; +import org.bukkit.event.player.PlayerItemConsumeEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.projectiles.ProjectileSource; + +public class AIEventHandler implements Listener +{ + private EquipmentSlot getSlotWithItemStack(PlayerInventory inventory, ItemStack brokenItem) + { + if(itemsAreSimilar(inventory.getItemInMainHand(), brokenItem, false)) + { + return EquipmentSlot.HAND; + } + if(itemsAreSimilar(inventory.getItemInOffHand(), brokenItem, false)) + { + return EquipmentSlot.OFF_HAND; + } + + return null; + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onToolBreak(PlayerItemBreakEvent event) + { + Player player = event.getPlayer(); + PlayerInventory inventory = player.getInventory(); + EquipmentSlot slot = this.getSlotWithItemStack(inventory, event.getBrokenItem()); + + tryRefillStackInHand(player, slot, false); + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onBlockPlace(BlockPlaceEvent event) + { + Player player = event.getPlayer(); + tryRefillStackInHand(player, event.getHand(), true); + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onConsumeItem(PlayerItemConsumeEvent event) + { + Player player = event.getPlayer(); + PlayerInventory inventory = player.getInventory(); + EquipmentSlot slot = this.getSlotWithItemStack(inventory, event.getItem()); + tryRefillStackInHand(player, slot, true); + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onProjectileLaunch(ProjectileLaunchEvent event) + { + ProjectileSource source = event.getEntity().getShooter(); + if(source == null || !(source instanceof Player)) return; + + Player player = (Player)source; + tryRefillStackInHand(player, EquipmentSlot.HAND, false); + } + + @SuppressWarnings("deprecation") + private void tryRefillStackInHand(Player player, EquipmentSlot slot, boolean dataValueMatters) + { + if(slot == null) return; + + if(!featureEnabled(Features.REFILLSTACKS, player)) return; + + ItemStack stack = null; + int slotIndex = 0; + if(slot == EquipmentSlot.HAND) + { + stack = player.getInventory().getItemInMainHand(); + slotIndex = player.getInventory().getHeldItemSlot(); + } + else if(slot == EquipmentSlot.OFF_HAND) + { + stack = player.getInventory().getItemInOffHand(); + slotIndex = 40; + } + else + { + return; + } + + if(AutomaticInventory.getInstance().config_noAutoRefillIDs.contains(stack.getTypeId())) return; + if(!dataValueMatters || stack.getAmount() == 1) + { + PlayerInventory inventory = player.getInventory(); + AutomaticInventory.getInstance().getServer().getScheduler().scheduleSyncDelayedTask( + AutomaticInventory.getInstance(), + new AutoRefillHotBarTask(player, inventory, slotIndex, stack.clone(), dataValueMatters), + 2L); + } + } + + public static boolean featureEnabled(Features feature, Player player) + { + if(!AutomaticInventory.hasPermission(feature, player)) return false; + + PlayerData data = PlayerData.FromPlayer(player); + + switch(feature) + { + case SORTINVENTORY: + if(data.isSortInventory()) return true; + break; + case SORTCHESTS: + if(data.isSortChests()) return true; + break; + case REFILLSTACKS: + return true; + case QUICKDEPOSIT: + return true; + case DEPOSITALL: + return true; + } + + return false; + } + + @SuppressWarnings("deprecation") + private boolean itemsAreSimilar(ItemStack a, ItemStack b, boolean dataValueMatters) + { + if(a.getType() == b.getType() && (!dataValueMatters || a.getData().getData() == b.getData().getData())) + { + if(a.containsEnchantment(Enchantment.LOOT_BONUS_BLOCKS) || a.containsEnchantment(Enchantment.SILK_TOUCH) || a.containsEnchantment(Enchantment.LOOT_BONUS_MOBS)) return false; + + if(a.hasItemMeta() != b.hasItemMeta()) return false; + + //compare metadata + if(a.hasItemMeta()) + { + if(!b.hasItemMeta()) return false; + + ItemMeta meta1 = a.getItemMeta(); + ItemMeta meta2 = b.getItemMeta(); + + //compare names + if(meta1.hasDisplayName()) + { + if(!meta2.hasDisplayName()) return false; + + return meta1.getDisplayName().equals(meta2.getDisplayName()); + } + } + + return true; + } + + return false; + } + + class AutoRefillHotBarTask implements Runnable + { + private Player player; + private PlayerInventory targetInventory; + private int slotToRefill; + private ItemStack stackToReplace; + private boolean dataValueMatters; + + public AutoRefillHotBarTask(Player player, PlayerInventory targetInventory, int slotToRefill, ItemStack stackToReplace, boolean dataValueMatters) + { + this.player = player; + this.targetInventory = targetInventory; + this.slotToRefill = slotToRefill; + this.stackToReplace = stackToReplace; + this.dataValueMatters = dataValueMatters; + } + + @Override + public void run() + { + ItemStack currentStack = this.targetInventory.getItem(this.slotToRefill); + if(currentStack != null) return; + + ItemStack bestMatchStack = null; + int bestMatchSlot = -1; + int bestMatchStackSize = Integer.MAX_VALUE; + for(int i = 0; i < 36; i++) + { + ItemStack itemInSlot = this.targetInventory.getItem(i); + if(itemInSlot == null) continue; + if(itemsAreSimilar(itemInSlot, this.stackToReplace, dataValueMatters)) + { + int stackSize = itemInSlot.getAmount(); + if(stackSize < bestMatchStackSize) + { + bestMatchStack = itemInSlot; + bestMatchSlot = i; + bestMatchStackSize = stackSize; + } + + if(bestMatchStackSize == 1) break; + } + } + + if(bestMatchStack == null) return; + + this.targetInventory.setItem(this.slotToRefill, bestMatchStack); + this.targetInventory.clear(bestMatchSlot); + + PlayerData playerData = PlayerData.FromPlayer(player); + if(!playerData.isGotRestackInfo()) + { + AutomaticInventory.getInstance().sendMessage(player, TextMode.INFO, Messages.AUTOREFILLEDUCATION); + playerData.setGotRestackInfo(true); + } + } + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onBlockDamage(BlockDamageEvent event) + { + Player player = event.getPlayer(); + if(!player.isSneaking()) return; + + if(!featureEnabled(Features.QUICKDEPOSIT, player)) return; + + Block clickedBlock = event.getBlock(); + if(clickedBlock == null) return; + Material clickedMaterial = clickedBlock.getType(); + + if(clickedMaterial != Material.CHEST && clickedMaterial != Material.TRAPPED_CHEST) return; + + @SuppressWarnings("deprecation") + PlayerInteractEvent fakeEvent = AutomaticInventory.getInstance().new FakePlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, player.getItemInHand(), clickedBlock, BlockFace.EAST); + Bukkit.getServer().getPluginManager().callEvent(fakeEvent); + if(fakeEvent.isCancelled()) + { return; } + + InventoryHolder chest = (InventoryHolder)clickedBlock.getState(); + Inventory chestInventory = chest.getInventory(); + PlayerInventory playerInventory = player.getInventory(); + + event.setCancelled(true); + + @SuppressWarnings("deprecation") + int aboveBlockID = clickedBlock.getRelative(BlockFace.UP).getTypeId(); + if(AutomaticInventory.getInstance().preventsChestOpen(aboveBlockID)) + { + AutomaticInventory.getInstance().sendMessage(player, TextMode.ERR, Messages.CHESTLIDBLOCKED); + return; + } + + DepositRecord deposits = AutomaticInventory.depositMatching(playerInventory, chestInventory, true); + + //send confirmation message to player with counts deposited. if none deposited, give instructions on how to set up the chest. + if(deposits.destinationFull && deposits.totalItems == 0) + { + AutomaticInventory.getInstance().sendMessage(player, TextMode.ERR, Messages.FAILEDDEPOSITCHESTFULL2); + } + else if(deposits.totalItems == 0) + { + AutomaticInventory.getInstance().sendMessage(player, TextMode.INFO, Messages.FAILEDDEPOSITNOMATCH); + } + else + { + AutomaticInventory.getInstance().sendMessage(player, TextMode.SUCCESS, Messages.SUCCESSFULDEPOSIT2, String.valueOf(deposits.totalItems)); + + //make a note that quick deposit was used so that player will not be bothered with advertisement messages again. + PlayerData playerData = PlayerData.FromPlayer(player); + if(!playerData.isUsedQuickDeposit()) + { + playerData.setUsedQuickDeposit(true); + } + } + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onInventoryOpen(InventoryOpenEvent event) + { + Inventory bottomInventory = event.getView().getBottomInventory(); + if(bottomInventory == null) return; + if(bottomInventory.getType() != InventoryType.PLAYER) return; + + HumanEntity holder = ((PlayerInventory)bottomInventory).getHolder(); + if(!(holder instanceof Player)) return; + + Player player = (Player)holder; + PlayerData playerData = PlayerData.FromPlayer(player); + sortPlayerIfEnabled(player, playerData, bottomInventory); + + if(!player.isSneaking() && featureEnabled(Features.SORTCHESTS, player)) + { + Inventory topInventory = event.getView().getTopInventory(); + if(!isSortableChestInventory(topInventory)) return; + + InventorySorter sorter = new InventorySorter(topInventory, 0); + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(AutomaticInventory.getInstance(), sorter, 1L); + + if(!playerData.isGotChestSortInfo()) + { + AutomaticInventory.getInstance().sendMessage(player, TextMode.INFO, Messages.CHESTSORTEDUCATION3); + playerData.setGotChestSortInfo(true); + } + } + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onInventoryClose(InventoryCloseEvent event) + { + Inventory bottomInventory = event.getView().getBottomInventory(); + if(bottomInventory == null) return; + if(bottomInventory.getType() != InventoryType.PLAYER) return; + + HumanEntity holder = ((PlayerInventory)bottomInventory).getHolder(); + if(!(holder instanceof Player)) return; + + Player player = (Player)holder; + PlayerData playerData = PlayerData.FromPlayer(player); + + sortPlayerIfEnabled(player, playerData, bottomInventory); + + if(player.getGameMode() != GameMode.CREATIVE && Math.random() < .1 && !playerData.isGotDepositAllInfo() && featureEnabled(Features.DEPOSITALL, player)) + { + Inventory topInventory = event.getView().getTopInventory(); + if(topInventory != null && topInventory.getType() == InventoryType.CHEST) + { + AutomaticInventory.getInstance().sendMessage(player, TextMode.INSTR, Messages.DEPOSITALLADVERTISEMENT); + playerData.setGotDepositAllInfo(true); + } + } + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onPickupItem(PlayerPickupItemEvent event) + { + Player player = event.getPlayer(); + if(featureEnabled(Features.SORTINVENTORY, player)) + { + PlayerData playerData = PlayerData.FromPlayer(player); + if(playerData.firstEmptySlot >= 0) return; + + PlayerInventory inventory = player.getInventory(); + int firstEmpty = inventory.firstEmpty(); + if(firstEmpty < 9) return; + playerData.firstEmptySlot = firstEmpty; + PickupSortTask task = new PickupSortTask(player, playerData, inventory); + Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(AutomaticInventory.getInstance(), task, 100L); + } + } + + public static void sortPlayerIfEnabled(Player player, PlayerData playerData, Inventory inventory) + { + if(featureEnabled(Features.SORTINVENTORY, player)) + { + new InventorySorter(inventory, 9).run(); + + if(!playerData.isGotInventorySortInfo()) + { + AutomaticInventory.getInstance().sendMessage(player, TextMode.INFO, Messages.INVENTORYSORTEDUCATION); + playerData.setGotInventorySortInfo(true); + } + } + } + + public static boolean isSortableChestInventory(Inventory inventory) + { + if(inventory == null) return false; + + InventoryType inventoryType = inventory.getType(); + if(inventoryType != InventoryType.CHEST && inventoryType != InventoryType.ENDER_CHEST) return false; + + String name = inventory.getName(); + if(name != null && name.contains("*")) return false; + + InventoryHolder holder = inventory.getHolder(); + if(holder == null || !(holder instanceof Chest || holder instanceof DoubleChest || holder instanceof StorageMinecart)) return false; + + return true; + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onPlayerJoin(PlayerJoinEvent event) + { + Player player = event.getPlayer(); + PlayerData.Preload(player); + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onPlayerQuit(PlayerQuitEvent event) + { + Player player = event.getPlayer(); + PlayerData.FromPlayer(player).saveChanges(); + } +} + +class PickupSortTask implements Runnable +{ + private Player player; + private PlayerData playerData; + private Inventory playerInventory; + + PickupSortTask(Player player, PlayerData playerData, Inventory playerInventory) + { + this.player = player; + this.playerData = playerData; + this.playerInventory = playerInventory; + } + + @Override + public void run() + { + if(this.playerData.firstEmptySlot == playerInventory.firstEmpty()) + { + this.playerData.firstEmptySlot = -1; + return; + } + + AIEventHandler.sortPlayerIfEnabled(this.player, this.playerData, this.playerInventory); + + this.playerData.firstEmptySlot = -1; + } +} + +class InventorySorter implements Runnable +{ + private Inventory inventory; + private int startIndex; + + InventorySorter(Inventory inventory, int startIndex) + { + this.inventory = inventory; + this.startIndex = startIndex; + } + + @Override + public void run() + { + ArrayList stacks = new ArrayList(); + ItemStack [] contents = this.inventory.getContents(); + int inventorySize = contents.length; + if(this.inventory.getType() == InventoryType.PLAYER) inventorySize = Math.min(contents.length, 36); + for(int i = this.startIndex; i < inventorySize; i++) + { + ItemStack stack = contents[i]; + if(stack != null) + { + stacks.add(stack); + } + } + + Collections.sort(stacks, new StackComparator()); + for(int i = 1; i < stacks.size(); i++) + { + ItemStack prevStack = stacks.get(i - 1); + ItemStack thisStack = stacks.get(i); + if(prevStack.isSimilar(thisStack)) + { + if(prevStack.getAmount() < prevStack.getMaxStackSize()) + { + int moveCount = Math.min(prevStack.getMaxStackSize() - prevStack.getAmount(), thisStack.getAmount()); + prevStack.setAmount(prevStack.getAmount() + moveCount); + thisStack.setAmount(thisStack.getAmount() - moveCount); + if(thisStack.getAmount() == 0) + { + stacks.remove(i); + i--; + }; + } + } + } + + int i; + for(i = 0; i < stacks.size(); i++) + { + this.inventory.setItem(i + this.startIndex, stacks.get(i)); + } + + for(i = i + this.startIndex; i < inventorySize; i++) + { + this.inventory.clear(i); + } + } + + private class StackComparator implements Comparator + { + @SuppressWarnings("deprecation") + @Override + public int compare(ItemStack a, ItemStack b) + { + int result = new Integer(b.getMaxStackSize()).compareTo(a.getMaxStackSize()); + if(result != 0) return result; + + result = new Integer(b.getTypeId()).compareTo(a.getTypeId()); + if(result != 0) return result; + + result = new Byte(b.getData().getData()).compareTo(a.getData().getData()); + if(result != 0) return result; + + result = new Integer(b.getAmount()).compareTo(a.getAmount()); + return result; + } + } +} + + From eb2f13a9f67b75ffc781787a6c8197c6a01cc79a Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Fri, 9 Dec 2016 12:10:57 +0100 Subject: [PATCH 30/31] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b69c533..08a2e39 100644 --- a/README.md +++ b/README.md @@ -5,4 +5,4 @@ I created this Minecraft server plugin using the Bukkit API to minimize the pain I stopped working on this project after Minecraft 1.10. Anyone may use my source code to continue the project, but see the LICENSE file for restrictions. # The future of this project -Actually, me (crazyhoorse961) i want to continue this project with a fork. Ill try update it, i won't publish it on spigot or bukkit but feel free to build it, soon ill leave releases here on github. +Actually, me (crazyhoorse961) i want to continue this project with a fork. Ill try update it, i won't publish it on spigot or bukkit but feel free to build it, i've now leaved releases too. From f24d090546af66c810bcb398fb049bfe1e905a91 Mon Sep 17 00:00:00 2001 From: crazyhorse961 Date: Fri, 13 Jan 2017 12:46:07 +0100 Subject: [PATCH 31/31] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 08a2e39..b6d704f 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,7 @@ I stopped working on this project after Minecraft 1.10. Anyone may use my sourc # The future of this project Actually, me (crazyhoorse961) i want to continue this project with a fork. Ill try update it, i won't publish it on spigot or bukkit but feel free to build it, i've now leaved releases too. + +# READ +I'm realizing that i haven't much time to take this project but, i will take it updated to 1.12 and all the future versions, but, i won't (probably) add many features and i won't be that active on solving issues. Sorry +