Skip to content

Commit d82cb47

Browse files
committed
feat: optimize item stack handling by using getTemplateRef() to reduce cloning
1 parent 55cc6ab commit d82cb47

4 files changed

Lines changed: 31 additions & 13 deletions

File tree

core/src/main/java/github/nighter/smartspawner/spawner/properties/SpawnerData.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,8 @@ public void incrementSellValue(Map<VirtualInventory.ItemSignature, Long> itemsAd
519519

520520
double addedValue = 0.0;
521521
for (Map.Entry<VirtualInventory.ItemSignature, Long> entry : itemsAdded.entrySet()) {
522-
ItemStack template = entry.getKey().getTemplate();
522+
// Use getTemplateRef() to avoid cloning - we only need to read properties
523+
ItemStack template = entry.getKey().getTemplateRef();
523524
long amount = entry.getValue();
524525
double itemPrice = findItemPrice(template, priceCache);
525526
if (itemPrice > 0.0) {
@@ -552,7 +553,8 @@ public void decrementSellValue(List<ItemStack> itemsRemoved, Map<String, Double>
552553

553554
double removedValue = 0.0;
554555
for (Map.Entry<VirtualInventory.ItemSignature, Long> entry : consolidated.entrySet()) {
555-
ItemStack template = entry.getKey().getTemplate();
556+
// Use getTemplateRef() to avoid cloning - we only need to read properties
557+
ItemStack template = entry.getKey().getTemplateRef();
556558
long amount = entry.getValue();
557559
double itemPrice = findItemPrice(template, priceCache);
558560
if (itemPrice > 0.0) {
@@ -582,7 +584,8 @@ public void recalculateSellValue() {
582584
double totalValue = 0.0;
583585

584586
for (Map.Entry<VirtualInventory.ItemSignature, Long> entry : items.entrySet()) {
585-
ItemStack template = entry.getKey().getTemplate();
587+
// Use getTemplateRef() to avoid cloning - we only need to read properties
588+
ItemStack template = entry.getKey().getTemplateRef();
586589
long amount = entry.getValue();
587590
double itemPrice = findItemPrice(template, priceCache);
588591
if (itemPrice > 0.0) {

core/src/main/java/github/nighter/smartspawner/spawner/properties/VirtualInventory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ public boolean removeItems(List<ItemStack> items) {
164164
// Calculate total amounts to remove in a single pass
165165
for (ItemStack item : items) {
166166
if (item == null || item.getAmount() <= 0) continue;
167-
ItemSignature sig = new ItemSignature(item);
167+
// Use cached signature to avoid excessive cloning
168+
ItemSignature sig = getSignature(item);
168169
toRemove.merge(sig, (long) item.getAmount(), Long::sum);
169170
}
170171

core/src/main/java/github/nighter/smartspawner/spawner/sell/SpawnerSellManager.java

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,29 +177,42 @@ private void processSellResult(Player player, SpawnerData spawner, SellResult se
177177
/**
178178
* Calculates the total sell value of items using cached accumulated value
179179
* This method is optimized to use pre-calculated sell values
180+
* OPTIMIZED: Single-pass iteration with progressive capacity adjustment
180181
*/
181182
private SellResult calculateSellValue(Map<VirtualInventory.ItemSignature, Long> consolidatedItems,
182183
SpawnerData spawner) {
183184
// Use the accumulated sell value from spawner (already calculated incrementally)
184185
double totalValue = spawner.getAccumulatedSellValue();
185186
long totalItemsSold = 0;
186-
List<ItemStack> itemsToRemove = new ArrayList<>();
187187

188-
// We still need to create the items list for removal
188+
// Start with reasonable initial capacity (will grow progressively)
189+
// Use ArrayList directly to access ensureCapacity method
190+
ArrayList<ItemStack> itemsToRemove = new ArrayList<>();
191+
192+
// Single-pass iteration: calculate stacks needed AND create them
189193
for (Map.Entry<VirtualInventory.ItemSignature, Long> entry : consolidatedItems.entrySet()) {
190-
ItemStack template = entry.getKey().getTemplate();
194+
// Use getTemplateRef() to avoid cloning when reading properties
195+
ItemStack templateRef = entry.getKey().getTemplateRef();
191196
long amount = entry.getValue();
192-
193-
// Count items (we need this even if we skip price calculation)
197+
int maxStackSize = templateRef.getMaxStackSize();
198+
199+
// Count items for statistics
194200
totalItemsSold += amount;
195201

202+
// Calculate how many stacks this item type needs
203+
int stacksNeeded = (int) Math.ceil((double) amount / maxStackSize);
204+
205+
// Ensure capacity before adding to avoid resizing during loop
206+
// This is cheaper than multiple resizes
207+
itemsToRemove.ensureCapacity(itemsToRemove.size() + stacksNeeded);
208+
196209
// Create ItemStacks to remove (handle stacking properly)
197210
long remainingAmount = amount;
198211
while (remainingAmount > 0) {
199-
ItemStack stackToRemove = template.clone();
200-
int stackSize = (int) Math.min(remainingAmount, template.getMaxStackSize());
212+
ItemStack stackToRemove = templateRef.clone(); // Single clone per stack
213+
int stackSize = (int) Math.min(remainingAmount, maxStackSize);
201214
stackToRemove.setAmount(stackSize);
202-
itemsToRemove.add(stackToRemove);
215+
itemsToRemove.add(stackToRemove); // No resize thanks to ensureCapacity
203216
remainingAmount -= stackSize;
204217
}
205218
}

core/src/main/java/github/nighter/smartspawner/spawner/utils/ItemStackSerializer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ public static List<String> serializeInventory(Map<VirtualInventory.ItemSignature
4242
Map<Material, ItemGroup> groupedItems = new HashMap<>();
4343

4444
for (Map.Entry<VirtualInventory.ItemSignature, Long> entry : items.entrySet()) {
45-
ItemStack template = entry.getKey().getTemplate();
45+
// Use getTemplateRef() to avoid cloning - we only need to read properties
46+
ItemStack template = entry.getKey().getTemplateRef();
4647
Material material = template.getType();
4748
ItemGroup group = groupedItems.computeIfAbsent(material, ItemGroup::new);
4849

0 commit comments

Comments
 (0)