Commit bad85357 authored by Akka's avatar Akka Committed by Melledy
Browse files

optimized the Lua func binding so that the script will not eval again

parent a8f38ad9
...@@ -138,7 +138,9 @@ public class DungeonChallenge { ...@@ -138,7 +138,9 @@ public class DungeonChallenge {
getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene())); getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene()));
if(!stage){ if(!stage){
getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE, new ScriptArgs(this.isSuccess() ? 1 : 0)); getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE,
// TODO record the time in PARAM2 and used in action
new ScriptArgs(this.isSuccess() ? 1 : 0, 100));
} }
} }
......
...@@ -26,7 +26,7 @@ public class WorldDataManager { ...@@ -26,7 +26,7 @@ public class WorldDataManager {
} }
public synchronized void load(){ public synchronized void load(){
try(InputStream is = DataLoader.load("ChestReward.json", false); InputStreamReader isr = new InputStreamReader(is)) { try(InputStream is = DataLoader.load("ChestReward.json"); InputStreamReader isr = new InputStreamReader(is)) {
List<ChestReward> chestReward = Grasscutter.getGsonFactory().fromJson( List<ChestReward> chestReward = Grasscutter.getGsonFactory().fromJson(
isr, isr,
TypeToken.getParameterized(List.class, ChestReward.class).getType()); TypeToken.getParameterized(List.class, ChestReward.class).getType());
......
...@@ -20,16 +20,11 @@ import org.luaj.vm2.LuaError; ...@@ -20,16 +20,11 @@ import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.jse.CoerceJavaToLua; import org.luaj.vm2.lib.jse.CoerceJavaToLua;
import javax.script.Bindings;
import javax.script.ScriptException;
import java.util.*; import java.util.*;
public class SceneScriptManager { public class SceneScriptManager {
private final Scene scene; private final Scene scene;
private final ScriptLib scriptLib;
private final LuaValue scriptLibLua;
private final Map<String, Integer> variables; private final Map<String, Integer> variables;
private Bindings bindings;
private SceneMeta meta; private SceneMeta meta;
private boolean isInit; private boolean isInit;
/** /**
...@@ -50,8 +45,6 @@ public class SceneScriptManager { ...@@ -50,8 +45,6 @@ public class SceneScriptManager {
private Int2ObjectMap<Set<SceneGroup>> loadedGroupSetPerBlock; private Int2ObjectMap<Set<SceneGroup>> loadedGroupSetPerBlock;
public SceneScriptManager(Scene scene) { public SceneScriptManager(Scene scene) {
this.scene = scene; this.scene = scene;
this.scriptLib = new ScriptLib(this);
this.scriptLibLua = CoerceJavaToLua.coerce(this.scriptLib);
this.triggers = new HashMap<>(); this.triggers = new HashMap<>();
this.currentTriggers = new Int2ObjectOpenHashMap<>(); this.currentTriggers = new Int2ObjectOpenHashMap<>();
...@@ -74,18 +67,6 @@ public class SceneScriptManager { ...@@ -74,18 +67,6 @@ public class SceneScriptManager {
return scene; return scene;
} }
public ScriptLib getScriptLib() {
return scriptLib;
}
public LuaValue getScriptLibLua() {
return scriptLibLua;
}
public Bindings getBindings() {
return bindings;
}
public SceneConfig getConfig() { public SceneConfig getConfig() {
if(!isInit){ if(!isInit){
return null; return null;
...@@ -162,11 +143,6 @@ public class SceneScriptManager { ...@@ -162,11 +143,6 @@ public class SceneScriptManager {
} }
private void init() { private void init() {
// Create bindings
bindings = ScriptLoader.getEngine().createBindings();
// Set variables
bindings.put("ScriptLib", getScriptLib());
var meta = ScriptLoader.getSceneMeta(getScene().getId()); var meta = ScriptLoader.getSceneMeta(getScene().getId());
if (meta == null){ if (meta == null){
return; return;
...@@ -186,14 +162,7 @@ public class SceneScriptManager { ...@@ -186,14 +162,7 @@ public class SceneScriptManager {
} }
public void loadGroupFromScript(SceneGroup group) { public void loadGroupFromScript(SceneGroup group) {
group.load(getScene().getId(), meta.context); group.load(getScene().getId());
try {
// build the trigger for this scene
group.getScript().eval(getBindings());
} catch (ScriptException e) {
Grasscutter.getLogger().error("Could not build the trigger for this scene", e);
}
group.variables.forEach(var -> this.getVariables().put(var.name, var.value)); group.variables.forEach(var -> this.getVariables().put(var.name, var.value));
this.sceneGroups.put(group.id, group); this.sceneGroups.put(group.id, group);
...@@ -284,47 +253,55 @@ public class SceneScriptManager { ...@@ -284,47 +253,55 @@ public class SceneScriptManager {
// Events // Events
public void callEvent(int eventType, ScriptArgs params) { public void callEvent(int eventType, ScriptArgs params) {
for (SceneTrigger trigger : this.getTriggersByEvent(eventType)) { try{
scriptLib.setCurrentGroup(trigger.currentGroup); ScriptLoader.getScriptLib().setSceneScriptManager(this);
LuaValue condition = null; for (SceneTrigger trigger : this.getTriggersByEvent(eventType)) {
try{
if (trigger.condition != null && !trigger.condition.isEmpty()) { ScriptLoader.getScriptLib().setCurrentGroup(trigger.currentGroup);
condition = (LuaValue) this.getBindings().get(trigger.condition);
} LuaValue ret = callScriptFunc(trigger.condition, trigger.currentGroup, params);
Grasscutter.getLogger().trace("Call Condition Trigger {}", trigger.condition);
LuaValue ret = LuaValue.TRUE;
if (ret.isboolean() && ret.checkboolean()) {
if (condition != null) { // the SetGroupVariableValueByGroup in tower need the param to record the first stage time
LuaValue args = LuaValue.NIL; callScriptFunc(trigger.action, trigger.currentGroup, params);
Grasscutter.getLogger().trace("Call Action Trigger {}", trigger.action);
if (params != null) { }
args = CoerceJavaToLua.coerce(params); //TODO some ret may not bool
}
ScriptLib.logger.trace("Call Condition Trigger {}", trigger); }finally {
ret = safetyCall(trigger.condition, condition, args); ScriptLoader.getScriptLib().removeCurrentGroup();
}
if (ret.isboolean() && ret.checkboolean()) {
if(trigger.action == null || trigger.action.isEmpty()){
return;
} }
ScriptLib.logger.trace("Call Action Trigger {}", trigger);
LuaValue action = (LuaValue) this.getBindings().get(trigger.action);
// TODO impl the param of SetGroupVariableValueByGroup
var arg = new ScriptArgs();
arg.param2 = 100;
var args = CoerceJavaToLua.coerce(arg);
safetyCall(trigger.action, action, args);
} }
//TODO some ret may not bool }finally {
scriptLib.removeCurrentGroup(); // make sure it is removed
ScriptLoader.getScriptLib().removeSceneScriptManager();
}
}
public LuaValue callScriptFunc(String funcName, SceneGroup group, ScriptArgs params){
LuaValue funcLua = null;
if (funcName != null && !funcName.isEmpty()) {
funcLua = (LuaValue) group.getBindings().get(funcName);
}
LuaValue ret = LuaValue.TRUE;
if (funcLua != null) {
LuaValue args = LuaValue.NIL;
if (params != null) {
args = CoerceJavaToLua.coerce(params);
}
ret = safetyCall(funcName, funcLua, args);
} }
return ret;
} }
public LuaValue safetyCall(String name, LuaValue func, LuaValue args){ public LuaValue safetyCall(String name, LuaValue func, LuaValue args){
try{ try{
return func.call(this.getScriptLibLua(), args); return func.call(ScriptLoader.getScriptLibLua(), args);
}catch (LuaError error){ }catch (LuaError error){
ScriptLib.logger.error("[LUA] call trigger failed {},{},{}",name,args,error.getMessage()); ScriptLib.logger.error("[LUA] call trigger failed {},{},{}",name,args,error.getMessage());
return LuaValue.valueOf(-1); return LuaValue.valueOf(-1);
......
...@@ -10,6 +10,7 @@ import emu.grasscutter.scripts.data.SceneRegion; ...@@ -10,6 +10,7 @@ import emu.grasscutter.scripts.data.SceneRegion;
import emu.grasscutter.server.packet.send.PacketCanUseSkillNotify; import emu.grasscutter.server.packet.send.PacketCanUseSkillNotify;
import emu.grasscutter.server.packet.send.PacketGadgetStateNotify; import emu.grasscutter.server.packet.send.PacketGadgetStateNotify;
import emu.grasscutter.server.packet.send.PacketWorktopOptionNotify; import emu.grasscutter.server.packet.send.PacketWorktopOptionNotify;
import io.netty.util.concurrent.FastThreadLocal;
import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -20,15 +21,24 @@ import java.util.Optional; ...@@ -20,15 +21,24 @@ import java.util.Optional;
public class ScriptLib { public class ScriptLib {
public static final Logger logger = LoggerFactory.getLogger(ScriptLib.class); public static final Logger logger = LoggerFactory.getLogger(ScriptLib.class);
private final SceneScriptManager sceneScriptManager; private final FastThreadLocal<SceneScriptManager> sceneScriptManager;
private final FastThreadLocal<SceneGroup> currentGroup;
public ScriptLib(SceneScriptManager sceneScriptManager) { public ScriptLib() {
this.sceneScriptManager = sceneScriptManager; this.sceneScriptManager = new FastThreadLocal<>();
this.currentGroup = new ThreadLocal<>(); this.currentGroup = new FastThreadLocal<>();
}
public void setSceneScriptManager(SceneScriptManager sceneScriptManager){
this.sceneScriptManager.set(sceneScriptManager);
}
public void removeSceneScriptManager(){
this.sceneScriptManager.remove();
} }
public SceneScriptManager getSceneScriptManager() { public SceneScriptManager getSceneScriptManager() {
return sceneScriptManager; // normally not null
return Optional.of(sceneScriptManager.get()).get();
} }
private String printTable(LuaTable table){ private String printTable(LuaTable table){
...@@ -40,13 +50,11 @@ public class ScriptLib { ...@@ -40,13 +50,11 @@ public class ScriptLib {
sb.append("}"); sb.append("}");
return sb.toString(); return sb.toString();
} }
private final ThreadLocal<SceneGroup> currentGroup;
public void setCurrentGroup(SceneGroup currentGroup){ public void setCurrentGroup(SceneGroup currentGroup){
logger.debug("current {}", currentGroup);
this.currentGroup.set(currentGroup); this.currentGroup.set(currentGroup);
} }
public Optional<SceneGroup> getCurrentGroup(){ public Optional<SceneGroup> getCurrentGroup(){
return Optional.ofNullable(this.currentGroup.get()); return Optional.of(this.currentGroup.get());
} }
public void removeCurrentGroup(){ public void removeCurrentGroup(){
this.currentGroup.remove(); this.currentGroup.remove();
......
...@@ -29,6 +29,8 @@ public class ScriptLoader { ...@@ -29,6 +29,8 @@ public class ScriptLoader {
private static ScriptEngineFactory factory; private static ScriptEngineFactory factory;
private static String fileType; private static String fileType;
private static Serializer serializer; private static Serializer serializer;
private static ScriptLib scriptLib;
private static LuaValue scriptLibLua;
/** /**
* suggest GC to remove it if the memory is less * suggest GC to remove it if the memory is less
*/ */
...@@ -68,6 +70,10 @@ public class ScriptLoader { ...@@ -68,6 +70,10 @@ public class ScriptLoader {
ctx.globals.set("EventType", CoerceJavaToLua.coerce(new EventType())); // TODO - make static class to avoid instantiating a new class every scene ctx.globals.set("EventType", CoerceJavaToLua.coerce(new EventType())); // TODO - make static class to avoid instantiating a new class every scene
ctx.globals.set("GadgetState", CoerceJavaToLua.coerce(new ScriptGadgetState())); ctx.globals.set("GadgetState", CoerceJavaToLua.coerce(new ScriptGadgetState()));
ctx.globals.set("RegionShape", CoerceJavaToLua.coerce(new ScriptRegionShape())); ctx.globals.set("RegionShape", CoerceJavaToLua.coerce(new ScriptRegionShape()));
scriptLib = new ScriptLib();
scriptLibLua = CoerceJavaToLua.coerce(scriptLib);
ctx.globals.set("ScriptLib", scriptLibLua);
} }
public static ScriptEngine getEngine() { public static ScriptEngine getEngine() {
...@@ -82,6 +88,14 @@ public class ScriptLoader { ...@@ -82,6 +88,14 @@ public class ScriptLoader {
return serializer; return serializer;
} }
public static ScriptLib getScriptLib() {
return scriptLib;
}
public static LuaValue getScriptLibLua() {
return scriptLibLua;
}
public static <T> Optional<T> tryGet(SoftReference<T> softReference){ public static <T> Optional<T> tryGet(SoftReference<T> softReference){
try{ try{
return Optional.ofNullable(softReference.get()); return Optional.ofNullable(softReference.get());
......
...@@ -10,12 +10,11 @@ import javax.script.Bindings; ...@@ -10,12 +10,11 @@ import javax.script.Bindings;
import javax.script.CompiledScript; import javax.script.CompiledScript;
import javax.script.ScriptException; import javax.script.ScriptException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static emu.grasscutter.Configuration.*; import static emu.grasscutter.Configuration.SCRIPT;
@ToString @ToString
@Setter @Setter
...@@ -40,6 +39,7 @@ public class SceneGroup { ...@@ -40,6 +39,7 @@ public class SceneGroup {
private transient boolean loaded; // Not an actual variable in the scripts either private transient boolean loaded; // Not an actual variable in the scripts either
private transient CompiledScript script; private transient CompiledScript script;
private transient Bindings bindings;
public boolean isLoaded() { public boolean isLoaded() {
return loaded; return loaded;
...@@ -65,13 +65,19 @@ public class SceneGroup { ...@@ -65,13 +65,19 @@ public class SceneGroup {
return suites.get(index - 1); return suites.get(index - 1);
} }
public SceneGroup load(int sceneId, Bindings bindings){ public Bindings getBindings() {
return bindings;
}
public SceneGroup load(int sceneId){
if(loaded){ if(loaded){
return this; return this;
} }
// Set flag here so if there is no script, we dont call this function over and over again. // Set flag here so if there is no script, we dont call this function over and over again.
setLoaded(true); setLoaded(true);
this.bindings = ScriptLoader.getEngine().createBindings();
CompiledScript cs = ScriptLoader.getScriptByPath( CompiledScript cs = ScriptLoader.getScriptByPath(
SCRIPT("Scene/" + sceneId + "/scene" + sceneId + "_group" + id + "." + ScriptLoader.getScriptType())); SCRIPT("Scene/" + sceneId + "/scene" + sceneId + "_group" + id + "." + ScriptLoader.getScriptType()));
......
...@@ -87,6 +87,9 @@ public class LuaSerializer implements Serializer { ...@@ -87,6 +87,9 @@ public class LuaSerializer implements Serializer {
object = (T) constructorCache.get(type).newInstance(); object = (T) constructorCache.get(type).newInstance();
if(table == null){
return object;
}
LuaValue[] keys = table.keys(); LuaValue[] keys = table.keys();
for (LuaValue k : keys) { for (LuaValue k : keys) {
try { try {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment