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

PotionEffectType overhaul #7364

Merged
merged 13 commits into from
Jan 9, 2025
Merged
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
18 changes: 18 additions & 0 deletions src/main/java/ch/njol/skript/bukkitutil/BukkitUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import ch.njol.skript.Skript;
import org.bukkit.Registry;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.Nullable;

/**
* Utility class with methods pertaining to Bukkit API
Expand All @@ -18,4 +20,20 @@ public static boolean registryExists(String registry) {
return Skript.classExists("org.bukkit.Registry") && Skript.fieldExists(Registry.class, registry);
}

/**
* Get an instance of the {@link PotionEffectType} {@link Registry}
* <p>Paper/Bukkit have 2 different names for the same registry.</p>
*
* @return PotionEffectType Registry
*/
@SuppressWarnings("NullableProblems")
public static @Nullable Registry<PotionEffectType> getPotionEffectTypeRegistry() {
if (registryExists("MOB_EFFECT")) { // Paper (1.21.4)
return Registry.MOB_EFFECT;
} else if (registryExists("EFFECT")) { // Bukkit (1.21.x)
return Registry.EFFECT;
}
return null;
ShaneBeee marked this conversation as resolved.
Show resolved Hide resolved
}

}
74 changes: 10 additions & 64 deletions src/main/java/ch/njol/skript/classes/data/BukkitClasses.java
Original file line number Diff line number Diff line change
Expand Up @@ -1015,73 +1015,19 @@ protected boolean canBeInstantiated() {
}
}));

Classes.registerClass(new ClassInfo<>(PotionEffectType.class, "potioneffecttype")
.user("potion( ?effect)? ?types?") // "type" had to be made non-optional to prevent clashing with potion effects
Registry<PotionEffectType> petRegistry = BukkitUtils.getPotionEffectTypeRegistry();
if (petRegistry != null) {
ShaneBeee marked this conversation as resolved.
Show resolved Hide resolved
Classes.registerClass(new RegistryClassInfo<>(PotionEffectType.class, petRegistry, "potioneffecttype", "potion effect types", false)
.user("potion( ?effect)? ?types?")
.name("Potion Effect Type")
.description("A potion effect type, e.g. 'strength' or 'swiftness'.")
.usage(StringUtils.join(PotionEffectUtils.getNames(), ", "))
.examples("apply swiftness 5 to the player",
"apply potion of speed 2 to the player for 60 seconds",
"remove invisibility from the victim")
.since("")
.supplier(PotionEffectType.values())
.parser(new Parser<PotionEffectType>() {
@Override
@Nullable
public PotionEffectType parse(final String s, final ParseContext context) {
return PotionEffectUtils.parseType(s);
}

@Override
public String toString(final PotionEffectType p, final int flags) {
return PotionEffectUtils.toString(p, flags);
}

@Override
public String toVariableNameString(final PotionEffectType p) {
return "" + p.getName();
}
})
.serializer(new Serializer<PotionEffectType>() {
@Override
public Fields serialize(final PotionEffectType o) {
final Fields f = new Fields();
f.putObject("name", o.getName());
return f;
}

@Override
public boolean canBeInstantiated() {
return false;
}

@Override
public void deserialize(final PotionEffectType o, final Fields f) {
assert false;
}

@Override
protected PotionEffectType deserialize(final Fields fields) throws StreamCorruptedException {
final String name = fields.getObject("name", String.class);
assert name != null;
final PotionEffectType t = PotionEffectType.getByName(name);
if (t == null)
throw new StreamCorruptedException("Invalid PotionEffectType " + name);
return t;
}

// return o.getName();
@Override
@Nullable
public PotionEffectType deserialize(final String s) {
return PotionEffectType.getByName(s);
}

@Override
public boolean mustSyncDeserialization() {
return false;
}
}));
"apply potion of speed 2 to the player for 60 seconds",
"remove invisibility from the victim")
.since(""));
} else {
Classes.registerClass(PotionEffectUtils.getLegacyClassInfo());
}

