summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMegaMech <MegaMech@users.noreply.github.com>2025-11-14 14:50:33 -0700
committerGitHub <noreply@github.com>2025-11-14 14:50:33 -0700
commitfffd3f7fe92c6eb45b68c0ca522066bf9c54abb2 (patch)
tree3dace8aa5a702dddfc0e5d7d7fde948c358a67dd /src
parentc2755aee40bb37c8440ec58f260b4bd36bd6e256 (diff)
RaceManager class (#562)
* Create RaceManager.cpp * Create RaceManager class for race lifecycle management Added RaceManager class to manage race events lifecycle. * Refactor World class and implement ClearWorld method Refactor World class constructor and destructor. Implement ClearWorld method to delete all objects and reset state. * Add RaceManager to World class * Update ValidateString for editor mode checks Refactor ValidateString to handle editor mode and empty strings. * Update Text.cpp * Add SetText method to Text class * Document RunGarbageCollector function Added documentation for the RunGarbageCollector function. * Refactor Game.cpp by removing dead code Removed unused ruleset handling and clean-up code. * Update Game.h * Remove CM_SpawnFromLevelProps call * Update Text.cpp * Update World.cpp * Add Clean method to RaceManager class * Update RaceManager.cpp * Update World.cpp * Update World.h * Update World.cpp
Diffstat (limited to 'src')
-rw-r--r--src/engine/GarbageCollector.cpp3
-rw-r--r--src/engine/RaceManager.cpp77
-rw-r--r--src/engine/RaceManager.h31
-rw-r--r--src/engine/World.cpp49
-rw-r--r--src/engine/World.h6
-rw-r--r--src/engine/actors/Text.cpp19
-rw-r--r--src/engine/actors/Text.h2
-rw-r--r--src/port/Game.cpp84
-rw-r--r--src/port/Game.h6
-rw-r--r--src/racing/actors.c3
10 files changed, 183 insertions, 97 deletions
diff --git a/src/engine/GarbageCollector.cpp b/src/engine/GarbageCollector.cpp
index e7f2d9975..d356602d3 100644
--- a/src/engine/GarbageCollector.cpp
+++ b/src/engine/GarbageCollector.cpp
@@ -1,6 +1,9 @@
#include "GarbageCollector.h"
#include "World.h"
+/**
+ * Removes objects if they are marked for deletion
+ */
void RunGarbageCollector() {
CleanActors();
CleanObjects();
diff --git a/src/engine/RaceManager.cpp b/src/engine/RaceManager.cpp
new file mode 100644
index 000000000..ae1ef828f
--- /dev/null
+++ b/src/engine/RaceManager.cpp
@@ -0,0 +1,77 @@
+#include "RaceManager.h"
+
+#include "AllActors.h"
+#include "World.h"
+#include "port/Game.h"
+#include "engine/editor/Editor.h"
+#include "engine/editor/SceneManager.h"
+
+extern "C" {
+#include "render_courses.h"
+}
+
+RaceManager::RaceManager(World& world) : WorldContext(world) {
+}
+
+void RaceManager::Load() {
+ if (WorldContext.CurrentCourse) {
+ WorldContext.CurrentCourse->Load();
+ }
+}
+
+void RaceManager::PreInit() {
+ // Ruleset options
+ if (CVarGetInteger("gDisableItemboxes", false) == true) {
+ gPlaceItemBoxes = false;
+ } else {
+ gPlaceItemBoxes = true;
+ }
+}
+
+void RaceManager::BeginPlay() {
+ auto course = WorldContext.CurrentCourse;
+
+ if (course) {
+ // Do not spawn finishline in credits or battle mode. And if bSpawnFinishline.
+ if ((gGamestate != CREDITS_SEQUENCE) && (gModeSelection != BATTLE)) {
+ if (course->bSpawnFinishline) {
+ if (course->FinishlineSpawnPoint.has_value()) {
+ AFinishline::Spawn(course->FinishlineSpawnPoint.value(), IRotator(0, 0, 0));
+ } else {
+ AFinishline::Spawn();
+ }
+
+ }
+ }
+ gEditor.AddLight("Sun", nullptr, D_800DC610[1].l->l.dir);
+
+ course->BeginPlay();
+ }
+}
+
+void RaceManager::PostInit() {
+ // Ruleset options
+ if (CVarGetInteger("gAllThwompsAreMarty", false) == true) {
+ for (auto object : gWorldInstance.Objects) {
+ if (OThwomp* thwomp = dynamic_cast<OThwomp*>(object)) {
+ gObjectList[thwomp->_objectIndex].unk_0D5 = OThwomp::States::JAILED; // Sets all the thwomp behaviour flags to marty
+ thwomp->Behaviour = OThwomp::States::JAILED;
+ }
+ }
+ }
+
+ if (CVarGetInteger("gAllBombKartsChase", false) == true) {
+ for (auto object : gWorldInstance.Objects) {
+ if (OBombKart* kart = dynamic_cast<OBombKart*>(object)) {
+ kart->Behaviour = OBombKart::States::CHASE;
+ }
+ }
+ }
+
+ if (CVarGetInteger("gGoFish", false) == true) {
+ OTrophy::Spawn(FVector(0,0,0), OTrophy::TrophyType::GOLD, OTrophy::Behaviour::GO_FISH);
+ }
+}
+
+void RaceManager::Clean() {
+}
diff --git a/src/engine/RaceManager.h b/src/engine/RaceManager.h
new file mode 100644
index 000000000..fb38bb33c
--- /dev/null
+++ b/src/engine/RaceManager.h
@@ -0,0 +1,31 @@
+#pragma once
+
+class World;
+
+/**
+ * This may eventually become GameMode class
+ *
+ * The RaceManager orchestrates the event lifecycle
+ * It defines when a race begins, actors spawn, and the race ends.
+ *
+ * It does not define the game mode itself.
+ *
+ * You must call the base function if you want the
+ * default functionality to run
+ * Example:
+ * MyRaceManager::BeginPlay() {
+ * RaceManager::BeginPlay() // <-- Calls default functionality
+ * // My code here
+ * }
+ */
+class RaceManager {
+public:
+ RaceManager(World& world);
+ virtual void Load(); // virtual required here in the base class to allow inherited classes to override
+ virtual void PreInit();
+ virtual void BeginPlay();
+ virtual void PostInit();
+ virtual void Clean();
+protected:
+ World& WorldContext;
+};
diff --git a/src/engine/World.cpp b/src/engine/World.cpp
index 0430edf6d..cca7a2199 100644
--- a/src/engine/World.cpp
+++ b/src/engine/World.cpp
@@ -21,14 +21,17 @@ extern "C" {
#include "mario_raceway_data.h"
}
-World::World() {}
-World::~World() {
- CM_CleanWorld();
-}
-
std::shared_ptr<Course> CurrentCourse;
Cup* CurrentCup;
+World::World() {
+ RaceManagerInstance = std::make_unique<RaceManager>(*this);
+}
+
+World::~World() {
+ ClearWorld();
+}
+
std::shared_ptr<Course> World::AddCourse(std::shared_ptr<Course> course) {
gWorldInstance.Courses.push_back(course);
return course;
@@ -252,13 +255,39 @@ Object* World::GetObjectByIndex(size_t index) {
return nullptr; // Or handle the error as needed
}
+// Deletes all objects from the world
void World::ClearWorld(void) {
- CM_CleanWorld();
+ printf("[Game.cpp] Clean World\n");
+ World* world = &gWorldInstance;
+ for (auto& actor : world->Actors) {
+ delete actor;
+ }
- // for (size_t i = 0; i < ARRAY_COUNT(gCollisionMesh); i++) {
+ gWorldInstance.Reset(); // Reset OObjects
+ for (auto& object : world->Objects) {
+ delete object;
+ }
- // }
+ for (auto& emitter : world->Emitters) {
+ delete emitter;
+ }
+
+ for (auto& actor : world->StaticMeshActors) {
+ delete actor;
+ }
+
+ for (size_t i = 0; i < ARRAY_COUNT(gWorldInstance.playerBombKart); i++) {
+ gWorldInstance.playerBombKart[i].state = PlayerBombKart::PlayerBombKartState::DISABLED;
+ gWorldInstance.playerBombKart[i]._primAlpha = 0;
+ }
+
+ gEditor.ClearObjects();
+ gWorldInstance.Actors.clear();
+ gWorldInstance.StaticMeshActors.clear();
+ gWorldInstance.Objects.clear();
+ gWorldInstance.Emitters.clear();
+ gWorldInstance.Lakitus.clear();
+
+ gWorldInstance.GetRaceManager().Clean();
- // gCollisionMesh
- // Paths
}
diff --git a/src/engine/World.h b/src/engine/World.h
index 52a307be5..4e1e6e06e 100644
--- a/src/engine/World.h
+++ b/src/engine/World.h
@@ -9,6 +9,7 @@
#include "TrainCrossing.h"
#include <memory>
#include <unordered_map>
+#include "RaceManager.h"
#include "Actor.h"
#include "StaticMeshActor.h"
#include "particles/ParticleEmitter.h"
@@ -50,6 +51,9 @@ public:
explicit World();
~World();
+ RaceManager& GetRaceManager() { return *RaceManagerInstance; }
+ void SetRaceManager(std::unique_ptr<RaceManager> manager) { RaceManagerInstance = std::move(manager); }
+
std::shared_ptr<Course> AddCourse(std::shared_ptr<Course> course);
AActor* AddActor(AActor* actor);
@@ -130,7 +134,7 @@ public:
std::vector<std::shared_ptr<Course>> Courses;
size_t CourseIndex = 0; // For browsing courses.
private:
-
+ std::unique_ptr<RaceManager> RaceManagerInstance;
};
extern World gWorldInstance;
diff --git a/src/engine/actors/Text.cpp b/src/engine/actors/Text.cpp
index 2d2fab0b0..06a74c54d 100644
--- a/src/engine/actors/Text.cpp
+++ b/src/engine/actors/Text.cpp
@@ -77,7 +77,11 @@ AText::AText(const SpawnParams& params) : AActor(params) {
* But these need to be checked thoroughly before white-listing.
*/
std::string AText::ValidateString(const std::string_view& s) {
- if (s.empty()) { return "Blank Text"; }
+ if (CVarGetInteger("gIsEditorEnabled", false) == true) {
+ if (s.empty()) { return "Blank Text"; }
+ } else {
+ if (s.empty()) { return ""; }
+ }
Text.clear();
@@ -100,6 +104,11 @@ std::string AText::ValidateString(const std::string_view& s) {
return Text;
}
+void AText::SetText(std::string text) {
+ AText::ValidateString(text);
+ Refresh();
+}
+
/*
* Most changes during runtime require a refresh because the text is generated statically
* with the intention of this code being somewhat performant
@@ -353,7 +362,9 @@ void AText::DrawText3D(Camera* camera) { // Based on func_80095BD0
FrameInterpolation_RecordOpenChild("actor_text", TAG_LETTER(this));
gSPDisplayList(gDisplayListHead++, (Gfx*)D_020077A8);
- switch (1) {
+
+ for (CharacterList& tex : TextureList) {
+ switch (tex.mode) {
case 1:
gSPDisplayList(gDisplayListHead++, (Gfx*)D_020077F8);
break;
@@ -361,8 +372,6 @@ void AText::DrawText3D(Camera* camera) { // Based on func_80095BD0
gSPDisplayList(gDisplayListHead++, (Gfx*)D_02007818);
break;
}
-
- for (CharacterList& tex : TextureList) {
//printf("tex texture %p width %d height %d mode %d col %f\n", tex.Texture, tex.width, tex.height, tex.mode, tex.column);
gDPLoadTextureTile_4b(gDisplayListHead++, (Gfx*)tex.Texture, G_IM_FMT_I, tex.width, 0, 0, 0, tex.width, tex.height + 2, 0,
G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
@@ -585,4 +594,4 @@ void AText::DrawColourEditor(bool* updated) {
}
}
}
-} \ No newline at end of file
+}
diff --git a/src/engine/actors/Text.h b/src/engine/actors/Text.h
index 7a9ac7407..e0b436709 100644
--- a/src/engine/actors/Text.h
+++ b/src/engine/actors/Text.h
@@ -118,6 +118,8 @@ public:
void DrawColourEditor(bool* updated);
void FollowPlayer();
+ void SetText(std::string text);
+
std::string ValidateString(const std::string_view& text);
void Refresh();
void Print3D(char* text, s32 tracking, s32 mode);
diff --git a/src/port/Game.cpp b/src/port/Game.cpp
index 37282346d..d3fb061e0 100644
--- a/src/port/Game.cpp
+++ b/src/port/Game.cpp
@@ -90,7 +90,6 @@ Cup* gBattleCup;
ModelLoader gModelLoader;
HarbourMastersIntro gMenuIntro;
-Rulesets gRulesets;
Editor::Editor gEditor;
@@ -194,14 +193,6 @@ void HM_DrawIntro() {
gMenuIntro.HM_DrawIntro();
}
-void CM_SpawnFromLevelProps() {
- // Spawning actors needs to be delayed to the correct time.
- // And loadlevel needs to happen asap
-
- //Editor::LoadLevel(nullptr);
- // Editor::SpawnFromLevelProps();
-}
-
// Set default course; mario raceway
void SetMarioRaceway(void) {
SetCourseById(0);
@@ -239,10 +230,7 @@ const char* GetCupName(void) {
}
void LoadCourse() {
- if (gWorldInstance.CurrentCourse) {
- gRulesets.PreLoad();
- gWorldInstance.CurrentCourse->Load();
- }
+ gWorldInstance.GetRaceManager().Load();
}
size_t GetCourseIndex() {
@@ -383,28 +371,15 @@ void CM_DrawStaticMeshActors() {
}
void CM_BeginPlay() {
- auto course = gWorldInstance.CurrentCourse;
-
- if (course) {
- Editor::LoadLevel(course.get(), course->SceneFilePtr);
-
- gRulesets.PreInit();
- // Do not spawn finishline in credits or battle mode. And if bSpawnFinishline.
- if ((gGamestate != CREDITS_SEQUENCE) && (gModeSelection != BATTLE)) {
- if (course->bSpawnFinishline) {
- if (course->FinishlineSpawnPoint.has_value()) {
- AFinishline::Spawn(course->FinishlineSpawnPoint.value(), IRotator(0, 0, 0));
- } else {
- AFinishline::Spawn();
- }
-
- }
- }
- gEditor.AddLight("Sun", nullptr, D_800DC610[1].l->l.dir);
-
- course->BeginPlay();
- gRulesets.PostInit();
+ if (gWorldInstance.CurrentCourse) {
+ // This line should likely be moved.
+ // It's here so PreInit is after the scene file has been loaded
+ // It used to be at the start of BeginPlay
+ Editor::LoadLevel(gWorldInstance.CurrentCourse.get(), gWorldInstance.CurrentCourse->SceneFilePtr);
}
+ gWorldInstance.GetRaceManager().PreInit();
+ gWorldInstance.GetRaceManager().BeginPlay();
+ gWorldInstance.GetRaceManager().PostInit();
}
void CM_TickObjects() {
@@ -451,16 +426,6 @@ void CM_DrawParticles(s32 cameraId) {
}
}
-// Helps prevents users from forgetting to add a finishline to their course
-bool CM_DoesFinishlineExist() {
- for (AActor* actor : gWorldInstance.Actors) {
- if (dynamic_cast<AFinishline*>(actor)) {
- return true;
- }
- }
- return false;
-}
-
void CM_InitClouds() {
if (gWorldInstance.CurrentCourse) {
gWorldInstance.CurrentCourse->InitClouds();
@@ -661,36 +626,7 @@ void CM_DeleteActor(size_t index) {
* Clean up actors and other game objects.
*/
void CM_CleanWorld(void) {
- printf("[Game.cpp] Clean World\n");
- World* world = &gWorldInstance;
- for (auto& actor : world->Actors) {
- delete actor;
- }
-
- gWorldInstance.Reset(); // Reset OObjects
- for (auto& object : world->Objects) {
- delete object;
- }
-
- for (auto& emitter : world->Emitters) {
- delete emitter;
- }
-
- for (auto& actor : world->StaticMeshActors) {
- delete actor;
- }
-
- for (size_t i = 0; i < ARRAY_COUNT(gWorldInstance.playerBombKart); i++) {
- gWorldInstance.playerBombKart[i].state = PlayerBombKart::PlayerBombKartState::DISABLED;
- gWorldInstance.playerBombKart[i]._primAlpha = 0;
- }
-
- gEditor.ClearObjects();
- gWorldInstance.Actors.clear();
- gWorldInstance.StaticMeshActors.clear();
- gWorldInstance.Objects.clear();
- gWorldInstance.Emitters.clear();
- gWorldInstance.Lakitus.clear();
+ gWorldInstance.ClearWorld();
}
struct Actor* CM_AddBaseActor() {
diff --git a/src/port/Game.h b/src/port/Game.h
index 062b9aafb..0982d649b 100644
--- a/src/port/Game.h
+++ b/src/port/Game.h
@@ -30,8 +30,6 @@ void HM_InitIntro(void);
void HM_TickIntro(void);
void HM_DrawIntro(void);
-void CM_SpawnFromLevelProps();
-
void CM_DisplayBattleBombKart(s32 playerId, s32 primAlpha);
void CM_DrawBattleBombKarts(s32 cameraId);
@@ -68,8 +66,6 @@ void CM_ActivateSecondLapLakitu(s32 playerId);
void CM_ActivateFinalLapLakitu(s32 playerId);
void CM_ActivateReverseLakitu(s32 playerId);
-bool CM_DoesFinishlineExist();
-
void CM_InitClouds();
void CM_DrawActors(Camera* camera);
@@ -224,4 +220,4 @@ void CM_RunGarbageCollector(void);
}
#endif
-#endif // _GAME_H \ No newline at end of file
+#endif // _GAME_H
diff --git a/src/racing/actors.c b/src/racing/actors.c
index 11bd79203..d9a59400a 100644
--- a/src/racing/actors.c
+++ b/src/racing/actors.c
@@ -1318,7 +1318,6 @@ void init_actors_and_load_textures(void) {
destroy_all_actors();
CM_CleanWorld();
- CM_SpawnFromLevelProps();
CM_BeginPlay();
spawn_course_actors();
}
@@ -2896,4 +2895,4 @@ const char* get_actor_resource_location_name(s32 id) {
default:
return "mk:actor";
}
-} \ No newline at end of file
+}