mirror of
https://github.com/HarbourMasters/SpaghettiKart
synced 2026-07-09 23:02:11 -04:00
Import courses working now
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user