From d8cbb7428406ee0849a11d52a7414384f3bedd8e Mon Sep 17 00:00:00 2001 From: Demur Rumed Date: Thu, 12 Jun 2025 03:57:30 +0000 Subject: [PATCH] invert TerrainCueState, removing userData / init / cleanup from AccessibleActor --- .../accessible-actors/AccessibleActorList.cpp | 5 +- .../accessible-actors/ActorAccessibility.cpp | 25 ++---- .../accessible-actors/ActorAccessibility.h | 19 ++-- .../accessible-actors/accessibility_cues.cpp | 88 +++++++++++-------- 4 files changed, 67 insertions(+), 70 deletions(-) diff --git a/soh/soh/Enhancements/accessible-actors/AccessibleActorList.cpp b/soh/soh/Enhancements/accessible-actors/AccessibleActorList.cpp index 58f0db114..b9e1e8fdb 100644 --- a/soh/soh/Enhancements/accessible-actors/AccessibleActorList.cpp +++ b/soh/soh/Enhancements/accessible-actors/AccessibleActorList.cpp @@ -1160,12 +1160,10 @@ void ActorAccessibility_InitActors() { temp->policy.ydist = 100; temp->policy.sound = NA_SE_EV_BLOCK_SHAKE; - ActorAccessibility_InitPolicy(&policy, "Terrain cue helper", accessible_va_terrain_cue); + ActorAccessibility_InitPolicy(&policy, "Terrain cue helper", nullptr); policy.n = 1; policy.runsAlways = true; policy.distance = 500; - policy.initUserData = ActorAccessibility_InitTerrainCueState; - policy.cleanupUserData = ActorAccessibility_CleanupTerrainCueState; ActorAccessibility_AddSupportedActor(VA_TERRAIN_CUE, policy); AccessibleActor* actor = new AccessibleActor; @@ -1185,6 +1183,5 @@ void ActorAccessibility_InitActors() { actor->aimAssist.framesSinceAimAssist = 0; actor->aimAssist.frequency = 10; actor->policy = policy; - ActorAccessibility_InitTerrainCueState(actor); ActorAccessibility_AddTerrainCues(actor); } diff --git a/soh/soh/Enhancements/accessible-actors/ActorAccessibility.cpp b/soh/soh/Enhancements/accessible-actors/ActorAccessibility.cpp index 0533cb3ee..423bbdc24 100644 --- a/soh/soh/Enhancements/accessible-actors/ActorAccessibility.cpp +++ b/soh/soh/Enhancements/accessible-actors/ActorAccessibility.cpp @@ -94,7 +94,7 @@ class ActorAccessibility { Vec3f prevPos = { 0, 0, 0 }; s16 prevYaw = 0; bool extractSfx = false; - AccessibleActor* terrainCues = nullptr; + TerrainCueState* terrainCues = nullptr; VirtualActorList* currentSceneGlobal = nullptr; VirtualActorList* currentRoomLocal = nullptr; }; @@ -161,8 +161,6 @@ void ActorAccessibility_InitPolicy(ActorAccessibilityPolicy* policy, const char* policy->pitch = 1.5; policy->runsAlways = false; policy->volume = 1.0; - policy->initUserData = NULL; - policy->cleanupUserData = NULL; policy->pitchModifier = 0.1; policy->aimAssist.isProvider = false; policy->aimAssist.sfx = NA_SE_SY_HITPOINT_ALARM; @@ -187,7 +185,7 @@ void ActorAccessibility_AddSupportedActor(s16 type, ActorAccessibilityPolicy pol } void ActorAccessibility_AddTerrainCues(AccessibleActor* actor) { - aa->terrainCues = actor; + aa->terrainCues = InitTerrainCueState(actor); } ActorAccessibilityPolicy* ActorAccessibility_GetPolicyForActor(s16 type) { @@ -226,10 +224,6 @@ void ActorAccessibility_TrackNewActor(Actor* actor) { aa->trackedActors[actor] = accessibleActor.instanceID; aa->accessibleActorList[accessibleActor.instanceID] = accessibleActor; - if (policy->initUserData) { - AccessibleActor& savedActor = aa->accessibleActorList[accessibleActor.instanceID]; - policy->initUserData(&savedActor); - } } void ActorAccessibility_RemoveTrackedActor(Actor* actor) { @@ -241,8 +235,6 @@ void ActorAccessibility_RemoveTrackedActor(Actor* actor) { AccessibleActorList_t::iterator i2 = aa->accessibleActorList.find(id); if (i2 == aa->accessibleActorList.end()) return; - if (i2->second.policy.cleanupUserData) - i2->second.policy.cleanupUserData(&i2->second); ActorAccessibility_StopAllSoundsForActor(&i2->second); aa->accessibleActorList.erase(i2); } @@ -446,7 +438,7 @@ void ActorAccessibility_RunAccessibilityForAllActors(PlayState* play) { ActorAccessibility_RunAccessibilityForActor(play, &i->second); if (aa->terrainCues) { - ActorAccessibility_RunAccessibilityForActor(play, aa->terrainCues); + RunTerrainCueState(aa->terrainCues, play); } // Virtual actors for the current room and scene. @@ -642,11 +634,7 @@ AccessibleActor* ActorAccessibility_AddVirtualActor(VirtualActorList* list, VIRT VAList_t* l = (VAList_t*)list; l->push_back(actor); - size_t index = l->size() - 1; - AccessibleActor* savedActor = &(*l)[l->size() - 1]; - if (policy->initUserData) - policy->initUserData(savedActor); - return savedActor; + return &(*l)[l->size() - 1]; } void ActorAccessibility_InterpretCurrentScene(PlayState* play) { @@ -760,9 +748,8 @@ bool ActorAccessibility_InitAudio() { void ActorAccessibility_ShutdownAudio() { if (aa->isOn) { delete aa->audioEngine; - if (aa->terrainCues) { - ActorAccessibility_CleanupTerrainCueState(aa->terrainCues); - delete aa->terrainCues; + if (aa->terrainCues) { + DeleteTerrainCueState(aa->terrainCues); } aa->isOn = false; } diff --git a/soh/soh/Enhancements/accessible-actors/ActorAccessibility.h b/soh/soh/Enhancements/accessible-actors/ActorAccessibility.h index 328b0a681..b8424739a 100644 --- a/soh/soh/Enhancements/accessible-actors/ActorAccessibility.h +++ b/soh/soh/Enhancements/accessible-actors/ActorAccessibility.h @@ -5,10 +5,6 @@ struct AccessibleActor; // A callback that is run regularely as the game progresses in order to provide accessibility services for an actor. typedef void (*ActorAccessibilityCallback)(AccessibleActor*); -// A callback which allows AccessibleActor instances to initialize custom user data (called once per instantiation). -typedef void (*ActorAccessibilityUserDataInit)(AccessibleActor*); -// A callback that can be used to clean up user data when an actor is destroyed. -typedef void (*ActorAccessibilityUserDataCleanup)(AccessibleActor*); struct VirtualActorList; @@ -26,8 +22,6 @@ struct ActorAccessibilityPolicy { f32 volume; f32 pitchModifier; bool runsAlways; // If set, then the distance policy is ignored. - ActorAccessibilityUserDataInit initUserData; - ActorAccessibilityUserDataCleanup cleanupUserData; // Aim assist settings. struct { bool isProvider; // determines whether or not this actor supports aim assist. @@ -45,8 +39,8 @@ struct ActorAccessibilityPolicy { struct AccessibleActor { uint64_t instanceID; - Actor* actor; // This can be null for a virtual actor. - s16 id; // For real actors, we copy the ID of the actor. For virtual actors we have our own table of values which + Actor* actor; // null for virtual actors + s16 id; // For real actors, copy actor ID. For virtual actors we have our own table of values which // are out of range for real actors. f32 yDistToPlayer; f32 xzDistToPlayer; @@ -75,7 +69,6 @@ struct AccessibleActor { // Add more state as needed. ActorAccessibilityPolicy policy; // A copy, so it can be customized on a per-actor basis if needed. - void* userData; // Set by the policy. Can be anything. }; struct AimAssistProps { @@ -84,6 +77,11 @@ struct AimAssistProps { f32 pan; }; +struct TerrainCueState; +void DeleteTerrainCueState(TerrainCueState*); +TerrainCueState* InitTerrainCueState(AccessibleActor*); +void RunTerrainCueState(TerrainCueState*, PlayState*); + // Initialize accessibility. void ActorAccessibility_Init(); void ActorAccessibility_InitActors(); @@ -92,9 +90,6 @@ void ActorAccessibility_InitPolicy(ActorAccessibilityPolicy* policy, const char* void ActorAccessibility_InitPolicy(ActorAccessibilityPolicy* policy, const char* englishName, ActorAccessibilityCallback callback); void ActorAccessibility_InitPolicy(ActorAccessibilityPolicy* policy, const char* englishName, s16 sfx); -void ActorAccessibility_InitTerrainCueState(AccessibleActor* actor); -void ActorAccessibility_CleanupTerrainCueState(AccessibleActor* actor); -void accessible_va_terrain_cue(AccessibleActor* actor); uint64_t ActorAccessibility_GetNextID(); void ActorAccessibility_TrackNewActor(Actor* actor); diff --git a/soh/soh/Enhancements/accessible-actors/accessibility_cues.cpp b/soh/soh/Enhancements/accessible-actors/accessibility_cues.cpp index 353c4710b..7e6023d8c 100644 --- a/soh/soh/Enhancements/accessible-actors/accessibility_cues.cpp +++ b/soh/soh/Enhancements/accessible-actors/accessibility_cues.cpp @@ -10,8 +10,8 @@ void Player_GetSlopeDirection(CollisionPoly* floorPoly, Vec3f* slopeNormal, s16* void CollisionPoly_GetVertices(CollisionPoly* poly, Vec3s* vtxList, Vec3f* dest); f32 BgCheck_RaycastFloorImpl(PlayState* play, CollisionContext* colCtx, u16 xpFlags, CollisionPoly** outPoly, s32* outBgId, Vec3f* pos, Actor* actor, u32 arg7, f32 chkDist); -#include "soh/Enhancements/speechsynthesizer/SpeechSynthesizer.h" -#include "soh/Enhancements/tts/tts.h" +//#include "soh/Enhancements/speechsynthesizer/SpeechSynthesizer.h" +//#include "soh/Enhancements/tts/tts.h" } #define DETECTION_DISTANCE 500.0 #define MIN_INCLINE_DISTANCE 5.0 @@ -34,6 +34,7 @@ enum DiscoveredTerrain { DISCOVERED_GROUND, DISCOVERED_LAVA, }; + // Abstract class for terrain cue sound handling. Implementations should not allocate memory. These are always in-place // constructed in static memory owned by the TerrainCueDirection object. class TerrainCueSound { @@ -91,6 +92,7 @@ class TerrainCueSound { run(); } }; + class Incline : protected TerrainCueSound { float pitchModifier; @@ -151,6 +153,7 @@ class Decline : protected TerrainCueSound { pitchModifier = mod; } }; + class Ledge : protected TerrainCueSound { s8 savedType; // Distinguishes between a ledge link can fall from and one he can climb up. Vec3s probeRot; @@ -195,6 +198,7 @@ class Ledge : protected TerrainCueSound { } } }; + class Platform : protected TerrainCueSound { public: Platform(AccessibleActor* actor, Vec3f pos) : TerrainCueSound(actor, pos) { @@ -259,6 +263,7 @@ class Wall : protected TerrainCueSound { ActorAccessibility_SetSoundPitch(this, 0, pitchModifier); } }; + class Spike : protected TerrainCueSound { public: Spike(AccessibleActor* actor, Vec3f pos) : TerrainCueSound(actor, pos) { @@ -276,6 +281,7 @@ class Spike : protected TerrainCueSound { restFrames--; } }; + class Water : protected TerrainCueSound { public: Water(AccessibleActor* actor, Vec3f pos) : TerrainCueSound(actor, pos) { @@ -394,8 +400,8 @@ class TerrainCueDirection final { currentSound = NULL; terrainDiscovered = DISCOVERED_NOTHING; } - // Play a sound from the position of a previously discovered incline. + // Play a sound from the position of a previously discovered incline. void discoverIncline(Vec3f pos, float pitchModifier = 0) { if (terrainDiscovered == DISCOVERED_INCLINE) { incline.setPitchModifier(pitchModifier); @@ -409,8 +415,8 @@ class TerrainCueDirection final { currentSound = (TerrainCueSound*)&incline; terrainDiscovered = DISCOVERED_INCLINE; } - // Play a sound from the position of a previously discovered decline. + // Play a sound from the position of a previously discovered decline. void discoverDecline(Vec3f pos, float pitchModifier = 0) { if (terrainDiscovered == DISCOVERED_DECLINE) { incline.setPitchModifier(pitchModifier); @@ -424,8 +430,8 @@ class TerrainCueDirection final { currentSound = (TerrainCueSound*)&decline; terrainDiscovered = DISCOVERED_DECLINE; } - // Play a sound from the position of a previously discovered ledge. + // Play a sound from the position of a previously discovered ledge. void discoverLedge(Vec3f pos, s8 type = 0) { if (terrainDiscovered == DISCOVERED_LEDGE && ledge.type() == type) return; @@ -436,8 +442,8 @@ class TerrainCueDirection final { currentSound = (TerrainCueSound*)&ledge; terrainDiscovered = DISCOVERED_LEDGE; } - // Play a sound from the position of a previously discovered wall. + // Play a sound from the position of a previously discovered wall. void discoverWall(Vec3f pos) { Player* player = GET_PLAYER(actor->play); if (player->stateFlags1 & PLAYER_STATE1_FIRST_PERSON) { @@ -454,6 +460,7 @@ class TerrainCueDirection final { currentSound = (TerrainCueSound*)&wall; terrainDiscovered = DISCOVERED_WALL; } + void discoverSpike(Vec3f pos) { if (terrainDiscovered == DISCOVERED_SPIKE) return; @@ -494,6 +501,7 @@ class TerrainCueDirection final { currentSound = (TerrainCueSound*)&lava; terrainDiscovered = DISCOVERED_LAVA; } + // Find out how high a wall goes. f32 findWallHeight(Vec3f& pos, CollisionPoly* poly) { Player* player = GET_PLAYER(actor->play); @@ -552,9 +560,9 @@ class TerrainCueDirection final { &wallBgId, NULL, wallCheckHeight); return wallPoly; } + // Another copy/modify job from z_player.c. This function sets windspeed and wind direction, which are used for // pushing the player up and down slopes. "Inspired" by func_8083E318. - s32 computePushedSpeedEtc() { s32 pad; s16 sp4A; @@ -662,6 +670,7 @@ class TerrainCueDirection final { } return false; } + // Check if we're being pushed away from our intended destination. bool isPushedAway() { f32 dist = Math_Vec3f_DistXZ(&velocity, &expectedVelocity); @@ -669,6 +678,7 @@ class TerrainCueDirection final { return true; return false; } + bool proveClimbableStep() { setVelocity(); if (!move()) @@ -680,6 +690,7 @@ class TerrainCueDirection final { return false; return true; } + bool proveClimbable() { Vec3s ogRot = rot; Vec3f ogPos = pos; @@ -796,6 +807,7 @@ class TerrainCueDirection final { return true; } + bool isHeadOnCollision(Vec3f& wallPos, Vec3f& velocity) { return true; @@ -810,7 +822,6 @@ class TerrainCueDirection final { } // Perform all terrain detection and sound book keeping. Call once per frame. - float rdist(Vec3f pos) { Player* player = GET_PLAYER(actor->play); float xdist = fabs(pos.x - player->actor.world.pos.x); @@ -879,9 +890,9 @@ class TerrainCueDirection final { distToTravel = 1.0; Vec3f collisionResult; s32 bgId = 0; + // Don't be fooled: link being in the air does not mean we've found a dropoff. I mean... it could mean that, but // it's a little too late to do anything about it at that point anyway. - if (player->stateFlags3 & PLAYER_STATE3_MIDAIR || player->stateFlags2 & PLAYER_STATE2_HOPPING) { f32 floorHeight = 0; floorHeight = BgCheck_EntityRaycastFloor3(&actor->play->colCtx, &floorPoly, &floorBgId, &pos); @@ -1033,7 +1044,6 @@ class TerrainCueDirection final { } // this means that either the wall poly found above is not a vine or is NULL // the next three secections check infront and behind the probe for wall polys - // if (moveMethod != 2) { prevPos = pos; rot.y = player->actor.shape.rot.y; @@ -1157,7 +1167,6 @@ class TerrainCueDirection final { } if (isPushedAway() && player->stateFlags1 != PLAYER_STATE1_CLIMBING_LADDER) { - // Call this a wall for now. discoverWall(pos); break; } @@ -1272,16 +1281,16 @@ class TerrainCueDirection final { CollisionPoly* wallPoly = checkWall(pos, prevPos, wallPos); if (wallPoly == NULL) continue; - // Is this a spiked wall? Vec3f polyVerts[3]; + // Is this a spiked wall? CollisionPoly_GetVertices(wallPoly, colCtx->colHeader->vtxList, polyVerts); if (SurfaceType_IsWallDamage(&actor->play->colCtx, wallPoly, BGCHECK_SCENE)) { discoverSpike(pos); break; } - // is this a ladder or vine wall? + // is this a ladder or vine wall? wallHeight = findWallHeight(pos, wallPoly); if (wallHeight <= player->ageProperties->unk_0C && player->stateFlags1 != PLAYER_STATE1_CLIMBING_LADDER) { @@ -1342,24 +1351,6 @@ class TerrainCueDirection final { } }; -typedef struct { - TerrainCueDirection directions[3]; // Directly ahead of Link, 90 degrees to his left and 90 degrees to his right. -} TerrainCueState; - -// Callback for initialization of terrain cue state. -void ActorAccessibility_InitTerrainCueState(AccessibleActor* actor) { - TerrainCueState* state = new TerrainCueState{ { - { actor, { 0, 0, 0 } }, - { actor, { 0, 16384, 0 } }, - { actor, { 0, -16384, 0 } }, - } }; - - actor->userData = state; -} -void ActorAccessibility_CleanupTerrainCueState(AccessibleActor* actor) { - delete (TerrainCueState*)actor->userData; - actor->userData = NULL; -} // Computes a relative angle based on Link's (or some other actor's) current angle. Vec3s ActorAccessibility_ComputeRelativeAngle(Vec3s* origin, Vec3s* offset) { Vec3s rot = *origin; @@ -1369,9 +1360,36 @@ Vec3s ActorAccessibility_ComputeRelativeAngle(Vec3s* origin, Vec3s* offset) { return rot; } -void accessible_va_terrain_cue(AccessibleActor* actor) { - TerrainCueState* state = (TerrainCueState*)actor->userData; +struct TerrainCueState { + AccessibleActor* actor; + TerrainCueDirection directions[3]; // Directly ahead of Link, 90 degrees to his left and 90 degrees to his right - for (int i = 0; i < 3; i++) - state->directions[i].scan(); + TerrainCueState(AccessibleActor* actor) : actor(actor), directions{ + { actor, { 0, 0, 0 } }, + { actor, { 0, 16384, 0 } }, + { actor, { 0, -16384, 0 } }, + } {} + + ~TerrainCueState() { + delete actor; + } + + void Run(PlayState* play) { + ActorAccessibility_RunAccessibilityForActor(play, actor); + for (int i = 0; i < 3; i++) { + directions[i].scan(); + } + } +}; + +TerrainCueState* InitTerrainCueState(AccessibleActor* actor) { + return new TerrainCueState(actor); +} + +void DeleteTerrainCueState(TerrainCueState* terrainCues) { + delete terrainCues; +} + +void RunTerrainCueState(TerrainCueState* terrainCues, PlayState* play) { + terrainCues->Run(play); } \ No newline at end of file