diff --git a/src/main/java/com/cleanroommc/groovyscript/GroovyScript.java b/src/main/java/com/cleanroommc/groovyscript/GroovyScript.java index e6f7e4aef..7a8fb9018 100644 --- a/src/main/java/com/cleanroommc/groovyscript/GroovyScript.java +++ b/src/main/java/com/cleanroommc/groovyscript/GroovyScript.java @@ -12,8 +12,9 @@ import com.cleanroommc.groovyscript.documentation.Documentation; import com.cleanroommc.groovyscript.documentation.linkgenerator.LinkGeneratorHooks; import com.cleanroommc.groovyscript.event.EventHandler; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandlerManager; import com.cleanroommc.groovyscript.helper.JsonHelper; +import com.cleanroommc.groovyscript.mapper.ObjectMapper; +import com.cleanroommc.groovyscript.mapper.ObjectMapperManager; import com.cleanroommc.groovyscript.network.CReload; import com.cleanroommc.groovyscript.network.NetworkHandler; import com.cleanroommc.groovyscript.network.NetworkUtils; @@ -155,9 +156,12 @@ public static void initializeRunConfig(File minecraftHome) { @ApiStatus.Internal public static void initializeGroovyPreInit() { // called via mixin in between construction and fml pre init - GameObjectHandlerManager.init(); + ObjectMapperManager.init(); VanillaModule.initializeBinding(); ModSupport.init(); + for (ObjectMapper goh : ObjectMapperManager.getObjectMappers()) { + getSandbox().registerBinding(goh); + } if (FMLLaunchHandler.isDeobfuscatedEnvironment()) Documentation.generate(); runGroovyScriptsInLoader(LoadStage.PRE_INIT); } diff --git a/src/main/java/com/cleanroommc/groovyscript/api/GroovyPlugin.java b/src/main/java/com/cleanroommc/groovyscript/api/GroovyPlugin.java index f69a57b6d..45fa4822c 100644 --- a/src/main/java/com/cleanroommc/groovyscript/api/GroovyPlugin.java +++ b/src/main/java/com/cleanroommc/groovyscript/api/GroovyPlugin.java @@ -1,5 +1,6 @@ package com.cleanroommc.groovyscript.api; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -18,6 +19,17 @@ public interface GroovyPlugin extends IGroovyContainer { */ @GroovyBlacklist @ApiStatus.OverrideOnly + default @Nullable GroovyPropertyContainer createGroovyPropertyContainer() { + return createModPropertyContainer(); + } + + /** + * @deprecated use {@link #createGroovyPropertyContainer()} instead + */ + @GroovyBlacklist + @ApiStatus.OverrideOnly + @Deprecated + @ApiStatus.ScheduledForRemoval(inVersion = "1.2.0") default @Nullable ModPropertyContainer createModPropertyContainer() { return null; } @@ -30,34 +42,4 @@ public interface GroovyPlugin extends IGroovyContainer { default boolean isLoaded() { return true; } - - /** - * Returns the override priority. Defines how this plugin should behave when another container with the same mod id exists. - * The return value should be as low as possible. Internal container always return {@link Priority#NONE}. - * @return the override priority - * @see Priority - */ - @NotNull - default Priority getOverridePriority() { - return Priority.NONE; - } - - enum Priority { - /** - * Default. Can be overridden by anything and can't override anything. - */ - NONE, - /** - * Can override containers with priority NONE. - */ - OVERRIDE, - /** - * Can override containers with priority NONE, OVERRIDE. - */ - OVERRIDE_HIGH, - /** - * Can override containers with priority NONE, OVERRIDE, OVERRIDE_HIGH. - */ - OVERRIDE_HIGHEST - } } diff --git a/src/main/java/com/cleanroommc/groovyscript/api/Hidden.java b/src/main/java/com/cleanroommc/groovyscript/api/Hidden.java new file mode 100644 index 000000000..d4af6b14d --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/api/Hidden.java @@ -0,0 +1,6 @@ +package com.cleanroommc.groovyscript.api; + +public interface Hidden { + + boolean isHidden(); +} diff --git a/src/main/java/com/cleanroommc/groovyscript/api/IDynamicGroovyProperty.java b/src/main/java/com/cleanroommc/groovyscript/api/IDynamicGroovyProperty.java index a0898b917..5a606a468 100644 --- a/src/main/java/com/cleanroommc/groovyscript/api/IDynamicGroovyProperty.java +++ b/src/main/java/com/cleanroommc/groovyscript/api/IDynamicGroovyProperty.java @@ -1,5 +1,6 @@ package com.cleanroommc.groovyscript.api; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import java.util.Map; @@ -7,6 +8,8 @@ /** * When this is implemented on a class, {@link #getProperty(String)} will be called when groovy tries to get a field from this class */ +@ApiStatus.ScheduledForRemoval(inVersion = "1.2.0") +@Deprecated public interface IDynamicGroovyProperty { /** @@ -34,5 +37,5 @@ default boolean setProperty(String name, @Nullable Object value) { * * @return all properties */ - Map getProperties(); + Map getProperties(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/api/IGameObjectParser.java b/src/main/java/com/cleanroommc/groovyscript/api/IGameObjectParser.java index 1d833588d..8faa54155 100644 --- a/src/main/java/com/cleanroommc/groovyscript/api/IGameObjectParser.java +++ b/src/main/java/com/cleanroommc/groovyscript/api/IGameObjectParser.java @@ -1,83 +1,41 @@ package com.cleanroommc.groovyscript.api; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandlers; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import net.minecraft.util.ResourceLocation; import net.minecraftforge.registries.IForgeRegistry; import net.minecraftforge.registries.IForgeRegistryEntry; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -import java.util.Locale; -import java.util.Map; import java.util.function.Function; /** - * A bracket handler returns a object based on its input arguments. - * A bracket handler can be called from groovy lik this: - *

- * {@code bracket_handler_name(args)} - *

- * In the first way there is always only one argument which is a String. - * In the second method the argument size is at least, but not limited to one. - * The first argument is always a string. The other can be anything. + * @deprecated use {@link IObjectParser} */ +@Deprecated +@ApiStatus.ScheduledForRemoval(inVersion = "1.2.0") @FunctionalInterface -public interface IGameObjectParser { +public interface IGameObjectParser extends IObjectParser { - /** - * Parses a object based on input arguments - * - * @param args arguments. length >= 1 && args[0] instanceof String - * @return a parsed Object - */ - @NotNull - Result parse(String mainArg, Object[] args); - - static > IGameObjectParser wrapForgeRegistry(IForgeRegistry forgeRegistry) { - return (s, args) -> { - Result rl = GameObjectHandlers.parseResourceLocation(s, args); - if (rl.hasError()) return Result.error(rl.getError()); - T value = forgeRegistry.getValue(rl.getValue()); - return value == null ? Result.error() : Result.some(value); - }; + static > IObjectParser wrapForgeRegistry(IForgeRegistry forgeRegistry) { + return IObjectParser.wrapForgeRegistry(forgeRegistry); } - static > IGameObjectParser wrapEnum(Class enumClass, boolean caseSensitive) { - Map map = new Object2ObjectOpenHashMap<>(); - for (T t : enumClass.getEnumConstants()) { - map.put(caseSensitive ? t.name() : t.name().toUpperCase(Locale.ROOT), t); - } - return (s, args) -> { - T t = map.get(caseSensitive ? s : s.toUpperCase(Locale.ROOT)); - return t == null ? Result.error() : Result.some(t); - }; + static > IObjectParser wrapEnum(Class enumClass, boolean caseSensitive) { + return IObjectParser.wrapEnum(enumClass, caseSensitive); } - static IGameObjectParser wrapStringGetter(Function getter) { - return wrapStringGetter(getter, false); + static IObjectParser wrapStringGetter(Function getter) { + return IObjectParser.wrapStringGetter(getter); } - static IGameObjectParser wrapStringGetter(Function getter, boolean isUpperCase) { - return (s, args) -> { - if (args.length > 0) { - return Result.error("extra arguments are not allowed"); - } - T t = getter.apply(isUpperCase ? s.toUpperCase(Locale.ROOT) : s); - return t == null ? Result.error() : Result.some(t); - }; + static IObjectParser wrapStringGetter(Function getter, boolean isUpperCase) { + return IObjectParser.wrapStringGetter(getter, isUpperCase); } - static IGameObjectParser wrapStringGetter(Function getter, Function trueTypeFunction) { - return wrapStringGetter(getter, trueTypeFunction, false); + static IObjectParser wrapStringGetter(Function getter, Function trueTypeFunction) { + return IObjectParser.wrapStringGetter(getter, trueTypeFunction); } - static IGameObjectParser wrapStringGetter(Function getter, Function trueTypeFunction, boolean isUpperCase) { - return (s, args) -> { - if (args.length > 0) { - return Result.error("extra arguments are not allowed"); - } - V v = getter.apply(isUpperCase ? s.toUpperCase(Locale.ROOT) : s); - return v == null ? Result.error() : Result.some(trueTypeFunction.apply(v)); - }; + static IObjectParser wrapStringGetter(Function getter, Function trueTypeFunction, boolean isUpperCase) { + return IObjectParser.wrapStringGetter(getter, trueTypeFunction, isUpperCase); } } diff --git a/src/main/java/com/cleanroommc/groovyscript/api/IGroovyContainer.java b/src/main/java/com/cleanroommc/groovyscript/api/IGroovyContainer.java index d7b8b2599..0d024ffbc 100644 --- a/src/main/java/com/cleanroommc/groovyscript/api/IGroovyContainer.java +++ b/src/main/java/com/cleanroommc/groovyscript/api/IGroovyContainer.java @@ -1,7 +1,7 @@ package com.cleanroommc.groovyscript.api; import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -17,7 +17,7 @@ public interface IGroovyContainer { /** * Returns the mod id of the compat mod. This will be used to check if the mod is loaded. - * Scripts will be able to refer to the mods {@link com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer ModPropertyContainer} + * Scripts will be able to refer to the mods {@link com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer GroovyPropertyContainer} * with this id. * * @return the compat mod id @@ -27,6 +27,7 @@ public interface IGroovyContainer { /** * Returns the name of this container. Is only used for logging and debugging. + * It usually returns a mod name, but it doesn't have to. * * @return the name of the container */ @@ -50,12 +51,43 @@ default Collection getAliases() { } /** - * Called before scripts are executed for the first time. Called right before {@link ModPropertyContainer#initialize()}. + * Called before scripts are executed for the first time. Called right before {@link GroovyPropertyContainer#initialize(GroovyContainer)}. * Used to initialize things like expansions with {@link com.cleanroommc.groovyscript.sandbox.expand.ExpansionHelper ExpansionHelper} and - * game object handlers with {@link com.cleanroommc.groovyscript.gameobjects.GameObjectHandlerManager GameObjectHandlerManager}. + * object mappers with {@link com.cleanroommc.groovyscript.mapper.ObjectMapperManager ObjectMapperManager}. * * @param container the created container for the compat mod */ @ApiStatus.OverrideOnly void onCompatLoaded(GroovyContainer container); + + /** + * Returns the override priority. Defines how this plugin should behave when another container with the same mod id exists. + * The return value should be as low as possible. Internal container always return {@link Priority#NONE}. + * + * @return the override priority + * @see Priority + */ + @NotNull + default Priority getOverridePriority() { + return Priority.NONE; + } + + enum Priority { + /** + * Default. Can be overridden by anything and can't override anything. + */ + NONE, + /** + * Can override containers with priority NONE. + */ + OVERRIDE, + /** + * Can override containers with priority NONE, OVERRIDE. + */ + OVERRIDE_HIGH, + /** + * Can override containers with priority NONE, OVERRIDE, OVERRIDE_HIGH. + */ + OVERRIDE_HIGHEST + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/api/IObjectParser.java b/src/main/java/com/cleanroommc/groovyscript/api/IObjectParser.java new file mode 100644 index 000000000..6f1878a86 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/api/IObjectParser.java @@ -0,0 +1,80 @@ +package com.cleanroommc.groovyscript.api; + +import com.cleanroommc.groovyscript.mapper.ObjectMappers; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.registries.IForgeRegistry; +import net.minecraftforge.registries.IForgeRegistryEntry; +import org.jetbrains.annotations.NotNull; + +import java.util.Locale; +import java.util.Map; +import java.util.function.Function; + +/** + * A function to parse an object from a string and any amount of additional arguments of any type. + * This is used for {@link com.cleanroommc.groovyscript.mapper.ObjectMapper object mappers}. + * + * @param type of the parsed objects + */ +@FunctionalInterface +public interface IObjectParser { + + /** + * Parses an object based on input arguments + * + * @param mainArg the first argument. Usually an id to get an object from a map. + * @param args additional arguments, like metadata for item stacks + * @return a parsed object + */ + @NotNull + Result parse(String mainArg, Object[] args); + + static > IObjectParser wrapForgeRegistry(IForgeRegistry forgeRegistry) { + return (s, args) -> { + Result rl = ObjectMappers.parseResourceLocation(s, args); + if (rl.hasError()) return Result.error(rl.getError()); + T value = forgeRegistry.getValue(rl.getValue()); + return value == null ? Result.error() : Result.some(value); + }; + } + + static > IObjectParser wrapEnum(Class enumClass, boolean caseSensitive) { + Map map = new Object2ObjectOpenHashMap<>(); + for (T t : enumClass.getEnumConstants()) { + map.put(caseSensitive ? t.name() : t.name().toUpperCase(Locale.ROOT), t); + } + return (s, args) -> { + T t = map.get(caseSensitive ? s : s.toUpperCase(Locale.ROOT)); + return t == null ? Result.error() : Result.some(t); + }; + } + + static IObjectParser wrapStringGetter(Function getter) { + return wrapStringGetter(getter, false); + } + + static IObjectParser wrapStringGetter(Function getter, boolean isUpperCase) { + return (s, args) -> { + if (args.length > 0) { + return Result.error("extra arguments are not allowed"); + } + T t = getter.apply(isUpperCase ? s.toUpperCase(Locale.ROOT) : s); + return t == null ? Result.error() : Result.some(t); + }; + } + + static IObjectParser wrapStringGetter(Function getter, Function trueTypeFunction) { + return wrapStringGetter(getter, trueTypeFunction, false); + } + + static IObjectParser wrapStringGetter(Function getter, Function trueTypeFunction, boolean isUpperCase) { + return (s, args) -> { + if (args.length > 0) { + return Result.error("extra arguments are not allowed"); + } + V v = getter.apply(isUpperCase ? s.toUpperCase(Locale.ROOT) : s); + return v == null ? Result.error() : Result.some(trueTypeFunction.apply(v)); + }; + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/api/IRegistrar.java b/src/main/java/com/cleanroommc/groovyscript/api/IRegistrar.java index 01dc94de3..ec65a483c 100644 --- a/src/main/java/com/cleanroommc/groovyscript/api/IRegistrar.java +++ b/src/main/java/com/cleanroommc/groovyscript/api/IRegistrar.java @@ -7,10 +7,10 @@ import java.lang.reflect.Modifier; /** - * A helper interface to register {@link INamed registries} without having direct access to the - * {@link com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer ModPropertyContainer}. - * An instance can be obtained from {@link GroovyContainer#getVirtualizedRegistrar()}. + * @deprecated The methods of this class have been added directly to {@link GroovyContainer} */ +@ApiStatus.ScheduledForRemoval(inVersion = "1.2.0") +@Deprecated @ApiStatus.NonExtendable public interface IRegistrar { @@ -19,6 +19,7 @@ public interface IRegistrar { * * @param registry registry to add. */ + @Deprecated void addRegistry(INamed registry); /** @@ -27,6 +28,7 @@ public interface IRegistrar { * * @param object object to add fields from */ + @Deprecated default void addFieldsOf(Object object) { boolean staticOnly = false; Class clazz; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ExternalModContainer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ExternalModContainer.java index f0ac5cb14..bcb994aea 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ExternalModContainer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ExternalModContainer.java @@ -1,8 +1,6 @@ package com.cleanroommc.groovyscript.compat.mods; import com.cleanroommc.groovyscript.api.GroovyPlugin; -import com.cleanroommc.groovyscript.api.IGroovyContainer; - import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import org.jetbrains.annotations.NotNull; @@ -11,16 +9,20 @@ import java.util.Objects; import java.util.Set; -public class ExternalModContainer extends GroovyContainer { +/** + * This is used for external mod compat. Don't use this directly. Instead, implement {@link GroovyPlugin} on any class. + * This class will then be automatically instanced. + */ +public class ExternalModContainer extends GroovyContainer { - private final IGroovyContainer groovyContainer; - private final ModPropertyContainer container; + private final GroovyPlugin groovyContainer; + private final GroovyPropertyContainer container; private final String modId; private final String containerName; private final Collection aliases; + private final Priority priority; - ExternalModContainer(@NotNull GroovyPlugin groovyContainer, @NotNull ModPropertyContainer container) { - super(groovyContainer.getOverridePriority()); + ExternalModContainer(@NotNull GroovyPlugin groovyContainer, @NotNull GroovyPropertyContainer container) { this.groovyContainer = Objects.requireNonNull(groovyContainer); this.container = Objects.requireNonNull(container); this.modId = groovyContainer.getModId(); @@ -28,6 +30,7 @@ public class ExternalModContainer extends GroovyContainer Set aliasSet = new ObjectOpenHashSet<>(groovyContainer.getAliases()); aliasSet.add(modId); this.aliases = Collections.unmodifiableSet(aliasSet); + this.priority = groovyContainer.getOverridePriority(); } @Override @@ -57,7 +60,12 @@ public void onCompatLoaded(GroovyContainer container) { } @Override - public ModPropertyContainer get() { + public GroovyPropertyContainer get() { return container; } + + @Override + public @NotNull GroovyPlugin.Priority getOverridePriority() { + return priority; + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/GroovyContainer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/GroovyContainer.java index a7c600c27..279802121 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/GroovyContainer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/GroovyContainer.java @@ -1,19 +1,21 @@ package com.cleanroommc.groovyscript.compat.mods; import com.cleanroommc.groovyscript.api.GroovyBlacklist; -import com.cleanroommc.groovyscript.api.GroovyPlugin; import com.cleanroommc.groovyscript.api.IGroovyContainer; +import com.cleanroommc.groovyscript.api.INamed; import com.cleanroommc.groovyscript.api.IRegistrar; +import com.cleanroommc.groovyscript.mapper.ObjectMapper; import org.jetbrains.annotations.ApiStatus; +/** + * This is the base class for mod compat. It is created even if the other mod is not loaded. + * For compat inside GroovyScript use {@link InternalModContainer}. + * Otherwise, take a look at {@link com.cleanroommc.groovyscript.api.GroovyPlugin}. + * + * @param type of the property container + */ @ApiStatus.NonExtendable -public abstract class GroovyContainer implements IGroovyContainer { - - private final GroovyPlugin.Priority overridePriority; - - protected GroovyContainer(GroovyPlugin.Priority overridePriority) { - this.overridePriority = overridePriority; - } +public abstract class GroovyContainer implements IGroovyContainer { public abstract T get(); @@ -22,21 +24,61 @@ public String toString() { return getContainerName(); } + /** + * @deprecated Use {@link #addProperty(INamed)} and {@link #addPropertiesOfFields(Object, boolean)} from this class instead. + */ @Deprecated - @ApiStatus.ScheduledForRemoval(inVersion = "1.1.0") + @ApiStatus.ScheduledForRemoval(inVersion = "1.2.0") @GroovyBlacklist public IRegistrar getVirtualizedRegistrar() { return getRegistrar(); } + /** + * @deprecated Use {@link #addProperty(INamed)} and {@link #addPropertiesOfFields(Object, boolean)} from this class instead. + */ + @Deprecated + @ApiStatus.ScheduledForRemoval(inVersion = "1.2.0") @GroovyBlacklist public IRegistrar getRegistrar() { if (!isLoaded()) return null; T t = get(); - return t::addRegistry; + return t::addProperty; + } + + /** + * Adds a property which can be accessed like a field from groovy. + * + * @param property the property to add + */ + public void addProperty(INamed property) { + if (isLoaded()) { + get().addProperty(property); + } + } + + /** + * Finds all fields in a class which type is an instance of {@link INamed} and adds it as a property. + * If the given object is a class only static variables are used. + * + * @param o object to find fields in + * @param privateToo true if private fields should be used too + */ + public void addPropertiesOfFields(Object o, boolean privateToo) { + if (isLoaded()) { + get().addPropertyFieldsOf(o, privateToo); + } } - public GroovyPlugin.Priority getOverridePriority() { - return overridePriority; + /** + * Creates an object mapper builder. + * + * @param name the function name + * @param returnType the return type + * @param the return type + * @return a new object mapper builder + */ + public ObjectMapper.Builder objectMapperBuilder(String name, Class returnType) { + return new ObjectMapper.Builder<>(name, returnType).mod(this); } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/GroovyPropertyContainer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/GroovyPropertyContainer.java new file mode 100644 index 000000000..0950602c8 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/GroovyPropertyContainer.java @@ -0,0 +1,81 @@ +package com.cleanroommc.groovyscript.compat.mods; + +import com.cleanroommc.groovyscript.GroovyScript; +import com.cleanroommc.groovyscript.api.GroovyBlacklist; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.INamed; +import com.cleanroommc.groovyscript.sandbox.expand.ExpansionHelper; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.UnmodifiableView; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +public class GroovyPropertyContainer { + + private final Map properties = new Object2ObjectOpenHashMap<>(); + private final Map view = Collections.unmodifiableMap(properties); + + protected void addProperty(INamed property) { + int i = 0; + for (String alias : property.getAliases()) { + INamed old = this.properties.put(alias, property); + if (old != null && old != property && GroovyScript.getRunConfig().isDebug()) { + // old property is replaced, sometimes this is intended + GroovyLog.get().warn("Property {} was replaced with property {} in class {}!", old.getName(), alias, getClass()); + } + ExpansionHelper.mixinConstProperty(getClass(), alias, property, i++ > 0); + } + } + + @UnmodifiableView + public Collection getRegistries() { + return this.view.values(); + } + + @UnmodifiableView + public Map getProperties() { + return view; + } + + /** + * Register bracket handlers, bindings, expansions etc. here + */ + @GroovyBlacklist + @ApiStatus.OverrideOnly + public void initialize(GroovyContainer owner) { + } + + protected void addPropertyFieldsOf(Object object, boolean privateToo) { + boolean staticOnly = false; + Class clazz; + if (object instanceof Class c) { + clazz = c; + staticOnly = true; + } else { + clazz = object.getClass(); + } + for (Field field : clazz.getDeclaredFields()) { + boolean isStatic = Modifier.isStatic(field.getModifiers()); + if (!field.isAnnotationPresent(GroovyBlacklist.class) && + INamed.class.isAssignableFrom(field.getType()) && + (!staticOnly || isStatic) && + (privateToo || (Modifier.isPublic(field.getModifiers())))) { + try { + if (!field.isAccessible()) field.setAccessible(true); + Object o = field.get(isStatic ? null : object); + if (o != null) { + addProperty((INamed) o); + } + } catch (IllegalAccessException e) { + GroovyLog.get().errorMC("Failed to register {} as named property", field.getName()); + } + } + } + } +} + diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/InternalModContainer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/InternalModContainer.java index b3379ed57..1333a67c6 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/InternalModContainer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/InternalModContainer.java @@ -13,10 +13,11 @@ import java.util.Set; /** - * Will not be removed but made private and renamed to InternalContainer + * This class is only used for internal mod compat. Do not use this. Instead, refer to {@link ExternalModContainer} ans {@link GroovyPlugin}. + * + * @param type of the mod property container. */ -@SuppressWarnings("all") -public class InternalModContainer extends GroovyContainer { +public class InternalModContainer extends GroovyContainer { private final String modId, containerName; private final Supplier modProperty; @@ -28,7 +29,6 @@ public class InternalModContainer extends Groovy } InternalModContainer(String modId, String containerName, @NotNull Supplier modProperty, String... aliases) { - super(GroovyPlugin.Priority.NONE); if (ModSupport.isFrozen()) { throw new RuntimeException("Groovy mod containers must be registered at construction event! Tried to register '" + containerName + "' too late."); } @@ -39,7 +39,11 @@ public class InternalModContainer extends Groovy } this.modId = modId; this.containerName = containerName; - this.modProperty = Suppliers.memoize(modProperty); + this.modProperty = Suppliers.memoize(() -> { + T t = modProperty.get(); + t.addPropertyFieldsOf(t, false); + return t; + }); this.loaded = Loader.isModLoaded(modId); Set aliasSet = new ObjectOpenHashSet<>(aliases); aliasSet.add(modId); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModPropertyContainer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModPropertyContainer.java index 9e09998ea..985862553 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModPropertyContainer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModPropertyContainer.java @@ -1,50 +1,47 @@ package com.cleanroommc.groovyscript.compat.mods; -import com.cleanroommc.groovyscript.api.*; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import com.cleanroommc.groovyscript.api.GroovyBlacklist; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.INamed; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; +/** + * @deprecated this class has been replaced by {@link GroovyPropertyContainer} + */ +@ApiStatus.ScheduledForRemoval(inVersion = "1.2.0") +@Deprecated +public class ModPropertyContainer extends GroovyPropertyContainer { -public class ModPropertyContainer implements IDynamicGroovyProperty { - - private final Map registries; - - public ModPropertyContainer() { - this.registries = new Object2ObjectOpenHashMap<>(); - ((IRegistrar) this::addRegistry).addFieldsOf(this); - } - - protected void addRegistry(INamed registry) { - for (String alias : registry.getAliases()) { - this.registries.put(alias, registry); - } - } - - public Collection getRegistries() { - return registries.values(); + /** + * @deprecated use {@link #addProperty(INamed)} + */ + @ApiStatus.ScheduledForRemoval(inVersion = "1.2.0") + @Deprecated + protected void addRegistry(INamed property) { + addProperty(property); } - @Override + @ApiStatus.ScheduledForRemoval(inVersion = "1.2.0") + @Deprecated public @Nullable Object getProperty(String name) { - INamed registry = registries.get(name); - if (registry == null) { - GroovyLog.get().error("Attempted to access registry {}, but could not find a registry with that name", name); + INamed property = getProperties().get(name); + if (property == null) { + GroovyLog.get().error("Attempted to access property {}, but could not find a property with that name", name); return null; } - if (!registry.isEnabled()) { - GroovyLog.get().error("Attempted to access registry {}, but that registry was disabled", registry.getName()); + if (!property.isEnabled()) { + GroovyLog.get().error("Attempted to access registry {}, but that registry was disabled", property.getName()); return null; } - return registry; + return property; } - @Override - public Map getProperties() { - return Collections.unmodifiableMap(this.registries); + @ApiStatus.ScheduledForRemoval(inVersion = "1.2.0") + @Deprecated + @GroovyBlacklist + @ApiStatus.OverrideOnly + public void initialize() { } /** @@ -52,6 +49,10 @@ public Map getProperties() { */ @GroovyBlacklist @ApiStatus.OverrideOnly - public void initialize() { + @Override + public void initialize(GroovyContainer owner) { + initialize(); } + } + diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java index 599c14da7..f1dba2762 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java @@ -3,7 +3,6 @@ import com.cleanroommc.groovyscript.GroovyScript; import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyPlugin; -import com.cleanroommc.groovyscript.api.IDynamicGroovyProperty; import com.cleanroommc.groovyscript.compat.mods.actuallyadditions.ActuallyAdditions; import com.cleanroommc.groovyscript.compat.mods.advancedmortars.AdvancedMortars; import com.cleanroommc.groovyscript.compat.mods.aetherlegacy.Aether; @@ -39,6 +38,7 @@ import com.cleanroommc.groovyscript.compat.mods.thermalexpansion.ThermalExpansion; import com.cleanroommc.groovyscript.compat.mods.tinkersconstruct.TinkersConstruct; import com.cleanroommc.groovyscript.compat.mods.woot.Woot; +import com.cleanroommc.groovyscript.sandbox.expand.ExpansionHelper; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraftforge.fml.common.Loader; @@ -46,14 +46,15 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnmodifiableView; import java.util.*; -import java.util.stream.Collectors; -public class ModSupport implements IDynamicGroovyProperty { +public class ModSupport { - private static final Map> containers = new Object2ObjectOpenHashMap<>(); - private static final List> containerList = new ArrayList<>(); + private static final Map> containers = new Object2ObjectOpenHashMap<>(); + private static final Map> containersView = Collections.unmodifiableMap(containers); + private static final List> containerList = new ArrayList<>(); private static final Set> externalPluginClasses = new ObjectOpenHashSet<>(); private static boolean frozen = false; @@ -94,7 +95,8 @@ public class ModSupport implements IDynamicGroovyProperty { public static final GroovyContainer TINKERS_COMPLEMENT = new InternalModContainer<>("tcomplement", "Tinkers Complement", TinkersComplement::new, "tcomp", "tinkerscomplement"); public static final GroovyContainer TINKERS_CONSTRUCT = new InternalModContainer<>("tconstruct", "Tinkers' Construct", TinkersConstruct::new, "ticon", "tinkersconstruct"); public static final GroovyContainer WOOT = new InternalModContainer<>("woot", "Woot", Woot::new); - public static Collection> getAllContainers() { + + public static Collection> getAllContainers() { return Collections.unmodifiableList(containerList); } @@ -139,11 +141,11 @@ private void registerContainer(GroovyPlugin container) { containerList.removeIf(c -> c == current); } - ModPropertyContainer modPropertyContainer = container.createModPropertyContainer(); - if (modPropertyContainer == null) { - modPropertyContainer = new ModPropertyContainer(); + GroovyPropertyContainer groovyPropertyContainer = container.createGroovyPropertyContainer(); + if (groovyPropertyContainer == null) { + groovyPropertyContainer = new GroovyPropertyContainer(); } - registerContainer(new ExternalModContainer(container, modPropertyContainer)); + registerContainer(new ExternalModContainer(container, groovyPropertyContainer)); externalPluginClasses.add(container.getClass()); } @@ -160,20 +162,17 @@ void registerContainer(GroovyContainer container) { } } - @Override + @Deprecated @Nullable public Object getProperty(String name) { GroovyContainer container = containers.get(name); return container != null ? container.get() : null; } - @Override - public Map getProperties() { - Map properties = new HashMap<>(); - for (var entry : containers.entrySet()) { - properties.put(entry.getKey(), entry.getValue().get()); - } - return properties; + + @Deprecated + public @UnmodifiableView Map> getProperties() { + return containersView; } @GroovyBlacklist @@ -183,7 +182,13 @@ public static void init() { for (GroovyContainer container : containerList) { if (container.isLoaded()) { container.onCompatLoaded(container); - container.get().initialize(); + container.get().initialize(container); + ExpansionHelper.mixinConstProperty(ModSupport.class, container.getModId(), container.get(), false); + for (String s : container.getAliases()) { + if (!container.getModId().equals(s)) { + ExpansionHelper.mixinConstProperty(ModSupport.class, s, container.get(), true); + } + } } } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/actuallyadditions/ActuallyAdditions.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/actuallyadditions/ActuallyAdditions.java index a34c0112c..4640e6e26 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/actuallyadditions/ActuallyAdditions.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/actuallyadditions/ActuallyAdditions.java @@ -1,8 +1,8 @@ package com.cleanroommc.groovyscript.compat.mods.actuallyadditions; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class ActuallyAdditions extends ModPropertyContainer { +public class ActuallyAdditions extends GroovyPropertyContainer { public final Crusher crusher = new Crusher(); public final OilGen oilGen = new OilGen(); @@ -14,16 +14,4 @@ public class ActuallyAdditions extends ModPropertyContainer { public final NetherMiningLens netherMiningLens = new NetherMiningLens(); public final StoneMiningLens stoneMiningLens = new StoneMiningLens(); - public ActuallyAdditions() { - addRegistry(crusher); - addRegistry(oilGen); - addRegistry(compost); - addRegistry(ballOfFur); - addRegistry(treasureChest); - addRegistry(empowerer); - addRegistry(atomicReconstructor); - addRegistry(netherMiningLens); - addRegistry(stoneMiningLens); - } - } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/advancedmortars/AdvancedMortars.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/advancedmortars/AdvancedMortars.java index 759d0b2c0..ce9d03c15 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/advancedmortars/AdvancedMortars.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/advancedmortars/AdvancedMortars.java @@ -1,13 +1,9 @@ package com.cleanroommc.groovyscript.compat.mods.advancedmortars; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class AdvancedMortars extends ModPropertyContainer { +public class AdvancedMortars extends GroovyPropertyContainer { public final Mortar mortar = new Mortar(); - public AdvancedMortars() { - addRegistry(mortar); - } - } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/aetherlegacy/Accessory.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/aetherlegacy/Accessory.java index aa4612530..c25bbdf00 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/aetherlegacy/Accessory.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/aetherlegacy/Accessory.java @@ -3,6 +3,7 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.helper.EnumHelper; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.ForgeRegistryWrapper; @@ -26,7 +27,7 @@ public void add(ItemStack item, String type) { AccessoryType accessoryType = EnumHelper.valueOfNullable(AccessoryType.class, type, false); if (accessoryType == null) { GroovyLog.msg("Error adding Aether accessory") - .add(accessoryType == null, "type with name {} does not exist. Valid values are {}.", type, Arrays.toString(AccessoryType.values())) + .add("type with name {} does not exist. Valid values are {}.", type, Arrays.toString(AccessoryType.values())) .error() .post(); return; @@ -85,7 +86,7 @@ public void validate(GroovyLog.Msg msg) { if (!validate()) return null; AetherAccessory accessory = new AetherAccessory(input.get(0).getMatchingStacks()[0], accessoryType); - Aether.accessory.add(accessory); + ModSupport.AETHER.get().accessory.add(accessory); return accessory; } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/aetherlegacy/Aether.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/aetherlegacy/Aether.java index f4eac9d8f..ac38eca74 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/aetherlegacy/Aether.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/aetherlegacy/Aether.java @@ -1,21 +1,13 @@ package com.cleanroommc.groovyscript.compat.mods.aetherlegacy; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class Aether extends ModPropertyContainer { +public class Aether extends GroovyPropertyContainer { - public static final Enchanter enchanter = new Enchanter(); - public static final EnchanterFuel enchanterFuel = new EnchanterFuel(); - public static final Freezer freezer = new Freezer(); - public static final FreezerFuel freezerFuel = new FreezerFuel(); - public static final Accessory accessory = new Accessory(); - - public Aether() { - addRegistry(enchanter); - addRegistry(enchanterFuel); - addRegistry(freezer); - addRegistry(freezerFuel); - addRegistry(accessory); - } + public final Enchanter enchanter = new Enchanter(); + public final EnchanterFuel enchanterFuel = new EnchanterFuel(); + public final Freezer freezer = new Freezer(); + public final FreezerFuel freezerFuel = new FreezerFuel(); + public final Accessory accessory = new Accessory(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/aetherlegacy/Enchanter.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/aetherlegacy/Enchanter.java index 77e900488..cb95f1985 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/aetherlegacy/Enchanter.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/aetherlegacy/Enchanter.java @@ -3,6 +3,7 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.ForgeRegistryWrapper; import com.gildedgames.the_aether.api.enchantments.AetherEnchantment; @@ -68,7 +69,7 @@ public void validate(GroovyLog.Msg msg) { if (!validate()) return null; AetherEnchantment enchantment = new AetherEnchantment(input.get(0).getMatchingStacks()[0], output.get(0), time); - Aether.enchanter.add(enchantment); + ModSupport.AETHER.get().enchanter.add(enchantment); return enchantment; } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/aetherlegacy/Freezer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/aetherlegacy/Freezer.java index 3d35f71e2..5ce5a9a6c 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/aetherlegacy/Freezer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/aetherlegacy/Freezer.java @@ -3,6 +3,7 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.ForgeRegistryWrapper; import com.gildedgames.the_aether.api.freezables.AetherFreezable; @@ -67,7 +68,7 @@ public void validate(GroovyLog.Msg msg) { public @Nullable AetherFreezable register() { if (!validate()) return null; AetherFreezable freezable = new AetherFreezable(input.get(0).getMatchingStacks()[0], output.get(0), time); - Aether.freezer.add(freezable); + ModSupport.AETHER.get().freezer.add(freezable); return freezable; } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/alchemistry/Alchemistry.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/alchemistry/Alchemistry.java index 9ba86f131..c00701056 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/alchemistry/Alchemistry.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/alchemistry/Alchemistry.java @@ -5,11 +5,11 @@ import al132.alchemistry.chemistry.CompoundRegistry; import al132.alchemistry.chemistry.ElementRegistry; import com.cleanroommc.groovyscript.api.Result; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandler; +import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import net.minecraft.item.ItemStack; -public class Alchemistry extends ModPropertyContainer { +public class Alchemistry extends GroovyPropertyContainer { public final Atomizer atomizer = new Atomizer(); public final Combiner combiner = new Combiner(); @@ -17,22 +17,12 @@ public class Alchemistry extends ModPropertyContainer { public final Electrolyzer electrolyzer = new Electrolyzer(); public final Evaporator evaporator = new Evaporator(); public final Liquifier liquifier = new Liquifier(); - - public Alchemistry() { - addRegistry(atomizer); - addRegistry(combiner); - addRegistry(dissolver); - addRegistry(electrolyzer); - addRegistry(evaporator); - addRegistry(liquifier); - // TODO: - // Compound Creation and Element Creation - } + // TODO: + // Compound Creation and Element Creation @Override - public void initialize() { - GameObjectHandler.builder("element", ItemStack.class) - .mod("alchemistry") + public void initialize(GroovyContainer container) { + container.objectMapperBuilder("element", ItemStack.class) .parser((s, args) -> { String parsedName = s.trim().toLowerCase().replace(" ", "_"); ChemicalCompound compound = CompoundRegistry.INSTANCE.get(parsedName); @@ -48,6 +38,7 @@ public void initialize() { .defaultValue(() -> ItemStack.EMPTY) .completerOfNamed(CompoundRegistry.INSTANCE::compounds, ChemicalCompound::getName) .completerOfNamed(ElementRegistry.INSTANCE::getAllElements, ChemicalElement::getName) + .docOfType("chemical element or compound as item stack") .register(); } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/appliedenergistics2/AppliedEnergistics2.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/appliedenergistics2/AppliedEnergistics2.java index 12a2ef3ca..fdaafb371 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/appliedenergistics2/AppliedEnergistics2.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/appliedenergistics2/AppliedEnergistics2.java @@ -1,14 +1,14 @@ package com.cleanroommc.groovyscript.compat.mods.appliedenergistics2; import appeng.api.config.TunnelType; -import com.cleanroommc.groovyscript.api.IGameObjectParser; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandler; +import com.cleanroommc.groovyscript.api.IObjectParser; +import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import java.util.Arrays; import java.util.Locale; -public class AppliedEnergistics2 extends ModPropertyContainer { +public class AppliedEnergistics2 extends GroovyPropertyContainer { public final Inscriber inscriber = new Inscriber(); public final Grinder grinder = new Grinder(); @@ -16,20 +16,12 @@ public class AppliedEnergistics2 extends ModPropertyContainer { public final Spatial spatial = new Spatial(); public final Attunement attunement = new Attunement(); - public AppliedEnergistics2() { - addRegistry(inscriber); - addRegistry(grinder); - addRegistry(cannonAmmo); - addRegistry(spatial); - addRegistry(attunement); - } - @Override - public void initialize() { - GameObjectHandler.builder("tunnel", TunnelType.class) - .mod("appliedenergistics2") - .parser(IGameObjectParser.wrapEnum(TunnelType.class, false)) + public void initialize(GroovyContainer container) { + container.objectMapperBuilder("tunnel", TunnelType.class) + .parser(IObjectParser.wrapEnum(TunnelType.class, false)) .completerOfNamed(() -> Arrays.asList(TunnelType.values()), v -> v.name().toUpperCase(Locale.ROOT)) + .docOfType("P2P tunnel type") .register(); } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/arcanearchives/ArcaneArchives.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/arcanearchives/ArcaneArchives.java index d12079491..b0431bfa1 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/arcanearchives/ArcaneArchives.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/arcanearchives/ArcaneArchives.java @@ -1,13 +1,9 @@ package com.cleanroommc.groovyscript.compat.mods.arcanearchives; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class ArcaneArchives extends ModPropertyContainer { +public class ArcaneArchives extends GroovyPropertyContainer { public final GemCuttingTable gemCuttingTable = new GemCuttingTable(); - public ArcaneArchives() { - addRegistry(gemCuttingTable); - } - } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/AstralSorcery.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/AstralSorcery.java index 31ce68ec1..6fc9c7e76 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/AstralSorcery.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/AstralSorcery.java @@ -2,13 +2,13 @@ import com.cleanroommc.groovyscript.api.IIngredient; import com.cleanroommc.groovyscript.api.Result; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import com.cleanroommc.groovyscript.compat.mods.astralsorcery.crystal.CrystalItemStackExpansion; import com.cleanroommc.groovyscript.compat.mods.astralsorcery.perktree.GroovyPerkTree; import com.cleanroommc.groovyscript.compat.mods.astralsorcery.perktree.PerkTreeConfig; import com.cleanroommc.groovyscript.compat.mods.astralsorcery.starlightaltar.StarlightAltar; import com.cleanroommc.groovyscript.core.mixin.astralsorcery.ConstellationRegistryAccessor; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandler; import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; import com.cleanroommc.groovyscript.sandbox.expand.ExpansionHelper; import hellfirepvp.astralsorcery.common.constellation.IConstellation; @@ -16,7 +16,7 @@ import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; -public class AstralSorcery extends ModPropertyContainer { +public class AstralSorcery extends GroovyPropertyContainer { public final StarlightAltar altar = new StarlightAltar(); public final Lightwell lightwell = new Lightwell(); @@ -34,28 +34,9 @@ public class AstralSorcery extends ModPropertyContainer { public final OreChance treasureShrineOreChance = OreChance.treasureShrineRegistry(); public final PerkTreeConfig perkTreeConfig = new PerkTreeConfig(); - public AstralSorcery() { - addRegistry(altar); - addRegistry(lightwell); - addRegistry(infusionAltar); - addRegistry(grindstone); - addRegistry(lightTransmutation); - addRegistry(chaliceInteraction); - addRegistry(perkTree); - addRegistry(constellation); - addRegistry(research); - addRegistry(fountain); - addRegistry(mineralisRitualOreChance); - addRegistry(aevitasPerkOreChance); - addRegistry(trashPerkOreChance); - addRegistry(treasureShrineOreChance); - addRegistry(perkTreeConfig); - } - @Override - public void initialize() { - GameObjectHandler.builder("constellation", IConstellation.class) - .mod("astralsorcery") + public void initialize(GroovyContainer container) { + container.objectMapperBuilder("constellation", IConstellation.class) .parser((s, args) -> { for (IConstellation constellation : ConstellationRegistryAccessor.getConstellationList()) { if (constellation.getSimpleName().equalsIgnoreCase(s)) { @@ -65,6 +46,7 @@ public void initialize() { return Result.error(); }) .completerOfNamed(ConstellationRegistryAccessor::getConstellationList, IConstellation::getSimpleName) + .docOfType("constellation") .register(); ExpansionHelper.mixinClass(ItemStack.class, CrystalItemStackExpansion.class); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/avaritia/Avaritia.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/avaritia/Avaritia.java index 610146e00..c6f6006be 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/avaritia/Avaritia.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/avaritia/Avaritia.java @@ -1,15 +1,10 @@ package com.cleanroommc.groovyscript.compat.mods.avaritia; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class Avaritia extends ModPropertyContainer { +public class Avaritia extends GroovyPropertyContainer { public final ExtremeCrafting extremeCrafting = new ExtremeCrafting(); public final Compressor compressor = new Compressor(); - public Avaritia() { - addRegistry(extremeCrafting); - addRegistry(compressor); - } - } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/BetterWithMods.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/BetterWithMods.java index 82273951b..f2033d46c 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/BetterWithMods.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/BetterWithMods.java @@ -1,8 +1,8 @@ package com.cleanroommc.groovyscript.compat.mods.betterwithmods; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class BetterWithMods extends ModPropertyContainer { +public class BetterWithMods extends GroovyPropertyContainer { public final AnvilCrafting anvilCrafting = new AnvilCrafting(); public final Cauldron cauldron = new Cauldron(); @@ -15,17 +15,4 @@ public class BetterWithMods extends ModPropertyContainer { public final Hopper hopper = new Hopper(); public final HopperFilters hopperFilters = new HopperFilters(); - public BetterWithMods() { - addRegistry(anvilCrafting); - addRegistry(cauldron); - addRegistry(crucible); - addRegistry(kiln); - addRegistry(millStone); - addRegistry(saw); - addRegistry(turntable); - addRegistry(heat); - addRegistry(hopper); - addRegistry(hopperFilters); - } - } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/BloodMagic.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/BloodMagic.java index afa7adc2b..06af2a84e 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/BloodMagic.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/BloodMagic.java @@ -1,8 +1,8 @@ package com.cleanroommc.groovyscript.compat.mods.bloodmagic; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class BloodMagic extends ModPropertyContainer { +public class BloodMagic extends GroovyPropertyContainer { public final BloodAltar bloodAltar = new BloodAltar(); public final AlchemyArray alchemyArray = new AlchemyArray(); @@ -12,14 +12,4 @@ public class BloodMagic extends ModPropertyContainer { public final Sacrificial sacrificial = new Sacrificial(); public final Meteor meteor = new Meteor(); - public BloodMagic() { - addRegistry(bloodAltar); - addRegistry(alchemyArray); - addRegistry(tartaricForge); - addRegistry(alchemyTable); - addRegistry(tranquility); - addRegistry(sacrificial); - addRegistry(meteor); - } - } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Botania.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Botania.java index e4c38ab6f..ac682b746 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Botania.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Botania.java @@ -1,13 +1,13 @@ package com.cleanroommc.groovyscript.compat.mods.botania; -import com.cleanroommc.groovyscript.api.IGameObjectParser; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandler; +import com.cleanroommc.groovyscript.api.IObjectParser; +import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import vazkii.botania.api.BotaniaAPI; import vazkii.botania.api.lexicon.LexiconCategory; import vazkii.botania.api.lexicon.LexiconEntry; -public class Botania extends ModPropertyContainer { +public class Botania extends GroovyPropertyContainer { public final ElvenTrade elvenTrade = new ElvenTrade(); public final ManaInfusion manaInfusion = new ManaInfusion(); @@ -23,23 +23,6 @@ public class Botania extends ModPropertyContainer { public final Magnet magnet = new Magnet(); public final Flowers flowers = new Flowers(); - public Botania() { - addRegistry(elvenTrade); - addRegistry(manaInfusion); - addRegistry(pureDaisy); - addRegistry(apothecary); - addRegistry(orechid); - addRegistry(orechidIgnem); - addRegistry(runeAltar); - addRegistry(brew); - addRegistry(brewRecipe); - addRegistry(lexicon.category); - addRegistry(lexicon.entry); - addRegistry(lexicon.page); - addRegistry(knowledge); - addRegistry(magnet); - } - public static LexiconCategory getCategory(String name) { for (LexiconCategory category : BotaniaAPI.getAllCategories()) if (category.getUnlocalizedName().equals(name)) return category; @@ -55,12 +38,12 @@ public static LexiconEntry getEntry(String name) { // using BotaniaAPI.brewMap::get crashes @SuppressWarnings("Convert2MethodRef") @Override - public void initialize() { - GameObjectHandler.builder("brew", vazkii.botania.api.brew.Brew.class) - .mod("botania") - .parser(IGameObjectParser.wrapStringGetter(val -> BotaniaAPI.brewMap.get(val), false)) + public void initialize(GroovyContainer container) { + container.objectMapperBuilder("brew", vazkii.botania.api.brew.Brew.class) + .parser(IObjectParser.wrapStringGetter(val -> BotaniaAPI.brewMap.get(val), false)) .completerOfNames(() -> BotaniaAPI.brewMap.keySet()) .defaultValue(() -> BotaniaAPI.fallbackBrew) + .docOfType("brew") .register(); } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/calculator/Calculator.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/calculator/Calculator.java index b59410c3d..c05681afd 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/calculator/Calculator.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/calculator/Calculator.java @@ -1,7 +1,7 @@ package com.cleanroommc.groovyscript.compat.mods.calculator; import com.cleanroommc.groovyscript.api.IIngredient; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; import com.cleanroommc.groovyscript.helper.ingredient.IngredientList; import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; @@ -15,7 +15,7 @@ import java.util.Arrays; import java.util.List; -public class Calculator extends ModPropertyContainer { +public class Calculator extends GroovyPropertyContainer { public final AlgorithmSeparator algorithmSeparator = new AlgorithmSeparator(); public final AnalysingChamber analysingChamber = new AnalysingChamber(); @@ -36,28 +36,6 @@ public class Calculator extends ModPropertyContainer { public final StarchExtractor starchExtractor = new StarchExtractor(); public final StoneSeparator stoneSeparator = new StoneSeparator(); - public Calculator() { - addRegistry(algorithmSeparator); - addRegistry(analysingChamber); - addRegistry(atomicCalculator); - addRegistry(basicCalculator); - addRegistry(conductorMast); - addRegistry(extractionChamber); - addRegistry(fabricationChamber); - addRegistry(flawlessCalculator); - addRegistry(glowstoneExtractor); - addRegistry(healthProcessor); - addRegistry(precisionChamber); - addRegistry(processingChamber); - addRegistry(reassemblyChamber); - addRegistry(redstoneExtractor); - addRegistry(restorationChamber); - addRegistry(scientificCalculator); - addRegistry(starchExtractor); - addRegistry(stoneSeparator); - } - - public static List toSonarRecipeObjectList(IngredientList list) { List output = new ArrayList<>(); for (IIngredient ingredient : list) { diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/chisel/Chisel.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/chisel/Chisel.java index a69eab345..a3873ec1b 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/chisel/Chisel.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/chisel/Chisel.java @@ -1,13 +1,9 @@ package com.cleanroommc.groovyscript.compat.mods.chisel; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class Chisel extends ModPropertyContainer { +public class Chisel extends GroovyPropertyContainer { public final Carving carving = new Carving(); - public Chisel() { - addRegistry(carving); - } - } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/compactmachines/CompactMachines.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/compactmachines/CompactMachines.java index 13616b820..fbcfac0d6 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/compactmachines/CompactMachines.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/compactmachines/CompactMachines.java @@ -1,13 +1,9 @@ package com.cleanroommc.groovyscript.compat.mods.compactmachines; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class CompactMachines extends ModPropertyContainer { +public class CompactMachines extends GroovyPropertyContainer { public final Miniaturization miniaturization = new Miniaturization(); - public CompactMachines() { - addRegistry(miniaturization); - } - } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/draconicevolution/DraconicEvolution.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/draconicevolution/DraconicEvolution.java index 15a61bd33..ba7623433 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/draconicevolution/DraconicEvolution.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/draconicevolution/DraconicEvolution.java @@ -1,16 +1,9 @@ package com.cleanroommc.groovyscript.compat.mods.draconicevolution; -import com.cleanroommc.groovyscript.GroovyScriptConfig; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class DraconicEvolution extends ModPropertyContainer { +public class DraconicEvolution extends GroovyPropertyContainer { public final Fusion fusion = new Fusion(); - public final EnergyCore energyCore; - - public DraconicEvolution() { - this.energyCore = GroovyScriptConfig.compat.draconicEvolutionEnergyCore ? new EnergyCore() : null; - addRegistry(fusion); - if (this.energyCore != null) addRegistry(energyCore); - } + public final EnergyCore energyCore = new EnergyCore(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/draconicevolution/EnergyCore.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/draconicevolution/EnergyCore.java index 5afacc0a6..52b5472df 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/draconicevolution/EnergyCore.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/draconicevolution/EnergyCore.java @@ -1,5 +1,6 @@ package com.cleanroommc.groovyscript.compat.mods.draconicevolution; +import com.cleanroommc.groovyscript.GroovyScriptConfig; import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IScriptReloadable; @@ -40,6 +41,11 @@ private void init() { onReload(); // increases version to 1 } + @Override + public boolean isEnabled() { + return GroovyScriptConfig.compat.draconicEvolutionEnergyCore; + } + @Override public Collection getAliases() { return Alias.generateOfClass(EnergyCore.class); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/EnderIO.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/EnderIO.java index f423d193d..b4fe0ee75 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/EnderIO.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/EnderIO.java @@ -1,8 +1,8 @@ package com.cleanroommc.groovyscript.compat.mods.enderio; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class EnderIO extends ModPropertyContainer { +public class EnderIO extends GroovyPropertyContainer { public final AlloySmelter alloySmelter = new AlloySmelter(); public final FluidFuel fluidFuel = new FluidFuel(); @@ -15,17 +15,4 @@ public class EnderIO extends ModPropertyContainer { public final Tank tank = new Tank(); public final Vat vat = new Vat(); - public EnderIO() { - addRegistry(alloySmelter); - addRegistry(fluidFuel); - addRegistry(fluidCoolant); - addRegistry(enchanter); - addRegistry(sagMill); - addRegistry(sagMillGrinding); - addRegistry(sliceNSplice); - addRegistry(soulBinder); - addRegistry(tank); - addRegistry(vat); - } - } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/evilcraft/EvilCraft.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/evilcraft/EvilCraft.java index baf1b501d..b1992cb66 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/evilcraft/EvilCraft.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/evilcraft/EvilCraft.java @@ -1,31 +1,26 @@ package com.cleanroommc.groovyscript.compat.mods.evilcraft; -import com.cleanroommc.groovyscript.api.IGameObjectParser; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandler; +import com.cleanroommc.groovyscript.api.IObjectParser; +import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import org.cyclops.evilcraft.core.weather.WeatherType; import java.util.Arrays; import java.util.List; -public class EvilCraft extends ModPropertyContainer { +public class EvilCraft extends GroovyPropertyContainer { public final BloodInfuser bloodInfuser = new BloodInfuser(); public final EnvironmentalAccumulator environmentalAccumulator = new EnvironmentalAccumulator(); - public EvilCraft() { - addRegistry(bloodInfuser); - addRegistry(environmentalAccumulator); - } - @Override - public void initialize() { + public void initialize(GroovyContainer container) { final List weatherTypes = Arrays.asList("any", "clear", "rain", "lightning"); - GameObjectHandler.builder("weather", WeatherType.class) - .mod("evilcraft") - .parser(IGameObjectParser.wrapStringGetter(WeatherType::valueOf, true)) + container.objectMapperBuilder("weather", WeatherType.class) + .parser(IObjectParser.wrapStringGetter(WeatherType::valueOf, true)) .completerOfNames(() -> weatherTypes) // elements don't have names .defaultValue(() -> WeatherType.ANY) + .docOfType("weather type") .register(); } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/ExtendedCrafting.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/ExtendedCrafting.java index b03dc358b..dad091452 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/ExtendedCrafting.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/ExtendedCrafting.java @@ -1,18 +1,12 @@ package com.cleanroommc.groovyscript.compat.mods.extendedcrafting; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class ExtendedCrafting extends ModPropertyContainer { +public class ExtendedCrafting extends GroovyPropertyContainer { public final TableCrafting tableCrafting = new TableCrafting(); public final EnderCrafting enderCrafting = new EnderCrafting(); public final CombinationCrafting combinationCrafting = new CombinationCrafting(); public final CompressionCrafting compressionCrafting = new CompressionCrafting(); - public ExtendedCrafting() { - addRegistry(tableCrafting); - addRegistry(enderCrafting); - addRegistry(combinationCrafting); - addRegistry(compressionCrafting); - } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/extrautils2/ExtraUtils2.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/extrautils2/ExtraUtils2.java index 26c2d0920..f2a6047a7 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/extrautils2/ExtraUtils2.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/extrautils2/ExtraUtils2.java @@ -1,8 +1,8 @@ package com.cleanroommc.groovyscript.compat.mods.extrautils2; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class ExtraUtils2 extends ModPropertyContainer { +public class ExtraUtils2 extends GroovyPropertyContainer { public final Resonator resonator = new Resonator(); public final Crusher crusher = new Crusher(); @@ -11,13 +11,4 @@ public class ExtraUtils2 extends ModPropertyContainer { public final GridPowerPassiveGenerator gridPowerPassiveGenerator = new GridPowerPassiveGenerator(); public final Generator generator = new Generator(); - public ExtraUtils2() { - addRegistry(resonator); - addRegistry(crusher); - addRegistry(enchanter); - addRegistry(furnace); - addRegistry(gridPowerPassiveGenerator); - addRegistry(generator); - } - } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/forestry/Forestry.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/forestry/Forestry.java index da95bb57a..df1991481 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/forestry/Forestry.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/forestry/Forestry.java @@ -1,15 +1,15 @@ package com.cleanroommc.groovyscript.compat.mods.forestry; import com.cleanroommc.groovyscript.api.Result; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandler; +import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import forestry.api.apiculture.IAlleleBeeSpecies; import forestry.api.core.ForestryAPI; import forestry.api.genetics.AlleleManager; import forestry.apiculture.genetics.alleles.AlleleBeeSpecies; import forestry.modules.ForestryModuleUids; -public class Forestry extends ModPropertyContainer { +public class Forestry extends GroovyPropertyContainer { public final CharcoalPile charcoalPile = new CharcoalPile(); public final Squeezer squeezer = new Squeezer(); @@ -23,21 +23,6 @@ public class Forestry extends ModPropertyContainer { public final BeeProduce beeProduce = new BeeProduce(); public final BeeMutations beeMutations = new BeeMutations(); - public Forestry() { - addRegistry(charcoalPile); - addRegistry(squeezer); - addRegistry(still); - addRegistry(centrifuge); - addRegistry(fermenter); - addRegistry(moistener); - addRegistry(moistenerFuel); - addRegistry(carpenter); - addRegistry(thermionicFabricator); - addRegistry(thermionicFabricator.smelting); - addRegistry(beeProduce); - addRegistry(beeMutations); - } - public static Result parseSpecies(String mainArg, Object... args) { if (!ForestryAPI.moduleManager.isModuleEnabled("forestry", ForestryModuleUids.APICULTURE)) { return Result.error("Can't get bee species while apiculture is disabled."); @@ -64,11 +49,11 @@ protected static String getNormalName(String name) { } @Override - public void initialize() { - GameObjectHandler.builder("species", AlleleBeeSpecies.class) - .mod("forestry") + public void initialize(GroovyContainer container) { + container.objectMapperBuilder("species", AlleleBeeSpecies.class) .parser(Forestry::parseSpecies) .completerOfNamed(() -> AlleleManager.alleleRegistry.getRegisteredAlleles().keySet(), s -> s.replace('.', ':')) // elements don't have names + .docOfType("allele bee species") .register(); } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/IC2.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/IC2.java index c39a98f57..172d339bd 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/IC2.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/IC2.java @@ -1,6 +1,6 @@ package com.cleanroommc.groovyscript.compat.mods.ic2; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import com.cleanroommc.groovyscript.compat.mods.ic2.classic.*; import com.cleanroommc.groovyscript.compat.mods.ic2.exp.*; import net.minecraft.item.ItemStack; @@ -9,7 +9,7 @@ import java.util.List; -public class IC2 extends ModPropertyContainer { +public class IC2 extends GroovyPropertyContainer { public final boolean isExp; @@ -48,14 +48,6 @@ public IC2() { compressor = isExp ? new Compressor() : new ClassicCompressor(); scrapbox = isExp ? new Scrapbox() : new ClassicScrapbox(); - addRegistry(macerator); - addRegistry(compressor); - addRegistry(extractor); - addRegistry(centrifuge); - addRegistry(metalFormer); - addRegistry(oreWasher); - addRegistry(scrapbox); - if (isExp) { semiFluidGenerator = new FluidGenerator(); electrolyzer = new Electrolyzer(); @@ -67,30 +59,12 @@ public IC2() { recycler = new Recycler(); liquidHeatExchanger = new LiquidHeatExchanger(); liquidFueledFirebox = new FluidHeater(); - - addRegistry(semiFluidGenerator); - addRegistry(electrolyzer); - addRegistry(fermenter); - addRegistry(blastFurnace); - addRegistry(blockCutter); - addRegistry(fluidCanner); - addRegistry(solidCanner); - addRegistry(recycler); - addRegistry(liquidHeatExchanger); - addRegistry(liquidFueledFirebox); - addRegistry(electrolyzer); } else { canner = new Canner(); classicElectrolyzer = new ClassicElectrolyzer(); sawmill = new Sawmill(); liquidFuelGenerator = new LiquidFuelGenerator(); rareEarthExtractor = new RareEarthExtractor(); - - addRegistry(canner); - addRegistry(classicElectrolyzer); - addRegistry(sawmill); - addRegistry(liquidFuelGenerator); - addRegistry(rareEarthExtractor); } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/ImmersiveEngineering.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/ImmersiveEngineering.java index 256fb1794..1982b124e 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/ImmersiveEngineering.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/ImmersiveEngineering.java @@ -2,7 +2,7 @@ import blusunrize.immersiveengineering.api.crafting.IngredientStack; import com.cleanroommc.groovyscript.api.IIngredient; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; import net.minecraft.item.ItemStack; @@ -10,7 +10,7 @@ import java.util.Arrays; -public class ImmersiveEngineering extends ModPropertyContainer { +public class ImmersiveEngineering extends GroovyPropertyContainer { public final AlloyKiln alloyKiln = new AlloyKiln(); public final ArcFurnace arcFurnace = new ArcFurnace(); @@ -27,23 +27,6 @@ public class ImmersiveEngineering extends ModPropertyContainer { public final Refinery refinery = new Refinery(); public final Squeezer squeezer = new Squeezer(); - public ImmersiveEngineering() { - addRegistry(alloyKiln); - addRegistry(arcFurnace); - addRegistry(blastFurnace); - addRegistry(blastFurnaceFuel); - addRegistry(blueprint); - addRegistry(bottlingMachine); - addRegistry(cokeOven); - addRegistry(crusher); - addRegistry(excavator); - addRegistry(fermenter); - addRegistry(metalPress); - addRegistry(mixer); - addRegistry(refinery); - addRegistry(squeezer); - } - public static IngredientStack toIngredientStack(IIngredient ingredient) { if (IngredientHelper.isItem(ingredient)) { return new IngredientStack(IngredientHelper.toItemStack(ingredient).copy()); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/inspirations/Inspirations.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/inspirations/Inspirations.java index 65b92f3b8..41eabc3af 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/inspirations/Inspirations.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/inspirations/Inspirations.java @@ -1,14 +1,10 @@ package com.cleanroommc.groovyscript.compat.mods.inspirations; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class Inspirations extends ModPropertyContainer { +public class Inspirations extends GroovyPropertyContainer { public final Cauldron cauldron = new Cauldron(); public final AnvilSmashing anvilSmashing = new AnvilSmashing(); - public Inspirations() { - addRegistry(cauldron); - addRegistry(anvilSmashing); - } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/integrateddynamics/IntegratedDynamics.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/integrateddynamics/IntegratedDynamics.java index 83fdb40f5..a8a281db5 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/integrateddynamics/IntegratedDynamics.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/integrateddynamics/IntegratedDynamics.java @@ -1,18 +1,12 @@ package com.cleanroommc.groovyscript.compat.mods.integrateddynamics; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class IntegratedDynamics extends ModPropertyContainer { +public class IntegratedDynamics extends GroovyPropertyContainer { public final DryingBasin dryingBasin = new DryingBasin(); public final MechanicalDryingBasin mechanicalDryingBasin = new MechanicalDryingBasin(); public final Squeezer squeezer = new Squeezer(); public final MechanicalSqueezer mechanicalSqueezer = new MechanicalSqueezer(); - public IntegratedDynamics() { - addRegistry(dryingBasin); - addRegistry(mechanicalDryingBasin); - addRegistry(squeezer); - addRegistry(mechanicalSqueezer); - } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/jei/JustEnoughItems.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/jei/JustEnoughItems.java index 170f7a53e..abb931f2d 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/jei/JustEnoughItems.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/jei/JustEnoughItems.java @@ -1,19 +1,12 @@ package com.cleanroommc.groovyscript.compat.mods.jei; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class JustEnoughItems extends ModPropertyContainer { +public class JustEnoughItems extends GroovyPropertyContainer { public final Ingredient ingredient = new Ingredient(); public final Category category = new Category(); public final Description description = new Description(); public final Catalyst catalyst = new Catalyst(); - public JustEnoughItems() { - addRegistry(ingredient); - addRegistry(category); - addRegistry(description); - addRegistry(catalyst); - } - } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Mekanism.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Mekanism.java index 7d5913589..98c7135d6 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Mekanism.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Mekanism.java @@ -1,10 +1,10 @@ package com.cleanroommc.groovyscript.compat.mods.mekanism; -import com.cleanroommc.groovyscript.api.IGameObjectParser; import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.IObjectParser; import com.cleanroommc.groovyscript.api.Result; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandler; +import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import mekanism.api.gas.Gas; import mekanism.api.gas.GasRegistry; import mekanism.api.gas.GasStack; @@ -15,7 +15,7 @@ import net.minecraftforge.fml.common.Optional; import org.jetbrains.annotations.Nullable; -public class Mekanism extends ModPropertyContainer { +public class Mekanism extends GroovyPropertyContainer { public final Infusion infusion = new Infusion(); @@ -38,43 +38,20 @@ public class Mekanism extends ModPropertyContainer { public final ThermalEvaporationPlant thermalEvaporationPlant = new ThermalEvaporationPlant(); public final Washer washer = new Washer(); - public Mekanism() { - addRegistry(infusion); - - addRegistry(chemicalInfuser); - addRegistry(combiner); - addRegistry(crusher); - addRegistry(crystallizer); - addRegistry(dissolutionChamber); - addRegistry(electrolyticSeparator); - addRegistry(enrichmentChamber); - addRegistry(injectionChamber); - addRegistry(metallurgicInfuser); - addRegistry(osmiumCompressor); - addRegistry(chemicalOxidizer); - addRegistry(pressurizedReactionChamber); - addRegistry(purificationChamber); - addRegistry(sawmill); - addRegistry(smelting); - addRegistry(solarNeutronActivator); - addRegistry(thermalEvaporationPlant); - addRegistry(washer); - } - @Override - public void initialize() { - GameObjectHandler.builder("gas", GasStack.class) - .mod("mekanism") + public void initialize(GroovyContainer container) { + container.objectMapperBuilder("gas", GasStack.class) .parser((s, args) -> { Gas gas = GasRegistry.getGas(s); return gas == null ? Result.error() : Result.some(new GasStack(gas, 1)); }) .completerOfNamed(GasRegistry::getRegisteredGasses, Gas::getName) + .docOfType("gas stack") .register(); - GameObjectHandler.builder("infusion", InfuseType.class) - .mod("mekanism") - .parser(IGameObjectParser.wrapStringGetter(InfuseRegistry::get, true)) + container.objectMapperBuilder("infusionType", InfuseType.class) // infusion clashes with infusion field + .parser(IObjectParser.wrapStringGetter(InfuseRegistry::get, true)) .completerOfNames(InfuseRegistry.getInfuseMap()::keySet) + .docOfType("infusion type") .register(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/naturesaura/NaturesAura.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/naturesaura/NaturesAura.java index a9aa65699..dc99007d8 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/naturesaura/NaturesAura.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/naturesaura/NaturesAura.java @@ -1,19 +1,12 @@ package com.cleanroommc.groovyscript.compat.mods.naturesaura; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class NaturesAura extends ModPropertyContainer { +public class NaturesAura extends GroovyPropertyContainer { public final Altar altar = new Altar(); public final Ritual ritual = new Ritual(); public final Offering offering = new Offering(); public final Spawning spawning = new Spawning(); - public NaturesAura() { - addRegistry(altar); - addRegistry(ritual); - addRegistry(offering); - addRegistry(spawning); - } - } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/pyrotech/PyroTech.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/pyrotech/PyroTech.java index 4128263e5..5a23c7f3c 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/pyrotech/PyroTech.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/pyrotech/PyroTech.java @@ -1,8 +1,8 @@ package com.cleanroommc.groovyscript.compat.mods.pyrotech; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class PyroTech extends ModPropertyContainer { +public class PyroTech extends GroovyPropertyContainer { public static final Barrel barrel = new Barrel(); public static final Campfire campfire = new Campfire(); @@ -16,17 +16,4 @@ public class PyroTech extends ModPropertyContainer { public static final SoakingPot soakingPot = new SoakingPot(); public static final TanningRack tanningRack = new TanningRack(); - public PyroTech() { - addRegistry(barrel); - addRegistry(campfire); - addRegistry(choppingBlock); - addRegistry(compactingBin); - addRegistry(compostBin); - addRegistry(crudeDryingRack); - addRegistry(dryingRack); - addRegistry(kiln); - addRegistry(anvil); - addRegistry(soakingPot); - addRegistry(tanningRack); - } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/roots/Roots.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/roots/Roots.java index 591b0e149..282b870a6 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/roots/Roots.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/roots/Roots.java @@ -1,10 +1,10 @@ package com.cleanroommc.groovyscript.compat.mods.roots; -import com.cleanroommc.groovyscript.api.IGameObjectParser; +import com.cleanroommc.groovyscript.api.IObjectParser; import com.cleanroommc.groovyscript.api.Result; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandler; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandlers; +import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; +import com.cleanroommc.groovyscript.mapper.ObjectMappers; import epicsquid.roots.api.Herb; import epicsquid.roots.init.HerbRegistry; import epicsquid.roots.modifiers.CostType; @@ -17,7 +17,7 @@ import epicsquid.roots.spell.SpellRegistry; import net.minecraft.util.ResourceLocation; -public class Roots extends ModPropertyContainer { +public class Roots extends GroovyPropertyContainer { public final AnimalHarvest animalHarvest = new AnimalHarvest(); public final AnimalHarvestFish animalHarvestFish = new AnimalHarvestFish(); @@ -39,61 +39,39 @@ public class Roots extends ModPropertyContainer { public final SummonCreature summonCreature = new SummonCreature(); public final Transmutation transmutation = new Transmutation(); - public Roots() { - addRegistry(animalHarvest); - addRegistry(animalHarvestFish); - addRegistry(barkCarving); - addRegistry(chrysopoeia); - addRegistry(feyCrafter); - addRegistry(flowerGeneration); - addRegistry(lifeEssence); - addRegistry(modifiers); - addRegistry(moss); - addRegistry(mortar); - addRegistry(pacifist); - addRegistry(pyre); - addRegistry(predicates); - addRegistry(rituals); - addRegistry(runicShearBlock); - addRegistry(runicShearEntity); - addRegistry(spells); - addRegistry(summonCreature); - addRegistry(transmutation); - } - @Override - public void initialize() { - GameObjectHandler.builder("ritual", RitualBase.class) - .mod("roots") - .parser(IGameObjectParser.wrapStringGetter(RitualRegistry::getRitual)) + public void initialize(GroovyContainer container) { + container.objectMapperBuilder("ritual", RitualBase.class) + .parser(IObjectParser.wrapStringGetter(RitualRegistry::getRitual)) .completerOfNames(() -> RitualRegistry.ritualRegistry.keySet()) + .docOfType("ritual") .register(); - GameObjectHandler.builder("herb", Herb.class) - .mod("roots") - .parser(IGameObjectParser.wrapStringGetter(HerbRegistry::getHerbByName)) + container.objectMapperBuilder("herb", Herb.class) + .parser(IObjectParser.wrapStringGetter(HerbRegistry::getHerbByName)) .completerOfNames(HerbRegistry.registry::keySet) + .docOfType("herb") .register(); - GameObjectHandler.builder("cost", CostType.class) - .mod("roots") - .parser(IGameObjectParser.wrapEnum(CostType.class, false)) + container.objectMapperBuilder("cost", CostType.class) + .parser(IObjectParser.wrapEnum(CostType.class, false)) .completerOfEnum(CostType.class, false) + .docOfType("cost") .register(); - GameObjectHandler.builder("spell", SpellBase.class) - .mod("roots") + container.objectMapperBuilder("spell", SpellBase.class) .parser(Roots::getSpell) .completer(SpellRegistry.spellRegistry::keySet) .defaultValueSup(() -> Result.some(FakeSpell.INSTANCE)) // crashes otherwise + .docOfType("spell") .register(); - GameObjectHandler.builder("modifier", Modifier.class) - .mod("roots") + container.objectMapperBuilder("modifier", Modifier.class) .parser(Roots::getModifier) .completerOfNamed(ModifierRegistry::getModifiers, v -> v.getRegistryName().toString()) + .docOfType("modifier") .register(); } private static Result getSpell(String s, Object... args) { if (s.contains(":")) { - Result rl = GameObjectHandlers.parseResourceLocation(s, args); + Result rl = ObjectMappers.parseResourceLocation(s, args); if (rl.hasError()) return Result.error(rl.getError()); SpellBase spell = SpellRegistry.getSpell(rl.getValue()); return spell == null ? Result.error() : Result.some(spell); @@ -106,7 +84,7 @@ private static Result getSpell(String s, Object... args) { } private static Result getModifier(String s, Object... args) { - Result rl = GameObjectHandlers.parseResourceLocation(s, args); + Result rl = ObjectMappers.parseResourceLocation(s, args); if (rl.hasError()) return Result.error(rl.getError()); Modifier modifier = ModifierRegistry.get(rl.getValue()); return modifier == null ? Result.error() : Result.some(modifier); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/rustic/Rustic.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/rustic/Rustic.java index 89afb99a8..631095f31 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/rustic/Rustic.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/rustic/Rustic.java @@ -1,19 +1,12 @@ package com.cleanroommc.groovyscript.compat.mods.rustic; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class Rustic extends ModPropertyContainer { +public class Rustic extends GroovyPropertyContainer { public final Alchemy alchemy = new Alchemy(); public final BrewingBarrel brewingBarrel = new BrewingBarrel(); public final CrushingTub crushingTub = new CrushingTub(); public final EvaporatingBasin evaporatingBasin = new EvaporatingBasin(); - public Rustic() { - addRegistry(alchemy); - addRegistry(brewingBarrel); - addRegistry(crushingTub); - addRegistry(evaporatingBasin); - } - } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/tcomplement/TinkersComplement.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/tcomplement/TinkersComplement.java index ac032aad8..916939ff0 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/tcomplement/TinkersComplement.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/tcomplement/TinkersComplement.java @@ -1,14 +1,10 @@ package com.cleanroommc.groovyscript.compat.mods.tcomplement; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class TinkersComplement extends ModPropertyContainer { +public class TinkersComplement extends GroovyPropertyContainer { public final Melter melter = new Melter(); public final HighOven highOven = new HighOven(); - public TinkersComplement() { - addRegistry(melter); - addRegistry(highOven); - } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/Thaumcraft.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/Thaumcraft.java index ca42efc62..8486e1e30 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/Thaumcraft.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/Thaumcraft.java @@ -1,8 +1,9 @@ package com.cleanroommc.groovyscript.compat.mods.thaumcraft; import com.cleanroommc.groovyscript.api.GroovyLog; -import com.cleanroommc.groovyscript.api.IGameObjectParser; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.api.IObjectParser; +import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import com.cleanroommc.groovyscript.compat.mods.thaumcraft.arcane.ArcaneWorkbench; import com.cleanroommc.groovyscript.compat.mods.thaumcraft.aspect.Aspect; import com.cleanroommc.groovyscript.compat.mods.thaumcraft.aspect.AspectHelper; @@ -10,7 +11,6 @@ import com.cleanroommc.groovyscript.compat.mods.thaumcraft.aspect.AspectStack; import com.cleanroommc.groovyscript.compat.mods.thaumcraft.warp.Warp; import com.cleanroommc.groovyscript.compat.mods.thaumcraft.warp.WarpItemStackExpansion; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandler; import com.cleanroommc.groovyscript.sandbox.expand.ExpansionHelper; import net.minecraft.item.ItemStack; import thaumcraft.api.ThaumcraftApiHelper; @@ -18,7 +18,7 @@ import java.util.Collection; -public class Thaumcraft extends ModPropertyContainer { +public class Thaumcraft extends GroovyPropertyContainer { public final Crucible crucible = new Crucible(); public final InfusionCrafting infusionCrafting = new InfusionCrafting(); @@ -32,31 +32,18 @@ public class Thaumcraft extends ModPropertyContainer { public final AspectHelper aspectHelper = new AspectHelper(); - public Thaumcraft() { - addRegistry(crucible); - addRegistry(infusionCrafting); - addRegistry(lootBag); - addRegistry(dustTrigger); - addRegistry(smeltingBonus); - addRegistry(warp); - addRegistry(aspectHelper); - addRegistry(arcaneWorkbench); - addRegistry(aspect); - addRegistry(research); - } - @Override - public void initialize() { - GameObjectHandler.builder("aspect", AspectStack.class) - .mod("thaumcraft") - .parser(IGameObjectParser.wrapStringGetter(Thaumcraft::getAspect, AspectStack::new)) + public void initialize(GroovyContainer container) { + container.objectMapperBuilder("aspect", AspectStack.class) + .parser(IObjectParser.wrapStringGetter(Thaumcraft::getAspect, AspectStack::new)) .completerOfNames(thaumcraft.api.aspects.Aspect.aspects::keySet) + .docOfType("aspect stack") .register(); - GameObjectHandler.builder("crystal", ItemStack.class) - .mod("thaumcraft") - .parser(IGameObjectParser.wrapStringGetter(Thaumcraft::getAspect, ThaumcraftApiHelper::makeCrystal)) + container.objectMapperBuilder("crystal", ItemStack.class) + .parser(IObjectParser.wrapStringGetter(Thaumcraft::getAspect, ThaumcraftApiHelper::makeCrystal)) .completerOfNames(thaumcraft.api.aspects.Aspect.aspects::keySet) .defaultValue(() -> ItemStack.EMPTY) + .docOfType("aspect crystal as item stack") .register(); ExpansionHelper.mixinClass(ItemStack.class, AspectItemStackExpansion.class); ExpansionHelper.mixinClass(ItemStack.class, WarpItemStackExpansion.class); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/ThermalExpansion.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/ThermalExpansion.java index 10bd5c8c2..e8920a661 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/ThermalExpansion.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/ThermalExpansion.java @@ -1,17 +1,18 @@ package com.cleanroommc.groovyscript.compat.mods.thermalexpansion; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import cofh.thermalexpansion.util.managers.machine.CompactorManager; -import com.cleanroommc.groovyscript.api.IGameObjectParser; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.api.IObjectParser; +import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; import com.cleanroommc.groovyscript.compat.mods.thermalexpansion.device.*; import com.cleanroommc.groovyscript.compat.mods.thermalexpansion.dynamo.*; import com.cleanroommc.groovyscript.compat.mods.thermalexpansion.machine.*; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandler; +import com.cleanroommc.groovyscript.mapper.ObjectMapper; import java.util.Arrays; import java.util.Locale; -public class ThermalExpansion extends ModPropertyContainer { +public class ThermalExpansion extends GroovyPropertyContainer { public final Brewer brewer = new Brewer(); public final Centrifuge centrifuge = new Centrifuge(); @@ -49,52 +50,12 @@ public class ThermalExpansion extends ModPropertyContainer { public final TransposerFill transposerFill = new TransposerFill(); public final XpCollector xpCollector = new XpCollector(); - - public ThermalExpansion() { - addRegistry(brewer); - addRegistry(centrifuge); - addRegistry(centrifugeMob); - addRegistry(charger); - addRegistry(compactor); - addRegistry(compression); - addRegistry(coolant); - addRegistry(crucible); - addRegistry(diffuser); - addRegistry(enchanter); - addRegistry(enervation); - addRegistry(extruder); - addRegistry(factorizer); - addRegistry(fisher); - addRegistry(fisherBait); - addRegistry(furnace); - addRegistry(furnacePyrolysis); - addRegistry(insolator); - addRegistry(lapidary); - addRegistry(magmatic); - addRegistry(numismatic); - addRegistry(precipitator); - addRegistry(pulverizer); - addRegistry(reactant); - addRegistry(refinery); - addRegistry(refineryPotion); - addRegistry(sawmill); - addRegistry(smelter); - addRegistry(steam); - addRegistry(tapper); - addRegistry(tapperFertilizer); - addRegistry(tapperTree); - addRegistry(transposerExtract); - addRegistry(transposerFill); - addRegistry(xpCollector); - } - @Override - public void initialize() { - GameObjectHandler.builder("compactorMode", CompactorManager.Mode.class) + public void initialize(GroovyContainer owner) { + ObjectMapper.builder("compactorMode", CompactorManager.Mode.class) .mod("thermalexpansion") - .parser(IGameObjectParser.wrapEnum(CompactorManager.Mode.class, false)) + .parser(IObjectParser.wrapEnum(CompactorManager.Mode.class, false)) .completerOfNamed(() -> Arrays.asList(CompactorManager.Mode.values()), v -> v.name().toUpperCase(Locale.ROOT)) .register(); } - } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/TinkersConstruct.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/TinkersConstruct.java index bc898aad8..9a1ca846e 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/TinkersConstruct.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/TinkersConstruct.java @@ -1,18 +1,18 @@ package com.cleanroommc.groovyscript.compat.mods.tinkersconstruct; -import com.cleanroommc.groovyscript.api.IGameObjectParser; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.api.IObjectParser; +import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import com.cleanroommc.groovyscript.compat.mods.tinkersconstruct.material.GroovyMaterial; import com.cleanroommc.groovyscript.compat.mods.tinkersconstruct.material.MaterialRegistryEvent; import com.cleanroommc.groovyscript.compat.mods.tinkersconstruct.material.ToolMaterialBuilder; import com.cleanroommc.groovyscript.compat.mods.tinkersconstruct.material.traits.TraitRegistryEvent; import com.cleanroommc.groovyscript.core.mixin.tconstruct.TinkerRegistryAccessor; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandler; import net.minecraftforge.common.MinecraftForge; import slimeknights.tconstruct.library.materials.Material; import slimeknights.tconstruct.library.traits.ITrait; -public class TinkersConstruct extends ModPropertyContainer { +public class TinkersConstruct extends GroovyPropertyContainer { public final Drying drying = new Drying(); public final Melting melting = new Melting(); @@ -23,34 +23,23 @@ public class TinkersConstruct extends ModPropertyContainer { public final CastingBasin castingBasin = new CastingBasin(); public final Materials materials = new Materials(); - public TinkersConstruct() { - addRegistry(drying); - addRegistry(melting); - addRegistry(entityMelting); - addRegistry(smelteryFuel); - addRegistry(alloying); - addRegistry(castingTable); - addRegistry(castingBasin); - addRegistry(materials); - } - @Override - public void initialize() { - GameObjectHandler.builder("toolMaterial", Material.class) - .mod("tconstruct") - .parser(IGameObjectParser.wrapStringGetter(TinkerRegistryAccessor.getMaterials()::get)) + public void initialize(GroovyContainer container) { + container.objectMapperBuilder("toolMaterial", Material.class) + .parser(IObjectParser.wrapStringGetter(TinkerRegistryAccessor.getMaterials()::get)) .completerOfNames(TinkerRegistryAccessor.getMaterials()::keySet) + .docOfType("tool material") .register(); - GameObjectHandler.builder("toolTrait", ITrait.class) - .mod("tconstruct") - .parser(IGameObjectParser.wrapStringGetter(TinkerRegistryAccessor.getTraits()::get)) + container.objectMapperBuilder("toolTrait", ITrait.class) + .parser(IObjectParser.wrapStringGetter(TinkerRegistryAccessor.getTraits()::get)) .completerOfNamed(TinkerRegistryAccessor.getTraits()::keySet, v -> v.endsWith("_armor") ? null : v) // only suggest non armor traits + .docOfType("tool trait") .register(); - GameObjectHandler.builder("armorTrait", ITrait.class) - .mod("tconstruct") - .parser(IGameObjectParser.wrapStringGetter(s -> TinkerRegistryAccessor.getTraits().get(s + "_armor"))) - .completerOfNamed(TinkerRegistryAccessor.getTraits()::keySet, v -> v.endsWith("_armor") ? v.substring(0, v.length() - 6) - : null) // only suggest armor traits + container.objectMapperBuilder("armorTrait", ITrait.class) + .parser(IObjectParser.wrapStringGetter(s -> TinkerRegistryAccessor.getTraits().get(s + "_armor"))) + .completerOfNamed(TinkerRegistryAccessor.getTraits()::keySet, + v -> v.endsWith("_armor") ? v.substring(0, v.length() - 6) : null) // only suggest armor traits + .docOfType("armor trait") .register(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/woot/Woot.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/woot/Woot.java index f0aec1566..af8c76a9b 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/woot/Woot.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/woot/Woot.java @@ -1,8 +1,8 @@ package com.cleanroommc.groovyscript.compat.mods.woot; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; -public class Woot extends ModPropertyContainer { +public class Woot extends GroovyPropertyContainer { public final StygianIronAnvil stygianIronAnvil = new StygianIronAnvil(); public final Drops drops = new Drops(); @@ -10,11 +10,4 @@ public class Woot extends ModPropertyContainer { public final Policy policy = new Policy(); public final MobConfig mobConfig = new MobConfig(); - public Woot() { - addRegistry(stygianIronAnvil); - addRegistry(drops); - addRegistry(spawning); - addRegistry(policy); - addRegistry(mobConfig); - } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/VanillaModule.java b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/VanillaModule.java index 2eb9962b6..a4a96112b 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/VanillaModule.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/VanillaModule.java @@ -6,13 +6,14 @@ import com.cleanroommc.groovyscript.compat.content.Content; import com.cleanroommc.groovyscript.compat.inworldcrafting.InWorldCrafting; import com.cleanroommc.groovyscript.compat.loot.Loot; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import com.cleanroommc.groovyscript.sandbox.expand.ExpansionHelper; import net.minecraft.item.ItemStack; import java.util.Collection; import java.util.Collections; -public class VanillaModule implements IScriptReloadable { +public class VanillaModule extends GroovyPropertyContainer implements IScriptReloadable { public static final VanillaModule INSTANCE = new VanillaModule(); diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/groovy/MetaClassImplMixin.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/groovy/MetaClassImplMixin.java index 2bc0d7732..e53c745bd 100644 --- a/src/main/java/com/cleanroommc/groovyscript/core/mixin/groovy/MetaClassImplMixin.java +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/groovy/MetaClassImplMixin.java @@ -1,6 +1,7 @@ package com.cleanroommc.groovyscript.core.mixin.groovy; import com.cleanroommc.groovyscript.api.IDynamicGroovyProperty; +import groovy.lang.Closure; import groovy.lang.MetaClassImpl; import groovy.lang.Script; import org.spongepowered.asm.mixin.Mixin; @@ -31,4 +32,14 @@ public void invokeStaticMissingMethod(Class sender, String methodName, Object cir.setReturnValue(null); } } + + @Inject(method = "invokePropertyOrMissing", at = @At("HEAD"), cancellable = true) + public void invokePropertyOrMissing(Object object, String methodName, Object[] originalArguments, boolean fromInsideClass, boolean isCallToSuper, CallbackInfoReturnable cir) { + if (!isCallToSuper && object instanceof IDynamicGroovyProperty dynamicGroovyProperty) { + Object o = dynamicGroovyProperty.getProperty(methodName); + if (o instanceof Closure closure) { + cir.setReturnValue(closure.call(originalArguments)); + } + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/documentation/Builder.java b/src/main/java/com/cleanroommc/groovyscript/documentation/Builder.java index 2e4ddeb5a..d33a33134 100644 --- a/src/main/java/com/cleanroommc/groovyscript/documentation/Builder.java +++ b/src/main/java/com/cleanroommc/groovyscript/documentation/Builder.java @@ -3,7 +3,7 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.documentation.annotations.*; import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import com.google.common.collect.ComparisonChain; import it.unimi.dsi.fastutil.chars.Char2CharArrayMap; import it.unimi.dsi.fastutil.chars.Char2CharMap; @@ -29,7 +29,7 @@ public class Builder { defaultReturnValue(Character.MIN_VALUE); }}; - private final GroovyContainer mod; + private final GroovyContainer mod; private final String reference; private final Method builderMethod; private final RecipeBuilderDescription annotation; @@ -37,7 +37,7 @@ public class Builder { private final Map> methods; private final List registrationMethods; - public Builder(GroovyContainer mod, Method builderMethod, String reference, String baseTranslationKey) { + public Builder(GroovyContainer mod, Method builderMethod, String reference, String baseTranslationKey) { this.mod = mod; this.builderMethod = builderMethod; this.reference = reference; diff --git a/src/main/java/com/cleanroommc/groovyscript/documentation/Documentation.java b/src/main/java/com/cleanroommc/groovyscript/documentation/Documentation.java index 1b2fcad67..7b925aea1 100644 --- a/src/main/java/com/cleanroommc/groovyscript/documentation/Documentation.java +++ b/src/main/java/com/cleanroommc/groovyscript/documentation/Documentation.java @@ -3,7 +3,7 @@ import com.cleanroommc.groovyscript.GroovyScript; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.documentation.format.IFormat; import com.cleanroommc.groovyscript.documentation.format.OutputFormat; @@ -53,7 +53,7 @@ public static void generateExamples() { File target = new File(EXAMPLES, stage.getName()); Files.createDirectories(target.toPath()); - for (GroovyContainer mod : ModSupport.getAllContainers()) { + for (GroovyContainer mod : ModSupport.getAllContainers()) { if (!mod.isLoaded()) continue; Exporter.generateExamples(stage.getName(), mod); } @@ -67,7 +67,7 @@ public static void generateExamples() { public static void generateWiki() { try { Files.createDirectories(WIKI.toPath()); - for (GroovyContainer mod : ModSupport.getAllContainers()) { + for (GroovyContainer mod : ModSupport.getAllContainers()) { if (!mod.isLoaded()) continue; File target = new File(WIKI, mod.getModId()); if (target.exists() || Files.createDirectories(target.toPath()) != null) { diff --git a/src/main/java/com/cleanroommc/groovyscript/documentation/Exporter.java b/src/main/java/com/cleanroommc/groovyscript/documentation/Exporter.java index 48881acba..091ee9269 100644 --- a/src/main/java/com/cleanroommc/groovyscript/documentation/Exporter.java +++ b/src/main/java/com/cleanroommc/groovyscript/documentation/Exporter.java @@ -6,7 +6,7 @@ import com.cleanroommc.groovyscript.api.IScriptReloadable; import com.cleanroommc.groovyscript.api.documentation.annotations.RegistryDescription; import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import com.google.common.collect.ComparisonChain; import net.minecraft.client.resources.I18n; @@ -41,7 +41,7 @@ private static String convertVarArgs(String name) { } - public static void generateWiki(File folder, GroovyContainer mod) { + public static void generateWiki(File folder, GroovyContainer mod) { List fileLinks = new ArrayList<>(); List registries = mod.get().getRegistries().stream() @@ -108,7 +108,7 @@ public static void generateWiki(File folder, GroovyContainer mod) { + public static void generateExamples(String target, GroovyContainer mod) { StringBuilder header = new StringBuilder(); StringBuilder body = new StringBuilder(); diff --git a/src/main/java/com/cleanroommc/groovyscript/documentation/Registry.java b/src/main/java/com/cleanroommc/groovyscript/documentation/Registry.java index 324733715..ad674f800 100644 --- a/src/main/java/com/cleanroommc/groovyscript/documentation/Registry.java +++ b/src/main/java/com/cleanroommc/groovyscript/documentation/Registry.java @@ -5,7 +5,7 @@ import com.cleanroommc.groovyscript.api.IScriptReloadable; import com.cleanroommc.groovyscript.api.documentation.annotations.*; import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import com.cleanroommc.groovyscript.documentation.linkgenerator.LinkGeneratorHooks; import com.google.common.collect.ComparisonChain; import net.minecraft.client.resources.I18n; @@ -19,7 +19,7 @@ public class Registry { - private final GroovyContainer mod; + private final GroovyContainer mod; private final INamed registry; private final String baseTranslationKey; private final String reference; @@ -29,7 +29,7 @@ public class Registry { private final EnumMap> methods = new EnumMap<>(MethodDescription.Type.class); private final List imports; - public Registry(GroovyContainer mod, INamed registry) { + public Registry(GroovyContainer mod, INamed registry) { this.mod = mod; this.registry = registry; this.baseTranslationKey = String.format("groovyscript.wiki.%s.%s", mod.getModId(), registry.getName()); diff --git a/src/main/java/com/cleanroommc/groovyscript/gameobjects/Completer.java b/src/main/java/com/cleanroommc/groovyscript/gameobjects/Completer.java index 4d8afdbf1..313cd76de 100644 --- a/src/main/java/com/cleanroommc/groovyscript/gameobjects/Completer.java +++ b/src/main/java/com/cleanroommc/groovyscript/gameobjects/Completer.java @@ -1,41 +1,21 @@ package com.cleanroommc.groovyscript.gameobjects; -import com.cleanroommc.groovyscript.server.Completions; import org.eclipse.lsp4j.CompletionItem; -import org.eclipse.lsp4j.CompletionItemKind; +import org.jetbrains.annotations.ApiStatus; import java.util.function.Function; import java.util.function.Supplier; +@Deprecated +@ApiStatus.ScheduledForRemoval(inVersion = "1.2.0") @FunctionalInterface -public interface Completer { - - void complete(int paramIndex, Completions items); +public interface Completer extends com.cleanroommc.groovyscript.mapper.Completer { static Completer ofNamed(Supplier> values, Function toString, int preferredParamIndex) { - return ofValues(values, v -> { - String s = toString.apply(v); - if (s != null) { - var item = new CompletionItem(toString.apply(v)); - item.setKind(CompletionItemKind.Constant); - return item; - } - return null; - }, preferredParamIndex); + return (Completer) com.cleanroommc.groovyscript.mapper.Completer.ofNamed(values, toString, preferredParamIndex); } static Completer ofValues(Supplier> values, Function toCompletionItem, int preferredParamIndex) { - return (paramIndex, items) -> { - if (preferredParamIndex < 0 || preferredParamIndex == paramIndex) { - items.addAll(values.get(), toCompletionItem); - } - }; - } - - default Completer and(Completer other) { - return (paramIndex, items) -> { - complete(paramIndex, items); - other.complete(paramIndex, items); - }; + return (Completer) com.cleanroommc.groovyscript.mapper.Completer.ofValues(values, toCompletionItem, preferredParamIndex); } } diff --git a/src/main/java/com/cleanroommc/groovyscript/gameobjects/GameObjectHandler.java b/src/main/java/com/cleanroommc/groovyscript/gameobjects/GameObjectHandler.java index 637e72a04..ec19a25e1 100644 --- a/src/main/java/com/cleanroommc/groovyscript/gameobjects/GameObjectHandler.java +++ b/src/main/java/com/cleanroommc/groovyscript/gameobjects/GameObjectHandler.java @@ -1,164 +1,14 @@ package com.cleanroommc.groovyscript.gameobjects; -import com.cleanroommc.groovyscript.api.GroovyLog; -import com.cleanroommc.groovyscript.api.IGameObjectParser; -import com.cleanroommc.groovyscript.api.Result; -import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.common.Loader; -import net.minecraftforge.registries.IForgeRegistry; -import net.minecraftforge.registries.IForgeRegistryEntry; -import org.eclipse.lsp4j.CompletionItem; -import org.eclipse.lsp4j.CompletionItemKind; - -import java.util.*; -import java.util.function.Function; -import java.util.function.Supplier; +import com.cleanroommc.groovyscript.mapper.ObjectMapper; +import org.jetbrains.annotations.ApiStatus; +@Deprecated +@ApiStatus.ScheduledForRemoval(inVersion = "1.2.0") public class GameObjectHandler { - public static Builder builder(String name, Class returnTpe) { - return new Builder<>(name, returnTpe); - } - - private final String name; - private final String mod; - private final IGameObjectParser handler; - private final Supplier> defaultValue; - private final Class returnType; - private final List[]> paramTypes; - private final Completer completer; - - private GameObjectHandler(String name, String mod, IGameObjectParser handler, Supplier> defaultValue, Class returnType, List[]> paramTypes, Completer completer) { - this.name = name; - this.mod = mod; - this.handler = handler; - this.defaultValue = defaultValue; - this.returnType = returnType; - this.paramTypes = paramTypes; - this.completer = completer; - } - - T invoke(String s, Object... args) { - Result t = Objects.requireNonNull(handler.parse(s, args), "Bracket handlers must return a non null result!"); - if (t.hasError()) { - if (this.mod == null) { - GroovyLog.get().error("Can't find {} for name {}!", name, s); - } else { - GroovyLog.get().error("Can't find {} {} for name {}!", mod, name, s); - } - if (t.getError() != null && !t.getError().isEmpty()) { - GroovyLog.get().error(" - reason: {}", t.getError()); - } - t = this.defaultValue.get(); - return t.hasError() ? null : t.getValue(); - } - return Objects.requireNonNull(t.getValue(), "Bracket handler result must contain a non-null value!"); - } - - public String getMod() { - return mod; - } - - public String getName() { - return name; - } - - public List[]> getParamTypes() { - return this.paramTypes; - } - - public Class getReturnType() { - return returnType; - } - - public Completer getCompleter() { - return completer; - } - - public static class Builder { - - private final String name; - private String mod; - private IGameObjectParser handler; - private Supplier> defaultValue; - private final Class returnType; - private final List[]> paramTypes = new ArrayList<>(); - private Completer completer; - - public Builder(String name, Class returnType) { - this.name = name; - this.returnType = returnType; - } - - public Builder mod(String mod) { - this.mod = mod; - return this; - } - - public Builder parser(IGameObjectParser handler) { - this.handler = handler; - return this; - } - - public Builder completer(Completer completer) { - if (this.completer == null) { - this.completer = completer; - } else { - this.completer = this.completer.and(completer); - } - return this; - } - - public Builder completerOfNames(Supplier> values) { - return completer(Completer.ofNamed(values, Function.identity(), 0)); - } - - public Builder completerOfNamed(Supplier> values, Function toString) { - return completer(Completer.ofNamed(values, toString, 0)); - } - - public > Builder completerOfEnum(Class values, boolean caseSensitive) { - return completerOfNamed(() -> Arrays.asList(values.getEnumConstants()), s -> caseSensitive ? s.name() : s.name().toLowerCase(Locale.ROOT)); - } - - public Builder completer(Supplier> values) { - return completer(Completer.ofValues(values, v -> { - CompletionItem item = new CompletionItem(v.toString()); - item.setKind(CompletionItemKind.Constant); - return item; - }, 0)); - } - - public > Builder completer(IForgeRegistry values) { - return completer(values::getKeys); - } - - public Builder defaultValue(Supplier defaultValue) { - return defaultValueSup(() -> Result.some(defaultValue.get())); - } - - public Builder defaultValueSup(Supplier> defaultValue) { - this.defaultValue = defaultValue; - return this; - } - - public Builder addSignature(Class... paramTypes) { - this.paramTypes.add(paramTypes); - return this; - } - - public void register() { - if (this.name == null || this.name.isEmpty()) throw new IllegalArgumentException("Name must not be empty"); - if (GameObjectHandlerManager.hasGameObjectHandler(this.name)) - throw new IllegalArgumentException("GameObjectHandler with name " + this.name + " already exists"); - if (this.mod != null && !Loader.isModLoaded(this.mod)) - throw new IllegalArgumentException("Tried to register GameObjectHandler for mod " + this.mod + ", but it's not loaded"); - Objects.requireNonNull(this.handler, () -> "The GameObjectHandler function must no be null"); - Objects.requireNonNull(this.returnType, () -> "The GameObjectHandler return type must not be null"); - if (this.paramTypes.isEmpty()) this.paramTypes.add(new Class[]{String.class}); - if (this.defaultValue == null) this.defaultValue = () -> null; - GameObjectHandlerManager.registerGameObjectHandler(new GameObjectHandler<>(this.name, this.mod, this.handler, this.defaultValue, - this.returnType, this.paramTypes, this.completer)); - } + @ApiStatus.Internal + public static ObjectMapper.Builder builder(String name, Class returnTpe) { + return ObjectMapper.builder(name, returnTpe); } } diff --git a/src/main/java/com/cleanroommc/groovyscript/gameobjects/GameObjectHandlerManager.java b/src/main/java/com/cleanroommc/groovyscript/gameobjects/GameObjectHandlerManager.java index ae0eb74f7..fde76dc38 100644 --- a/src/main/java/com/cleanroommc/groovyscript/gameobjects/GameObjectHandlerManager.java +++ b/src/main/java/com/cleanroommc/groovyscript/gameobjects/GameObjectHandlerManager.java @@ -1,157 +1,53 @@ package com.cleanroommc.groovyscript.gameobjects; -import com.cleanroommc.groovyscript.api.IGameObjectParser; -import com.cleanroommc.groovyscript.api.IIngredient; -import com.cleanroommc.groovyscript.api.Result; -import com.cleanroommc.groovyscript.core.mixin.CreativeTabsAccessor; -import com.cleanroommc.groovyscript.core.mixin.OreDictionaryAccessor; -import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; -import com.cleanroommc.groovyscript.helper.ingredient.OreDictWildcardIngredient; +import com.cleanroommc.groovyscript.mapper.ObjectMapper; +import com.cleanroommc.groovyscript.mapper.ObjectMapperManager; import com.cleanroommc.groovyscript.server.Completions; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.creativetab.CreativeTabs; -import net.minecraft.enchantment.Enchantment; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.potion.Potion; -import net.minecraft.potion.PotionType; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.SoundEvent; -import net.minecraft.util.text.TextFormatting; -import net.minecraft.world.biome.Biome; -import net.minecraftforge.fluids.FluidRegistry; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fml.common.registry.EntityEntry; -import net.minecraftforge.fml.common.registry.ForgeRegistries; -import net.minecraftforge.fml.common.registry.VillagerRegistry; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; import java.util.Collection; -import java.util.Locale; -import java.util.Map; +import java.util.List; +@Deprecated +@ApiStatus.ScheduledForRemoval(inVersion = "1.2.0") public class GameObjectHandlerManager { - private static final Map> handlers = new Object2ObjectOpenHashMap<>(); public static final String EMPTY = "empty", WILDCARD = "*", SPLITTER = ":"; - static void registerGameObjectHandler(GameObjectHandler goh) { - handlers.put(goh.getName(), goh); - } - public static void init() { - GameObjectHandler.builder("resource", ResourceLocation.class) - .parser(GameObjectHandlers::parseResourceLocation) - .addSignature(String.class) - .addSignature(String.class, String.class) - .register(); - GameObjectHandler.builder("ore", IIngredient.class) - .parser((s, args) -> s.contains(WILDCARD) ? Result.some(OreDictWildcardIngredient.of(s)) : Result.some(new OreDictIngredient(s))) - .completerOfNames(OreDictionaryAccessor::getIdToName) - .register(); - GameObjectHandler.builder("item", ItemStack.class) - .parser(GameObjectHandlers::parseItemStack) - .addSignature(String.class) - .addSignature(String.class, int.class) - .defaultValue(() -> ItemStack.EMPTY) - .completer(ForgeRegistries.ITEMS) - .register(); - GameObjectHandler.builder("liquid", FluidStack.class) - .parser(GameObjectHandlers::parseFluidStack) - .completerOfNames(FluidRegistry.getRegisteredFluids()::keySet) - .register(); - GameObjectHandler.builder("fluid", FluidStack.class) - .parser(GameObjectHandlers::parseFluidStack) - .completerOfNames(FluidRegistry.getRegisteredFluids()::keySet) - .register(); - GameObjectHandler.builder("block", Block.class) - .parser(IGameObjectParser.wrapForgeRegistry(ForgeRegistries.BLOCKS)) - .completer(ForgeRegistries.BLOCKS) - .register(); - GameObjectHandler.builder("blockstate", IBlockState.class) - .parser(GameObjectHandlers::parseBlockState) - .addSignature(String.class) - .addSignature(String.class, int.class) - .addSignature(String.class, String[].class) - .completer(ForgeRegistries.BLOCKS) - .register(); - GameObjectHandler.builder("enchantment", Enchantment.class) - .parser(IGameObjectParser.wrapForgeRegistry(ForgeRegistries.ENCHANTMENTS)) - .completer(ForgeRegistries.ENCHANTMENTS) - .register(); - GameObjectHandler.builder("potion", Potion.class) - .parser(IGameObjectParser.wrapForgeRegistry(ForgeRegistries.POTIONS)) - .completer(ForgeRegistries.POTIONS) - .register(); - GameObjectHandler.builder("potionType", PotionType.class) - .parser(IGameObjectParser.wrapForgeRegistry(ForgeRegistries.POTION_TYPES)) - .completer(ForgeRegistries.POTION_TYPES) - .register(); - GameObjectHandler.builder("sound", SoundEvent.class) - .parser(IGameObjectParser.wrapForgeRegistry(ForgeRegistries.SOUND_EVENTS)) - .completer(ForgeRegistries.SOUND_EVENTS) - .register(); - GameObjectHandler.builder("entity", EntityEntry.class) - .parser(IGameObjectParser.wrapForgeRegistry(ForgeRegistries.ENTITIES)) - .completer(ForgeRegistries.ENTITIES) - .register(); - GameObjectHandler.builder("biome", Biome.class) - .parser(IGameObjectParser.wrapForgeRegistry(ForgeRegistries.BIOMES)) - .completer(ForgeRegistries.BIOMES) - .register(); - GameObjectHandler.builder("profession", VillagerRegistry.VillagerProfession.class) - .parser(IGameObjectParser.wrapForgeRegistry(ForgeRegistries.VILLAGER_PROFESSIONS)) - .completer(ForgeRegistries.VILLAGER_PROFESSIONS) - .register(); - GameObjectHandler.builder("creativeTab", CreativeTabs.class) - .parser(GameObjectHandlers::parseCreativeTab) - .completerOfNamed(() -> Arrays.asList(CreativeTabs.CREATIVE_TAB_ARRAY), v -> ((CreativeTabsAccessor) v).getTabLabel2()) - .register(); - GameObjectHandler.builder("textformat", TextFormatting.class) - .parser(GameObjectHandlers::parseTextFormatting) - .completerOfNamed(() -> Arrays.asList(TextFormatting.values()), format -> format.name().toLowerCase(Locale.ROOT).replaceAll("[^a-z]", "")) - .register(); - GameObjectHandler.builder("nbt", NBTTagCompound.class) - .parser(GameObjectHandlers::parseNBT) - .register(); } - /** - * Finds the game object handle and invokes it. Called by injected calls via the groovy script transformer. - * - * @param name game object handler name (method name) - * @param mainArg main argument - * @param args extra arguments - * @return game object or null - */ @Nullable public static Object getGameObject(String name, String mainArg, Object... args) { - GameObjectHandler gameObjectHandler = handlers.get(name); - if (gameObjectHandler != null) { - return gameObjectHandler.invoke(mainArg, args); - } - return null; + return ObjectMapperManager.getGameObject(name, mainArg, args); } public static boolean hasGameObjectHandler(String key) { - return handlers.containsKey(key); + return ObjectMapperManager.hasObjectMapper(key); + } + + public static ObjectMapper getGameObjectHandler(String key) { + return ObjectMapperManager.getObjectMapper(key); + } + + public static List> getConflicts(String key) { + return ObjectMapperManager.getConflicts(key); + } + + public static ObjectMapper getGameObjectHandler(Class containerClass, String key) { + return ObjectMapperManager.getObjectMapper(containerClass, key); } - public static Collection> getGameObjectHandlers() { - return handlers.values(); + public static Collection> getGameObjectHandlers() { + return ObjectMapperManager.getObjectMappers(); } public static Class getReturnTypeOf(String name) { - GameObjectHandler goh = handlers.get(name); - return goh == null ? null : goh.getReturnType(); + return ObjectMapperManager.getReturnTypeOf(name); } public static void provideCompletion(String name, int index, Completions items) { - Completer completer = handlers.get(name).getCompleter(); - if (completer == null) return; - completer.complete(index, items); + ObjectMapperManager.provideCompletion(name, index, items); } } diff --git a/src/main/java/com/cleanroommc/groovyscript/gameobjects/GameObjectHandlers.java b/src/main/java/com/cleanroommc/groovyscript/gameobjects/GameObjectHandlers.java index d5413802b..fde0d50ce 100644 --- a/src/main/java/com/cleanroommc/groovyscript/gameobjects/GameObjectHandlers.java +++ b/src/main/java/com/cleanroommc/groovyscript/gameobjects/GameObjectHandlers.java @@ -1,219 +1,9 @@ package com.cleanroommc.groovyscript.gameobjects; -import com.cleanroommc.groovyscript.GroovyScript; -import com.cleanroommc.groovyscript.api.Result; -import com.cleanroommc.groovyscript.core.mixin.CreativeTabsAccessor; -import com.google.common.base.Optional; -import com.google.common.collect.Iterators; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import net.minecraft.block.Block; -import net.minecraft.block.material.Material; -import net.minecraft.block.properties.IProperty; -import net.minecraft.block.state.IBlockState; -import net.minecraft.creativetab.CreativeTabs; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.JsonToNBT; -import net.minecraft.nbt.NBTException; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.text.TextFormatting; -import net.minecraftforge.fluids.Fluid; -import net.minecraftforge.fluids.FluidRegistry; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fml.common.registry.ForgeRegistries; -import org.jetbrains.annotations.NotNull; +import com.cleanroommc.groovyscript.mapper.ObjectMappers; +import org.jetbrains.annotations.ApiStatus; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.Arrays; -import java.util.Iterator; -import java.util.Locale; -import java.util.Map; - -import static com.cleanroommc.groovyscript.gameobjects.GameObjectHandlerManager.SPLITTER; -import static com.cleanroommc.groovyscript.gameobjects.GameObjectHandlerManager.WILDCARD; - -public class GameObjectHandlers { - - private static final String COMMA = ",", EQUALS = "="; - - public static @NotNull Result parseResourceLocation(String mainArg, Object... args) { - String[] parts = mainArg.split(SPLITTER); - if (parts.length > 1) { - if (parts.length > 2) { - return Result.error("Resource location must only contain one ':' to separate mod and path."); - } - if (args.length > 0) { - return Result.error("If ':' is used in the resource location, no other arguments are allowed."); - } - return Result.some(new ResourceLocation(parts[0], parts[1])); - } - - if (args.length > 0) { - if (args.length > 1 || !(args[0] instanceof String)) { - return Result.error("Arguments not valid for bracket handler. Use 'resource(String)' or 'resource(String mod, String path)'"); - } - return Result.some(new ResourceLocation(mainArg, (String) args[0])); - } - return Result.some(new ResourceLocation(GroovyScript.getRunConfig().getPackId(), mainArg)); - } - - public static @NotNull Result parseItemStack(String mainArg, Object... args) { - if (args.length > 1 || (args.length == 1 && !(args[0] instanceof Integer))) { - return Result.error("Arguments not valid for bracket handler. Use 'item(String)' or 'item(String, int meta)'"); - } - String[] parts = mainArg.split(SPLITTER); - if (parts.length < 2) { - return Result.error("must contain a ':' to separate mod and path"); - } - Item item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(parts[0], parts[1])); - if (item == null) { - return Result.error(); - } - int meta = 0; - if (parts.length > 2) { - if (WILDCARD.equals(parts[2])) { - meta = Short.MAX_VALUE; - } else { - try { - meta = Integer.parseInt(parts[2]); - } catch (NumberFormatException ignored) { - } - } - } - if (args.length == 1) { - if (meta != 0) { - return Result.error("Defined meta value twice for item bracket handler"); - } - meta = (int) args[0]; - } - return Result.some(new ItemStack(item, 1, meta)); - } - - public static Result parseFluidStack(String s, Object... args) { - if (args.length > 0) return Result.error("No extra arguments are allowed."); - Fluid fluid = FluidRegistry.getFluid(s); - if (fluid == null) return Result.error(); - return Result.some(new FluidStack(fluid, 1)); - } - - public static @NotNull Result parseBlockState(String mainArg, Object... args) { - Result blockStateResult = parseBlockState(mainArg); - if (blockStateResult.hasError()) return blockStateResult; - IBlockState blockState = blockStateResult.getValue(); - if (args.length > 0) { - if (args.length == 1 && args[0] instanceof Integer) { - try { - return Result.some(blockState.getBlock().getStateFromMeta((Integer) args[0])); - } catch (Exception e) { - return Result.error("could not get block state from meta"); - } - } - for (Object arg : args) { - if (!(arg instanceof String)) { - return Result.error("All arguments must be strings!"); - } - } - String[] stringArgs = Arrays.stream(args).map(Object::toString).toArray(String[]::new); - return parseBlockStates(blockState, Iterators.forArray(stringArgs)); - } - return blockStateResult; - } - - public static Result parseBlockState(String arg) { - String[] parts = arg.split(SPLITTER); - if (parts.length < 2) { - return Result.error("Can't find block for '{}'", arg); - } - Block block = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(parts[0], parts[1])); - if (block == null) { - return Result.error("Can't find block for '{}'", arg); - } - IBlockState blockState = block.getDefaultState(); - if (parts.length > 2) { - String[] states = parts[2].split(COMMA); - if (states.length == 1) { - try { - int meta = Integer.parseInt(states[0]); - return Result.some(blockState.getBlock().getStateFromMeta(meta)); - } catch (NumberFormatException ignored) { - } catch (Exception e) { - return Result.error("could not get block state from meta"); - } - } - return parseBlockStates(blockState, Iterators.forArray(states)); - } - return Result.some(blockState); - } - - @SuppressWarnings("all") - private static Result parseBlockStates(IBlockState defaultState, Iterator iterable) { - for (Iterator it = iterable; it.hasNext(); ) { - String state = it.next(); - String[] prop = state.split(EQUALS, 2); - IProperty property = defaultState.getBlock().getBlockState().getProperty(prop[0]); - if (property == null) { - return Result.error("Invalid property name '{}' for block '{}'", prop[0], defaultState.getBlock().getRegistryName()); - } - Optional value = property.parseValue(prop[1]); - if (value.isPresent()) { - defaultState = defaultState.withProperty(property, value.get()); - } else { - return Result.error("Invalid property value '{}' for block '{}:{}'", prop[1], defaultState.getBlock().getRegistryName()); - } - } - return Result.some(defaultState); - } - - - public static Result parseCreativeTab(String mainArg, Object... args) { - for (CreativeTabs tab : CreativeTabs.CREATIVE_TAB_ARRAY) { - if (tab != null && mainArg.equals(((CreativeTabsAccessor) tab).getTabLabel2())) { - return Result.some(tab); - } - } - return Result.error(); - } - - public static Result parseTextFormatting(String mainArg, Object... args) { - TextFormatting textformat = TextFormatting.getValueByName(mainArg); - if (textformat == null) { - try { - textformat = TextFormatting.fromColorIndex(Integer.parseInt(mainArg)); - } catch (NumberFormatException e) { - return Result.error("argument is not a number and not a valid text formatting name"); - } - } - return textformat == null ? Result.error() : Result.some(textformat); - } - - private static Map materials; - - public static Result parseBlockMaterial(String mainArg, Object... args) { - if (materials == null) { - materials = new Object2ObjectOpenHashMap<>(); - for (Field field : Material.class.getFields()) { - if ((field.getModifiers() & Modifier.STATIC) != 0 && field.getType() == Material.class) { - try { - Material material = (Material) field.get(null); - materials.put(field.getName(), material); - materials.put(field.getName().toLowerCase(Locale.ROOT), material); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - } - } - Material material = materials.get(mainArg); - return material == null ? Result.error() : Result.some(material); - } - - public static @NotNull Result parseNBT(String mainArg, Object... args) { - try { - return Result.some(JsonToNBT.getTagFromJson(mainArg)); - } catch (NBTException e) { - return Result.error("unable to parse provided nbt string"); - } - } +@Deprecated +@ApiStatus.ScheduledForRemoval(inVersion = "1.2.0") +public class GameObjectHandlers extends ObjectMappers { } diff --git a/src/main/java/com/cleanroommc/groovyscript/helper/EnumHelper.java b/src/main/java/com/cleanroommc/groovyscript/helper/EnumHelper.java index 821b0ef1b..4d2c90cb1 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/EnumHelper.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/EnumHelper.java @@ -1,6 +1,6 @@ package com.cleanroommc.groovyscript.helper; -import com.cleanroommc.groovyscript.api.IGameObjectParser; +import com.cleanroommc.groovyscript.api.IObjectParser; import com.cleanroommc.groovyscript.api.Result; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.jetbrains.annotations.NotNull; @@ -12,15 +12,15 @@ public class EnumHelper { private static final Object[] EMPTY = new Object[0]; - private static final Map>, IGameObjectParser> cs = new Object2ObjectOpenHashMap<>(); - private static final Map>, IGameObjectParser> ncs = new Object2ObjectOpenHashMap<>(); + private static final Map>, IObjectParser> cs = new Object2ObjectOpenHashMap<>(); + private static final Map>, IObjectParser> ncs = new Object2ObjectOpenHashMap<>(); @NotNull public static > Result valueOf(Class clazz, String s, boolean caseSensitive) { var map = caseSensitive ? cs : ncs; - IGameObjectParser goh = map.get(clazz); + IObjectParser goh = map.get(clazz); if (goh == null) { - goh = IGameObjectParser.wrapEnum(clazz, caseSensitive); + goh = IObjectParser.wrapEnum(clazz, caseSensitive); map.put(clazz, goh); } return (Result) goh.parse(s, EMPTY); diff --git a/src/main/java/com/cleanroommc/groovyscript/mapper/Completer.java b/src/main/java/com/cleanroommc/groovyscript/mapper/Completer.java new file mode 100644 index 000000000..e38aef925 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/mapper/Completer.java @@ -0,0 +1,41 @@ +package com.cleanroommc.groovyscript.mapper; + +import com.cleanroommc.groovyscript.server.Completions; +import org.eclipse.lsp4j.CompletionItem; +import org.eclipse.lsp4j.CompletionItemKind; + +import java.util.function.Function; +import java.util.function.Supplier; + +@FunctionalInterface +public interface Completer { + + void complete(int paramIndex, Completions items); + + static Completer ofNamed(Supplier> values, Function toString, int preferredParamIndex) { + return ofValues(values, v -> { + String s = toString.apply(v); + if (s != null) { + var item = new CompletionItem(toString.apply(v)); + item.setKind(CompletionItemKind.Constant); + return item; + } + return null; + }, preferredParamIndex); + } + + static Completer ofValues(Supplier> values, Function toCompletionItem, int preferredParamIndex) { + return (paramIndex, items) -> { + if (preferredParamIndex < 0 || preferredParamIndex == paramIndex) { + items.addAll(values.get(), toCompletionItem); + } + }; + } + + default Completer and(Completer other) { + return (paramIndex, items) -> { + complete(paramIndex, items); + other.complete(paramIndex, items); + }; + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapper.java b/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapper.java new file mode 100644 index 000000000..9b834eb5c --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapper.java @@ -0,0 +1,336 @@ +package com.cleanroommc.groovyscript.mapper; + +import com.cleanroommc.groovyscript.api.*; +import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.ArrayUtils; +import com.cleanroommc.groovyscript.sandbox.expand.IDocumented; +import groovy.lang.Closure; +import groovy.lang.groovydoc.Groovydoc; +import groovy.lang.groovydoc.GroovydocHolder; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.registries.IForgeRegistry; +import net.minecraftforge.registries.IForgeRegistryEntry; +import org.apache.commons.lang3.StringUtils; +import org.codehaus.groovy.ast.ClassHelper; +import org.codehaus.groovy.ast.MethodNode; +import org.codehaus.groovy.ast.Parameter; +import org.eclipse.lsp4j.CompletionItem; +import org.eclipse.lsp4j.CompletionItemKind; +import org.jetbrains.annotations.ApiStatus; + +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * This class handles global getter functions like `item(...)` and `fluid(...)` + * + * @param return type of the function + */ +public class ObjectMapper extends Closure implements INamed, IDocumented { + + /** + * Creates an object mapper builder. + * Use {@link GroovyContainer#objectMapperBuilder(String, Class)} instead! + * + * @param name the function name + * @param returnType the return type + * @param the return type + * @return a new object mapper builder + */ + @ApiStatus.Internal + public static Builder builder(String name, Class returnType) { + return new Builder<>(name, returnType); + } + + private final String name; + private final GroovyContainer mod; + private final IObjectParser handler; + private final Supplier> defaultValue; + private final Class returnType; + private final List[]> paramTypes; + private final Completer completer; + private final String documentation; + private List methodNodes; + + private ObjectMapper(String name, GroovyContainer mod, IObjectParser handler, Supplier> defaultValue, Class returnType, List[]> paramTypes, Completer completer, String documentation) { + super(null); + this.name = name; + this.mod = mod; + this.handler = handler; + this.defaultValue = defaultValue; + this.returnType = returnType; + this.paramTypes = paramTypes; + this.completer = completer; + this.documentation = documentation; + } + + T invoke(String s, Object... args) { + Result t = Objects.requireNonNull(handler.parse(s, args), "Object mapper must return a non null result!"); + if (t.hasError()) { + if (this.mod == null) { + GroovyLog.get().error("Can't find {} for name {}!", name, s); + } else { + GroovyLog.get().error("Can't find {} {} for name {}!", mod, name, s); + } + if (t.getError() != null && !t.getError().isEmpty()) { + GroovyLog.get().error(" - reason: {}", t.getError()); + } + t = this.defaultValue.get(); + return t == null || t.hasError() ? null : t.getValue(); + } + return Objects.requireNonNull(t.getValue(), "Object napper result must contain a non-null value!"); + } + + public GroovyContainer getMod() { + return mod; + } + + @Override + public Collection getAliases() { + return Collections.singleton(this.name); + } + + public String getName() { + return name; + } + + public List[]> getParamTypes() { + return this.paramTypes; + } + + public Class getReturnType() { + return returnType; + } + + @GroovyBlacklist + public Completer getCompleter() { + return completer; + } + + public T doCall(String s, Object... args) { + return invoke(s, args); + } + + @Override + public String getDocumentation() { + return documentation; + } + + public List getMethodNodes() { + if (methodNodes == null) { + this.methodNodes = new ArrayList<>(); + for (Class[] paramType : this.paramTypes) { + Parameter[] params = ArrayUtils.map(paramType, c -> new Parameter(ClassHelper.makeCached(c), ""), + new Parameter[paramType.length]); + MethodNode node = new MethodNode(this.name, Modifier.PUBLIC | Modifier.FINAL, + ClassHelper.makeCached(this.returnType), params, null, null); + node.setDeclaringClass(this.mod != null ? + ClassHelper.makeCached(this.mod.get().getClass()) : + ClassHelper.makeCached(ObjectMapperManager.class)); + node.setNodeMetaData(GroovydocHolder.DOC_COMMENT, new Groovydoc(this.documentation, node)); + this.methodNodes.add(node); + } + } + return methodNodes; + } + + /** + * A helper class to create {@link ObjectMapper}s. + * + * @param the return type of the mapper + */ + public static class Builder { + + private final String name; + private GroovyContainer mod; + private IObjectParser handler; + private Supplier> defaultValue; + private final Class returnType; + private final List[]> paramTypes = new ArrayList<>(); + private Completer completer; + private String documentation; + + @ApiStatus.Internal + public Builder(String name, Class returnType) { + this.name = name; + this.returnType = returnType; + } + + /** + * Sets the mod who creates this mapper. This is already done when {@link GroovyContainer#objectMapperBuilder(String, Class)} is used. + * + * @param mod the creator mod + * @return this builder + * @throws IllegalStateException if GroovyScript doesn't have compat with that mod + */ + public Builder mod(String mod) { + return mod(ModSupport.INSTANCE.getContainer(mod)); + } + + /** + * Sets the mod who creates this mapper. This is already done when {@link GroovyContainer#objectMapperBuilder(String, Class)} is used. + * + * @param mod the creator mod + * @return this builder + */ + public Builder mod(GroovyContainer mod) { + if (this.mod == null) { + this.mod = mod; + } + return this; + } + + /** + * Sets the parser function. It receives a String and any amount of other arguments and returns an object of the specified type or an error. + * + * @param handler parser function + * @return this builder + */ + public Builder parser(IObjectParser handler) { + this.handler = handler; + return this; + } + + /** + * Sets a value completer. This is used by the LSP to provide completion for mappers. + * Take a look at {@link Completer}'s static methods for helpers. + * + * @param completer completer + * @return this builder + */ + public Builder completer(Completer completer) { + if (this.completer == null) { + this.completer = completer; + } else { + this.completer = this.completer.and(completer); + } + return this; + } + + /** + * Sets a value completer. This is used by the LSP to provide completion for mappers. + * + * @param values a supplier if a list of names + * @return this builder + */ + public Builder completerOfNames(Supplier> values) { + return completer(Completer.ofNamed(values, Function.identity(), 0)); + } + + /** + * Sets a value completer. This is used by the LSP to provide completion for mappers. + * + * @param values a supplier if a list of objects which have names + * @param toString a function to turn said objects into names + * @return this builder + */ + public Builder completerOfNamed(Supplier> values, Function toString) { + return completer(Completer.ofNamed(values, toString, 0)); + } + + /** + * Sets a value completer. This is used by the LSP to provide completion for mappers. + * + * @param values an enum class + * @param caseSensitive lower case names are used if this is false + * @return this builder + */ + public > Builder completerOfEnum(Class values, boolean caseSensitive) { + return completerOfNamed(() -> Arrays.asList(values.getEnumConstants()), s -> caseSensitive ? s.name() : s.name().toLowerCase(Locale.ROOT)); + } + + public Builder completer(Supplier> values) { + return completer(Completer.ofValues(values, v -> { + CompletionItem item = new CompletionItem(v.toString()); + item.setKind(CompletionItemKind.Constant); + return item; + }, 0)); + } + + /** + * Sets a value completer. This is used by the LSP to provide completion for mappers. + * + * @param values a forge registry + * @return this builder + */ + public > Builder completer(IForgeRegistry values) { + return completer(values::getKeys); + } + + /** + * Sets a default value. This is what the mapper returns when no value could be found or an error occurred. Default is null. + * + * @param defaultValue default value + * @return this builder + */ + public Builder defaultValue(Supplier defaultValue) { + return defaultValueSup(() -> Result.some(defaultValue.get())); + } + + /** + * Sets a default value. This is what the mapper returns when no value could be found or an error occurred. Default is null. + * + * @param defaultValue default value + * @return this builder + */ + public Builder defaultValueSup(Supplier> defaultValue) { + this.defaultValue = defaultValue; + return this; + } + + /** + * Adds a method signature. This is only used by LSP to provide helpful tooltips. + * + * @param paramTypes parameter types + * @return this builder + */ + public Builder addSignature(Class... paramTypes) { + this.paramTypes.add(paramTypes); + return this; + } + + /** + * Adds a documentation string. This is only used by LSP to provide helpful tooltips. + * + * @param doc documentation + * @return this builder + */ + public Builder documentation(String doc) { + this.documentation = doc; + return this; + } + + /** + * Adds a documentation string. This is only used by LSP to provide helpful tooltips. + * + * @param type type of the returned objects + * @return this builder + */ + public Builder docOfType(String type) { + String mod = this.mod == null ? StringUtils.EMPTY : this.mod.getContainerName() + ' '; + return documentation("returns a " + mod + type); + } + + /** + * Registers the mapper. + * + * @throws IllegalArgumentException if the mapper was misconfigured. + */ + public void register() { + if (this.name == null || this.name.isEmpty()) throw new IllegalArgumentException("Name must not be empty"); + if (this.mod != null && !this.mod.isLoaded()) + throw new IllegalArgumentException("Tried to register ObjectMapper for mod " + this.mod + ", but it's not loaded"); + Objects.requireNonNull(this.handler, () -> "The ObjectMapper function must no be null"); + Objects.requireNonNull(this.returnType, () -> "The ObjectMapper return type must not be null"); + if (this.paramTypes.isEmpty()) this.paramTypes.add(new Class[]{String.class}); + if (this.defaultValue == null) this.defaultValue = () -> null; + this.documentation = IDocumented.toJavaDoc(this.documentation); + ObjectMapper goh = new ObjectMapper<>(this.name, this.mod, this.handler, this.defaultValue, + this.returnType, this.paramTypes, this.completer, this.documentation); + ObjectMapperManager.registerObjectMapper(this.mod, goh); + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapperManager.java b/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapperManager.java new file mode 100644 index 000000000..e095d8602 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapperManager.java @@ -0,0 +1,216 @@ +package com.cleanroommc.groovyscript.mapper; + +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.IObjectParser; +import com.cleanroommc.groovyscript.api.Result; +import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; +import com.cleanroommc.groovyscript.core.mixin.CreativeTabsAccessor; +import com.cleanroommc.groovyscript.core.mixin.OreDictionaryAccessor; +import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; +import com.cleanroommc.groovyscript.helper.ingredient.OreDictWildcardIngredient; +import com.cleanroommc.groovyscript.sandbox.expand.ExpansionHelper; +import com.cleanroommc.groovyscript.server.Completions; +import groovy.lang.ExpandoMetaClass; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionType; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.world.biome.Biome; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.common.registry.EntityEntry; +import net.minecraftforge.fml.common.registry.ForgeRegistries; +import net.minecraftforge.fml.common.registry.VillagerRegistry; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public class ObjectMapperManager { + + private static final Map> handlers = new Object2ObjectOpenHashMap<>(); + private static final Map>> handlerConflicts = new Object2ObjectOpenHashMap<>(); + private static final Map, Map>> modHandlers = new Object2ObjectOpenHashMap<>(); + public static final String EMPTY = "empty"; + public static final String WILDCARD = "*"; + public static final String SPLITTER = ":"; + + static void registerObjectMapper(GroovyContainer container, ObjectMapper goh) { + String key = goh.getName(); + if (goh.getMod() != null) { + Class clazz = goh.getMod().get().getClass(); + for (Class[] paramTypes : goh.getParamTypes()) { + ExpandoMetaClass emc = ExpansionHelper.getExpandoClass(clazz); + emc.registerInstanceMethod(new ObjectMapperMetaMethod(goh, paramTypes, clazz)); + } + } + if (handlerConflicts.containsKey(key)) { + handlerConflicts.get(key).add(goh); + } else if (handlers.containsKey(key)) { + List> conflicts = handlerConflicts.computeIfAbsent(key, k -> new ArrayList<>()); + conflicts.add(handlers.remove(key)); + conflicts.add(goh); + } else { + handlers.put(key, goh); + } + if (container != null) { + GroovyPropertyContainer propertyContainer = container.get(); + var map = modHandlers.computeIfAbsent(propertyContainer.getClass(), k -> new Object2ObjectOpenHashMap<>()); + if (map.containsKey(key)) { + throw new IllegalStateException("There already is a ObjectMapper with name '" + key + "' in mod " + container.getContainerName()); + } + map.put(key, goh); + } + } + + public static void init() { + ObjectMapper.builder("resource", ResourceLocation.class) + .parser(ObjectMappers::parseResourceLocation) + .addSignature(String.class) + .addSignature(String.class, String.class) + .docOfType("resource location") + .register(); + ObjectMapper.builder("ore", IIngredient.class) + .parser((s, args) -> s.contains(WILDCARD) ? Result.some(OreDictWildcardIngredient.of(s)) : Result.some(new OreDictIngredient(s))) + .completerOfNames(OreDictionaryAccessor::getIdToName) + .docOfType("ore dict entry") + .register(); + ObjectMapper.builder("item", ItemStack.class) + .parser(ObjectMappers::parseItemStack) + .addSignature(String.class) + .addSignature(String.class, int.class) + .defaultValue(() -> ItemStack.EMPTY) + .completer(ForgeRegistries.ITEMS) + .docOfType("item stack") + .register(); + ObjectMapper.builder("liquid", FluidStack.class) + .parser(ObjectMappers::parseFluidStack) + .completerOfNames(FluidRegistry.getRegisteredFluids()::keySet) + .docOfType("fluid stack") + .register(); + ObjectMapper.builder("fluid", FluidStack.class) + .parser(ObjectMappers::parseFluidStack) + .completerOfNames(FluidRegistry.getRegisteredFluids()::keySet) + .register(); + ObjectMapper.builder("block", Block.class) + .parser(IObjectParser.wrapForgeRegistry(ForgeRegistries.BLOCKS)) + .completer(ForgeRegistries.BLOCKS) + .docOfType("block") + .register(); + ObjectMapper.builder("blockstate", IBlockState.class) + .parser(ObjectMappers::parseBlockState) + .addSignature(String.class) + .addSignature(String.class, int.class) + .addSignature(String.class, String[].class) + .completer(ForgeRegistries.BLOCKS) + .docOfType("block state") + .register(); + ObjectMapper.builder("enchantment", Enchantment.class) + .parser(IObjectParser.wrapForgeRegistry(ForgeRegistries.ENCHANTMENTS)) + .completer(ForgeRegistries.ENCHANTMENTS) + .docOfType("enchantment") + .register(); + ObjectMapper.builder("potion", Potion.class) + .parser(IObjectParser.wrapForgeRegistry(ForgeRegistries.POTIONS)) + .completer(ForgeRegistries.POTIONS) + .docOfType("potion") + .register(); + ObjectMapper.builder("potionType", PotionType.class) + .parser(IObjectParser.wrapForgeRegistry(ForgeRegistries.POTION_TYPES)) + .completer(ForgeRegistries.POTION_TYPES) + .docOfType("potion type") + .register(); + ObjectMapper.builder("sound", SoundEvent.class) + .parser(IObjectParser.wrapForgeRegistry(ForgeRegistries.SOUND_EVENTS)) + .completer(ForgeRegistries.SOUND_EVENTS) + .docOfType("sound") + .register(); + ObjectMapper.builder("entity", EntityEntry.class) + .parser(IObjectParser.wrapForgeRegistry(ForgeRegistries.ENTITIES)) + .completer(ForgeRegistries.ENTITIES) + .docOfType("entity entry") + .register(); + ObjectMapper.builder("biome", Biome.class) + .parser(IObjectParser.wrapForgeRegistry(ForgeRegistries.BIOMES)) + .completer(ForgeRegistries.BIOMES) + .docOfType("biome") + .register(); + ObjectMapper.builder("profession", VillagerRegistry.VillagerProfession.class) + .parser(IObjectParser.wrapForgeRegistry(ForgeRegistries.VILLAGER_PROFESSIONS)) + .completer(ForgeRegistries.VILLAGER_PROFESSIONS) + .docOfType("villager profession") + .register(); + ObjectMapper.builder("creativeTab", CreativeTabs.class) + .parser(ObjectMappers::parseCreativeTab) + .completerOfNamed(() -> Arrays.asList(CreativeTabs.CREATIVE_TAB_ARRAY), v -> ((CreativeTabsAccessor) v).getTabLabel2()) + .docOfType("creative tab") + .register(); + ObjectMapper.builder("textformat", TextFormatting.class) + .parser(ObjectMappers::parseTextFormatting) + .completerOfNamed(() -> Arrays.asList(TextFormatting.values()), format -> format.name().toLowerCase(Locale.ROOT).replaceAll("[^a-z]", "")) + .docOfType("text format") + .register(); + ObjectMapper.builder("nbt", NBTTagCompound.class) + .parser(ObjectMappers::parseNBT) + .docOfType("nbt tag") + .register(); + } + + /** + * Finds the game object handle and invokes it. Called by injected calls via the groovy script transformer. + * + * @param name game object handler name (method name) + * @param mainArg main argument + * @param args extra arguments + * @return game object or null + */ + @Nullable + public static Object getGameObject(String name, String mainArg, Object... args) { + ObjectMapper objectMapper = handlers.get(name); + if (objectMapper != null) { + return objectMapper.invoke(mainArg, args); + } + return null; + } + + public static boolean hasObjectMapper(String key) { + return handlers.containsKey(key); + } + + public static ObjectMapper getObjectMapper(String key) { + return handlers.get(key); + } + + public static List> getConflicts(String key) { + return handlerConflicts.get(key); + } + + public static ObjectMapper getObjectMapper(Class containerClass, String key) { + if (!GroovyPropertyContainer.class.isAssignableFrom(containerClass)) return null; + var map = modHandlers.get(containerClass); + return map != null ? map.get(key) : null; + } + + public static Collection> getObjectMappers() { + return handlers.values(); + } + + public static Class getReturnTypeOf(String name) { + ObjectMapper goh = handlers.get(name); + return goh == null ? null : goh.getReturnType(); + } + + public static void provideCompletion(String name, int index, Completions items) { + Completer completer = handlers.get(name).getCompleter(); + if (completer == null) return; + completer.complete(index, items); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapperMetaMethod.java b/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapperMetaMethod.java new file mode 100644 index 000000000..08e155e7a --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapperMetaMethod.java @@ -0,0 +1,52 @@ +package com.cleanroommc.groovyscript.mapper; + +import com.cleanroommc.groovyscript.sandbox.expand.IDocumented; +import groovy.lang.MetaMethod; +import org.codehaus.groovy.reflection.CachedClass; +import org.codehaus.groovy.reflection.ReflectionCache; + +import java.lang.reflect.Modifier; + +public class ObjectMapperMetaMethod extends MetaMethod implements IDocumented { + + private final ObjectMapper closure; + private final Class owner; + + ObjectMapperMetaMethod(ObjectMapper closure, Class[] nativeParamTypes, Class owner) { + super(nativeParamTypes); + this.closure = closure; + this.nativeParamTypes = nativeParamTypes; + this.owner = owner; + } + + @Override + public int getModifiers() { + return Modifier.PUBLIC; + } + + @Override + public String getName() { + return this.closure.getName(); + } + + @Override + public Class getReturnType() { + return this.closure.getReturnType(); + } + + @Override + public CachedClass getDeclaringClass() { + return ReflectionCache.getCachedClass(this.owner); + } + + @Override + public Object invoke(Object object, Object[] arguments) { + arguments = coerceArgumentsToClasses(arguments); + return this.closure.call(arguments); + } + + @Override + public String getDocumentation() { + return this.closure.getDocumentation(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMappers.java b/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMappers.java new file mode 100644 index 000000000..5d2731b55 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMappers.java @@ -0,0 +1,220 @@ +package com.cleanroommc.groovyscript.mapper; + +import com.cleanroommc.groovyscript.GroovyScript; +import com.cleanroommc.groovyscript.api.Result; +import com.cleanroommc.groovyscript.core.mixin.CreativeTabsAccessor; +import com.google.common.base.Optional; +import com.google.common.collect.Iterators; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.block.properties.IProperty; +import net.minecraft.block.state.IBlockState; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.JsonToNBT; +import net.minecraft.nbt.NBTException; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.common.registry.ForgeRegistries; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; + +import static com.cleanroommc.groovyscript.mapper.ObjectMapperManager.SPLITTER; +import static com.cleanroommc.groovyscript.mapper.ObjectMapperManager.WILDCARD; + +public class ObjectMappers { + + private static final String COMMA = ","; + private static final String EQUALS = "="; + + public static @NotNull Result parseResourceLocation(String mainArg, Object... args) { + String[] parts = mainArg.split(SPLITTER); + if (parts.length > 1) { + if (parts.length > 2) { + return Result.error("Resource location must only contain one ':' to separate mod and path."); + } + if (args.length > 0) { + return Result.error("If ':' is used in the resource location, no other arguments are allowed."); + } + return Result.some(new ResourceLocation(parts[0], parts[1])); + } + + if (args.length > 0) { + if (args.length > 1 || !(args[0] instanceof String)) { + return Result.error("Arguments not valid for object mapper. Use 'resource(String)' or 'resource(String mod, String path)'"); + } + return Result.some(new ResourceLocation(mainArg, (String) args[0])); + } + return Result.some(new ResourceLocation(GroovyScript.getRunConfig().getPackId(), mainArg)); + } + + public static @NotNull Result parseItemStack(String mainArg, Object... args) { + if (args.length > 1 || (args.length == 1 && !(args[0] instanceof Integer))) { + return Result.error("Arguments not valid for bracket handler. Use 'item(String)' or 'item(String, int meta)'"); + } + String[] parts = mainArg.split(SPLITTER); + if (parts.length < 2) { + return Result.error("must contain a ':' to separate mod and path"); + } + Item item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(parts[0], parts[1])); + if (item == null) { + return Result.error(); + } + int meta = 0; + if (parts.length > 2) { + if (WILDCARD.equals(parts[2])) { + meta = Short.MAX_VALUE; + } else { + try { + meta = Integer.parseInt(parts[2]); + } catch (NumberFormatException ignored) { + } + } + } + if (args.length == 1) { + if (meta != 0) { + return Result.error("Defined meta value twice for item mapper"); + } + meta = (int) args[0]; + } + return Result.some(new ItemStack(item, 1, meta)); + } + + public static Result parseFluidStack(String s, Object... args) { + if (args.length > 0) return Result.error("No extra arguments are allowed."); + Fluid fluid = FluidRegistry.getFluid(s); + if (fluid == null) return Result.error(); + return Result.some(new FluidStack(fluid, 1)); + } + + public static @NotNull Result parseBlockState(String mainArg, Object... args) { + Result blockStateResult = parseBlockState(mainArg); + if (blockStateResult.hasError()) return blockStateResult; + IBlockState blockState = blockStateResult.getValue(); + if (args.length > 0) { + if (args.length == 1 && args[0] instanceof Integer) { + try { + return Result.some(blockState.getBlock().getStateFromMeta((Integer) args[0])); + } catch (Exception e) { + return Result.error("could not get block state from meta"); + } + } + for (Object arg : args) { + if (!(arg instanceof String)) { + return Result.error("All arguments must be strings!"); + } + } + String[] stringArgs = Arrays.stream(args).map(Object::toString).toArray(String[]::new); + return parseBlockStates(blockState, Iterators.forArray(stringArgs)); + } + return blockStateResult; + } + + public static Result parseBlockState(String arg) { + String[] parts = arg.split(SPLITTER); + if (parts.length < 2) { + return Result.error("Can't find block for '{}'", arg); + } + Block block = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(parts[0], parts[1])); + if (block == null) { + return Result.error("Can't find block for '{}'", arg); + } + IBlockState blockState = block.getDefaultState(); + if (parts.length > 2) { + String[] states = parts[2].split(COMMA); + if (states.length == 1) { + try { + int meta = Integer.parseInt(states[0]); + return Result.some(blockState.getBlock().getStateFromMeta(meta)); + } catch (NumberFormatException ignored) { + } catch (Exception e) { + return Result.error("could not get block state from meta"); + } + } + return parseBlockStates(blockState, Iterators.forArray(states)); + } + return Result.some(blockState); + } + + @SuppressWarnings("all") + private static Result parseBlockStates(IBlockState defaultState, Iterator iterable) { + for (Iterator it = iterable; it.hasNext(); ) { + String state = it.next(); + String[] prop = state.split(EQUALS, 2); + IProperty property = defaultState.getBlock().getBlockState().getProperty(prop[0]); + if (property == null) { + return Result.error("Invalid property name '{}' for block '{}'", prop[0], defaultState.getBlock().getRegistryName()); + } + Optional value = property.parseValue(prop[1]); + if (value.isPresent()) { + defaultState = defaultState.withProperty(property, value.get()); + } else { + return Result.error("Invalid property value '{}' for block '{}:{}'", prop[1], defaultState.getBlock().getRegistryName()); + } + } + return Result.some(defaultState); + } + + + public static Result parseCreativeTab(String mainArg, Object... args) { + for (CreativeTabs tab : CreativeTabs.CREATIVE_TAB_ARRAY) { + if (tab != null && mainArg.equals(((CreativeTabsAccessor) tab).getTabLabel2())) { + return Result.some(tab); + } + } + return Result.error(); + } + + public static Result parseTextFormatting(String mainArg, Object... args) { + TextFormatting textformat = TextFormatting.getValueByName(mainArg); + if (textformat == null) { + try { + textformat = TextFormatting.fromColorIndex(Integer.parseInt(mainArg)); + } catch (NumberFormatException e) { + return Result.error("argument is not a number and not a valid text formatting name"); + } + } + return textformat == null ? Result.error() : Result.some(textformat); + } + + private static Map materials; + + public static Result parseBlockMaterial(String mainArg, Object... args) { + if (materials == null) { + materials = new Object2ObjectOpenHashMap<>(); + for (Field field : Material.class.getFields()) { + if ((field.getModifiers() & Modifier.STATIC) != 0 && field.getType() == Material.class) { + try { + Material material = (Material) field.get(null); + materials.put(field.getName(), material); + materials.put(field.getName().toLowerCase(Locale.ROOT), material); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + } + Material material = materials.get(mainArg); + return material == null ? Result.error() : Result.some(material); + } + + public static @NotNull Result parseNBT(String mainArg, Object... args) { + try { + return Result.some(JsonToNBT.getTagFromJson(mainArg)); + } catch (NBTException e) { + return Result.error("unable to parse provided nbt string"); + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/registry/ReloadableRegistryManager.java b/src/main/java/com/cleanroommc/groovyscript/registry/ReloadableRegistryManager.java index 92aca9d1a..9175b1e1a 100644 --- a/src/main/java/com/cleanroommc/groovyscript/registry/ReloadableRegistryManager.java +++ b/src/main/java/com/cleanroommc/groovyscript/registry/ReloadableRegistryManager.java @@ -6,7 +6,7 @@ import com.cleanroommc.groovyscript.api.IReloadableForgeRegistry; import com.cleanroommc.groovyscript.api.IScriptReloadable; import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; -import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.compat.mods.jei.JeiPlugin; import com.cleanroommc.groovyscript.compat.vanilla.VanillaModule; @@ -81,7 +81,7 @@ public static void onReload() { ModSupport.getAllContainers().stream() .filter(GroovyContainer::isLoaded) .map(GroovyContainer::get) - .map(ModPropertyContainer::getRegistries) + .map(GroovyPropertyContainer::getRegistries) .flatMap(Collection::stream) .distinct() .filter(INamed::isEnabled) @@ -95,7 +95,7 @@ public static void afterScriptRun() { ModSupport.getAllContainers().stream() .filter(GroovyContainer::isLoaded) .map(GroovyContainer::get) - .map(ModPropertyContainer::getRegistries) + .map(GroovyPropertyContainer::getRegistries) .flatMap(Collection::stream) .distinct() .filter(INamed::isEnabled) diff --git a/src/main/java/com/cleanroommc/groovyscript/sandbox/expand/ClosureMetaMethod.java b/src/main/java/com/cleanroommc/groovyscript/sandbox/expand/ClosureMetaMethod.java new file mode 100644 index 000000000..3dfced0bc --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/sandbox/expand/ClosureMetaMethod.java @@ -0,0 +1,51 @@ +package com.cleanroommc.groovyscript.sandbox.expand; + +import groovy.lang.Closure; +import groovy.lang.MetaMethod; +import org.codehaus.groovy.reflection.CachedClass; +import org.codehaus.groovy.reflection.ReflectionCache; +import org.codehaus.groovy.runtime.InvokerHelper; + +import java.lang.reflect.Modifier; + +public class ClosureMetaMethod extends MetaMethod { + + private final Closure closure; + private final String name; + private final Class declaringClass; + + public ClosureMetaMethod(Closure closure, String name, Class declaringClass) { + super(closure.getParameterTypes()); + this.closure = closure; + this.name = name; + this.declaringClass = declaringClass; + } + + @Override + public int getModifiers() { + return Modifier.PUBLIC; + } + + @Override + public String getName() { + return name; + } + + @Override + public Class getReturnType() { + return Object.class; + } + + @Override + public CachedClass getDeclaringClass() { + return ReflectionCache.getCachedClass(declaringClass); + } + + @Override + public Object invoke(Object object, Object[] arguments) { + Closure cloned = (Closure) closure.clone(); + cloned.setDelegate(object); + arguments = coerceArgumentsToClasses(arguments); + return InvokerHelper.invokeMethod(cloned, "call", arguments); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/sandbox/expand/ExpansionHelper.java b/src/main/java/com/cleanroommc/groovyscript/sandbox/expand/ExpansionHelper.java index bfec73cae..73375ea53 100644 --- a/src/main/java/com/cleanroommc/groovyscript/sandbox/expand/ExpansionHelper.java +++ b/src/main/java/com/cleanroommc/groovyscript/sandbox/expand/ExpansionHelper.java @@ -1,18 +1,25 @@ package com.cleanroommc.groovyscript.sandbox.expand; import com.cleanroommc.groovyscript.api.GroovyBlacklist; +import com.cleanroommc.groovyscript.api.Hidden; import com.cleanroommc.groovyscript.sandbox.ClosureHelper; import groovy.lang.*; import groovy.transform.Internal; +import org.apache.groovy.util.BeanUtils; import org.codehaus.groovy.reflection.*; import org.codehaus.groovy.runtime.HandleMetaClass; import org.codehaus.groovy.runtime.metaclass.*; +import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collection; +import java.util.Objects; +import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; public class ExpansionHelper { @@ -21,13 +28,13 @@ public static ExpandoMetaClass getExpandoClass(Class clazz) { } public static ExpandoMetaClass getExpandoClass(MetaClass clazz) { - if (clazz instanceof HandleMetaClass) { - clazz = (MetaClass) ((HandleMetaClass) clazz).replaceDelegate(); + if (clazz instanceof HandleMetaClass handleMetaClass) { + clazz = (MetaClass) handleMetaClass.replaceDelegate(); } if (!(clazz instanceof ExpandoMetaClass)) { - if (clazz instanceof DelegatingMetaClass && ((DelegatingMetaClass) clazz).getAdaptee() instanceof ExpandoMetaClass) { - clazz = ((DelegatingMetaClass) clazz).getAdaptee(); + if (clazz instanceof DelegatingMetaClass delegatingMetaClass && delegatingMetaClass.getAdaptee() instanceof ExpandoMetaClass emc) { + clazz = emc; } else { ExpandoMetaClass emc = new ExpandoMetaClass(clazz.getTheClass(), true, true); emc.initialize(); @@ -102,6 +109,11 @@ private static void mixinClass(ExpandoMetaClass emc, MixinInMetaClass mixin, Cla } } + public static void mixinClosure(Class self, String name, Closure closure) { + ExpandoMetaClass emc = getExpandoClass(self); + emc.registerInstanceMethod(name, closure); + } + public static void mixinMethod(Class self, Method method) { ExpandoMetaClass emc = getExpandoClass(self); MixinInMetaClass mixin = Modifier.isStatic(method.getModifiers()) ? null : getMixinMetaClass(method.getDeclaringClass(), emc); @@ -153,6 +165,39 @@ public CachedClass getDeclaringClass() { self.registerInstanceMethod(metaMethod); } + public static void mixinConstProperty(Class self, String name, T obj, boolean hidden) { + Objects.requireNonNull(obj, "Can't add null property to class!"); + Class type = (Class) obj.getClass(); + mixinProperty(self, name, type, s -> obj, null, hidden); + } + + public static void mixinProperty(Class self, String name, Class type, + @Nullable Supplier getter, @Nullable Consumer setter, boolean hidden) { + mixinProperty(self, name, type, getter != null ? s -> getter.get() : null, setter != null ? (s, t) -> setter.accept(t) : null, hidden); + } + + public static void mixinProperty(Class self, String name, Class type, + @Nullable Function getter, @Nullable BiConsumer setter, boolean hidden) { + if (getter == null && setter == null) return; + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException("Name for property must not be empty!"); + } + String upperName = name; + if (!Character.isDigit(name.charAt(0))) upperName = BeanUtils.capitalize(name); + if (getter == null) { + getter = so -> {throw new GroovyRuntimeException("Property '" + name + "' in " + self.getName() + " is writable, but not readable!");}; + } + if (setter == null) { + setter = (so, t) -> {throw new GroovyRuntimeException("Property '" + name + "' in " + self.getName() + " is readable, but not writable!");}; + } + + MetaMethod g = new Getter<>("get" + upperName, type, self, getter); + MetaMethod s = new Setter<>("set" + upperName, type, self, setter); + + ExpandoMetaClass emc = getExpandoClass(self); + emc.registerBeanProperty(name, new Property(name, type, g, s, hidden)); + } + private static boolean isValid(CachedMethod method) { final int mod = method.getModifiers(); return Modifier.isPublic(mod) && !Modifier.isAbstract(mod) && !method.isSynthetic() && @@ -201,4 +246,19 @@ public CachedClass getOwnerClass() { return owner; } } + + private static class Property extends MetaBeanProperty implements Hidden { + + private final boolean hidden; + + public Property(String name, Class type, MetaMethod getter, MetaMethod setter, boolean hidden) { + super(name, type, getter, setter); + this.hidden = hidden; + } + + @Override + public boolean isHidden() { + return hidden; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/sandbox/expand/Getter.java b/src/main/java/com/cleanroommc/groovyscript/sandbox/expand/Getter.java new file mode 100644 index 000000000..a68d31b6f --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/sandbox/expand/Getter.java @@ -0,0 +1,60 @@ +package com.cleanroommc.groovyscript.sandbox.expand; + +import com.cleanroommc.groovyscript.api.Hidden; +import groovy.lang.MetaMethod; +import org.codehaus.groovy.reflection.CachedClass; +import org.codehaus.groovy.reflection.ReflectionCache; + +import java.lang.reflect.Modifier; +import java.util.function.Function; + +public class Getter extends MetaMethod implements Hidden { + + public static final Class[] PARAMS = {}; + public static final CachedClass[] PARAM_CACHED = {}; + + private final String name; + private final Class returnType; + private final Class owner; + private final Function getter; + + public Getter(String name, Class returnType, Class owner, Function getter) { + super(PARAMS); + this.name = name; + this.returnType = returnType; + this.owner = owner; + this.getter = getter; + setParametersTypes(PARAM_CACHED); + } + + @Override + public int getModifiers() { + return Modifier.PUBLIC; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public Class getReturnType() { + return this.returnType; + } + + @Override + public CachedClass getDeclaringClass() { + return ReflectionCache.getCachedClass(this.owner); + } + + @Override + public Object invoke(Object object, Object[] arguments) { + S self = object == null ? null : (S) object; + return this.getter.apply(self); + } + + @Override + public boolean isHidden() { + return true; + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/sandbox/expand/IDocumented.java b/src/main/java/com/cleanroommc/groovyscript/sandbox/expand/IDocumented.java new file mode 100644 index 000000000..184a5e887 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/sandbox/expand/IDocumented.java @@ -0,0 +1,14 @@ +package com.cleanroommc.groovyscript.sandbox.expand; + +import org.apache.commons.lang3.StringUtils; + +public interface IDocumented { + + String getDocumentation(); + + static String toJavaDoc(String s) { + if (s == null || s.isEmpty()) return StringUtils.EMPTY; + if (s.startsWith("/**") && s.endsWith("*/")) return s; + return "/**\n *" + s.replaceAll("\n", "\n * ") + "\n*/"; + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/sandbox/expand/Setter.java b/src/main/java/com/cleanroommc/groovyscript/sandbox/expand/Setter.java new file mode 100644 index 000000000..53918204f --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/sandbox/expand/Setter.java @@ -0,0 +1,57 @@ +package com.cleanroommc.groovyscript.sandbox.expand; + +import com.cleanroommc.groovyscript.api.Hidden; +import groovy.lang.MetaMethod; +import org.codehaus.groovy.reflection.CachedClass; +import org.codehaus.groovy.reflection.ReflectionCache; + +import java.lang.reflect.Modifier; +import java.util.function.BiConsumer; + +public class Setter extends MetaMethod implements Hidden { + + private final String name; + private final Class owner; + private final BiConsumer setter; + + public Setter(String name, Class paramType, Class owner, BiConsumer setter) { + super(new Class[]{paramType}); + this.name = name; + this.owner = owner; + this.setter = setter; + setParametersTypes(new CachedClass[]{ReflectionCache.getCachedClass(paramType)}); + } + + @Override + public int getModifiers() { + return Modifier.PUBLIC; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public Class getReturnType() { + return void.class; + } + + @Override + public CachedClass getDeclaringClass() { + return ReflectionCache.getCachedClass(this.owner); + } + + @Override + public Object invoke(Object object, Object[] arguments) { + S self = object == null ? null : (S) object; + T arg = (T) arguments[0]; + this.setter.accept(self, arg); + return null; + } + + @Override + public boolean isHidden() { + return true; + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/sandbox/transformer/GroovyScriptTransformer.java b/src/main/java/com/cleanroommc/groovyscript/sandbox/transformer/GroovyScriptTransformer.java index 2164f6b34..cafbd923a 100644 --- a/src/main/java/com/cleanroommc/groovyscript/sandbox/transformer/GroovyScriptTransformer.java +++ b/src/main/java/com/cleanroommc/groovyscript/sandbox/transformer/GroovyScriptTransformer.java @@ -1,7 +1,9 @@ package com.cleanroommc.groovyscript.sandbox.transformer; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandlerManager; +import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.helper.GroovyFile; +import com.cleanroommc.groovyscript.mapper.ObjectMapper; +import com.cleanroommc.groovyscript.mapper.ObjectMapperManager; import org.codehaus.groovy.ast.ClassCodeExpressionTransformer; import org.codehaus.groovy.ast.ClassHelper; import org.codehaus.groovy.ast.ClassNode; @@ -14,10 +16,10 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; public class GroovyScriptTransformer extends ClassCodeExpressionTransformer { - private static final ClassNode bracketHandlerClass = ClassHelper.makeCached(GameObjectHandlerManager.class); private static final ClassNode groovyFile = ClassHelper.makeCached(GroovyFile.class); private final SourceUnit source; private final ClassNode classNode; @@ -63,11 +65,11 @@ public Expression transform(Expression expr) { } private Expression transformInternal(Expression expr) { - if (expr instanceof ClosureExpression) { - return transformClosure((ClosureExpression) expr); + if (expr instanceof ClosureExpression ce) { + return transformClosure(ce); } - if (expr instanceof MethodCallExpression) { - return checkValid((MethodCallExpression) expr); + if (expr instanceof MethodCallExpression mce) { + return transformMethodCall(mce); } if (expr instanceof ConstructorCallExpression cce) { if (cce.getType().getName().equals(File.class.getName())) { @@ -97,19 +99,18 @@ private Expression transformClosure(ClosureExpression closure) { return closure; } - private Expression checkValid(MethodCallExpression expression) { - int argCount = 0; - if (expression.getArguments() instanceof TupleExpression) { - argCount = ((TupleExpression) expression.getArguments()).getExpressions().size(); - } - if (expression.isImplicitThis() && argCount > 0) { - String name = expression.getMethodAsString(); - if (GameObjectHandlerManager.hasGameObjectHandler(name)) { - List args = getArguments(expression.getArguments()); - args.add(0, new ConstantExpression(name)); - return makeCheckedCall(bracketHandlerClass, "getGameObject", args); + private Expression transformMethodCall(MethodCallExpression mce) { + if (mce.isImplicitThis()) { + List> conflicts = ObjectMapperManager.getConflicts(mce.getMethodAsString()); + if (conflicts != null) { + List suggestions = conflicts.stream() + .map(goh -> goh.getMod() == null ? goh.getName() : "mods." + goh.getMod().getModId() + "." + goh.getName()) + .collect(Collectors.toList()); + String msg = GroovyLog.format("Can't infer ObjectMapper from name {}, since one is added by {} mods. " + + "Please choose one of the following: {}", mce.getMethodAsString(), conflicts.size(), suggestions); + source.addError(new SyntaxException(msg, mce)); } } - return expression; + return mce; } } diff --git a/src/main/java/net/prominic/groovyls/compiler/documentation/GroovydocProvider.java b/src/main/java/net/prominic/groovyls/compiler/documentation/GroovydocProvider.java index 208955346..fd3a25bc4 100644 --- a/src/main/java/net/prominic/groovyls/compiler/documentation/GroovydocProvider.java +++ b/src/main/java/net/prominic/groovyls/compiler/documentation/GroovydocProvider.java @@ -6,6 +6,10 @@ public class GroovydocProvider implements IDocumentationProvider { + public static final String PARAM_TAG = "@param"; + public static final String RETURN_TAG = "@return"; + public static final String THROWS_TAG = "@throws"; + @Override public @Nullable String getDocumentation(AnnotatedNode node, ASTContext context) { var groovydoc = node.getGroovydoc(); @@ -29,18 +33,39 @@ public class GroovydocProvider implements IDocumentationProvider { int lengthToRemove = Math.min(line.length(), 3); line = line.substring(lengthToRemove); appendLine(markdownBuilder, line); + boolean paramMode = false; + boolean throwMode = false; for (int i = 1; i < n - 1; i++) { line = lines[i]; int star = line.indexOf("*"); int at = line.indexOf("@"); - if (at == -1) { - if (star > -1) // line starts with a * - { - appendLine(markdownBuilder, line.substring(star + 1)); + if (at >= 0) { + if (at == line.indexOf(PARAM_TAG, at)) { + if (!paramMode) { + paramMode = true; + throwMode = false; + appendLine(markdownBuilder, "Params:"); + } + appendLine(markdownBuilder, " - " + line.substring(at + PARAM_TAG.length()).trim()); + } else if (at == line.indexOf(RETURN_TAG, at)) { + appendLine(markdownBuilder, "Returns " + line.substring(at + RETURN_TAG.length()).trim()); + } else if (at == line.indexOf(THROWS_TAG)) { + if (!throwMode) { + paramMode = false; + throwMode = true; + appendLine(markdownBuilder, "Throws:"); + } + appendLine(markdownBuilder, " - " + line.substring(at + THROWS_TAG.length()).trim()); } + } else if (star >= 0) { + // line starts with a * + appendLine(markdownBuilder, line.substring(star + 1)); } + } - return markdownBuilder.toString().trim(); + return markdownBuilder.toString(). + + trim(); } private static void appendLine(StringBuilder markdownBuilder, String line) { @@ -53,20 +78,20 @@ private static void appendLine(StringBuilder markdownBuilder, String line) { } private static String reformatLine(String line) { - // remove all attributes (including namespaced) - line = line.replaceAll("<(\\w+)(?:\\s+\\w+(?::\\w+)?=(\"|\')[^\"\']*\\2)*\\s*(\\/{0,1})>", "<$1$3>"); + // remove all attributes (including namespace) + line = line.replaceAll("<(\\w+)(?:\\s+\\w+(?::\\w+)?=([\"'])[^\"']*\\2)*\\s*(/?)>", "<$1$3>"); line = line.replaceAll("
", "\n\n```\n");
         line = line.replaceAll("
", "\n```\n"); line = line.replaceAll("", "_"); line = line.replaceAll("", "**"); line = line.replaceAll("", "`"); - line = line.replaceAll("
", "\n\n---\n\n"); + line = line.replaceAll("
", "\n\n---\n\n"); line = line.replaceAll("<(p|ul|ol|dl|li|dt|table|tr|div|blockquote)>", "\n\n"); // to add a line break to markdown, there needs to be at least two // spaces at the end of the line line = line.replaceAll("\\s*", " \n"); - line = line.replaceAll("<\\/{0,1}\\w+\\/{0,1}>", ""); + line = line.replaceAll("", ""); return line; } } diff --git a/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java b/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java index a9fd1e3cd..0ac9b7421 100644 --- a/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java +++ b/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java @@ -19,19 +19,26 @@ //////////////////////////////////////////////////////////////////////////////// package net.prominic.groovyls.compiler.util; -import com.cleanroommc.groovyscript.api.IDynamicGroovyProperty; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandlerManager; +import com.cleanroommc.groovyscript.api.Hidden; +import com.cleanroommc.groovyscript.helper.ArrayUtils; +import com.cleanroommc.groovyscript.mapper.ObjectMapper; +import com.cleanroommc.groovyscript.mapper.ObjectMapperManager; +import com.cleanroommc.groovyscript.sandbox.expand.IDocumented; +import groovy.lang.*; +import groovy.lang.groovydoc.Groovydoc; +import groovy.lang.groovydoc.GroovydocHolder; import net.prominic.groovyls.compiler.ast.ASTContext; -import net.prominic.groovyls.util.ClassGraphUtils; import net.prominic.groovyls.util.GroovyLanguageServerUtils; import org.codehaus.groovy.ast.*; import org.codehaus.groovy.ast.expr.*; import org.codehaus.groovy.ast.stmt.ExpressionStatement; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.NotNull; import org.objectweb.asm.Opcodes; +import java.lang.reflect.Modifier; +import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -39,6 +46,9 @@ public class GroovyASTUtils { + public static final int EXPANSION_MARKER = 0x01000000; + public static final int HIDDEN_MARKER = 0x02000000; + public static ASTNode getEnclosingNodeOfType(ASTNode offsetNode, Class nodeType, ASTContext context) { ASTNode current = offsetNode; @@ -110,46 +120,11 @@ public static ASTNode getDefinition(ASTNode node, boolean strict, ASTContext con } else if (node instanceof MethodCallExpression methodCallExpression) { return getDefinition(methodCallExpression.getObjectExpression(), strict, context); } else if (node instanceof StaticMethodCallExpression staticMethodCallExpression) { - var gameObjectName = getAccessedGameObjectName(staticMethodCallExpression); - - if (gameObjectName != null) { - var gameObjectReturnType = GameObjectHandlerManager.getReturnTypeOf(gameObjectName); - - if (gameObjectReturnType == null) { - return null; - } - - var methodNode = new MethodNode(gameObjectName, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, - ClassHelper.makeCached(gameObjectReturnType), - new Parameter[]{ - new Parameter(ClassHelper.makeCached(String.class), "mainArg"), - new Parameter(ClassHelper.makeCached(Object[].class), "args") - }, - null, - null - ); - - methodNode.setDeclaringClass(ClassHelper.makeCached(GameObjectHandlerManager.class)); - - return methodNode; - } - return GroovyASTUtils.getMethodFromCallExpression(staticMethodCallExpression, context); } return null; } - private static @Nullable String getAccessedGameObjectName(StaticMethodCallExpression staticMethodCallExpression) { - return staticMethodCallExpression.getOwnerType().equals(ClassHelper.makeCached(GameObjectHandlerManager.class)) && - staticMethodCallExpression.getMethod().equals("getGameObject") && - staticMethodCallExpression.getArguments() instanceof ArgumentListExpression argumentListExpression && - !argumentListExpression.getExpressions().isEmpty() && - argumentListExpression.getExpression(0) instanceof ConstantExpression objectNameConstantExpression && - GameObjectHandlerManager.hasGameObjectHandler(objectNameConstantExpression.getText()) ? - objectNameConstantExpression.getText() : - null; - } - public static ASTNode getTypeDefinition(ASTNode node, ASTContext context) { ASTNode definitionNode = getDefinition(node, false, context); if (definitionNode == null) { @@ -190,27 +165,16 @@ private static ClassNode tryToResolveOriginalClassNode(ClassNode node, boolean s public static PropertyNode getPropertyFromExpression(PropertyExpression node, ASTContext context) { ClassNode classNode = getTypeOfNode(node.getObjectExpression(), context); - if (classNode != null && classNode.implementsInterface(new ClassNode(IDynamicGroovyProperty.class))) { - var value = resolveDynamicValue(node, context); + if (classNode == null) return null; + fillClassNode(classNode); + var prop = classNode.getProperty(node.getProperty().getText()); + var field = classNode.getField(node.getProperty().getText()); - if (value != null) { - return new PropertyNode(node.getProperty().getText(), Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, - new ClassNode(value.getClass()), - classNode, - null, null, null); - } + if (prop == null && field != null) { + prop = new PropertyNode(field, Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, null, null); } - if (classNode != null) { - var prop = classNode.getProperty(node.getProperty().getText()); - var field = classNode.getField(node.getProperty().getText()); - if (prop == null && field != null) { - prop = new PropertyNode(field, Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, null, null); - } - - return prop; - } - return null; + return prop; } public static Object resolveDynamicValue(ASTNode node, ASTContext context) { @@ -218,11 +182,8 @@ public static Object resolveDynamicValue(ASTNode node, ASTContext context) { var value = resolveDynamicValue(propertyExpression.getObjectExpression(), context); Object result = null; - if (value instanceof IDynamicGroovyProperty dynamicValue) { - result = dynamicValue.getProperty(propertyExpression.getProperty().getText()); - } - if (value != null && result == null) { + if (value != null) { try { result = value.getClass().getDeclaredField(propertyExpression.getProperty().getText()).get(value); } catch (IllegalAccessException e) { @@ -247,56 +208,25 @@ public static FieldNode getFieldFromExpression(PropertyExpression node, ASTConte return null; } - public static List getFieldsForLeftSideOfPropertyExpression(Expression node, ASTContext context) { - ClassNode classNode = getTypeOfNode(node, context); - - if (classNode != null && node instanceof VariableExpression) { - var binding = context.getLanguageServerContext().getSandbox().getBindings().get(((VariableExpression) node).getName()); - var classInfo = ClassGraphUtils.resolveAllowedClassInfo(classNode, context); - - if (classInfo != null && binding != null && (classInfo.loadClass().equals(IDynamicGroovyProperty.class) || classInfo.implementsInterface(IDynamicGroovyProperty.class))) { - final ClassNode finalClassNode = classNode; - return ((IDynamicGroovyProperty) binding).getProperties().entrySet().stream() - .filter(entry -> entry.getValue() != null) - .map(entry -> new FieldNode(entry.getKey(), Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, - new ClassNode(entry.getValue().getClass()), - finalClassNode, - new ConstantExpression(entry.getValue()))) - .collect(Collectors.toList()); - } - } - - if (classNode != null) { - boolean statics = node instanceof ClassExpression; - return classNode.getFields().stream().filter(fieldNode -> { - return statics ? fieldNode.isStatic() : !fieldNode.isStatic(); - }).collect(Collectors.toList()); - } - return Collections.emptyList(); + public static List getFieldsForLeftSideOfPropertyExpression(ClassNode classNode, Expression node, ASTContext context) { + boolean statics = node instanceof ClassExpression; + return classNode.getFields().stream() + .filter(fieldNode -> statics == fieldNode.isStatic() && (fieldNode.getModifiers() & HIDDEN_MARKER) == 0) + .collect(Collectors.toList()); } - public static List getPropertiesForLeftSideOfPropertyExpression(Expression node, - ASTContext context) { - ClassNode classNode = getTypeOfNode(node, context); - if (classNode != null) { - boolean statics = node instanceof ClassExpression; - return classNode.getProperties().stream().filter(propNode -> { - return statics ? propNode.isStatic() : !propNode.isStatic(); - }).collect(Collectors.toList()); - } - return Collections.emptyList(); + public static List getPropertiesForLeftSideOfPropertyExpression(ClassNode classNode, Expression node, ASTContext context) { + boolean statics = node instanceof ClassExpression; + return classNode.getProperties().stream() + .filter(propNode -> statics == propNode.isStatic() && (propNode.getModifiers() & HIDDEN_MARKER) == 0) + .collect(Collectors.toList()); } - public static List getMethodsForLeftSideOfPropertyExpression(Expression node, - ASTContext context) { - ClassNode classNode = getTypeOfNode(node, context); - if (classNode != null) { - boolean statics = node instanceof ClassExpression; - return classNode.getMethods().stream().filter(methodNode -> { - return statics ? methodNode.isStatic() : !methodNode.isStatic(); - }).collect(Collectors.toList()); - } - return Collections.emptyList(); + public static List getMethodsForLeftSideOfPropertyExpression(ClassNode classNode, Expression node, ASTContext context) { + boolean statics = node instanceof ClassExpression; + return classNode.getMethods().stream() + .filter(methodNode -> statics == methodNode.isStatic() && (methodNode.getModifiers() & HIDDEN_MARKER) == 0) + .collect(Collectors.toList()); } public static ClassNode getTypeOfNode(ASTNode node, ASTContext context) { @@ -315,17 +245,16 @@ public static ClassNode getTypeOfNode(ASTNode node, ASTContext context) { return expression.getType(); } else if (node instanceof MethodCallExpression) { MethodCallExpression expression = (MethodCallExpression) node; + ObjectMapper goh = getGohOfNode(expression, context); + if (goh != null) { + return ClassHelper.makeCached(goh.getReturnType()); + } MethodNode methodNode = GroovyASTUtils.getMethodFromCallExpression(expression, context); if (methodNode != null) { return methodNode.getReturnType(); } return expression.getType(); } else if (node instanceof StaticMethodCallExpression expr) { - var gameObjectName = getAccessedGameObjectName(expr); - if (gameObjectName != null) { - return ClassHelper.makeCached(GameObjectHandlerManager.getReturnTypeOf(gameObjectName)); - } - MethodNode methodNode = GroovyASTUtils.getMethodFromCallExpression(expr, context); if (methodNode != null) { return methodNode.getReturnType(); @@ -375,22 +304,33 @@ public static ClassNode getTypeOfNode(ASTNode node, ASTContext context) { } public static List getMethodOverloadsFromCallExpression(MethodCall node, ASTContext context) { - if (node instanceof MethodCallExpression) { - MethodCallExpression methodCallExpr = (MethodCallExpression) node; + if (node instanceof MethodCallExpression methodCallExpr) { + List mn = new ArrayList<>(); + if (methodCallExpr.isImplicitThis()) { + Object o = context.getLanguageServerContext().getSandbox().getBindings().get(node.getMethodAsString()); + if (o instanceof ObjectMapper goh) { + mn.addAll(goh.getMethodNodes()); + } else if (o instanceof Closure closure) { + mn.add(methodNodeOfClosure(node.getMethodAsString(), closure)); + } + } ClassNode leftType = getTypeOfNode(methodCallExpr.getObjectExpression(), context); if (leftType != null) { - return leftType.getMethods(methodCallExpr.getMethod().getText()); + fillClassNode(leftType); + mn.addAll(leftType.getMethods(methodCallExpr.getMethod().getText())); } - } else if (node instanceof ConstructorCallExpression) { - ConstructorCallExpression constructorCallExpr = (ConstructorCallExpression) node; + return mn; + } else if (node instanceof ConstructorCallExpression constructorCallExpr) { ClassNode constructorType = constructorCallExpr.getType(); if (constructorType != null) { + fillClassNode(constructorType); return constructorType.getDeclaredConstructors().stream().map(constructor -> (MethodNode) constructor) .collect(Collectors.toList()); } } else if (node instanceof StaticMethodCallExpression staticMethodCallExpression) { var ownerType = staticMethodCallExpression.getOwnerType(); if (ownerType != null) { + fillClassNode(ownerType); return ownerType.getMethods(staticMethodCallExpression.getMethod()); } } @@ -484,4 +424,84 @@ public static Range findAddImportRange(ASTNode offsetNode, ASTContext context) { Position position = new Position(nodeRange.getEnd().getLine() + 1, 0); return new Range(position, position); } + + public static MethodNode methodNodeOfClosure(String name, Closure closure) { + Class declarer = closure.getThisObject() == null ? + (closure.getOwner() == null ? Object.class : closure.getOwner().getClass()) : + closure.getThisObject().getClass(); + MethodNode method = new MethodNode(name, Modifier.PUBLIC, ClassHelper.OBJECT_TYPE, + ArrayUtils.map(closure.getParameterTypes(), + c -> new Parameter(ClassHelper.makeCached(c), ""), + new Parameter[closure.getParameterTypes().length]), + null, null); + method.setDeclaringClass(ClassHelper.makeCached(declarer)); + return method; + } + + public static ObjectMapper getGohOfNode(MethodCallExpression expr, ASTContext context) { + if (expr.isImplicitThis()) { + return ObjectMapperManager.getObjectMapper(expr.getMethodAsString()); + } + ClassNode type = getTypeOfNode(expr.getObjectExpression(), context); + if (type != null) { + return ObjectMapperManager.getObjectMapper(type.getTypeClass(), expr.getMethodAsString()); + } + return null; + } + + public static void fillClassNode(ClassNode classNode) { + if (!classNode.isResolved()) return; + Class clazz; + try { + clazz = classNode.getTypeClass(); + } catch (Exception ignored) { + return; + } + MetaClass mc = GroovySystem.getMetaClassRegistry().getMetaClass(clazz); + if (mc instanceof ExpandoMetaClass emc) { + for (MetaMethod mm : emc.getExpandoMethods()) { + if (mm.isPrivate()) continue; + int m = mm.getModifiers(); + if (mm instanceof Hidden hidden && hidden.isHidden()) m |= HIDDEN_MARKER; + Parameter[] params = ArrayUtils.map(mm.getNativeParameterTypes(), + c -> new Parameter(ClassHelper.makeCached(c), ""), + new Parameter[mm.getNativeParameterTypes().length]); + MethodNode node = new MethodNode(mm.getName(), m, ClassHelper.makeCached(mm.getReturnType()), params, null, null); + node.setDeclaringClass(classNode); + if (mm instanceof IDocumented documented && documented.getDocumentation() != null) { + node.setNodeMetaData(GroovydocHolder.DOC_COMMENT, new Groovydoc(documented.getDocumentation(), node)); + } + classNode.addMethod(node); + } + for (MetaProperty mp : emc.getExpandoProperties()) { + int m = mp.getModifiers(); + if (mp instanceof Hidden hidden && hidden.isHidden()) m |= HIDDEN_MARKER; + FieldNode field = new FieldNode(mp.getName(), m, ClassHelper.makeCached(mp.getType()), classNode.redirect(), null); + PropertyNode property = makeProperty(classNode, field, m); + classNode.addProperty(property); + } + } + } + + @NotNull + private static PropertyNode makeProperty(ClassNode classNode, FieldNode field, int m) { + PropertyNode property = new PropertyNode(field, m, null, null); + property.setDeclaringClass(classNode); + // remove any previous set fields and properties with the same name + List properties = classNode.getProperties(); + for (int i = 0; i < properties.size(); i++) { + PropertyNode node = properties.get(i); + if (node.getName().equals(property.getName())) { + properties.remove(i--); + } + } + List fields = classNode.getFields(); + for (int i = 0; i < fields.size(); i++) { + FieldNode node = fields.get(i); + if (node.getName().equals(property.getName())) { + fields.remove(i--); + } + } + return property; + } } \ No newline at end of file diff --git a/src/main/java/net/prominic/groovyls/providers/CompletionProvider.java b/src/main/java/net/prominic/groovyls/providers/CompletionProvider.java index cae6246ea..9c6c0c275 100644 --- a/src/main/java/net/prominic/groovyls/providers/CompletionProvider.java +++ b/src/main/java/net/prominic/groovyls/providers/CompletionProvider.java @@ -19,10 +19,13 @@ //////////////////////////////////////////////////////////////////////////////// package net.prominic.groovyls.providers; -import com.cleanroommc.groovyscript.gameobjects.GameObjectHandlerManager; +import com.cleanroommc.groovyscript.mapper.ObjectMapper; +import com.cleanroommc.groovyscript.mapper.ObjectMapperManager; import com.cleanroommc.groovyscript.server.Completions; +import groovy.lang.Closure; import groovy.lang.DelegatesTo; import io.github.classgraph.*; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.prominic.groovyls.compiler.ast.ASTContext; import net.prominic.groovyls.compiler.util.GroovyASTUtils; import net.prominic.groovyls.compiler.util.GroovyReflectionUtils; @@ -59,10 +62,9 @@ public CompletableFuture, CompletionList>> provideCo Completions items = new Completions(1000); ASTNode offsetNode = astContext.getVisitor().getNodeAtLineAndColumn(uri, position.getLine(), position.getCharacter()); - if (offsetNode != null) { - populateItemsFromNode(position, offsetNode, items); + if (offsetNode == null || populateItemsFromNode(position, offsetNode, items)) { + populateKeywords(items); } - populateKeywords(items); return CompletableFuture.completedFuture(items.getResult(this.isIncomplete)); } @@ -80,7 +82,7 @@ private void populateKeywords(Completions items) { }); } - private void populateItemsFromNode(Position position, ASTNode offsetNode, Completions items) { + private boolean populateItemsFromNode(Position position, ASTNode offsetNode, Completions items) { ASTNode parentNode = astContext.getVisitor().getParent(offsetNode); if (offsetNode instanceof PropertyExpression) { @@ -108,57 +110,40 @@ private void populateItemsFromNode(Position position, ASTNode offsetNode, Comple } else if (offsetNode instanceof StaticMethodCallExpression) { populateItemsFromStaticMethodCallExpression((StaticMethodCallExpression) offsetNode, position, items); } else if (offsetNode instanceof ConstantExpression) { - populateItemsFromConstantExpression((ConstantExpression) offsetNode, parentNode, items); + return populateItemsFromConstantExpression((ConstantExpression) offsetNode, parentNode, items); } + return true; } - private void populateItemsFromConstantExpression(ConstantExpression node, ASTNode parent, Completions items) { - if (node.getType().getName().equals(String.class.getName())) { + private boolean populateItemsFromConstantExpression(ConstantExpression node, ASTNode parent, Completions items) { + if (node.getType().getTypeClass() == String.class) { ASTNode parentParent = astContext.getVisitor().getParent(parent); - if (parentParent instanceof StaticMethodCallExpression expr && - expr.getOwnerType().getName().equals(GameObjectHandlerManager.class.getName()) && - expr.getMethod().equals("getGameObject") && - expr.getArguments() instanceof ArgumentListExpression args && !args.getExpressions().isEmpty() && - args.getExpression(0) instanceof ConstantExpression expr1 && expr1.getValue() instanceof String name && - GameObjectHandlerManager.hasGameObjectHandler(name)) { - int index = -1; - if (args.getExpressions().size() > 1) { - for (int i = 1; i < args.getExpressions().size(); i++) { + if (parentParent instanceof MethodCallExpression expr && expr.getArguments() instanceof ArgumentListExpression args && !args.getExpressions().isEmpty()) { + ObjectMapper goh = GroovyASTUtils.getGohOfNode(expr, astContext); + if (goh != null && goh.getCompleter() != null) { + int index = -1; + for (int i = 0; i < args.getExpressions().size(); i++) { if (args.getExpression(i) == node) { - index = i - 1; + index = i; break; } } + goh.getCompleter().complete(index, items); } - GameObjectHandlerManager.provideCompletion(name, index, items); } + return false; // don't complete keyword in strings } + return true; } private void populateItemsFromStaticMethodCallExpression(StaticMethodCallExpression methodCallExpr, Position position, Completions items) { - Set existingNames = new HashSet<>(); - - if (methodCallExpr.getOwnerType().getTypeClass().equals(GameObjectHandlerManager.class) && methodCallExpr.getMethod().equals("getGameObject")) { - // expression like item() - - var argumentsExpr = methodCallExpr.getArguments(); - if (argumentsExpr instanceof ArgumentListExpression) { - var firstArgumentExpr = ((ArgumentListExpression) argumentsExpr).getExpression(0); - - if (firstArgumentExpr instanceof ConstantExpression) { - var memberNamePrefix = ((ConstantExpression) firstArgumentExpr).getValue().toString(); - - populateItemsFromGameObjects(memberNamePrefix, existingNames, items); - } - } - } - + Set existingNames = new ObjectOpenHashSet<>(); populateItemsFromGlobalScope(methodCallExpr.getMethod(), existingNames, items); } private static void populateItemsFromGameObjects(String memberNamePrefix, Set existingNames, Completions items) { - GameObjectHandlerManager.getGameObjectHandlers().stream() + ObjectMapperManager.getObjectMappers().stream() .filter(handler -> { if (handler.getName().startsWith(memberNamePrefix) && !existingNames.contains(handler.getName())) { existingNames.add(handler.getName()); @@ -373,7 +358,9 @@ private void populateItemsFromMethods(List methods, String memberNam // overloads can cause duplicates if (methodName.startsWith(memberNamePrefix) && !existingNames.contains(methodName)) { existingNames.add(methodName); - return !method.getDeclaringClass().isResolved() || GroovyReflectionUtils.resolveMethodFromMethodNode(method, astContext).isPresent(); + return !method.getDeclaringClass().isResolved() || + (method.getModifiers() & GroovyASTUtils.EXPANSION_MARKER) != 0 || + GroovyReflectionUtils.resolveMethodFromMethodNode(method, astContext).isPresent(); } return false; }).map(method -> { @@ -427,14 +414,18 @@ private static CompletionItemLabelDetails getMethodInfoDetails(MethodInfo method return details; } + private void populateItemsFromExpression(Expression leftSide, String memberNamePrefix, Completions items) { - Set existingNames = new HashSet<>(); + Set existingNames = new ObjectOpenHashSet<>(); - List properties = GroovyASTUtils.getPropertiesForLeftSideOfPropertyExpression(leftSide, astContext); - List fields = GroovyASTUtils.getFieldsForLeftSideOfPropertyExpression(leftSide, astContext); + ClassNode classNode = GroovyASTUtils.getTypeOfNode(leftSide, astContext); + if (classNode == null) return; + GroovyASTUtils.fillClassNode(classNode); + List properties = GroovyASTUtils.getPropertiesForLeftSideOfPropertyExpression(classNode, leftSide, astContext); + List fields = GroovyASTUtils.getFieldsForLeftSideOfPropertyExpression(classNode, leftSide, astContext); populateItemsFromPropertiesAndFields(properties, fields, memberNamePrefix, existingNames, items); - List methods = GroovyASTUtils.getMethodsForLeftSideOfPropertyExpression(leftSide, astContext); + List methods = GroovyASTUtils.getMethodsForLeftSideOfPropertyExpression(classNode, leftSide, astContext); populateItemsFromMethods(methods, memberNamePrefix, existingNames, items); } @@ -445,12 +436,22 @@ private void populateItemsFromGlobalScope(String memberNamePrefix, return; } existingNames.add(variableName); - - var item = CompletionItemFactory.createCompletion(CompletionItemKind.Variable, variableName); - - item.setDetail("(global scope)"); - - items.add(item); + if (value instanceof ObjectMapper goh) { + for (MethodNode method : goh.getMethodNodes()) { + var item = CompletionItemFactory.createCompletion(method, goh.getName(), astContext); + item.setLabelDetails(getMethodNodeDetails(method)); + items.add(item); + } + } else if (value instanceof Closure closure) { + MethodNode method = GroovyASTUtils.methodNodeOfClosure(variableName, closure); + var item = CompletionItemFactory.createCompletion(method, variableName, astContext); + item.setLabelDetails(getMethodNodeDetails(method)); + items.add(item); + } else { + var item = CompletionItemFactory.createCompletion(CompletionItemKind.Variable, variableName); + item.setDetail("(global scope)"); + items.add(item); + } }); List staticMethodItems = astContext.getLanguageServerContext().getSandbox().getStaticImports().stream() @@ -478,7 +479,7 @@ private void populateItemsFromGlobalScope(String memberNamePrefix, private void populateItemsFromVariableScope(VariableScope variableScope, String memberNamePrefix, Set existingNames, Completions items) { - populateItemsFromGameObjects(memberNamePrefix, existingNames, items); + //populateItemsFromGameObjects(memberNamePrefix, existingNames, items); populateItemsFromGlobalScope(memberNamePrefix, existingNames, items); List variableItems = variableScope.getDeclaredVariables().values().stream().filter(variable -> { @@ -551,7 +552,7 @@ private void populateItemsFromScope(ASTNode node, String namePrefix, Completions } } if (current instanceof VariableExpression || current instanceof StaticMethodCallExpression) { - populateItemsFromGameObjects(namePrefix, existingNames, items); + //populateItemsFromGameObjects(namePrefix, existingNames, items); populateItemsFromGlobalScope(namePrefix, existingNames, items); } child = current;