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

Adds destroyable/placeable key syntaxes #6494

Draft
wants to merge 53 commits into
base: dev/feature
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
7c4dba1
Initial commit.
cheeezburga Mar 14, 2024
d9d4e18
Formatting change.
cheeezburga Mar 14, 2024
2962c50
Change annotations
cheeezburga Mar 14, 2024
9ca4fff
Fix up some iffy logic
cheeezburga Mar 14, 2024
2a49d62
Change annotations
cheeezburga Mar 14, 2024
0020353
Add blank space at end of file
cheeezburga Mar 14, 2024
d0807e3
Add blank space at end of file
cheeezburga Mar 14, 2024
b329d99
Fixed up some stuff with the conditions.
cheeezburga Mar 14, 2024
496b2f4
Merge remote-tracking branch 'origin/destroyable-placeable-keys' into…
cheeezburga Mar 14, 2024
deaad20
Fixed wrong method being called.
cheeezburga Mar 14, 2024
f5f891f
Fixed some stuff with the effects.
cheeezburga Mar 15, 2024
ef2f49a
Fixed stuff with the expressions.
cheeezburga Mar 15, 2024
59cdead
Added methodExists() checks in expressions.
cheeezburga Mar 15, 2024
831aee8
Renamed and merged destroyable/placeable keys expressions into ExprBu…
cheeezburga Mar 16, 2024
a7a9677
Changed back methodExists() check to the correct method.
cheeezburga Mar 16, 2024
81886b1
Renamed and merged effects into EffBuildRestrictions. Small change to…
cheeezburga Mar 16, 2024
4d023c5
Renamed and merged conditions into CondHasBuildRestrictions.
cheeezburga Mar 17, 2024
6fb3d8b
Deleted old condition class.
cheeezburga Mar 17, 2024
a102fb3
Small changes.
cheeezburga Mar 18, 2024
770c84c
Big changes to condition.
cheeezburga Mar 20, 2024
8837814
Removed unused import.
cheeezburga Mar 20, 2024
8797c9a
Update src/main/java/ch/njol/skript/conditions/CondHasBuildRestrictio…
cheeezburga Mar 22, 2024
b1994d0
Update src/main/java/ch/njol/skript/conditions/CondHasBuildRestrictio…
cheeezburga Mar 22, 2024
30e0cee
Update src/main/java/ch/njol/skript/conditions/CondHasBuildRestrictio…
cheeezburga Mar 22, 2024
60db683
Update src/main/java/ch/njol/skript/effects/EffBuildRestrictions.java
cheeezburga Mar 22, 2024
6052e1a
Some changes and fixes
cheeezburga Mar 22, 2024
5c36cc4
Changes and fixes to the condition
cheeezburga Mar 22, 2024
1a7c06e
Changes and fixes to the expression
cheeezburga Mar 24, 2024
7861e72
Renamed to adventure restrictions and fixed examples
cheeezburga Mar 24, 2024
7c938c9
Added license at top.
cheeezburga Mar 25, 2024
7bebc7e
Apply suggestions from code review
cheeezburga Mar 25, 2024
bdd65cd
Merge remote-tracking branch 'origin/destroyable-placeable-keys' into…
cheeezburga Mar 25, 2024
9f7c6a5
Changes and fixes to the effect
cheeezburga Apr 7, 2024
152d26b
Changes and fixes to the expression
cheeezburga Apr 7, 2024
50d6368
Changes and fixes to the condition
cheeezburga Apr 7, 2024
f1b23cd
Merge branch 'dev/feature' into destroyable-placeable-keys
cheeezburga Apr 7, 2024
d8b8790
Merge branch 'dev/feature' into destroyable-placeable-keys
Moderocky Apr 7, 2024
0101a02
fix condition, update syntaxes, add test
sovdeeth Apr 14, 2024
57b44d4
Merge branch 'dev/feature' into destroyable-placeable-keys
cheeezburga Apr 14, 2024
0fb61f4
mangrove doesn't exist in 1.13
sovdeeth Apr 14, 2024
6cbaab8
Merge branch 'dev/feature' into destroyable-placeable-keys
cheeezburga Apr 15, 2024
2edf35f
Fixed examples and other small changes to condition
cheeezburga Apr 15, 2024
94621f1
Makes adventure part of pattern required
cheeezburga Apr 22, 2024
c339af1
Apply suggestions from code review
cheeezburga May 8, 2024
5b36886
Update ExprAdventureRestrictions.java
sovdeeth May 8, 2024
1f8af78
Merge branch 'destroyable-placeable-keys' of https://github.com/cheee…
sovdeeth May 8, 2024
265d7b1
Merge branch 'dev/feature' into destroyable-placeable-keys
sovdeeth May 8, 2024
2b9a362
Apply suggestions from code review
cheeezburga May 16, 2024
efd1f2a
Merge branch 'dev/feature' into destroyable-placeable-keys
cheeezburga May 16, 2024
27ba572
Changed syntax classes to use reflection and changed test version
cheeezburga May 16, 2024
aa4b90b
Correct version of CondHasAdventureRestrictions
cheeezburga May 16, 2024
a481600
Small fixes
cheeezburga May 16, 2024
4455636
Merge branch 'dev/feature' into destroyable-placeable-keys
sovdeeth May 28, 2024
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
@@ -0,0 +1,150 @@
/**
* 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.conditions;
cheeezburga marked this conversation as resolved.
Show resolved Hide resolved

import ch.njol.skript.Skript;
import ch.njol.skript.aliases.ItemData;
import ch.njol.skript.aliases.ItemType;
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.lang.Condition;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.util.Kleenean;
import org.bukkit.event.Event;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Set;

@Name("Has Adventure Restrictions")
@Description("Check if an item has any adventure restrictions.")
@Examples({
"player's tool has any build restrictions",
"{_item} doesn't have a break restriction",
"{_item} is able to break (stone and dirt) in adventure mode",
"{_item} can not be placed on diamond ore in adventure"
})
@Since("INSERT VERSION")
@RequiredPlugins("Paper")
public class CondHasAdventureRestrictions extends Condition {

@SuppressWarnings("NotNullFieldNotInitialized")
private static Method DESTROY_HAS, PLACE_HAS, DESTROY_GET, PLACE_GET;

static {

if (Skript.methodExists(ItemMeta.class, "hasDestroyableKeys")) {
Skript.registerCondition(CondHasAdventureRestrictions.class,
"%itemtypes% (has|have) [a|any|:no] (break|place:(build|place)) restriction[s]",
"%itemtypes% (doesn't|does not|do not|don't) have [a|any] (break|place:(build|place)) restriction[s]",
"%itemtypes% (can|is able to) (break|destroy|mine|place:be placed on) %itemtypes% in adventure [mode]",
"%itemtypes% (can't|can[ ]not|is unable to) (break|destroy|mine|place:be placed on) %itemtypes% in adventure [mode]"
);

try {
Class<?> META_CLASS = Class.forName("org.bukkit.inventory.meta.ItemMeta");

DESTROY_HAS = META_CLASS.getDeclaredMethod("hasDestroyableKeys");
PLACE_HAS = META_CLASS.getDeclaredMethod("hasPlaceableKeys");
DESTROY_GET = META_CLASS.getDeclaredMethod("getDestroyableKeys");
PLACE_GET = META_CLASS.getDeclaredMethod("getPlaceableKeys");
} catch (ClassNotFoundException | NoSuchMethodException e) {
assert false: e.getMessage();
}
}

}

@SuppressWarnings("NotNullFieldNotInitialized")
private Expression<ItemType> items;
@Nullable
private Expression<ItemType> keysToCheck;
private boolean place;

@SuppressWarnings("unchecked")
@Override
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
this.items = (Expression<ItemType>) exprs[0];
if (matchedPattern == 2 || matchedPattern == 3)
this.keysToCheck = (Expression<ItemType>) exprs[1];
this.place = parseResult.hasTag("place");
setNegated(matchedPattern == 1 || matchedPattern == 3 || parseResult.hasTag("no"));
return true;
}

@SuppressWarnings("unchecked")
@Override
public boolean check(Event event) {
if (keysToCheck == null) {
return items.check(event, item -> {
try {
return place ? ((boolean) PLACE_HAS.invoke(item.getItemMeta())) : ((boolean) DESTROY_HAS.invoke(item.getItemMeta()));
} catch (IllegalAccessException | InvocationTargetException e) {
return false;
}
}, isNegated());
}

return items.check(event, (itemType) -> {
Set<Object> itemKeys = Collections.EMPTY_SET;
try {
itemKeys = (Set<Object>) (place ? PLACE_GET.invoke(itemType.getItemMeta()) : DESTROY_GET.invoke(itemType.getItemMeta()));
} catch (IllegalAccessException | InvocationTargetException e) {
assert false: e.getMessage();
}

// short circuit if no keys
if (itemKeys.isEmpty())
return false;

// for each key itemtype, if it isAll, we need to ensure every Material is represented in the item's keys
// if it isn't isAll, we need to ensure at least one of the Materials is represented in the item's keys.
Set<Object> finalItemKeys = itemKeys;
return keysToCheck.check(event, (keyItemType) -> {
boolean isAll = keyItemType.isAll();
for (ItemData keyData : keyItemType.getTypes()) {
if (!finalItemKeys.contains(keyData.getType().getKey())) {
// if we're isAll, we can exit out early. Not all keys matched.
if (isAll)
return false;
} else if (!isAll) {
// if we're not isAll, we can exit out early, since one matched.
return true;
}
}
return isAll;
});
}, isNegated());
}

@SuppressWarnings("ConstantConditions")
@Override
public String toString(@Nullable Event event, boolean debug) {
if (keysToCheck == null)
return items.toString(event, debug) + " has" + (isNegated() ? " no" : "") + (place ? " placeable" : " destroyable") + " keys";
return "the" + (place ? " placeable" : " destroyable") + " keys of" + items.toString(event, debug) + (isNegated() ? " do not" : "") + " contain" + keysToCheck.toString(event, debug);
}
}
135 changes: 135 additions & 0 deletions src/main/java/ch/njol/skript/effects/EffAdventureRestrictions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/**
* 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.effects;
cheeezburga marked this conversation as resolved.
Show resolved Hide resolved

import ch.njol.skript.Skript;
import ch.njol.skript.aliases.ItemType;
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.lang.Effect;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.util.Kleenean;
import org.bukkit.event.Event;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

@Name("Apply Adventure Restrictions")
@Description("Allow or prevent an item to destroy or be placed on certain types of blocks while in /gamemode adventure.")
@Examples({
"allow player's tool to destroy (stone, oak wood planks) in adventure mode",
"prevent {_item} from being placed on (diamond ore, diamond block) in adventure"
})
@Since("INSERT VERSION")
@RequiredPlugins("Paper")
public class EffAdventureRestrictions extends Effect {

@SuppressWarnings("NotNullFieldNotInitialized")
private static Method DESTROY_SET, PLACE_SET, DESTROY_GET, PLACE_GET;

static {
if (Skript.methodExists(ItemMeta.class, "setDestroyableKeys", Collection.class)) {
Skript.registerEffect(EffAdventureRestrictions.class,
"allow %~itemtypes% to (destroy|break|mine|place:be placed on) %itemtypes% in adventure [mode]",
"(disallow|prevent) %~itemtypes% from (destroying|breaking|mining|place:being placed on) %itemtypes% in adventure [mode]");

try {
Class<?> META_CLASS = Class.forName("org.bukkit.inventory.meta.ItemMeta");

DESTROY_GET = META_CLASS.getDeclaredMethod("getDestroyableKeys");
PLACE_GET = META_CLASS.getDeclaredMethod("getPlaceableKeys");
DESTROY_SET = META_CLASS.getDeclaredMethod("setDestroyableKeys", Collection.class);
PLACE_SET = META_CLASS.getDeclaredMethod("setPlaceableKeys", Collection.class);
} catch (ClassNotFoundException | NoSuchMethodException e) {
assert false: e.getMessage();
}
}
}

@SuppressWarnings("NotNullFieldNotInitialized")
private Expression<ItemType> items;
@SuppressWarnings("NotNullFieldNotInitialized")
private Expression<ItemType> deltaKeys;
private boolean allow;
private boolean destroy;

@Override
@SuppressWarnings("unchecked")
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
this.items = (Expression<ItemType>) exprs[0];
this.deltaKeys = (Expression<ItemType>) exprs[1];
this.allow = matchedPattern == 0;
this.destroy = !parseResult.hasTag("place");
return true;
}

@SuppressWarnings("unchecked")
@Override
protected void execute(Event event) {
ItemType[] items = this.items.getArray(event);
if (items.length == 0)
return;

Set<Object> keys = new HashSet<>();

for (ItemType itemType : deltaKeys.getArray(event)) {
Iterator<ItemStack> iter = itemType.containerIterator();
while (iter.hasNext()) {
ItemStack stack = iter.next();
keys.add(stack.getType().getKey());
}
}

if (!keys.isEmpty()) {
for (ItemType item : items) {
try {
ItemMeta meta = item.getItemMeta();
Set<Object> existingKeys = new HashSet<>((Set<Object>) (destroy ? DESTROY_GET.invoke(meta) : PLACE_GET.invoke(meta)));
if (allow) {
existingKeys.addAll(keys);
} else {
existingKeys.removeAll(keys);
}
if (destroy) { DESTROY_SET.invoke(meta, existingKeys); } else { PLACE_SET.invoke(meta, existingKeys); }
item.setItemMeta(meta);
} catch (IllegalAccessException | InvocationTargetException e) {
assert false: e.getMessage();
}
}
}
}

@Override
public String toString(@Nullable Event event, boolean debug) {
if (allow)
return "allow " + items.toString(event, debug) + " to " + (destroy ? "destroy " : "be placed on ") + deltaKeys.toString(event, debug);
return "prevent " + items.toString(event, debug) + " from " + (destroy ? "destroying " : "being placed on ") + deltaKeys.toString(event, debug);
}
}
Loading
Loading