Got item saving/reclaiming to a workable state, expected behavior:

All inventory holding blocks in the rental space will be scanned,
their items added to a temporary extra-dimensional storage along with
the holding block (IE the contents of a chest will be put in this
storage, then the chest will be added). After which the storage will be
deleted (well the block will be set to air).

The player can later reclaim the items using /re reclaim, which will pop
a gui this will contain the first 54 items(and their containing blocks).
Subsequent activations of this command will provide an opprotunity to
reclaim other items until there are none left.

Once all items have been withdrawn, there will be a message saying the
storage is empty.

Warning: The reclaim inventory *can* store extra items, however the
space is not unlimited. I will have to ask around if this is an issue.
This commit is contained in:
Famous_Longwing 2024-02-25 16:51:28 -05:00
parent fefe9424b7
commit 87af20d396
5 changed files with 226 additions and 94 deletions

View File

@ -6,6 +6,7 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.bouncycastle.util.Arrays;
import org.bukkit.Location;
@ -35,7 +36,7 @@ public class AbandonedItems extends YamlConfiguration
}
owner=item_owner;
Saved_Items=new ArrayList<ItemStack>();
Saved_Items=new CopyOnWriteArrayList<ItemStack>();
String path= RealEstate.pluginDirPath + "/Abandoned_inventories/"+item_owner+".inventory";
file=new File(path);
if(file.exists())//user has stuff already saved, load it
@ -47,46 +48,74 @@ public class AbandonedItems extends YamlConfiguration
{
return owner;
}
public void set_items(List<ItemStack> new_set)
{
Saved_Items=new_set;
if(Saved_Items.size()>0)
{
save();
}
else
{
delete_save();
}
}
public void add_item(ItemStack addme)
{
int remaining=addme.getAmount();
RealEstate.instance.log.info("Attempting to add: "+addme.getType()+" of stack amount "+addme.getAmount());
for(ItemStack a : Saved_Items)
{
//for(ItemStack a : current_items)
// we want the last instance of any particular item stack, or 0
int last_stack=-1;
for(int i=0;i<Saved_Items.size();i++)
{
ItemStack a=Saved_Items.get(i);
if(a ==null)
{
i++;
continue;
}
if(a.getType()==addme.getType())
{
RealEstate.instance.log.info("Found an existing stack, combining: "+a.getType()+" With existing size of "+a.getAmount());
int cursize=a.getAmount();
int maxamount=a.getMaxStackSize();
if(cursize<maxamount) //room to add more
{
RealEstate.instance.log.info("We went over the limit, adding what we can");
cursize+=addme.getAmount();
cursize=cursize>maxamount? maxamount:cursize;
remaining -= maxamount-a.getAmount();
a.setAmount(cursize);
}
last_stack=i;
}
if(remaining >0)//there is atleast one more to put in
}
//at this point last_stack either points to the latest stack of items, which means we need to do some jiggling around, or it is -1 meaning no items of addme.type are in the array.
if(last_stack>=0) {
ItemStack a=Saved_Items.get(last_stack);
int cursize=a.getAmount();
int maxamount=a.getMaxStackSize();
if(cursize<maxamount) //room to add more
{
RealEstate.instance.log.info("Remaining items: "+remaining+" adding remaining stack to saved items");
addme.setAmount(remaining);//just in case we removed some earlier
Saved_Items.add(addme);
remaining=0;
cursize+=addme.getAmount();
if(cursize>maxamount)
{
cursize=maxamount;
remaining-=maxamount-a.getAmount();
addme.setAmount(remaining);
Saved_Items.add(addme);
}
a.setAmount(cursize);//reset the amount in the array;
}
else//cursize was *exactly* maxamount, so we just add the stack as-is.
{
Saved_Items.add(addme);
}
}
if(last_stack==-1) {
Saved_Items.add(addme);
}
if(Saved_Items.size()==0)//first item being put in, heh
{
RealEstate.instance.log.info("Adding first item to the save queue");
{
Saved_Items.add(addme);
}
this.save();
}

View File

@ -0,0 +1,100 @@
package me.EtienneDx.RealEstate;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.PluginManager;
import org.bukkit.inventory.Inventory;
public class PlayerItemReclaim implements Listener
{
void registerEvents()
{
PluginManager pm = RealEstate.instance.getServer().getPluginManager();
pm.registerEvents(this, RealEstate.instance);
}
public static void reclaimItems(Player player, int page) {
// Get the items from AbandonedItems
AbandonedItems player_items=new AbandonedItems(player.getUniqueId().toString());
List<ItemStack> items = player_items.get_items();
// Create an inventory for the player to hold the items
int number=items.size();
if(number==0)
{
Messages.sendMessage(player, "You don't have any items in storage!");
return;
}
int roundedNumber=0;
/*
if (number > 54) {
roundedNumber = 54;
} else {
roundedNumber = (number + 9 - 1) / 9 * 9;
}*/
roundedNumber=(int)(Math.ceil(number / 9.0) * 9);
if(roundedNumber>54)
{
roundedNumber=54;
}
Inventory inv = Bukkit.createInventory(null, roundedNumber, "Reclaimed Items");
if(page>items.size())
{
page=0;
}
// Add the items to the inventory
int i = page;
while (i < items.size() && i < roundedNumber) {
inv.setItem(i - page, items.get(i));
i++;
}
// Give the inventory to the player
player.openInventory(inv);
}
@EventHandler
public void OnInventoryCloseEvent(InventoryCloseEvent event)
{
String title=event.getView().getTitle();
if(title =="Reclaimed Items")
{
Inventory inv =event.getInventory();
HumanEntity player= event.getPlayer();
AbandonedItems reclaimed_items=new AbandonedItems(player.getUniqueId().toString());
List<ItemStack> remaining_items=new ArrayList<ItemStack>();
for(ItemStack a: inv.getContents())
{
if(a != null)
{
RealEstate.instance.log.info("Top inventory still had: "+a.getType());
remaining_items.add(a);
}
}
reclaimed_items.set_items(remaining_items);
}
}
}

View File

@ -54,8 +54,8 @@ public class RECommand extends BaseCommand
@Subcommand("list")
@Description("Displays the list of all real estate offers currently existing")
@CommandCompletion("all|sell|rent|lease")
@Syntax("[all|sell|rent|lease] <page>")
@CommandCompletion("all|sell|rent|lease|reclaim")
@Syntax("[all|sell|rent|lease|reclaim] <page>")
public static void list(CommandSender sender, @Optional String type, @Default("1") int page)
{
Player player = null;
@ -395,17 +395,20 @@ public class RECommand extends BaseCommand
}
}
}
@Subcommand("purge")
@CommandPermission("realestate.admin")
public static void perge(Player player)
@Subcommand("reclaim")
@CommandPermission("realestate.rent")
//@Syntax("<page>")
public static void reclaim(Player player)//, @Optional @Default("0") int page)
{
if(RealEstate.instance.config.SaveInventory) {
AbandonedItems.purge_items(player);
// AbandonedItems.purge_items(player);
PlayerItemReclaim.reclaimItems(player, 0);
}
else
Messages.sendMessage(player, RealEstate.instance.messages.msgErrorSavingDisabled);
}
@Subcommand("cancel")
@Conditions("claimHasTransaction")
@CommandPermission("realestate.admin")

