-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move IO-related operations to a helper .dll #164
Conversation
The following (3) hard crashes the game instead of throwing an error:
dir = Directory("randomGibberish")
dir:directories()
dir = Directory("randomGibberish")
dir:files()
dir = Directory("randomGibberish")
dir:parent():parent()
dir = Directory("mods")
LOG(save_table(dir:directories())) Moving a file does not update the File instance to the new path. Not sure if intentional or not. file = File(GetSavedataLocation().."blah.txt")
file:write_string("blah")
file:move(GetSavedataLocation().."blahMoved.txt")
LOG(file:path()) -- returns "blah.txt" |
This way we can pass wrapper tables directory into save_table, and it will still work correctly
Fixed the hard crashes and tweaked the file = File("blah.txt")
file:write_string("blah")
file2 = file:move("blah_moved.txt")
LOG(file:path()) -- old path
LOG(file2:path()) -- new path
For the This might have unintended consequences if some code relies on this behavior, but I think it's the correct way of handling this case, since as far as I'm aware, tbl = { 1, 2, 3 }
serialized = save_table(tbl)
result = loadstring(serialized)()
-- Edit: maybe not quite loadstring, but the game uses something like this to load save data files,
-- which are serialzied lua tables without this change, Directories and Files would be saved as regular tables with a single |
All my previous points seems to have been addressed, and works well now. While testing it with Easy Edit, I came over a few other minor "issues", or maybe just nitpicks.
File(Directory.savedata():path().."blah.txt")
File(Directory.savedata():path().."/blah.txt")
Directory(Directory.savedata():path().."/profile_alpha") Could the static function Directory.savedata("profile_alpha") Similarly, accessing files in savedata is equally verbose. Not sure if you would agree to add a static File.savedata("profile_alpha/modcontent.lua") |
local myFile = Directory.savedata():file("blah.txt")
local myProfile = Directory.savedata():directory("my_profile") I think I'd rather keep paths without trailing slashes to discourage manual concatenation of strings. |
I wasn't aware that writing a file would create directories for the full path for you actually, so maybe it wasn't strictly needed. I still think the ability to create empty folders can be useful though, so thanks for this addition.
I must have completely missed those two methods: From your examples, I suppose getting a file under savedata will look something like this: local myFile = Directory.savedata():file("my_profile/modcontent.lua") I do find this to look rather neat. There is no use of I will test how using those functions will change things in practice. |
I've now rewritten Easy Edit, exclusively using functions from this PR for io operation. Everything seems to be working well. I still believe output from One thing that came up was how some of the mod loader's functions take arguments that are paths relative to the save game. I am finished testing this branch, and think it can be merged. |
Also rework it to use a buffer instead of writing directly to the file
- File and Directory report paths using slashes instead of backslashes - Directory reports its path with a trailing slash
I ended up adding the trailing slash for directories - I still feel kinda iffy about it, since there isn't really any standard like that, and most languages/frameworks I'm familiar with don't do that, but I guess it makes sense in the context of Lua, and is convenient. It doesn't seem to break anything on the Rust side, just gets pruned. Also fixed I also changed |
- Add vararg support to Directory:file() and Directory:directory()
Instances where os is used in the mod loader instead of itb_io.dll
Instances where io is used in the mod loader instead of itb_io.dll
|
Removed all mentioned usages of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 6980810
scripts/mod_loader/mod_loader.lua
Outdated
|
||
for _, dir in ipairs(dirs) do | ||
dir = dir:name() | ||
local modDirPath = inputDir:name().."/"..dir.."/" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When enumerating submods, inputDir:name()
is incorrectly just mods
, which makes loading of submods fail.
In some places in the code base we need to access the file system, for example to read a file, check if a file exists, or walk a directory. Lua is not a particularly good fit for this, and in some cases where we need speed, we ended up resorting to running native system commands via
os.execute
.This has some issues, most notably security concerns that - thankfully - we have thus far avoided. Another is that when running native system commands, a command terminal windows briefly pops up, which is not only distracting, but might cause some people to think something went wrong.
This PR addresses the latter concern, and attempts to partially address the former, via a helper
itb_io.dll
(source code: https://github.com/kartoFlane/itb-io-rs). This library providesFile
andDirectory
abstractions, which expose several helper functions for file system navigation, reading, and writing. I've replaced almost all instances where we needed to access the file system in the mod loader with these functions. If we need additional functionality in the future, it should be simple to add.For security, the library throws an error whenever Lua code attempts to navigate away from the game's root directory, the game's save data directory, or any of their children. This security measure is based on abstract paths that are not validated against the filesystem unless strictly necessary, so it is possible to "break out" in a limited fashion, if a directory happens to be a symlink, but this issue should have a limited impact, as realistically it only affects power users. The library gives Lua full reign over anything inside of those directories.
Basically:
Available methods:
File new(string)
- creates a new File instancelocal f = File("resources/resource.dat")
string path()
- returns the File's full pathstring name()
- returns the file's name, including extensionstring name_without_extension()
- returns the file's name, without extensionstring extension()
- returns the file's extension, ornil
if it doesn't have anyDirectory parent()
- returns a Directory instance of the file's parent directorystring read_to_string()
- contents of the file as stringtable read_to_byte_array()
- contents of the file as byte arrayvoid write_string(string)
- replaces the file's content with the specified string contentvoid append(string)
- appends the specified string at the end of the filevoid write_byte_array(table)
- replaces the file's content with the specified byte array contentvoid copy(string)
- copies this file to the specified destination path, overwrites anything at destination. Returns a new File instance for the destination pathvoid move(string)
- moves this file to the specified destination. Returns a new File instance for the destination pathvoid make_directories()
- creates missing directories in this File's abstract pathboolean exists()
- returns true if the file exists, false otherwisevoid delete()
- deletes the fileDirectory new(string)
- creates a new Directory instancelocal d = Directory("resources")
Directory savedata()
- returns a Directory instance for the save data directorystring path()
- returns the Directory's full pathstring name()
- returns the Directory's nameDirectory parent()
- returns a Directory instance of the directory's parent directoryFile file(paths...)
- returns a File instance for the specified path under this directoryDirectory directory(paths...)
- returns a Directory instance for the specified path under this directorytable files()
- returns a list table of Files within this directorytable directories()
- returns a list table of Directories within this directoryvoid make_directories()
- creates missing directories in this Directory's abstract pathboolean exists()
- returns true if the directory exists, false otherwisevoid delete()
- deletes the directory and all its contents