[jak2] support for multiple out/ directories (#1585)

* [jak2] support for multiple out/ directories

* windows
This commit is contained in:
water111 2022-06-30 21:11:58 -04:00 committed by GitHub
parent 728d234976
commit f763eb6bf0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 207 additions and 141 deletions

View File

@ -34,7 +34,10 @@ void ReplWrapper::print_welcome_message() {
fmt::print(" for help with common commands and REPL usage.\n");
fmt::print("Run ");
fmt::print(fmt::emphasis::bold | fg(fmt::color::cyan), "(lt)");
fmt::print(" to connect to the local target.\n\n");
fmt::print(" to connect to the local target.\n");
fmt::print("Run ");
fmt::print(fmt::emphasis::bold | fg(fmt::color::cyan), "(mi)");
fmt::print(" to rebuild the entire game.\n\n");
}
void ReplWrapper::print_to_repl(const std::string_view& str) {
@ -55,7 +58,8 @@ void ReplWrapper::add_to_history(const std::string& line) {
void ReplWrapper::save_history() {
std::filesystem::path path = file_util::get_user_config_dir();
if (file_util::create_dir_if_needed(path)) {
file_util::create_dir_if_needed(path);
if (exists(path)) {
repl.history_save((path / ".opengoal.repl.history").string());
} else {
fmt::print("Couldn't save REPL history file to '{}'", path.string());
@ -95,7 +99,7 @@ void ReplWrapper::print_help_message() {
fmt::print(fmt::emphasis::bold | fg(fmt::color::cyan), "(:clear)\n");
fmt::print(" - Clear the current screen\n");
fmt::print(fmt::emphasis::bold | fg(fmt::color::cyan), "(e)\n");
fmt::print(" - Exit the compiler once the current REPL command is finished\n");
fmt::print(" - Exit the compiler\n");
fmt::print(fmt::emphasis::bold | fg(fmt::color::cyan), "(lt [ip-address] [port-number])\n");
fmt::print(
" - Connect the listener to a running target. The IP address defaults to `127.0.0.1` and the "
@ -110,34 +114,24 @@ void ReplWrapper::print_help_message() {
fmt::print(" - If the target is connected, make it exit\n");
fmt::print(fmt::emphasis::bold, "\nCompiling & Building:\n");
fmt::print(fmt::emphasis::bold | fg(fmt::color::lime_green), "(mi)\n");
fmt::print(" - Build entire game\n");
fmt::print(fmt::emphasis::bold | fg(fmt::color::lime_green), "(mng)\n");
fmt::print(" - Build game engine\n");
fmt::print(fmt::emphasis::bold | fg(fmt::color::lime_green), "(m \"filename\")\n");
fmt::print(" - Compile an OpenGOAL source file\n");
fmt::print(fmt::emphasis::bold | fg(fmt::color::lime_green), "(ml \"filename\")\n");
fmt::print(" - Compile and Load an OpenGOAL source file\n");
fmt::print(fmt::emphasis::bold | fg(fmt::color::lime_green), "(build-game)\n");
fmt::print(" - Loads and builds all game files and rebuilds DGOs\n");
fmt::print(" - Compile and Load (or reload) an OpenGOAL source file\n");
fmt::print(fmt::emphasis::bold | fg(fmt::color::lime_green), "(build-kernel)\n");
fmt::print(" - Similar to (build-game) but only the kernel files\n");
fmt::print(fmt::emphasis::bold | fg(fmt::color::lime_green), "(blg)\n");
fmt::print(" - Performs a (build-game) and then loads all CGOs\n");
fmt::print(fmt::emphasis::bold | fg(fmt::color::lime_green),
"(build-dgos \"path/to/dgos/description/file\")\n");
fmt::print(" - Build the GOAL kernel\n");
fmt::print(fmt::emphasis::bold | fg(fmt::color::lime_green), "(make \"file-name\")\n");
fmt::print(
" - Builds all the DGO files described in the DGO description file. See "
"`goal_src/builds/dgos.txt` for an example.\n");
fmt::print(fmt::emphasis::bold | fg(fmt::color::lime_green),
"(asm-data-file tool-name \"file-name\")\n");
fmt::print(
" - Build a data file. The `tool-name` refers to which data building tool should be used.\n");
fmt::print(fmt::emphasis::bold | fg(fmt::color::lime_green), "(build-data)\n");
fmt::print(" - Macro for rebuilding all data files\n");
" - Build a file and any out-of-date dependencies. This file must be a target in the make "
"system.\n");
fmt::print(fmt::emphasis::bold, "\nOther:\n");
fmt::print(fmt::emphasis::bold | fg(fmt::color::magenta), "(gs)\n");
fmt::print(" - Enter a GOOS REPL\n");
fmt::print(fmt::emphasis::bold | fg(fmt::color::magenta),
"(set-config! config-name config-value)\n");
fmt::print(" - Used to set compiler configuration\n");
}
void ReplWrapper::init_default_settings() {

View File

@ -8,16 +8,15 @@
#include "BinaryWriter.h"
#include "FileUtil.h"
void build_dgo(const DgoDescription& description) {
void build_dgo(const DgoDescription& description, const std::string& output_prefix) {
BinaryWriter writer;
// dgo header
writer.add<uint32_t>(description.entries.size());
writer.add_cstr_len(description.dgo_name.c_str(), 60);
for (auto& obj : description.entries) {
// todo: hardcoded out
auto obj_data =
file_util::read_binary_file(file_util::get_file_path({"out", "obj", obj.file_name}));
auto obj_data = file_util::read_binary_file(file_util::get_jak_project_dir() / "out" /
output_prefix / "obj" / obj.file_name);
// size
writer.add<uint32_t>(obj_data.size());
// name
@ -30,6 +29,6 @@ void build_dgo(const DgoDescription& description) {
}
}
file_util::create_dir_if_needed(file_util::get_file_path({"out", "iso"}));
writer.write_to_file(file_util::get_file_path({"out", "iso", description.dgo_name}));
writer.write_to_file(file_util::get_jak_project_dir() / "out" / output_prefix / "iso" /
description.dgo_name);
}

View File

@ -5,6 +5,7 @@
* Create a DGO from existing files.
*/
#include <filesystem>
#include <string>
#include <vector>
@ -17,4 +18,4 @@ struct DgoDescription {
std::vector<DgoEntry> entries;
};
void build_dgo(const DgoDescription& description);
void build_dgo(const DgoDescription& description, const std::string& output_prefix);

View File

@ -192,7 +192,11 @@ bool create_dir_if_needed(const std::filesystem::path& path) {
}
bool create_dir_if_needed_for_file(const std::string& path) {
return std::filesystem::create_directories(std::filesystem::path(path).parent_path());
return create_dir_if_needed_for_file(std::filesystem::path(path));
}
bool create_dir_if_needed_for_file(const std::filesystem::path& path) {
return std::filesystem::create_directories(path.parent_path());
}
void write_binary_file(const std::filesystem::path& name, const void* data, size_t size) {

View File

@ -23,6 +23,7 @@ std::filesystem::path get_jak_project_dir();
bool create_dir_if_needed(const std::filesystem::path& path);
bool create_dir_if_needed_for_file(const std::string& path);
bool create_dir_if_needed_for_file(const std::filesystem::path& path);
bool setup_project_path(std::optional<std::filesystem::path> project_path_override);
std::string get_file_path(const std::vector<std::string>& path);
void write_binary_file(const std::string& name, const void* data, size_t size);

View File

@ -46,4 +46,6 @@ struct PerGameVersion {
constexpr PerGameVersion(T jak1, T jak2) : data{jak1, jak2} {}
constexpr T operator[](GameVersion v) const { return data[(int)v - 1]; }
T data[2];
};
};
constexpr PerGameVersion<const char*> game_version_names = {"jak1", "jak2"};

View File

@ -105,10 +105,10 @@
////////////////////////////
// PATCHING OPTIONS
////////////////////////////
// these are options related to xdelta3 patches on specific objects
// this allows us to get a more consistent input
// this allows us to get a more consistent input
// set to true to write new patch files
"write_patches": false,
// set to true to apply patch files

View File

@ -109,10 +109,10 @@
////////////////////////////
// PATCHING OPTIONS
////////////////////////////
// these are options related to xdelta3 patches on specific objects
// this allows us to get a more consistent input
// this allows us to get a more consistent input
// set to true to write new patch files
"write_patches": false,
// set to true to apply patch files

View File

@ -436,8 +436,8 @@ void decompile(std::filesystem::path jak1_input_files) {
// levels
{
// TODO separate out dirs
auto level_out_path = file_util::get_jak_project_dir() / "out" / "fr3";
auto level_out_path =
file_util::get_jak_project_dir() / "out" / game_version_names[config.game_version] / "fr3";
file_util::create_dir_if_needed(level_out_path);
extract_all_levels(db, tex_db, config.levels_to_extract, "GAME.CGO", config.hacks,
config.rip_levels, config.extract_collision, level_out_path);

View File

@ -232,8 +232,8 @@ int main(int argc, char** argv) {
}
if (config.levels_extract) {
// TODO separate out dirs
auto level_out_path = file_util::get_jak_project_dir() / "out" / "fr3";
auto level_out_path =
file_util::get_jak_project_dir() / "out" / game_version_names[config.game_version] / "fr3";
file_util::create_dir_if_needed(level_out_path);
extract_all_levels(db, tex_db, config.levels_to_extract, "GAME.CGO", config.hacks,
config.rip_levels, config.extract_collision, level_out_path);

View File

@ -82,13 +82,18 @@ std::shared_ptr<GfxDisplay> GetMainDisplay() {
return g_displays.front()->is_active() ? g_displays.front() : NULL;
}
int InitMainDisplay(int width, int height, const char* title, GfxSettings& settings) {
int InitMainDisplay(int width,
int height,
const char* title,
GfxSettings& settings,
GameVersion version) {
if (GetMainDisplay() != NULL) {
lg::warn("InitMainDisplay called when main display already exists.");
return 1;
}
auto display = Gfx::GetCurrentRenderer()->make_display(width, height, title, settings, true);
auto display =
Gfx::GetCurrentRenderer()->make_display(width, height, title, settings, version, true);
if (display == NULL) {
lg::error("Failed to make main display.");
return 1;

View File

@ -87,7 +87,11 @@ namespace Display {
// views.
extern std::vector<std::shared_ptr<GfxDisplay>> g_displays;
int InitMainDisplay(int width, int height, const char* title, GfxSettings& settings);
int InitMainDisplay(int width,
int height,
const char* title,
GfxSettings& settings,
GameVersion version);
void KillDisplay(std::shared_ptr<GfxDisplay> display);
void KillMainDisplay();

View File

@ -106,7 +106,7 @@ const GfxRendererModule* GetCurrentRenderer() {
return g_global_settings.renderer;
}
u32 Init() {
u32 Init(GameVersion version) {
lg::info("GFX Init");
// initialize settings
InitSettings(g_settings);
@ -124,8 +124,9 @@ u32 Init() {
if (g_main_thread_id != std::this_thread::get_id()) {
lg::error("Ran Gfx::Init outside main thread. Init display elsewhere?");
} else {
Display::InitMainDisplay(
640, 480, fmt::format("OpenGOAL - Work in Progress - {}", GIT_VERSION).c_str(), g_settings);
Display::InitMainDisplay(640, 480,
fmt::format("OpenGOAL - Work in Progress - {}", GIT_VERSION).c_str(),
g_settings, version);
}
return 0;

View File

@ -10,6 +10,7 @@
#include <memory>
#include "common/common_types.h"
#include "common/versions.h"
#include "game/kernel/common/kboot.h"
#include "game/system/newpad.h"
@ -25,8 +26,12 @@ enum GfxDisplayMode { Windowed = 0, Fullscreen = 1, Borderless = 2 };
// module for the different rendering pipelines
struct GfxRendererModule {
std::function<int(GfxSettings&)> init;
std::function<std::shared_ptr<
GfxDisplay>(int width, int height, const char* title, GfxSettings& settings, bool is_main)>
std::function<std::shared_ptr<GfxDisplay>(int width,
int height,
const char* title,
GfxSettings& settings,
GameVersion version,
bool is_main)>
make_display;
std::function<void()> exit;
std::function<u32()> vsync;
@ -108,7 +113,7 @@ extern GfxSettings g_settings;
const GfxRendererModule* GetCurrentRenderer();
u32 Init();
u32 Init(GameVersion version);
void Loop(std::function<bool()> f);
u32 Exit();

View File

@ -64,13 +64,15 @@ struct GraphicsData {
float pmode_alp = 0.f;
std::string imgui_log_filename, imgui_filename;
GameVersion version;
GraphicsData()
GraphicsData(GameVersion version)
: dma_copier(EE_MAIN_MEM_SIZE),
texture_pool(std::make_shared<TexturePool>()),
// TODO out dir
loader(std::make_shared<Loader>(file_util::get_jak_project_dir() / "out" / "fr3")),
ogl_renderer(texture_pool, loader) {}
loader(std::make_shared<Loader>(file_util::get_jak_project_dir() / "out" /
game_version_names[version] / "fr3")),
ogl_renderer(texture_pool, loader),
version(version) {}
};
std::unique_ptr<GraphicsData> g_gfx_data;
@ -154,6 +156,7 @@ static std::shared_ptr<GfxDisplay> gl_make_display(int width,
int height,
const char* title,
GfxSettings& settings,
GameVersion game_version,
bool is_main) {
GLFWwindow* window = glfwCreateWindow(width, height, title, NULL, NULL);
@ -169,7 +172,7 @@ static std::shared_ptr<GfxDisplay> gl_make_display(int width,
lg::error("GL init fail");
return NULL;
}
g_gfx_data = std::make_unique<GraphicsData>();
g_gfx_data = std::make_unique<GraphicsData>(game_version);
gl_inited = true;
}

View File

@ -24,6 +24,7 @@
#include "game/overlord/sbank.h"
#include "game/overlord/soundcommon.h"
#include "game/overlord/srpc.h"
#include "game/runtime.h"
#include "game/sce/iop.h"
#include "game/sound/sndshim.h"
@ -89,14 +90,16 @@ void fake_iso_init_globals() {
int FS_Init(u8* buffer) {
(void)buffer;
for (const auto& f : std::filesystem::directory_iterator(file_util::get_file_path({"out/iso"}))) {
for (const auto& f : std::filesystem::directory_iterator(
file_util::get_jak_project_dir() / "out" / game_version_names[g_game_version] / "iso")) {
if (f.is_regular_file()) {
ASSERT(fake_iso_entry_count < MAX_ISO_FILES);
FakeIsoEntry* e = &fake_iso_entries[fake_iso_entry_count];
std::string file_name = f.path().filename().string();
ASSERT(file_name.length() < 16); // should be 8.3.
strcpy(e->iso_name, file_name.c_str());
strcpy(e->file_path, fmt::format("out/iso/{}", file_name).c_str());
strcpy(e->file_path,
fmt::format("out/{}/iso/{}", game_version_names[g_game_version], file_name).c_str());
fake_iso_entry_count++;
}
}

View File

@ -305,6 +305,7 @@ RuntimeExitStatus exec_runtime(int argc, char** argv) {
g_main_thread_id = std::this_thread::get_id();
// parse opengoal arguments
g_game_version = GameVersion::Jak1;
bool enable_display = true;
for (int i = 1; i < argc; i++) {
if (std::string("-nodisplay") == argv[i]) { // disable video display
@ -321,7 +322,7 @@ RuntimeExitStatus exec_runtime(int argc, char** argv) {
// initialize graphics first - the EE code will upload textures during boot and we
// want the graphics system to catch them.
if (enable_display) {
Gfx::Init();
Gfx::Init(g_game_version);
}
// step 1: sce library prep

View File

@ -878,7 +878,7 @@
(defmacro makeo (object-name &rest flags)
"Make the given object. Can use a string, or not."
`(make ,(string-append
"out/obj/"
"$OUT/"
(if (string? object-name) object-name (symbol->string object-name))
".o"
)
@ -886,11 +886,11 @@
)
(defmacro make-cgo (file)
`(make ,(string-append "out/iso/" file ".CGO"))
`(make ,(string-append "$OUT/iso/" file ".CGO"))
)
(defmacro make-dgo (file)
`(make ,(string-append "out/iso/" file ".DGO"))
`(make ,(string-append "$OUT/iso/" file ".DGO"))
)
(defmacro make-group (name &key (verbose #f) &key (force #f))
@ -1053,5 +1053,5 @@
(defmacro __get_jak1_full_game () *jak1-full-game*)
(defconstant *jak1-full-game* (__get_jak1_full_game))
;; load the default project
;; todo: loading jak1 by default
(load-project "goal_src/jak1/game.gp")

View File

@ -62,9 +62,11 @@
;; Output
;;;;;;;;;;;;;;;;;;;;;;;
;; NOTE: this isn't perfect yet, some tools still are hardcoded to look in out/ for stuff.
(map-path! "$OUT" "out/")
;; NOTE: the game itself will load from out/jak1/iso and out/jak1/fr3.
(map-path! "$OUT" "out/jak1/")
;; tell the compiler to put its outputs in out/jak1/
(set-output-prefix "jak1/")
;; use defmacro to define goos macros.
(define defmacro defsmacro)
@ -142,7 +144,7 @@
)
(defun custom-level-cgo (output-name desc-file-name)
"Add a CGO with the given output name (in out/iso) and input name (in custom_levels/)"
"Add a CGO with the given output name (in $OUT/iso) and input name (in custom_levels/)"
(let ((out-name (string-append "$OUT/iso/" output-name)))
(defstep :in (string-append "custom_levels/" desc-file-name)
:tool 'dgo
@ -153,7 +155,7 @@
)
(defun cgo (output-name desc-file-name)
"Add a CGO with the given output name (in out/iso) and input name (in goal_src/jak1/dgos)"
"Add a CGO with the given output name (in $OUT/iso) and input name (in goal_src/jak1/dgos)"
(let ((out-name (string-append "$OUT/iso/" output-name)))
(defstep :in (string-append "goal_src/jak1/dgos/" desc-file-name)
:tool 'dgo
@ -1420,7 +1422,7 @@
(goal-src-sequence
"levels/citadel/"
:deps ("$OUT/obj/battlecontroller.o" "out/obj/snow-bunny.o")
:deps ("$OUT/obj/battlecontroller.o" "$OUT/obj/snow-bunny.o")
"citadel-part.gc"
"citadel-obs.gc"

View File

@ -16,7 +16,7 @@
void save_pc_data(const std::string& nickname,
tfrag3::Level& data,
const std::filesystem::path& output_dir) {
const std::filesystem::path& fr3_output_dir) {
Serializer ser;
data.serialize(ser);
auto compressed =
@ -25,7 +25,7 @@ void save_pc_data(const std::string& nickname,
print_memory_usage(data, ser.get_save_result().second);
fmt::print("compressed: {} -> {} ({:.2f}%)\n", ser.get_save_result().second, compressed.size(),
100.f * compressed.size() / ser.get_save_result().second);
file_util::write_binary_file(output_dir / fmt::format("{}.fr3", nickname), compressed.data(),
file_util::write_binary_file(fr3_output_dir / fmt::format("{}.fr3", nickname), compressed.data(),
compressed.size());
}
@ -35,7 +35,9 @@ std::vector<std::string> get_build_level_deps(const std::string& input_file) {
return {level_json.at("gltf_file").get<std::string>()};
}
bool run_build_level(const std::string& input_file, const std::string& output_file) {
bool run_build_level(const std::string& input_file,
const std::string& bsp_output_file,
const std::string& output_prefix) {
auto level_json = parse_commented_json(
file_util::read_text_file(file_util::get_file_path({input_file})), input_file);
LevelFile file; // GOAL level file
@ -102,14 +104,14 @@ bool run_build_level(const std::string& input_file, const std::string& output_fi
// Save the GOAL level
auto result = file.save_object_file();
fmt::print("Level bsp file size {} bytes\n", result.size());
auto save_path = file_util::get_file_path({output_file});
auto save_path = file_util::get_jak_project_dir() / bsp_output_file;
file_util::create_dir_if_needed_for_file(save_path);
fmt::print("Saving to {}\n", save_path);
fmt::print("Saving to {}\n", save_path.string());
file_util::write_binary_file(save_path, result.data(), result.size());
// Save the PC level
// TODO out dir
save_pc_data(file.nickname, pc_level, file_util::get_jak_project_dir() / "out" / "fr3");
save_pc_data(file.nickname, pc_level,
file_util::get_jak_project_dir() / "out" / output_prefix / "fr3");
return true;
}

View File

@ -1,7 +1,10 @@
#pragma once
#include <filesystem>
#include <string>
#include <vector>
bool run_build_level(const std::string& input_file, const std::string& output_file);
bool run_build_level(const std::string& input_file,
const std::string& bsp_output_file,
const std::string& output_prefix);
std::vector<std::string> get_build_level_deps(const std::string& input_file);

View File

@ -422,7 +422,8 @@ void Compiler::asm_file(const CompilationOptions& options) {
// save file
if (options.write) {
auto path = file_util::get_file_path({"out", "obj", obj_file_name + ".o"});
auto path = file_util::get_jak_project_dir() / "out" / m_make.compiler_output_prefix() /
"obj" / (obj_file_name + ".o");
file_util::create_dir_if_needed_for_file(path);
file_util::write_binary_file(path, (void*)data.data(), data.size());
}

View File

@ -9,8 +9,6 @@ CompilerSettings::CompilerSettings() {
m_settings["disable-math-const-prop"].kind = SettingKind::BOOL;
m_settings["disable-math-const-prop"].boolp = &disable_math_const_prop;
link(print_timing, "print-timing");
}
void CompilerSettings::set(const std::string& name, const goos::Object& value) {

View File

@ -1,8 +1,5 @@
#pragma once
#ifndef JAK_COMPILERSETTINGS_H
#define JAK_COMPILERSETTINGS_H
#include <string>
#include <unordered_map>
@ -15,13 +12,13 @@ class CompilerSettings {
bool debug_print_regalloc = false;
bool disable_math_const_prop = false;
bool emit_move_after_return = true;
bool print_timing = false;
void set(const std::string& name, const goos::Object& value);
private:
void link(bool& val, const std::string& name);
enum class SettingKind { BOOL, INVALID };
enum class SettingKind { BOOL, STRING, INVALID };
struct SettingsEntry {
SettingKind kind = SettingKind::INVALID;
@ -31,5 +28,3 @@ class CompilerSettings {
std::unordered_map<std::string, SettingsEntry> m_settings;
};
#endif // JAK_COMPILERSETTINGS_H

View File

@ -67,9 +67,9 @@ Val* Compiler::compile_asm_data_file(const goos::Object& form, const goos::Objec
va_check(form, args, {goos::ObjectType::SYMBOL, goos::ObjectType::STRING}, {});
auto kind = symbol_string(args.unnamed.at(0));
if (kind == "game-count") {
compile_game_count(as_string(args.unnamed.at(1)));
compile_game_count(as_string(args.unnamed.at(1)), m_make.compiler_output_prefix());
} else if (kind == "dir-tpages") {
compile_dir_tpages(as_string(args.unnamed.at(1)));
compile_dir_tpages(as_string(args.unnamed.at(1)), m_make.compiler_output_prefix());
} else {
throw_compiler_error(form, "The option {} was not recognized for asm-data-file.", kind);
}
@ -102,10 +102,10 @@ Val* Compiler::compile_asm_text_file(const goos::Object& form, const goos::Objec
// compile files.
if (kind == "subtitle") {
GameSubtitleDB db;
compile_game_subtitle(inputs, db);
compile_game_subtitle(inputs, db, m_make.compiler_output_prefix());
} else if (kind == "text") {
GameTextDB db;
compile_game_text(inputs, db);
compile_game_text(inputs, db, m_make.compiler_output_prefix());
} else {
throw_compiler_error(form, "The option {} was not recognized for asm-text-file.", kind);
}
@ -306,13 +306,14 @@ Val* Compiler::compile_build_dgo(const goos::Object& form, const goos::Object& r
desc.entries.push_back(o);
} else {
// allow data objects to be missing.
if (std::filesystem::exists(file_util::get_file_path({"out", "obj", o.file_name}))) {
if (std::filesystem::exists(file_util::get_file_path(
{"out", m_make.compiler_output_prefix(), "obj", o.file_name}))) {
desc.entries.push_back(o);
}
}
});
build_dgo(desc);
build_dgo(desc, m_make.compiler_output_prefix());
});
return get_none();

View File

@ -6,11 +6,11 @@
#include "common/goos/Reader.h"
#include "common/util/FileUtil.h"
void compile_dir_tpages(const std::string& filename) {
void compile_dir_tpages(const std::string& input_file, const std::string& output_prefix) {
std::vector<int> lengths;
goos::Reader reader;
auto code = reader.read_from_file({filename});
auto code = reader.read_from_file({input_file});
std::string err;
goos::for_each_in_list(code.as_pair()->cdr, [&](const goos::Object& obj) {
@ -30,7 +30,7 @@ void compile_dir_tpages(const std::string& filename) {
}
auto data = gen.generate_v4();
file_util::create_dir_if_needed(file_util::get_file_path({"out", "obj"}));
file_util::write_binary_file(file_util::get_file_path({"out", "obj", "dir-tpages.go"}),
data.data(), data.size());
file_util::write_binary_file(
file_util::get_jak_project_dir() / "out" / output_prefix / "obj" / "dir-tpages.go",
data.data(), data.size());
}

View File

@ -2,4 +2,4 @@
#include <string>
void compile_dir_tpages(const std::string& filename);
void compile_dir_tpages(const std::string& input_file, const std::string& output_prefix);

View File

@ -8,7 +8,7 @@
#include "common/goos/Reader.h"
#include "common/util/FileUtil.h"
void compile_game_count(const std::string& filename) {
void compile_game_count(const std::string& input_filename, const std::string& output_prefix) {
struct Count {
int buzzer;
int money;
@ -18,7 +18,7 @@ void compile_game_count(const std::string& filename) {
int unknowns[2] = {0, 0};
goos::Reader reader;
auto code = reader.read_from_file({filename});
auto code = reader.read_from_file({input_filename});
int len = goos::list_length(code) - 1;
int i = 0;
std::string err;
@ -74,7 +74,7 @@ void compile_game_count(const std::string& filename) {
gen.add_word(unknowns[1]);
auto result = gen.generate_v4();
file_util::create_dir_if_needed(file_util::get_file_path({"out", "obj"}));
file_util::write_binary_file(file_util::get_file_path({"out", "obj", "game-cnt.go"}),
result.data(), result.size());
file_util::write_binary_file(
file_util::get_jak_project_dir() / "out" / output_prefix / "obj" / "game-cnt.go",
result.data(), result.size());
}

View File

@ -1,4 +1,4 @@
#pragma once
#include <string>
void compile_game_count(const std::string& filename);
void compile_game_count(const std::string& input_filename, const std::string& output_prefix);

View File

@ -60,7 +60,7 @@ std::string uppercase(const std::string& in) {
* Write game text data to a file. Uses the V2 object format which is identical between GOAL and
* OpenGOAL, so this should produce exactly identical files to what is found in the game.
*/
void compile_text(GameTextDB& db) {
void compile_text(GameTextDB& db, const std::string& output_prefix) {
for (const auto& [group_name, banks] : db.groups()) {
for (const auto& [lang, bank] : banks) {
DataObjectGenerator gen;
@ -81,10 +81,10 @@ void compile_text(GameTextDB& db) {
auto data = gen.generate_v2();
file_util::create_dir_if_needed(file_util::get_file_path({"out", "iso"}));
file_util::create_dir_if_needed(file_util::get_file_path({"out", output_prefix, "iso"}));
file_util::write_binary_file(
file_util::get_file_path(
{"out", "iso", fmt::format("{}{}.TXT", lang, uppercase(group_name))}),
{"out", output_prefix, "iso", fmt::format("{}{}.TXT", lang, uppercase(group_name))}),
data.data(), data.size());
}
}
@ -94,7 +94,7 @@ void compile_text(GameTextDB& db) {
* Write game subtitle data to a file. Uses the V2 object format which is identical between GOAL and
* OpenGOAL.
*/
void compile_subtitle(GameSubtitleDB& db) {
void compile_subtitle(GameSubtitleDB& db, const std::string& output_prefix) {
for (const auto& [lang, bank] : db.banks()) {
DataObjectGenerator gen;
gen.add_type_tag("subtitle-text-info"); // type
@ -136,10 +136,10 @@ void compile_subtitle(GameSubtitleDB& db) {
auto data = gen.generate_v2();
file_util::create_dir_if_needed(file_util::get_file_path({"out", "iso"}));
file_util::create_dir_if_needed(file_util::get_file_path({"out", output_prefix, "iso"}));
file_util::write_binary_file(
file_util::get_file_path(
{"out", "iso", fmt::format("{}{}.TXT", lang, uppercase("subtit"))}),
{"out", output_prefix, "iso", fmt::format("{}{}.TXT", lang, uppercase("subtit"))}),
data.data(), data.size());
}
}
@ -148,22 +148,26 @@ void compile_subtitle(GameSubtitleDB& db) {
/*!
* Read a game text description file and generate GOAL objects.
*/
void compile_game_text(const std::vector<std::string>& filenames, GameTextDB& db) {
void compile_game_text(const std::vector<std::string>& filenames,
GameTextDB& db,
const std::string& output_prefix) {
goos::Reader reader;
for (auto& filename : filenames) {
fmt::print("[Build Game Text] {}\n", filename.c_str());
auto code = reader.read_from_file({filename});
parse_text(code, db);
}
compile_text(db);
compile_text(db, output_prefix);
}
void compile_game_subtitle(const std::vector<std::string>& filenames, GameSubtitleDB& db) {
void compile_game_subtitle(const std::vector<std::string>& filenames,
GameSubtitleDB& db,
const std::string& output_prefix) {
goos::Reader reader;
for (auto& filename : filenames) {
fmt::print("[Build Game Subtitle] {}\n", filename.c_str());
auto code = reader.read_from_file({filename});
parse_subtitle(code, db, filename);
}
compile_subtitle(db);
compile_subtitle(db, output_prefix);
}

View File

@ -9,5 +9,9 @@
#include "common/util/Assert.h"
#include "common/util/FontUtils.h"
void compile_game_text(const std::vector<std::string>& filenames, GameTextDB& db);
void compile_game_subtitle(const std::vector<std::string>& filenames, GameSubtitleDB& db);
void compile_game_text(const std::vector<std::string>& filenames,
GameTextDB& db,
const std::string& output_prefix);
void compile_game_subtitle(const std::vector<std::string>& filenames,
GameSubtitleDB& db,
const std::string& output_prefix);

View File

@ -59,6 +59,12 @@ MakeSystem::MakeSystem(const std::string& username) : m_goos(username) {
return handle_map_path(obj, args, env);
});
m_goos.register_form("set-output-prefix",
[=](const goos::Object& obj, goos::Arguments& args,
const std::shared_ptr<goos::EnvironmentObject>& env) {
return handle_set_output_prefix(obj, args, env);
});
m_goos.set_global_variable_to_symbol("ASSETS", "#t");
set_constant("*iso-data*", file_util::get_file_path({"iso_data"}));
@ -202,6 +208,16 @@ goos::Object MakeSystem::handle_map_path(const goos::Object& form,
return goos::Object::make_empty_list();
}
goos::Object MakeSystem::handle_set_output_prefix(
const goos::Object& form,
goos::Arguments& args,
const std::shared_ptr<goos::EnvironmentObject>& env) {
m_goos.eval_args(&args, env);
va_check(form, args, {goos::ObjectType::STRING}, {});
m_path_map.output_prefix = args.unnamed.at(0).as_string()->data;
return goos::Object::make_empty_list();
}
void MakeSystem::get_dependencies(const std::string& master_target,
const std::string& output,
std::vector<std::string>* result,
@ -321,7 +337,8 @@ void print_input(const std::vector<std::string>& in, char end) {
}
} // namespace
bool MakeSystem::make(const std::string& target, bool force, bool verbose) {
bool MakeSystem::make(const std::string& target_in, bool force, bool verbose) {
std::string target = m_path_map.apply_remaps(target_in);
auto deps = get_dependencies(target);
// fmt::print("All deps:\n");
// for (auto& dep : deps) {

View File

@ -34,6 +34,10 @@ class MakeSystem {
goos::Arguments& args,
const std::shared_ptr<goos::EnvironmentObject>& env);
goos::Object handle_set_output_prefix(const goos::Object& obj,
goos::Arguments& args,
const std::shared_ptr<goos::EnvironmentObject>& env);
std::vector<std::string> get_dependencies(const std::string& target) const;
std::vector<std::string> filter_dependencies(const std::vector<std::string>& all_deps);
@ -50,6 +54,11 @@ class MakeSystem {
void clear_project();
/*!
* Get the prefix that the project has requested for all compiler outputs
*/
const std::string& compiler_output_prefix() const { return m_path_map.output_prefix; }
private:
void va_check(const goos::Object& form,
const goos::Arguments& args,

View File

@ -7,6 +7,7 @@
#include "common/goos/Object.h"
struct PathMap {
std::string output_prefix;
std::unordered_map<std::string, std::string> path_remap;
std::string apply_remaps(const std::string& input) const;
};

View File

@ -76,33 +76,33 @@ DgoDescription parse_desc_file(const std::string& filename, goos::Reader& reader
DgoTool::DgoTool() : Tool("dgo") {}
bool DgoTool::run(const ToolInput& task, const PathMap& /*path_map*/) {
bool DgoTool::run(const ToolInput& task, const PathMap& path_map) {
if (task.input.size() != 1) {
throw std::runtime_error(fmt::format("Invalid amount of inputs to {} tool", name()));
}
auto desc = parse_desc_file(task.input.at(0), m_reader);
build_dgo(desc);
build_dgo(desc, path_map.output_prefix);
return true;
}
std::vector<std::string> DgoTool::get_additional_dependencies(const ToolInput& task,
const PathMap& /*path_map*/) {
const PathMap& path_map) {
std::vector<std::string> result;
auto desc = parse_desc_file(task.input.at(0), m_reader);
for (auto& x : desc.entries) {
// todo out
result.push_back(fmt::format("out/obj/{}", x.file_name));
result.push_back(fmt::format("out/{}obj/{}", path_map.output_prefix, x.file_name));
}
return result;
}
TpageDirTool::TpageDirTool() : Tool("tpage-dir") {}
bool TpageDirTool::run(const ToolInput& task, const PathMap& /*path_map*/) {
bool TpageDirTool::run(const ToolInput& task, const PathMap& path_map) {
if (task.input.size() != 1) {
throw std::runtime_error(fmt::format("Invalid amount of inputs to {} tool", name()));
}
compile_dir_tpages(task.input.at(0));
compile_dir_tpages(task.input.at(0), path_map.output_prefix);
return true;
}
@ -122,11 +122,11 @@ bool CopyTool::run(const ToolInput& task, const PathMap& /*path_map*/) {
GameCntTool::GameCntTool() : Tool("game-cnt") {}
bool GameCntTool::run(const ToolInput& task, const PathMap& /*path_map*/) {
bool GameCntTool::run(const ToolInput& task, const PathMap& path_map) {
if (task.input.size() != 1) {
throw std::runtime_error(fmt::format("Invalid amount of inputs to {} tool", name()));
}
compile_game_count(task.input.at(0));
compile_game_count(task.input.at(0), path_map.output_prefix);
return true;
}
@ -152,7 +152,7 @@ bool TextTool::run(const ToolInput& task, const PathMap& path_map) {
for (auto& in : inputs) {
in = path_map.apply_remaps(in);
}
compile_game_text(inputs, db);
compile_game_text(inputs, db, path_map.output_prefix);
return true;
}
@ -186,7 +186,7 @@ bool SubtitleTool::run(const ToolInput& task, const PathMap& path_map) {
for (auto& in : inputs) {
in = path_map.apply_remaps(in);
}
compile_game_subtitle(inputs, db);
compile_game_subtitle(inputs, db, path_map.output_prefix);
return true;
}
@ -200,9 +200,9 @@ bool BuildLevelTool::needs_run(const ToolInput& task, const PathMap& path_map) {
return Tool::needs_run({task.input, deps, task.output, task.arg}, path_map);
}
bool BuildLevelTool::run(const ToolInput& task, const PathMap& /*path_map*/) {
bool BuildLevelTool::run(const ToolInput& task, const PathMap& path_map) {
if (task.input.size() != 1) {
throw std::runtime_error(fmt::format("Invalid amount of inputs to {} tool", name()));
}
return run_build_level(task.input.at(0), task.output.at(0));
return run_build_level(task.input.at(0), task.output.at(0), path_map.output_prefix);
}

View File

@ -1,9 +0,0 @@
b06369c2dd9197cb17aae6286246caf9 iso/0COMMON.TXT
da0d6012181f13803e8b3267a4099b97 iso/1COMMON.TXT
4a9a27beb4ce7e75fa4c70811d2c0013 iso/2COMMON.TXT
abcc25e5d7469dd6a572dc53dbb9671c iso/3COMMON.TXT
82eabdb7159f2059fbdbd18bb6fc06aa iso/4COMMON.TXT
5d62de2c78b4cf102b9a78f3aa96c8c9 iso/5COMMON.TXT
9495f80955e6782513fe12f6539fc8e7 iso/6COMMON.TXT
9765bdc3add08cb06fd3e87ebd5713aa obj/game-cnt.go
5033811c685e1bde4411d396b1d4ffba obj/dir-tpages.go

View File

@ -1,3 +1,3 @@
*
!.gitignore
!hash.md5
!hash.md5

3
out/jak1/iso/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*
!.gitignore
!hash.md5

3
out/jak1/obj/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*
!.gitignore
!hash.md5

3
out/jak2/fr3/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*
!.gitignore
!hash.md5

3
out/jak2/iso/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*
!.gitignore
!hash.md5

3
out/jak2/obj/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*
!.gitignore
!hash.md5

View File

@ -131,7 +131,7 @@ std::vector<std::string> get_test_pass_string(const std::string& name, int count
} // namespace
TEST_F(WithGameTests, MakeSystem) {
shared_compiler->compiler.run_front_end_on_string("(make \"out/iso/ENGINE.CGO\")");
shared_compiler->compiler.run_front_end_on_string("(make \"out/jak1/iso/ENGINE.CGO\")");
}
TEST_F(WithGameTests, ReturnConstant) {
@ -380,8 +380,8 @@ TEST_F(WithGameTests, GameCount) {
shared_compiler->runner.run_static_test(env, testCategory, "test-game-count.gc",
get_test_pass_string("game-count", 4));
// don't leave behind a weird version of the game-count file.
std::filesystem::remove(file_util::get_file_path({"out", "iso", "ENGINE.CGO"}));
std::filesystem::remove(file_util::get_file_path({"out", "obj", "game-cnt.go"}));
std::filesystem::remove(file_util::get_file_path({"out", "jak1", "iso", "ENGINE.CGO"}));
std::filesystem::remove(file_util::get_file_path({"out", "jak1", "obj", "game-cnt.go"}));
}
TEST_F(WithGameTests, BitFieldAccess) {