View File

@ -127,6 +127,7 @@ public class RealEstate extends JavaPlugin
new REListener().registerEvents();
new ClaimPermissionListener().registerEvents();
new PlayerItemReclaim().registerEvents();
manager = new BukkitCommandManager(this);
manager.enableUnstableAPI("help");

View File

@ -3,7 +3,6 @@ package me.EtienneDx.RealEstate.Transactions;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.reflect.Method;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
@ -22,9 +21,12 @@ import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
import org.bukkit.block.sign.Side;
import org.bukkit.block.sign.SignSide;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import com.earth2me.essentials.User;
@ -154,9 +156,12 @@ public class ClaimRent extends BoughtTransaction
{
if(sign.getBlock().getState() instanceof Sign)
{
Sign s = (Sign) sign.getBlock().getState();
s.setWaxed(true);
Sign thissign = (Sign) sign.getBlock().getState();
thissign.setWaxed(true);
SignSide s=thissign.getSide(Side.valueOf("FRONT"));
s.setLine(0, Messages.getMessage(RealEstate.instance.config.cfgSignsHeader, false));
s.setLine(1, ChatColor.DARK_GREEN + RealEstate.instance.config.cfgReplaceRent);
//s.setLine(2, owner != null ? Bukkit.getOfflinePlayer(owner).getName() : "SERVER");
String price_line = "";
@ -191,7 +196,7 @@ public class ClaimRent extends BoughtTransaction
s.setLine(2, RealEstate.instance.config.cfgContainerRentLine);
s.setLine(3, price_line + " - " + period);
}
s.update(true);
thissign.update(true);
}
else
{
@ -214,7 +219,8 @@ public class ClaimRent extends BoughtTransaction
}
else if(sign.getBlock().getState() instanceof Sign)
{
Sign s = (Sign) sign.getBlock().getState();
Sign thissign = (Sign) sign.getBlock().getState();
SignSide s=thissign.getSide(Side.valueOf("FRONT"));
s.setLine(0, ChatColor.GOLD + RealEstate.instance.config.cfgReplaceOngoingRent); //Changed the header to "[Rented]" so that it won't waste space on the next line and allow the name of the player to show underneath.
s.setLine(1, Utils.getSignString(Bukkit.getOfflinePlayer(buyer).getName()));//remove "Rented by"
s.setLine(2, "Time remaining : ");
@ -223,7 +229,7 @@ public class ClaimRent extends BoughtTransaction
Duration timeRemaining = Duration.ofHours(24).minus(hours);
s.setLine(3, Utils.getTime(daysLeft, timeRemaining, false));
s.update(true);
thissign.update(true);
}
}
return false;
@ -235,7 +241,7 @@ public class ClaimRent extends BoughtTransaction
return;
}
String item_owner=mybuyer;//uuid saved when we started the transaction
//so now we need to scan through the entire claim, and find any inventory to save X.x
//get chunks within area, get inventories, check if inventory is within the bounds, then process.
List<Chunk> chunksToProcess=new ArrayList<Chunk>();
@ -243,9 +249,6 @@ public class ClaimRent extends BoughtTransaction
Location max=claim.getGreaterBoundaryCorner();
World world=min.getWorld();
List<Inventory> lifeboat=new ArrayList<Inventory>();
int invsize=0;
for (double x=min.getX();x<max.getX();x+=16) {
for(double z=min.getZ();z<max.getZ();z+=16)
{
@ -260,6 +263,7 @@ public class ClaimRent extends BoughtTransaction
}
//now we have all the chunks involved, now to find inventories...
List<Inventory> processed=new ArrayList<Inventory>();//we have seen these inventories, this is more important for things like double chests, which we will see twice
AbandonedItems item_saver=new AbandonedItems(mybuyer);
for(Chunk chunk:chunksToProcess)
{
@ -269,63 +273,37 @@ public class ClaimRent extends BoughtTransaction
{
if (tileEntity.getZ()>min.getZ()&&tileEntity.getZ()<max.getZ())
{
try
if(tileEntity instanceof InventoryHolder)
{
if(tileEntity.getClass().getMethod("getInventory") != null)
InventoryHolder inv=(InventoryHolder) tileEntity;
Inventory found_inv=inv.getInventory();
for(int i=0;i<processed.size();i++)
{
Method method= tileEntity.getClass().getMethod("getInventory");
Inventory found_inventory=(Inventory) method.invoke(tileEntity, null);
for(ItemStack j : found_inventory.getStorageContents())
if(processed.get(i).equals(found_inv))
{
if(j !=null) {
item_saver.add_item(j);
}
else
{
continue;
}
continue; //we found an inventory we already worked on.... next
}
//blow away the container after we save everything
Location inventoryloc=tileEntity.getLocation();
world.setType(inventoryloc, Material.AIR);
}
}
catch (Exception e)
{
// TODO Auto-generated catch block
//RealEstate.instance.log.info("");
//nothing to do here, we know some of these are not going to have this method, we don't care.
RealEstate.instance.log.info("exception raised: "+e.getMessage());
processed.add(found_inv);
for(ItemStack j:found_inv.getContents())
{
if(j != null)
{
item_saver.add_item(j);
}
}
Location inventoryloc=tileEntity.getLocation();
ItemStack breakthis=new ItemStack(tileEntity.getType(),1);
item_saver.add_item(breakthis);
world.setType(inventoryloc, Material.AIR);
}
}
}
}
}
item_saver.save();
//ok, so now i have an array list of inventories, and how many stacks of items we have.... now what?
//well bukkit needs a size that is a factor of 9, so next highest factor of 9?
/*
* while((invsize %9)!=0) {
* RealEstate.instance.log.info("Inventory size was only "
* +invsize+" not divisible by 9, incrementing"); invsize++; //increase invsize
* until it is divisible by 9 } //move everything into one inventory Inventory
* saved_inventory=Bukkit.createInventory(null, invsize); for (Inventory
* passengers:lifeboat) { for(ItemStack j:passengers.getStorageContents()) {
* RealEstate.instance.log.info("Moving item stack of "+j.getType());
* saved_inventory.addItem(j);
*
* } }
*/
}
public static void restore_rental(Claim claim)
@ -362,11 +340,12 @@ public class ClaimRent extends BoughtTransaction
BlockType air=new BlockType("minecraft:air");//we want to capture all the air from the saved schematic, to empty out the space that used to be empty
BlockTypeMask mask= new BlockTypeMask(clipboard,air);//create a mask, specifying we want to keep just the air from the schematic
BlockTypeMask mask_air= new BlockTypeMask(clipboard,air);//create a mask, specifying we want to keep just the air from the schematic
Operation operation = new ClipboardHolder(clipboard)
.createPaste(editSession)
.to(BlockVector3.at(lesser.getX(), lesser.getWorld().getMinHeight(), lesser.getZ()))
.maskSource(mask)//ignore non-air blocks from the schematic.
.maskSource(mask_air)//ignore non-air blocks from the schematic.
.ignoreAirBlocks(false) //well that would be silly, we want the air
.build();
Operations.complete(operation);
@ -437,7 +416,11 @@ public class ClaimRent extends BoughtTransaction
else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null)
{
User u = RealEstate.ess.getUser(this.buyer);
u.addMail(Messages.getMessage(RealEstate.instance.messages.msgInfoClaimInfoRentPaymentBuyer,
/*u.addMail(Messages.getMessage(RealEstate.instance.messages.msgInfoClaimInfoRentPaymentBuyer,
claimType,
location,
RealEstate.econ.format(price)));*/
u.sendMail(null,Messages.getMessage(RealEstate.instance.messages.msgInfoClaimInfoRentPaymentBuyer,
claimType,
location,
RealEstate.econ.format(price)));
@ -456,7 +439,13 @@ public class ClaimRent extends BoughtTransaction
else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null)
{
User u = RealEstate.ess.getUser(this.owner);
u.addMail(Messages.getMessage(RealEstate.instance.messages.msgInfoClaimInfoRentPaymentOwner,
/*u.addMail(Messages.getMessage(RealEstate.instance.messages.msgInfoClaimInfoRentPaymentOwner,
buyerPlayer.getName(),
claimType,
location,
RealEstate.econ.format(price)));*/
u.sendMail(null, Messages.getMessage(RealEstate.instance.messages.msgInfoClaimInfoRentPaymentOwner,
buyerPlayer.getName(),
claimType,
location,
@ -477,7 +466,12 @@ public class ClaimRent extends BoughtTransaction
else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null)
{
User u = RealEstate.ess.getUser(this.buyer);
u.addMail(Messages.getMessage(RealEstate.instance.messages.msgInfoClaimInfoRentPaymentBuyerCancelled,
/*u.addMail(Messages.getMessage(RealEstate.instance.messages.msgInfoClaimInfoRentPaymentBuyerCancelled,
claimType,
location,
RealEstate.econ.format(price)));*/
u.sendMail(null, Messages.getMessage(RealEstate.instance.messages.msgInfoClaimInfoRentPaymentBuyerCancelled,
claimType,
location,
RealEstate.econ.format(price)));
@ -603,7 +597,12 @@ public class ClaimRent extends BoughtTransaction
else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null)
{
User u = RealEstate.ess.getUser(this.owner);
u.addMail(Messages.getMessage(RealEstate.instance.messages.msgInfoClaimOwnerRented,
/*u.addMail(Messages.getMessage(RealEstate.instance.messages.msgInfoClaimOwnerRented,
player.getName(),
claimTypeDisplay,
RealEstate.econ.format(price),
location));*/
u.sendMail(null, Messages.getMessage(RealEstate.instance.messages.msgInfoClaimOwnerRented,
player.getName(),
claimTypeDisplay,
RealEstate.econ.format(price),