SceneManager nearly working

This commit is contained in:
MegaMech
2025-03-23 18:28:25 -06:00
parent 1dee7001f6
commit 8fe7732039
12 changed files with 238 additions and 135 deletions
+2
View File
@@ -150,6 +150,8 @@ namespace Editor {
eObjectPicker.eGizmo.dimensions.MinZ = minZ + -1000;
eObjectPicker.eGizmo.dimensions.MaxZ = maxZ + 1000;
}
// This is more of a reset
void Editor::NewTrack() {
auto course = gWorldInstance.CurrentCourse = new Course();
course->Props.New();
-85
View File
@@ -1,85 +0,0 @@
#include "SaveLevel.h"
#include "port/Game.h"
#include "CoreMath.h"
#include "World.h"
#include "GameObject.h"
#include <iostream>
#include <fstream>
#include <nlohmann/json.hpp>
namespace Editor {
// SaveLevel::SaveLevel() {}
void SaveLevel() {
auto props = gWorldInstance.CurrentCourse->Props;
nlohmann::json data;
data["Props"] = props.to_json();
nlohmann::json actors;
/* for (const auto& actor : gWorldInstance.StaticMeshActors) {
actors.push_back(actor->to_json());
}
data["Actors"] = actors;*/
std::ofstream file("track.json");
file << data.dump(4); // Pretty print with indent
}
void LoadLevel() {
// Open the JSON file
std::ifstream file("track.json");
if (!file.is_open()) {
std::cerr << "Failed to open track.json for reading!" << std::endl;
return;
}
// Check if level data file is empty
if (file.peek() == std::ifstream::traits_type::eof()) {
return;
}
// Parse the JSON file into a nlohmann::json object
nlohmann::json data;
file >> data;
// Load the Props (deserialize it)
if (data.contains("Props")) {
auto& propsJson = data["Props"];
gWorldInstance.CurrentCourse->Props.from_json(propsJson); // Assuming you have a `from_json` function
} else {
std::cerr << "Props data not found in the JSON file!" << std::endl;
}
// Load the Actors (deserialize them)
if (data.contains("Actors")) {
auto& actorsJson = data["Actors"];
gWorldInstance.StaticMeshActors.clear(); // Clear existing actors, if any
for (const auto& actorJson : actorsJson) {
Load_AddStaticMeshActor(actorJson);
}
} else {
std::cerr << "Actors data not found in the JSON file!" << std::endl;
}
// Close the file after loading
file.close();
}
void Load_AddStaticMeshActor(const nlohmann::json& actorJson) {
gWorldInstance.StaticMeshActors.push_back(new StaticMeshActor("", FVector(0, 0, 0), IRotator(0, 0, 0), FVector(1, 1, 1), "", nullptr));
auto actor = gWorldInstance.StaticMeshActors.back();
actor->from_json(actorJson);
printf("After from_json: Pos(%f, %f, %f), Name: %s, Model: %s\n",
actor->Pos.x, actor->Pos.y, actor->Pos.z, actor->Name.c_str(), actor->Model.c_str());
gEditor.AddObject(actor->Name.c_str(), &actor->Pos, (Vec3s*)&actor->Rot, &actor->Scale, (Gfx*) nullptr, 1.0f,
GameObject::CollisionType::BOUNDING_BOX, 20.0f, (int32_t*) &actor->bPendingDestroy, (int32_t) 1);
}
}
-8
View File
@@ -1,8 +0,0 @@
#include <libultraship.h>
#include "Course.h"
namespace Editor {
void SaveLevel();
void LoadLevel();
void Load_AddStaticMeshActor(const nlohmann::json& actorJson);
}
+108
View File
@@ -0,0 +1,108 @@
#include "SceneManager.h"
#include "port/Game.h"
#include "CoreMath.h"
#include "World.h"
#include "GameObject.h"
#include <iostream>
#include <fstream>
#include <nlohmann/json.hpp>
#include "port/Engine.h"
#include <libultraship/src/resource/type/json.h>
#include <libultraship/src/resource/File.h>
namespace Editor {
std::shared_ptr<Ship::Archive> CurrentArchive;
std::string SceneFile = "";
void SaveLevel() {
auto props = gWorldInstance.CurrentCourse->Props;
if ((CurrentArchive) && (!SceneFile.empty())) {
nlohmann::json data;
data["Props"] = props.to_json();
nlohmann::json actors;
// for (const auto& actor : gWorldInstance.StaticMeshActors) {
// actors.push_back(actor->to_json());
// }
// data["Actors"] = actors;
auto dat = data.dump();
std::vector<uint8_t> stringify;
stringify.assign(dat.begin(), dat.end());
bool wrote = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager()->WriteFile(CurrentArchive, SceneFile, stringify);
if (wrote) {
printf("Successfully wrote scene file!\n");
} else {
printf("Failed to write scene file!\n");
}
} else {
printf("Could not save scene file, SceneFile or CurrentArchive not set\n");
}
}
void LoadLevel(std::string sceneFile) {
printf("LOAD TRACK PROPS %s\n", sceneFile.c_str());
nlohmann::json data;
CurrentArchive = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager()->GetArchiveFromFile(sceneFile);
SceneFile = sceneFile;
if (CurrentArchive) {
auto initData = std::make_shared<Ship::ResourceInitData>();
initData->Parent = CurrentArchive;
initData->Format = RESOURCE_FORMAT_BINARY;
initData->ByteOrder = Ship::Endianness::Little;
initData->Type = static_cast<uint32_t>(Ship::ResourceType::Json);
initData->ResourceVersion = 0;
nlohmann::json data = std::static_pointer_cast<Ship::Json>(
GameEngine::Instance->context->GetResourceManager()->LoadResource(sceneFile, true, initData))->Data;
if (data == nullptr) {
return;
}
// Load the Props (deserialize it)
if (data.contains("Props")) {
auto& propsJson = data["Props"];
gWorldInstance.CurrentCourse->Props.from_json(propsJson); // Assuming you have a `from_json` function
} else {
std::cerr << "Props data not found in the JSON file!" << std::endl;
}
// Load the Actors (deserialize them)
if (data.contains("Actors")) {
auto& actorsJson = data["Actors"];
gWorldInstance.StaticMeshActors.clear(); // Clear existing actors, if any
for (const auto& actorJson : actorsJson) {
Load_AddStaticMeshActor(actorJson);
}
} else {
std::cerr << "Actors data not found in the JSON file!" << std::endl;
}
}
}
void Load_AddStaticMeshActor(const nlohmann::json& actorJson) {
gWorldInstance.StaticMeshActors.push_back(new StaticMeshActor("", FVector(0, 0, 0), IRotator(0, 0, 0), FVector(1, 1, 1), "", nullptr));
auto actor = gWorldInstance.StaticMeshActors.back();
actor->from_json(actorJson);
printf("After from_json: Pos(%f, %f, %f), Name: %s, Model: %s\n",
actor->Pos.x, actor->Pos.y, actor->Pos.z, actor->Name.c_str(), actor->Model.c_str());
gEditor.AddObject(actor->Name.c_str(), &actor->Pos, (Vec3s*)&actor->Rot, &actor->Scale, (Gfx*) nullptr, 1.0f,
GameObject::CollisionType::BOUNDING_BOX, 20.0f, (int32_t*) &actor->bPendingDestroy, (int32_t) 1);
}
void SetSceneFile(std::string sceneFile) {
SceneFile = sceneFile;
}
}
+12
View File
@@ -0,0 +1,12 @@
#include <libultraship.h>
#include "Course.h"
namespace Editor {
void SaveLevel();
void LoadLevel(std::string sceneFile);
void Load_AddStaticMeshActor(const nlohmann::json& actorJson);
void SetSceneFile(std::string sceneFile);
extern std::shared_ptr<Ship::Archive> CurrentArchive; // This is used to retrieve and write the scene data file
extern std::string SceneFile;
}
+1 -1
View File
@@ -77,7 +77,7 @@ GameEngine::GameEngine() {
if (std::filesystem::is_directory(patches_path)) {
for (const auto& p : std::filesystem::recursive_directory_iterator(patches_path)) {
auto ext = p.path().extension().string();
if (StringHelper::IEquals(ext, ".otr") || StringHelper::IEquals(ext, ".o2r")) {
if (StringHelper::IEquals(ext, ".zip") || StringHelper::IEquals(ext, ".o2r")) {
archiveFiles.push_back(p.path().generic_string());
}
}
+7 -3
View File
@@ -47,7 +47,7 @@
#include "engine/editor/Editor.h"
#include "engine/editor/EditorMath.h"
#include "engine/editor/SaveLevel.h"
#include "engine/editor/SceneManager.h"
extern "C" {
#include "main.h"
@@ -212,8 +212,12 @@ void HM_DrawIntro() {
gMenuIntro.HM_DrawIntro();
}
void CM_LoadLevelProps() {
Editor::LoadLevel();
void CM_SpawnFromLevelProps() {
// Spawning actors needs to be delayed to the correct time.
// And loadlevel needs to happen asap
//Editor::LoadLevel(nullptr);
// Editor::SpawnFromLevelProps();
}
World* GetWorld(void) {
+1 -1
View File
@@ -26,7 +26,7 @@ void HM_InitIntro(void);
void HM_TickIntro(void);
void HM_DrawIntro(void);
void CM_LoadLevelProps();
void CM_SpawnFromLevelProps();
void CM_DisplayBattleBombKart(s32 playerId, s32 primAlpha);
void CM_DrawBattleBombKarts(s32 cameraId);
+97 -35
View File
@@ -16,6 +16,8 @@
#include "CoreMath.h"
#include "World.h"
#include "AllActors.h"
#include "port/Game.h"
#include "src/engine/editor/SceneManager.h"
namespace Editor {
@@ -24,51 +26,36 @@ namespace Editor {
}
void ContentBrowserWindow::DrawElement() {
static bool refresh = true;
static bool actorContent = false;
static bool objectContent = false;
static bool customContent = false;
static bool trackContent = false;
// List the available mods/o2r files
// for (size_t i = 0; i < GameEngine::Instance->archiveFiles.size(); i++) {
// auto str = GameEngine::Instance->archiveFiles[i];
// if (str.starts_with("./mods/")) {
// ImGui::Text(GameEngine::Instance->archiveFiles[i].c_str());
// }
// }
if (ImGui::Button(ICON_FA_REFRESH)) {
refresh = true;
Refresh = true;
}
// Query content in o2r and add them to Content
if (refresh) {
refresh = false;
if (Refresh) {
Refresh = false;
Tracks.clear();
Content.clear();
TrackAssetMap.clear();
TrackPath.clear();
FindTracks();
FindContent();
return;
}
ContentBrowserWindow::FolderButton("Tracks", trackContent);
ContentBrowserWindow::FolderButton("Actors", actorContent);
ContentBrowserWindow::FolderButton("Objects", objectContent);
ContentBrowserWindow::FolderButton("Custom", customContent);
std::string actorText = fmt::format("{0} {1}", actorContent ? ICON_FA_FOLDER_OPEN_O : ICON_FA_FOLDER_O, "Actors");
if (ImGui::Button(actorText.c_str(), ImVec2(80, 32))) {
actorContent = !actorContent;
objectContent = false;
customContent = false;
}
std::string objectText = fmt::format("{0} {1}", objectContent ? ICON_FA_FOLDER_OPEN_O : ICON_FA_FOLDER_O, "Objects");
if (ImGui::Button(objectText.c_str(), ImVec2(80, 32))) {
objectContent = !objectContent;
actorContent = false;
customContent = false;
}
std::string customText = fmt::format("{0} {1}", customContent ? ICON_FA_FOLDER_OPEN_O : ICON_FA_FOLDER_O, "Custom");
if (ImGui::Button(customText.c_str(), ImVec2(80, 32))) {
customContent = !customContent;
actorContent = false;
objectContent = false;
if (trackContent) {
AddTrackContent();
}
if (actorContent) {
@@ -84,6 +71,13 @@ namespace Editor {
}
}
void ContentBrowserWindow::FolderButton(const char* label, bool& contentFlag, const ImVec2& size) {
std::string buttonText = fmt::format("{0} {1}", contentFlag ? ICON_FA_FOLDER_OPEN_O : ICON_FA_FOLDER_O, label);
if (ImGui::Button(buttonText.c_str(), size)) {
contentFlag = !contentFlag;
}
}
std::unordered_map<std::string, std::function<AActor*(const FVector&)>> ActorList = {
{ "Mario Sign", [](const FVector& pos) { return new AMarioSign(pos); } },
{ "Wario Sign", [](const FVector& pos) { return new AWarioSign(pos); } },
@@ -125,6 +119,39 @@ namespace Editor {
{ "Podium", [](const FVector& pos) { return new OPodium(pos); } },
};
void ContentBrowserWindow::AddTrackContent() {
size_t i_track = 0;
for (const auto& track : Tracks) {
std::string label = fmt::format("{}##{}", track, i_track);
bool foundTrackFile = false;
for (auto& asset : TrackAssetMap[track]) {
if (asset.ends_with("track.json")) {
foundTrackFile = true;
if (ImGui::Button(label.c_str())) {
SetCourseByClass(new Course());
LoadLevel(asset);
gGamestateNext = RACING;
break;
}
}
}
if (!foundTrackFile) {
std::string label = fmt::format("{} {}", "ADD PATH AND MESH TO TRACK PROPS AND CLICK HERE TO INIT TRACK:", track);
if (ImGui::Button(label.c_str())) {
SetSceneFile(TrackPath[track]);
SaveLevel();
Refresh = true;
}
}
i_track += 1;
}
}
void ContentBrowserWindow::AddActorContent() {
FVector pos = GetPositionAheadOfCamera(300.0f);
@@ -183,12 +210,47 @@ namespace Editor {
}
}
// Finds modded archives only. For discovering tracks
void ContentBrowserWindow::FindTracks() {
// ListFiles(whitelist, blacklist);
auto ptr2 = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager()->ListFiles({"*/tracks/*"}, {""});
if (ptr2) {
auto files = *ptr2;
std::set<std::string> uniqueTracks;
for (const auto& file : files) {
//printf("TRACK FILES: %s\n", file.c_str());
// Find "tracks/"
size_t pos = file.find("tracks/");
if (pos == std::string::npos) continue; // Skip if not found
// Extract track name
size_t start = pos + 7; // Move past "tracks/"
size_t end = file.find('/', start); // Find next '/'
std::string trackName = file.substr(start, end - start);
TrackAssetMap[trackName].push_back(file);
// Insert into set (ensuring uniqueness)
uniqueTracks.insert(trackName);
// Extract directory path (remove filename)
size_t lastSlash = file.find_last_of('/');
std::string directoryPath = (lastSlash != std::string::npos) ? file.substr(0, lastSlash) : file;
// Store in TrackPath
TrackPath[trackName] = directoryPath;
}
// Move unique tracks into the vector
Tracks.assign(uniqueTracks.begin(), uniqueTracks.end());
}
}
void ContentBrowserWindow::FindContent() {
std::list<std::string> myList = {"tracks/*", "actors/*", "objects/*"};
std::list<std::string> myList2 = {""};
auto ptr = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager()->ListFiles(myList, myList2);
auto ptr = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager()->ListFiles({"*tracks/*","actors/*", "objects/*"}, {""});
if (ptr) {
auto files = *ptr;
for (const auto& file : files) {
+8
View File
@@ -9,13 +9,21 @@ public:
~ContentBrowserWindow();
std::vector<std::string> Content;
std::vector<std::string> Tracks; // Contains modded archives in mods/
std::unordered_map<std::string, std::vector<std::string>> TrackAssetMap;
std::unordered_map<std::string, std::string> TrackPath;
bool Refresh = true;
protected:
void InitElement() override {};
void DrawElement() override;
void UpdateElement() override {};
void AddTrackContent();
void AddActorContent();
void AddObjectContent();
void AddCustomContent();
void FindTracks();
void FindContent();
void FolderButton(const char* label, bool& contentFlag, const ImVec2& size = ImVec2(80, 32));
};
}
+1 -1
View File
@@ -11,7 +11,7 @@
#include <common_structs.h>
#include <defines.h>
#include "port/Game.h"
#include "engine/editor/SaveLevel.h"
#include "engine/editor/SceneManager.h"
extern "C" {
#include "code_800029B0.h"
+1 -1
View File
@@ -1227,8 +1227,8 @@ void init_actors_and_load_textures(void) {
init_red_shell_texture();
destroy_all_actors();
CM_CleanWorld();
CM_LoadLevelProps();
CM_SpawnFromLevelProps();
CM_BeginPlay();
spawn_course_actors();
}