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.io.InputStreamReader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Arrays;
import org.bukkit.Location; import org.bukkit.Location;
@ -35,7 +36,7 @@ public class AbandonedItems extends YamlConfiguration
} }
owner=item_owner; owner=item_owner;
Saved_Items=new ArrayList<ItemStack>(); Saved_Items=new CopyOnWriteArrayList<ItemStack>();
String path= RealEstate.pluginDirPath + "/Abandoned_inventories/"+item_owner+".inventory"; String path= RealEstate.pluginDirPath + "/Abandoned_inventories/"+item_owner+".inventory";
file=new File(path); file=new File(path);
if(file.exists())//user has stuff already saved, load it if(file.exists())//user has stuff already saved, load it
@ -47,46 +48,74 @@ public class AbandonedItems extends YamlConfiguration
{ {
return owner; 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) public void add_item(ItemStack addme)
{ {
int remaining=addme.getAmount(); 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()) if(a.getType()==addme.getType())
{ {
RealEstate.instance.log.info("Found an existing stack, combining: "+a.getType()+" With existing size of "+a.getAmount()); last_stack=i;
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);
}
} }
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"); cursize+=addme.getAmount();
addme.setAmount(remaining);//just in case we removed some earlier if(cursize>maxamount)
Saved_Items.add(addme); {
remaining=0; 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 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); Saved_Items.add(addme);
} }
this.save(); 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") @Subcommand("list")
@Description("Displays the list of all real estate offers currently existing") @Description("Displays the list of all real estate offers currently existing")
@CommandCompletion("all|sell|rent|lease") @CommandCompletion("all|sell|rent|lease|reclaim")
@Syntax("[all|sell|rent|lease] <page>") @Syntax("[all|sell|rent|lease|reclaim] <page>")
public static void list(CommandSender sender, @Optional String type, @Default("1") int page) public static void list(CommandSender sender, @Optional String type, @Default("1") int page)
{ {
Player player = null; Player player = null;
@ -395,17 +395,20 @@ public class RECommand extends BaseCommand
} }
} }
} }
@Subcommand("purge") @Subcommand("reclaim")
@CommandPermission("realestate.admin") @CommandPermission("realestate.rent")
public static void perge(Player player) //@Syntax("<page>")
public static void reclaim(Player player)//, @Optional @Default("0") int page)
{ {
if(RealEstate.instance.config.SaveInventory) { if(RealEstate.instance.config.SaveInventory) {
AbandonedItems.purge_items(player); // AbandonedItems.purge_items(player);
PlayerItemReclaim.reclaimItems(player, 0);
} }
else else
Messages.sendMessage(player, RealEstate.instance.messages.msgErrorSavingDisabled); Messages.sendMessage(player, RealEstate.instance.messages.msgErrorSavingDisabled);
} }
@Subcommand("cancel") @Subcommand("cancel")
@Conditions("claimHasTransaction") @Conditions("claimHasTransaction")
@CommandPermission("realestate.admin") @CommandPermission("realestate.admin")

View File

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

View File

