Skip to content
Snippets Groups Projects
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
Branches
Tags
No related merge requests found
...@@ -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 {
......
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