diff --git a/FactorioDataWrapper/src/com/demod/factorio/FactorioData.java b/FactorioDataWrapper/src/com/demod/factorio/FactorioData.java index 9f123b7..56e19e9 100644 --- a/FactorioDataWrapper/src/com/demod/factorio/FactorioData.java +++ b/FactorioDataWrapper/src/com/demod/factorio/FactorioData.java @@ -15,6 +15,7 @@ import java.io.InputStreamReader; import java.io.StringReader; import java.net.URISyntaxException; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -31,6 +32,7 @@ import org.json.JSONException; import org.json.JSONObject; import org.luaj.vm2.Globals; +import org.luaj.vm2.LuaString; import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaValue; import org.luaj.vm2.lib.BaseLib; @@ -161,10 +163,10 @@ public static BufferedImage getIcon(DataPrototype prototype) { // Overlay icon of equipment technology icons are outside bounds of base icon. // So, move the overlay icon up. Do the same for mining productivity tech. String path = l.get("icon").tojstring(); - if (path.equals("__core__/graphics/icons/technology/constants/constant-equipment.png")) { - g.translate(0, -20); - } else if (path.equals("__core__/graphics/icons/technology/constants/constant-mining-productivity.png")) { + if (path.equals("__core__/graphics/icons/technology/constants/constant-mining-productivity.png")) { g.translate(-8, -7); + } else if (path.equals("__core__/graphics/icons/technology/constants/constant-equipment.png")) { + g.translate(0, -20); } g.scale(scale, scale); @@ -248,82 +250,6 @@ private static DataTable initializeDataTable() throws JSONException, IOException TypeHierarchy typeHiearchy = new TypeHierarchy(Utils .readJsonFromStream(FactorioData.class.getClassLoader().getResourceAsStream("type-hiearchy.json"))); - Box currentMod = Box.of(modLoader.getMod("core").get()); - - Globals globals = JsePlatform.standardGlobals(); - globals.load(new BaseLib()); - globals.load(new DebugLib()); - globals.load(new Bit32Lib()); - globals.load(new StringReader("package.path = package.path .. ';" + luaPath + "'"), "initLuaPath").call(); - globals.finder = new ResourceFinder() { - @Override - public InputStream findResource(String filename) { - /* - * Problematic call stack: PackageLib$searchpath.invoke(Varargs) line: 291 - * PackageLib$lua_searcher.invoke(Varargs) line: 263 - * PackageLib$require.call(LuaValue) line: 217 - * - * PackageLib$searchpath.invoke(Varargs) line: 291 replaces all "." with - * FILE_SEP ( = System.getProperty("file.separator")), on windows this is "\". - * This means that if a require uses "file.lua" as the file name, this is - * converted to "file\lua". - * - * So now when applying the package path, LuaJ will add the ".lua" from the - * "?.lua" package path back on it and it turns into "file\lua.lua". And then - * the file isn't found! - * - * Solution: Hack it by turning "\lua.lua" back into ".lua". - * - * This will give wrong results if someone has a file named "lua.lua". I - * consider this less likely than a require that contains the file extension. - * - * TODO: Test if this works on Linux - * - */ - if (filename.endsWith(File.separator + "lua.lua")) { - filename = filename.replace(File.separator + "lua.lua", ".lua"); - } - if (filename.startsWith(SEARCH_MOD) && currentMod.get() != null) { - try { - return currentMod.get().getResource(filename.replace(SEARCH_MOD, "")).orElse(null); - } catch (Exception e) { - e.printStackTrace(); - throw new InternalError(e); - } - } else if (filename.startsWith(SEARCH_RESOURCE)) { - InputStream stream = FactorioData.class.getClassLoader() - .getResourceAsStream(filename.replace(SEARCH_RESOURCE, "lua")); - // System.out.println(stream != null); - return stream; - } else if (filename.startsWith("__") && (filename.indexOf("__", 2) > -1)) { - int matchEnd = filename.indexOf("__", 2); - String modName = filename.substring(2, matchEnd); - Optional mod = modLoader.getMod(modName); - if (!mod.isPresent()) { - throw new IllegalStateException("Mod does not exist: " + modName); - } - try { - return mod.get().getResource(filename.substring(matchEnd + 2)).orElse(null); - } catch (Exception e) { - e.printStackTrace(); - throw new InternalError(e); - } - } else { - File file = new File(filename); - // System.out.println(file.exists()); - try { - return file.exists() ? new FileInputStream(file) : null; - } catch (FileNotFoundException e) { - e.printStackTrace(); - throw new InternalError(e); - } - } - } - }; - - globals.load(new InputStreamReader(globals.finder.findResource(SEARCH_RESOURCE + "/loader.lua")), "loader") - .call(); - List loadOrder = modLoader.getModsInLoadOrder(); System.out.println("LOAD ORDER:"); @@ -332,23 +258,27 @@ public InputStream findResource(String filename) { System.out.println(" " + info.getName()); } - LuaValue modsTable = LuaValue.tableOf(0, loadOrder.size()); - for (Mod mod : loadOrder) { - ModInfo info = mod.getInfo(); - if (!info.getName().equals("core")) - modsTable.set(info.getName(), info.getVersion()); - } - globals.set("mods", modsTable); + Box currentMod = Box.of(modLoader.getMod("core").get()); + + Globals globals = setupLuaState(luaPath, loadOrder, currentMod); + List initialPackages = new ArrayList<>(); + Utils.forEach(globals.get("package").get("loaded"), (k, v) -> { + initialPackages.add(k.checkstring()); + }); + + loadStage(globals, initialPackages, loadOrder, currentMod, "/settings.lua"); + loadStage(globals, initialPackages, loadOrder, currentMod, "/settings-updates.lua"); + loadStage(globals, initialPackages, loadOrder, currentMod, "/settings-final-fixes.lua"); - loadStage(globals, loadOrder, currentMod, "/settings.lua"); - loadStage(globals, loadOrder, currentMod, "/settings-updates.lua"); - loadStage(globals, loadOrder, currentMod, "/settings-final-fixes.lua"); + LuaTable settingsLua = initializeSettings(globals); - initializeSettings(globals); + // Discard the LuaState from settings and create a new one for data + globals = setupLuaState(luaPath, loadOrder, currentMod); + globals.set("settings", settingsLua); - loadStage(globals, loadOrder, currentMod, "/data.lua"); - loadStage(globals, loadOrder, currentMod, "/data-updates.lua"); - loadStage(globals, loadOrder, currentMod, "/data-final-fixes.lua"); + loadStage(globals, initialPackages, loadOrder, currentMod, "/data.lua"); + loadStage(globals, initialPackages, loadOrder, currentMod, "/data-updates.lua"); + loadStage(globals, initialPackages, loadOrder, currentMod, "/data-final-fixes.lua"); JSONObject excludeDataJson = Utils .readJsonFromStream(FactorioData.class.getClassLoader().getResourceAsStream("exclude-data.json")); @@ -362,7 +292,7 @@ public InputStream findResource(String filename) { return dataTable; } - private static void initializeSettings(Globals globals) { + private static LuaTable initializeSettings(Globals globals) { LuaTable settingsLua = new LuaTable(); LuaTable startupLua = new LuaTable(); settingsLua.set("startup", startupLua); @@ -397,7 +327,7 @@ private static void initializeSettings(Globals globals) { }); }); - globals.set("settings", settingsLua); + return settingsLua; } private static BufferedImage loadImage(InputStream is) throws IOException { @@ -408,9 +338,10 @@ private static BufferedImage loadImage(InputStream is) throws IOException { return image; } - private static void loadStage(Globals globals, List loadOrder, Box currentMod, String filename) - throws IOException { + private static void loadStage(Globals globals, List initialPackages, List loadOrder, + Box currentMod, String filename) throws IOException { for (Mod mod : loadOrder) { + resetPackagesLoaded(globals, initialPackages); currentMod.set(mod); Optional resource = mod.getResource(filename); if (resource.isPresent()) { @@ -435,6 +366,103 @@ public static IntUnaryOperator parseCountFormula(String countFormula) { }; } + private static void resetPackagesLoaded(Globals globals, List initialPackages) { + List toErase = new ArrayList<>(); + LuaTable loaded = globals.get("package").get("loaded").checktable(); + Utils.forEach(loaded, (k, v) -> { + LuaString packageName = k.checkstring(); + if (!initialPackages.contains(packageName)) + toErase.add(packageName); + }); + for (LuaString packageName : toErase) { + loaded.set(packageName, LuaValue.NIL); + } + } + + private static Globals setupLuaState(String luaPath, List loadOrder, Box currentMod) { + Globals globals = JsePlatform.standardGlobals(); + globals.load(new BaseLib()); + globals.load(new DebugLib()); + globals.load(new Bit32Lib()); + globals.load(new StringReader("package.path = package.path .. ';" + luaPath + "'"), "initLuaPath").call(); + globals.finder = new ResourceFinder() { + @Override + public InputStream findResource(String filename) { + /* + * Problematic call stack: PackageLib$searchpath.invoke(Varargs) line: 291 + * PackageLib$lua_searcher.invoke(Varargs) line: 263 + * PackageLib$require.call(LuaValue) line: 217 + * + * PackageLib$searchpath.invoke(Varargs) line: 291 replaces all "." with + * FILE_SEP ( = System.getProperty("file.separator")), on Windows this is "\". + * This means that if a require uses "file.lua" as the file name, this is + * converted to "file\lua". + * + * So now when applying the package path, LuaJ will add the ".lua" from the + * "?.lua" package path back on it and it turns into "file\lua.lua". And then + * the file isn't found! + * + * Solution: Hack it by turning "\lua.lua" back into ".lua". + * + * This will give wrong results if someone has a file named "lua.lua". I + * consider this less likely than a require that contains the file extension. + * + */ + if (filename.endsWith(File.separator + "lua.lua")) { + filename = filename.replace(File.separator + "lua.lua", ".lua"); + } + if (filename.startsWith(SEARCH_MOD) && currentMod.get() != null) { + try { + return currentMod.get().getResource(filename.replace(SEARCH_MOD, "")).orElse(null); + } catch (Exception e) { + e.printStackTrace(); + throw new InternalError(e); + } + } else if (filename.startsWith(SEARCH_RESOURCE)) { + InputStream stream = FactorioData.class.getClassLoader() + .getResourceAsStream(filename.replace(SEARCH_RESOURCE, "lua")); + // System.out.println(stream != null); + return stream; + } else if (filename.startsWith("__") && (filename.indexOf("__", 2) > -1)) { + int matchEnd = filename.indexOf("__", 2); + String modName = filename.substring(2, matchEnd); + Optional mod = modLoader.getMod(modName); + if (!mod.isPresent()) { + throw new IllegalStateException("Mod does not exist: " + modName); + } + try { + return mod.get().getResource(filename.substring(matchEnd + 2)).orElse(null); + } catch (Exception e) { + e.printStackTrace(); + throw new InternalError(e); + } + } else { + File file = new File(filename); + // System.out.println(file.exists()); + try { + return file.exists() ? new FileInputStream(file) : null; + } catch (FileNotFoundException e) { + e.printStackTrace(); + throw new InternalError(e); + } + } + } + }; + + globals.load(new InputStreamReader(globals.finder.findResource(SEARCH_RESOURCE + "/loader.lua")), "loader") + .call(); + + LuaValue modsTable = LuaValue.tableOf(0, loadOrder.size()); + for (Mod mod : loadOrder) { + ModInfo info = mod.getInfo(); + if (!info.getName().equals("core")) + modsTable.set(info.getName(), info.getVersion()); + } + globals.set("mods", modsTable); + + return globals; + } + private static void setupWorkingDirectory() { String className = FactorioData.class.getName().replace('.', '/'); String classJar = FactorioData.class.getResource("/" + className + ".class").toString();