Skip to content

Commit

Permalink
Changeable Max Stack Size for Items and Inventory (#6698)
Browse files Browse the repository at this point in the history
* Changeable max stack size for item and inventory

* Changeable max stack size for item and inventory

* Fix required plugins versioning

* Fix human error and removing redundant debug message

* Fix breaking change to inventory max stack size in 1.20.5

* Requested changes

* Annotation correction

* More tests

* Check for ItemType#getRandom() nullability

* Check for ItemType#getRandom() nullability

* Remove license header (#6684)

* Java 17 and some code optimisations

* Requested changes

* Improve examples

* Requested changes

* Minor logic change for changer

* chezburger simplified

---------

Co-authored-by: Moderocky <[email protected]>
Co-authored-by: sovdee <[email protected]>
  • Loading branch information
3 people authored Nov 23, 2024
1 parent 59b1ff4 commit 541dc12
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 38 deletions.
128 changes: 91 additions & 37 deletions src/main/java/ch/njol/skript/expressions/ExprMaxStack.java
Original file line number Diff line number Diff line change
@@ -1,62 +1,116 @@
/**
* This file is part of Skript.
*
* Skript is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Skript is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Skript. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright Peter Güttinger, SkriptLang team and contributors
*/
package ch.njol.skript.expressions;

import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.event.Event;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.Nullable;

import ch.njol.skript.Skript;
import ch.njol.skript.aliases.ItemType;
import ch.njol.skript.classes.Changer.ChangeMode;
import ch.njol.skript.doc.Description;
import ch.njol.skript.doc.Examples;
import ch.njol.skript.doc.Name;
import ch.njol.skript.doc.RequiredPlugins;
import ch.njol.skript.doc.Since;
import ch.njol.skript.expressions.base.SimplePropertyExpression;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import ch.njol.util.Math2;
import ch.njol.util.coll.CollectionUtils;

/**
* @author joeuguce99
*/
@Name("Maximum Stack Size")
@Description("The maximum stack size of the specified material, e.g. 64 for torches, 16 for buckets, and 1 for swords.")
@Examples("send \"You can only pick up %max stack size of player's tool% of %type of (player's tool)%\" to player")
@Since("2.1")
public class ExprMaxStack extends SimplePropertyExpression<ItemType, Long> {
@Description({
"The maximum stack size of an item (e.g. 64 for torches, 16 for buckets, 1 for swords, etc.) or inventory.",
"In 1.20.5+, the maximum stack size of items can be changed to any integer from 1 to 99, and stacked up to the maximum stack size of the inventory they're in."
})
@Examples({
"send \"You can hold %max stack size of player's tool% of %type of player's tool% in a slot.\" to player",
"set the maximum stack size of inventory of all players to 16",
"add 8 to the maximum stack size of player's tool",
"reset the maximum stack size of {_gui}"
})
@Since("2.1, INSERT VERSION (changeable, inventories)")
@RequiredPlugins("Spigot 1.20.5+ (changeable)")
public class ExprMaxStack extends SimplePropertyExpression<Object, Integer> {

static {
register(ExprMaxStack.class, Long.class, "max[imum] stack[[ ]size]", "itemtype");
register(ExprMaxStack.class, Integer.class, "max[imum] stack[[ ]size]", "itemtypes/inventories");
}

@SuppressWarnings("null")

private static final boolean CHANGEABLE_ITEM_STACK_SIZE = Skript.methodExists(ItemMeta.class, "setMaxStackSize", Integer.class);

@Override
public Long convert(ItemType itemType) {
Object random = itemType.getRandomStackOrMaterial();
if (random instanceof Material)
return (long) ((Material) random).getMaxStackSize();
return (long) ((ItemStack) random).getMaxStackSize();
public @Nullable Integer convert(Object from) {
if (from instanceof ItemType itemType)
return getMaxStackSize(itemType);
if (from instanceof Inventory inventory)
return inventory.getMaxStackSize();
return null;
}

@Override
public Class<? extends Long> getReturnType() {
return Long.class;
public @Nullable Class<?>[] acceptChange(ChangeMode mode) {
return switch (mode) {
case ADD, REMOVE, RESET, SET -> {
if (!CHANGEABLE_ITEM_STACK_SIZE && ItemType.class.isAssignableFrom(getExpr().getReturnType())) {
Skript.error("Changing the maximum stack size of items requires Minecraft 1.20.5 or newer!");
yield null;
}
yield CollectionUtils.array(Integer.class);
}
default -> null;
};
}

@Override
public void change(Event event, Object @Nullable [] delta, ChangeMode mode) {
int change = delta == null ? 0 : ((Number) delta[0]).intValue();
for (Object source : getExpr().getArray(event)) {
if (source instanceof ItemType itemType) {
if (!CHANGEABLE_ITEM_STACK_SIZE)
continue;
int size = getMaxStackSize(itemType);
switch (mode) {
case ADD -> size += change;
case SET -> size = change;
case REMOVE -> size -= change;
}
ItemMeta meta = itemType.getItemMeta();
// Minecraft only accepts stack size from 1 to 99
meta.setMaxStackSize(mode != ChangeMode.RESET ? Math2.fit(1, size, 99) : null);
itemType.setItemMeta(meta);
} else if (source instanceof Inventory inventory) {
int size = inventory.getMaxStackSize();
switch (mode) {
case ADD -> size += change;
case SET -> size = change;
case REMOVE -> size -= change;
case RESET -> size = Bukkit.createInventory(null, inventory.getType()).getMaxStackSize();
}
inventory.setMaxStackSize(size);
}
}
}

@Override
public Class<? extends Integer> getReturnType() {
return Integer.class;
}

@Override
protected String getPropertyName() {
return "maximum stack size";
}

private static int getMaxStackSize(ItemType itemType) {
Object item = itemType.getRandomStackOrMaterial();
if (item instanceof ItemStack stack)
return stack.getMaxStackSize();
if (item instanceof Material material)
return material.getMaxStackSize();
throw new UnsupportedOperationException();
}

}
62 changes: 61 additions & 1 deletion src/test/skript/tests/syntaxes/expressions/ExprMaxStack.sk
Original file line number Diff line number Diff line change
@@ -1,4 +1,64 @@
test "max stack":
test "max stack - itemtype":
assert max stack size of diamond sword is 1 with "diamond sword max stack size failed"
assert max stack size of bucket is 16 with "bucket max stack size failed"
assert max stack size of dirt is 64 with "dirt max stack size failed"

# edge case
assert max stack size of {_null} is not set with "max stack size of non itemtype expected to fail ##1"
assert max stack size of {_null} is 0 to fail with "max stack size of non itemtype expected to fail ##2"
assert max stack size of diamond and diamond sword is 64 and 1 with "max stack size of itemtypes 'and' case failed"
assert max stack size of diamond or diamond sword is 64 or 1 with "max stack size of itemtypes 'or' case failed"
loop any log and any wool:
assert max stack size of loop-value is 64 with "max stack size of category itemtypes (%loop-value%) failed"

test "max stack override - itemtype" when running minecraft "1.20.5":
set {_item} to diamond
set max stack size of {_item} to 32
assert max stack size of {_item} is 32 with "diamond should have max stack size of 32"
add 2 to max stack size of {_item}
assert max stack size of {_item} is 34 with "diamond should have max stack size of 34"
remove 4 from max stack size of {_item}
assert max stack size of {_item} is 30 with "diamond should have max stack size of 30"
reset max stack size of {_item}
assert max stack size of {_item} is 64 with "diamond should have max stack size of 64"

set {_item} to bucket
set max stack size of {_item} to 24
assert max stack size of {_item} is 24 with "bucket should have max stack size of 24"
add 2 to max stack size of {_item}
assert max stack size of {_item} is 26 with "bucket should have max stack size of 26"
remove 4 from max stack size of {_item}
assert max stack size of {_item} is 22 with "bucket should have max stack size of 22"
reset max stack size of {_item}
assert max stack size of {_item} is 16 with "bucket should have max stack size of 16"

set {_item} to diamond sword
set max stack size of {_item} to 16
assert max stack size of {_item} is 16 with "diamond sword should have max stack size of 16"
add 2 to max stack size of {_item}
assert max stack size of {_item} is 18 with "diamond sword should have max stack size of 18"
remove 4 from max stack size of {_item}
assert max stack size of {_item} is 14 with "diamond sword should have max stack size of 14"
reset max stack size of {_item}
assert max stack size of {_item} is 1 with "diamond sword should have max stack size of 1"

# edge case
loop any log and any wool:
set {_edge} to loop-value
set max stack size of {_edge} to 1
assert max stack size of {_edge} is 1 with "max stack size override of category itemtypes (%{_edge}%) failed"

test "max stack override - inventory":
set {_default} to 99 # 1.20.5 and newer
if running below minecraft "1.20.5":
set {_default} to 64
set {_inv} to a new chest inventory with 1 rows
assert max stack size of {_inv} is {_default} with "inventory should have max stack size of %{_default}%"
set max stack size of {_inv} to 32
assert max stack size of {_inv} is 32 with "inventory should have max stack size of 32"
add 2 to max stack size of {_inv}
assert max stack size of {_inv} is 34 with "inventory should have max stack size of 34"
remove 4 from max stack size of {_inv}
assert max stack size of {_inv} is 30 with "inventory should have max stack size of 30"
reset max stack size of {_inv}
assert max stack size of {_inv} is {_default} with "inventory should have factory max stack size of %{_default}%"

0 comments on commit 541dc12

Please sign in to comment.