-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a PlaceholderExpansion to check light level
- Loading branch information
Showing
4 changed files
with
261 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,3 +21,5 @@ | |
|
||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml | ||
hs_err_pid* | ||
|
||
target/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
|
||
# CheckLightExpansion | ||
|
||
Expose a placeholder to check if the player as a specific light in inventory. | ||
|
||
## Properties and action | ||
|
||
The placeholder checklight expose 2 properties : | ||
- level : It specify the level of light wanted. It can be a value between 1 and 15 or "no" for no nbt level | ||
- amount : The quantity wanted | ||
|
||
And one action : | ||
- remove : Remove the items matching the expectation. | ||
|
||
## Output | ||
|
||
The placeholder will output "no" if the placeholder can't find the wanted lights and "yes" if it can; | ||
|
||
## Examples | ||
|
||
`%checklight_level:2_amount:5%` -> Check the player have 5 light with level 2 | ||
`%checklight_level:2_level:no_amount:5%` -> Check the player have 5 light with level 2 or without nbt level | ||
`%checklight_remove_level:2_amount:5%` -> Check the player have 5 light with level 2 and remove them |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<groupId>fr.freebuild.papi.expansion.checklight</groupId> | ||
<artifactId>checklight-expansion</artifactId> | ||
<version>1.0.0</version> | ||
|
||
<name>PAPI-Expansion-CheckLight</name> | ||
<description>PlaceholderAPI expansion to check light</description> | ||
|
||
<properties> | ||
<maven.compiler.source>1.8</maven.compiler.source> | ||
<maven.compiler.target>1.8</maven.compiler.target> | ||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
</properties> | ||
|
||
<repositories> | ||
<repository> | ||
<id>spigot-repo</id> | ||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url> | ||
</repository> | ||
<repository> | ||
<id>placeholderapi</id> | ||
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url> | ||
</repository> | ||
</repositories> | ||
|
||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.spigotmc</groupId> | ||
<artifactId>spigot-api</artifactId> | ||
<version>1.19.3-R0.1-SNAPSHOT</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>me.clip</groupId> | ||
<artifactId>placeholderapi</artifactId> | ||
<version>2.11.2</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-jar-plugin</artifactId> | ||
<version>2.3.2</version> | ||
<configuration> | ||
<finalName>${project.name}</finalName> | ||
<archive> | ||
<manifest> | ||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries> | ||
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> | ||
</manifest> | ||
</archive> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</project> | ||
|
173 changes: 173 additions & 0 deletions
173
src/main/java/fr/freebuild/papi/expansion/checklight/CheckLightExpansion.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
package fr.freebuild.papi.expansion.checklight; | ||
|
||
import java.lang.reflect.InvocationTargetException; | ||
import java.lang.reflect.Method; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import org.bukkit.Bukkit; | ||
import org.bukkit.Material; | ||
import org.bukkit.entity.Player; | ||
import org.bukkit.inventory.ItemStack; | ||
|
||
import me.clip.placeholderapi.expansion.PlaceholderExpansion; | ||
|
||
public class CheckLightExpansion extends PlaceholderExpansion { | ||
|
||
private String craftItemStackPath; | ||
|
||
|
||
public CheckLightExpansion() { | ||
String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; | ||
this.craftItemStackPath = "org.bukkit.craftbukkit." + version + ".inventory.CraftItemStack"; | ||
} | ||
|
||
@Override | ||
public String getAuthor() { | ||
return "Freebuild"; | ||
} | ||
|
||
@Override | ||
public String getIdentifier() { | ||
return "checklight"; | ||
} | ||
|
||
@Override | ||
public String getVersion() { | ||
return "1.0.0"; | ||
} | ||
|
||
private class ParsingFailedException extends Exception { | ||
public ParsingFailedException(String message) { | ||
super(message); | ||
} | ||
} | ||
|
||
/** | ||
* Expose a placeholder to check if the player as a specific light in inventory. | ||
* | ||
* The placeholder checklight expose 2 properties : | ||
* - level : It specify the level of light wanted. It can be a value between 1 and 15 or "no" for no nbt level | ||
* - amount : The quantity wanted | ||
* And one action : | ||
* - remove : Remove it if it match the expectation. | ||
* | ||
* Examples : | ||
* %checklight_level:2_amount:5% -> Check the player have 5 light with level 2 | ||
* %checklight_level:2_level:no_amount:5% -> Check the player have 5 light with level 2 or without nbt level | ||
* %checklight_remove_level:2_amount:5% -> Check the player have 5 light with level 2 and remove them | ||
*/ | ||
@Override | ||
public String onPlaceholderRequest(Player player, String param) { | ||
if (player == null) | ||
return null; | ||
|
||
try { | ||
return handleRequest(player, param.split("_")); | ||
} catch (ParsingFailedException e) { | ||
return e.getMessage(); | ||
} | ||
} | ||
|
||
private String handleRequest(Player player, String[] args) throws ParsingFailedException { | ||
|
||
List<Integer> levels = new ArrayList<>(); | ||
Integer amount = 1; | ||
Boolean remove = false; | ||
for (int i = 0; i < args.length; i++) { | ||
if (args[i].equalsIgnoreCase("remove")) | ||
remove = true; | ||
if (args[i].startsWith("level:")) | ||
levels.add(parseIntArg(args[i], "level", 0, 15)); | ||
if (args[i].startsWith("amount:")) | ||
amount = parseIntArg(args[i], "amount", 1, null); | ||
} | ||
|
||
ItemStack[] contents = player.getInventory().getContents(); | ||
|
||
Integer remaining = amount; | ||
List<ItemStack> toDelete = new ArrayList<>(); | ||
|
||
for (int i = 0; i < contents.length && remaining > 0; i++) { | ||
ItemStack item = contents[i]; | ||
|
||
if(item != null && item.getType() == Material.LIGHT) { | ||
try { | ||
Integer lightLevel = getNbtLevel(item); | ||
if (levels.stream().anyMatch(level -> lightLevel == level)) { | ||
Integer amountToRemove = Math.min(remaining, item.getAmount()); | ||
remaining -= amountToRemove; | ||
ItemStack itemToDelete = item.clone(); | ||
itemToDelete.setAmount(amountToRemove); | ||
toDelete.add(itemToDelete); | ||
} | ||
} catch (Exception e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
} | ||
|
||
if (remove && remaining <= 0) { | ||
toDelete.forEach(it -> player.getInventory().removeItem(it)); | ||
} | ||
|
||
return (remaining > 0) ? "no" : "yes"; | ||
} | ||
|
||
private Integer parseIntArg(String arg, String name, Integer start, Integer end) throws ParsingFailedException { | ||
try { | ||
String value = arg.substring(name.length() + 1); | ||
if (value.equals("no")) | ||
return null; | ||
Integer num = Integer.parseInt(value); | ||
if (start != null && num < start) { | ||
num = start; | ||
} | ||
if (end != null && num > end) { | ||
num = end; | ||
} | ||
return num; | ||
} catch (Exception e) { | ||
e.printStackTrace(); | ||
throw new ParsingFailedException(String.format("Invalid value for %s. Expecting: %<s:15 Got: %$", name, arg)); | ||
} | ||
} | ||
|
||
private Integer getNbtLevel(ItemStack itemStack) throws Exception { | ||
Method asNMSCopy = Class.forName(this.craftItemStackPath).getDeclaredMethod("asNMSCopy", ItemStack.class); | ||
Object nmsItemStack = asNMSCopy.invoke(null, itemStack); | ||
|
||
Object nbtCompound = invokeMethod(nmsItemStack, "u"); | ||
if (nbtCompound != null) { | ||
|
||
Object blockState = invokeMethod(nbtCompound, "c", "BlockStateTag"); | ||
if (blockState != null) { | ||
Object levl = invokeMethod(blockState, "c", "level"); | ||
return Integer.parseInt(levl.toString().replace("\"", "")); | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
private Object invokeMethod(Object object, String method, Object... args) { | ||
try { | ||
return object.getClass().getMethod(method, fromObjectToClass(args)).invoke(object, args); | ||
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { | ||
e.printStackTrace(); | ||
} | ||
return null; | ||
} | ||
|
||
|
||
private Class<?>[] fromObjectToClass(Object[] args) { | ||
Class<?>[] classes = new Class<?>[0]; | ||
|
||
if (args != null) { | ||
classes = new Class<?>[args.length]; | ||
for (int i = 0; i < args.length; i++) { | ||
classes[i] = args[i].getClass(); | ||
} | ||
} | ||
return classes; | ||
} | ||
} |