@ -3,7 +3,6 @@ package me.EtienneDx.RealEstate.Transactions;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.lang.reflect.Method;
import java.time.Duration; import java.time.Duration;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -22,9 +21,12 @@ import org.bukkit.OfflinePlayer;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.bukkit.block.Sign; 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.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import com.earth2me.essentials.User; import com.earth2me.essentials.User;
@ -154,9 +156,12 @@ public class ClaimRent extends BoughtTransaction
{ {
if(sign.getBlock().getState() instanceof Sign) if(sign.getBlock().getState() instanceof Sign)
{ {
Sign s = (Sign) sign.getBlock().getState(); Sign thissign = (Sign) sign.getBlock().getState();
s.setWaxed(true); thissign.setWaxed(true);
SignSide s=thissign.getSide(Side.valueOf("FRONT"));
s.setLine(0, Messages.getMessage(RealEstate.instance.config.cfgSignsHeader, false)); s.setLine(0, Messages.getMessage(RealEstate.instance.config.cfgSignsHeader, false));
s.setLine(1, ChatColor.DARK_GREEN + RealEstate.instance.config.cfgReplaceRent); s.setLine(1, ChatColor.DARK_GREEN + RealEstate.instance.config.cfgReplaceRent);
//s.setLine(2, owner != null ? Bukkit.getOfflinePlayer(owner).getName() : "SERVER"); //s.setLine(2, owner != null ? Bukkit.getOfflinePlayer(owner).getName() : "SERVER");
String price_line = ""; String price_line = "";
@ -191,7 +196,7 @@ public class ClaimRent extends BoughtTransaction
s.setLine(2, RealEstate.instance.config.cfgContainerRentLine); s.setLine(2, RealEstate.instance.config.cfgContainerRentLine);
s.setLine(3, price_line + " - " + period); s.setLine(3, price_line + " - " + period);
} }
s.update(true); thissign.update(true);
} }
else else
{ {
@ -214,7 +219,8 @@ public class ClaimRent extends BoughtTransaction
} }
else if(sign.getBlock().getState() instanceof Sign) 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(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(1, Utils.getSignString(Bukkit.getOfflinePlayer(buyer).getName()));//remove "Rented by"
s.setLine(2, "Time remaining : "); s.setLine(2, "Time remaining : ");
@ -223,7 +229,7 @@ public class ClaimRent extends BoughtTransaction
Duration timeRemaining = Duration.ofHours(24).minus(hours); Duration timeRemaining = Duration.ofHours(24).minus(hours);
s.setLine(3, Utils.getTime(daysLeft, timeRemaining, false)); s.setLine(3, Utils.getTime(daysLeft, timeRemaining, false));
s.update(true); thissign.update(true);
} }
} }
return false; return false;
@ -235,7 +241,7 @@ public class ClaimRent extends BoughtTransaction
return; 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 //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. //get chunks within area, get inventories, check if inventory is within the bounds, then process.
List<Chunk> chunksToProcess=new ArrayList<Chunk>(); List<Chunk> chunksToProcess=new ArrayList<Chunk>();
@ -243,9 +249,6 @@ public class ClaimRent extends BoughtTransaction
Location max=claim.getGreaterBoundaryCorner(); Location max=claim.getGreaterBoundaryCorner();
World world=min.getWorld(); 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 x=min.getX();x<max.getX();x+=16) {
for(double z=min.getZ();z<max.getZ();z+=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... //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); AbandonedItems item_saver=new AbandonedItems(mybuyer);
for(Chunk chunk:chunksToProcess) for(Chunk chunk:chunksToProcess)
{ {
@ -269,63 +273,37 @@ public class ClaimRent extends BoughtTransaction
{ {
if (tileEntity.getZ()>min.getZ()&&tileEntity.getZ()<max.getZ()) 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++)
{ {
if(processed.get(i).equals(found_inv))
Method method= tileEntity.getClass().getMethod("getInventory");
Inventory found_inventory=(Inventory) method.invoke(tileEntity, null);
for(ItemStack j : found_inventory.getStorageContents())
{ {
if(j !=null) { continue; //we found an inventory we already worked on.... next
item_saver.add_item(j);
}
else
{
continue;
}
} }
//blow away the container after we save everything
Location inventoryloc=tileEntity.getLocation();
world.setType(inventoryloc, Material.AIR);
} }
} processed.add(found_inv);
catch (Exception e) for(ItemStack j:found_inv.getContents())
{ {
// TODO Auto-generated catch block if(j != null)
//RealEstate.instance.log.info(""); {
//nothing to do here, we know some of these are not going to have this method, we don't care. item_saver.add_item(j);
}
RealEstate.instance.log.info("exception raised: "+e.getMessage()); }
Location inventoryloc=tileEntity.getLocation();
ItemStack breakthis=new ItemStack(tileEntity.getType(),1);
item_saver.add_item(breakthis);
world.setType(inventoryloc, Material.AIR);
} }
} }
} }
} }
} }
item_saver.save(); 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) 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 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) Operation operation = new ClipboardHolder(clipboard)
.createPaste(editSession) .createPaste(editSession)
.to(BlockVector3.at(lesser.getX(), lesser.getWorld().getMinHeight(), lesser.getZ())) .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 .ignoreAirBlocks(false) //well that would be silly, we want the air
.build(); .build();
Operations.complete(operation); Operations.complete(operation);
@ -437,7 +416,11 @@ public class ClaimRent extends BoughtTransaction
else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null) else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null)
{ {
User u = RealEstate.ess.getUser(this.buyer); 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, claimType,
location, location,
RealEstate.econ.format(price))); RealEstate.econ.format(price)));
@ -456,7 +439,13 @@ public class ClaimRent extends BoughtTransaction
else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null) else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null)
{ {
User u = RealEstate.ess.getUser(this.owner); 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(), buyerPlayer.getName(),
claimType, claimType,
location, location,
@ -477,7 +466,12 @@ public class ClaimRent extends BoughtTransaction
else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null) else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null)
{ {
User u = RealEstate.ess.getUser(this.buyer); 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, claimType,
location, location,
RealEstate.econ.format(price))); RealEstate.econ.format(price)));
@ -603,7 +597,12 @@ public class ClaimRent extends BoughtTransaction
else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null) else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null)
{ {
User u = RealEstate.ess.getUser(this.owner); 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(), player.getName(),
claimTypeDisplay, claimTypeDisplay,
RealEstate.econ.format(price), RealEstate.econ.format(price),