Skip to content

Commit

Permalink
Registry ClassInfo Utility (#6695)
Browse files Browse the repository at this point in the history
  • Loading branch information
ShaneBeee authored Jun 21, 2024
1 parent 7dcf34a commit 34b303b
Show file tree
Hide file tree
Showing 4 changed files with 302 additions and 3 deletions.
14 changes: 11 additions & 3 deletions src/main/java/ch/njol/skript/classes/data/BukkitClasses.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.Registry;
import org.bukkit.SoundCategory;
import org.bukkit.World;
import org.bukkit.World.Environment;
Expand Down Expand Up @@ -77,7 +78,6 @@
import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.CachedServerIcon;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.Nullable;

import ch.njol.skript.Skript;
import ch.njol.skript.SkriptConfig;
Expand All @@ -90,6 +90,7 @@
import ch.njol.skript.classes.EnumClassInfo;
import ch.njol.skript.classes.Parser;
import ch.njol.skript.classes.Serializer;
import ch.njol.skript.classes.registry.RegistryClassInfo;
import ch.njol.skript.entity.EntityData;
import ch.njol.skript.expressions.ExprDamageCause;
import ch.njol.skript.expressions.base.EventValueExpression;
Expand All @@ -104,6 +105,7 @@
import ch.njol.util.StringUtils;
import ch.njol.yggdrasil.Fields;
import io.papermc.paper.world.MoonPhase;
import org.jetbrains.annotations.Nullable;

/**
* @author Peter Güttinger
Expand Down Expand Up @@ -976,8 +978,14 @@ public String toVariableNameString(final ItemStack i) {
.name(ClassInfo.NO_DOC)
.since("2.0")
.changer(DefaultChangers.itemChanger));

Classes.registerClass(new EnumClassInfo<>(Biome.class, "biome", "biomes")

ClassInfo<?> biomeClassInfo;
if (Skript.classExists("org.bukkit.Registry") && Skript.fieldExists(Registry.class, "BIOME")) {
biomeClassInfo = new RegistryClassInfo<>(Biome.class, Registry.BIOME, "biome", "biomes");
} else {
biomeClassInfo = new EnumClassInfo<>(Biome.class, "biome", "biomes");
}
Classes.registerClass(biomeClassInfo
.user("biomes?")
.name("Biome")
.description("All possible biomes Minecraft uses to generate a world.")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* 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.classes.registry;

import ch.njol.skript.classes.ClassInfo;
import ch.njol.skript.expressions.base.EventValueExpression;
import ch.njol.skript.lang.DefaultExpression;
import org.bukkit.Keyed;
import org.bukkit.Registry;

/**
* This class can be used for easily creating ClassInfos for {@link Registry}s.
* It registers a language node with usage, a serializer, default expression, and a parser.
*
* @param <R> The Registry class.
*/
public class RegistryClassInfo<R extends Keyed> extends ClassInfo<R> {

public RegistryClassInfo(Class<R> registryClass, Registry<R> registry, String codeName, String languageNode) {
this(registryClass, registry, codeName, languageNode, new EventValueExpression<>(registryClass));
}

/**
* @param registry The registry
* @param codeName The name used in patterns
*/
public RegistryClassInfo(Class<R> registryClass, Registry<R> registry, String codeName, String languageNode, DefaultExpression<R> defaultExpression) {
super(registryClass, codeName);
RegistryParser<R> registryParser = new RegistryParser<>(registry, languageNode);
usage(registryParser.getAllNames())
.supplier(registry::iterator)
.serializer(new RegistrySerializer<R>(registry))
.defaultExpression(defaultExpression)
.parser(registryParser);
}

}
155 changes: 155 additions & 0 deletions src/main/java/ch/njol/skript/classes/registry/RegistryParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/**
* 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.classes.registry;

import ch.njol.skript.classes.Parser;
import ch.njol.skript.lang.ParseContext;
import ch.njol.skript.localization.Language;
import ch.njol.skript.localization.Noun;
import ch.njol.util.NonNullPair;
import ch.njol.util.StringUtils;
import org.bukkit.Keyed;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
* A parser based on a {@link Registry} used to parse data from a string or turn data into a string.
*
* @param <R> Registry class
*/
public class RegistryParser<R extends Keyed> extends Parser<R> {

private final Registry<R> registry;
private final String languageNode;

private final Map<R, String> names = new HashMap<>();
private final Map<String, R> parseMap = new HashMap<>();

public RegistryParser(Registry<R> registry, String languageNode) {
assert !languageNode.isEmpty() && !languageNode.endsWith(".") : languageNode;
this.registry = registry;
this.languageNode = languageNode;
refresh();
Language.addListener(this::refresh);
}

private void refresh() {
names.clear();
parseMap.clear();
for (R registryObject : registry) {
NamespacedKey namespacedKey = registryObject.getKey();
String namespace = namespacedKey.getNamespace();
String key = namespacedKey.getKey();
String keyWithSpaces = key.replace("_", " ");
String languageKey = languageNode + "." + key;

// Put the full namespaced key as a pattern
parseMap.put(namespacedKey.toString(), registryObject);

// If the object is a vanilla Minecraft object, we'll add the key with spaces as a pattern
if (namespace.equalsIgnoreCase(NamespacedKey.MINECRAFT)) {
parseMap.put(keyWithSpaces, registryObject);
}

String[] options = Language.getList(languageKey);
// Missing/Custom registry objects
if (options.length == 1 && options[0].equals(languageKey.toLowerCase(Locale.ENGLISH))) {
if (namespace.equalsIgnoreCase(NamespacedKey.MINECRAFT)) {
// If the object is a vanilla Minecraft object, we'll use the key with spaces as a name
names.put(registryObject, keyWithSpaces);
} else {
// If the object is a custom object, we'll use the full namespaced key as a name
names.put(registryObject, namespacedKey.toString());
}
} else {
for (String option : options) {
option = option.toLowerCase(Locale.ENGLISH);

// Isolate the gender if one is present
NonNullPair<String, Integer> strippedOption = Noun.stripGender(option, languageKey);
String first = strippedOption.getFirst();
Integer second = strippedOption.getSecond();

// Add to name map if needed
names.putIfAbsent(registryObject, first);

parseMap.put(first, registryObject);
if (second != -1) { // There is a gender present
parseMap.put(Noun.getArticleWithSpace(second, Language.F_INDEFINITE_ARTICLE) + first, registryObject);
}
}
}
}
}

/**
* This method attempts to match the string input against one of the string representations of the registry.
*
* @param input a string to attempt to match against one in the registry.
* @param context of parsing, may not be null
* @return The registry object matching the input, or null if no match could be made.
*/
@Override
public @Nullable R parse(String input, @NotNull ParseContext context) {
return parseMap.get(input.toLowerCase(Locale.ENGLISH));
}

/**
* This method returns the string representation of a registry.
*
* @param object The object to represent as a string.
* @param flags not currently used
* @return A string representation of the registry object.
*/
@Override
public @NotNull String toString(R object, int flags) {
return names.get(object);
}

/**
* Returns a registry object's string representation in a variable name.
*
* @param object Object to represent in a variable name.
* @return The given object's representation in a variable name.
*/
@Override
public @NotNull String toVariableNameString(R object) {
return toString(object, 0);
}

/**
* @return A comma-separated string containing a list of all names representing the registry.
* Note that some entries may represent the same registry object.
*/
public String getAllNames() {
List<String> strings = new ArrayList<>(parseMap.keySet());
Collections.sort(strings);
return StringUtils.join(strings, ", ");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* 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.classes.registry;

import ch.njol.skript.classes.Serializer;
import ch.njol.yggdrasil.Fields;
import org.bukkit.Keyed;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;

import java.io.StreamCorruptedException;

/**
* Serializer for {@link RegistryClassInfo}
*
* @param <R> Registry class
*/
public class RegistrySerializer<R extends Keyed> extends Serializer<R> {

private final Registry<R> registry;

public RegistrySerializer(Registry<R> registry) {
this.registry = registry;
}

@Override
public Fields serialize(R o) {
Fields fields = new Fields();
fields.putPrimitive("name", o.getKey().toString());
return null;
}

@Override
protected R deserialize(Fields fields) {
try {
String name = fields.getAndRemovePrimitive("name", String.class);
NamespacedKey namespacedKey;
if (!name.contains(":")) {
// Old variables
namespacedKey = NamespacedKey.minecraft(name);
} else {
namespacedKey = NamespacedKey.fromString(name);
}
if (namespacedKey == null)
return null;
return registry.get(namespacedKey);
} catch (StreamCorruptedException e) {
return null;
}
}

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

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

@Override
public void deserialize(R o, Fields f) {
throw new UnsupportedOperationException();
}

}

0 comments on commit 34b303b

Please sign in to comment.