Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Item rollback improvements #41

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Hanging;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.entity.Vehicle;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
Expand Down Expand Up @@ -400,7 +401,26 @@ public static Handler createItemStack(String actionType, ItemStack item, Map<Enc
*/
public static Handler createItemStack(String actionType, ItemStack item, int quantity, int slot,
Map<Enchantment, Integer> enchantments, Location loc, OfflinePlayer player) {
return createItemStack(actionType, item, quantity, slot, enchantments, loc, player, null);
}

/**
* ItemStack Handler.
*
* @param actionType String
* @param item Item
* @param quantity int
* @param slot int
* @param enchantments map
* @param loc Location
* @param player Player
* @param itemEntity The entity when rollbacked remove.
* @return handler
*/
public static Handler createItemStack(String actionType, ItemStack item, int quantity, int slot,
Map<Enchantment, Integer> enchantments, Location loc, OfflinePlayer player, Item itemEntity) {
final ItemStackAction a = createItemStack(actionType, item, quantity, enchantments, loc, player);
a.setItemEntity(itemEntity);
a.setSlot(String.valueOf(slot));

return a;
Expand All @@ -421,12 +441,32 @@ public static Handler createItemStack(String actionType, ItemStack item, int qua
public static Handler createItemStack(String actionType, ItemStack item, int quantity, int slot,
Map<Enchantment, Integer> enchantments,
Location loc, String sourceName) {
return createItemStack(actionType, item, quantity, slot, enchantments, loc, sourceName, null);
}

/**
* Handles a block being dropped or dispensed.
*
* @param actionType type
* @param item item
* @param quantity qty
* @param slot slot it was in
* @param enchantments Map of enchants
* @param loc Location
* @param sourceName Source of the item.
* @param itemEntity The entity when rollbacked remove.
* @return Handler
*/
public static Handler createItemStack(String actionType, ItemStack item, int quantity, int slot,
Map<Enchantment, Integer> enchantments,
Location loc, String sourceName, Item itemEntity) {
final ItemStackAction a = new ItemStackAction();
a.setActionType(actionType);
a.setLoc(loc);
a.setSourceName(sourceName);
a.setItem(item, quantity, enchantments);
a.setSlot(String.valueOf(slot));
a.setItemEntity(itemEntity);
return a;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package network.darkhelmet.prism.actionlibs;

import network.darkhelmet.prism.Prism;
import network.darkhelmet.prism.actions.ItemStackAction;
import network.darkhelmet.prism.api.actions.Handler;
import network.darkhelmet.prism.database.InsertQuery;
import network.darkhelmet.prism.measurement.QueueStats;
Expand Down Expand Up @@ -122,7 +123,10 @@ void insertActionsIntoDatabase() {
if (a.isCanceled()) {
continue;
}
batchedQuery.insertActionIntoDatabase(a);
long dataId = batchedQuery.insertActionIntoDatabase(a);
if (a instanceof ItemStackAction && ((ItemStackAction) a).getItemEntity() != null) {
ItemStackAction.addCache(dataId, ((ItemStackAction) a).getItemEntity());
}

actionsRecorded++;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package network.darkhelmet.prism.actions;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import network.darkhelmet.prism.Prism;
import network.darkhelmet.prism.actions.data.ItemStackActionData;
import network.darkhelmet.prism.api.ChangeResult;
Expand Down Expand Up @@ -30,16 +32,47 @@
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class ItemStackAction extends GenericAction {

private static final Cache<Long, Item> dropCache = CacheBuilder
.newBuilder()
.softValues()
.expireAfterWrite(3, TimeUnit.DAYS) // LONGGGGGGGGGGGGGGGGGGGGGG
.build();

public static void addCache(Long dataId, Item item) {
dropCache.put(dataId, item);
}

public static boolean removeFromCache(Long dataId) {
Item item = dropCache.getIfPresent(dataId);
if (item != null) {
dropCache.invalidate(dataId);
item.remove();
return true;
}
return false;
}

protected ItemStack item;
private ItemStackActionData actionData;
private Item dropEntity;

/**
* Holds durability if no actionData yet exists.
*/
private short tempDurability = -1;

public Item getItemEntity() {
return dropEntity;
}

public void setItemEntity(Item dropEntity) {
this.dropEntity = dropEntity;
}

@Override
public boolean hasExtraData() {
return actionData != null;
Expand Down Expand Up @@ -164,6 +197,12 @@ protected ChangeResult placeItems(Player player, PrismParameters parameters, boo
final Block block = getWorld().getBlockAt(getLoc());
Inventory inventory = null;

// Entity death drops. Just remove the drops.
if (getUuid() == null || getActionType().getName().equals("item-drop")) {
removeItemEntity();
return new ChangeResultImpl(ChangeResultType.APPLIED, null);
}

// Item drop/pickup from player inventories
if (getActionType().getName().equals("item-drop") || getActionType().getName().equals("item-pickup")) {

Expand Down Expand Up @@ -324,6 +363,17 @@ protected ChangeResult placeItems(Player player, PrismParameters parameters, boo
inventory.setItem(iSlot, item);
}
}
if (added && (n.equals("item-insert") || n.equals("item-remove"))) {
final Player onlinePlayer = Bukkit.getServer().getPlayer(getUuid());
if (onlinePlayer != null) {
Inventory playerInventory = onlinePlayer.getInventory();
final HashMap<Integer, ItemStack> leftovers = InventoryUtils.removeItemFromInventory(playerInventory,
getItem());
if (leftovers.size() > 0) {
Prism.debug("There are leftovers when roll-backing player inventory, action " + n);
}
}
}
}
// If that failed we'll attempt to put it anywhere
if (!added) {
Expand All @@ -341,21 +391,7 @@ protected ChangeResult placeItems(Player player, PrismParameters parameters, boo

// Item was added to the inv, we need to remove the entity
if (added && (n.equals("item-drop") || n.equals("item-pickup"))) {
final Entity[] entities = getLoc().getChunk().getEntities();
for (final Entity entity : entities) {
if (entity instanceof Item) {
final ItemStack stack = ((Item) entity).getItemStack();
if (stack.isSimilar(getItem())) {
// Remove the event's number of items from
// the stack
stack.setAmount(stack.getAmount() - getItem().getAmount());
if (stack.getAmount() == 0) {
entity.remove();
}
break;
}
}
}
removeItemEntity();
}
}

Expand All @@ -374,7 +410,7 @@ protected ChangeResult placeItems(Player player, PrismParameters parameters, boo
if (iSlot >= 0) {

if (iSlot >= inventory.getContents().length) {
inventory.addItem(getItem());
inventory.removeItem(getItem());
} else {
final ItemStack currentSlotItem = inventory.getItem(iSlot);
ItemStack item = getItem().clone();
Expand All @@ -390,7 +426,33 @@ protected ChangeResult placeItems(Player player, PrismParameters parameters, boo
inventory.setItem(iSlot, amount > 0 ? item : null);
}
}
if (removed && (n.equals("item-insert") || n.equals("item-remove"))) {
final Player onlinePlayer = Bukkit.getServer().getPlayer(getUuid());
if (onlinePlayer != null) {
Inventory playerInventory = onlinePlayer.getInventory();
final HashMap<Integer, ItemStack> leftovers = InventoryUtils.addItemToInventory(playerInventory,
getItem());
if (leftovers.size() > 0) {
Prism.debug("There are leftovers when roll-backing player inventory, action " + n);
}
}
}
}

// If that failed we'll attempt to remove it anywhere
if (!removed) {
// TODO: Skip is actually "partially applied"
final HashMap<Integer, ItemStack> leftovers = InventoryUtils.removeItemFromInventory(inventory,
getItem());
if (leftovers.size() > 0) {
Prism.debug("Skipping removing items because there are leftovers");
result = ChangeResultType.SKIPPED;
} else {
result = ChangeResultType.APPLIED;
removed = true;
}
}

if (removed && (n.equals("item-drop") || n.equals("item-pickup"))) {
ItemUtils.dropItem(getLoc(), getItem());
}
Expand All @@ -399,4 +461,24 @@ protected ChangeResult placeItems(Player player, PrismParameters parameters, boo
}
return new ChangeResultImpl(result, null);
}

private void removeItemEntity() {
if (!removeFromCache(getId())) {
// Not cached, search nearby for it.
for (final Entity entity : getLoc().getWorld().getNearbyEntities(getLoc(), 10, 10, 10)) {
if (entity instanceof Item) {
final ItemStack stack = ((Item) entity).getItemStack();
if (stack.isSimilar(getItem())) {
// Remove the event's number of items from
// the stack
stack.setAmount(stack.getAmount() - getItem().getAmount());
if (stack.getAmount() == 0) {
entity.remove();
}
break;
}
}
}
}
}
}
Loading