Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 125 additions & 97 deletions FactorioDataWrapper/src/com/demod/factorio/FactorioData.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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<Mod> 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> 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<Mod> loadOrder = modLoader.getModsInLoadOrder();

System.out.println("LOAD ORDER:");
Expand All @@ -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<Mod> currentMod = Box.of(modLoader.getMod("core").get());

Globals globals = setupLuaState(luaPath, loadOrder, currentMod);
List<LuaString> 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"));
Expand All @@ -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);
Expand Down Expand Up @@ -397,7 +327,7 @@ private static void initializeSettings(Globals globals) {
});
});

globals.set("settings", settingsLua);
return settingsLua;
}

private static BufferedImage loadImage(InputStream is) throws IOException {
Expand All @@ -408,9 +338,10 @@ private static BufferedImage loadImage(InputStream is) throws IOException {
return image;
}

private static void loadStage(Globals globals, List<Mod> loadOrder, Box<Mod> currentMod, String filename)
throws IOException {
private static void loadStage(Globals globals, List<LuaString> initialPackages, List<Mod> loadOrder,
Box<Mod> currentMod, String filename) throws IOException {
for (Mod mod : loadOrder) {
resetPackagesLoaded(globals, initialPackages);
currentMod.set(mod);
Optional<InputStream> resource = mod.getResource(filename);
if (resource.isPresent()) {
Expand All @@ -435,6 +366,103 @@ public static IntUnaryOperator parseCountFormula(String countFormula) {
};
}

private static void resetPackagesLoaded(Globals globals, List<LuaString> initialPackages) {
List<LuaString> 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<Mod> loadOrder, Box<Mod> 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> 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();
Expand Down