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

This commit is contained in:
Akka 2022-05-19 11:15:40 +08:00 committed by Melledy
parent 1fef837a97
commit 8faf8decec
7 changed files with 89 additions and 79 deletions

View File

@ -138,7 +138,9 @@ public class DungeonChallenge {
getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene()));
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));
}
}

View File

@ -26,7 +26,7 @@ public class WorldDataManager {
}
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(
isr,
TypeToken.getParameterized(List.class, ChestReward.class).getType());

View File

@ -20,16 +20,11 @@ import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
import javax.script.Bindings;
import javax.script.ScriptException;
import java.util.*;
public class SceneScriptManager {
private final Scene scene;
private final ScriptLib scriptLib;
private final LuaValue scriptLibLua;
private final Map<String, Integer> variables;
private Bindings bindings;
private SceneMeta meta;
private boolean isInit;
/**
@ -50,8 +45,6 @@ public class SceneScriptManager {
private Int2ObjectMap<Set<SceneGroup>> loadedGroupSetPerBlock;
public SceneScriptManager(Scene scene) {
this.scene = scene;
this.scriptLib = new ScriptLib(this);
this.scriptLibLua = CoerceJavaToLua.coerce(this.scriptLib);
this.triggers = new HashMap<>();
this.currentTriggers = new Int2ObjectOpenHashMap<>();
@ -74,18 +67,6 @@ public class SceneScriptManager {
return scene;
}
public ScriptLib getScriptLib() {
return scriptLib;
}
public LuaValue getScriptLibLua() {
return scriptLibLua;
}
public Bindings getBindings() {
return bindings;
}
public SceneConfig getConfig() {
if(!isInit){
return null;
@ -162,11 +143,6 @@ public class SceneScriptManager {
}
private void init() {
// Create bindings
bindings = ScriptLoader.getEngine().createBindings();
// Set variables
bindings.put("ScriptLib", getScriptLib());
var meta = ScriptLoader.getSceneMeta(getScene().getId());
if (meta == null){
return;
@ -186,14 +162,7 @@ public class SceneScriptManager {
}
public void loadGroupFromScript(SceneGroup group) {
group.load(getScene().getId(), meta.context);
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.load(getScene().getId());
group.variables.forEach(var -> this.getVariables().put(var.name, var.value));
this.sceneGroups.put(group.id, group);
@ -284,47 +253,55 @@ public class SceneScriptManager {
// Events
public void callEvent(int eventType, ScriptArgs params) {
for (SceneTrigger trigger : this.getTriggersByEvent(eventType)) {
scriptLib.setCurrentGroup(trigger.currentGroup);
LuaValue condition = null;
if (trigger.condition != null && !trigger.condition.isEmpty()) {
condition = (LuaValue) this.getBindings().get(trigger.condition);
}
LuaValue ret = LuaValue.TRUE;
if (condition != null) {
LuaValue args = LuaValue.NIL;
if (params != null) {
args = CoerceJavaToLua.coerce(params);
}
try{
ScriptLoader.getScriptLib().setSceneScriptManager(this);
for (SceneTrigger trigger : this.getTriggersByEvent(eventType)) {
try{
ScriptLoader.getScriptLib().setCurrentGroup(trigger.currentGroup);
ScriptLib.logger.trace("Call Condition Trigger {}", trigger);
ret = safetyCall(trigger.condition, condition, args);
}
if (ret.isboolean() && ret.checkboolean()) {
if(trigger.action == null || trigger.action.isEmpty()){
return;
LuaValue ret = callScriptFunc(trigger.condition, trigger.currentGroup, params);
Grasscutter.getLogger().trace("Call Condition Trigger {}", trigger.condition);
if (ret.isboolean() && ret.checkboolean()) {
// the SetGroupVariableValueByGroup in tower need the param to record the first stage time
callScriptFunc(trigger.action, trigger.currentGroup, params);
Grasscutter.getLogger().trace("Call Action Trigger {}", trigger.action);
}
//TODO some ret may not bool
}finally {
ScriptLoader.getScriptLib().removeCurrentGroup();
}
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
scriptLib.removeCurrentGroup();
}finally {
// 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){
try{
return func.call(this.getScriptLibLua(), args);
return func.call(ScriptLoader.getScriptLibLua(), args);
}catch (LuaError error){
ScriptLib.logger.error("[LUA] call trigger failed {},{},{}",name,args,error.getMessage());
return LuaValue.valueOf(-1);

View File

@ -10,6 +10,7 @@ import emu.grasscutter.scripts.data.SceneRegion;
import emu.grasscutter.server.packet.send.PacketCanUseSkillNotify;
import emu.grasscutter.server.packet.send.PacketGadgetStateNotify;
import emu.grasscutter.server.packet.send.PacketWorktopOptionNotify;
import io.netty.util.concurrent.FastThreadLocal;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.slf4j.Logger;
@ -20,15 +21,24 @@ import java.util.Optional;
public class ScriptLib {
public static final Logger logger = LoggerFactory.getLogger(ScriptLib.class);
private final SceneScriptManager sceneScriptManager;
public ScriptLib(SceneScriptManager sceneScriptManager) {
this.sceneScriptManager = sceneScriptManager;
this.currentGroup = new ThreadLocal<>();
private final FastThreadLocal<SceneScriptManager> sceneScriptManager;
private final FastThreadLocal<SceneGroup> currentGroup;
public ScriptLib() {
this.sceneScriptManager = new FastThreadLocal<>();
this.currentGroup = new FastThreadLocal<>();
}
public void setSceneScriptManager(SceneScriptManager sceneScriptManager){
this.sceneScriptManager.set(sceneScriptManager);
}
public void removeSceneScriptManager(){
this.sceneScriptManager.remove();
}
public SceneScriptManager getSceneScriptManager() {
return sceneScriptManager;
// normally not null
return Optional.of(sceneScriptManager.get()).get();
}
private String printTable(LuaTable table){
@ -40,13 +50,11 @@ public class ScriptLib {
sb.append("}");
return sb.toString();
}
private final ThreadLocal<SceneGroup> currentGroup;
public void setCurrentGroup(SceneGroup currentGroup){
logger.debug("current {}", currentGroup);
this.currentGroup.set(currentGroup);
}
public Optional<SceneGroup> getCurrentGroup(){
return Optional.ofNullable(this.currentGroup.get());
return Optional.of(this.currentGroup.get());
}
public void removeCurrentGroup(){
this.currentGroup.remove();

View File

@ -29,6 +29,8 @@ public class ScriptLoader {
private static ScriptEngineFactory factory;
private static String fileType;
private static Serializer serializer;
private static ScriptLib scriptLib;
private static LuaValue scriptLibLua;
/**
* suggest GC to remove it if the memory is less
*/
@ -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("GadgetState", CoerceJavaToLua.coerce(new ScriptGadgetState()));
ctx.globals.set("RegionShape", CoerceJavaToLua.coerce(new ScriptRegionShape()));
scriptLib = new ScriptLib();
scriptLibLua = CoerceJavaToLua.coerce(scriptLib);
ctx.globals.set("ScriptLib", scriptLibLua);
}
public static ScriptEngine getEngine() {
@ -82,6 +88,14 @@ public class ScriptLoader {
return serializer;
}
public static ScriptLib getScriptLib() {
return scriptLib;
}
public static LuaValue getScriptLibLua() {
return scriptLibLua;
}
public static <T> Optional<T> tryGet(SoftReference<T> softReference){
try{
return Optional.ofNullable(softReference.get());

View File

@ -10,12 +10,11 @@ import javax.script.Bindings;
import javax.script.CompiledScript;
import javax.script.ScriptException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static emu.grasscutter.Configuration.*;
import static emu.grasscutter.Configuration.SCRIPT;
@ToString
@Setter
@ -40,6 +39,7 @@ public class SceneGroup {
private transient boolean loaded; // Not an actual variable in the scripts either
private transient CompiledScript script;
private transient Bindings bindings;
public boolean isLoaded() {
return loaded;
@ -65,13 +65,19 @@ public class SceneGroup {
return suites.get(index - 1);
}
public SceneGroup load(int sceneId, Bindings bindings){
public Bindings getBindings() {
return bindings;
}
public SceneGroup load(int sceneId){
if(loaded){
return this;
}
// Set flag here so if there is no script, we dont call this function over and over again.
setLoaded(true);
this.bindings = ScriptLoader.getEngine().createBindings();
CompiledScript cs = ScriptLoader.getScriptByPath(
SCRIPT("Scene/" + sceneId + "/scene" + sceneId + "_group" + id + "." + ScriptLoader.getScriptType()));

View File

@ -87,6 +87,9 @@ public class LuaSerializer implements Serializer {
object = (T) constructorCache.get(type).newInstance();
if(table == null){
return object;
}
LuaValue[] keys = table.keys();
for (LuaValue k : keys) {
try {