Files
CustomNPC-Plus/src/main/java/noppes/npcs/controllers/ScriptController.java
T

401 lines
13 KiB
Java
Raw Normal View History

2018-09-13 12:03:28 -04:00
package noppes.npcs.controllers;
2023-01-12 21:33:06 -05:00
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import jdk.nashorn.api.scripting.ClassFilter;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
import kamkeel.npcs.network.packets.request.script.ScriptFilesPacket;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
2018-09-13 12:03:28 -04:00
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTTagString;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.event.world.WorldEvent;
import noppes.npcs.CustomNpcs;
import noppes.npcs.LogWriter;
2025-04-09 01:55:34 -04:00
import noppes.npcs.api.entity.IPlayer;
2023-11-16 15:19:32 -05:00
import noppes.npcs.config.ConfigScript;
import noppes.npcs.controllers.data.ForgeDataScript;
2023-03-16 04:27:19 -05:00
import noppes.npcs.controllers.data.GlobalNPCDataScript;
2025-04-09 01:55:34 -04:00
import noppes.npcs.controllers.data.PlayerData;
import noppes.npcs.controllers.data.PlayerDataScript;
2018-09-13 12:03:28 -04:00
import noppes.npcs.entity.EntityNPCInterface;
import noppes.npcs.scripted.ScriptWorld;
import noppes.npcs.util.JsonException;
2018-09-13 12:03:28 -04:00
import noppes.npcs.util.NBTJsonUtil;
2025-12-09 08:11:34 +01:00
import somehussar.janino.EntityUnloadListener;
2023-01-12 21:33:06 -05:00
import javax.script.ScriptContext;
2023-01-12 21:33:06 -05:00
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
2025-02-20 21:40:39 -05:00
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
2025-07-23 14:22:52 -04:00
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
2018-09-13 12:03:28 -04:00
2024-04-04 18:53:53 -04:00
import static noppes.npcs.util.CustomNPCsThreader.customNPCThread;
2018-09-13 12:03:28 -04:00
public class ScriptController {
2021-10-19 02:49:46 -05:00
2025-03-13 17:14:45 -04:00
public static ScriptController Instance;
public static boolean HasStart = false;
private final ScriptEngineManager manager;
private ScriptEngineFactory nashornFactory;
2025-12-14 21:41:21 +02:00
public final Map<String, String> languages = new HashMap<String, String>();
2025-03-13 17:14:45 -04:00
public Map<String, String> scripts = new HashMap<String, String>();
public long lastLoaded = 0;
public File dir;
public NBTTagCompound compound = new NBTTagCompound();
public boolean shouldSave = false;
public PlayerDataScript playerScripts = new PlayerDataScript((EntityPlayer) null);
public long lastPlayerUpdate = 0L;
public ForgeDataScript forgeScripts = new ForgeDataScript();
public long lastForgeUpdate = 0L;
public GlobalNPCDataScript globalNpcScripts = new GlobalNPCDataScript((EntityNPCInterface) null);
public long lastGlobalNpcUpdate = 0L;
/**
* Incremented whenever external scripts loaded.
*/
public int globalRevision;
2025-03-13 17:14:45 -04:00
public ScriptController() {
Instance = this;
manager = new ScriptEngineManager();
if (!CustomNpcs.proxy.isScriptingEnabled())
2025-03-13 17:14:45 -04:00
return;
LogWriter.info("Script Engines Available:");
2025-05-25 22:44:04 -04:00
try {
this.nashornFactory = new NashornScriptEngineFactory();
LogWriter.info("→ standalone Nashorn loaded");
} catch (NoClassDefFoundError e) {
// fallback to built-in (Java 8–11) — also guarded
try {
ScriptEngine eng = manager.getEngineByName("nashorn");
if (eng != null) {
this.nashornFactory = eng.getFactory();
LogWriter.info("→ built-in Nashorn loaded");
}
} catch (Throwable t) {
LogWriter.error("No Nashorn engine available");
}
2025-03-13 17:14:45 -04:00
}
for (ScriptEngineFactory fac : manager.getEngineFactories()) {
if (fac.getExtensions().isEmpty())
continue;
ScriptEngine scriptEngine = fac.getScriptEngine();
try {
scriptEngine.put("$RunTest", null);
String ext = "." + fac.getExtensions().get(0).toLowerCase();
LogWriter.info("Engine " + fac.getEngineName() + " running " + fac.getLanguageName() + " with extension: " + ext);
languages.put(fac.getLanguageName(), ext);
} catch (Exception ignored) {
}
}
languages.put("Java", ".java");
2025-03-13 17:14:45 -04:00
}
private File forgeScriptsFile() {
return new File(this.dir, "forge_scripts.json");
}
public boolean loadForgeScripts() {
this.forgeScripts.clear();
File file = this.forgeScriptsFile();
try {
if (!file.exists()) {
return false;
} else {
this.forgeScripts.readFromNBT(NBTJsonUtil.LoadFile(file));
return true;
}
} catch (Exception var3) {
LogWriter.error("Error loading: " + file.getAbsolutePath(), var3);
return false;
}
}
public void saveForgeScripts() {
File file = this.forgeScriptsFile();
try {
NBTJsonUtil.SaveFile(file, this.forgeScripts.writeToNBT(new NBTTagCompound()));
2026-01-22 14:27:48 -05:00
this.forgeScripts.resetLastInited();
2025-03-13 17:14:45 -04:00
} catch (IOException | JsonException var4) {
var4.printStackTrace();
}
}
private File playerScriptsFile() {
return new File(dir, "player_scripts.json");
}
private File npcScriptsFile() {
return new File(dir, "npc_scripts.json");
}
public boolean loadPlayerScripts() {
this.playerScripts.clear();
File file = this.playerScriptsFile();
try {
if (!file.exists()) {
return false;
} else {
this.playerScripts.readFromNBT(NBTJsonUtil.LoadFile(file));
shouldSave = false;
return true;
}
} catch (Exception var3) {
LogWriter.error("Error loading: " + file.getAbsolutePath(), var3);
return false;
}
}
public void savePlayerScripts() {
File file = this.playerScriptsFile();
try {
NBTJsonUtil.SaveFile(file, this.playerScripts.writeToNBT(new NBTTagCompound()));
2026-01-22 14:27:48 -05:00
this.playerScripts.resetLastInited();
2025-03-13 17:14:45 -04:00
} catch (IOException | JsonException var4) {
var4.printStackTrace();
}
}
2025-05-20 13:53:26 -04:00
public PlayerDataScript getPlayerScripts(EntityPlayer player) {
if (ConfigScript.IndividualPlayerScripts)
2025-04-09 01:55:34 -04:00
return PlayerData.get(player).scriptData;
return this.playerScripts;
}
2025-05-20 13:53:26 -04:00
public PlayerDataScript getPlayerScripts(IPlayer player) {
if (ConfigScript.IndividualPlayerScripts)
2025-04-09 01:55:34 -04:00
return PlayerData.get((EntityPlayer) player.getMCEntity()).scriptData;
return this.playerScripts;
}
2025-03-13 17:14:45 -04:00
public boolean loadGlobalNPCScripts() {
this.globalNpcScripts.clear();
File file = this.npcScriptsFile();
try {
if (!file.exists()) {
return false;
} else {
this.globalNpcScripts.readFromNBT(NBTJsonUtil.LoadFile(file));
shouldSave = false;
return true;
}
} catch (Exception var3) {
LogWriter.error("Error loading: " + file.getAbsolutePath(), var3);
return false;
}
}
public void saveGlobalNpcScripts() {
File file = this.npcScriptsFile();
try {
NBTJsonUtil.SaveFile(file, this.globalNpcScripts.writeToNBT(new NBTTagCompound()));
2026-01-22 14:27:48 -05:00
this.globalNpcScripts.resetLastInited();
2025-03-13 17:14:45 -04:00
} catch (IOException | JsonException var4) {
var4.printStackTrace();
}
}
public synchronized void saveForgeScriptsSync() {
2024-04-04 18:53:53 -04:00
customNPCThread.execute(this::saveForgeScripts);
}
2025-03-13 17:14:45 -04:00
public synchronized void savePlayerScriptsSync() {
2024-04-04 18:53:53 -04:00
customNPCThread.execute(() -> {
File file = this.playerScriptsFile();
try {
NBTJsonUtil.SaveFile(file, this.playerScripts.writeToNBT(new NBTTagCompound()));
2026-01-22 14:27:48 -05:00
this.playerScripts.resetLastInited();
2024-04-04 18:53:53 -04:00
} catch (IOException | JsonException var4) {
var4.printStackTrace();
}
});
}
2025-03-13 17:14:45 -04:00
public synchronized void saveGlobalScriptsSync() {
2024-04-04 18:53:53 -04:00
customNPCThread.execute(this::saveGlobalNpcScripts);
}
public void syncClientScripts(EntityPlayerMP player) {
if (player != null) {
ScriptFilesPacket.sendToPlayer(player, "Java");
} else {
ScriptFilesPacket.sendToAll("Java");
}
}
2025-03-13 17:14:45 -04:00
public void loadCategories() {
dir = new File(CustomNpcs.getWorldSaveDirectory(), "scripts");
if (!dir.exists())
dir.mkdir();
if (!getSavedFile().exists())
shouldSave = true;
new ScriptWorld(null).clearTempData();
scripts.clear();
for (String language : languages.keySet()) {
String ext = languages.get(language);
File scriptDir = new File(dir, language.toLowerCase());
if (!scriptDir.exists())
scriptDir.mkdir();
else
loadDir(scriptDir, "", ext);
}
lastLoaded = System.currentTimeMillis();
globalRevision++;
2025-03-13 17:14:45 -04:00
}
private void loadDir(File dir, String name, String ext) {
for (File file : dir.listFiles()) {
String filename = name + file.getName().toLowerCase();
if (file.isDirectory()) {
loadDir(file, filename + "/", ext);
continue;
}
if (!filename.endsWith(ext))
continue;
try {
scripts.put(filename, readFile(file));
} catch (IOException e) {
e.printStackTrace();
}
}
}
public boolean loadStoredData() {
loadCategories();
File file = getSavedFile();
try {
if (!file.exists())
return false;
this.compound = NBTJsonUtil.LoadFile(file);
shouldSave = false;
} catch (Exception e) {
LogWriter.error("Error loading: " + file.getAbsolutePath(), e);
return false;
}
return true;
}
private File getSavedFile() {
return new File(dir, "world_data.json");
}
private String readFile(File file) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(file));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append("\n");
line = br.readLine();
}
return sb.toString();
} finally {
br.close();
}
}
private static final List<String> nashornNames = immutableList("nashorn", "Nashorn", "js", "JS", "JavaScript", "javascript", "ECMAScript", "ecmascript");
public ScriptEngine getEngineByName(String language) {
if (nashornNames.contains(language) && this.nashornFactory != null) {
ScriptEngine scriptEngine;
2025-03-13 17:14:45 -04:00
if (ConfigScript.EnableBannedClasses) {
2024-02-29 20:23:42 -05:00
try {
ClassFilter filter = s -> {
for (String className : ConfigScript.BannedClasses) {
if (s.compareTo(className) == 0) {
return false;
}
}
2024-02-29 20:23:42 -05:00
return true;
};
NashornScriptEngineFactory nashornScriptEngineFactory = (NashornScriptEngineFactory) this.nashornFactory;
scriptEngine = nashornScriptEngineFactory.getScriptEngine(filter);
} catch (Exception e) {
scriptEngine = this.nashornFactory.getScriptEngine();
}
} else {
scriptEngine = this.nashornFactory.getScriptEngine();
}
2025-03-13 17:14:45 -04:00
scriptEngine.setBindings(this.manager.getBindings(), ScriptContext.GLOBAL_SCOPE);
return scriptEngine;
}
return manager.getEngineByName(language);
}
private static List<String> immutableList(String... elements) {
return Collections.unmodifiableList(Arrays.asList(elements));
}
public NBTTagList nbtLanguages() {
NBTTagList list = new NBTTagList();
for (String language : languages.keySet()) {
NBTTagCompound compound = new NBTTagCompound();
NBTTagList scripts = new NBTTagList();
for (String script : getScripts(language)) {
scripts.appendTag(new NBTTagString(script));
}
compound.setTag("Scripts", scripts);
compound.setString("Language", language);
list.appendTag(compound);
}
return list;
}
public List<String> getScripts(String language) {
2025-03-13 17:14:45 -04:00
List<String> list = new ArrayList<String>();
String ext = languages.get(language);
if (ext == null)
return list;
for (String script : scripts.keySet()) {
if (script.endsWith(ext)) {
list.add(script);
}
}
return list;
}
2025-12-09 08:11:34 +01:00
@SubscribeEvent
public void addWorldAccess(WorldEvent.Load event) {
event.world.addWorldAccess(new EntityUnloadListener());
}
2025-03-13 17:14:45 -04:00
@SubscribeEvent
public void invoke(WorldEvent.Save event) {
if (!shouldSave || event.world.isRemote || event.world != MinecraftServer.getServer().worldServers[0])
return;
try {
NBTJsonUtil.SaveFile(getSavedFile(), compound);
} catch (Exception e) {
LogWriter.except(e);
}
shouldSave = false;
}
}