Skip to content

Commit

Permalink
Started with adding BEP validation
Browse files Browse the repository at this point in the history
Works by having another Method annotated as BracketValidator that takes the String and returns a bool stating whether this worked out or not
  • Loading branch information
kindlich committed Apr 27, 2020
1 parent a4e09eb commit 4088c8b
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 33 deletions.
21 changes: 6 additions & 15 deletions src/main/java/com/blamejared/crafttweaker/api/CraftTweakerAPI.java
Expand Up @@ -9,6 +9,7 @@
import com.blamejared.crafttweaker.api.logger.ILogger;
import com.blamejared.crafttweaker.api.logger.LogLevel;
import com.blamejared.crafttweaker.api.mods.MCMods;
import com.blamejared.crafttweaker.api.zencode.brackets.*;
import com.blamejared.crafttweaker.api.zencode.expands.IDataRewrites;
import com.blamejared.crafttweaker.api.zencode.impl.FileAccessSingle;
import com.blamejared.crafttweaker.impl.brackets.RecipeTypeBracketHandler;
Expand Down Expand Up @@ -142,14 +143,10 @@ public static void loadScripts(SourceFile[] sourceFiles, ScriptLoadingOptions sc

PrefixedBracketParser bep = new PrefixedBracketParser(null);
bep.register("recipetype", new RecipeTypeBracketHandler());
crafttweakerModule.registerBEP(bep);
for(Method method : CraftTweakerRegistry.getBracketResolvers("crafttweaker")) {
String name = method.getAnnotation(BracketResolver.class).value();
FunctionalMemberRef memberRef = crafttweakerModule.loadStaticMethod(method);
bep.register(name, new SimpleBracketParser(SCRIPTING_ENGINE.registry, memberRef));
crafttweakerModule.getCompiled().setMethodInfo(memberRef.getTarget(), crafttweakerModule.getCompiled().getMethodInfo(memberRef));
for(ValidatedEscapableBracketParser bracketResolver : CraftTweakerRegistry.getBracketResolvers("crafttweaker", SCRIPTING_ENGINE, crafttweakerModule)) {
bep.register(bracketResolver.getName(), bracketResolver);
}

crafttweakerModule.registerBEP(bep);

CraftTweakerRegistry.getClassesInPackage("crafttweaker").forEach(crafttweakerModule::addClass);
CraftTweakerRegistry.getZenGlobals().forEach(crafttweakerModule::addGlobals);
Expand All @@ -163,15 +160,9 @@ public static void loadScripts(SourceFile[] sourceFiles, ScriptLoadingOptions sc
}
JavaNativeModule module = SCRIPTING_ENGINE.createNativeModule(key, key, crafttweakerModule);
module.registerBEP(bep);

for(Method method : CraftTweakerRegistry.getBracketResolvers(key)) {
String name = method.getAnnotation(BracketResolver.class).value();
FunctionalMemberRef memberRef = module.loadStaticMethod(method);
bep.register(name, new SimpleBracketParser(SCRIPTING_ENGINE.registry, memberRef));
crafttweakerModule.getCompiled().setMethodInfo(memberRef.getTarget(), module.getCompiled().getMethodInfo(memberRef));
for(ValidatedEscapableBracketParser bracketResolver : CraftTweakerRegistry.getBracketResolvers(key, SCRIPTING_ENGINE, module)) {
bep.register(bracketResolver.getName(), bracketResolver);
}


CraftTweakerRegistry.getClassesInPackage(key).forEach(module::addClass);
SCRIPTING_ENGINE.registerNativeProvided(module);
modules.add(module);
Expand Down
Expand Up @@ -5,14 +5,16 @@
import com.blamejared.crafttweaker.api.brackets.CommandStringDisplayable;
import com.blamejared.crafttweaker.api.managers.IRecipeManager;
import com.blamejared.crafttweaker.api.zencode.IPreprocessor;
import com.blamejared.crafttweaker.api.zencode.brackets.*;
import com.blamejared.crafttweaker.impl.brackets.RecipeTypeBracketHandler;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.forgespi.language.ModFileScanData;
import org.objectweb.asm.Type;
import org.openzen.zencode.java.ZenCodeGlobals;
import org.openzen.zencode.java.ZenCodeType;
import org.openzen.zencode.java.*;
import org.openzen.zenscript.codemodel.member.ref.*;
import org.openzen.zenscript.parser.*;

import java.lang.reflect.*;
import java.util.*;
Expand All @@ -27,7 +29,12 @@ public class CraftTweakerRegistry {

private static final List<Class> ZEN_CLASSES = new ArrayList<>();
private static final List<Class> ZEN_GLOBALS = new ArrayList<>();
private static final Map<String, List<Method>> BRACKET_RESOLVERS = new HashMap<>();
//Name to BEP methods
private static final Map<String, Method> BRACKET_RESOLVERS = new HashMap<>();
//Root package to BEP Names
private static final Map<String, Collection<String>> BRACKET_RESOLVERS_2 = new HashMap<>();
//BEP name to BEP validator method
private static final Map<String, Method> BRACKET_VALIDATORS = new HashMap<>();
private static final Map<String, Supplier<Collection<String>>> BRACKET_DUMPERS = new HashMap<>();
private static final Map<String, Class> ZEN_CLASS_MAP = new HashMap<>();
private static final List<IPreprocessor> PREPROCESSORS = new ArrayList<>();
Expand Down Expand Up @@ -76,6 +83,8 @@ public static void findClasses() {
e.printStackTrace();
}
});

validateBrackets();
}

/**
Expand Down Expand Up @@ -127,7 +136,40 @@ private static void sortClasses() {
for(Method method : zenClass.getDeclaredMethods()) {
handleBracketResolver(method);
handleBracketDumper(method);
handleBracketValidator(method);
}
}
}

private static void handleBracketValidator(Method method) {
if(!method.isAnnotationPresent(BracketValidator.class)) {
return;
}
if(!Modifier.isPublic(method.getModifiers()) && !Modifier.isStatic(method.getModifiers())) {
CraftTweakerAPI.logWarning("Method \"%s\" is marked as a BracketValidator, but it is not public and static.", method.toString());
return;
}
boolean valid = true;

final String value = method.getAnnotation(BracketValidator.class).value();
Class<?>[] parameters = method.getParameterTypes();
if(parameters.length == 1 && parameters[0].equals(String.class)) {
if(BRACKET_VALIDATORS.containsKey(value)) {
CraftTweakerAPI.logError("Bracket validator for bep name %s was found twice: %s and %s", value, BRACKET_VALIDATORS.get(value), method);
valid = false;
}
} else {
CraftTweakerAPI.logError("Method \"%s\" is marked as a BracketValidator, but it does not have a String as it's only parameter.", method.toString());
valid = false;
}

if(method.getReturnType() != boolean.class) {
CraftTweakerAPI.logError("Method \"%s\" is marked as a BracketValidator, so it must return a boolean", method);
valid = false;
}

if(valid){
BRACKET_VALIDATORS.put(value, method);
}
}

Expand All @@ -139,19 +181,39 @@ private static void handleBracketResolver(Method method) {
CraftTweakerAPI.logWarning("Method \"%s\" is marked as a BracketResolver, but it is not public and static.", method.toString());
return;
}

boolean isValid = true;
Class<?>[] parameters = method.getParameterTypes();
if(parameters.length == 1 && parameters[0].equals(String.class)) {
Class<?> cls = method.getDeclaringClass();
final ZenCodeType.Name annotation = cls.getAnnotation(ZenCodeType.Name.class);
final String name = annotation == null ? cls.getCanonicalName() : annotation.value();
BRACKET_RESOLVERS.computeIfAbsent(name.split("[.]", 2)[0], s -> new ArrayList<>())
.add(method);
} else {
CraftTweakerAPI.logWarning("Method \"%s\" is marked as a BracketResolver, but it does not have a String as it's only parameter.", method.toString());
final String name = method.getAnnotation(BracketResolver.class).value();

if(parameters.length != 1 || !parameters[0].equals(String.class)) {
//BRACKET_RESOLVERS.computeIfAbsent(name.split("[.]", 2)[0], s -> new ArrayList<>())
// .add(method);
CraftTweakerAPI.logError("Method \"%s\" is marked as a BracketResolver, but it does not have a String as it's only parameter.", method.toString());
isValid = false;
}

if(!CommandStringDisplayable.class.isAssignableFrom(method.getReturnType())){
CraftTweakerAPI.logWarning("Method \"%s\" is marked as a BracketResolver, so it should return something that implements %s.", method.toString(), CommandStringDisplayable.class.getSimpleName());
CraftTweakerAPI.logError("Method \"%s\" is marked as a BracketResolver, so it should return something that implements %s.", method.toString(), CommandStringDisplayable.class.getSimpleName());
isValid = false;
}

if(!BRACKET_RESOLVERS.getOrDefault(name, method).equals(method)) {
final Method other = BRACKET_RESOLVERS.get(name);
CraftTweakerAPI.logError("BracketResolve \"%s\" was registered twice: '%s' and '%s'", name, other, method);
isValid = false;
}

if(isValid) {
BRACKET_RESOLVERS.put(name, method);

final Class<?> cls = method.getDeclaringClass();
final String clsName = cls.isAnnotationPresent(ZenCodeType.Name.class)
? cls.getAnnotation(ZenCodeType.Name.class).value()
: cls.getCanonicalName();

BRACKET_RESOLVERS_2.computeIfAbsent(clsName.split("[.]", 2)[0], s -> new ArrayList<>())
.add(name);
}
}

Expand Down Expand Up @@ -268,8 +330,28 @@ public static List<Class> getZenGlobals() {
*
* @return ImmutableList of the Bracket Resolvers
*/
public static List<Method> getBracketResolvers(String rootPackage) {
return ImmutableList.copyOf(BRACKET_RESOLVERS.getOrDefault(rootPackage, Collections.emptyList()));
public static List<ValidatedEscapableBracketParser> getBracketResolvers(String name, ScriptingEngine scriptingEngine, JavaNativeModule crafttweakerModule) {
final List<ValidatedEscapableBracketParser> validatedEscapableBracketParsers = new ArrayList<>();
for(String bepName : BRACKET_RESOLVERS_2.getOrDefault(name, Collections.emptyList())) {
final Method parserMethod = BRACKET_RESOLVERS.get(bepName);
final Method validatorMethod = CraftTweakerRegistry.getBracketValidator(bepName);
final FunctionalMemberRef functionalMemberRef = crafttweakerModule.loadStaticMethod(parserMethod);
final ValidatedEscapableBracketParser validated = new ValidatedEscapableBracketParser(bepName, functionalMemberRef, validatorMethod, scriptingEngine.registry);
validatedEscapableBracketParsers.add(validated);
}
return validatedEscapableBracketParsers;
}

public static Method getBracketValidator(String bepName) {
return BRACKET_VALIDATORS.getOrDefault(bepName, null);
}

private static void validateBrackets(){
for(String validatedBep : BRACKET_VALIDATORS.keySet()) {
if(!BRACKET_RESOLVERS.containsKey(validatedBep)) {
CraftTweakerAPI.logError("BEP %s has a validator but no BEP method", validatedBep);
}
}
}

/**
Expand Down
Expand Up @@ -6,6 +6,8 @@
* Used to mark a Method as a bracket handler resolver, the method NEEDS to be {@code public static <type> <methodName>(String bracket)}.
* <p>
* The String provided is the exact text inside the bracket {@code <this text here>}, which can then be parsed by the method.
* <p>
* The returned Type should implement ICommandStringDisplayable, otherwise it will log a warning at runtime, and an error at compile time if the annotation processors are part of your build Dependencies
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
Expand Down
@@ -0,0 +1,10 @@
package com.blamejared.crafttweaker.api.annotations;


import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface BracketValidator {
String value();
}
Expand Up @@ -205,29 +205,37 @@ default ResourceLocation getBracketResourceLocation() {

@FunctionalInterface
@ZenRegister
@ZenCodeType.Name("crafttweaker.api.recipe.RecipeFilter")
@Document("vanilla/api/recipe/RecipeFilter")
interface RecipeFilter {

@ZenCodeType.Method
boolean test(String name);
}

@FunctionalInterface
@ZenRegister
@ZenCodeType.Name("crafttweaker.api.recipe.RecipeFunctionSingle")
@Document("vanilla/api/recipe/RecipeFunctionSingle")
interface RecipeFunctionSingle {

@ZenCodeType.Method
IItemStack process(IItemStack usualOut, IItemStack inputs);
}

@FunctionalInterface
@ZenRegister
@ZenCodeType.Name("crafttweaker.api.recipe.RecipeFunctionArray")
@Document("vanilla/api/recipe/RecipeFunctionArray")
interface RecipeFunctionArray {

@ZenCodeType.Method
IItemStack process(IItemStack usualOut, IItemStack[] inputs);
}

@FunctionalInterface
@ZenRegister
@ZenCodeType.Name("crafttweaker.api.recipe.RecipeFunctionMatrix")
@Document("vanilla/api/recipe/RecipeFunctionMatrix")
interface RecipeFunctionMatrix {

@ZenCodeType.Method
IItemStack process(IItemStack usualOut, IItemStack[][] inputs);
}

Expand Down

0 comments on commit 4088c8b

Please sign in to comment.