Enable script in big world (#884)

* add docs for tower

* fix: LEAK: ByteBuf.release() was not called

* enableScriptInBigWorld

* not print log when loaded scripts from cache

* revert the change of server tick

* revert the change of server tick

* fix

* optimize the performance: lazy load & cache

* fix the refresh group

* fix NPE

Co-authored-by: Melledy <52122272+Melledy@users.noreply.github.com>
This commit is contained in:
Akka
2022-05-15 19:19:24 +08:00
committed by GitHub
parent eb64b25f12
commit 6dc30e4def
21 changed files with 643 additions and 321 deletions

View File

@@ -1,32 +1,27 @@
package emu.grasscutter.scripts;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.OneArgFunction;
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
import org.luaj.vm2.script.LuajContext;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.props.EntityType;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.constants.ScriptGadgetState;
import emu.grasscutter.scripts.constants.ScriptRegionShape;
import emu.grasscutter.scripts.data.SceneMeta;
import emu.grasscutter.scripts.serializer.LuaSerializer;
import emu.grasscutter.scripts.serializer.Serializer;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.OneArgFunction;
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
import org.luaj.vm2.script.LuajContext;
import javax.script.*;
import java.io.File;
import java.io.FileReader;
import java.lang.ref.SoftReference;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
public class ScriptLoader {
private static ScriptEngineManager sm;
@@ -34,9 +29,15 @@ public class ScriptLoader {
private static ScriptEngineFactory factory;
private static String fileType;
private static Serializer serializer;
private static Map<String, CompiledScript> scripts = new HashMap<>();
/**
* suggest GC to remove it if the memory is less
*/
private static Map<String, SoftReference<CompiledScript>> scriptsCache = new ConcurrentHashMap<>();
/**
* sceneId - SceneMeta
*/
private static Map<Integer, SoftReference<SceneMeta>> sceneMetaCache = new ConcurrentHashMap<>();
public synchronized static void init() throws Exception {
if (sm != null) {
throw new Exception("Script loader already initialized");
@@ -81,25 +82,42 @@ public class ScriptLoader {
return serializer;
}
public static CompiledScript getScriptByPath(String path) {
CompiledScript sc = scripts.get(path);
Grasscutter.getLogger().info("Loaded " + path);
if (sc == null) {
File file = new File(path);
if (!file.exists()) return null;
try (FileReader fr = new FileReader(file)) {
sc = ((Compilable) getEngine()).compile(fr);
scripts.put(path, sc);
} catch (Exception e) {
//e.printStackTrace();
return null;
}
public static <T> Optional<T> tryGet(SoftReference<T> softReference){
try{
return Optional.ofNullable(softReference.get());
}catch (NullPointerException npe){
return Optional.empty();
}
return sc;
}
public static CompiledScript getScriptByPath(String path) {
var sc = tryGet(scriptsCache.get(path));
if (sc.isPresent()) {
return sc.get();
}
Grasscutter.getLogger().info("Loaded Script" + path);
File file = new File(path);
if (!file.exists()) return null;
try (FileReader fr = new FileReader(file)) {
var script = ((Compilable) getEngine()).compile(fr);
scriptsCache.put(path, new SoftReference<>(script));
return script;
} catch (Exception e) {
Grasscutter.getLogger().error("Loaded Script {} failed!", path, e);
return null;
}
}
public static SceneMeta getSceneMeta(int sceneId) {
return tryGet(sceneMetaCache.get(sceneId)).orElseGet(() -> {
var instance = SceneMeta.of(sceneId);
sceneMetaCache.put(sceneId, new SoftReference<>(instance));
return instance;
});
}
}