From 10ac78200bf14cadc9cd7c5a529046b7c46f90e0 Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Tue, 11 Apr 2023 16:57:20 -0500 Subject: [PATCH] repl: add `gameVersionFolder` to repl-config for running the non-default version (#2463) Adds a decent way to customize the folders the project file expects the iso data and decompiler data to be in. When you run any version other than the default, for example Jak 1 PAL, it uses the `gameName` decompiler config to consume and output it's results. However the project file will assume `jak1` unless you hard-code it differently -- basically, it needs to be explicitly told just the decompiler is told what version to use. We now have a per-user REPL Config json file, so that can be used to override the default `jak1` behaviour. Fixes #1993 --- README.md | 4 ++-- common/repl/config.cpp | 4 ++++ common/repl/config.h | 1 + goal_src/jak1/game.gp | 21 +++++++++++++++------ goal_src/jak2/game.gp | 16 +++++++++++++--- goal_src/user/{readme.md => README.md} | 2 ++ goalc/compiler/Compiler.cpp | 3 ++- goalc/compiler/Compiler.h | 1 + goalc/main.cpp | 4 ++-- goalc/make/MakeSystem.cpp | 22 +++++++++++++++++++++- goalc/make/MakeSystem.h | 8 +++++++- goalc/simple_main.cpp | 6 +++--- 12 files changed, 73 insertions(+), 19 deletions(-) rename goal_src/user/{readme.md => README.md} (90%) diff --git a/README.md b/README.md index 2b6fd104f5..32b8c3ba0e 100644 --- a/README.md +++ b/README.md @@ -299,11 +299,11 @@ Run the following to build the game: g > (mi) ``` -> IMPORTANT NOTE! If you're not using the black label version, you may hit issues trying to run `(mi)` in this step. An example error might include something like: +> IMPORTANT NOTE! If you're not using the non-default version of the game, you may hit issues trying to run `(mi)` in this step. An example error might include something like: > > `Input file iso_data/jak1/MUS/TWEAKVAL.MUS does not exist.` > -> This is because other version paths are not currently accounted for in the build. A quick workaround is to rename both your `decompiler_out` and `iso_data` folders to use the black label naming, for example changing `decompiler_out/jak1_pal` to `decompiler_out/jak1` and `iso_data/jak1_pal` to `iso_data/jak1`, then running `(mi)` again. +> This is because the decompiler inputs/outputs using the `gameName` JSON field in the decompiler config. For example if you are using Jak 1 PAL, it will assume `iso_data/jak1_pal` and `decompiler_out/jak1_pal`. Therefore, you can inform the REPL/compiler of this via the `gameVersionFolder` config field described [here](./goal_src/user/README.md) #### Run the Game diff --git a/common/repl/config.cpp b/common/repl/config.cpp index ea106405e6..32c805a2f5 100644 --- a/common/repl/config.cpp +++ b/common/repl/config.cpp @@ -7,6 +7,7 @@ namespace REPL { void to_json(json& j, const Config& obj) { j = json{ + {"gameVersionFolder", obj.game_version_folder}, {"numConnectToTargetAttempts", obj.target_connect_attempts}, {"asmFileSearchDirs", obj.asm_file_search_dirs}, {"keybinds", obj.keybinds}, @@ -14,6 +15,9 @@ void to_json(json& j, const Config& obj) { } void from_json(const json& j, Config& obj) { + if (j.contains("gameVersionFolder")) { + j.at("gameVersionFolder").get_to(obj.game_version_folder); + } if (j.contains("numConnectToTargetAttempts")) { j.at("numConnectToTargetAttempts").get_to(obj.target_connect_attempts); } diff --git a/common/repl/config.h b/common/repl/config.h index c051ea5153..0da9563f52 100644 --- a/common/repl/config.h +++ b/common/repl/config.h @@ -31,6 +31,7 @@ struct Config { Config(GameVersion _game_version) : game_version(_game_version){}; // this is the default REPL configuration + std::string game_version_folder; int target_connect_attempts = 30; std::vector asm_file_search_dirs = {}; bool append_keybinds = true; diff --git a/goal_src/jak1/game.gp b/goal_src/jak1/game.gp index d548cf1b1b..23d060c2ed 100644 --- a/goal_src/jak1/game.gp +++ b/goal_src/jak1/game.gp @@ -39,13 +39,17 @@ (cond ;; extractor can override everything by providing *use-iso-data-path* (*use-iso-data-path* - (map-path! "$ISO" (string-append *iso-data* "/"))) + (map-path! "$ISO" (string-append *iso-data* "/"))) ;; user-specific places to put $ISO + ;; TODO - remove? ((user? dass) - (map-path! "$ISO" "iso_data/jak1_us2/")) - ;; for normal people, just use jak1. + (map-path! "$ISO" "iso_data/jak1_us2/")) + ;; if the user's repl-config has a game version folder, use that + ((> (string-length (get-game-version-folder)) 0) + (map-path! "$ISO" (string-append "iso_data/" (get-game-version-folder) "/"))) + ;; otherwise, default to jak1 (#t - (map-path! "$ISO" "iso_data/jak1/"))) + (map-path! "$ISO" "iso_data/jak1/"))) ;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Inputs from decompiler @@ -53,10 +57,15 @@ (cond ;; user-specific places to put $ISO + ;; TODO - remove? ((user? dass) - (map-path! "$DECOMP" "decompiler_out/jak1_us2/")) + (map-path! "$DECOMP" "decompiler_out/jak1_us2/")) + ;; if the user's repl-config has a game version folder, use that + ((> (string-length (get-game-version-folder)) 0) + (map-path! "$DECOMP" (string-append "decompiler_out/" (get-game-version-folder) "/"))) + ;; otherwise, default to jak1 (#t - (map-path! "$DECOMP" "decompiler_out/jak1/"))) + (map-path! "$DECOMP" "decompiler_out/jak1/"))) ;;;;;;;;;;;;;;;;;;;;;;; ;; Output diff --git a/goal_src/jak2/game.gp b/goal_src/jak2/game.gp index d8b9cff3ee..58011f2f0f 100644 --- a/goal_src/jak2/game.gp +++ b/goal_src/jak2/game.gp @@ -13,15 +13,25 @@ (cond ;; extractor can override everything by providing *use-iso-data-path* (*use-iso-data-path* - (map-path! "$ISO" (string-append *iso-data* "/"))) + (map-path! "$ISO" (string-append *iso-data* "/"))) + ;; if the user's repl-config has a game version folder, use that + ((> (string-length (get-game-version-folder)) 0) + (map-path! "$ISO" (string-append "iso_data/" (get-game-version-folder) "/"))) + ;; otherwise, default to jak2 (#t - (map-path! "$ISO" "iso_data/jak2/"))) + (map-path! "$ISO" "iso_data/jak2/"))) ;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Inputs from decompiler ;;;;;;;;;;;;;;;;;;;;;;;;;; -(map-path! "$DECOMP" "decompiler_out/jak2/") +(cond + ;; if the user's repl-config has a game version folder, use that + ((> (string-length (get-game-version-folder)) 0) + (map-path! "$DECOMP" (string-append "decompiler_out/" (get-game-version-folder) "/"))) + ;; otherwise, default to jak2 + (#t + (map-path! "$DECOMP" "decompiler_out/jak2/"))) ;;;;;;;;;;;;;;;;;;;;;;; ;; Output diff --git a/goal_src/user/readme.md b/goal_src/user/README.md similarity index 90% rename from goal_src/user/readme.md rename to goal_src/user/README.md index d4f5d66f53..c602277794 100644 --- a/goal_src/user/readme.md +++ b/goal_src/user/README.md @@ -20,11 +20,13 @@ Additionally, you can provide a `repl-config.json` to set various REPL settings, { "numConnectToTargetAttempts": 1, "jak1": { + "gameVersionFolder": "jak1_pal", // corresponds with your "gameName" in the decomp config, "jak1" by default "asmFileSearchDirs": [ "goal_src/jak1" ] }, "jak2": { + "gameVersionFolder": "jak2_pal", // corresponds with your "gameName" in the decomp config, "jak2" by default "asmFileSearchDirs": [ "goal_src/jak2" ] diff --git a/goalc/compiler/Compiler.cpp b/goalc/compiler/Compiler.cpp index 207d7946b2..c7d1b6b4cc 100644 --- a/goalc/compiler/Compiler.cpp +++ b/goalc/compiler/Compiler.cpp @@ -19,13 +19,14 @@ using namespace goos; Compiler::Compiler(GameVersion version, + const std::optional repl_config, const std::string& user_profile, std::unique_ptr repl) : m_version(version), m_goos(user_profile), m_debugger(&m_listener, &m_goos.reader, version), m_repl(std::move(repl)), - m_make(user_profile) { + m_make(repl_config, user_profile) { m_listener.add_debugger(&m_debugger); m_listener.set_default_port(version); m_ts.add_builtin_types(m_version); diff --git a/goalc/compiler/Compiler.h b/goalc/compiler/Compiler.h index a7a53e1945..104e0231f9 100644 --- a/goalc/compiler/Compiler.h +++ b/goalc/compiler/Compiler.h @@ -40,6 +40,7 @@ struct CompilationOptions { class Compiler { public: Compiler(GameVersion version, + const std::optional repl_config = {}, const std::string& user_profile = "#f", std::unique_ptr repl = nullptr); ~Compiler(); diff --git a/goalc/main.cpp b/goalc/main.cpp index ac5695d11e..52466ce0c0 100644 --- a/goalc/main.cpp +++ b/goalc/main.cpp @@ -115,7 +115,7 @@ int main(int argc, char** argv) { // the compiler may throw an exception if it fails to load its standard library. try { compiler = std::make_unique( - game_version, username, + game_version, std::make_optional(repl_config), username, std::make_unique(username, repl_config, startup_file)); // Start nREPL Server if it spun up successfully if (repl_server_ok) { @@ -143,7 +143,7 @@ int main(int argc, char** argv) { compiler->save_repl_history(); } compiler = std::make_unique( - game_version, username, + game_version, std::make_optional(repl_config), username, std::make_unique(username, repl_config, startup_file)); status = ReplStatus::OK; } diff --git a/goalc/make/MakeSystem.cpp b/goalc/make/MakeSystem.cpp index dba65adea4..5bb825494c 100644 --- a/goalc/make/MakeSystem.cpp +++ b/goalc/make/MakeSystem.cpp @@ -38,7 +38,8 @@ std::string MakeStep::print() const { return result; } -MakeSystem::MakeSystem(const std::string& username) : m_goos(username) { +MakeSystem::MakeSystem(const std::optional repl_config, const std::string& username) + : m_goos(username), m_repl_config(repl_config) { m_goos.register_form("defstep", [=](const goos::Object& obj, goos::Arguments& args, const std::shared_ptr& env) { return handle_defstep(obj, args, env); @@ -81,6 +82,12 @@ MakeSystem::MakeSystem(const std::string& username) : m_goos(username) { return handle_get_gsrc_folder(obj, args, env); }); + m_goos.register_form("get-game-version-folder", + [=](const goos::Object& obj, goos::Arguments& args, + const std::shared_ptr& env) { + return handle_get_game_version_folder(obj, args, env); + }); + m_goos.set_global_variable_to_symbol("ASSETS", "#t"); set_constant("*iso-data*", file_util::get_file_path({"iso_data"})); @@ -296,6 +303,19 @@ goos::Object MakeSystem::handle_get_gsrc_folder( return goos::StringObject::make_new(out); } +goos::Object MakeSystem::handle_get_game_version_folder( + const goos::Object& form, + goos::Arguments& args, + const std::shared_ptr& env) { + m_goos.eval_args(&args, env); + va_check(form, args, {}, {}); + if (m_repl_config) { + return goos::StringObject::make_new(m_repl_config->game_version_folder); + } else { + return goos::StringObject::make_new(""); + } +} + void MakeSystem::get_dependencies(const std::string& master_target, const std::string& output, std::vector* result, diff --git a/goalc/make/MakeSystem.h b/goalc/make/MakeSystem.h index 1b36d413ed..b7c75b8252 100644 --- a/goalc/make/MakeSystem.h +++ b/goalc/make/MakeSystem.h @@ -15,7 +15,7 @@ struct MakeStep { class MakeSystem { public: - MakeSystem(const std::string& username = "#f"); + MakeSystem(const std::optional repl_config, const std::string& username = "#f"); void load_project_file(const std::string& file_path); goos::Object handle_defstep(const goos::Object& obj, @@ -50,6 +50,10 @@ class MakeSystem { goos::Arguments& args, const std::shared_ptr& env); + goos::Object handle_get_game_version_folder(const goos::Object& obj, + goos::Arguments&, + const std::shared_ptr& env); + std::vector get_dependencies(const std::string& target) const; std::vector filter_dependencies(const std::vector& all_deps); @@ -85,6 +89,8 @@ class MakeSystem { goos::Interpreter m_goos; + std::optional m_repl_config; + std::unordered_map> m_output_to_step; std::unordered_map> m_tools; PathMap m_path_map; diff --git a/goalc/simple_main.cpp b/goalc/simple_main.cpp index b582fba8ff..ee48b73bd4 100644 --- a/goalc/simple_main.cpp +++ b/goalc/simple_main.cpp @@ -27,15 +27,15 @@ int main(int argc, char** argv) { std::unique_ptr compiler; ReplStatus status = ReplStatus::OK; try { - compiler = - std::make_unique(game_version, "", std::make_unique(game_version)); + compiler = std::make_unique(game_version, std::nullopt, "", + std::make_unique(game_version)); while (status != ReplStatus::WANT_EXIT) { if (status == ReplStatus::WANT_RELOAD) { lg::info("Reloading compiler..."); if (compiler) { compiler->save_repl_history(); } - compiler = std::make_unique(game_version, "", + compiler = std::make_unique(game_version, std::nullopt, "", std::make_unique(game_version)); status = ReplStatus::OK; }