// REMIND make my own damage cause class (that e.g. stores the attacker entity, the projectile, or the attacking block)
Classes.registerClass(new EnumClassInfo<>(DamageCause.class, "damagecause", "damage causes", new ExprDamageCause())
Expand Down
120 changes: 95 additions & 25 deletions src/main/java/ch/njol/skript/util/PotionEffectUtils.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package ch.njol.skript.util;

import java.io.StreamCorruptedException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import ch.njol.skript.classes.ClassInfo;
import ch.njol.skript.classes.Parser;
import ch.njol.skript.classes.Serializer;
import ch.njol.skript.lang.ParseContext;
import ch.njol.util.StringUtils;
import ch.njol.yggdrasil.Fields;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.PotionMeta;
Expand All @@ -14,6 +21,7 @@
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.potion.PotionType;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;

import ch.njol.skript.Skript;
Expand All @@ -29,32 +37,18 @@ public abstract class PotionEffectUtils {
private PotionEffectUtils() {}

final static Map<String, PotionEffectType> types = new HashMap<>();

final static String[] names = new String[getMaxPotionId() + 1];

// MCPC+ workaround
private static int getMaxPotionId() {
int i = 0;
for (final PotionEffectType t : PotionEffectType.values()) {
if (t != null && t.getId() > i)
i = t.getId();
}
return i;
}
private final static Map<String, String> names = new HashMap<>();

static {
Language.addListener(() -> {
types.clear();
for (final PotionEffectType t : PotionEffectType.values()) {
if (t == null)
continue;
String name = t.getName();
if (name.startsWith("minecraft:")) // seems to be the case for experimental entries...
name = name.substring(10); // trim off namespace
final String[] ls = Language.getList("potions." + name);
names[t.getId()] = ls[0];
for (final String l : ls) {
types.put(l.toLowerCase(Locale.ENGLISH), t);
names.clear();
for (final PotionEffectType potionEffectType : PotionEffectType.values()) {
String key = potionEffectType.getKey().getKey();
final String[] entries = Language.getList("potion effect types." + key);
names.put(key, entries[0]);
for (final String entry : entries) {
types.put(entry.toLowerCase(Locale.ENGLISH), potionEffectType);
}
}
});
Expand All @@ -77,12 +71,12 @@ public static PotionEffectType parseByEffectType(PotionEffectType t) {
}

public static String toString(PotionEffectType t) {
return names[t.getId()];
return names.get(t.getKey().getKey());
}

// REMIND flags?
public static String toString(PotionEffectType t, int flags) {
return names[t.getId()];
return toString(t);
}

public static String toString(PotionEffect potionEffect) {
Expand All @@ -101,7 +95,7 @@ public static String toString(PotionEffect potionEffect) {
}

public static String[] getNames() {
return names;
return names.values().toArray(new String[0]);
}

/**
Expand Down Expand Up @@ -341,4 +335,80 @@ public static List<PotionEffect> getEffects(ItemType itemType) {
return effects;
}

/**
* Legacy class info for PotionEffectType (pre-registry)
*
* @return ClassInfo for PotionEffeectType
*/
@ApiStatus.Internal
public static ClassInfo<PotionEffectType> getLegacyClassInfo() {
ShaneBeee marked this conversation as resolved.
Show resolved Hide resolved
return new ClassInfo<>(PotionEffectType.class, "potioneffecttype")
.user("potion( ?effect)? ?types?") // "type" had to be made non-optional to prevent clashing with potion effects
.name("Potion Effect Type")
.description("A potion effect type, e.g. 'strength' or 'swiftness'.")
.usage(StringUtils.join(getNames(), ", "))
.examples("apply swiftness 5 to the player",
"apply potion of speed 2 to the player for 60 seconds",
"remove invisibility from the victim")
.since("")
.supplier(PotionEffectType.values())
.parser(new Parser<>() {
@Override
@Nullable
public PotionEffectType parse(final String string, final ParseContext context) {
return parseType(string);
}

@Override
public String toString(final PotionEffectType potionEffectType, final int flags) {
return PotionEffectUtils.toString(potionEffectType, flags);
}

@Override
public String toVariableNameString(final PotionEffectType potionEffectType) {
return toString(potionEffectType, 0);
}
})
.serializer(new Serializer<>() {
@Override
public Fields serialize(final PotionEffectType potionEffectType) {
final Fields f = new Fields();
f.putObject("name", potionEffectType.getKey().getKey());
return f;
}

@Override
public boolean canBeInstantiated() {
return false;
}

@Override
public void deserialize(final PotionEffectType o, final Fields f) {
assert false;
}
APickledWalrus marked this conversation as resolved.
Show resolved Hide resolved

@Override
protected PotionEffectType deserialize(final Fields fields) throws StreamCorruptedException {
final String name = fields.getObject("name", String.class);
assert name != null;
final PotionEffectType t = PotionEffectType.getByName(name);
if (t == null)
throw new StreamCorruptedException("Invalid PotionEffectType " + name);
return t;
}

// return o.getName();
@Override
@Nullable
public PotionEffectType deserialize(final String s) {
return PotionEffectType.getByName(s);
}

@Override
public boolean mustSyncDeserialization() {
return false;
}
});
}

}
22 changes: 11 additions & 11 deletions src/main/resources/lang/default.lang
Original file line number Diff line number Diff line change
Expand Up @@ -99,19 +99,19 @@ enchantments:
breach: Breach
wind_burst: Wind Burst

# -- Potion Effects --
potions:
# -- Potion Effect Types --
potion effect types:
speed: speed, swiftness
slow: slowness, slow
fast_digging: haste, fast digging, fast mining
slow_digging: mining fatigue, slow digging, slow mining
increase_damage: strength, increase damage, increased damage
heal: instant health, health
harm: instant damage, damage
jump: jump boost, jump
confusion: nausea, confusion
slowness: slowness, slow
haste: haste, fast digging, fast mining
mining_fatigue: mining fatigue, slow digging, slow mining
strength: strength, increase damage, increased damage
instant_health: instant health, health
instant_damage: instant damage, damage
jump_boost: jump boost, jump
nausea: nausea, confusion
regeneration: regeneration
damage_resistance: resistance, damage resistance
resistance: resistance, damage resistance
fire_resistance: fire resistance, fire immunity
water_breathing: water breathing
invisibility: invisibility
Expand Down
Loading