Import courses working now

This commit is contained in:
MegaMech
2025-04-21 13:17:14 -06:00
parent 9055c9c7ee
commit 12c3f2b7e3
6 changed files with 87 additions and 70 deletions
+5 -1
View File
@@ -29,9 +29,13 @@ extern StaffGhost* d_mario_raceway_staff_ghost;
Course::Course() {
// Props.Name = "Course Name";
// Props.DebugName = "CName";
// Props.CourseLength = "567m";
Props.SetText(Props.CourseLength, "100m", sizeof(Props.CourseLength));
// Props.Cup = FLOWER_CUP;
// Props.CupIndex = 3;
Props.Id = "";
Props.MinimapTexture = gTextureCourseOutlineMarioRaceway;
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
Props.LakituTowType = (s32) OLakitu::LakituTowType::NORMAL;
Props.AIBehaviour = D_0D008F28;
Props.AIMaximumSeparation = 50.0f;
+3
View File
@@ -122,6 +122,8 @@ typedef struct Properties {
// j["Skybox"] = Skybox; // Implement your serialization logic here
j["Sequence"] = static_cast<int>(Sequence);
j["WaterLevel"] = static_cast<float>(WaterLevel);
return j;
}
@@ -194,6 +196,7 @@ typedef struct Properties {
MinimapFinishlineY = j.at("MinimapFinishlineY").get<float>();
//textures = nullptr; // Deserialize textures if present
Sequence = static_cast<MusicSeq>(j.at("Sequence").get<int>());
WaterLevel = static_cast<float>(j.at("WaterLevel").get<float>());
}
void SetText(char* name, const char* title, size_t bufferSize) {
// Copy the title into the name buffer, ensuring it's null-terminated and within bounds
+7 -10
View File
@@ -46,17 +46,14 @@ namespace Editor {
}
}
void LoadLevel(std::string sceneFile) {
printf("LOAD TRACK PROPS %s\n", sceneFile.c_str());
void LoadLevel(std::shared_ptr<Ship::Archive> archive, Course* course, std::string sceneFile) {
nlohmann::json data;
CurrentArchive = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager()->GetArchiveFromFile(sceneFile);
SceneFile = sceneFile;
if (CurrentArchive) {
if (archive) {
auto initData = std::make_shared<Ship::ResourceInitData>();
initData->Parent = CurrentArchive;
initData->Parent = archive;
initData->Format = RESOURCE_FORMAT_BINARY;
initData->ByteOrder = Ship::Endianness::Little;
initData->Type = static_cast<uint32_t>(Ship::ResourceType::Json);
@@ -72,7 +69,7 @@ namespace Editor {
// 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
course->Props.from_json(propsJson); // Assuming you have a `from_json` function
} else {
std::cerr << "Props data not found in the JSON file!" << std::endl;
}
@@ -102,8 +99,8 @@ namespace Editor {
GameObject::CollisionType::BOUNDING_BOX, 20.0f, (int32_t*) &actor->bPendingDestroy, (int32_t) 1);
}
void SetSceneFile(std::string archive, std::string sceneFile) {
CurrentArchive = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager()->GetArchiveFromFile(archive);
SceneFile = sceneFile+"/scene.json";
void SetSceneFile(std::shared_ptr<Ship::Archive> archive, std::string sceneFile) {
CurrentArchive = archive;
SceneFile = sceneFile;
}
}
+3 -3
View File
@@ -1,11 +1,11 @@
#include <libultraship/libultraship.h>
#include "Course.h"
#include "engine/courses/Course.h"
namespace Editor {
void SaveLevel();
void LoadLevel(std::string sceneFile);
void LoadLevel(std::shared_ptr<Ship::Archive> archive, Course* course, std::string sceneFile);
void Load_AddStaticMeshActor(const nlohmann::json& actorJson);
void SetSceneFile(std::string archive, std::string sceneFile);
void SetSceneFile(std::shared_ptr<Ship::Archive> archive, 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;
+57 -53
View File
@@ -33,10 +33,9 @@ namespace Editor {
// Query content in o2r and add them to Content
if (Refresh) {
Refresh = false;
RemoveCustomTracksFromTrackList();
Tracks.clear();
Content.clear();
TrackAssetMap.clear();
TrackPath.clear();
FindTracks();
FindContent();
return;
@@ -123,28 +122,21 @@ namespace Editor {
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("scene.json")) {
foundTrackFile = true;
if (ImGui::Button(label.c_str())) {
gWorldInstance.Courses.push_back(new Course());
SetCourseByClass(gWorldInstance.Courses.back());
LoadLevel(asset);
gWorldInstance.CurrentCourse->LoadO2R(TrackPath[track]);
gGamestateNext = RACING;
break;
}
}
}
if (!foundTrackFile) {
std::string label = fmt::format("{} {}", ICON_FA_EXCLAMATION_TRIANGLE, track);
for (auto& track : Tracks) {
if (!track.SceneFile.empty()) { // has scene file
std::string label = fmt::format("{}##{}", track.Name, i_track);
if (ImGui::Button(label.c_str())) {
SetSceneFile(TrackAssetMap[track][0], TrackPath[track]);
SetCourseByClass(track.course);
gGamestateNext = RACING;
SetSceneFile(track.Archive, track.SceneFile);
break;
}
} else { // no scene file
std::string label = fmt::format("{} {}", ICON_FA_EXCLAMATION_TRIANGLE, track.Name);
if (ImGui::Button(label.c_str())) {
track.SceneFile = track.Dir + "/scene.json";
SetCourseByClass(track.course);
SetSceneFile(track.Archive, track.SceneFile);
SaveLevel();
Refresh = true;
}
@@ -154,6 +146,20 @@ namespace Editor {
}
}
void ContentBrowserWindow::RemoveCustomTracksFromTrackList() {
for (auto& track : Tracks) {
auto it = gWorldInstance.Courses.begin();
while (it != gWorldInstance.Courses.end()) {
if (track.course == *it) {
delete *it;
it = gWorldInstance.Courses.erase(it);
} else {
++it;
}
}
}
}
void ContentBrowserWindow::AddActorContent() {
FVector pos = GetPositionAheadOfCamera(300.0f);
@@ -216,43 +222,41 @@ namespace Editor {
// Finds modded archives only. For discovering tracks
void ContentBrowserWindow::FindTracks() {
auto manager = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager();
// ListFiles(whitelist, blacklist);
auto ptr2 = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager()->ListFiles({"tracks/*/scene.json"}, {""});
auto ptr2 = manager->ListDirectories("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);
auto dirs = *ptr2;
TrackAssetMap[trackName].push_back(file);
// Insert into set (ensuring uniqueness)
uniqueTracks.insert(trackName);
for (const std::string& dir : dirs) {
std::string name = dir.substr(dir.find_last_of('/') + 1);
std::string sceneFile = dir + "/scene.json";
if (manager->HasFile(sceneFile)) {
auto archive = manager->GetArchiveFromFile(sceneFile);
Course* course = new Course();
course->LoadO2R(dir);
gWorldInstance.Courses.push_back(course);
LoadLevel(archive, course, sceneFile);
Tracks.push_back({course, sceneFile, name, dir, archive});
} else {
const std::string file = dir + "/data_track_sections";
if (manager->HasFile(file)) {
// Extract directory path (remove filename)
size_t lastSlash = file.find_last_of('/');
printf("file %s\n", file.c_str());
Course* course = new Course();
course->Props.Id = (std::string("mods:") + name).c_str();
course->Props.SetText(course->Props.Name, name.c_str(), sizeof(course->Props.Name));
course->Props.SetText(course->Props.DebugName, name.c_str(), sizeof(course->Props.Name));
std::string directoryPath = (lastSlash != std::string::npos) ? file.substr(0, lastSlash) : file;
printf("dir %s\n", directoryPath.c_str());
auto archive = manager->GetArchiveFromFile(file);
Tracks.push_back({course, "", name, dir, archive});
} else {
printf("ContentBrowser.cpp: Track '%s' missing required track files. Cannot add to game\n Missing %s/data_track_sections file\n", name.c_str(), dir.c_str());
}
// Store in TrackPath
TrackPath[trackName] = directoryPath;
}
}
// Move unique tracks into the vector
Tracks.assign(uniqueTracks.begin(), uniqueTracks.end());
}
}
+12 -3
View File
@@ -1,6 +1,7 @@
#pragma once
#include <libultraship/libultraship.h>
#include "engine/courses/Course.h"
namespace Editor {
class ContentBrowserWindow : public Ship::GuiWindow {
@@ -8,10 +9,17 @@ public:
using Ship::GuiWindow::GuiWindow;
~ContentBrowserWindow();
struct Tracks {
Course* course;
std::string SceneFile;
std::string Name;
std::string Dir; // Directory
std::shared_ptr<Ship::Archive> Archive;
};
std::vector<Tracks> Tracks;
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;
@@ -24,6 +32,7 @@ protected:
void DrawElement() override;
void UpdateElement() override {};
void AddTrackContent();
void RemoveCustomTracksFromTrackList(); // Prevents duplicate courses being added to World->Courses array
void AddActorContent();
void AddObjectContent();
void AddCustomContent();