diff --git a/MarathonRecomp/api/Marathon.h b/MarathonRecomp/api/Marathon.h index 5c08f6fe..49069f9a 100644 --- a/MarathonRecomp/api/Marathon.h +++ b/MarathonRecomp/api/Marathon.h @@ -20,6 +20,7 @@ #include "Sonicteam/AlertWindowTask.h" #include "Sonicteam/AppMarathon.h" #include "Sonicteam/AudioEngineXenon.h" +#include "Sonicteam/BasicIScriptParamsDesc.h" #include "Sonicteam/ButtonWindowTask.h" #include "Sonicteam/CObjBalloonIconDrawable.h" #include "Sonicteam/Camera/CameraMode.h" @@ -55,6 +56,7 @@ #include "Sonicteam/HintWindowTask.h" #include "Sonicteam/HudTextParts.h" #include "Sonicteam/ImageFilter.h" +#include "Sonicteam/KeyframedPath.h" #include "Sonicteam/MainDisplayTask.h" #include "Sonicteam/MainMenuTask.h" #include "Sonicteam/MainMode.h" @@ -85,8 +87,16 @@ #include "Sonicteam/NoSyncThread.h" #include "Sonicteam/ObjectVehicle.h" #include "Sonicteam/ObjectVehicleBike.h" +#include "Sonicteam/Package.h" +#include "Sonicteam/PackageBinary.h" +#include "Sonicteam/PathAnimation/Animation.h" +#include "Sonicteam/PathAnimation/Controller.h" +#include "Sonicteam/PathAnimation/Entity.h" #include "Sonicteam/PauseAdapter.h" #include "Sonicteam/PauseTask.h" +#include "Sonicteam/Player/AllListener.h" +#include "Sonicteam/Player/Gravity.h" +#include "Sonicteam/Player/GroundListener.h" #include "Sonicteam/Player/GroundRayListener.h" #include "Sonicteam/Player/ICollisionListener.h" #include "Sonicteam/Player/ICollisionListenerTemplate.h" @@ -94,10 +104,16 @@ #include "Sonicteam/Player/IEventerListener.h" #include "Sonicteam/Player/IExportExternalFlag.h" #include "Sonicteam/Player/IExportPostureRequestFlag.h" +#include "Sonicteam/Player/IExportVehicleFlag.h" #include "Sonicteam/Player/IExportWeaponRequestFlag.h" #include "Sonicteam/Player/IFlagCommunicator.h" +#include "Sonicteam/Player/IForce.h" #include "Sonicteam/Player/IGauge.h" +#include "Sonicteam/Player/IImportAnimation.h" +#include "Sonicteam/Player/ILoad.h" +#include "Sonicteam/Player/IModel.h" #include "Sonicteam/Player/INotification.h" +#include "Sonicteam/Player/IPath.h" #include "Sonicteam/Player/IPlugIn.h" #include "Sonicteam/Player/IPostureControl.h" #include "Sonicteam/Player/IPosturePlugIn.h" @@ -113,14 +129,23 @@ #include "Sonicteam/Player/Input/IListener.h" #include "Sonicteam/Player/Input/ListenerNormal.h" #include "Sonicteam/Player/Input/TimedAction.h" +#include "Sonicteam/Player/Load.h" +#include "Sonicteam/Player/MovableBody.h" #include "Sonicteam/Player/Object.h" +#include "Sonicteam/Player/PhysicsBodyList.h" #include "Sonicteam/Player/PostureControl.h" +#include "Sonicteam/Player/PostureEdge.h" +#include "Sonicteam/Player/PostureVehicle.h" +#include "Sonicteam/Player/RealGroundRayListener.h" #include "Sonicteam/Player/RootFrame.h" +#include "Sonicteam/Player/RotationGravityAxis.h" #include "Sonicteam/Player/Score.h" #include "Sonicteam/Player/SonicGauge.h" #include "Sonicteam/Player/State/CommonContext.h" #include "Sonicteam/Player/State/CommonFall.h" +#include "Sonicteam/Player/State/CommonGrind.h" #include "Sonicteam/Player/State/CommonObject.h" +#include "Sonicteam/Player/State/CommonSpringTemplate.h" #include "Sonicteam/Player/State/ContextSpeedAndJump.h" #include "Sonicteam/Player/State/ICommonContext.h" #include "Sonicteam/Player/State/ICommonContextIF.h" @@ -130,9 +155,12 @@ #include "Sonicteam/Player/State/Object2.h" #include "Sonicteam/Player/State/SonicContext.h" #include "Sonicteam/Player/State/SonicObject.h" +#include "Sonicteam/Player/State/SonicState.h" #include "Sonicteam/Player/State/TailsContext.h" #include "Sonicteam/Player/State/TailsFlight.h" #include "Sonicteam/Player/Unit/ITestCase.h" +#include "Sonicteam/Player/WallListener.h" +#include "Sonicteam/Player/WallRayListener.h" #include "Sonicteam/Player/Weapon/SonicWeapons.h" #include "Sonicteam/Player/Zock.h" #include "Sonicteam/PropFixture.h" @@ -187,8 +215,10 @@ #include "Sonicteam/SaveDataTask.h" #include "Sonicteam/SaveDataTaskXENON.h" #include "Sonicteam/SelectWindowTask.h" +#include "Sonicteam/SoX/AI/State.h" #include "Sonicteam/SoX/AI/StateMachine.h" #include "Sonicteam/SoX/ApplicationXenon.h" +#include "Sonicteam/SoX/Array.h" #include "Sonicteam/SoX/Audio/Cue.h" #include "Sonicteam/SoX/Audio/IAudioEngine.h" #include "Sonicteam/SoX/Audio/Player.h" @@ -199,12 +229,14 @@ #include "Sonicteam/SoX/Engine/DocMode.h" #include "Sonicteam/SoX/Engine/RenderProcess.h" #include "Sonicteam/SoX/Engine/Task.h" +#include "Sonicteam/SoX/Graphics/AnimationUserDataListener.h" #include "Sonicteam/SoX/Graphics/Device.h" #include "Sonicteam/SoX/Graphics/Frame.h" #include "Sonicteam/SoX/Graphics/FrameGP.h" #include "Sonicteam/SoX/Graphics/FrameObserver.h" #include "Sonicteam/SoX/Graphics/Technique.h" #include "Sonicteam/SoX/Graphics/TechniqueFXL.h" +#include "Sonicteam/SoX/Graphics/Texture.h" #include "Sonicteam/SoX/Graphics/Transforms.h" #include "Sonicteam/SoX/Graphics/Vertex.h" #include "Sonicteam/SoX/Graphics/Xenon/DeviceXenon.h" @@ -212,32 +244,43 @@ #include "Sonicteam/SoX/IResource.h" #include "Sonicteam/SoX/IResource2.h" #include "Sonicteam/SoX/IResourceMgr.h" +#include "Sonicteam/SoX/Input/Listener.h" #include "Sonicteam/SoX/Input/Manager.h" #include "Sonicteam/SoX/LinkNode.h" +#include "Sonicteam/SoX/Math/Math.h" #include "Sonicteam/SoX/Math/Matrix.h" #include "Sonicteam/SoX/Math/Quaternion.h" #include "Sonicteam/SoX/Math/Vector.h" +#include "Sonicteam/SoX/Math/__vector.h" #include "Sonicteam/SoX/Message.h" #include "Sonicteam/SoX/MessageReceiver.h" #include "Sonicteam/SoX/Object.h" +#include "Sonicteam/SoX/Physics/Body.h" #include "Sonicteam/SoX/Physics/Entity.h" +#include "Sonicteam/SoX/Physics/EntityRef.h" #include "Sonicteam/SoX/Physics/Havok/EntityHavok.h" #include "Sonicteam/SoX/Physics/Havok/EntityHavokImp.h" #include "Sonicteam/SoX/Physics/Havok/PhantomHavok.h" +#include "Sonicteam/SoX/Physics/Havok/RayCastHavok.h" +#include "Sonicteam/SoX/Physics/Havok/ShapeCastHavok.h" #include "Sonicteam/SoX/Physics/Havok/WorldHavok.h" #include "Sonicteam/SoX/Physics/IntersectEvent.h" #include "Sonicteam/SoX/Physics/IntersectListener.h" #include "Sonicteam/SoX/Physics/Phantom.h" #include "Sonicteam/SoX/Physics/PhantomListener.h" +#include "Sonicteam/SoX/Physics/RayCast.h" #include "Sonicteam/SoX/Physics/Shape.h" +#include "Sonicteam/SoX/Physics/ShapeCast.h" #include "Sonicteam/SoX/Physics/ShapeCastEvent.h" #include "Sonicteam/SoX/Physics/ShapeCastListener.h" #include "Sonicteam/SoX/Physics/World.h" #include "Sonicteam/SoX/RefCountObject.h" #include "Sonicteam/SoX/RefSharedPointer.h" +#include "Sonicteam/SoX/ResourceManager.h" #include "Sonicteam/SoX/Scenery/Camera.h" #include "Sonicteam/SoX/Scenery/CameraEventCallback.h" #include "Sonicteam/SoX/Scenery/CameraImp.h" +#include "Sonicteam/SoX/Scenery/Clump.h" #include "Sonicteam/SoX/Scenery/Drawable.h" #include "Sonicteam/SoX/Thread.h" #include "Sonicteam/StdImageFilters/BurnoutBlurFilter.h" @@ -263,12 +306,14 @@ #include "hk330/hkArray.h" #include "hk330/hkReferencedObject.h" #include "hk330/hkpBroadPhaseHandle.h" +#include "hk330/hkpBvShape.h" #include "hk330/hkpCdBody.h" #include "hk330/hkpCollidable.h" #include "hk330/hkpCollidableCollidableFilter.h" #include "hk330/hkpCollisionFilter.h" #include "hk330/hkpEntity.h" #include "hk330/hkpLinkedCollidable.h" +#include "hk330/hkpMotion.h" #include "hk330/hkpPhantom.h" #include "hk330/hkpProperty.h" #include "hk330/hkpRayCollidableFilter.h" @@ -276,9 +321,17 @@ #include "hk330/hkpRigidBody.h" #include "hk330/hkpShape.h" #include "hk330/hkpShapeCollectionFilter.h" +#include "hk330/hkpShapeContainer.h" +#include "hk330/hkpShapeSphere.h" +#include "hk330/hkpSingleShapeContainer.h" #include "hk330/hkpTypedBroadPhaseHandle.h" #include "hk330/hkpWorld.h" #include "hk330/hkpWorldObject.h" +#include "stdx/RTTI.h" +#include "stdx/deque.h" +#include "stdx/list.h" +#include "stdx/map.h" #include "stdx/string.h" +#include "stdx/type_info.h" #include "stdx/vector.h" #include "stdx/wstring.h" diff --git a/MarathonRecomp/api/Marathon.inl b/MarathonRecomp/api/Marathon.inl index c6b017eb..cfd8078b 100644 --- a/MarathonRecomp/api/Marathon.inl +++ b/MarathonRecomp/api/Marathon.inl @@ -1,6 +1,7 @@ #pragma once #include +#include #include constexpr float RAD2DEGf = 57.2958f; @@ -24,6 +25,9 @@ constexpr double DEG2RAD = 0.01745329238474369; #define MARATHON_VIRTUAL_FUNCTION(returnType, virtualIndex, ...) \ GuestToHostFunction(*(be*)(g_memory.Translate(*(be*)(this) + (4 * virtualIndex))), __VA_ARGS__) +#define MARATHON_CALL_VIRTUAL_FUNCTION(base, returnType, func, ...) \ + GuestToHostFunction((Vftable*)(static_cast(this)->m_pVftable.get())->*func, ##__VA_ARGS__) + struct marathon_null_ctor {}; inline std::vector ParseTextVariables(const char* pVariables) @@ -138,3 +142,13 @@ inline void printU16(const uint16_t* str, bool endianSwap = false) printf("\n"); } + +struct MARATHON_NULL_CTOR {}; + +struct MARATHON_STD_MAP_CONST_CHAR_COMPARE +{ + bool operator()(xpointer lhs, xpointer rhs) const + { + return std::strcmp(lhs.get(), rhs.get()) < 0; + } +}; diff --git a/MarathonRecomp/api/Sonicteam/ActorManager.h b/MarathonRecomp/api/Sonicteam/ActorManager.h index 437c2c80..6f8c3126 100644 --- a/MarathonRecomp/api/Sonicteam/ActorManager.h +++ b/MarathonRecomp/api/Sonicteam/ActorManager.h @@ -8,16 +8,13 @@ namespace Sonicteam class ActorManager { public: - be m_aActorIDs[0xFFFF]; - xpointer m_aActors[0xFFFF]; - be m_LastActorID; - be m_LastActorIndex; - MARATHON_INSERT_PADDING(4); - }; + be m_ActorID[0xFFFF]; + xpointer m_Actor[0xFFFF]; + be m_LastActorID; + be m_LastActorIndex; - MARATHON_ASSERT_OFFSETOF(ActorManager, m_aActorIDs, 0x00); - MARATHON_ASSERT_OFFSETOF(ActorManager, m_aActors, 0x3FFFC); - MARATHON_ASSERT_OFFSETOF(ActorManager, m_LastActorID, 0x7FFF8); - MARATHON_ASSERT_OFFSETOF(ActorManager, m_LastActorIndex, 0x7FFFC); - MARATHON_ASSERT_SIZEOF(ActorManager, 0x80004); + Sonicteam::Actor* FindActor(uint32_t ActorID); + }; } + +#include "ActorManager.inl" diff --git a/MarathonRecomp/api/Sonicteam/ActorManager.inl b/MarathonRecomp/api/Sonicteam/ActorManager.inl new file mode 100644 index 00000000..829ef1b9 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/ActorManager.inl @@ -0,0 +1,27 @@ +#pragma once + +namespace Sonicteam +{ + inline Actor* ActorManager::FindActor(uint32_t ActorID) + { + unsigned int left = 0; + unsigned int right = this->m_LastActorIndex - 1; + int Index = 0; + + while (left <= right) { + unsigned int mid = left + (right - left) / 2; + if (this->m_ActorID[mid] == ActorID) { + Index = mid; + break; + } + if (this->m_ActorID[mid] < ActorID) { + left = mid + 1; + } + else { + right = mid - 1; + } + } + if (!this->m_Actor[Index]) return 0; + return this->m_Actor[Index]; + } +} diff --git a/MarathonRecomp/api/Sonicteam/BasicIScriptParamsDesc.h b/MarathonRecomp/api/Sonicteam/BasicIScriptParamsDesc.h new file mode 100644 index 00000000..927be15e --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/BasicIScriptParamsDesc.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +namespace Sonicteam +{ + class BasicIScriptParamsDesc + { + xpointer m_pDefaultDesc; // Points to static ? + }; + + // Static 0x8202AC38 ? +} diff --git a/MarathonRecomp/api/Sonicteam/DocMarathonImp.h b/MarathonRecomp/api/Sonicteam/DocMarathonImp.h index 5284d332..e73420bd 100644 --- a/MarathonRecomp/api/Sonicteam/DocMarathonImp.h +++ b/MarathonRecomp/api/Sonicteam/DocMarathonImp.h @@ -1,26 +1,49 @@ #pragma once #include +#include #include #include -#include -#include +#include +#include +#include +#include +#include namespace Sonicteam { + class RenderTargetContainer; + class SFXAgent; + class DocMarathonImp : public SoX::Engine::Doc { public: - MARATHON_INSERT_PADDING(0x40); - stdx::vector> m_vspInputManager; + MARATHON_INSERT_PADDING(4); + xpointer m_pMyGraphicsDevice; + MARATHON_INSERT_PADDING(0x38); + stdx::vector> m_vspInputManagers; MARATHON_INSERT_PADDING(0x24); bool m_VFrame; - MARATHON_INSERT_PADDING(0x55B58); + MARATHON_INSERT_PADDING(4); + xpointer m_pRenderTargetContainer; + xpointer m_pSFXAgent; + MARATHON_INSERT_PADDING(0x8); + be m_DocSpeed; + be m_PauseFlags; + MARATHON_INSERT_PADDING(0x8); + xpointer> m_lnThread; + MARATHON_INSERT_PADDING(0x288); + xpointer m_pParticleManager; + MARATHON_INSERT_PADDING(0x15D0); + xpointer m_pRaderMapManager; + MARATHON_INSERT_PADDING(0x542D0); be m_aPadIDs[4]; MARATHON_INSERT_PADDING(0x2C); }; - MARATHON_ASSERT_OFFSETOF(DocMarathonImp, m_vspInputManager, 0x9C); + MARATHON_ASSERT_OFFSETOF(DocMarathonImp, m_DocSpeed, 0xE8); + MARATHON_ASSERT_OFFSETOF(DocMarathonImp, m_PauseFlags, 0xEC); + MARATHON_ASSERT_OFFSETOF(DocMarathonImp, m_vspInputManagers, 0x9C); MARATHON_ASSERT_OFFSETOF(DocMarathonImp, m_VFrame, 0xD0); MARATHON_ASSERT_OFFSETOF(DocMarathonImp, m_aPadIDs, 0x55C2C); MARATHON_ASSERT_SIZEOF(DocMarathonImp, 0x55C68); diff --git a/MarathonRecomp/api/Sonicteam/KeyframedPath.h b/MarathonRecomp/api/Sonicteam/KeyframedPath.h new file mode 100644 index 00000000..c20a422d --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/KeyframedPath.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +namespace Sonicteam +{ + class KeyframedPath : public PathAnimation::Animation + { + MARATHON_INSERT_PADDING(0x14); + }; + + MARATHON_ASSERT_SIZEOF(KeyframedPath, 0x1C); +} diff --git a/MarathonRecomp/api/Sonicteam/Package.h b/MarathonRecomp/api/Sonicteam/Package.h new file mode 100644 index 00000000..648ea566 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Package.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +namespace Sonicteam +{ + class PackageMgr; + + class Package : public SoX::IResource2 {}; + + MARATHON_ASSERT_SIZEOF(Package, 0x64); +} diff --git a/MarathonRecomp/api/Sonicteam/PackageBinary.h b/MarathonRecomp/api/Sonicteam/PackageBinary.h new file mode 100644 index 00000000..fd155fff --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/PackageBinary.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +namespace Sonicteam +{ + class PackageBinary : public Package + { + public: + MARATHON_INSERT_PADDING(0x18); + }; + + MARATHON_ASSERT_SIZEOF(PackageBinary, 0x7C); +} diff --git a/MarathonRecomp/api/Sonicteam/PathAnimation/Animation.h b/MarathonRecomp/api/Sonicteam/PathAnimation/Animation.h new file mode 100644 index 00000000..cdf1d22c --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/PathAnimation/Animation.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace Sonicteam::PathAnimation +{ + class Animation : public SoX::RefCountObject {}; + + MARATHON_ASSERT_SIZEOF(Animation, 0x8); +} diff --git a/MarathonRecomp/api/Sonicteam/PathAnimation/Controller.h b/MarathonRecomp/api/Sonicteam/PathAnimation/Controller.h new file mode 100644 index 00000000..133fa272 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/PathAnimation/Controller.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include +#include + +namespace Sonicteam::PathAnimation +{ + class Entity; + + class Controller : public SoX::RefCountObject + { + public: + xpointer m_pEntity; + SoX::LinkNode m_lnEntity; + SoX::Math::Vector m_Position; + SoX::Math::Vector m_Up; + SoX::Math::Vector m_Tangent; + }; + + MARATHON_ASSERT_SIZEOF(Controller, 0x50); + MARATHON_ASSERT_OFFSETOF(Controller, m_pEntity, 0x8); + MARATHON_ASSERT_OFFSETOF(Controller, m_lnEntity, 0xC); + MARATHON_ASSERT_OFFSETOF(Controller, m_Position, 0x20); + MARATHON_ASSERT_OFFSETOF(Controller, m_Up, 0x30); + MARATHON_ASSERT_OFFSETOF(Controller, m_Tangent, 0x40); +} diff --git a/MarathonRecomp/api/Sonicteam/PathAnimation/Entity.h b/MarathonRecomp/api/Sonicteam/PathAnimation/Entity.h new file mode 100644 index 00000000..ca4639ae --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/PathAnimation/Entity.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include +#include + +namespace Sonicteam::PathAnimation +{ + class Controller; + class Animation; + + class Entity : public SoX::RefCountObject + { + public: + SoX::LinkNode m_lnController; + SoX::RefSharedPointer m_PathAnimation; + }; + + MARATHON_ASSERT_SIZEOF(Entity, 0x18); + MARATHON_ASSERT_OFFSETOF(Entity, m_lnController, 0x8); + MARATHON_ASSERT_OFFSETOF(Entity, m_PathAnimation, 0x14); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/AllListener.h b/MarathonRecomp/api/Sonicteam/Player/AllListener.h new file mode 100644 index 00000000..b512cf8f --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/AllListener.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace Sonicteam::Player +{ + class AllListener : public ICollisionListenerTemplate + { + public: + SoX::Math::Vector m_Position; + SoX::Math::Vector m_Vector90; + be m_Radius; + uint8_t m_FieldA4; // Flag, Type , Mode ????, 1 or 0 + SoX::Math::Vector m_aContactNormals[6]; // m_CurrentSurfaceContacts, all contacts? + be m_Field110; + }; + + MARATHON_ASSERT_SIZEOF(AllListener, 0x120); + MARATHON_ASSERT_OFFSETOF(AllListener, m_Position, 0x80); + MARATHON_ASSERT_OFFSETOF(AllListener, m_Vector90, 0x90); + MARATHON_ASSERT_OFFSETOF(AllListener, m_Radius, 0xA0); + MARATHON_ASSERT_OFFSETOF(AllListener, m_FieldA4, 0xA4); + MARATHON_ASSERT_OFFSETOF(AllListener, m_aContactNormals, 0xB0); + MARATHON_ASSERT_OFFSETOF(AllListener, m_Field110, 0x110); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/Gravity.h b/MarathonRecomp/api/Sonicteam/Player/Gravity.h new file mode 100644 index 00000000..153ec94c --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/Gravity.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace Sonicteam::Player +{ + class Gravity : public IForce, public IVariable, public IStepable + { + public: + be c_gravity; + be c_pass_fluid; + bool m_Enabled; // ground = false, air = true + be m_DownForce; + SoX::Math::Vector m_DownDirection; + + }; + + MARATHON_ASSERT_SIZEOF(Gravity, 0x60); + MARATHON_ASSERT_OFFSETOF(Gravity, c_gravity, 0x38); + MARATHON_ASSERT_OFFSETOF(Gravity, c_pass_fluid, 0x3C); + MARATHON_ASSERT_OFFSETOF(Gravity, m_Enabled, 0x40); + MARATHON_ASSERT_OFFSETOF(Gravity, m_DownForce, 0x44); + MARATHON_ASSERT_OFFSETOF(Gravity, m_DownDirection, 0x50); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/GroundListener.h b/MarathonRecomp/api/Sonicteam/Player/GroundListener.h new file mode 100644 index 00000000..952051a8 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/GroundListener.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include +#include +#include + +namespace Sonicteam::Player +{ + class GroundListener: public ICollisionListenerTemplate {}; + + MARATHON_ASSERT_SIZEOF(GroundListener, 0x80); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/GroundRayListener.h b/MarathonRecomp/api/Sonicteam/Player/GroundRayListener.h index 497126d5..af0df9f9 100644 --- a/MarathonRecomp/api/Sonicteam/Player/GroundRayListener.h +++ b/MarathonRecomp/api/Sonicteam/Player/GroundRayListener.h @@ -4,26 +4,10 @@ #include #include #include -#include -#include -#include namespace Sonicteam::Player { - class GroundRayListener : public ICollisionListenerTemplate - { - public: - SoX::Math::Vector m_ContactPosition; - SoX::Math::Vector m_ContactNormal; - be m_RayDistance; - be m_RayFlags; - SoX::LinkRef m_ContactEntity; - }; + class GroundRayListener : public ICollisionListenerTemplate {}; - MARATHON_ASSERT_OFFSETOF(GroundRayListener, m_ContactPosition, 0x50); - MARATHON_ASSERT_OFFSETOF(GroundRayListener, m_ContactNormal, 0x60); - MARATHON_ASSERT_OFFSETOF(GroundRayListener, m_RayDistance, 0x70); - MARATHON_ASSERT_OFFSETOF(GroundRayListener, m_RayFlags, 0x74); - MARATHON_ASSERT_OFFSETOF(GroundRayListener, m_ContactEntity, 0x78); - MARATHON_ASSERT_SIZEOF(GroundRayListener, 0x90); + MARATHON_ASSERT_SIZEOF(GroundRayListener, 0x80); } diff --git a/MarathonRecomp/api/Sonicteam/Player/ICollisionListener.h b/MarathonRecomp/api/Sonicteam/Player/ICollisionListener.h index 6d984889..c86fa432 100644 --- a/MarathonRecomp/api/Sonicteam/Player/ICollisionListener.h +++ b/MarathonRecomp/api/Sonicteam/Player/ICollisionListener.h @@ -1,24 +1,60 @@ #pragma once #include +#include +#include +#include namespace Sonicteam::Player { class ICollisionListener { public: - xpointer m_pVftable; - MARATHON_INSERT_PADDING(0x0C); - be m_FlagsA; - be m_FlagsB; - be m_FlagsC; - MARATHON_INSERT_PADDING(4); - SoX::Math::Vector m_SurfaceNormal; + struct Vftable + { + be fpDestroy; + be fpSetPostureRequestFlag; + be fpUpdate; + be fpGetContactPosition; + be fpGetContactNormal; + be fpGetLength; + be fpGetCollisionFlag; + be GetContactEntity; + be fpGetCurrentSurfaceContacts; + be fpGetRayFlag; + }; + + xpointer m_pVftable; + MARATHON_INSERT_PADDING(0xC); + be m_Flag1; + be m_CurrentSurfaceContacts; + be m_PostureRequestFlag; + SoX::Math::Vector m_CollisionNormal; + + void SetPostureRequestFlag(uint32_t postureRequestFlag); + + void Update(); + + SoX::Math::Vector GetContactPosition(); + + SoX::Math::Vector GetContactNormal(); + + float GetLength(float normalize); // GetLength(), of what? + + uint32_t GetCollisionFlag(); // GetCollisionFlag() + + SoX::Physics::EntityRefWrapper GetContactEntity(); + + uint32_t GetCurrentSurfaceContacts(); + + uint32_t GetRayFlag(); }; - MARATHON_ASSERT_OFFSETOF(ICollisionListener, m_pVftable, 0x00); - MARATHON_ASSERT_OFFSETOF(ICollisionListener, m_FlagsA, 0x10); - MARATHON_ASSERT_OFFSETOF(ICollisionListener, m_FlagsB, 0x14); - MARATHON_ASSERT_OFFSETOF(ICollisionListener, m_FlagsC, 0x18); - MARATHON_ASSERT_OFFSETOF(ICollisionListener, m_SurfaceNormal, 0x20); + MARATHON_ASSERT_SIZEOF(ICollisionListener, 0x30); + MARATHON_ASSERT_OFFSETOF(ICollisionListener, m_Flag1, 0x10); + MARATHON_ASSERT_OFFSETOF(ICollisionListener, m_CurrentSurfaceContacts, 0x14); + MARATHON_ASSERT_OFFSETOF(ICollisionListener, m_PostureRequestFlag, 0x18); + MARATHON_ASSERT_OFFSETOF(ICollisionListener, m_CollisionNormal, 0x20); } + +#include "ICollisionListener.inl" diff --git a/MarathonRecomp/api/Sonicteam/Player/ICollisionListener.inl b/MarathonRecomp/api/Sonicteam/Player/ICollisionListener.inl new file mode 100644 index 00000000..0601b54f --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/ICollisionListener.inl @@ -0,0 +1,55 @@ +#pragma once + +namespace Sonicteam::Player +{ + inline void ICollisionListener::SetPostureRequestFlag(uint32_t postureRequestFlag) + { + GuestToHostFunction(m_pVftable->fpSetPostureRequestFlag, this, postureRequestFlag); + } + + inline void ICollisionListener::Update() + { + GuestToHostFunction(m_pVftable->fpUpdate, this); + } + + inline SoX::Math::Vector ICollisionListener::GetContactPosition() + { + guest_heap_var ret; + GuestToHostFunction(m_pVftable->fpGetContactPosition, ret.get(), this); + return *ret; + } + + inline SoX::Math::Vector ICollisionListener::GetContactNormal() + { + guest_heap_var result; + GuestToHostFunction(m_pVftable->fpGetContactNormal, result.get(), this); + return *result; + } + + inline float ICollisionListener::GetLength(float normalize = 0.0) + { + return GuestToHostFunction(m_pVftable->fpGetLength, this, normalize); + } + + inline uint32_t ICollisionListener::GetCollisionFlag() + { + return GuestToHostFunction(m_pVftable->fpGetCollisionFlag, this); + } + + inline SoX::Physics::EntityRefWrapper ICollisionListener::GetContactEntity() + { + guest_heap_var ret; + GuestToHostFunction(m_pVftable->GetContactEntity, ret.get(), this); + return (SoX::Physics::EntityRefWrapper)ret.get(); + } + + inline uint32_t ICollisionListener::GetCurrentSurfaceContacts() + { + return GuestToHostFunction(m_pVftable->fpGetCurrentSurfaceContacts, this); + } + + inline uint32_t ICollisionListener::GetRayFlag() + { + return GuestToHostFunction(m_pVftable->fpGetRayFlag, this); + } +} diff --git a/MarathonRecomp/api/Sonicteam/Player/ICollisionListenerTemplate.h b/MarathonRecomp/api/Sonicteam/Player/ICollisionListenerTemplate.h index 1c89999a..acb27728 100644 --- a/MarathonRecomp/api/Sonicteam/Player/ICollisionListenerTemplate.h +++ b/MarathonRecomp/api/Sonicteam/Player/ICollisionListenerTemplate.h @@ -2,9 +2,37 @@ #include #include +#include +#include +#include +#include namespace Sonicteam::Player { - template - class ICollisionListenerTemplate : public ICollisionListener, public TListener {}; -} + class TCast + { + MARATHON_INSERT_PADDING(8); + }; + + class TEvent {}; + + template + class ICollisionListenerTemplate: public ICollisionListener, public Cast + { + public: + SoX::Math::Vector m_ContactPosition; + SoX::Math::Vector m_ContactNormal; + be m_RayDistance; // Not sure + be m_RayFlag; // Not sure + SoX::LinkRef m_lrContactEntity; + }; + + typedef ICollisionListenerTemplate ICollisionListenerTemplate_Default; + + MARATHON_ASSERT_SIZEOF(ICollisionListenerTemplate_Default, 0x80); + MARATHON_ASSERT_OFFSETOF(ICollisionListenerTemplate_Default, m_ContactPosition, 0x40); + MARATHON_ASSERT_OFFSETOF(ICollisionListenerTemplate_Default, m_ContactNormal, 0x50); + MARATHON_ASSERT_OFFSETOF(ICollisionListenerTemplate_Default, m_RayDistance, 0x60); + MARATHON_ASSERT_OFFSETOF(ICollisionListenerTemplate_Default, m_RayFlag, 0x64); + MARATHON_ASSERT_OFFSETOF(ICollisionListenerTemplate_Default, m_lrContactEntity, 0x68); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/IExportVehicleFlag.h b/MarathonRecomp/api/Sonicteam/Player/IExportVehicleFlag.h new file mode 100644 index 00000000..46da3ce0 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/IExportVehicleFlag.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace Sonicteam::Player +{ + class IExportVehicleFlag + { + public: + xpointer m_pVftable; + }; +} diff --git a/MarathonRecomp/api/Sonicteam/Player/IFlagCommunicator.h b/MarathonRecomp/api/Sonicteam/Player/IFlagCommunicator.h index e178006c..49cceb8b 100644 --- a/MarathonRecomp/api/Sonicteam/Player/IFlagCommunicator.h +++ b/MarathonRecomp/api/Sonicteam/Player/IFlagCommunicator.h @@ -7,9 +7,40 @@ namespace Sonicteam::Player class IFlagCommunicator { public: - xpointer m_pVftable; + struct Vftable + { + be fpDestroy; + be fpImportICommonContextIFFlag; + be fpImportIPostureControlFlag; + be fpFunc0xC; + be fpImportExternalFlag; + be fpImportICommonContextIFFlag2; + be fpImportICommonContextIFFlag3; + be fpImportIModelAnimationFlag; + be fpImportPostureRequestFlag; + be fpImportWeaponRequestFlag; + be fpImportUpgradeFlag; + be fpImportVehicleFlag; + be fpImportAIIBaseFlag; + }; + + xpointer m_pVftable; }; MARATHON_ASSERT_OFFSETOF(IFlagCommunicator, m_pVftable, 0x00); + MARATHON_ASSERT_OFFSETOF(IFlagCommunicator::Vftable, fpDestroy, 0); + MARATHON_ASSERT_OFFSETOF(IFlagCommunicator::Vftable, fpImportICommonContextIFFlag, 4); + MARATHON_ASSERT_OFFSETOF(IFlagCommunicator::Vftable, fpImportIPostureControlFlag, 8); + MARATHON_ASSERT_OFFSETOF(IFlagCommunicator::Vftable, fpFunc0xC, 0xC); + MARATHON_ASSERT_OFFSETOF(IFlagCommunicator::Vftable, fpImportExternalFlag, 0x10); + MARATHON_ASSERT_OFFSETOF(IFlagCommunicator::Vftable, fpImportICommonContextIFFlag2, 0x14); + MARATHON_ASSERT_OFFSETOF(IFlagCommunicator::Vftable, fpImportICommonContextIFFlag3, 0x18); + MARATHON_ASSERT_OFFSETOF(IFlagCommunicator::Vftable, fpImportIModelAnimationFlag, 0x1C); + MARATHON_ASSERT_OFFSETOF(IFlagCommunicator::Vftable, fpImportPostureRequestFlag, 0x20); + MARATHON_ASSERT_OFFSETOF(IFlagCommunicator::Vftable, fpImportWeaponRequestFlag, 0x24); + MARATHON_ASSERT_OFFSETOF(IFlagCommunicator::Vftable, fpImportUpgradeFlag, 0x28); + MARATHON_ASSERT_OFFSETOF(IFlagCommunicator::Vftable, fpImportVehicleFlag, 0x2C); + MARATHON_ASSERT_OFFSETOF(IFlagCommunicator::Vftable, fpImportAIIBaseFlag, 0x30); MARATHON_ASSERT_SIZEOF(IFlagCommunicator, 4); + } diff --git a/MarathonRecomp/api/Sonicteam/Player/IForce.h b/MarathonRecomp/api/Sonicteam/Player/IForce.h new file mode 100644 index 00000000..acc311d4 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/IForce.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include + +namespace Sonicteam::Player +{ + class IForce : public IPlugIn, public IFlagCommunicator + { + public: + struct Vftable:IPlugIn::Vftable + { + be fpGetDirection; + be fpGetForce; + }; + + be m_ICommonContextIFFlag; + be m_IPostureControlFlag; + be m_PostureRequestFlag; + + SoX::Math::Vector& GetDirection(); + + float GetForce(); + + }; + + MARATHON_ASSERT_SIZEOF(IForce, 0x30); + MARATHON_ASSERT_OFFSETOF(IForce, m_ICommonContextIFFlag, 0x24); + MARATHON_ASSERT_OFFSETOF(IForce, m_IPostureControlFlag, 0x28); + MARATHON_ASSERT_OFFSETOF(IForce, m_PostureRequestFlag, 0x2C); +} + +#include "IForce.inl" diff --git a/MarathonRecomp/api/Sonicteam/Player/IForce.inl b/MarathonRecomp/api/Sonicteam/Player/IForce.inl new file mode 100644 index 00000000..cacbee3d --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/IForce.inl @@ -0,0 +1,16 @@ +#pragma once + +namespace Sonicteam::Player +{ + inline SoX::Math::Vector& IForce::GetDirection() + { + auto vft = reinterpret_cast(static_cast(this)->m_pVftable.get()); + return *GuestToHostFunction(vft->fpGetDirection, this); + } + + inline float IForce::GetForce() + { + auto vft = reinterpret_cast(static_cast(this)->m_pVftable.get()); + return GuestToHostFunction(vft->fpGetForce, this); + } +} diff --git a/MarathonRecomp/api/Sonicteam/Player/IImportAnimation.h b/MarathonRecomp/api/Sonicteam/Player/IImportAnimation.h new file mode 100644 index 00000000..beb783be --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/IImportAnimation.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +namespace Sonicteam::Player +{ + class IImportAnimation + { + public: + struct Vftable + { + be fpDestroy; + be fpImportAnimation; + }; + + xpointer m_pVftable; + }; + + MARATHON_ASSERT_OFFSETOF(IImportAnimation, m_pVftable, 0x00); + MARATHON_ASSERT_SIZEOF(IImportAnimation, 4); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/ILoad.h b/MarathonRecomp/api/Sonicteam/Player/ILoad.h new file mode 100644 index 00000000..2fd7aed8 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/ILoad.h @@ -0,0 +1,80 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace Sonicteam::Player +{ + class ILoad : public IPlugIn + { + public: + struct Vftable : IPlugIn::Vftable + { + be fpLoadPackage; + be fpConnectListenerToInput; + be fpSyncFrame; + be fpProcessClump01; + be fpAddClump; + be fpProcessClump02_01; + be fpAddShadowClump; + be fpILoadUnknown; + be fpProcessClump02_03; + be fpGetGraphicDevice; + be fpGetParticleManager; + be fpSendMessageToSFXAgent; + be fpAddThread; + }; + + SoX::RefSharedPointer LoadPackage(stdx::string* package) + { + guest_heap_var> r = reinterpret_cast(0); + MARATHON_CALL_VIRTUAL_FUNCTION(IPlugIn, void, &Vftable::fpLoadPackage, r.get(), this, package); + return *r; + } + + SoX::RefSharedPointer LoadPackage(stdx::string& package) + { + guest_heap_var> r = reinterpret_cast(0); + guest_heap_var s(package); + MARATHON_CALL_VIRTUAL_FUNCTION(IPlugIn, void, &Vftable::fpLoadPackage, r.get(), this, s.get()); + return *r; + } + + void AddFrame(SoX::Graphics::Frame* pClump) + { + auto spclump = guest_heap_var>(pClump); + MARATHON_CALL_VIRTUAL_FUNCTION(IPlugIn, void, &Vftable::fpSyncFrame, this,spclump.get()); + } + + void AddClump(SoX::Scenery::Clump* pClump) + { + auto spclump = guest_heap_var>(pClump); + MARATHON_CALL_VIRTUAL_FUNCTION(IPlugIn, void, &Vftable::fpAddClump, this,spclump.get()); + } + + void AddShadowClump(SoX::Scenery::Clump* pClump) + { + auto spclump = guest_heap_var>(pClump); + MARATHON_CALL_VIRTUAL_FUNCTION(IPlugIn, void, &Vftable::fpAddShadowClump, this,spclump.get()); + } + }; + + MARATHON_ASSERT_OFFSETOF(ILoad::Vftable, fpLoadPackage, 4); + MARATHON_ASSERT_OFFSETOF(ILoad::Vftable, fpConnectListenerToInput, 8); + MARATHON_ASSERT_OFFSETOF(ILoad::Vftable, fpSyncFrame, 0xC); + MARATHON_ASSERT_OFFSETOF(ILoad::Vftable, fpProcessClump01, 0x10); + MARATHON_ASSERT_OFFSETOF(ILoad::Vftable, fpAddClump, 0x14); + MARATHON_ASSERT_OFFSETOF(ILoad::Vftable, fpProcessClump02_01, 0x18); + MARATHON_ASSERT_OFFSETOF(ILoad::Vftable, fpAddShadowClump, 0x1C); + MARATHON_ASSERT_OFFSETOF(ILoad::Vftable, fpILoadUnknown, 0x20); + MARATHON_ASSERT_OFFSETOF(ILoad::Vftable, fpProcessClump02_03, 0x24); + MARATHON_ASSERT_OFFSETOF(ILoad::Vftable, fpGetGraphicDevice, 0x28); + MARATHON_ASSERT_OFFSETOF(ILoad::Vftable, fpGetParticleManager, 0x2C); + MARATHON_ASSERT_OFFSETOF(ILoad::Vftable, fpSendMessageToSFXAgent, 0x30); + MARATHON_ASSERT_OFFSETOF(ILoad::Vftable, fpAddThread, 0x34); + MARATHON_ASSERT_SIZEOF(ILoad, 0x20); + +} diff --git a/MarathonRecomp/api/Sonicteam/Player/IModel.h b/MarathonRecomp/api/Sonicteam/Player/IModel.h new file mode 100644 index 00000000..e8e46d61 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/IModel.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +namespace Sonicteam::Player +{ + class IModel : public IPlugIn + { + public: + struct Vftable : public IPlugIn::Vftable + { + be fpGetAnimationID; + be fpGetAnimationID2; + be fpIsAnimationEnd; + be fpSetFunction; + be fpCaseUpdate; + be fpGetClump; + be fpUpdateTransform; + }; + }; + + MARATHON_ASSERT_OFFSETOF(IModel::Vftable, fpGetAnimationID, 4); + MARATHON_ASSERT_OFFSETOF(IModel::Vftable, fpGetAnimationID2, 8); + MARATHON_ASSERT_OFFSETOF(IModel::Vftable, fpIsAnimationEnd, 0xC); + MARATHON_ASSERT_OFFSETOF(IModel::Vftable, fpSetFunction, 0x10); + MARATHON_ASSERT_OFFSETOF(IModel::Vftable, fpCaseUpdate, 0x14); + MARATHON_ASSERT_OFFSETOF(IModel::Vftable, fpGetClump, 0x18); + MARATHON_ASSERT_OFFSETOF(IModel::Vftable, fpUpdateTransform, 0x1C); + MARATHON_ASSERT_SIZEOF(IModel, 0x20); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/IPath.h b/MarathonRecomp/api/Sonicteam/Player/IPath.h new file mode 100644 index 00000000..df8ea700 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/IPath.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Sonicteam::Player +{ + class IPath : public IPlugIn, public IPosturePlugIn, public IFlagCommunicator, public IStepable, public IDynamicLink, public IVariable + { + public: + be m_ICommonContextIFFlag; + be m_PostureRequestFlag; + be m_DirectionForward; + be m_DirectionVertical; + SoX::RefSharedPointer m_spController; + boost::shared_ptr m_spGravityForce; + }; + + MARATHON_ASSERT_SIZEOF(IPath, 0x50); + MARATHON_ASSERT_OFFSETOF(IPath, m_ICommonContextIFFlag, 0x34); + MARATHON_ASSERT_OFFSETOF(IPath, m_PostureRequestFlag, 0x38); + MARATHON_ASSERT_OFFSETOF(IPath, m_DirectionForward, 0x3C); + MARATHON_ASSERT_OFFSETOF(IPath, m_DirectionVertical, 0x40); + MARATHON_ASSERT_OFFSETOF(IPath, m_spController, 0x44); + MARATHON_ASSERT_OFFSETOF(IPath, m_spGravityForce, 0x48); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/IPlugIn.h b/MarathonRecomp/api/Sonicteam/Player/IPlugIn.h index 0fa8521f..76449637 100644 --- a/MarathonRecomp/api/Sonicteam/Player/IPlugIn.h +++ b/MarathonRecomp/api/Sonicteam/Player/IPlugIn.h @@ -8,7 +8,12 @@ namespace Sonicteam::Player class IPlugIn { public: - xpointer m_pVftable; + struct Vftable + { + be fpDestroy; + }; + + xpointer m_pVftable; stdx::string m_Name; }; diff --git a/MarathonRecomp/api/Sonicteam/Player/IPostureControl.h b/MarathonRecomp/api/Sonicteam/Player/IPostureControl.h index a401c852..e2f3e58b 100644 --- a/MarathonRecomp/api/Sonicteam/Player/IPostureControl.h +++ b/MarathonRecomp/api/Sonicteam/Player/IPostureControl.h @@ -1,75 +1,134 @@ #pragma once #include + +#include +#include +#include +#include +#include #include #include #include #include #include #include -#include -#include -#include -#include -#include +#include +#include #include -#include namespace Sonicteam::Player { class IPostureControl : public IVariable, public IDynamicLink, public Unit::ITestCase, public IFlagCommunicator { public: - SoX::RefSharedPointer<> m_spRootFrame; - SoX::Math::Quaternion m_RotationFixed; - SoX::Math::Vector m_PositionFixed; + struct Vftable : IVariable::Vftable + { + be fpfunc4; + be fpStep; + be fpImportPad; + }; + + // Based on Context Info + enum ContextIFFlag + { + ContextIFFlag_IsSonicDead = 0x1, // From v17 calculation + ContextIFFlag_BlinkInvulMode = 0x2, // Blink invulnerability mode + ContextIFFlag_InvulnerableState = 0x4, // Combined invulnerability state + ContextIFFlag_AnimationRotationLocked = 0x8, // IsAnimationRotationLocked + ContextIFFlag_IsUnkE6 = 0x10, // Unknown flag E6 + ContextIFFlag_GravityDisabled = 0x20, // IsGravityDisabled or ResetGravity + ContextIFFlag_JumpedPosture = 0x40, // IsJumped_PostureVelocityYHandle + ContextIFFlag_InActionsRunJumpBound = 0x80, // IsInActionsRunJumpBound_MB + ContextIFFlag_JumpPush = 0x1000, // JumpPush + ContextIFFlag_IsUnkEC = 0x200, // Unknown flag EC + ContextIFFlag_IsUnkED = 0x400, // Unknown flag ED + ContextIFFlag_IsUnkEE = 0x800, // Unknown flag EE + ContextIFFlag_DamageInvincibleActive = 0x2000, // DamageInvincibleTime > 0.0 + ContextIFFlag_UnkF0 = 0x4000, // Unknown flag F0 + ContextIFFlag_UnkF1 = 0x8000, // Unknown flag F1 + ContextIFFlag_UnkF2 = 0x10000, // Unknown flag F2 + ContextIFFlag_UnkF3 = 0x20000, // Unknown flag F3 + ContextIFFlag_EdgeGrab = 0x40000, // IsEdgeGrab + ContextIFFlag_WeaponRequest = 0x80000, // WeaponRequestFlag related + ContextIFFlag_DisableGravity = 0x200000, // DisableGravity + ContextIFFlag_IsUnkFE = 0x400000, // Unknown flag FE + ContextIFFlag_IsUnkFF = 0x800000, // Unknown flag FF + ContextIFFlag_IsUnk107 = 0x1000000, // Unknown flag 107 + ContextIFFlag_InvulnerableItemBox = 0x8000000, // IsInvulnerableItemBox + ContextIFFlag_GrabbedAura = 0x2000000, // IsGrabbedAura + ContextIFFlag_GhostMode = 0x4000000, // IsGhostMode + ContextIFFlag_InputLocked = 0x8, // LockInputTime > 0.0 (duplicate bit, appears to be OR'd) + ContextIFFlag_InputLockedAlt = 0x100, // LockInputTime > 0.0 (alternative bit position) + }; + + SoX::RefSharedPointer m_spRootFrame; + SoX::Math::Quaternion m_LocalRotation; + SoX::Math::Vector m_LocalPosition; SoX::RefSharedPointer m_spWorld; - boost::shared_ptr m_spGravity; - boost::shared_ptr m_spInputListener; - boost::shared_ptr m_spAmigoListener; - boost::shared_ptr m_spCommonContextIF; + boost::shared_ptr m_spGravityForce; + boost::shared_ptr m_spInputListener; + boost::shared_ptr m_spAmigoListener; + boost::shared_ptr m_ContextIF; boost::shared_ptr m_spActorManager; - xpointer m_pTask; + xpointer m_pPlayerTask; // Object::Player, but as ::Task boost::shared_ptr m_spPosturePlugIn; SoX::Math::Vector m_GravityDirection; be m_GravityForce; - SoX::Math::Vector m_SurfaceNormal; + SoX::Math::Quaternion m_GroundNormal; // GroundRotation?? SoX::Math::Vector m_Position; SoX::Math::Quaternion m_Rotation; - MARATHON_INSERT_PADDING(0x20); + SoX::Math::Quaternion m_PadRotation; + MARATHON_INSERT_PADDING(0x10); be m_PostureFlag; be m_ImpulseForward; be m_ImpulseVertical; - SoX::Math::Vector m_ImpulseUp; - be m_CommonContextIFFlags; - be m_PostureRequestFlags; - be m_PostureFlags118; - be m_PostureFlags11C; + SoX::Math::Vector m_ImpulseUP; + be m_ContextIFFlag; + be m_PostureRequestFlag; + be m_PostureFlag118; + be m_PostureFlag11C; + + template + T* GetWorld(); + + template + T* GetGravity(); + + SoX::Math::Quaternion CalculateDefaultTaskPad(); + + void ImportPad(SoX::Math::Quaternion pad, float step); + + // Recreate from sub_821F1E30, Full 1:1 recreated for debugging purposes + void RecreatedUpdate(double deltaTime); }; + MARATHON_ASSERT_SIZEOF(IPostureControl, 0x120); MARATHON_ASSERT_OFFSETOF(IPostureControl, m_spRootFrame, 0x10); - MARATHON_ASSERT_OFFSETOF(IPostureControl, m_RotationFixed, 0x20); - MARATHON_ASSERT_OFFSETOF(IPostureControl, m_PositionFixed, 0x30); + MARATHON_ASSERT_OFFSETOF(IPostureControl, m_LocalRotation, 0x20); + MARATHON_ASSERT_OFFSETOF(IPostureControl, m_LocalPosition, 0x30); MARATHON_ASSERT_OFFSETOF(IPostureControl, m_spWorld, 0x40); - MARATHON_ASSERT_OFFSETOF(IPostureControl, m_spGravity, 0x44); + MARATHON_ASSERT_OFFSETOF(IPostureControl, m_spGravityForce, 0x44); MARATHON_ASSERT_OFFSETOF(IPostureControl, m_spInputListener, 0x4C); MARATHON_ASSERT_OFFSETOF(IPostureControl, m_spAmigoListener, 0x54); - MARATHON_ASSERT_OFFSETOF(IPostureControl, m_spCommonContextIF, 0x5C); + MARATHON_ASSERT_OFFSETOF(IPostureControl, m_ContextIF, 0x5C); MARATHON_ASSERT_OFFSETOF(IPostureControl, m_spActorManager, 0x64); - MARATHON_ASSERT_OFFSETOF(IPostureControl, m_pTask, 0x6C); + MARATHON_ASSERT_OFFSETOF(IPostureControl, m_pPlayerTask, 0x6C); MARATHON_ASSERT_OFFSETOF(IPostureControl, m_spPosturePlugIn, 0x70); MARATHON_ASSERT_OFFSETOF(IPostureControl, m_GravityDirection, 0x80); MARATHON_ASSERT_OFFSETOF(IPostureControl, m_GravityForce, 0x90); - MARATHON_ASSERT_OFFSETOF(IPostureControl, m_SurfaceNormal, 0xA0); + MARATHON_ASSERT_OFFSETOF(IPostureControl, m_GroundNormal, 0xA0); MARATHON_ASSERT_OFFSETOF(IPostureControl, m_Position, 0xB0); MARATHON_ASSERT_OFFSETOF(IPostureControl, m_Rotation, 0xC0); + MARATHON_ASSERT_OFFSETOF(IPostureControl, m_PadRotation, 0xD0); MARATHON_ASSERT_OFFSETOF(IPostureControl, m_PostureFlag, 0xF0); MARATHON_ASSERT_OFFSETOF(IPostureControl, m_ImpulseForward, 0xF4); MARATHON_ASSERT_OFFSETOF(IPostureControl, m_ImpulseVertical, 0xF8); - MARATHON_ASSERT_OFFSETOF(IPostureControl, m_ImpulseUp, 0x100); - MARATHON_ASSERT_OFFSETOF(IPostureControl, m_CommonContextIFFlags, 0x110); - MARATHON_ASSERT_OFFSETOF(IPostureControl, m_PostureRequestFlags, 0x114); - MARATHON_ASSERT_OFFSETOF(IPostureControl, m_PostureFlags118, 0x118); - MARATHON_ASSERT_OFFSETOF(IPostureControl, m_PostureFlags11C, 0x11C); - MARATHON_ASSERT_SIZEOF(IPostureControl, 0x120); + MARATHON_ASSERT_OFFSETOF(IPostureControl, m_ImpulseUP, 0x100); + MARATHON_ASSERT_OFFSETOF(IPostureControl, m_ContextIFFlag, 0x110); + MARATHON_ASSERT_OFFSETOF(IPostureControl, m_PostureRequestFlag, 0x114); + MARATHON_ASSERT_OFFSETOF(IPostureControl, m_PostureFlag118, 0x118); + MARATHON_ASSERT_OFFSETOF(IPostureControl, m_PostureFlag11C, 0x11C); } + +#include "IPostureControl.inl" diff --git a/MarathonRecomp/api/Sonicteam/Player/IPostureControl.inl b/MarathonRecomp/api/Sonicteam/Player/IPostureControl.inl new file mode 100644 index 00000000..5388288b --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/IPostureControl.inl @@ -0,0 +1,79 @@ +#pragma once + +namespace Sonicteam::Player +{ + // Recreate from sub_821F1E30, Full 1:1 recreated for debugging purposes + inline void IPostureControl::RecreatedUpdate(double deltaTime) + { + if (auto contextIF = this->m_ContextIF.get()) + { + this->m_ImpulseForward = contextIF->GetTotalForwardImpulse(); + this->m_ImpulseVertical = contextIF->GetTotalVerticalImpulse(); + } + + if ((this->m_PostureRequestFlag.get() & 0x8000) != 0) + this->ImportPad(this->CalculateDefaultTaskPad(), 1.0); + else + { + auto pAmigoAIListener = this->m_spAmigoListener.get(); + auto pInputListener = this->m_spInputListener.get(); + + if (pAmigoAIListener && pAmigoAIListener->IsEnabled()) + this->ImportPad(pAmigoAIListener->GetPadQuat(), pAmigoAIListener->GetPadMagnitude()); + else if (pInputListener && pInputListener->IsEnabled()) + this->ImportPad(pInputListener->GetPadQuat(), pInputListener->GetPadMagnitude()); + } + + if (auto pGravity = this->GetGravity()) + { + this->m_GravityDirection = pGravity->GetDirection(); + this->m_GravityForce = pGravity->GetForce(); + this->m_GroundNormal = Sonicteam::SoX::Math::CreateRotationFromUpToDirection(this->m_GravityDirection); + } + } + + template + inline T* IPostureControl::GetGravity() + { + return static_cast(this->m_spGravityForce.get()); + } + + template + inline T* IPostureControl::GetWorld() + { + return static_cast(this->m_spWorld.get()); + } + + //ref to sub_821F1B38 + inline SoX::Math::Quaternion IPostureControl::CalculateDefaultTaskPad() + { + if (!this->m_pPlayerTask.get()) + return SoX::Math::Quaternion::Identity(); + + struct MessageGetActorID :SoX::Message<0x1300C> + { + be ActorID; + }; + guest_stack_var m_gsvMessageGetActorID; + this->m_pPlayerTask->ProcessMessage(m_gsvMessageGetActorID.get()); + auto pActor = this->m_spActorManager->FindActor(m_gsvMessageGetActorID->ActorID); + if (!pActor) + return SoX::Math::Quaternion::Identity(); + + struct MessageGetActorTransform :SoX::Message<0x10009> + { + SoX::Math::Matrix4x4 Matrix4x4; + }; + guest_stack_var m_gsvMessageGetActorTransform; + pActor->ProcessMessage(m_gsvMessageGetActorTransform.get()); + auto transformCoord = SoX::Math::TransformCoord(SoX::Math::Vector::Forward(), m_gsvMessageGetActorTransform->Matrix4x4); + return SoX::Math::Quaternion::CreateFromVectors(transformCoord, SoX::Math::Vector::Forward(), SoX::Math::Vector::Up()); + } + + inline void IPostureControl::ImportPad(SoX::Math::Quaternion pad, float step) + { + auto vft = reinterpret_cast(static_cast(this)->m_pVftable.get()); + GuestToHostFunction(vft->fpImportPad, this, guest_heap_var< SoX::Math::Quaternion>(pad).get(), step); + } +} + diff --git a/MarathonRecomp/api/Sonicteam/Player/IPosturePlugIn.h b/MarathonRecomp/api/Sonicteam/Player/IPosturePlugIn.h index 20a28f5d..55dc75d2 100644 --- a/MarathonRecomp/api/Sonicteam/Player/IPosturePlugIn.h +++ b/MarathonRecomp/api/Sonicteam/Player/IPosturePlugIn.h @@ -1,15 +1,65 @@ #pragma once #include +#include +#include +#include namespace Sonicteam::Player { class IPosturePlugIn { public: - xpointer m_pVftable; + struct Vftable + { + be fpDestroy; + be fpFunc4; + be fpSetControllerMovement; + be fpIsInContact; + be fpIsOffContact; + be fpGetContactFlag; + be fpOutContactPosition; + be fpOutContactUP; + be fpFunc20; + be fpFunc24; + be fpFunc28; + }; + xpointer m_pVftable; + + bool SetControllerMovement(SoX::RefSharedPointer* RefObj, SoX::Math::Quaternion* v); + + bool SetControllerMovement(SoX::RefSharedPointer& RefObj, SoX::Math::Quaternion& v); + + bool IsInContact(); + + bool IsOffContact(); + + uint32_t GetContactFlag(); + + void OutContactPosition(SoX::Math::Vector* vector); + + void OutContactUP(SoX::Math::Vector* quat); + + uint32_t Func20(SoX::Math::Vector* impulseForward, SoX::Math::Vector* impulseVertical, SoX::Math::Vector* impulseForward2, SoX::Math::Vector* impulse, double delta); + + uint32_t Func24(SoX::Math::Vector* vector, SoX::Math::Quaternion* quat); + + void Func28(SoX::Math::Vector* v1, SoX::Math::Quaternion* n1); }; MARATHON_ASSERT_OFFSETOF(IPosturePlugIn, m_pVftable, 0x00); + MARATHON_ASSERT_OFFSETOF(IPosturePlugIn::Vftable, fpDestroy, 0x00); + MARATHON_ASSERT_OFFSETOF(IPosturePlugIn::Vftable, fpFunc4, 4); + MARATHON_ASSERT_OFFSETOF(IPosturePlugIn::Vftable, fpSetControllerMovement, 8); + MARATHON_ASSERT_OFFSETOF(IPosturePlugIn::Vftable, fpIsInContact, 0xC); + MARATHON_ASSERT_OFFSETOF(IPosturePlugIn::Vftable, fpIsOffContact, 0x10); + MARATHON_ASSERT_OFFSETOF(IPosturePlugIn::Vftable, fpGetContactFlag, 0x14); + MARATHON_ASSERT_OFFSETOF(IPosturePlugIn::Vftable, fpOutContactPosition, 0x18); + MARATHON_ASSERT_OFFSETOF(IPosturePlugIn::Vftable, fpOutContactUP, 0x1C); + MARATHON_ASSERT_OFFSETOF(IPosturePlugIn::Vftable, fpFunc20, 0x20); + MARATHON_ASSERT_OFFSETOF(IPosturePlugIn::Vftable, fpFunc24, 0x24); + MARATHON_ASSERT_OFFSETOF(IPosturePlugIn::Vftable, fpFunc28, 0x28); MARATHON_ASSERT_SIZEOF(IPosturePlugIn, 4); } + +#include "IPosturePlugIn.inl" diff --git a/MarathonRecomp/api/Sonicteam/Player/IPosturePlugIn.inl b/MarathonRecomp/api/Sonicteam/Player/IPosturePlugIn.inl new file mode 100644 index 00000000..70fa111e --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/IPosturePlugIn.inl @@ -0,0 +1,57 @@ +#pragma once + +namespace Sonicteam::Player +{ + inline bool IPosturePlugIn::SetControllerMovement(SoX::RefSharedPointer* RefObj, SoX::Math::Quaternion* v) + { + return GuestToHostFunction(m_pVftable->fpSetControllerMovement, this, RefObj, v); + } + + inline bool IPosturePlugIn::SetControllerMovement(SoX::RefSharedPointer& RefObj, SoX::Math::Quaternion& v) + { + guest_heap_var gsvV(v); + guest_heap_var> gsvObj(RefObj); + bool result = SetControllerMovement(gsvObj.get(), gsvV.get()); + return result; + } + + inline bool IPosturePlugIn::IsInContact() + { + return GuestToHostFunction(m_pVftable->fpIsInContact, this); + } + + inline bool IPosturePlugIn::IsOffContact() + { + return GuestToHostFunction(m_pVftable->fpIsOffContact, this); + } + + inline uint32_t IPosturePlugIn::GetContactFlag() + { + return GuestToHostFunction(m_pVftable->fpGetContactFlag, this); + } + + inline void IPosturePlugIn::OutContactPosition(SoX::Math::Vector* vector) + { + GuestToHostFunction(m_pVftable->fpOutContactPosition, this, vector); + } + + inline void IPosturePlugIn::OutContactUP(SoX::Math::Vector* quat) + { + GuestToHostFunction(m_pVftable->fpOutContactUP, this, quat); + } + + inline uint32_t IPosturePlugIn::Func20(SoX::Math::Vector* impulseForward, SoX::Math::Vector* impulseVertical, SoX::Math::Vector* impulseForward2, SoX::Math::Vector* impulse, double delta) + { + return GuestToHostFunction(m_pVftable->fpFunc20, this, impulseForward, impulseVertical, impulseForward2, impulse, delta); + } + + inline uint32_t IPosturePlugIn::Func24(SoX::Math::Vector* vector, SoX::Math::Quaternion* quat) + { + return GuestToHostFunction(m_pVftable->fpFunc24, this, vector, quat); + } + + inline void IPosturePlugIn::Func28(SoX::Math::Vector* v1, SoX::Math::Quaternion* n1) + { + return GuestToHostFunction(m_pVftable->fpFunc28, this, v1, n1); + } +} diff --git a/MarathonRecomp/api/Sonicteam/Player/IPostureSupportEdge.h b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportEdge.h index 685f6625..3f2c98c4 100644 --- a/MarathonRecomp/api/Sonicteam/Player/IPostureSupportEdge.h +++ b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportEdge.h @@ -1,6 +1,10 @@ #pragma once #include +#include +#include +#include +#include namespace Sonicteam::Player { @@ -8,9 +12,30 @@ namespace Sonicteam::Player { public: xpointer m_pVftable; - MARATHON_INSERT_PADDING(0x6C); + MARATHON_INSERT_PADDING(0xC); + boost::shared_ptr m_spWallListener; + SoX::RefSharedPointer m_spCollisionEdge; + xpointer> m_pPostureRequestFlag; + SoX::Math::Vector m_EdgeBottomPosition; // -72.00,30.27 -0.53 + SoX::Math::Vector m_EdgeTopPosistion; // -72.00 50.27 -0.53 + SoX::Math::Vector m_EdgeOffset; // Vector operations & Lua Parameters + SoX::Math::Vector m_EdgeHeight; // Lua Parameter but c_edge_height(Y) + MARATHON_INSERT_PADDING(0x10); + + void sub_82202B08(SoX::Math::Quaternion groundRotation); + + bool EdgeGrabLeftOverFunction(SoX::Math::Vector position); + }; - MARATHON_ASSERT_OFFSETOF(IPostureSupportEdge, m_pVftable, 0x00); - MARATHON_ASSERT_SIZEOF(IPostureSupportEdge, 0x70); + MARATHON_ASSERT_SIZEOF(IPostureSupportEdge, 112); + MARATHON_ASSERT_OFFSETOF(IPostureSupportEdge, m_spWallListener, 0x10); + MARATHON_ASSERT_OFFSETOF(IPostureSupportEdge, m_spCollisionEdge, 0x18); + MARATHON_ASSERT_OFFSETOF(IPostureSupportEdge, m_pPostureRequestFlag, 0x1C); + MARATHON_ASSERT_OFFSETOF(IPostureSupportEdge, m_EdgeBottomPosition, 0x20); + MARATHON_ASSERT_OFFSETOF(IPostureSupportEdge, m_EdgeTopPosistion, 0x30); + MARATHON_ASSERT_OFFSETOF(IPostureSupportEdge, m_EdgeOffset, 0x40); + MARATHON_ASSERT_OFFSETOF(IPostureSupportEdge, m_EdgeHeight, 0x50); } + +#include "IPostureSupportEdge.inl" diff --git a/MarathonRecomp/api/Sonicteam/Player/IPostureSupportEdge.inl b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportEdge.inl new file mode 100644 index 00000000..dc684035 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportEdge.inl @@ -0,0 +1,49 @@ +#pragma once + +#include + +namespace Sonicteam::Player +{ + // Recreated from sub_82202B08-- + inline void IPostureSupportEdge::sub_82202B08(SoX::Math::Quaternion groundRotation) + { + this->m_EdgeBottomPosition = groundRotation * m_EdgeOffset; + this->m_EdgeTopPosistion = m_EdgeBottomPosition + m_EdgeHeight; + } + + // position 82200B94, Function was removed, i've tried to restore depending on how they usually do it + inline bool IPostureSupportEdge::EdgeGrabLeftOverFunction(SoX::Math::Vector position) + { + return false; + + if (!m_spWallListener) + return false; + + auto ledgeBottom = position + m_EdgeBottomPosition; + auto ledgeTop = position + m_EdgeTopPosistion; + + m_spWallListener->SetPostureRequestFlag(m_pPostureRequestFlag->get()); + + struct LedgeDetectionVolume + { + SoX::Math::Vector bottomSearch; + SoX::Math::Vector topSearch; + }; + + guest_heap_var ledgeVolume(ledgeBottom, ledgeTop); + + m_spCollisionEdge->Func3C( + reinterpret_cast(ledgeVolume.get()), + static_cast(m_spWallListener.get()) + ); + + m_spWallListener->Update(); + + if (m_spWallListener->GetCurrentSurfaceContacts() > 0) + { + return true; + } + + return false; + } +} diff --git a/MarathonRecomp/api/Sonicteam/Player/IPostureSupportInput.h b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportInput.h index a044222e..18fb91ad 100644 --- a/MarathonRecomp/api/Sonicteam/Player/IPostureSupportInput.h +++ b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportInput.h @@ -1,16 +1,44 @@ #pragma once #include +#include namespace Sonicteam::Player { class IPostureSupportInput { public: - xpointer m_pVftable; - MARATHON_INSERT_PADDING(0x2C); + struct Vftable + { + be fpIsInput; + be fpDestroy; + }; + + xpointer m_pVftable; + SoX::Math::Quaternion m_InputRotation; + be m_InputForce; // [0..1.0] + be m_RotationMethod; + be m_RotationSpeed; + + bool IsInput(); + + bool sub_82201E78(SoX::Math::Quaternion rot); + + SoX::Math::Quaternion sub_82201D88(SoX::Math::Quaternion rot); + + SoX::Math::Quaternion sub_82201E00(SoX::Math::Quaternion rot); + + SoX::Math::Quaternion sub_82201F28(SoX::Math::Quaternion rot, float precission); + + SoX::Math::Quaternion sub_82201BC8(SoX::Math::Quaternion rot, float impulseForward); + }; - MARATHON_ASSERT_OFFSETOF(IPostureSupportInput, m_pVftable, 0x00); - MARATHON_ASSERT_SIZEOF(IPostureSupportInput, 0x30); + MARATHON_ASSERT_SIZEOF(IPostureSupportInput, 48); + MARATHON_ASSERT_OFFSETOF(IPostureSupportInput, m_InputRotation, 0x10); + MARATHON_ASSERT_OFFSETOF(IPostureSupportInput, m_InputForce, 0x20); + MARATHON_ASSERT_OFFSETOF(IPostureSupportInput, m_RotationMethod, 0x24); + MARATHON_ASSERT_OFFSETOF(IPostureSupportInput, m_RotationSpeed, 0x28); } + +#include "IPostureSupportInput.inl" diff --git a/MarathonRecomp/api/Sonicteam/Player/IPostureSupportInput.inl b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportInput.inl new file mode 100644 index 00000000..949506c8 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportInput.inl @@ -0,0 +1,90 @@ +#pragma once + +#include +#include + +namespace Sonicteam::Player +{ + + inline bool IPostureSupportInput::IsInput() + { + return GuestToHostFunction(this->m_pVftable->fpIsInput, this); + } + + // Recreated from sub_82201E78 + inline bool IPostureSupportInput::sub_82201E78(SoX::Math::Quaternion rot) + { + if (this->m_InputForce <= 0.0) + return 0; + + auto v1 = SoX::Math::TransformCoord({ 0,0,1,1 }, SoX::Math::MatrixFromQuaternion(rot)); + auto v2 = SoX::Math::TransformCoord({ 0,0,1,1 }, SoX::Math::MatrixFromQuaternion(m_InputRotation)); + return (v2.Dot(v1).X < 0.0); + } + + // Recreated from sub_82201D88 + inline SoX::Math::Quaternion IPostureSupportInput::sub_82201D88(SoX::Math::Quaternion rot) + { + if (this->IsInput() || this->m_InputForce <= 0.0) + return rot; + else + { + return m_InputRotation; + } + } + + // Recreated from sub_82201E00 + inline SoX::Math::Quaternion IPostureSupportInput::sub_82201E00(SoX::Math::Quaternion rot) + { + if (this->IsInput()) + return rot; + else + { + return SoX::Math::QuaternionMultiply(m_InputRotation, { 0,0,0,0 }); + } + } + + // Recreated from sub_82201F28 + inline SoX::Math::Quaternion IPostureSupportInput::sub_82201F28(SoX::Math::Quaternion rot, float precission) + { + + if (this->IsInput() || this->m_InputForce <= 0.0f) + { + return rot; + } + else + { + auto forward = rot * SoX::Math::Vector::Forward(); + auto forwardInput = this->m_InputRotation * SoX::Math::Vector::Forward(); + auto forwardEnd = Sonicteam::SoX::Math::Vector::Normalize3((forwardInput * precission) + (forward * (1.0 - precission))); + return SoX::Math::Quaternion::CreateFromVectors(SoX::Math::Vector::Forward(), forwardEnd, SoX::Math::Vector::Up()); + + } + } + + // Recreated from sub_82201BC8 + inline SoX::Math::Quaternion IPostureSupportInput::sub_82201BC8(SoX::Math::Quaternion rot, float impulseForward) + { + if (this->IsInput() || this->m_InputForce <= 0.0f) + return rot; + + if (this->m_RotationMethod == 0) + { + auto forward = rot * SoX::Math::Vector::Forward(); + auto forwardInput = m_InputRotation * SoX::Math::Vector::Forward(); + auto forwardOutInput = (SoX::Math::Vector)(forward * 0.5) + (forwardInput * 0.5); + return SoX::Math::Quaternion::CreateFromVectors(SoX::Math::Vector::Forward(), forwardOutInput, SoX::Math::Vector::Up()); + } + else if (this->m_RotationMethod == 1) + { + auto forwardImpulse = rot * (SoX::Math::Vector::Forward() * impulseForward); + auto forwardInput = m_InputRotation * (SoX::Math::Vector::Forward() * m_RotationSpeed); + auto forwardOutInput = forwardImpulse + forwardInput; + return SoX::Math::Quaternion::CreateFromVectors(SoX::Math::Vector::Forward(), forwardOutInput, SoX::Math::Vector::Up()); + } + + return rot; + } + +}; + diff --git a/MarathonRecomp/api/Sonicteam/Player/IPostureSupportOttoto.h b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportOttoto.h index 37d3adf2..f280e428 100644 --- a/MarathonRecomp/api/Sonicteam/Player/IPostureSupportOttoto.h +++ b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportOttoto.h @@ -1,16 +1,44 @@ #pragma once #include +#include +#include +#include +#include namespace Sonicteam::Player { + class GroundListener; + class WallListener; + class IPostureSupportOttoto { public: xpointer m_pVftable; - MARATHON_INSERT_PADDING(0x6C); + MARATHON_INSERT_PADDING(0xC); + boost::shared_ptr m_spGroundListener; + boost::shared_ptr m_spWallListener; + SoX::RefSharedPointer m_spCollisionOttoto; + xpointer> m_pPostureRequestFlag; + SoX::Math::Vector m_GroundAngle; + SoX::Math::Vector m_WallAngle; + SoX::Math::Vector m_OttotoVolume; + be m_OttotoHeight; + + void sub_82201620(SoX::Math::Vector invertNormal, SoX::Math::Quaternion groundRotation); + + bool sub_82201758(SoX::Math::Vector position1, SoX::Math::Vector position2); }; - MARATHON_ASSERT_OFFSETOF(IPostureSupportOttoto, m_pVftable, 0x00); - MARATHON_ASSERT_SIZEOF(IPostureSupportOttoto, 0x70); + MARATHON_ASSERT_SIZEOF(IPostureSupportOttoto, 112); + MARATHON_ASSERT_OFFSETOF(IPostureSupportOttoto, m_spGroundListener, 0x10); + MARATHON_ASSERT_OFFSETOF(IPostureSupportOttoto, m_spWallListener, 0x18); + MARATHON_ASSERT_OFFSETOF(IPostureSupportOttoto, m_spCollisionOttoto, 0x20); + MARATHON_ASSERT_OFFSETOF(IPostureSupportOttoto, m_pPostureRequestFlag, 0x24); + MARATHON_ASSERT_OFFSETOF(IPostureSupportOttoto, m_GroundAngle, 0x30); + MARATHON_ASSERT_OFFSETOF(IPostureSupportOttoto, m_WallAngle, 0x40); + MARATHON_ASSERT_OFFSETOF(IPostureSupportOttoto, m_OttotoVolume, 0x50); + MARATHON_ASSERT_OFFSETOF(IPostureSupportOttoto, m_OttotoHeight, 0x60); } + +#include "IPostureSupportOttoto.inl" diff --git a/MarathonRecomp/api/Sonicteam/Player/IPostureSupportOttoto.inl b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportOttoto.inl new file mode 100644 index 00000000..89e663c4 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportOttoto.inl @@ -0,0 +1,76 @@ +#pragma once + +namespace Sonicteam::Player +{ + // Recreated from sub_82201620 + inline void IPostureSupportOttoto::sub_82201620(SoX::Math::Vector invertNormal, SoX::Math::Quaternion groundRotation) + { + m_GroundAngle = groundRotation * m_OttotoVolume; + m_WallAngle = (invertNormal * m_OttotoHeight) + m_GroundAngle; + if (m_spGroundListener.get()) + { + m_spGroundListener->m_CollisionNormal = invertNormal.InvertNormal(); + } + if (m_spWallListener.get()) + { + m_spWallListener->m_CollisionNormal = invertNormal.InvertNormal(); + } + } + + // Recreated from sub_82201758 + inline bool IPostureSupportOttoto::sub_82201758(SoX::Math::Vector position1, SoX::Math::Vector position2) + { + if ((this->m_pPostureRequestFlag.get()->get() & 0x40) != 0) + return 0; + + auto v38 = position1 + m_WallAngle; + auto v39 = position1 + m_GroundAngle; + + struct _points_ + { + SoX::Math::Vector p1; + SoX::Math::Vector p2; + }; + guest_heap_var<_points_> _g_points_(v39, v38); + m_spGroundListener->SetPostureRequestFlag(m_pPostureRequestFlag.get()->get()); + m_spCollisionOttoto->Func3C((SoX::Math::Vector*)_g_points_.get(), static_cast(m_spGroundListener.get())); + + m_spGroundListener->Update(); + auto groundContact = m_spGroundListener->GetCurrentSurfaceContacts() > 0; + + auto v42 = position2 + m_WallAngle; + auto v40 = position2 + m_GroundAngle; + *_g_points_ = + { + v40, + v42 + }; + m_spGroundListener->SetPostureRequestFlag(m_pPostureRequestFlag.get()->get()); + m_spCollisionOttoto->Func3C((SoX::Math::Vector*)_g_points_.get(), static_cast(m_spGroundListener.get())); + m_spGroundListener->Update(); + auto groundContact2 = m_spGroundListener->GetCurrentSurfaceContacts() > 0; + + auto v41 = position2 + m_GroundAngle; + auto v37 = position1 + m_GroundAngle; + *_g_points_ = + { + v37, + v41 + }; + + m_spWallListener->SetPostureRequestFlag(m_pPostureRequestFlag.get()->get()); + m_spCollisionOttoto->Func3C((SoX::Math::Vector*)_g_points_.get(), static_cast(m_spWallListener.get())); + m_spWallListener->Update(); + auto wallContact = m_spWallListener->GetCurrentSurfaceContacts() > 0; + + if (!groundContact || groundContact2 || !wallContact) + { + return false; + } + else + { + return true; + } + + } +} diff --git a/MarathonRecomp/api/Sonicteam/Player/IPostureSupportRayTemplate.h b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportRayTemplate.h index bcb4f647..13e7cc12 100644 --- a/MarathonRecomp/api/Sonicteam/Player/IPostureSupportRayTemplate.h +++ b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportRayTemplate.h @@ -4,23 +4,21 @@ #include #include #include -#include namespace Sonicteam::Player { - template + template class IPostureSupportRayTemplate { public: xpointer m_pVftable; SoX::RefSharedPointer m_spWorld; - boost::shared_ptr m_spCollisionListener; - xpointer m_pRootFrame; + boost::shared_ptr m_spCollisionListener; + xpointer> m_pPostureRequestFlag; }; - MARATHON_ASSERT_OFFSETOF(IPostureSupportRayTemplate, m_pVftable, 0x00); - MARATHON_ASSERT_OFFSETOF(IPostureSupportRayTemplate, m_spWorld, 0x04); - MARATHON_ASSERT_OFFSETOF(IPostureSupportRayTemplate, m_spCollisionListener, 0x08); - MARATHON_ASSERT_OFFSETOF(IPostureSupportRayTemplate, m_pRootFrame, 0x10); - MARATHON_ASSERT_SIZEOF(IPostureSupportRayTemplate, 0x14); + MARATHON_ASSERT_SIZEOF(IPostureSupportRayTemplate, 20); + MARATHON_ASSERT_OFFSETOF(IPostureSupportRayTemplate, m_spWorld, 0x4); + MARATHON_ASSERT_OFFSETOF(IPostureSupportRayTemplate, m_spCollisionListener, 0x8); + MARATHON_ASSERT_OFFSETOF(IPostureSupportRayTemplate, m_pPostureRequestFlag, 0x10); } diff --git a/MarathonRecomp/api/Sonicteam/Player/IPostureSupportSphere.h b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportSphere.h index 6c1efd8b..b1af1f08 100644 --- a/MarathonRecomp/api/Sonicteam/Player/IPostureSupportSphere.h +++ b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportSphere.h @@ -1,6 +1,15 @@ #pragma once #include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace Sonicteam::Player { @@ -8,9 +17,68 @@ namespace Sonicteam::Player { public: xpointer m_pVftable; - MARATHON_INSERT_PADDING(0xCC); + MARATHON_INSERT_PADDING(0xC); + SoX::RefSharedPointer m_spPhysicsWorld; + boost::shared_ptr m_spGroundListener; + boost::shared_ptr m_spWallListener; + boost::shared_ptr m_spAllListener1; + boost::shared_ptr m_spAllListener2; + boost::shared_ptr m_spGroundRayListener; + boost::shared_ptr m_spRealGroundRayListener; + boost::shared_ptr m_spWallRayListener; + //Array[2] [0] - Normal [1] - Small + SoX::Array,2> m_aShapeCollisionAll; + SoX::Array,2> m_aShapeCollisionWalk; + SoX::Array,2> m_aShapeCollisionWall; + SoX::RefSharedPointer m_RayCast; + xpointer> m_pPostureRequestFlag; + SoX::Math::Vector m_CollisionAllAngle; + SoX::Array, 2> m_aCollisionAllRadius; + SoX::Math::Vector m_CollisionWalkAngle; + SoX::Array, 2> m_aCollisionWalkRadius; + SoX::Math::Vector m_CollisionWallAngle; + SoX::Array, 2> m_aCollisionWallRadius; + be m_FlagC8; //m_Normal, Small Toggle, not sure if bool either? + + Player::GroundListener* sub_822014B8(SoX::Math::Vector point); + + ICollisionListener* sub_82202180(SoX::Math::Vector position, SoX::Math::Vector endPosition, be* flag); + + void sub_82200EC0(SoX::Math::Vector invertNormal); + + bool sub_822024F0(SoX::Math::Vector& position, SoX::Math::Vector& impulse, be* postureFlag); + + bool sub_82202300(SoX::Math::Vector& position, SoX::Math::Vector& impulse, be* postureFlag); + + ICollisionListener* sub_82201058(SoX::Math::Vector position, SoX::Math::Vector endPosition, be* flag); + + ICollisionListener* sub_822011E8(SoX::Math::Vector d1, SoX::Math::Vector d2, be* outFlag1); + + ICollisionListener* sub_82203840(SoX::Math::Vector* d1, SoX::Math::Vector d2, be* outFlag1); + + ICollisionListener* sub_82201350(SoX::Math::Vector& pos1, SoX::Math::Vector& pos2, be* outFlag1); }; - MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_pVftable, 0x00); - MARATHON_ASSERT_SIZEOF(IPostureSupportSphere, 0xD0); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_spPhysicsWorld, 0x10); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_spGroundListener, 0x14); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_spWallListener, 0x1C); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_spAllListener1, 0x24); //Sonicteam::Player::ICollisionListenerTemplate + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_spAllListener2, 0x2C); //Sonicteam::Player::ICollisionListenerTemplate + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_spGroundRayListener, 0x34); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_spRealGroundRayListener, 0x3C); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_spWallRayListener, 0x44); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_aShapeCollisionAll, 0x4C); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_aShapeCollisionWalk, 0x54); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_aShapeCollisionWall, 0x5C); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_RayCast, 0x64); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_pPostureRequestFlag, 0x68); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_CollisionAllAngle, 0x70); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_aCollisionAllRadius, 0x80); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_CollisionWalkAngle, 0x90); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_aCollisionWalkRadius, 0xA0); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_CollisionWallAngle, 0xB0); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_aCollisionWallRadius, 0xC0); + MARATHON_ASSERT_OFFSETOF(IPostureSupportSphere, m_FlagC8, 0xC8); } + +#include "IPostureSupportSphere.inl" diff --git a/MarathonRecomp/api/Sonicteam/Player/IPostureSupportSphere.inl b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportSphere.inl new file mode 100644 index 00000000..ea820938 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/IPostureSupportSphere.inl @@ -0,0 +1,272 @@ +#pragma once + +namespace Sonicteam::Player +{ + // Recreated from sub_822014B8 + inline Player::GroundListener* IPostureSupportSphere::sub_822014B8(SoX::Math::Vector point) + { + if (!this->m_spGroundListener.get()) + return 0; + + auto v1ColAngle = point + m_CollisionAllAngle; + m_spGroundListener->SetPostureRequestFlag(this->m_pPostureRequestFlag.get()->get()); + + auto pGroundListener = this->m_spGroundListener.get(); + auto pGroundShapeCastListener = static_cast(pGroundListener); + auto pShapeCollisionWalk = m_aShapeCollisionWalk[m_FlagC8.get()].get(); + + struct Vec2 + { + SoX::Math::Vector _vec1; + SoX::Math::Vector _vec2; + }; + guest_stack_var gsv_vector = + { + v1ColAngle, + point + }; + + pShapeCollisionWalk->Func38((SoX::Math::Vector*)gsv_vector.get(), pGroundShapeCastListener); + this->m_spGroundListener->Update(); + if (this->m_spGroundListener->GetCurrentSurfaceContacts() > 0) + return this->m_spGroundListener.get(); + else + return 0; + + } + + // Recreated from sub_82202180 + inline ICollisionListener* IPostureSupportSphere::sub_82202180(SoX::Math::Vector position, SoX::Math::Vector endPosition, be* flag) + { + if (!m_spWallListener.get()) + return 0; + + m_spWallListener->SetPostureRequestFlag(m_pPostureRequestFlag->get()); + + auto collisionWallAnglePosition = position + m_CollisionWallAngle; + auto collisionWallAngleEndPosition = endPosition + m_CollisionWallAngle; + struct _vector_ + { + SoX::Math::Vector p1; + SoX::Math::Vector p2; + }; + guest_stack_var< _vector_> points = + { + collisionWallAnglePosition, + collisionWallAngleEndPosition + }; + + auto shapeCollisionWall = m_aShapeCollisionWall[m_FlagC8]; + shapeCollisionWall->Func38((SoX::Math::Vector*)points.get(), static_cast(m_spWallListener.get())); + + if (flag) + *flag = m_spWallListener->GetCollisionFlag(); + + if (m_spWallListener->GetCurrentSurfaceContacts() > 0) + return m_spWallListener.get(); + + return 0; + } + + // Recreated from sub_82200EC0 + inline void IPostureSupportSphere::sub_82200EC0(SoX::Math::Vector invertNormal) + { + SoX::Math::Vector normal = invertNormal.InvertNormal(); + + + m_CollisionAllAngle = normal * m_aCollisionAllRadius[m_FlagC8]; + m_CollisionWalkAngle = normal * m_aCollisionWalkRadius[m_FlagC8]; + m_CollisionWallAngle = normal * m_aCollisionWallRadius[m_FlagC8]; + + if (m_spGroundListener.get()) + m_spGroundListener->m_CollisionNormal = normal; + + if (m_spWallListener.get()) + m_spWallListener->m_CollisionNormal = normal; + + if (m_spGroundRayListener.get()) + m_spGroundRayListener->m_CollisionNormal = normal; + + if (m_spRealGroundRayListener.get()) + m_spRealGroundRayListener->m_CollisionNormal = normal; + + if (m_spWallRayListener.get()) + m_spWallRayListener->m_CollisionNormal = normal; + } + + // Recreated from sub_822024F0 + inline bool IPostureSupportSphere::sub_822024F0(SoX::Math::Vector& position, SoX::Math::Vector& impulse, be* postureFlag) + { + auto listener = this->sub_82202180(position, position + impulse, 0); + if (listener && (listener->GetCollisionFlag() & 1) != 0) + { + auto nImpulse = impulse.NormalizeEX(); + impulse = nImpulse.first; + auto norm_14 = listener->GetLength(nImpulse.second); + auto invertNormal = listener->GetContactNormal().InvertNormal(); + if (impulse.Dot(invertNormal).X >= 0.89999998) + *postureFlag = postureFlag->get() | 0x10; //PostureFlag_HeadOnWall + + position = position + (impulse * norm_14); + impulse = SoX::Math::Vector::Zero(); + *postureFlag = postureFlag->get() | 8; //PostureFlag_WallBrushing + return true; + } + return false; + } + + // Recreated from sub_82202300 + inline bool IPostureSupportSphere::sub_82202300(SoX::Math::Vector& position, SoX::Math::Vector& impulse, be* postureFlag) + { + auto listener = this->sub_82202180(position, position + impulse, 0); + if (listener && (listener->GetCollisionFlag() & 1) != 0) + { + auto nImpulse = impulse.NormalizeEX(); + impulse = nImpulse.first; + auto norm_14 = listener->GetLength(nImpulse.second); + auto invertNormal = listener->GetContactNormal().InvertNormal(); + if (impulse.Dot(invertNormal).X >= 0.89999998) + *postureFlag = postureFlag->get() | 0x10; //PostureFlag_HeadOnWall + + position = position + (impulse * norm_14); + + auto v24 = invertNormal.Cross(impulse); + auto v25 = v24.Cross(invertNormal); + + impulse = v25 * (nImpulse.second - norm_14); + + *postureFlag = postureFlag->get() | 8; //PostureFlag_WallBrushing + return true; + } + return false; + } + + // Recreated from sub_82201058 + inline ICollisionListener* IPostureSupportSphere::sub_82201058(SoX::Math::Vector position, SoX::Math::Vector endPosition, be* flag) + { + if (!m_spGroundListener.get()) + return 0; + + auto collisionWalkAnglePosition = position + m_CollisionWalkAngle; + auto collisionWalkAngleEndPosition = endPosition + m_CollisionWalkAngle; + + m_spGroundListener->SetPostureRequestFlag(m_pPostureRequestFlag->get()); + + struct _vector_ + { + SoX::Math::Vector p1; + SoX::Math::Vector p2; + }; + guest_heap_var<_vector_> points(collisionWalkAnglePosition, collisionWalkAngleEndPosition); + + auto shapeCollisionWalk = m_aShapeCollisionWalk[m_FlagC8]; + shapeCollisionWalk->Func38((SoX::Math::Vector*)points.get(), static_cast(m_spGroundListener.get())); + m_spGroundListener->Update(); + + if (flag) + *flag = m_spGroundListener->GetCollisionFlag(); + + if (m_spGroundListener->GetCurrentSurfaceContacts() > 0) + return m_spGroundListener.get(); + + return 0; + } + + // Recreated from sub_822011E8 + inline ICollisionListener* IPostureSupportSphere::sub_822011E8(SoX::Math::Vector d1, SoX::Math::Vector d2, be* outFlag1) + { + if (!m_spGroundRayListener.get()) + return 0; + + + m_spGroundRayListener->SetPostureRequestFlag(m_pPostureRequestFlag->get()); + + struct _vector_ + { + SoX::Math::Vector p1; + SoX::Math::Vector p2; + }; + guest_heap_var<_vector_> points(d1, d2); + + m_RayCast->Func14((SoX::Math::Vector*)points.get(), static_cast(m_spGroundRayListener.get())); + m_spGroundRayListener->Update(); + + if (outFlag1) + *outFlag1 = m_spGroundRayListener->GetCollisionFlag(); + + if (m_spGroundRayListener->GetCurrentSurfaceContacts() > 0) + return m_spGroundRayListener.get(); + + return 0; + } + + // Recreated from sub_82203840 + inline ICollisionListener* IPostureSupportSphere::sub_82203840(SoX::Math::Vector* d1, SoX::Math::Vector d2, be* outFlag1) + { + if (d1) + { + *d1 = d2; + } + + if (auto listener = m_spAllListener1.get()) + { + printf("listener %p\n", listener); + auto v22 = d2 + m_CollisionAllAngle; + + struct _vector_ + { + SoX::Math::Vector p1; + SoX::Math::Vector p2; + }; + guest_heap_var<_vector_> points(v22, v22); + listener->m_Position = v22; + listener->m_Radius = m_aCollisionAllRadius[m_FlagC8]; + listener->SetPostureRequestFlag(m_pPostureRequestFlag.get()->get()); + + m_aShapeCollisionAll[m_FlagC8]->Func3C((SoX::Math::Vector*)points.get(), static_cast(listener)); + listener->Update(); + + if (outFlag1) + *outFlag1 = listener->GetCollisionFlag(); + + if (d1) + { + *d1 = listener->GetContactPosition() - m_CollisionAllAngle; + } + + if (listener->GetCurrentSurfaceContacts() > 0) + return listener; + + } + return 0; + } + + // Recreated from sub_82201350 + inline ICollisionListener* IPostureSupportSphere::sub_82201350(SoX::Math::Vector& pos1, SoX::Math::Vector& pos2, be* outFlag1) + { + if (!m_spWallRayListener.get()) + return 0; + + + m_spWallRayListener->SetPostureRequestFlag(m_pPostureRequestFlag->get()); + + struct _vector_ + { + SoX::Math::Vector p1; + SoX::Math::Vector p2; + }; + guest_heap_var<_vector_> points(pos1, pos2); + + m_RayCast->Func14((SoX::Math::Vector*)points.get(), static_cast(m_spWallRayListener.get())); + m_spWallRayListener->Update(); + + if (outFlag1) + *outFlag1 = m_spWallRayListener->GetCollisionFlag(); + + if (m_spWallRayListener->GetCurrentSurfaceContacts() > 0) + return m_spWallRayListener.get(); + + return 0; + } +}; + diff --git a/MarathonRecomp/api/Sonicteam/Player/IStepable.h b/MarathonRecomp/api/Sonicteam/Player/IStepable.h index b430f4bc..a615ea92 100644 --- a/MarathonRecomp/api/Sonicteam/Player/IStepable.h +++ b/MarathonRecomp/api/Sonicteam/Player/IStepable.h @@ -7,7 +7,18 @@ namespace Sonicteam::Player class IStepable { public: - xpointer m_pVftable; + struct Vftable + { + be fpDestroy; + be fpStep; + }; + + xpointer m_pVftable; + + void Step(float delta) + { + GuestToHostFunction(m_pVftable->fpStep, this, delta); + } }; MARATHON_ASSERT_OFFSETOF(IStepable, m_pVftable, 0x00); diff --git a/MarathonRecomp/api/Sonicteam/Player/IVariable.h b/MarathonRecomp/api/Sonicteam/Player/IVariable.h index 34955456..3cecc239 100644 --- a/MarathonRecomp/api/Sonicteam/Player/IVariable.h +++ b/MarathonRecomp/api/Sonicteam/Player/IVariable.h @@ -7,7 +7,12 @@ namespace Sonicteam::Player class IVariable { public: - xpointer m_pVftable; + struct Vftable + { + be fpImportVariable; + }; + + xpointer m_pVftable; }; MARATHON_ASSERT_OFFSETOF(IVariable, m_pVftable, 0x00); diff --git a/MarathonRecomp/api/Sonicteam/Player/Input/IListener.h b/MarathonRecomp/api/Sonicteam/Player/Input/IListener.h index f889a348..fdcda711 100644 --- a/MarathonRecomp/api/Sonicteam/Player/Input/IListener.h +++ b/MarathonRecomp/api/Sonicteam/Player/Input/IListener.h @@ -1,16 +1,32 @@ #pragma once #include +#include +#include +#include namespace Sonicteam::Player::Input { - class IListener + class IListener : public SoX::Input::Listener { public: - xpointer m_pVftable; - MARATHON_INSERT_PADDING(0x14); - }; + struct Vftable: public SoX::Object::Vftable + { + be fpStep; + be fpGetPadQuat; + be fpGetPadMagnitude; + be fpGetPadButtons; + be fpIsEnabled; + }; + + SoX::Math::Quaternion& GetPadQuat(); + + float GetPadMagnitude(); - MARATHON_ASSERT_OFFSETOF(IListener, m_pVftable, 0x00); - MARATHON_ASSERT_SIZEOF(IListener, 0x18); + uint32_t GetPadButtons(); + + bool IsEnabled(); + }; } + +#include "IListener.inl" diff --git a/MarathonRecomp/api/Sonicteam/Player/Input/IListener.inl b/MarathonRecomp/api/Sonicteam/Player/Input/IListener.inl new file mode 100644 index 00000000..aa230472 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/Input/IListener.inl @@ -0,0 +1,28 @@ +#pragma once + +namespace Sonicteam::Player::Input +{ + inline SoX::Math::Quaternion& IListener::GetPadQuat() + { + auto vft = reinterpret_cast(this->m_pVftable.get()); + return *GuestToHostFunction(vft->fpGetPadQuat, this); + } + + inline float IListener::GetPadMagnitude() + { + auto vft = reinterpret_cast(this->m_pVftable.get()); + return GuestToHostFunction(vft->fpGetPadMagnitude, this); + } + + inline uint32_t IListener::GetPadButtons() + { + auto vft = reinterpret_cast(this->m_pVftable.get()); + return GuestToHostFunction(vft->fpGetPadButtons, this); + } + + inline bool IListener::IsEnabled() + { + auto vft = reinterpret_cast(this->m_pVftable.get()); + return GuestToHostFunction(vft->fpIsEnabled, this); + } +} diff --git a/MarathonRecomp/api/Sonicteam/Player/Load.h b/MarathonRecomp/api/Sonicteam/Player/Load.h new file mode 100644 index 00000000..dedaecb6 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/Load.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Sonicteam::Player +{ + class AnimationScript; + + class Load : public ILoad + { + public: + stdx::map> m_spPackageBinary; + stdx::map> m_spAnimationScript; + stdx::deque> m_dspField38; + xpointer m_pDoc; + }; + + + MARATHON_ASSERT_OFFSETOF(Load, m_spPackageBinary, 0x20); + MARATHON_ASSERT_OFFSETOF(Load, m_spAnimationScript, 0x2C); + MARATHON_ASSERT_OFFSETOF(Load, m_dspField38, 0x38); + MARATHON_ASSERT_OFFSETOF(Load, m_pDoc, 0x4C); + MARATHON_ASSERT_SIZEOF(Load, 0x50); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/MovableBody.h b/MarathonRecomp/api/Sonicteam/Player/MovableBody.h new file mode 100644 index 00000000..5c80c422 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/MovableBody.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace Sonicteam::Player +{ + class PhysicsBodyList; + + class MovableBody : public IPosturePlugIn + { + public: + boost::shared_ptr m_spPhysicsBodyList; + SoX::LinkRef m_lrBody; + SoX::Math::Vector m_BodyForce; + }; + + MARATHON_ASSERT_SIZEOF(MovableBody, 0x30); + MARATHON_ASSERT_OFFSETOF(MovableBody, m_spPhysicsBodyList, 0x4); + MARATHON_ASSERT_OFFSETOF(MovableBody, m_lrBody, 0xC); + MARATHON_ASSERT_OFFSETOF(MovableBody, m_lrBody, 0xC); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/Object.h b/MarathonRecomp/api/Sonicteam/Player/Object.h index 52e59781..13ec8a3b 100644 --- a/MarathonRecomp/api/Sonicteam/Player/Object.h +++ b/MarathonRecomp/api/Sonicteam/Player/Object.h @@ -9,10 +9,13 @@ #include #include #include +#include #include namespace Sonicteam::Player { + class AnimationScript; + class Object : public Actor { public: @@ -44,10 +47,10 @@ namespace Sonicteam::Player bool m_IsAmigo; MARATHON_INSERT_PADDING(1); SoX::RefSharedPointer m_spRootFrame; - SoX::RefSharedPointer<> m_spPackageBinary; + SoX::RefSharedPointer m_spPackageBinary; boost::shared_ptr m_spModel; boost::shared_ptr m_spPostureControl; - boost::shared_ptr m_spStateMachine; + boost::shared_ptr m_spStateMachine; boost::shared_ptr m_spGravity; boost::shared_ptr m_spImpulse; be m_SetupModuleIndexPrefix; @@ -59,7 +62,7 @@ namespace Sonicteam::Player be m_DeltaTime; MARATHON_INSERT_PADDING(0x48); stdx::vector m_vEquipFlags; - stdx::string m_Name; + stdx::string m_AttachPoint; MARATHON_INSERT_PADDING(0x110); template @@ -68,6 +71,18 @@ namespace Sonicteam::Player return (T*)m_spGauge.get(); } + template + T* GetModel() + { + return (T*)m_spModel.get(); + } + + template + T* GetStateMachine() + { + return static_cast(m_spStateMachine.get()); + } + template inline T* GetPlugin(const char* pluginName) { @@ -90,7 +105,7 @@ namespace Sonicteam::Player auto playerIndex = pGame->PlayerActorIDToIndex(m_ActorID); auto padID = pDoc->m_aPadIDs[playerIndex]; - return pDoc->m_vspInputManager[padID].get(); + return pDoc->m_vspInputManagers[padID].get(); } }; @@ -126,6 +141,6 @@ namespace Sonicteam::Player MARATHON_ASSERT_OFFSETOF(Object, m_vspPlugins, 0x114); MARATHON_ASSERT_OFFSETOF(Object, m_DeltaTime, 0x17C); MARATHON_ASSERT_OFFSETOF(Object, m_vEquipFlags, 0x1C8); - MARATHON_ASSERT_OFFSETOF(Object, m_Name, 0x1D8); + MARATHON_ASSERT_OFFSETOF(Object, m_AttachPoint, 0x1D8); MARATHON_ASSERT_SIZEOF(Object, 0x310); } diff --git a/MarathonRecomp/api/Sonicteam/Player/PhysicsBodyList.h b/MarathonRecomp/api/Sonicteam/Player/PhysicsBodyList.h new file mode 100644 index 00000000..6723a180 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/PhysicsBodyList.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include +#include + +namespace Sonicteam::Player +{ + class PhysicsBodyList : public IPlugIn + { + public: + stdx::vector m_vlrBody; + be m_ActorID; // Target + + bool sub_8223B148(SoX::Physics::EntityRef* entityRef); + }; + + MARATHON_ASSERT_SIZEOF(PhysicsBodyList, 0x34); + MARATHON_ASSERT_OFFSETOF(PhysicsBodyList, m_vlrBody, 0x20); + MARATHON_ASSERT_OFFSETOF(PhysicsBodyList, m_ActorID, 0x30); +} + +#include "PhysicsBodyList.inl" diff --git a/MarathonRecomp/api/Sonicteam/Player/PhysicsBodyList.inl b/MarathonRecomp/api/Sonicteam/Player/PhysicsBodyList.inl new file mode 100644 index 00000000..c74457f8 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/PhysicsBodyList.inl @@ -0,0 +1,21 @@ +#pragma once + +namespace Sonicteam::Player +{ + // Recreated from sub_8223B148 + inline bool PhysicsBodyList::sub_8223B148(SoX::Physics::EntityRef* entityRef) + { + if (entityRef->sub_82595500(0)) + { + if (auto entity = entityRef->sub_82595020()) + { + if (entity->m_pReceiver.get()) + m_vlrBody.push_back(*entityRef); + + } + return true; + } + return false; + } +}; + diff --git a/MarathonRecomp/api/Sonicteam/Player/PostureControl.h b/MarathonRecomp/api/Sonicteam/Player/PostureControl.h index c4d273d4..061063db 100644 --- a/MarathonRecomp/api/Sonicteam/Player/PostureControl.h +++ b/MarathonRecomp/api/Sonicteam/Player/PostureControl.h @@ -8,6 +8,16 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include + +// DEBUGGING HFR ISSUES FOR PostureControl +#define MARATHON_POSTURECONTROL_USE_RECREATED_VERSION 0 namespace Sonicteam::Player { @@ -16,11 +26,14 @@ namespace Sonicteam::Player public: enum PostureFlag { - // The player is grounded. - PostureFlag_Grounded = 0x01, + // The player is detecting ground. + PostureFlag_Grounded = 0x1, + + // The player is detecting death collision or water death. + PostureFlag_DeathCollision = 0x2, // The player is brushing against a wall. - PostureFlag_WallSide = 0x08, + PostureFlag_WallSide = 0x8, // The player is head on against a wall. PostureFlag_WallFront = 0x10, @@ -37,6 +50,9 @@ namespace Sonicteam::Player // The player is on water collision. PostureFlag_Water = 0x800, + // The player is in the OTTOTTO state. + PostureFlag_OTTOTTO = 0x2000, + // The player is light dashing. PostureFlag_LightDash = 0x4000, @@ -52,18 +68,155 @@ namespace Sonicteam::Player // The player is on grass collision. PostureFlag_Grass = 0x100000, - // The player is on dirt collision. - PostureFlag_Dirt = 0x200000, + // The player is on dirt/clay collision. + PostureFlag_DirtClay = 0x200000, // The player is on stone collision. PostureFlag_Stone = 0x400000, - // The player is on sand collision. - PostureFlag_Sand = 0x1000000 + // The player is on material 1 collision. + PostureFlag_Material1 = 0x800000, + + // The player is on shoreline collision. + PostureFlag_Sand = 0x1000000, + + // The player is on material 2 collision. + PostureFlag_Material2 = 0x2000000, + + // The player is on material 3 collision. + PostureFlag_Material3 = 0x4000000, + + // The player is on material 4 collision. + PostureFlag_Material4 = 0x8000000 }; - MARATHON_INSERT_PADDING(0xE0); - }; + enum ContactId + { + ContactId_Default = 0, + ContactId_Path = 1, + ContactId_WaterSlider = 2, + ContactId_LightDash = 3, + ContactId_PathCollision = 4, + ContactId_Homing = 5, + ContactId_6 = 6, + ContactId_PostureVehicle = 8, + ContactId_PostureRodeo = 9, + }; + + boost::shared_ptr m_spPhysicsBodyList; + be m_Weight; + be m_SlopeRad; + be m_SlopeRadB; + be m_DownForce; + be m_InterpGravity; + be m_PostureContinueNum; + be m_PostureContinueLen; + be m_RotationSpeedBorder; + be m_PostureIntertiaMove; + boost::shared_ptr m_spPath; + boost::shared_ptr m_spPathGuide; + boost::shared_ptr m_spWaterSlider; + boost::shared_ptr m_spPathLightDash; + boost::shared_ptr m_spPathCollision; + boost::shared_ptr m_spImpulse; + boost::shared_ptr m_spMovableBody; + boost::shared_ptr m_spRotationGravityAxis; + boost::shared_ptr m_spHoming; + boost::shared_ptr m_spPostureEdge; + boost::shared_ptr m_spPostureVehicle; + boost::shared_ptr m_spPostureRodeo; + SoX::Math::Vector m_VectorA0; + SoX::Math::Vector m_GroundUp; // Inverted Normal + bool m_DisableAccuratePosture; + SoX::Math::Vector m_Vector3D0; + SoX::Math::Vector m_Vector3E0; + be m_CurrentPostureContinueNum; + MARATHON_INSERT_PADDING(0x8); + + RotationGravityAxis* GetRotationGravityAxis(); + + MovableBody* GetMovableBody(); + + uint32_t GetPostureContact(); + + template + Type* GetPosturePath(uint32_t path); + + uint32_t OutPostureContactFlag(IPosturePlugIn* plugin); + + bool OutPostureContactPosition(IPosturePlugIn* plugin, SoX::Math::Vector* position); + + bool OutPostureContactUP(IPosturePlugIn* plugin, SoX::Math::Vector* position); + + bool sub_821F1858(IPosturePlugIn* plugin, SoX::Math::Vector vector, SoX::Math::Quaternion* quat); + + SoX::Math::Vector CalculateVerticalImpulse(); + bool sub_821F1410(uint32_t Flag1); + + bool CalculateForwardImpulse(SoX::Math::Vector& outForwardImpulse, uint32_t lostArgument, SoX::Math::Vector point,double delta); + + bool sub_821FC148(SoX::Math::Vector* lerpImpulse, SoX::Math::Vector forwardImpulse, SoX::Math::Vector VerticalImpulse, double delta); + + bool sub_821F1728(IPosturePlugIn* plugin, SoX::Math::Vector& impulse, SoX::Math::Vector& impulseForward, SoX::Math::Vector& impulseVertical, double delta); + + bool sub_821F18E0(IPosturePlugIn* plugin, SoX::Math::Vector contactNormal, SoX::Math::Quaternion* outGroundNormal); + + void sub_821FDF90(SoX::Math::Vector invertNormal); + + bool sub_821FE560(SoX::Math::Vector& position, SoX::Math::Vector& impulse, be* postureFlag); + + void sub_821F1400(uint32_t inputFlag); + + void sub_821F1378(uint32_t inputFlag); + + void sub_821FEEF0(ICollisionListener* listener, uint32_t cflag); + + bool sub_821FF910(SoX::Math::Vector& position, SoX::Math::Quaternion* groundNormal, SoX::Math::Vector& impulse); + + bool sub_821FF0F0(SoX::Math::Vector& p1, SoX::Math::Quaternion* outNormal, SoX::Math::Vector p2); + + bool sub_821F17C8(IPosturePlugIn* plugin); + + bool sub_821FFC08(Sonicteam::SoX::Math::Vector& position, Sonicteam::SoX::Math::Quaternion* groundNormal, Sonicteam::SoX::Math::Vector& impulse); + + void sub_821F1968(SoX::Math::Vector v1, SoX::Math::Vector v2); + + void sub_821FDDB0(); + + // Recreated from sub_82200538, Full 0.9:1 for debugging purposes + void RecreatedUpdate(double deltaTime); + }; + MARATHON_ASSERT_SIZEOF(PostureControl, 0x400); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_spPhysicsBodyList, 0x314); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_Weight, 0x31C); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_SlopeRad, 0x320); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_SlopeRadB, 0x324); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_DownForce, 0x328); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_InterpGravity, 0x32C); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_PostureContinueNum, 0x330); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_PostureContinueLen, 0x334); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_RotationSpeedBorder, 0x338); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_PostureIntertiaMove, 0x33C); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_spPath, 0x340); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_spPathGuide, 0x348); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_spWaterSlider, 0x350); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_spPathLightDash, 0x358); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_spPathCollision, 0x360); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_spImpulse, 0x368); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_spMovableBody, 0x370); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_spRotationGravityAxis, 0x378); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_spHoming, 0x380); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_spPostureEdge, 0x388); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_spPostureVehicle, 0x390); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_spPostureRodeo, 0x398); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_VectorA0, 0x3A0); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_GroundUp, 0x3B0); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_DisableAccuratePosture, 0x3C0); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_Vector3D0, 0x3D0); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_Vector3E0, 0x3E0); + MARATHON_ASSERT_OFFSETOF(PostureControl, m_CurrentPostureContinueNum, 0x3F0); } + +#include "PostureControl.inl" diff --git a/MarathonRecomp/api/Sonicteam/Player/PostureControl.inl b/MarathonRecomp/api/Sonicteam/Player/PostureControl.inl new file mode 100644 index 00000000..546563f4 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/PostureControl.inl @@ -0,0 +1,953 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace Sonicteam::Player +{ + // Recreate from sub_82200538, Full 0.9:1 recreated for debugging purposes + // Silver doesn't stand on marked objects during Psycho Move + // Character doesn't stand on rct conveyors + inline void Sonicteam::Player::PostureControl::RecreatedUpdate(double deltaTime) + { + this->m_DisableAccuratePosture = false; + + auto r1_0xB0 = this->m_GroundNormal; //?? + IPostureControl::RecreatedUpdate(deltaTime); + + //Jump Direction + if ((this->m_PostureFlag118.get() & 8) != 0) + { + this->m_PostureFlag118 = this->m_PostureFlag118.get() & ~8; + this->m_GroundUp = this->m_LocalRotation * Sonicteam::SoX::Math::Vector::Up(); + } + + //m_FlagC8 small, normal collision + this->m_FlagC8 = (this->m_PostureRequestFlag.get() & 0x4000) != 0; //sub_82200EA8(a1 + 0x120, (*(_DWORD *)(a1 + 0x114) >> 0xE) & 1); + auto PostureContactID = this->GetPostureContact(); + auto pPosturePath = this->GetPosturePath(PostureContactID); + auto postureContactFlag = this->OutPostureContactFlag(pPosturePath); //v19 = sub_821F1578(a1, pPosturePath); + this->m_PostureFlag = postureContactFlag; + + //Impulse Direction + if (this->m_PostureRequestFlag.get() & 0x40000) + { + this->m_ImpulseUP = Sonicteam::SoX::Math::Vector::Up(); + } + + this->OutPostureContactPosition(pPosturePath, &this->m_Position); + this->OutPostureContactPosition(this->m_spImpulse.get(), &this->m_Position); + this->OutPostureContactUP(pPosturePath, &this->m_ImpulseUP); + this->OutPostureContactUP(this->m_spImpulse.get(), &this->m_ImpulseUP); + + auto v0 = this->m_ImpulseUP; + + // Lerp Impulse + Sonicteam::SoX::Math::Vector r1_0x60 = Sonicteam::SoX::Math::Vector::Zero(); + auto r1_0x50 = this->m_Position; + auto r1_0x80 = this->m_Position; + + Sonicteam::SoX::Math::Vector r1_0xC0; + Sonicteam::SoX::Math::Vector r1_0x90; + Sonicteam::SoX::Math::Vector r1_0x70; + + //forward impulse + Sonicteam::SoX::Math::Vector r1_0x120; + + Sonicteam::SoX::Math::Vector r1_0xF0; + Sonicteam::SoX::Math::Vector r1_0xE0; + Sonicteam::SoX::Math::Vector r1_0x110; + Sonicteam::SoX::Math::Vector r1_0x1B0; + Sonicteam::SoX::Math::Vector r1_0x140; + Sonicteam::SoX::Math::Vector r1_0x170; + Sonicteam::SoX::Math::Vector r1_0x1C0; + Sonicteam::SoX::Math::Vector r1_0x190; + Sonicteam::SoX::Math::Vector r1_0x1A0; + Sonicteam::SoX::Math::Quaternion r1_0x130; + Sonicteam::SoX::Math::Quaternion r1_0x160; + Sonicteam::SoX::Math::Vector r1_0x150; + + //Can QuickRotate + if (this->sub_82201E78(this->m_Rotation)) + this->m_PostureFlag = this->m_PostureFlag.get() | Sonicteam::Player::PostureControl::PostureFlag_QuickRotate; + + //TODO : redo to not repeat if (PostureContactID < PostureControl::ContactId_6) + using Sonicteam::Player::PostureControl; + switch (PostureContactID) + { + case PostureControl::ContactId_Default: + { + if ((this->m_PostureRequestFlag.get() & 0x20) != 0) + { + this->m_PadRotation = this->sub_82201D88(this->m_Rotation); //IPostureSupportInput + } + else + { + if ((this->m_ContextIFFlag.get() & 0x80000) != 0) + { + this->sub_82201E00(this->m_Rotation); + } + else + { + auto impulseForward = this->m_ImpulseForward.get(); + if (this->m_RotationSpeedBorder > impulseForward) + this->m_Rotation = this->sub_82201D88(this->m_Rotation); //IPostureSupportInput + else + this->m_Rotation = this->sub_82201BC8(this->m_Rotation, impulseForward); + } + } + this->sub_821F1858(this->m_spImpulse.get(), Sonicteam::SoX::Math::Vector::Zero(), &this->m_Rotation); + auto v39 = this->m_GroundUp; + auto v40 = this->m_spPathGuide.get(); + //LABEL_20: + this->sub_821F1858(v40, v39, &this->m_Rotation); + //LABEL_21: + if (PostureContactID < PostureControl::ContactId_6) + { + r1_0x140 = this->CalculateVerticalImpulse(); + r1_0xC0 = r1_0x140; + this->CalculateForwardImpulse(r1_0x120, 0, r1_0x80,deltaTime); + } + } + break; + //Other Cases + case PostureControl::ContactId_Path: + case PostureControl::ContactId_WaterSlider: + case PostureControl::ContactId_LightDash: + { + //LABEL_21: + if (PostureContactID < PostureControl::ContactId_6) + { + r1_0x140 = this->CalculateVerticalImpulse(); + r1_0xC0 = r1_0x140; + this->CalculateForwardImpulse(r1_0x120, 0, r1_0x80, deltaTime); + } + } + break; + case PostureControl::ContactId_PathCollision: + { + r1_0x1A0 = this->sub_82201BC8(this->m_Rotation, this->m_ImpulseForward);; + if (PostureContactID < PostureControl::ContactId_6) + { + r1_0x140 = this->CalculateVerticalImpulse(); + r1_0xC0 = r1_0x140; + this->CalculateForwardImpulse(r1_0x120, 0, r1_0x80, deltaTime); + } + + } + break; + case PostureControl::ContactId_Homing: + { + r1_0x1C0 = this->sub_82201F28(this->m_Rotation, 0.30000001); + this->m_Rotation = r1_0x1C0; + if (PostureContactID < PostureControl::ContactId_6) + { + r1_0x140 = this->CalculateVerticalImpulse(); + r1_0xC0 = r1_0x140; + this->CalculateForwardImpulse(r1_0x120, 0, r1_0x80, deltaTime); + } + } + break; + case PostureControl::ContactId_6: + { + r1_0x130 = this->sub_82201D88(this->m_Rotation); + Sonicteam::SoX::Math::Vector r1_0x130_forward = r1_0x130 * Sonicteam::SoX::Math::Vector::Forward(); + this->sub_821F1858(pPosturePath, r1_0x130_forward, &this->m_Rotation); + if (PostureContactID < PostureControl::ContactId_6) + { + r1_0x140 = this->CalculateVerticalImpulse(); + r1_0xC0 = r1_0x140; + this->CalculateForwardImpulse(r1_0x120, 0, r1_0x80, deltaTime); + } + } + break; + default: + break; + } + + if (!PostureContactID) + { + this->sub_821FC148(&r1_0x60, r1_0x120, r1_0xC0, deltaTime); + //Make Sure it works properly + //this->sub_821F1728(this->m_spMovableBody.get(), r1_0x60, r1_0x120, r1_0x70,deltaTime); + this->sub_821F1728(this->m_spMovableBody.get(), r1_0x60, r1_0x120, r1_0xC0, deltaTime); + } + else if (PostureContactID < 6) + { + this->sub_821F1728(pPosturePath, r1_0x60, r1_0x120, r1_0xC0, deltaTime); + } + + //i think + if (this->m_spPhysicsBodyList.get()) // if ( v51 && sub_82615D60 ) sub_821FD5A0(v51 + 0x20); + this->m_spPhysicsBodyList->m_vlrBody.clear(); + + auto v52 = (this->m_PostureRequestFlag.get() & 0x2000) != 0; + switch (PostureContactID) + { + case PostureControl::ContactId_Default: + { + + auto r1_0x60_len = r1_0x60.Length3().X.get(); //v53 + auto r1_0x90 = r1_0x60.Normalize3(); + this->m_CurrentPostureContinueNum = 0; + do + { + auto ContinueLen = this->m_PostureContinueLen.get(); + if (r1_0x60_len <= ContinueLen) + { + r1_0xF0 = r1_0x90 * r1_0x60_len; + r1_0x60_len = 0.0; + r1_0x60 = r1_0xF0; + } + else + { + r1_0x110 = r1_0x90 * ContinueLen; + r1_0x60_len -= this->m_PostureContinueLen.get(); + r1_0x60 = r1_0x110; + } + + //Not Sure Here + r1_0xE0 = r1_0x50; + + this->m_PostureFlag = this->m_PostureFlag.get() & ~1; + if ((this->m_PostureFlag.get() & 0x40) != 0) + { + if (this->sub_821FE560(r1_0x50, r1_0x60, &this->m_PostureFlag)) + v52 = false; + } + else + { + if ((this->m_ContextIFFlag.get() & 0x1000) != 0) + this->sub_822024F0(r1_0x50, r1_0x60, &this->m_PostureFlag); + else + this->sub_82202300(r1_0x50, r1_0x60, &this->m_PostureFlag); + + this->sub_821FF910(r1_0x50, &this->m_GroundNormal, r1_0x60); + if (this->sub_82201758(r1_0xE0, r1_0x50)) + this->m_PostureFlag = this->m_PostureFlag.get() | PostureControl::PostureFlag_OTTOTTO; + r1_0x1B0 = r1_0x50 - r1_0x80; + this->sub_821FF0F0(r1_0x50, &this->m_GroundNormal, r1_0x1B0); + this->m_CurrentPostureContinueNum = this->m_CurrentPostureContinueNum + 1; + if (r1_0x60.Length3().X > 0.0) + { + r1_0x60_len += r1_0x60.Length3().X; + r1_0x140 = r1_0x60.Normalize3(); + r1_0x90 = r1_0x140; + } + } + } while (((this->m_ContextIFFlag.get() & 0x40) == 0 || (this->m_PostureFlag.get() & 1) == 0) + && r1_0x60_len > 0.0 + && this->m_CurrentPostureContinueNum < this->m_PostureContinueNum); + + r1_0x170 = r1_0x50 - r1_0x80; + this->sub_821F18E0(this->m_spImpulse.get(), r1_0x170, &this->m_GroundNormal); + this->sub_821F18E0(this->m_spPathGuide.get(), this->m_GroundUp, &this->m_GroundNormal); + this->m_Position = r1_0x50; + + if (!this->m_DisableAccuratePosture) + { + be Flag1; + auto v69 = this->sub_82203840(&this->m_Position, this->m_Position, &Flag1); + this->sub_821FEEF0(v69, Flag1); + } + + if (this->EdgeGrabLeftOverFunction(r1_0x50)) + { + this->m_PostureFlag = this->m_PostureFlag.get() | 0x80; + auto pPostureEdge = static_cast(this->m_spPostureEdge.get()); + pPostureEdge->m_Field54 = 0x80; + pPostureEdge->m_Field70 = 0; + } + + if (this->sub_821F17C8(this->m_spImpulse.get()) && + this->sub_821F17C8(this->m_spPathGuide.get()) && + v52) + { + r1_0x1C0 = Sonicteam::SoX::Math::Quaternion::Slerp(r1_0xB0, this->m_GroundNormal, 0.1); + this->m_GroundNormal = r1_0x1C0; + } + } + break; + case PostureControl::ContactId_Path: + case PostureControl::ContactId_WaterSlider: + case PostureControl::ContactId_PathCollision: + { + this->sub_822024F0(r1_0x50, r1_0x60, &this->m_PostureFlag); + this->sub_821F1858(pPosturePath, r1_0x60, &this->m_Rotation); + this->sub_821F18E0(pPosturePath, r1_0x60, &this->m_GroundNormal); + r1_0x50 = r1_0x50 + r1_0x60; + this->OutPostureContactPosition(pPosturePath, &this->m_Position); + this->m_GroundNormal = Sonicteam::SoX::Math::Quaternion::Slerp(r1_0xB0, this->m_GroundNormal, 0.1); + } + break; + case PostureControl::ContactId_LightDash: + { + this->sub_822024F0(r1_0x50, r1_0x60, &this->m_PostureFlag); + this->sub_821F1858(pPosturePath, r1_0x60, &this->m_Rotation); + this->sub_821F18E0(pPosturePath, r1_0x60, &this->m_GroundNormal); + auto gr1_0x50 = guest_heap_var(r1_0x50); + this->OutPostureContactPosition(pPosturePath, gr1_0x50.get()); + r1_0x50 = *gr1_0x50; + r1_0x160 = r1_0x50 - r1_0x80; + this->sub_821FF0F0(r1_0x50, &this->m_GroundNormal, r1_0x160); + this->m_Position = r1_0x50; + this->m_GroundNormal = Sonicteam::SoX::Math::Quaternion::Slerp(r1_0xB0, this->m_GroundNormal, 0.1); + } + break; + case PostureControl::ContactId_Homing: + { + this->sub_821FFC08(r1_0x50, &this->m_GroundNormal, r1_0x60); + this->sub_821F1858(pPosturePath, r1_0x60, &this->m_Rotation); + this->sub_821F18E0(pPosturePath, r1_0x60, &this->m_GroundNormal); + r1_0x50 = r1_0x50 + r1_0x60; + r1_0x150 = r1_0x50 - r1_0x80; + this->sub_821FF0F0(r1_0x50, &this->m_GroundNormal, r1_0x150); + this->m_Position = r1_0x50; + if (!this->m_DisableAccuratePosture) + { + be Flag1; + auto v69 = this->sub_82203840(&this->m_Position, this->m_Position, &Flag1); + this->sub_821FEEF0(v69, Flag1); + } + this->m_PostureFlag = this->m_PostureFlag | this->OutPostureContactFlag(pPosturePath); + } + break; + case PostureControl::ContactId_PostureVehicle: + case PostureControl::ContactId_PostureRodeo: + { + this->sub_821F1858(pPosturePath, r1_0x60, &this->m_Rotation); + } + break; + default: + break; + } + r1_0x190 = this->m_Position - r1_0x80; + guest_heap_var gr1_0x190(r1_0x190); + this->OutPostureContactPosition(this->m_spPathGuide.get(), gr1_0x190.get()); + this->sub_821FDDB0(); + return; + } + + inline RotationGravityAxis* PostureControl::GetRotationGravityAxis() + { + return reinterpret_cast(this->m_spRotationGravityAxis.get()); + } + + inline MovableBody* PostureControl::GetMovableBody() + { + return reinterpret_cast(this->m_spMovableBody.get()); + } + + inline uint32_t PostureControl::GetPostureContact() + { + if (m_spPath.get() && m_spPath->IsInContact()) + return 1; + + if (m_spWaterSlider.get() && m_spWaterSlider->IsInContact()) + return 2; + + if (m_spPathLightDash.get() && m_spPathLightDash->IsInContact()) + return 3; + + if (m_spPathCollision.get() && m_spPathCollision->IsInContact()) + return 4; + + if (m_spHoming.get() && m_spHoming->IsInContact()) + return 5; + + if (m_spPostureVehicle.get() && m_spPostureVehicle->IsInContact()) + return 8; + + if (m_spPostureRodeo.get() && m_spPostureRodeo->IsInContact()) + return 9; + else + return (this->m_ContextIFFlag.get() & 0x40000) == 0 ? 0 : 6; + } + + //ref to sub_821FDC28 + template + inline Type* PostureControl::GetPosturePath(uint32_t path) + { + switch (path) + { + case 1: + return static_cast(m_spPath.get()); + case 2: + return static_cast(m_spWaterSlider.get()); + case 3: + return static_cast(m_spPathLightDash.get()); + case 4: + return static_cast(m_spPathCollision.get()); + case 5: + return static_cast(m_spHoming.get()); + case 6: + return static_cast(m_spPostureEdge.get()); + case 8: + return static_cast(m_spPostureVehicle.get()); + case 9: + return static_cast(m_spPostureRodeo.get()); + default: + return static_cast(m_spPosturePlugIn.get()); + } + } + + //sub_821F1578 + inline uint32_t PostureControl::OutPostureContactFlag(IPosturePlugIn* plugin) + { + if (plugin && plugin->IsInContact()) + return plugin->GetContactFlag(); + + return false; + } + + //sub_821F1608 + inline bool PostureControl::OutPostureContactPosition(IPosturePlugIn* plugin, SoX::Math::Vector* position) + { + if (plugin && plugin->IsInContact()) + { + plugin->OutContactPosition(position); + return true; + } + + return false; + } + + //sub_821F1698 + inline bool PostureControl::OutPostureContactUP(IPosturePlugIn* plugin, SoX::Math::Vector* position) + { + if (plugin && plugin->IsInContact()) + { + plugin->OutContactUP(position); + return true; + } + + return false; + } + + inline bool PostureControl::sub_821F1858(IPosturePlugIn* plugin, SoX::Math::Vector vector, SoX::Math::Quaternion* quat) + { + if (plugin && plugin->IsInContact()) + return plugin->Func24(guest_heap_var(vector).get(), quat); + + return false; + } + + //ref to sub_821FDCD0 + inline SoX::Math::Vector PostureControl::CalculateVerticalImpulse() + { + SoX::Math::Vector vector; + auto velocityImpulse = this->m_ImpulseUP * this->m_ImpulseVertical.get(); + auto velocityGravity = this->m_GravityDirection * this->m_GravityForce.get(); + auto Velocity = velocityImpulse + velocityGravity; + vector = Velocity; + if (this->m_ImpulseVertical.get() == 0.0 && this->m_GravityForce.get() == 0.0) + return vector; + + auto usableImpulse = this->m_ImpulseVertical.get() - this->m_GravityForce.get(); + + if (-200.0 <= usableImpulse && usableImpulse <= 200.0) + { + this->m_PostureFlag = this->m_PostureFlag.get() | PostureFlag_FallIntermediate; + return vector; + } + if (usableImpulse < 0.0) + { + this->m_PostureFlag = this->m_PostureFlag.get() | PostureFlag_Fall; + } + return vector; + } + + //done, probabl it works fine + inline bool PostureControl::sub_821F1410(uint32_t Flag1) + { + bool result = (Flag1 & 8) != 0; + if ((Flag1 & 0x40) != 0 && (this->m_PostureRequestFlag.get() & 8) != 0) + result = 1; + if ((Flag1 & 0x100) != 0 && (this->m_PostureRequestFlag.get() & 0x200) != 0) + result = 1; + if ((Flag1 & 1) != 0 && (this->m_ContextIFFlag.get() & 0x200000) != 0) + return 1; + + return result; + } + + //sub_821FE3A0, --done-- + inline bool PostureControl::CalculateForwardImpulse(SoX::Math::Vector& outForwardImpulse, uint32_t lostArgument, SoX::Math::Vector point,double delta) + { + this->m_VectorA0 = SoX::Math::Quaternion::Identity(); + auto v12 = this->sub_822014B8(point); + if (!v12) + { + outForwardImpulse = (this->m_Rotation * (SoX::Math::Vector::Forward() * this->m_ImpulseForward.get())); + } + else + { + auto Flag1 = v12->GetCollisionFlag(); + if (!this->sub_821F1410(Flag1)) + { + outForwardImpulse = (this->m_Rotation * (SoX::Math::Vector::Forward() * this->m_ImpulseForward.get())); + } + else + { + auto normal = v12->GetContactNormal(); + outForwardImpulse = (this->m_LocalRotation * (SoX::Math::Vector::Forward() * this->m_ImpulseForward.get())); + m_VectorA0 = SoX::Math::Quaternion::Identity(); + } + } + + if (((this->m_PostureRequestFlag.get() & 0x20) != 0) && ((this->m_ContextIFFlag.get() & 0x100) == 0)) + { + auto forwardIntertiaMove = (SoX::Math::Vector::Forward() * this->m_PostureIntertiaMove * this->m_InputForce); + auto forwardRotatedIntertiaMove = (m_PadRotation * forwardIntertiaMove); + outForwardImpulse = outForwardImpulse + forwardRotatedIntertiaMove; + } + + return 1; + } + + inline bool PostureControl::sub_821FC148(SoX::Math::Vector* lerpImpulse, SoX::Math::Vector forwardImpulse, SoX::Math::Vector VerticalImpulse, double delta) + { + if (!lerpImpulse) + return 0; + + *lerpImpulse = (forwardImpulse + VerticalImpulse) * delta; + return 1; + } + + inline bool PostureControl::sub_821F1728(IPosturePlugIn* plugin, SoX::Math::Vector& impulse, SoX::Math::Vector& impulseForward, SoX::Math::Vector& impulseVertical, double delta) + { + if (plugin && plugin->IsInContact()) + { + guest_heap_var< SoX::Math::Vector> gsv_v1(impulseForward); + guest_heap_var< SoX::Math::Vector> gsv_v2(impulseVertical); + guest_heap_var< SoX::Math::Vector> gsv_v3(impulse); + plugin->Func20(gsv_v1.get(), gsv_v2.get(), gsv_v1.get(), gsv_v3.get(), delta); + impulse = *gsv_v3; + return 1; + } + return 0; + } + + inline bool PostureControl::sub_821F18E0(IPosturePlugIn* plugin, SoX::Math::Vector contactNormal, SoX::Math::Quaternion* outGroundNormal) + { + if (plugin && plugin->IsInContact()) + { + plugin->Func28(guest_heap_var(contactNormal).get(), outGroundNormal); + return true; + } + return false; + } + + + //--done-- + inline void PostureControl::sub_821FDF90(SoX::Math::Vector invertNormal) + { + m_GroundUp = invertNormal; + if ((this->m_PostureFlag.get() & PostureControl::PostureFlag_Tentative) != 0 || (this->m_PostureRequestFlag.get() & 0x2000) != 0) + { + m_ImpulseUP = invertNormal.InvertNormal(); + } + else if (this->m_PostureFlag.get() & PostureControl::PostureFlag_Grounded) + { + m_ImpulseUP = SoX::Math::Vector::Up(); + } + //TODO : Not Sure if It Really XMVector3Rotate, probably XMQuatMultiply, but for GroundNormal its not exactly Quaternion but :|, ot ST really did jackshit in code + this->sub_82200EC0(invertNormal); + this->sub_82201620(invertNormal, m_GroundNormal * m_Rotation); + this->sub_82202B08(m_GroundNormal * m_Rotation); + } + + //--done-- make sure it works properly + inline bool PostureControl::sub_821FE560(SoX::Math::Vector& position, SoX::Math::Vector& impulse, be* postureFlag) + { + auto listener = this->sub_82202180(position, position + impulse, 0); + if (!listener) + return 0; + + //TODO: make sure it works properly + if ((this->m_PostureRequestFlag.get() & 0x40) != 0 && (listener->GetCollisionFlag() & 0x400) != 0) + { + auto nImpulse = impulse.NormalizeEX(); + impulse = nImpulse.first; + auto normImpulseX = nImpulse.second; + auto norm_14 = listener->GetLength(impulse.X); + auto normal = listener->GetContactNormal(); + this->sub_821F18E0(m_spRotationGravityAxis.get(), norm_14, &m_GroundNormal); + position = listener->GetContactPosition(); + impulse = SoX::Math::Vector::Zero(); + *postureFlag = PostureControl::PostureFlag_Stone | PostureControl::PostureFlag_Grounded | PostureControl::PostureFlag_WallSide; + this->sub_821FDF90(listener->GetContactNormal().InvertNormal()); + return 1; + } + else if ((listener->GetCollisionFlag() & 0x1) != 0) + { + auto nImpulse = impulse.NormalizeEX(); + impulse = nImpulse.first; + auto normImpulseX = nImpulse.second; + auto norm_14 = listener->GetLength(impulse.X); + auto normal = listener->GetContactNormal(); + + if (impulse.Dot(normal.InvertNormal()).X > 0.89999998) + *postureFlag = PostureControl::PostureFlag_WallFront; + + position = position + (impulse * norm_14); + + auto v33 = normal.InvertNormal().Cross(impulse); + auto v34 = v33.Cross(normal.InvertNormal()); + auto v32 = v34 * (normImpulseX - norm_14); + + impulse = v32; + *postureFlag = PostureControl::PostureFlag_WallSide; + + } + return 0; + } + + inline void PostureControl::sub_821F1400(uint32_t inputFlag) + { + uint32_t materialBits = (inputFlag >> 4) & 0xFF00000; + this->m_PostureFlag = (this->m_PostureFlag.get() & ~(PostureControl::PostureFlag_Grass | PostureControl::PostureFlag_DirtClay | PostureControl::PostureFlag_Stone | PostureControl::PostureFlag_Material1 | PostureControl::PostureFlag_Sand | PostureControl::PostureFlag_Material2 | PostureControl::PostureFlag_Material3 | PostureControl::PostureFlag_Material4)) | materialBits; // this->m_PostureFlag = (this->m_PostureFlag & 0xF00FFFFF) | materialBits; + } + + // TODO : Make Readable, if you try to do check water, bounce on it and if you didn't hear water and sonic just died then you did something wrong + // --done-- + inline void PostureControl::sub_821F1378(uint32_t inputFlag) + { + GuestToHostFunction(::sub_821F1378, this, inputFlag); + return; + + uint32_t flags = this->m_PostureFlag.get(); + uint32_t transformedBits = ((inputFlag << 2) & 0xFFFFFFFC) | inputFlag; + uint32_t rotatedInput = (inputFlag << 2) | (inputFlag >> 30); + transformedBits = (rotatedInput & 0x100) | (transformedBits & 0xFFFFFEFF); + transformedBits = (transformedBits & 0x300) | (inputFlag & 0x100); + transformedBits = ((transformedBits << 2) & 0xFFFFFFFC) | + (((inputFlag << 29) | (inputFlag >> 3)) & 0x1) | + (inputFlag & 0x2); + + flags |= transformedBits; + this->m_PostureFlag = flags; + + if (inputFlag & 0x400) flags |= PostureControl::PostureFlag_Tentative; + + uint32_t rotatedBits = (((inputFlag << 23) | (inputFlag >> 9)) & 0x4) | + (((inputFlag << 3) | (inputFlag >> 29)) & 0x8); + + flags |= rotatedBits; + this->m_PostureFlag = flags; + + + if (inputFlag & 0x1000) flags |= PostureControl::PostureFlag_Stone; + + this->m_PostureFlag = flags; + } + + //--done-- + inline void PostureControl::sub_821FEEF0(ICollisionListener* listener, uint32_t cflag) + { + if ((cflag & 0x10) != 0 && listener) + { + auto lrEntity = listener->GetContactEntity(); + if (lrEntity->m_pElement.get() && lrEntity->m_pElement->IsInitializedToWorld()) + { + auto position = listener->GetContactPosition(); + auto flag = listener->GetRayFlag(); + lrEntity = listener->GetContactEntity(); + struct _message_ : SoX::Message<0x1A001> + { + be field4 = 0; + be field8 = 0; //ret-prm + SoX::Math::Vector point; + be rflag; + SoX::RefSharedPointer robj; + } msg; + msg.point = position; + msg.rflag = flag; + if (m_spPath.get() && lrEntity->m_pElement->ProcessMessage(msg) && m_spPath->SetControllerMovement(msg.robj, m_Rotation)) + { + m_PostureFlag = m_PostureFlag.get() | PostureControl::PostureFlag_RailGrind; + } + } + } + if ((cflag & 0x20) != 0) + { + m_PostureFlag = m_PostureFlag.get() | 0x80; + if (auto pPostureEdge = static_cast(m_spPostureEdge.get())) + { + pPostureEdge->m_Field54 = 0x80; + pPostureEdge->m_Field70 = 0; + } + } + if ((m_PostureRequestFlag.get() & 0x40) != 0 && (cflag & 0x400) != 0) + m_PostureFlag = m_PostureFlag.get() | PostureControl::PostureFlag_Tentative; + } + + //--done-- + inline bool PostureControl::sub_821FF910(SoX::Math::Vector& position, SoX::Math::Quaternion* groundNormal, SoX::Math::Vector& impulse) + { + be flag; + auto listener = this->sub_82201058(position, position + impulse, &flag); + this->sub_821F1378(flag); + this->sub_821F1400(flag); + this->sub_821FEEF0(listener, flag); + if (!listener) + { + position = (position + impulse); + impulse = SoX::Math::Vector::Zero(); + return true; + } + + if (!this->sub_821F1410(flag)) + { + return false; + } + + auto nImpulse = impulse.NormalizeEX(); + impulse = nImpulse.first; + float normX = nImpulse.second; + float normX_14 = listener->GetLength(normX); + auto normal = listener->GetContactNormal(); + this->sub_821F18E0(this->m_spRotationGravityAxis.get(), normal, groundNormal); + position = listener->GetContactPosition(); + auto invertNormal = SoX::Math::Vector::Zero(); + if ((this->m_ContextIFFlag.get() & 0x40) != 0) + { + impulse = SoX::Math::Vector::Zero(); + invertNormal = listener->GetContactNormal().InvertNormal(); + } + else + { + auto rot_1 = SoX::Math::Quaternion::CreateFromVectors(SoX::Math::Vector::Up(), normal, SoX::Math::Vector::Right()); + auto rot_2 = this->m_Rotation; + + auto forwardNorm = (SoX::Math::Vector)(this->m_Rotation * (SoX::Math::Vector::Forward() * (normX - normX_14))); + auto upRightNormal = (rot_1 * forwardNorm); + impulse = upRightNormal; + invertNormal = listener->GetContactNormal().InvertNormal(); + } + this->sub_821FDF90(invertNormal); + if (!m_spPhysicsBodyList.get()) + { + return true; + } + auto listenerEntity = listener->GetContactEntity(); + m_spPhysicsBodyList->sub_8223B148(listenerEntity.get()); + return true; + } + + //--done-- + inline bool PostureControl::sub_821FF0F0(SoX::Math::Vector& p1, SoX::Math::Quaternion* outNormal, SoX::Math::Vector p2) + { + if ((this->m_PostureRequestFlag.get() & 0x10) != 0) + return false; + + auto v28 = m_GroundUp * m_DownForce; + auto v8 = true; + + if (p2.Length3().X > 0.0 && (this->m_ContextIFFlag.get() & 0x40) != 0) + { + auto v12 = v28.Normalize3(); + auto v13 = p2.Normalize3(); + v8 = SoX::Math::Vector::Dot(v13, v12).X > 0.0; + } + + ICollisionListener* v14; + be Flag1; + if (((this->m_PostureFlag.get() & PostureControl::PostureFlag_Grounded) == 0) + && v8 + && (v14 = this->sub_822011E8(p1 - v28, p1 + v28, &Flag1)) != 0 + && this->sub_821F1410(Flag1)) + { + this->sub_821F1378(Flag1); + this->sub_821F1400(Flag1); + this->sub_821FEEF0(v14, Flag1); + auto v15 = v14->GetContactNormal(); + this->sub_821F18E0(m_spRotationGravityAxis.get(), v15, outNormal); + auto v16 = v14->GetContactNormal(); + sub_821FDF90(v16.InvertNormal()); + auto v19 = v14->GetLength(); + auto v35 = (v28.Normalize3() * v19); + auto v34 = p1 - v28; + auto v30 = v34 + v35; + p1 = v30; + if (m_spPhysicsBodyList.get()) + { + auto entity = v14->GetContactEntity(); + m_spPhysicsBodyList->sub_8223B148(entity.get()); + + } + return true; + } + + return false; + } + + inline bool PostureControl::sub_821F17C8(IPosturePlugIn* plugin) + { + if (plugin->IsInContact()) + { + plugin->IsOffContact(); + return true; + } + return false; + } + + //--done-- + inline bool PostureControl::sub_821FFC08(Sonicteam::SoX::Math::Vector& position, Sonicteam::SoX::Math::Quaternion* groundNormal, Sonicteam::SoX::Math::Vector& impulse) + { + auto v63 = position + impulse; + be Flag1; + auto v8 = this->sub_82202180(position, v63, &Flag1); + this->sub_821F1378(Flag1); + this->sub_821F1400(Flag1); + this->sub_821FEEF0(v8, Flag1); + if (v8) + { + auto [nImpulse, length] = impulse.NormalizeEX(); + impulse = nImpulse; + auto v11 = v8->GetLength(); + auto v51 = v8->GetContactNormal(); + if ((Flag1.get() & 0x400) != 0) + { + if (nImpulse.Dot(v51.InvertNormal()).X > 0.80000001) + { + this->sub_821F18E0(m_spRotationGravityAxis.get(), v51, groundNormal); + auto v58 = nImpulse * v11; + position = position + v58; + auto v65 = nImpulse * 50.0; + auto v62 = position + v65; + if (auto v14 = this->sub_82201350(position, v62, 0)) + { + auto v52 = v14->GetContactPosition(); + position = v52; + impulse = SoX::Math::Vector::Zero(); + m_DisableAccuratePosture = 1; + + if (m_spPhysicsBodyList.get()) + { + auto entity = v8->GetContactEntity(); + m_spPhysicsBodyList->sub_8223B148(entity.get()); + } + + m_PostureFlag = m_PostureFlag.get() | PostureControl::PostureFlag_Grass | PostureControl::PostureFlag_Grounded; + + auto v20 = v8->GetContactNormal(); + this->sub_821FDF90(v20.InvertNormal()); + return 1; + } + } + } + + if ((Flag1.get() & 1) != 0) + { + auto v62 = nImpulse * v11; + if (nImpulse.Dot(v51.InvertNormal()).X >= 0.89999998) + m_PostureFlag = m_PostureFlag.get() | PostureControl::PostureFlag_WallFront; + + position = position + v62; + impulse = SoX::Math::Vector::Zero(); + + m_PostureFlag = m_PostureFlag.get() | PostureControl::PostureFlag_WallSide; + } + } + + + auto v64 = position + impulse; + auto v27 = this->sub_82201058(position, v64, &Flag1); + this->sub_821F1378(Flag1); + this->sub_821F1400(Flag1); + this->sub_821FEEF0(v27, Flag1); + if (!v27) + { + position = position + impulse; + impulse = SoX::Math::Vector::Zero(); + return 1; + } + if (this->sub_821F1410(Flag1)) + { + auto [nImpulse, length] = impulse.NormalizeEX(); + impulse = nImpulse; + auto v30 = v27->GetLength(); + auto v51 = v27->GetContactNormal(); + this->sub_821F18E0(m_spRotationGravityAxis.get(), v51, groundNormal); + auto v60 = impulse * v30; + position = position + v60; + if ((m_PostureRequestFlag.get() & 0x40) != 0) + { + impulse = SoX::Math::Vector::Zero(); + auto v44 = v27->GetContactNormal(); + this->sub_821FDF90(v44.InvertNormal()); + } + else + { + auto v70 = SoX::Math::Quaternion::CreateFromVectors(SoX::Math::Vector::Up(), v51, SoX::Math::Vector::Right()); + auto v52 = (SoX::Math::Vector)(m_Rotation * (SoX::Math::Vector::Forward() * (length - v30))); + impulse = v70 * v52; + this->sub_821FDF90(v27->GetContactNormal()); + } + + if (m_spPhysicsBodyList.get()) + { + auto entity = v27->GetContactEntity(); + m_spPhysicsBodyList->sub_8223B148(entity.get()); + } + + } + return 0; + } + + inline void PostureControl::sub_821F1968(SoX::Math::Vector v1, SoX::Math::Vector v2) + { + this->m_LocalRotation = v2; + this->m_LocalPosition = v1; + if (auto pRootFrame = m_spRootFrame.get()) + { + auto m1 = SoX::Math::Matrix4x4::RotationQuaternion(m_LocalRotation); + auto m2 = SoX::Math::Matrix4x4::TranslationFromVector(m_LocalPosition); + auto f = m1 * m2; //XMMatrixMultiply_2___1 82168C48 + pRootFrame->UpdateTransform(f); + } + } + + inline void PostureControl::sub_821FDDB0() + { + //Spining + if ((m_PostureFlag118.get() & 0x10) != 0) + { + m_PostureFlag118 = m_PostureFlag118.get() & ~0x10; + this->sub_821F1968(m_LocalPosition, m_LocalRotation); + } + else + { + this->sub_821F1968(m_Position, m_Rotation * (SoX::Math::Quaternion)m_GroundNormal); // * = XMQuaternionMultiplys + } + + if ((m_PostureFlag.get() & PostureControl::PostureControl::PostureFlag_Grounded) == 0) + { + m_GroundUp = SoX::Math::Vector::Up().InvertNormal(); + this->sub_82200EC0(m_GroundUp); + } + + if ((m_PostureRequestFlag.get() & 0x1000) != 0) + { + m_Vector3D0 = m_Rotation; + m_Vector3E0 = m_GroundNormal; + } + + if ((m_PostureRequestFlag.get() & 0x2000) != 0) + { + auto matrix = SoX::Math::Matrix4x4::LookToRH(m_Position, m_GroundUp.InvertNormal(), m_Position + SoX::Math::Vector::Up()); + if (auto pRootFrame = m_spRootFrame.get()) + { + auto m1 = SoX::Math::Matrix4x4::RotationQuaternion(matrix.V[0]); + auto m2 = SoX::Math::Matrix4x4::TranslationFromVector(matrix.V[1]); + auto f = m1 * m2; //XMMatrixMultiply_2___1 82168C48 + pRootFrame->UpdateTransform(f); + } + } + } + +} diff --git a/MarathonRecomp/api/Sonicteam/Player/PostureEdge.h b/MarathonRecomp/api/Sonicteam/Player/PostureEdge.h new file mode 100644 index 00000000..96000294 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/PostureEdge.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Sonicteam::Player +{ + class PostureEdge : public IPlugIn, public IFlagCommunicator, public IPosturePlugIn, public IPostureSupportRayTemplate, public IPostureSupportRayTemplate + { + public: + SoX::RefSharedPointer m_spPhysicsWorld; + be m_Field54; + SoX::Math::Vector m_Vector60; + bool m_Field70; + be m_Field74; + }; + + MARATHON_ASSERT_SIZEOF(PostureEdge, 0x80); + MARATHON_ASSERT_OFFSETOF(PostureEdge, m_spPhysicsWorld, 0x50); + MARATHON_ASSERT_OFFSETOF(PostureEdge, m_Field54, 0x54); + MARATHON_ASSERT_OFFSETOF(PostureEdge, m_Vector60, 0x60); + MARATHON_ASSERT_OFFSETOF(PostureEdge, m_Field70, 0x70); + MARATHON_ASSERT_OFFSETOF(PostureEdge, m_Field74, 0x74); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/PostureVehicle.h b/MarathonRecomp/api/Sonicteam/Player/PostureVehicle.h new file mode 100644 index 00000000..19e4af51 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/PostureVehicle.h @@ -0,0 +1,69 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Sonicteam::Player +{ + class PostureVehicle : public IPlugIn, public IPosturePlugIn, public IDynamicLink, public IExportExternalFlag, public IStepable, public IFlagCommunicator, public IExportVehicleFlag + { + public: + SoX::RefSharedPointer m_spWorld; + SoX::RefSharedPointer m_spRayCast; + SoX::Physics::EntityRef m_CollideEntity; + SoX::RefSharedPointer m_spAttachNode; + boost::shared_ptr m_spVehicleListener; + MARATHON_INSERT_PADDING(0x8); + be m_VehicleFlag1; + be m_VehicleFlag2; + be m_VehicleFlag3; + MARATHON_INSERT_PADDING(4); + bool m_InVehicle; // collision checker + SoX::Math::Vector m_Rotation; + SoX::Math::Vector m_Position; + stdx::deque m_dEntityRef; + xpointer m_pPlayer; + xpointer m_spComboAttackManager; + bool m_IsBroken; // Contact Flag + + template + T* GetRayCast() + { + return static_cast(m_spRayCast.get()); + } + + }; + + MARATHON_ASSERT_SIZEOF(PostureVehicle, 0xC0); + MARATHON_ASSERT_OFFSETOF(PostureVehicle, m_spWorld, 0x38); + MARATHON_ASSERT_OFFSETOF(PostureVehicle, m_spRayCast, 0x3C); + MARATHON_ASSERT_OFFSETOF(PostureVehicle, m_CollideEntity, 0x40); + MARATHON_ASSERT_OFFSETOF(PostureVehicle, m_spAttachNode, 0x50); + MARATHON_ASSERT_OFFSETOF(PostureVehicle, m_spVehicleListener, 0x54); + MARATHON_ASSERT_OFFSETOF(PostureVehicle, m_VehicleFlag1, 0x64); + MARATHON_ASSERT_OFFSETOF(PostureVehicle, m_VehicleFlag2, 0x68); + MARATHON_ASSERT_OFFSETOF(PostureVehicle, m_VehicleFlag3, 0x6C); + MARATHON_ASSERT_OFFSETOF(PostureVehicle, m_InVehicle, 0x74); + MARATHON_ASSERT_OFFSETOF(PostureVehicle, m_Rotation, 0x80); + MARATHON_ASSERT_OFFSETOF(PostureVehicle, m_Position, 0x90); + MARATHON_ASSERT_OFFSETOF(PostureVehicle, m_dEntityRef, 0xA0); + MARATHON_ASSERT_OFFSETOF(PostureVehicle, m_pPlayer, 0xB4); + MARATHON_ASSERT_OFFSETOF(PostureVehicle, m_spComboAttackManager, 0xB8); + MARATHON_ASSERT_OFFSETOF(PostureVehicle, m_IsBroken, 0xBC); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/RealGroundRayListener.h b/MarathonRecomp/api/Sonicteam/Player/RealGroundRayListener.h new file mode 100644 index 00000000..a6e2c3bb --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/RealGroundRayListener.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include +#include +#include + +namespace Sonicteam::Player +{ + class RealGroundRayListener: public ICollisionListenerTemplate {}; + + MARATHON_ASSERT_SIZEOF(RealGroundRayListener, 0x80); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/RotationGravityAxis.h b/MarathonRecomp/api/Sonicteam/Player/RotationGravityAxis.h new file mode 100644 index 00000000..9bf38833 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/RotationGravityAxis.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include + +namespace Sonicteam::Player +{ + class RotationGravityAxis : public IPosturePlugIn + { + public: + SoX::Math::Vector m_GravityAxis; + }; + + MARATHON_ASSERT_SIZEOF(RotationGravityAxis, 0x20); + MARATHON_ASSERT_OFFSETOF(RotationGravityAxis, m_GravityAxis, 0x10); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/State/CommonContext.h b/MarathonRecomp/api/Sonicteam/Player/State/CommonContext.h index a84a51d9..2f2cadc3 100644 --- a/MarathonRecomp/api/Sonicteam/Player/State/CommonContext.h +++ b/MarathonRecomp/api/Sonicteam/Player/State/CommonContext.h @@ -28,7 +28,64 @@ namespace Sonicteam::Player::State MARATHON_INSERT_PADDING(8); boost::shared_ptr m_spInputListenerNormal; boost::anonymous_shared_ptr m_spInputListenerAmigo; - MARATHON_INSERT_PADDING(0xE8); + be m_Field148; + be gravity; // Lua parameter (no "c_" prefix) + be c_brake_acc; + be c_brake_dashpanel; + be c_walk_border; + be c_run_border; + be c_walk_speed_max; + be c_run_acc; + be c_run_speed_max; + be c_speedup_acc; + be c_speedup_speed_max; + be c_jump_time_min; + be c_jump_brake; + be c_jump_speed_acc; + be c_jump_speed_brake; + be c_jump_speed; + be c_jump_walk; + be c_jump_run; + be c_brake_quick_acc; + be c_wait_no_input_time; + be c_damage_time; + be c_damage_jump; + be c_damage_speed; + be c_run_against_time; + be c_grind_speed_org; + be c_grind_acc; + be c_grind_speed_max; + be c_grind_time; + be c_grind_penalty_time; + be c_grind_brake_acc; + be c_invincible_time; + be c_invincible_time_ring1; + be c_invincible_item; + be c_speedup_time; + be c_wind_init; + be c_wind_spd; + be c_wind_dist; + be c_border_gravity; + be c_landing_time; + be c_ottoto_time; + be c_dead_animation_time; + be c_dead_animation_time_coll; + be c_wallwait_time; + be c_lclick_time; + be c_flight_acc; + be c_flight_speed_acc; + be c_flight_speed_min; + be c_flight_speed_max; + be c_hovering_acc; + be c_climb_speed; + be c_stun; + be c_brake_acc_sand; + be c_run_acc_sand; + be c_jump_speed_sand; + be c_psi_throw_speed; + be m_Field224; + be m_Field228; + be m_Field22C; SoX::Input::Manager* GetInputManager() const { @@ -52,5 +109,63 @@ namespace Sonicteam::Player::State MARATHON_ASSERT_OFFSETOF(CommonContext, m_spScore, 0x128); MARATHON_ASSERT_OFFSETOF(CommonContext, m_spInputListenerNormal, 0x138); MARATHON_ASSERT_OFFSETOF(CommonContext, m_spInputListenerAmigo, 0x140); + MARATHON_ASSERT_OFFSETOF(CommonContext, m_Field148, 0x148); + MARATHON_ASSERT_OFFSETOF(CommonContext, gravity, 0x14C); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_brake_acc, 0x150); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_brake_dashpanel, 0x154); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_walk_border, 0x158); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_run_border, 0x15C); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_walk_speed_max, 0x160); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_run_acc, 0x164); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_run_speed_max, 0x168); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_speedup_acc, 0x16C); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_speedup_speed_max, 0x170); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_jump_time_min, 0x174); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_jump_brake, 0x178); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_jump_speed_acc, 0x17C); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_jump_speed_brake, 0x180); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_jump_speed, 0x184); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_jump_walk, 0x188); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_jump_run, 0x18C); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_brake_quick_acc, 0x190); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_wait_no_input_time, 0x194); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_damage_time, 0x198); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_damage_jump, 0x19C); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_damage_speed, 0x1A0); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_run_against_time, 0x1A4); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_grind_speed_org, 0x1A8); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_grind_acc, 0x1AC); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_grind_speed_max, 0x1B0); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_grind_time, 0x1B4); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_grind_penalty_time, 0x1B8); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_grind_brake_acc, 0x1BC); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_invincible_time, 0x1C0); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_invincible_time_ring1, 0x1C4); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_invincible_item, 0x1C8); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_speedup_time, 0x1CC); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_wind_init, 0x1D0); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_wind_spd, 0x1D4); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_wind_dist, 0x1D8); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_border_gravity, 0x1DC); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_landing_time, 0x1E0); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_ottoto_time, 0x1E4); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_dead_animation_time, 0x1E8); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_dead_animation_time_coll, 0x1EC); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_wallwait_time, 0x1F0); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_lclick_time, 0x1F4); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_flight_acc, 0x1F8); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_flight_speed_acc, 0x1FC); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_flight_speed_min, 0x200); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_flight_speed_max, 0x204); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_hovering_acc, 0x208); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_climb_speed, 0x20C); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_stun, 0x210); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_brake_acc_sand, 0x214); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_run_acc_sand, 0x218); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_jump_speed_sand, 0x21C); + MARATHON_ASSERT_OFFSETOF(CommonContext, c_psi_throw_speed, 0x220); + MARATHON_ASSERT_OFFSETOF(CommonContext, m_Field224, 0x224); + MARATHON_ASSERT_OFFSETOF(CommonContext, m_Field228, 0x228); + MARATHON_ASSERT_OFFSETOF(CommonContext, m_Field22C, 0x22C); MARATHON_ASSERT_SIZEOF(CommonContext, 0x230); } diff --git a/MarathonRecomp/api/Sonicteam/Player/State/CommonFall.h b/MarathonRecomp/api/Sonicteam/Player/State/CommonFall.h index 5fbd6f01..b9046fc9 100644 --- a/MarathonRecomp/api/Sonicteam/Player/State/CommonFall.h +++ b/MarathonRecomp/api/Sonicteam/Player/State/CommonFall.h @@ -8,8 +8,11 @@ namespace Sonicteam::Player::State class CommonFall : public CommonObject { public: - MARATHON_INSERT_PADDING(8); + be m_FallTime; + bool m_IsRunBorder; }; + MARATHON_ASSERT_OFFSETOF(CommonFall, m_FallTime, 0xC); + MARATHON_ASSERT_OFFSETOF(CommonFall, m_IsRunBorder, 0x10); MARATHON_ASSERT_SIZEOF(CommonFall, 0x14); } diff --git a/MarathonRecomp/api/Sonicteam/Player/State/CommonGrind.h b/MarathonRecomp/api/Sonicteam/Player/State/CommonGrind.h new file mode 100644 index 00000000..b2ea7ec1 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/State/CommonGrind.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +namespace Sonicteam::Player::State +{ + class CommonGrind : public CommonObject + { + public: + be m_GrindTime; + be m_PenaltyTime; + }; + + MARATHON_ASSERT_OFFSETOF(CommonGrind, m_GrindTime, 0xC); + MARATHON_ASSERT_OFFSETOF(CommonGrind, m_PenaltyTime, 0x10); + MARATHON_ASSERT_SIZEOF(CommonGrind, 0x14); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/State/CommonObject.h b/MarathonRecomp/api/Sonicteam/Player/State/CommonObject.h index 7f51cae5..21d7a98d 100644 --- a/MarathonRecomp/api/Sonicteam/Player/State/CommonObject.h +++ b/MarathonRecomp/api/Sonicteam/Player/State/CommonObject.h @@ -5,5 +5,11 @@ namespace Sonicteam::Player::State { - class CommonObject : public Object2 {}; + class CommonContext; + + class CommonObject : public Object2 + { + public: + xpointer m_pContext; + }; } diff --git a/MarathonRecomp/api/Sonicteam/Player/State/CommonSpringTemplate.h b/MarathonRecomp/api/Sonicteam/Player/State/CommonSpringTemplate.h new file mode 100644 index 00000000..c0db407a --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/State/CommonSpringTemplate.h @@ -0,0 +1,28 @@ +namespace Sonicteam::Player::State +{ + // T - Probably Angle, flag - ExternalFlag ( from IExportExternalFlag ) + template + class CommonSpringTemplate : public CommonObject + { + public: + be m_AngleMoveData; // Default Value 1.0, +- + bool m_IsRunBorder; + be m_ContinuousForceTime; // LastLockInputTime * 0.5, + be m_CurrentState; + }; + + typedef CommonSpringTemplate<0, 0> CommonSpringTemplate_Default; + + // Default 06 Types + typedef CommonSpringTemplate<25, 0x40> CommonSpringTemplate_2540; // DashRamp + typedef CommonSpringTemplate<75, 0x10> CommonSpringTemplate_7510; // Spring, DashRamp, Pole + typedef CommonSpringTemplate<75, 0x2000000> CommonSpringTemplate_752000000; + typedef CommonSpringTemplate<75, 0x20000000> CommonSpringTemplate_7520000000; + typedef CommonSpringTemplate<76, 0x80> CommonSpringTemplate_7680; // WideSpring usually + + MARATHON_ASSERT_OFFSETOF(CommonSpringTemplate_Default, m_AngleMoveData, 0xC); + MARATHON_ASSERT_OFFSETOF(CommonSpringTemplate_Default, m_IsRunBorder, 0x10); + MARATHON_ASSERT_OFFSETOF(CommonSpringTemplate_Default, m_ContinuousForceTime, 0x14); + MARATHON_ASSERT_OFFSETOF(CommonSpringTemplate_Default, m_CurrentState, 0x18); + MARATHON_ASSERT_SIZEOF(CommonSpringTemplate_Default, 0x1C); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/State/ICommonContext.h b/MarathonRecomp/api/Sonicteam/Player/State/ICommonContext.h index 3f8521cc..63970452 100644 --- a/MarathonRecomp/api/Sonicteam/Player/State/ICommonContext.h +++ b/MarathonRecomp/api/Sonicteam/Player/State/ICommonContext.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace Sonicteam::Player::State { @@ -14,12 +15,18 @@ namespace Sonicteam::Player::State be m_LockButtons; be m_LastVelocityForward; be m_LastVelocityVertical; - be m_LastLockButtons; + be m_LastLockButtons; be m_Buttons; be m_CurrentStickBorder; MARATHON_INSERT_PADDING(4); + SoX::Math::Quaternion m_PadRotation; be m_AnimationState; - MARATHON_INSERT_PADDING(0x2C); + MARATHON_INSERT_PADDING(0x1C); + + uint32_t GetButtons() + { + return m_LockButtons.get() > 0.0 ? 0u : m_Buttons.get(); + } }; MARATHON_ASSERT_OFFSETOF(ICommonContext, m_AnimationID, 0x40); @@ -29,6 +36,6 @@ namespace Sonicteam::Player::State MARATHON_ASSERT_OFFSETOF(ICommonContext, m_LastLockButtons, 0x50); MARATHON_ASSERT_OFFSETOF(ICommonContext, m_Buttons, 0x54); MARATHON_ASSERT_OFFSETOF(ICommonContext, m_CurrentStickBorder, 0x58); - MARATHON_ASSERT_OFFSETOF(ICommonContext, m_AnimationState, 0x60); + MARATHON_ASSERT_OFFSETOF(ICommonContext, m_AnimationState, 0x70); MARATHON_ASSERT_SIZEOF(ICommonContext, 0x90); } diff --git a/MarathonRecomp/api/Sonicteam/Player/State/ICommonContextIF.h b/MarathonRecomp/api/Sonicteam/Player/State/ICommonContextIF.h index 670f3047..d9082dfc 100644 --- a/MarathonRecomp/api/Sonicteam/Player/State/ICommonContextIF.h +++ b/MarathonRecomp/api/Sonicteam/Player/State/ICommonContextIF.h @@ -7,9 +7,29 @@ namespace Sonicteam::Player::State class ICommonContextIF { public: - xpointer m_pVftable; + struct Vftable + { + be fpSetImpulse; + be fpfunc4; + be fpGetFlag; + be fpGetFlag2; + be fpGetFlag3; + be fpGetTotalVerticalImpulse; + be fpGetTotalForwardImpulse; + }; + + xpointer m_pVftable; + + float GetTotalVerticalImpulse(); + + float GetTotalForwardImpulse(); + + void SetImpulse(float forward, float vertical, float lockInput); + }; MARATHON_ASSERT_OFFSETOF(ICommonContextIF, m_pVftable, 0x00); MARATHON_ASSERT_SIZEOF(ICommonContextIF, 4); } + +#include "ICommonContextIF.inl" diff --git a/MarathonRecomp/api/Sonicteam/Player/State/ICommonContextIF.inl b/MarathonRecomp/api/Sonicteam/Player/State/ICommonContextIF.inl new file mode 100644 index 00000000..9437321e --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/State/ICommonContextIF.inl @@ -0,0 +1,19 @@ +#pragma once + +namespace Sonicteam::Player::State +{ + inline float ICommonContextIF::GetTotalVerticalImpulse() + { + return GuestToHostFunction(m_pVftable->fpGetTotalVerticalImpulse, this); + } + + inline float ICommonContextIF::GetTotalForwardImpulse() + { + return GuestToHostFunction(m_pVftable->fpGetTotalForwardImpulse, this); + } + + inline void ICommonContextIF::SetImpulse(float forward, float vertical, float lockInput) + { + GuestToHostFunction(m_pVftable->fpSetImpulse, this, forward, vertical, lockInput); + } +} diff --git a/MarathonRecomp/api/Sonicteam/Player/State/IMachine.h b/MarathonRecomp/api/Sonicteam/Player/State/IMachine.h index c233a3e6..2676b6f2 100644 --- a/MarathonRecomp/api/Sonicteam/Player/State/IMachine.h +++ b/MarathonRecomp/api/Sonicteam/Player/State/IMachine.h @@ -4,5 +4,32 @@ namespace Sonicteam::Player::State { - class IMachine : public IPlugIn {}; + class IMachine : public IPlugIn + { + public: + struct Vftable : IPlugIn::Vftable + { + be fpUpdate; + be fpGetStateContext; + be fpChangeState; + be fpChangeStateQueue; + be fpEnableQueueState; + be fpEnableQueueStatePop; + be fpChangeStatePop; + be fpGetStateID; + }; + + void ChangeState(uint32_t state) + { + auto vft = (Vftable*)(m_pVftable.get()); + GuestToHostFunction(vft->fpChangeState, this, state); + } + + void ChangeStateQueue(uint32_t state) + { + auto vft = (Vftable*)(m_pVftable.get()); + GuestToHostFunction(vft->fpChangeStateQueue, this, state); + } + + }; } diff --git a/MarathonRecomp/api/Sonicteam/Player/State/Machine2.h b/MarathonRecomp/api/Sonicteam/Player/State/Machine2.h index 90cdbb08..f960d2f5 100644 --- a/MarathonRecomp/api/Sonicteam/Player/State/Machine2.h +++ b/MarathonRecomp/api/Sonicteam/Player/State/Machine2.h @@ -4,19 +4,37 @@ #include #include #include +#include +#include namespace Sonicteam::Player::State { + //std::function + using ConstructFunction = xpointer>()>; + class Machine2 : public SoX::AI::StateMachine, public IMachine { public: - MARATHON_INSERT_PADDING(0x4C); - - inline SoX::AI::StateMachine* GetBase() - { - return (SoX::AI::StateMachine*)((uint8_t*)this - 0x20); - } + stdx::vector m_vInitialStates; + be m_PreState; + be m_PostState; + bool m_IsNewStateQueue; // place current state to deqeue, then use Construct New State + bool m_DoPendingState; // does not remove element m_dPendingStates + bool m_DoPendingStatePop; //does remove element m_dPendingStates also m_dspPendingStates + bool m_Flag4; + stdx::deque m_dPendingStates; + boost::shared_ptr m_spContext; + }; + MARATHON_ASSERT_OFFSETOF(Machine2, m_vInitialStates, 0x40); + MARATHON_ASSERT_OFFSETOF(Machine2, m_PreState, 0x50); + MARATHON_ASSERT_OFFSETOF(Machine2, m_PostState, 0x54); + MARATHON_ASSERT_OFFSETOF(Machine2, m_IsNewStateQueue, 0x58); + MARATHON_ASSERT_OFFSETOF(Machine2, m_DoPendingState, 0x59); + MARATHON_ASSERT_OFFSETOF(Machine2, m_DoPendingStatePop, 0x5A); + MARATHON_ASSERT_OFFSETOF(Machine2, m_Flag4, 0x5B); + MARATHON_ASSERT_OFFSETOF(Machine2, m_dPendingStates, 0x5C); + MARATHON_ASSERT_OFFSETOF(Machine2, m_spContext, 0x70); MARATHON_ASSERT_SIZEOF(Machine2, 0x78); } diff --git a/MarathonRecomp/api/Sonicteam/Player/State/Object2.h b/MarathonRecomp/api/Sonicteam/Player/State/Object2.h index 13d6016a..20222583 100644 --- a/MarathonRecomp/api/Sonicteam/Player/State/Object2.h +++ b/MarathonRecomp/api/Sonicteam/Player/State/Object2.h @@ -1,8 +1,32 @@ #pragma once #include +#include namespace Sonicteam::Player::State { - class Object2 : public SoX::AI::StateMachine {}; + class IMachine; + + class Object2 : public SoX::AI::State + { + public: + struct Vftable : SoX::AI::State::Vftable + { + be fpOnStart2; + be fpOnUpdate2; + be fpOnEnd2; + be fpOnPreUpdate; + be fpOnPostUpdate; + }; + + xpointer m_pStateMachine; + }; + + MARATHON_ASSERT_OFFSETOF(Object2, m_pStateMachine, 0x4); + MARATHON_ASSERT_OFFSETOF(Object2::Vftable, fpOnStart2, 0x14); + MARATHON_ASSERT_OFFSETOF(Object2::Vftable, fpOnUpdate2, 0x18); + MARATHON_ASSERT_OFFSETOF(Object2::Vftable, fpOnEnd2, 0x1C); + MARATHON_ASSERT_OFFSETOF(Object2::Vftable, fpOnPreUpdate, 0x20); + MARATHON_ASSERT_OFFSETOF(Object2::Vftable, fpOnPostUpdate, 0x24); + MARATHON_ASSERT_SIZEOF(Object2, 0x8); } diff --git a/MarathonRecomp/api/Sonicteam/Player/State/SonicContext.h b/MarathonRecomp/api/Sonicteam/Player/State/SonicContext.h index f7825707..6ffddaa9 100644 --- a/MarathonRecomp/api/Sonicteam/Player/State/SonicContext.h +++ b/MarathonRecomp/api/Sonicteam/Player/State/SonicContext.h @@ -66,7 +66,28 @@ namespace Sonicteam::Player::State uint8_t m_Field24B; be m_HomingFlip; be m_CurrentGem; - MARATHON_INSERT_PADDING(0x58); + be c_homing_spd; + be c_homing_brake; + be c_sliding_time; + be c_spindash_spd; + be c_spindash_time; + be c_bound_jump_spd_0; + be c_bound_jump_spd_1; + be c_lightdash_speed; + be c_boundjump_jmp; + be c_boundjump_block; + be c_attack_brake; + be c_sliding_speed_min; + be c_sliding_speed_max; + be c_homing_smash_charge; + be c_custom_action_slow_time; + be c_custom_action_machspeed_acc; + be c_custom_action_machspeed_time; + be c_scale_run_speed_max; + be c_scale_run_acc; + be c_scale_walk_speed_max; + be c_scale_jump_speed; + be c_scale_jump_block; }; MARATHON_ASSERT_OFFSETOF(SonicContext, m_CurrentGemSprite, 0x230); @@ -89,5 +110,27 @@ namespace Sonicteam::Player::State MARATHON_ASSERT_OFFSETOF(SonicContext, m_Field24B, 0x24B); MARATHON_ASSERT_OFFSETOF(SonicContext, m_HomingFlip, 0x24C); MARATHON_ASSERT_OFFSETOF(SonicContext, m_CurrentGem, 0x250); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_homing_spd, 0x254); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_homing_brake, 0x258); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_sliding_time, 0x25C); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_spindash_spd, 0x260); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_spindash_time, 0x264); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_bound_jump_spd_0, 0x268); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_bound_jump_spd_1, 0x26C); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_lightdash_speed, 0x270); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_boundjump_jmp, 0x274); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_boundjump_block, 0x278); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_attack_brake, 0x27C); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_sliding_speed_min, 0x280); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_sliding_speed_max, 0x284); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_homing_smash_charge, 0x288); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_custom_action_slow_time, 0x28C); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_custom_action_machspeed_acc, 0x290); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_custom_action_machspeed_time, 0x294); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_scale_run_speed_max, 0x298); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_scale_run_acc, 0x29C); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_scale_walk_speed_max, 0x2A0); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_scale_jump_speed, 0x2A4); + MARATHON_ASSERT_OFFSETOF(SonicContext, c_scale_jump_block, 0x2A8); MARATHON_ASSERT_SIZEOF(SonicContext, 0x2B0); } diff --git a/MarathonRecomp/api/Sonicteam/Player/State/SonicState.h b/MarathonRecomp/api/Sonicteam/Player/State/SonicState.h new file mode 100644 index 00000000..7da8e633 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/State/SonicState.h @@ -0,0 +1,67 @@ +#pragma once + +#include + +namespace Sonicteam::Player::State +{ + enum SonicState + { + SonicState_Wait = 0, + SonicState_Walk = 1, + SonicState_Run = 2, + SonicState_Fall = 3, + SonicState_Jump = 4, + SonicState_CommonJump = 5, + SonicState_Brake = 6, + SonicState_QuickTurn = 7, + SonicState_Dead = 8, + SonicState_Damage = 9, + SonicState_Push = 0xA, + SonicState_Damage2 = 0xB, + SonicState_Grind = 0xC, + SonicState_Edge = 0xD, + SonicState_EdgeTemplateCommonFall = 0xE, + SonicState_EdgeTemplateCommonJump = 0xF, + SonicState_Ottotto = 0x10, + SonicState_SpringTemplateTypeA = 0x11, + SonicState_WideSpring = 0x12, + SonicState_SpringTemplateTypeB = 0x13, + SonicState_DashPanel = 0x14, + SonicState_SpringTemplateTypeC = 0x15, + SonicState_Goal = 0x16, + SonicState_Invincible = 0x17, + SonicState_Wind = 0x18, + SonicState_Landing = 0x19, + SonicState_DontMove = 0x1A, + SonicState_HoldObjectTemplate_571000 = 0x1B, + SonicState_HoldObjectTemplate_622000 = 0x1E, + SonicState_ChainJump = 0x1F, + SonicState_RainbowRing = 0x20, + SonicState_WallLanding = 0x21, + SonicState_OnPathColli = 0x22, + SonicState_BlastJump = 0x24, + SonicState_Talk = 0x25, + SonicState_PsiCatched = 0x26, + SonicState_CommonSpringTemplate752000000 = 0x27, + SonicState_Stun = 0x28, + SonicState_Rodeo = 0x29, + SonicState_Balancer = 0x2A, + SonicState_WaterSlider = 0x2B, + SonicState_Amigo = 0x30, + SonicState_AmigoChase = 0x31, + SonicState_GemThrow = 0x2E, + SonicState_GemSnipe = 0x2F, + SonicState_HomingSmash = 0x41, + SonicState_Homing = 0x42, + SonicState_HomingAfter = 0x43, + SonicState_Sliding = 0x44, + SonicState_Attack = 0x45, + SonicState_SpinDash = 0x46, + SonicState_Bound = 0x47, + SonicState_LightDash = 0x48, + SonicState_MachSpeed = 0x49, + SonicState_TornadoGround = 0x4A, + SonicState_TornadoAir = 0x4B, + SonicState_SonicSuper = 0x4D + }; +} diff --git a/MarathonRecomp/api/Sonicteam/Player/WallListener.h b/MarathonRecomp/api/Sonicteam/Player/WallListener.h new file mode 100644 index 00000000..3f1c730d --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/WallListener.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include +#include +#include + +namespace Sonicteam::Player +{ + class WallListener : public ICollisionListenerTemplate {}; + MARATHON_ASSERT_SIZEOF(WallListener, 0x80); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/WallRayListener.h b/MarathonRecomp/api/Sonicteam/Player/WallRayListener.h new file mode 100644 index 00000000..8eb87e76 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/Player/WallRayListener.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include +#include +#include + +namespace Sonicteam::Player +{ + class WallRayListener : public ICollisionListenerTemplate {}; + + MARATHON_ASSERT_SIZEOF(WallRayListener, 0x80); +} diff --git a/MarathonRecomp/api/Sonicteam/Player/Zock.h b/MarathonRecomp/api/Sonicteam/Player/Zock.h index 0701b663..ceeb1859 100644 --- a/MarathonRecomp/api/Sonicteam/Player/Zock.h +++ b/MarathonRecomp/api/Sonicteam/Player/Zock.h @@ -33,5 +33,4 @@ namespace Sonicteam::Player MARATHON_ASSERT_OFFSETOF(Zock, m_spPhantomA, 0x38); MARATHON_ASSERT_OFFSETOF(Zock, m_spPhantomB, 0x5C); MARATHON_ASSERT_OFFSETOF(Zock, m_spPhantomListener, 0xA0); - MARATHON_ASSERT_SIZEOF(Zock, 0xE0); } diff --git a/MarathonRecomp/api/Sonicteam/RaderMapManager.h b/MarathonRecomp/api/Sonicteam/RaderMapManager.h index 5999dfe6..a212e1be 100644 --- a/MarathonRecomp/api/Sonicteam/RaderMapManager.h +++ b/MarathonRecomp/api/Sonicteam/RaderMapManager.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace Sonicteam { diff --git a/MarathonRecomp/api/Sonicteam/SoX/AI/State.h b/MarathonRecomp/api/Sonicteam/SoX/AI/State.h new file mode 100644 index 00000000..f21732cc --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/SoX/AI/State.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +namespace Sonicteam::SoX::AI +{ + template + class State + { + public: + struct Vftable + { + be fpGetName; + be fpOnStart; + be fpOnUpdate; + be fpOnEnd; + be fpProcessMessage; + }; + + xpointer m_pVftable; + + const char* GetName() + { + return GuestToHostFunction(m_pVftable->fpGetName, this); + } + + void OnStart() + { + return GuestToHostFunction(m_pVftable->fpOnStart, this); + } + + void OnUpdate(double delta) + { + return GuestToHostFunction(m_pVftable->fpOnUpdate, this, delta); + } + + void OnEnd() + { + return GuestToHostFunction(m_pVftable->fpOnEnd, this); + } + + bool ProcessMessage(void* ptr,SoX::IMessage* message) + { + return GuestToHostFunction(m_pVftable->fpProcessMessage, this, ptr,message); + } + + }; +} diff --git a/MarathonRecomp/api/Sonicteam/SoX/AI/StateMachine.h b/MarathonRecomp/api/Sonicteam/SoX/AI/StateMachine.h index 8c54a44f..e279b2c8 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/AI/StateMachine.h +++ b/MarathonRecomp/api/Sonicteam/SoX/AI/StateMachine.h @@ -1,6 +1,9 @@ #pragma once #include +#include +#include +#include namespace Sonicteam::SoX::AI { @@ -9,28 +12,18 @@ namespace Sonicteam::SoX::AI { public: xpointer m_pVftable; - xpointer> m_pState; - xpointer m_pContext; + boost::shared_ptr> m_spState; + stdx::deque>> m_dspPendingStates; template TState* GetState() { - return (TState*)m_pState.get(); - } - - TStateContext* GetContext() - { - return (TStateContext*)m_pContext.get(); - } - - template - TContext* GetContext() - { - return (TContext*)m_pContext.get(); + return (TState*)m_spState.get(); } }; - MARATHON_ASSERT_OFFSETOF(StateMachine, m_pVftable, 0x00); - MARATHON_ASSERT_OFFSETOF(StateMachine, m_pState, 0x04); - MARATHON_ASSERT_OFFSETOF(StateMachine, m_pContext, 0x08); + MARATHON_ASSERT_OFFSETOF(StateMachine, m_pVftable, 0x0); + MARATHON_ASSERT_OFFSETOF(StateMachine, m_spState, 0x4); + MARATHON_ASSERT_OFFSETOF(StateMachine, m_dspPendingStates, 0xC); + MARATHON_ASSERT_SIZEOF(StateMachine, 0x20); } diff --git a/MarathonRecomp/api/Sonicteam/SoX/Array.h b/MarathonRecomp/api/Sonicteam/SoX/Array.h new file mode 100644 index 00000000..3b82b7a1 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/SoX/Array.h @@ -0,0 +1,259 @@ +#pragma once + +#include +#include + +namespace Sonicteam::SoX +{ + // add support for custom destructor function + template + class ArrayOld + { + private: + struct Header + { + be m_count; + T m_elements[0]; + }; + + xpointer m_elements; + + public: + // Iterator types + using iterator = T*; + using const_iterator = const T*; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + + ArrayOld() + { + + } + + ArrayOld(uint32_t count) + { + size_t size = sizeof(Header) + sizeof(T) * count; + Header* header = (Header*)g_userHeap.Alloc(size); + header->m_count = count; + + m_elements = reinterpret_cast(header + 1); + + for (uint32_t i = 0; i < count; ++i) + { + new (&m_elements[i]) T(); + } + } + + // Element access + T* data() + { + return m_elements; + } + + const T* data() const + { + return m_elements; + } + + T& operator[](size_t index) + { + return m_elements[index]; + } + + const T& operator[](size_t index) const + { + return m_elements[index]; + } + + uint32_t size() const + { + + Header* header = reinterpret_cast(reinterpret_cast(m_elements.get()) - sizeof(Header)); + return header->m_count; + } + + bool empty() const + { + return size() == 0; + } + + // Iterators + iterator begin() + { + return m_elements; + } + + iterator end() + { + return m_elements + size(); + } + + const_iterator begin() const + { + return m_elements; + } + + const_iterator end() const + { + return m_elements + size(); + } + + const_iterator cbegin() const + { + return m_elements; + } + + const_iterator cend() const + { + return m_elements + size(); + } + + // Reverse iterators + reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + + reverse_iterator rend() + { + return reverse_iterator(begin()); + } + + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(end()); + } + + const_reverse_iterator rend() const + { + return const_reverse_iterator(begin()); + } + + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(end()); + } + + const_reverse_iterator crend() const + { + return const_reverse_iterator(begin()); + } + + ~ArrayOld() + { + if (!m_elements) return; + + Header* header = reinterpret_cast(reinterpret_cast(m_elements.get()) - sizeof(Header)); + uint32_t count = header->m_count; + + // Destroy elements backwards + for (int32_t i = count - 1; i >= 0; --i) + { + m_elements[i].~T(); + } + + g_userHeap.Free(header); + } + }; + + + template + class Array + { + private: + T m_container[count]; + + public: + Array() + { + } + ~Array() = default; + + T& operator[](uint32_t index) + { + return m_container[index]; + } + + const T& operator[](uint32_t index) const + { + return m_container[index]; + } + + uint32_t size() const + { + return count; + } + }; + + template + struct ArrayPtr { + xpointer pitems; + uint32_t count; + + ArrayPtr() : pitems(NULL), count(0) + { + } + + explicit ArrayPtr(uint32_t size) : + pitems(g_userHeap.Alloc(size * sizeof(T))), + count(size) + { + } + + + ArrayPtr(T* ptr, uint32_t size) + : pitems(ptr), count(size) + { + } + + T& operator[](size_t index) + { + return pitems[index]; + } + + ArrayPtr(const ArrayPtr&); + ArrayPtr& operator=(const ArrayPtr&); + }; + + template + struct AIMArray + { + xpointer pitems; + uint32_t LastItemID; + uint32_t EndItemID; + + explicit AIMArray(uint32_t size) + : pitems(g_userHeap.Alloc(size * sizeof(T))), + LastItemID(-1), + EndItemID(size - 1) + { + } + + AIMArray(T* existingItems, uint32_t size) + : pitems(existingItems), LastItemID(size - 1), EndItemID(size - 1) + { + } + + ~AIMArray() + { + g_userHeap.Free(pitems); + pitems = 0; + } + + private: + AIMArray(const AIMArray&); + AIMArray& operator=(const AIMArray&); + + public: + + T& at(size_t index) { + return pitems[index]; + } + + const T& at(size_t index) const { + return pitems[index]; + } + }; + +} diff --git a/MarathonRecomp/api/Sonicteam/SoX/Engine/Task.h b/MarathonRecomp/api/Sonicteam/SoX/Engine/Task.h index f5edcef8..3bd09610 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/Engine/Task.h +++ b/MarathonRecomp/api/Sonicteam/SoX/Engine/Task.h @@ -12,7 +12,8 @@ namespace Sonicteam::SoX::Engine class Task : public Component, public MessageReceiver { public: - be m_Flags; + char m_Flag1; + MARATHON_INSERT_PADDING(3); be m_Timestamp; xpointer m_pPrevSibling; xpointer m_pNextSibling; @@ -21,7 +22,48 @@ namespace Sonicteam::SoX::Engine xpointer m_pDoc; LinkNode m_lnTask; - Task* GetFirstDependency() const + class iterator + { + Task* m_pCurrent; + + public: + iterator(Task* pCurrent = nullptr) : m_pCurrent(pCurrent) {} + + Task& operator*() const + { + return *m_pCurrent; + } + + Task* operator->() const + { + return m_pCurrent; + } + + iterator& operator++() + { + if (m_pCurrent) + m_pCurrent = m_pCurrent->m_pPrevSibling.get(); + + return *this; + } + + bool operator!=(const iterator& other) const + { + return m_pCurrent != other.m_pCurrent; + } + }; + + iterator begin() + { + return iterator(this); + } + + iterator end() + { + return iterator(nullptr); + } + + Task* GetFirstDependency() const { if (!m_pDependencies) return nullptr; @@ -39,14 +81,14 @@ namespace Sonicteam::SoX::Engine return m_pDependencies.get(); } - template + template T* GetDoc() { return (T*)m_pDoc.get(); } }; - MARATHON_ASSERT_OFFSETOF(Task, m_Flags, 0x24); + MARATHON_ASSERT_OFFSETOF(Task, m_Flag1, 0x24); MARATHON_ASSERT_OFFSETOF(Task, m_Timestamp, 0x28); MARATHON_ASSERT_OFFSETOF(Task, m_pPrevSibling, 0x2C); MARATHON_ASSERT_OFFSETOF(Task, m_pNextSibling, 0x30); @@ -55,4 +97,4 @@ namespace Sonicteam::SoX::Engine MARATHON_ASSERT_OFFSETOF(Task, m_pDoc, 0x3C); MARATHON_ASSERT_OFFSETOF(Task, m_lnTask, 0x40); MARATHON_ASSERT_SIZEOF(Task, 0x4C); -} +} \ No newline at end of file diff --git a/MarathonRecomp/api/Sonicteam/SoX/Graphics/AnimationUserDataListener.h b/MarathonRecomp/api/Sonicteam/SoX/Graphics/AnimationUserDataListener.h new file mode 100644 index 00000000..e039e122 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/SoX/Graphics/AnimationUserDataListener.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace Sonicteam::SoX::Graphics +{ + class AnimationUserDataListener + { + }; +} diff --git a/MarathonRecomp/api/Sonicteam/SoX/Graphics/Frame.h b/MarathonRecomp/api/Sonicteam/SoX/Graphics/Frame.h index d8af078a..b914c332 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/Graphics/Frame.h +++ b/MarathonRecomp/api/Sonicteam/SoX/Graphics/Frame.h @@ -2,15 +2,135 @@ #include #include +#include +#include +#include +#include +#include namespace Sonicteam::SoX::Graphics { + class Frame; + + class FrameSynchronizer + { + public: + xpointer m_pVftable; + SoX::LinkedList m_llFrames; + SoX::ArrayOld> m_aollFrame; + xpointer> m_aPriorityCounts; + be m_Count; + + FrameSynchronizer(uint32_t count) + { + m_pVftable = nullptr; + m_llFrames.m_pPrev = &m_llFrames; + m_llFrames.m_pNext = &m_llFrames; + + m_aollFrame = SoX::ArrayOld>(count); + m_aPriorityCounts = (be*)g_userHeap.Alloc(sizeof(be) * count); + + for (uint32_t i = 0; i < count; ++i) { + + m_aPriorityCounts[i] = 0; + } + + m_Count = count; + } + + void RemoveFromPriorityQueue(Frame* pFrame); + }; + + MARATHON_ASSERT_OFFSETOF(FrameSynchronizer, m_llFrames, 4); + MARATHON_ASSERT_OFFSETOF(FrameSynchronizer, m_aollFrame, 0x10); + MARATHON_ASSERT_OFFSETOF(FrameSynchronizer, m_aPriorityCounts, 0x14); + MARATHON_ASSERT_OFFSETOF(FrameSynchronizer, m_Count, 0x18); + class Frame : public RefCountObject { public: - MARATHON_INSERT_PADDING(0x18); // SimpleNode - MARATHON_INSERT_PADDING(0x2C); + enum FrameFlags + { + FLAG_ACTIVE = 0x1, + FLAG_VISIBLE = 0x2, + FLAG_SYNC_ENABLED = 0x10, + FLAG_DIRTY = 0x20, + FLAG_IN_SYNC_LIST = 0x40 + }; + + be m_Flag; + xpointer m_pOwner; + xpointer m_pParent; + xpointer m_pNextSibling; + xpointer m_pPrevSibling; + xpointer m_pFirstChild; + LinkNode m_llFrameObserver; // For Particles + xpointer> m_plnFrame; + xpointer m_pSynchronizer; + LinkNode m_lnFrame1; + LinkNode m_lnFrame2; + + struct Vftable : public RefCountObject::Vftable + { + be fpFunc4; + be fpGetName; + be fpGetTransform1; + be fpGetTransform2; + be fpSetTransform; + be fpGetCollisionFlag; + be GetContactEntity; + be fpFunc20; + }; + + // Core hierarchy methods + void AddChild(Frame* pChild); + void RemoveChild(Frame* pChild); + void RemoveFromParent(); + void DestroyFrame(); + bool Func8(); + + // Transform methods + void SetTransform(SoX::Math::Matrix4x4* matrix); + void SetTransform(SoX::Math::Matrix4x4& matrix); + void UpdateTransform(SoX::Math::Matrix4x4& matrix); + + // Utility methods + bool IsAttached() const { return m_pParent != nullptr; } + bool HasChildren() const { return m_pFirstChild != nullptr; } + xpointer GetRoot(); + void SetSynchronizer(FrameSynchronizer* pSync); + + void UpdateOwnerRecursive(Frame* pNewOwner); + void DestroyChildren(); + + void DetachFromParent(); + void DestroyFrameHierarchy(); + + // Search and traversal methods + const char* GetName(); + void ForEach(std::function); + Frame* FindNode(const char* name); + + Frame* FindChild(const char* name); + Frame* FindNode(Frame* pFrame); + bool ContainsFrame(Frame* pFrame); + bool HasDirectChild(Frame* pFrame); + void RemoveChildByName(const char* name); + void RemoveNodeByName(const char* name); }; MARATHON_ASSERT_SIZEOF(Frame, 0x4C); + MARATHON_ASSERT_OFFSETOF(Frame, m_Flag, 8); + MARATHON_ASSERT_OFFSETOF(Frame, m_pOwner, 0xC); + MARATHON_ASSERT_OFFSETOF(Frame, m_pParent, 0x10); + MARATHON_ASSERT_OFFSETOF(Frame, m_pNextSibling, 0x14); + MARATHON_ASSERT_OFFSETOF(Frame, m_pPrevSibling, 0x18); + MARATHON_ASSERT_OFFSETOF(Frame, m_pFirstChild, 0x1C); + MARATHON_ASSERT_OFFSETOF(Frame, m_llFrameObserver, 0x20); + MARATHON_ASSERT_OFFSETOF(Frame, m_plnFrame, 0x2C); + MARATHON_ASSERT_OFFSETOF(Frame, m_pSynchronizer, 0x30); + MARATHON_ASSERT_OFFSETOF(Frame, m_lnFrame1, 0x34); + MARATHON_ASSERT_OFFSETOF(Frame, m_lnFrame2, 0x40); } + +#include "Frame.inl" diff --git a/MarathonRecomp/api/Sonicteam/SoX/Graphics/Frame.inl b/MarathonRecomp/api/Sonicteam/SoX/Graphics/Frame.inl new file mode 100644 index 00000000..1eb3855c --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/SoX/Graphics/Frame.inl @@ -0,0 +1,408 @@ +#pragma once + +#include +#include +#include "Frame.h" + +namespace Sonicteam::SoX::Graphics +{ + inline void FrameSynchronizer::RemoveFromPriorityQueue(Frame* pFrame) + { + // Exact sub_825942F0 implementation + if (pFrame->m_lnFrame1.m_pNext) + { + pFrame->m_lnFrame1.m_pPrev->m_pNext = pFrame->m_lnFrame1.m_pNext; + pFrame->m_lnFrame1.m_pNext->m_pPrev = pFrame->m_lnFrame1.m_pPrev; + pFrame->m_lnFrame1.m_pNext = nullptr; + pFrame->m_lnFrame1.m_pPrev = nullptr; + } + + if (pFrame->m_lnFrame2.m_pNext) + { + pFrame->m_lnFrame2.m_pPrev->m_pNext = pFrame->m_lnFrame2.m_pNext; + pFrame->m_lnFrame2.m_pNext->m_pPrev = pFrame->m_lnFrame2.m_pPrev; + pFrame->m_lnFrame2.m_pNext = nullptr; + pFrame->m_lnFrame2.m_pPrev = nullptr; + } + + uint32_t queueSize = m_Count; + uint32_t foundIndex = queueSize; + + if (queueSize != 0) + { + auto currentList = m_aollFrame.begin(); + for (uint32_t i = 0; i < queueSize; ++i, ++currentList) + { + if (currentList == pFrame->m_plnFrame) + { + foundIndex = i; + break; + } + } + } + + if (foundIndex < queueSize) + { + m_aPriorityCounts[foundIndex] = m_aPriorityCounts[foundIndex] - 1; + } + + pFrame->m_pSynchronizer = nullptr; + pFrame->m_plnFrame = nullptr; + } + + // Recreation (sub_825949F0) + inline void Frame::AddChild(Frame* pChild) + { + if (!pChild) return; + + Frame* child = pChild; + + // Link into child list + if (m_pFirstChild) + { + Frame* lastChild = m_pFirstChild->m_pPrevSibling; + lastChild->m_pNextSibling = child; + child->m_pPrevSibling = lastChild; + } + else + { + m_pFirstChild = child; + } + + m_pFirstChild->m_pPrevSibling = child; + + // Update ownership recursively + child->UpdateOwnerRecursive(m_pOwner); + + // Handle synchronizer + child->m_pParent = this; + if (child->m_pSynchronizer) + { + child->m_Flag = child->m_Flag.get() | 0x10u; + child->m_pSynchronizer->RemoveFromPriorityQueue(child); + } + + // Link into owner's frame list if needed + if (child->m_pOwner && !child->m_pOwner->m_lnFrame2.m_pNext) + { + auto frameNode = child->m_pOwner->m_plnFrame; + if (frameNode) { + auto& frame2 = child->m_pOwner->m_lnFrame2; + frame2.m_pPrev = frameNode; + frame2.m_pNext = frameNode->m_pNext; + frameNode->m_pNext->m_pPrev = &frame2; + frameNode->m_pNext = &frame2; + } + } + + child->m_pOwner->m_Flag = child->m_pOwner->m_Flag.get() | 1u; + child->m_Flag = child->m_Flag.get() | 2u; + child->m_ReferenceCount = child->m_ReferenceCount.get() + 1; + } + + inline void Frame::RemoveChild(Frame* pChild) + { + if (!pChild || pChild->m_pParent != this) return; + pChild->RemoveFromParent(); + } + + // sub_82594590 (Recreation) + inline void Frame::RemoveFromParent() + { + if (!m_pParent) return; + + Frame* parent = m_pParent; + + FrameSynchronizer* pSynchronizer = 0; + if (((m_Flag.get() >> 4) & 1) != 0) + { + auto pOwner = this->m_pOwner; + m_Flag = m_Flag.get() &~0x10; + pSynchronizer = pOwner->m_pSynchronizer; + } + + auto pNextSibling = this->m_pNextSibling; + if (!pNextSibling) + pNextSibling = m_pParent->m_pFirstChild; + pNextSibling->m_pPrevSibling = this->m_pPrevSibling; + auto v7 = this->m_pParent; + auto v8 = this->m_pNextSibling; + if (v7->m_pFirstChild == this) + v7->m_pFirstChild = v8; + else + this->m_pPrevSibling->m_pNextSibling = v8; + this->m_pParent = 0; + this->m_pNextSibling = 0; + this->m_pPrevSibling = this; + + UpdateOwnerRecursive(this); + + if (pSynchronizer) + { + auto refPtr = guest_heap_var>(this); + GuestToHostFunction(::sub_82594240, m_pOwner->m_pSynchronizer.get(), refPtr.get()); + } + + Release(); + } + + inline void Frame::DestroyChildren() + { + Frame* child = m_pFirstChild; + while (child) + { + Frame* next = child->m_pNextSibling; + child->RemoveFromParent(); + child = next; + } + m_pFirstChild = nullptr; + } + + inline void Frame::DestroyFrame() + { + DestroyChildren(); + RemoveFromParent(); + + // Clear remaining references + m_pOwner = nullptr; + m_pSynchronizer = nullptr; + m_plnFrame = nullptr; + } + + inline void Frame::UpdateOwnerRecursive(Frame* pNewOwner) + { + m_pOwner = pNewOwner; + Frame* child = m_pFirstChild; + while (child) + { + child->UpdateOwnerRecursive(pNewOwner); + child = child->m_pNextSibling; + } + } + + inline const char* Frame::GetName() + { + return MARATHON_CALL_VIRTUAL_FUNCTION(Frame, const char*, &Vftable::fpGetName, this); + } + + inline xpointer Frame::GetRoot() + { + Frame* root = this; + while (root->m_pParent) + { + root = root->m_pParent; + } + return root; + } + + inline void Frame::SetSynchronizer(FrameSynchronizer* pSync) + { + if (m_pSynchronizer != pSync) + { + m_pSynchronizer = pSync; + } + } + + inline void Frame::SetTransform(SoX::Math::Matrix4x4* matrix) + { + auto vft = (Vftable*)m_pVftable.get(); + GuestToHostFunction(vft->fpSetTransform, this, matrix); + } + + inline void Frame::SetTransform(SoX::Math::Matrix4x4& matrix) + { + SetTransform(guest_heap_var(matrix).get()); + } + + inline void Frame::UpdateTransform(SoX::Math::Matrix4x4& matrix) + { + SetTransform(matrix); + auto owner = m_pOwner; + if (owner && !owner->m_lnFrame2.m_pNext && owner->m_plnFrame) + { + owner->m_plnFrame->InsertFast(&owner->m_lnFrame2); + } + if (owner) + { + owner->m_Flag = owner->m_Flag.get() | 1; + } + m_Flag = m_Flag.get() | 2; + } + + inline void Frame::DetachFromParent() + { + if (!m_pParent) return; + + Frame* parent = m_pParent; + bool wasSynced = (m_Flag.get() & FrameFlags::FLAG_SYNC_ENABLED) != 0; + + if (wasSynced) + { + m_Flag = m_Flag.get() & ~FrameFlags::FLAG_SYNC_ENABLED; + } + + // Remove from circular sibling list + if (m_pPrevSibling == this) + { + // Only child case + parent->m_pFirstChild = nullptr; + } + else { + // Update sibling pointers + m_pPrevSibling->m_pNextSibling = m_pNextSibling; + m_pNextSibling->m_pPrevSibling = m_pPrevSibling; + + // Update parent's first child if we were first + if (parent->m_pFirstChild == this) { + parent->m_pFirstChild = m_pNextSibling; + } + } + + // Reset our sibling pointers to self + m_pParent = nullptr; + m_pNextSibling = nullptr; + m_pPrevSibling = this; + + UpdateOwnerRecursive(this); + + if (wasSynced) + { + auto refPtr = guest_heap_var>(this); + GuestToHostFunction(::sub_82594240, m_pOwner->m_pSynchronizer.get(), refPtr.get()); + } + + Release(); + } + + inline void Frame::DestroyFrameHierarchy() + { + // Destroy all children recursively + DestroyChildren(); + + // Detach from parent + DetachFromParent(); + + // Clear synchronization links + if (m_pSynchronizer) + { + m_pSynchronizer->RemoveFromPriorityQueue(this); + } + + // Reset all links + m_lnFrame1.Reset(); + m_lnFrame2.Reset(); + m_llFrameObserver.Reset(); + + m_pOwner = nullptr; + m_pSynchronizer = nullptr; + m_plnFrame = nullptr; + } + + inline void Frame::ForEach(std::function f) + { + f(this); + + for (Frame* child = m_pFirstChild.get(); child; child = child->m_pNextSibling.get()) + { + child->ForEach(f); + } + } + + inline Frame* Frame::FindNode(const char* name) + { + // Check current node first + if (auto currentName = GetName()) + { + if (strcmp(currentName, name) == 0) + return this; + } + + // Depth-first search through children + for (Frame* child = m_pFirstChild.get(); child; child = child->m_pNextSibling.get()) + { + if (Frame* found = child->FindNode(name)) + return found; + } + + return nullptr; + } + + inline Frame* Frame::FindChild(const char* name) + { + // Search only direct children (non-recursive) + for (Frame* child = m_pFirstChild.get(); child; child = child->m_pNextSibling.get()) + { + if (auto childName = child->GetName()) + { + if (strcmp(childName, name) == 0) + return child; + } + } + return nullptr; + } + + inline Frame* Frame::FindNode(Frame* pFrame) + { + if (!pFrame) return nullptr; + + // Check current node + if (this == pFrame) + return this; + + // Recursively search children + for (Frame* child = m_pFirstChild.get(); child; child = child->m_pNextSibling.get()) + { + if (Frame* found = child->FindNode(pFrame)) + return found; + } + + return nullptr; + } + + inline bool Frame::ContainsFrame(Frame* pFrame) + { + if (!pFrame) return false; + + if (this == pFrame) + return true; + + for (Frame* child = m_pFirstChild.get(); child; child = child->m_pNextSibling.get()) + { + if (child->ContainsFrame(pFrame)) + return true; + } + + return false; + } + + inline bool Frame::HasDirectChild(Frame* pFrame) + { + if (!pFrame) return false; + + for (Frame* child = m_pFirstChild.get(); child; child = child->m_pNextSibling.get()) + { + if (child == pFrame) + return true; + } + + return false; + } + + inline void Frame::RemoveChildByName(const char* name) + { + Frame* child = FindChild(name); + if (child) + { + RemoveChild(child); + } + } + + inline void Frame::RemoveNodeByName(const char* name) + { + Frame* node = FindNode(name); + if (node && node != this) + { + node->RemoveFromParent(); + } + } +} diff --git a/MarathonRecomp/api/Sonicteam/SoX/Graphics/FrameObserver.h b/MarathonRecomp/api/Sonicteam/SoX/Graphics/FrameObserver.h index dcd89d3e..a08ad4b7 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/Graphics/FrameObserver.h +++ b/MarathonRecomp/api/Sonicteam/SoX/Graphics/FrameObserver.h @@ -1,21 +1,22 @@ #pragma once #include -#include +#include namespace Sonicteam::SoX::Graphics { + class Frame; + class FrameObserver { public: xpointer m_pVftable; - MARATHON_INSERT_PADDING(8); - xpointer m_pParent; - xpointer m_pFrameGP; + LinkNode m_lnFrameObserver; + xpointer m_pFrameGPStandard; }; MARATHON_ASSERT_OFFSETOF(FrameObserver, m_pVftable, 0x00); - MARATHON_ASSERT_OFFSETOF(FrameObserver, m_pParent, 0x0C); - MARATHON_ASSERT_OFFSETOF(FrameObserver, m_pFrameGP, 0x10); + MARATHON_ASSERT_OFFSETOF(FrameObserver, m_lnFrameObserver, 0x4); + MARATHON_ASSERT_OFFSETOF(FrameObserver, m_pFrameGPStandard, 0x10); MARATHON_ASSERT_SIZEOF(FrameObserver, 0x14); } diff --git a/MarathonRecomp/api/Sonicteam/SoX/Graphics/Technique.h b/MarathonRecomp/api/Sonicteam/SoX/Graphics/Technique.h index 0e43c22c..f7fbd527 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/Graphics/Technique.h +++ b/MarathonRecomp/api/Sonicteam/SoX/Graphics/Technique.h @@ -12,4 +12,4 @@ namespace Sonicteam::SoX::Graphics MARATHON_ASSERT_OFFSETOF(Technique, m_pShader, 0x08); MARATHON_ASSERT_SIZEOF(Technique, 0x0C); -} +} \ No newline at end of file diff --git a/MarathonRecomp/api/Sonicteam/SoX/IResource.h b/MarathonRecomp/api/Sonicteam/SoX/IResource.h index b4072464..6561be6e 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/IResource.h +++ b/MarathonRecomp/api/Sonicteam/SoX/IResource.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include namespace Sonicteam::SoX @@ -8,11 +9,40 @@ namespace Sonicteam::SoX class IResource : public RefCountObject { public: - MARATHON_INSERT_PADDING(4); - stdx::string m_FilePath; - MARATHON_INSERT_PADDING(0x3C); + struct Vftable : RefCountObject::Vftable + { + be fpInit; + be fpGetPath; + be fpIsInARC; + }; + + be m_MgrRegistryIndex; // Used to free resource. + stdx::string m_MgrResourceName; + stdx::string m_ResourceNameInitial; + stdx::string m_ResourceName; + bool m_IsInResourceManager; + MARATHON_INSERT_PADDING(3); + + void Init(void* file, uint64_t size) + { + GuestToHostFunction(((Vftable*)m_pVftable.get())->fpInit, this, file, size); + } + + stdx::string GetPath(stdx::string* fileName) + { + guest_stack_var out{}; + + GuestToHostFunction(((Vftable*)m_pVftable.get())->fpGetPath, out.get(), this, fileName); + + return *out; + } + + bool IsInARC() + { + return GuestToHostFunction(((Vftable*)m_pVftable.get())->fpIsInARC, this); + } }; - MARATHON_ASSERT_OFFSETOF(IResource, m_FilePath, 0x0C); + MARATHON_ASSERT_OFFSETOF(IResource, m_MgrResourceName, 0x0C); MARATHON_ASSERT_SIZEOF(IResource, 0x64); } diff --git a/MarathonRecomp/api/Sonicteam/SoX/IResourceMgr.h b/MarathonRecomp/api/Sonicteam/SoX/IResourceMgr.h index 977ced4f..ae36d546 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/IResourceMgr.h +++ b/MarathonRecomp/api/Sonicteam/SoX/IResourceMgr.h @@ -1,21 +1,49 @@ #pragma once #include +#include namespace Sonicteam::SoX { + // Different for each implementation. + struct IResourceMgrCreationParams; + class IResourceMgr { public: struct Vftable { be fpDestroy; - be fpMakeResource; - MARATHON_INSERT_PADDING(4); + be fpCreateResource; + be fpGetPath; + MARATHON_INSERT_PADDING(8); }; xpointer m_pVftable; - MARATHON_INSERT_PADDING(0x0C); + be m_MgrIndex; + bool m_IsInResourceManager; + bool m_Field9; + MARATHON_INSERT_PADDING(2); + be m_FieldC; + + void* Destroy(uint32_t flag) + { + return GuestToHostFunction(m_pVftable->fpDestroy, this, flag); + } + + Sonicteam::SoX::IResource* CreateResource(IResourceMgrCreationParams& param) + { + return GuestToHostFunction(m_pVftable->fpCreateResource, this, ¶m); + } + + stdx::string GetPath(stdx::string* fileName) + { + guest_stack_var out{}; + + GuestToHostFunction(m_pVftable->fpGetPath, out.get(), this, fileName); + + return *out; + } }; MARATHON_ASSERT_OFFSETOF(IResourceMgr, m_pVftable, 0x00); diff --git a/MarathonRecomp/api/Sonicteam/SoX/Input/Listener.h b/MarathonRecomp/api/Sonicteam/SoX/Input/Listener.h new file mode 100644 index 00000000..45f9b87e --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/SoX/Input/Listener.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + +namespace Sonicteam::SoX::Input +{ + class Listener : public SoX::Object + { + public: + SoX::LinkNode m_lnListener; + bool m_Flag1; + bool m_Flag2; + be m_Field14; + }; + + MARATHON_ASSERT_SIZEOF(Listener, 0x18); + MARATHON_ASSERT_OFFSETOF(Listener, m_lnListener, 0x4); + MARATHON_ASSERT_OFFSETOF(Listener, m_Flag1, 0x10); + MARATHON_ASSERT_OFFSETOF(Listener, m_Flag2, 0x11); + MARATHON_ASSERT_OFFSETOF(Listener, m_Field14, 0x14); +} + diff --git a/MarathonRecomp/api/Sonicteam/SoX/Input/Manager.h b/MarathonRecomp/api/Sonicteam/SoX/Input/Manager.h index fc0430fd..8fc4b2dc 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/Input/Manager.h +++ b/MarathonRecomp/api/Sonicteam/SoX/Input/Manager.h @@ -1,6 +1,8 @@ #pragma once #include +#include +#include namespace Sonicteam::SoX::Input { @@ -48,7 +50,7 @@ namespace Sonicteam::SoX::Input { public: be m_PadID; - MARATHON_INSERT_PADDING(0x0C); + SoX::LinkedList m_llListeners; PadState m_PadState; MARATHON_INSERT_PADDING(0x28); }; @@ -67,6 +69,7 @@ namespace Sonicteam::SoX::Input MARATHON_ASSERT_OFFSETOF(PadState, RightStickVerticalS16, 0x26); MARATHON_ASSERT_OFFSETOF(Manager, m_PadID, 0x00); + MARATHON_ASSERT_OFFSETOF(Manager, m_llListeners, 0x4); MARATHON_ASSERT_OFFSETOF(Manager, m_PadState, 0x10); } diff --git a/MarathonRecomp/api/Sonicteam/SoX/LinkNode.h b/MarathonRecomp/api/Sonicteam/SoX/LinkNode.h index 9c650442..af88df80 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/LinkNode.h +++ b/MarathonRecomp/api/Sonicteam/SoX/LinkNode.h @@ -8,6 +8,240 @@ namespace Sonicteam::SoX public: xpointer m_pPrev; xpointer m_pNext; + + void InsertFast(T* nextNode) + { + nextNode->m_pPrev = static_cast(this); + nextNode->m_pNext = this->m_pNext; + + this->m_pNext->m_pPrev = nextNode; + this->m_pNext = nextNode; + } + + void Insert(T* nextNode) + { + if (!nextNode) return; + + nextNode->m_pPrev = static_cast(this); + nextNode->m_pNext = this->m_pNext; + + if (this->m_pNext) + this->m_pNext->m_pPrev = nextNode; + + this->m_pNext = nextNode; + } + + void ResetList() + { + T* current = this->m_pNext.get(); + + while (current && current != this) + { + T* next = current->m_pNext.get(); + current->m_pPrev = nullptr; + current->m_pNext = nullptr; + current = next; + } + + if (this->m_pPrev) this->m_pPrev->m_pNext = this->m_pNext; + if (this->m_pNext) this->m_pNext->m_pPrev = this->m_pPrev; + } + + void Reset() + { + if (this->m_pPrev) this->m_pPrev->m_pNext = this->m_pNext; + if (this->m_pNext) this->m_pNext->m_pPrev = this->m_pPrev; + this->m_pPrev = 0; + this->m_pNext = 0; + } + + void ResetFast() + { + this->m_pPrev->m_pNext = this->m_pNext; + this->m_pNext->m_pPrev = this->m_pPrev; + this->m_pPrev = 0; + this->m_pNext = 0; + } + + class iterator + { + T* m_pCurrent; + T* m_pStart; + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = T*; + using reference = T&; + + explicit iterator(T* start = nullptr) + : m_pCurrent(start ? start->m_pNext.get() : nullptr) + , m_pStart(start) + { + if (m_pStart && m_pStart->m_pNext.get() == m_pStart) + { + m_pCurrent = nullptr; + } + else if (m_pStart) + { + m_pCurrent = m_pStart->m_pNext.get(); + } + } + + reference operator*() const + { + return *m_pCurrent; + } + + pointer operator->() const + { + return m_pCurrent; + } + + iterator& operator++() + { + if (m_pCurrent && m_pCurrent->m_pNext) + { + m_pCurrent = m_pCurrent->m_pNext.get(); + + // Stop if we reach the start node again. + if (m_pCurrent == m_pStart) + m_pCurrent = nullptr; + } + else + { + m_pCurrent = nullptr; + } + + return *this; + } + + iterator operator++(int) + { + iterator tmp = *this; + ++(*this); + return tmp; + } + + bool operator==(const iterator& other) const + { + return m_pCurrent == other.m_pCurrent; + } + + bool operator!=(const iterator& other) const + { + return m_pCurrent != other.m_pCurrent; + } + }; + + class const_iterator + { + const T* m_pCurrent; + const T* m_pStart; + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = const T; + using difference_type = std::ptrdiff_t; + using pointer = const T*; + using reference = const T&; + + explicit const_iterator(const T* start = nullptr) + : m_pCurrent(start ? start->m_pNext.get() : nullptr) + , m_pStart(start) + { + if (m_pStart && m_pStart->m_pNext.get() == m_pStart) + { + m_pCurrent = nullptr; + } + else if (m_pStart) + { + m_pCurrent = m_pStart->m_pNext.get(); + } + } + + const_iterator(const iterator& it) + : m_pCurrent(it.m_pCurrent) + , m_pStart(it.m_pStart) + { + } + + reference operator*() const + { + return *m_pCurrent; + } + + pointer operator->() const + { + return m_pCurrent; + } + + const_iterator& operator++() + { + if (m_pCurrent && m_pCurrent->m_pNext) + { + m_pCurrent = m_pCurrent->m_pNext.get(); + + // Stop if we reach the start node again. + if (m_pCurrent == m_pStart) + m_pCurrent = nullptr; + } + else + { + m_pCurrent = nullptr; + } + + return *this; + } + + const_iterator operator++(int) + { + const_iterator tmp = *this; + ++(*this); + return tmp; + } + + bool operator==(const const_iterator& other) const + { + return m_pCurrent == other.m_pCurrent; + } + + bool operator!=(const const_iterator& other) const + { + return m_pCurrent != other.m_pCurrent; + } + }; + + iterator begin() + { + return iterator(static_cast(this)); + } + + iterator end() + { + return iterator(nullptr); + } + + const_iterator begin() const + { + return const_iterator(static_cast(this)); + } + + const_iterator end() const + { + return const_iterator(nullptr); + } + + const_iterator cbegin() const + { + return begin(); + } + + const_iterator cend() const + { + return end(); + } }; template @@ -15,13 +249,33 @@ namespace Sonicteam::SoX { public: xpointer m_pThis; + + void ForEach(std::function callback) + { + for (auto& node : *this) { + if (node.m_pThis) { + callback(node.m_pThis.get()); + } + } + } + + typedef LinkNode IType; + typedef ILinkNode> INodeType; + typedef T pThisType; }; template + using LinkedList = LinkNode; + + template class LinkRef { public: - xpointer m_pElement; - LinkNode m_lnElement; + xpointer m_pElement; + LinkNode> m_lnElement; + + typedef LinkNode> lnElementType; + typedef T pElementType; }; + } diff --git a/MarathonRecomp/api/Sonicteam/SoX/Math/Math.h b/MarathonRecomp/api/Sonicteam/SoX/Math/Math.h new file mode 100644 index 00000000..92cc3225 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/SoX/Math/Math.h @@ -0,0 +1,129 @@ +#pragma once + +#include "Marathon.inl" +#include +#include +#include +#include + +namespace Sonicteam::SoX::Math +{ + inline Matrix4x4 MatrixFromQuaternion(const Quaternion& quat) + { + Matrix4x4 result; + + float xx = quat.X * quat.X; + float yy = quat.Y * quat.Y; + float zz = quat.Z * quat.Z; + float xy = quat.X * quat.Y; + float xz = quat.X * quat.Z; + float yz = quat.Y * quat.Z; + float wx = quat.W * quat.X; + float wy = quat.W * quat.Y; + float wz = quat.W * quat.Z; + + result.M[0][0] = 1.0f - 2.0f * (yy + zz); + result.M[0][1] = 2.0f * (xy + wz); + result.M[0][2] = 2.0f * (xz - wy); + result.M[0][3] = 0.0f; + + result.M[1][0] = 2.0f * (xy - wz); + result.M[1][1] = 1.0f - 2.0f * (xx + zz); + result.M[1][2] = 2.0f * (yz + wx); + result.M[1][3] = 0.0f; + + result.M[2][0] = 2.0f * (xz + wy); + result.M[2][1] = 2.0f * (yz - wx); + result.M[2][2] = 1.0f - 2.0f * (xx + yy); + result.M[2][3] = 0.0f; + + result.M[3][0] = 0.0f; + result.M[3][1] = 0.0f; + result.M[3][2] = 0.0f; + result.M[3][3] = 1.0f; + + return result; + } + + inline Vector TransformCoord(const Vector& vector, const Matrix4x4& matrix) + { + Vector result; + + result.X = vector.X * matrix.M[0][0] + vector.Y * matrix.M[1][0] + vector.Z * matrix.M[2][0] + matrix.M[3][0]; + result.Y = vector.X * matrix.M[0][1] + vector.Y * matrix.M[1][1] + vector.Z * matrix.M[2][1] + matrix.M[3][1]; + result.Z = vector.X * matrix.M[0][2] + vector.Y * matrix.M[1][2] + vector.Z * matrix.M[2][2] + matrix.M[3][2]; + + float w = vector.X * matrix.M[0][3] + vector.Y * matrix.M[1][3] + vector.Z * matrix.M[2][3] + matrix.M[3][3]; + + if (w != 0.0f && w != 1.0f) + { + result.X = result.X.get() / w; + result.Y = result.Y.get() / w; + result.Z = result.Z.get() / w; + + } + + return result; + } + + // Calculates a normalized surface vector based on gravity direction. (analog to 821E8578) + static Quaternion CreateRotationFromUpToDirection(DirectX::XMVECTOR inputDirection) + { + const DirectX::XMVECTOR upVector = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); + + const float epsilon = DirectX::XMVectorGetX(DirectX::XMVectorSplatEpsilon()); + + // 1. Load and normalize input vector + DirectX::XMVECTOR direction = inputDirection; + DirectX::XMVECTOR normDirection = DirectX::XMVector3Normalize(direction); + + // 2. Check for zero-length input + if (DirectX::XMVector3NearEqual(normDirection, DirectX::XMVectorZero(), DirectX::XMVectorReplicate(epsilon))) + { + return DirectX::XMQuaternionIdentity(); + } + + // 3. Calculate orthogonal basis + DirectX::XMVECTOR cross = DirectX::XMVector3Cross(upVector, normDirection); + DirectX::XMVECTOR normCross = DirectX::XMVector3Normalize(cross); + + // 4. Check for colinear vectors + if (DirectX::XMVector3NearEqual(normCross, DirectX::XMVectorZero(), DirectX::XMVectorReplicate(epsilon))) + { + return DirectX::XMQuaternionIdentity(); + } + + // 5. Calculate angle components + DirectX::XMVECTOR dot = DirectX::XMVector3Dot(normDirection, upVector); + float cosAngle = DirectX::XMVectorGetX(DirectX::XMVectorClamp(dot, + DirectX::XMVectorReplicate(-1.0f), + DirectX::XMVectorReplicate(1.0f))); + + // 6. Create rotation quaternion + DirectX::XMVECTOR quat = DirectX::XMQuaternionRotationAxis(normCross, DirectX::XMScalarACos(cosAngle)); + + // Convert XMVECTOR to XMFLOAT4 for return + DirectX::XMFLOAT4 result; + DirectX::XMStoreFloat4(&result, quat); + return result; + } + + static Quaternion QuaternionMultiply(const DirectX::XMVECTOR q1, const DirectX::XMVECTOR q2) + { + return DirectX::XMQuaternionMultiply(q1, q2); + } + + static Quaternion CreateRotationFromForwardUp(const DirectX::XMVECTOR& forward, const DirectX::XMVECTOR& up) + { + DirectX::XMVECTOR rotationQuat = DirectX::XMQuaternionRotationMatrix( + DirectX::XMMatrixLookToLH(DirectX::XMVectorZero(), forward, up) + ); + + return rotationQuat; + } + + static Vector QuaternionToVector(Quaternion quat) + { + return *(Vector*)&quat; + } +} diff --git a/MarathonRecomp/api/Sonicteam/SoX/Math/Matrix.h b/MarathonRecomp/api/Sonicteam/SoX/Math/Matrix.h index a3a79a36..3056e1d3 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/Math/Matrix.h +++ b/MarathonRecomp/api/Sonicteam/SoX/Math/Matrix.h @@ -1,13 +1,20 @@ #pragma once #include "Marathon.inl" +#include +#include namespace Sonicteam::SoX::Math { class Matrix4x4 { public: - be M[4][4]; + union + { + be M[4][4]; + Vector V[4]; + }; + Matrix4x4() {} @@ -20,6 +27,27 @@ namespace Sonicteam::SoX::Math } } + Matrix4x4(DirectX::XMMATRIX& other) + { + for (int i = 0; i < 4; i++) + { + V[i] = other.r[i]; + } + } + + Matrix4x4(const DirectX::XMMATRIX& other) + { + for (int i = 0; i < 4; i++) + { + V[i] = other.r[i]; + } + } + + operator DirectX::XMMATRIX() const + { + return DirectX::XMMATRIX(V[0], V[1], V[2], V[3]); + } + Matrix4x4 Multiply(const Matrix4x4& other) const { Matrix4x4 result{}; @@ -40,7 +68,22 @@ namespace Sonicteam::SoX::Math Matrix4x4 operator*(Matrix4x4 other) { - return Multiply(other); + return DirectX::XMMatrixMultiply(*this, other); + } + + static Matrix4x4 RotationQuaternion(const Quaternion& rotation) + { + return DirectX::XMMatrixRotationQuaternion(rotation); + } + + static Matrix4x4 TranslationFromVector(const Vector& translation) + { + return DirectX::XMMatrixTranslationFromVector(translation); + } + + static Matrix4x4 LookToRH(const Vector& eye, const Vector& focus, const Vector& up) + { + return DirectX::XMMatrixLookAtRH(eye, focus, up); } }; } diff --git a/MarathonRecomp/api/Sonicteam/SoX/Math/Quaternion.h b/MarathonRecomp/api/Sonicteam/SoX/Math/Quaternion.h index 587b4f54..ebe4ecd7 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/Math/Quaternion.h +++ b/MarathonRecomp/api/Sonicteam/SoX/Math/Quaternion.h @@ -1,15 +1,157 @@ #pragma once #include +#include +#include +#include namespace Sonicteam::SoX::Math { - class alignas(16) Quaternion + + class alignas(16) Quaternion : public __vector { public: - be X; - be Y; - be Z; - be W; + + Quaternion() :__vector(0, 0, 0, 1) {} + Quaternion(float x, float y = 0, float z = 0, float w = 0) :__vector(x, y, z, w) {} + + Quaternion(__vector v) :__vector(v.X, v.Y, v.Z, v.W) {}; + + Quaternion(DirectX::XMVECTOR vec) : __vector(vec) {} + Quaternion(DirectX::XMFLOAT4 vec) : __vector(vec) {} + + Quaternion operator*(float scalar) const + { + return { X * scalar, Y * scalar, Z * scalar, W * scalar }; + } + + Quaternion operator*(const Quaternion& quat) const + { + return DirectX::XMQuaternionMultiply(*this, quat); + } + + Vector operator*(const Vector& vector) const + { + return DirectX::XMVector3Rotate(vector, *this); + } + + static const Quaternion Identity() + { + return { 0 , 0, 0, 1 }; + } + + Vector GetForwardVector() const + { + return DirectX::XMVector3Rotate(Vector::Forward(), *this); + } + + Vector GetUpVector() const + { + return DirectX::XMVector3Rotate(Vector::Up(), *this); + } + + Vector GetRightVector() const + { + return DirectX::XMVector3Rotate(Vector::Right(), *this); + } + + static Quaternion FromVector(const Vector& direction, const Vector& up = Vector::Up()) + { + Vector normalizedDir = direction.Normalize3(); + if (DirectX::XMVectorGetX(DirectX::XMVector3Length(normalizedDir)) < 0.001f) + return Identity(); + + Vector zaxis = normalizedDir; + Vector xaxis = Vector::Cross(up, zaxis).Normalize3(); + Vector yaxis = Vector::Cross(zaxis, xaxis); + + DirectX::XMMATRIX mat = DirectX::XMMatrixSet( + xaxis.X, xaxis.Y, xaxis.Z, 0.0f, + yaxis.X, yaxis.Y, yaxis.Z, 0.0f, + zaxis.X, zaxis.Y, zaxis.Z, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ); + + return DirectX::XMQuaternionRotationMatrix(mat); + } + + //sub_821E8778 --done-- + static Quaternion CreateFromVectors(Vector forward, Vector target, Vector up) + { + auto cross1 = Vector::Cross(up, forward).Normalize3(); + auto cross2 = Vector::Cross(up, target).Normalize3(); + + auto rotationAxis = Vector::Cross(cross1, cross2); + auto [normalizedAxis, axisLengthZero] = rotationAxis.NormalizeEX(); + + float dot = Vector::Dot(cross2, cross1).X.get(); + dot = std::clamp(dot, -1.0f, 1.0f); + + float sinHalf = std::sqrt((1.0f - dot) * 0.5f); + float cosHalf = std::sqrt((1.0f + dot) * 0.5f); + + if (sinHalf != 0.0f && axisLengthZero == 0.0f) + { + normalizedAxis = up.Normalize3(); + } + + return Quaternion( + normalizedAxis.X * sinHalf, + normalizedAxis.Y * sinHalf, + normalizedAxis.Z * sinHalf, + cosHalf + ); + } + + static Quaternion Slerp(Quaternion q1, Quaternion q2, float lerp) + { + return DirectX::XMQuaternionSlerp(q1, q2, lerp);; + } + + Quaternion Slerp(Quaternion q2, float lerp) + { + return Slerp(*this, q2, lerp); + } + + static Quaternion Inverse(Quaternion q1) + { + return DirectX::XMQuaternionInverse(q1);; + } + + Quaternion Inverse() + { + return Inverse(*this); + } }; + + inline Quaternion __vector::AsQuaternion() const + { + return Quaternion(X, Y, Z, W); + } + + inline Vector __vector::AsVector() const + { + return Vector(X, Y, Z, W); + } + + inline Quaternion Vector::ToQuaternion(float angle) const + { + Vector axis = this->Normalize3(); + return DirectX::XMQuaternionRotationAxis(axis, angle); + } + + inline Quaternion Vector::RotationTo(const Vector& target) const + { + Vector from = this->Normalize3(); + Vector to = target.Normalize3(); + + float dot = DirectX::XMVectorGetX(Vector::Dot(from, to)); + dot = std::clamp(dot, -1.0f, 1.0f); + + if (dot > 0.9999f) return Quaternion::Identity(); + + Vector axis = Vector::Cross(from, to).Normalize3(); + float angle = std::acos(dot); + return axis.ToQuaternion(angle); + } } diff --git a/MarathonRecomp/api/Sonicteam/SoX/Math/Vector.h b/MarathonRecomp/api/Sonicteam/SoX/Math/Vector.h index e3ac86e3..f7cf3521 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/Math/Vector.h +++ b/MarathonRecomp/api/Sonicteam/SoX/Math/Vector.h @@ -1,6 +1,8 @@ #pragma once #include +#include +#include namespace Sonicteam::SoX::Math { @@ -19,26 +21,169 @@ namespace Sonicteam::SoX::Math be Z; }; - class alignas(16) Vector + class alignas(16) Vector : public __vector { public: - be X; - be Y; - be Z; - be W; + Vector() :__vector() + { + } + + Vector(__vector v) :__vector(v.X, v.Y, v.Z, v.W) + { + } + + Vector(float x, float y = 0.0f, float z = 0.0f, float w = 0.0f) :__vector(x, y, z, w) + { + } + + Vector(DirectX::XMVECTOR vec) : __vector(vec) + { + } + + Vector(DirectX::XMFLOAT4 vec) : __vector(vec) + { + } + + Vector operator+(float scalar) const + { + return { X + scalar, Y + scalar, Z + scalar, W + scalar }; + } + + Vector operator+(Vector v2) const + { + return { X + v2.X, Y + v2.Y, Z + v2.Z, W + v2.W }; + } + + Vector operator-(Vector v2) const + { + return { X - v2.X, Y - v2.Y, Z - v2.Z, W - v2.W }; + } + + Vector operator*(float scalar) const + { + return { X * scalar, Y * scalar, Z * scalar, W * scalar }; + } + + Vector operator/(float scalar) const + { + return { X / scalar, Y / scalar, Z / scalar, W / scalar }; + } + + Vector operator*(const Vector& scalar) const + { + return { X * scalar.X, Y * scalar.Y, Z * scalar.Z, 1.0 }; + } float DistanceTo(const Vector& other) const { float dx = static_cast(X) - static_cast(other.X); float dy = static_cast(Y) - static_cast(other.Y); float dz = static_cast(Z) - static_cast(other.Z); + return sqrtf(dx * dx + dy * dy + dz * dz); + } + + static Vector Cross(const Vector& first, const Vector& second) + { + return { + first.Y * second.Z - first.Z * second.Y, + first.Z * second.X - first.X * second.Z, + first.X * second.Y - first.Y * second.X + }; + } + + static Vector Dot(const Vector& first, const Vector& second) + { + return DirectX::XMVector3Dot(first, second); + } + + static Vector Slerp(const Vector& first, const Vector& second, float lerp = 1.0f) + { + return DirectX::XMQuaternionSlerp(first, second, lerp); + } - return std::sqrt(dx * dx + dy * dy + dz * dz); + static Vector Length3(const Vector& first) + { + return DirectX::XMVector3Length(first); + } + + static Vector Normalize(const Vector& first) + { + return DirectX::XMVector3Normalize(first); + } + + static Vector Normalize3(const Vector& first) + { + return DirectX::XMVector3Normalize(first); + } + + // Analog to sub_825D22A0 + static std::pair NormalizeEX(const Vector& first) + { + float length = DirectX::XMVectorGetX(DirectX::XMVector3Length(first)); + return { DirectX::XMVector3Normalize(first), length }; + } + + Vector Cross(const Vector& other) const + { + return Cross(*this, other); + } + + Vector Dot(const Vector& other) const + { + return Dot(*this, other); + } + + Vector Slerp(const Vector& other, float lerp = 1.0f) const + { + return Slerp(*this, other, lerp); + } + + Vector Normalize3() const + { + return Normalize3(*this); + } + + std::pair NormalizeEX() const + { + return NormalizeEX(*this); + } + + Vector Length3() const + { + return Length3(*this); + } + + Vector InvertNormal() const + { + return { -X, -Y, -Z, 1.0f }; + } + + Quaternion ToQuaternion(float angle) const; + Quaternion RotationTo(const Vector& target) const; + + static const Vector Forward() + { + return { 0.0f, 0.0f, 1.0f, 1.0f }; + } + + static const Vector Up() + { + return { 0.0f, 1.0f, 0.0f, 1.0f }; + } + + static const Vector Zero() + { + return { 0.0f, 0.0f, 0.0f, 1.0f }; + } + + static const Vector Right() + { + return { 1.0f, 0.0f, 0.0f, 1.0f }; } - Vector operator+(float addend) + static const Vector Left() { - return { X + addend, Y + addend, Z + addend, W + addend }; + return { -1.0f, 0.0f, 0.0f, 1.0f }; } }; } diff --git a/MarathonRecomp/api/Sonicteam/SoX/Math/__vector.h b/MarathonRecomp/api/Sonicteam/SoX/Math/__vector.h new file mode 100644 index 00000000..609271af --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/SoX/Math/__vector.h @@ -0,0 +1,126 @@ +#pragma once + +#include +#include +#include +#include + +namespace Sonicteam::SoX::Math +{ + // Forward declarations + class Vector; + class Quaternion; + + struct alignas(16) __vector + { + public: + be X; + be Y; + be Z; + be W; + + __vector() + : X(0) + , Y(0) + , Z(0) + , W(0) + { + } + + __vector(float x, float y, float z, float w) + : X(x) + , Y(y) + , Z(z) + , W(w) + { + } + + __vector(float x, float y, float z) + : X(x) + , Y(y) + , Z(z) + , W(0) + { + } + + __vector(const DirectX::XMFLOAT4& vec) + : X(vec.x) + , Y(vec.y) + , Z(vec.z) + , W(vec.w) + { + } + + __vector(const DirectX::XMFLOAT3& vec) + : X(vec.x) + , Y(vec.y) + , Z(vec.z) + , W(0) + { + } + + __vector(const DirectX::XMVECTOR& vec) + { + DirectX::XMFLOAT4 temp; + DirectX::XMStoreFloat4(&temp, vec); + X = temp.x; + Y = temp.y; + Z = temp.z; + W = temp.w; + } + + // Conversion operators + operator DirectX::XMFLOAT4() const + { + return DirectX::XMFLOAT4( + static_cast(X), + static_cast(Y), + static_cast(Z), + static_cast(W) + ); + } + + operator DirectX::XMFLOAT3() const + { + return DirectX::XMFLOAT3( + static_cast(X), + static_cast(Y), + static_cast(Z) + ); + } + + operator DirectX::XMVECTOR() const + { + return DirectX::XMVectorSet( + this->X, + this->Y, + this->Z, + this->W + ); + } + + __vector operator*(float scalar) const + { + return { this->X * scalar, this->Y * scalar, this->Z * scalar, this->W * scalar }; + } + + __vector operator+(__vector v) const + { + return { this->X + v.X, this->Y + v.Y, this->Z + v.Z, this->W + v.W }; + } + + __vector operator-(__vector v) const + { + return { this->X - v.X, this->Y - v.Y, this->Z - v.Z, this->W - v.W }; + } + + // Universal conversion methods (declarations only) + Quaternion AsQuaternion() const; + Vector AsVector() const; + + std::string tostring() const + { + return fmt::format("({}, {}, {}, {})", X.get(), Y.get(), Z.get(), W.get()); + } + }; +} diff --git a/MarathonRecomp/api/Sonicteam/SoX/Message.h b/MarathonRecomp/api/Sonicteam/SoX/Message.h index eaf2a8d0..cffc9011 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/Message.h +++ b/MarathonRecomp/api/Sonicteam/SoX/Message.h @@ -15,6 +15,7 @@ namespace Sonicteam::SoX template struct Message : IMessage { + public: Message() { ID = id; diff --git a/MarathonRecomp/api/Sonicteam/SoX/MessageReceiver.h b/MarathonRecomp/api/Sonicteam/SoX/MessageReceiver.h index 09c45232..b9c420a4 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/MessageReceiver.h +++ b/MarathonRecomp/api/Sonicteam/SoX/MessageReceiver.h @@ -25,6 +25,15 @@ namespace Sonicteam::SoX { return GuestToHostFunction(m_pVftable->fpProcessMessage, this, pMessage); } + + template + bool ProcessMessage(Message& message) + { + guest_heap_var msg(message); + bool result = ProcessMessage((IMessage*)msg.get()); + message = *msg; + return result; + } }; MARATHON_ASSERT_OFFSETOF(MessageReceiver, m_pVftable, 0x00); diff --git a/MarathonRecomp/api/Sonicteam/SoX/Object.h b/MarathonRecomp/api/Sonicteam/SoX/Object.h index 28ced9c1..7848a80e 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/Object.h +++ b/MarathonRecomp/api/Sonicteam/SoX/Object.h @@ -10,6 +10,7 @@ namespace Sonicteam::SoX struct Vftable { be fpGetName; + be fpDestroy; }; xpointer m_pVftable; diff --git a/MarathonRecomp/api/Sonicteam/SoX/Physics/Body.h b/MarathonRecomp/api/Sonicteam/SoX/Physics/Body.h new file mode 100644 index 00000000..18ed0f29 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/SoX/Physics/Body.h @@ -0,0 +1,9 @@ +#pragma once + +#include +#include + +namespace Sonicteam::SoX::Physics +{ + class Body : public Entity {}; +} diff --git a/MarathonRecomp/api/Sonicteam/SoX/Physics/Entity.h b/MarathonRecomp/api/Sonicteam/SoX/Physics/Entity.h index 68fec9b2..cf7970dc 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/Physics/Entity.h +++ b/MarathonRecomp/api/Sonicteam/SoX/Physics/Entity.h @@ -11,37 +11,72 @@ namespace Sonicteam::SoX::Physics { + class EntityRef; + class Entity : public MessageReceiver, public RefCountObject { public: struct Vftable : public MessageReceiver::Vftable { - MARATHON_INSERT_PADDING(0x38); - be fpInitializeToWorld; + MARATHON_INSERT_PADDING(0x30); + be fpIsInitializedToWorld; + MARATHON_INSERT_PADDING(0x4); + be InitializeToWorld; MARATHON_INSERT_PADDING(0x18); - be fpSetPhantomListener; + be SetPhantomListener; + MARATHON_INSERT_PADDING(0x30); + be fpApplyForce1; // void (__cdecl *applyForce)(hkpMotion *this, const float, const hkVector4 *, const hkVector4 *); linear + MARATHON_INSERT_PADDING(0xC); + be fpApplyForce2; // void (__cdecl *applyForce)(hkpMotion *this, const float, const hkVector4 *); angular + be fpGetLinearVelocity; + be fpSetLinearVelocity; + be fpGetAngularVelocity; + be fpSetAngularVelocity; }; - MARATHON_INSERT_PADDING(0x10); + MARATHON_INSERT_PADDING(0x4); + SoX::LinkNode m_lnEntity; RefSharedPointer m_spPhantomListener; xpointer m_pReceiver; RefSharedPointer m_spShape; + bool IsInitializedToWorld() + { + auto vft = static_cast(MessageReceiver::m_pVftable.get()); + return GuestToHostFunction(vft->fpIsInitializedToWorld, this); + } + void InitializeToWorld(RefSharedPointer& world) { auto vft = static_cast(MessageReceiver::m_pVftable.get()); - GuestToHostFunction(vft->fpInitializeToWorld, this, &world); + GuestToHostFunction(vft->InitializeToWorld, this, &world); } void SetPhantomListener(RefSharedPointer& phantomListener) { auto vft = static_cast(MessageReceiver::m_pVftable.get()); - GuestToHostFunction(vft->fpSetPhantomListener, this, &phantomListener); + GuestToHostFunction(vft->SetPhantomListener, this, guest_heap_var>(phantomListener).get()); + } + + SoX::Math::Vector GetAngularVelocity() + { + guest_heap_var ret; + auto vft = static_cast(MessageReceiver::m_pVftable.get()); + GuestToHostFunction(vft->fpGetAngularVelocity,ret.get(), this); + return *ret.get(); + } + + SoX::Math::Vector GetLinearVelocity() + { + guest_heap_var ret; + auto vft = static_cast(MessageReceiver::m_pVftable.get()); + GuestToHostFunction(vft->fpGetLinearVelocity,ret.get(), this); + return *ret.get(); } }; - MARATHON_ASSERT_OFFSETOF(Entity, m_spPhantomListener, 0x1C); - MARATHON_ASSERT_OFFSETOF(Entity, m_pReceiver, 0x20); - MARATHON_ASSERT_OFFSETOF(Entity, m_spShape, 0x24); MARATHON_ASSERT_SIZEOF(Entity, 0x28); + MARATHON_ASSERT_OFFSETOF(Entity::Vftable, fpApplyForce1, 0x90); + MARATHON_ASSERT_OFFSETOF(Entity::Vftable, fpApplyForce2, 0xA0); + MARATHON_ASSERT_OFFSETOF(Entity::Vftable, fpGetLinearVelocity, 0xA4); } diff --git a/MarathonRecomp/api/Sonicteam/SoX/Physics/EntityRef.h b/MarathonRecomp/api/Sonicteam/SoX/Physics/EntityRef.h new file mode 100644 index 00000000..158149b5 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/SoX/Physics/EntityRef.h @@ -0,0 +1,211 @@ +#pragma once + +#include +#include +#include + +namespace Sonicteam::SoX::Physics +{ + class EntityRef : public LinkRef + { + public: + ~EntityRef() + { + ClearRef(); + m_lnElement.Reset(); + } + + EntityRef() noexcept + { + InitializeEmpty(); + } + + EntityRef(const EntityRef& other) + { + InitializeEmpty(); + CopyFrom(other); + } + + EntityRef& operator=(const EntityRef& other) + { + if (this != &other) + { + ClearRef(); + InitializeEmpty(); + CopyFrom(other); + } + return *this; + } + + EntityRef(EntityRef&& other) noexcept + { + InitializeEmpty(); + MoveFrom(std::move(other)); + } + + EntityRef& operator=(EntityRef&& other) noexcept + { + if (this != &other) + { + ClearRef(); + InitializeEmpty(); + MoveFrom(std::move(other)); + } + return *this; + } + + void ClearRef() noexcept + { + if (m_lnElement.m_pNext) + { + m_lnElement.ResetFast(); + } + } + + bool sub_82595500(Entity* entityRef) + { + if (m_pElement && m_pElement->IsInitializedToWorld()) + return entityRef != m_pElement.get(); + else + return entityRef != nullptr; + } + + Entity* sub_82595020() + { + if (m_pElement && m_pElement->IsInitializedToWorld()) + return m_pElement.get(); + return nullptr; + } + + private: + void InitializeEmpty() noexcept + { + m_pElement = nullptr; + m_lnElement.m_pNext = nullptr; + m_lnElement.m_pPrev = nullptr; + m_lnElement.m_pThis = this; + } + + void CopyFrom(const EntityRef& other) + { + if (other.m_pElement && other.m_pElement->IsInitializedToWorld()) + { + m_pElement = other.m_pElement; + other.m_pElement->m_lnEntity.InsertFast((LinkNode::IType*) & m_lnElement); + } + } + + void MoveFrom(EntityRef&& other) noexcept + { + CopyFrom(other); + other.ClearRef(); + other.InitializeEmpty(); + } + }; + + class EntityRefWrapper + { + private: + xpointer m_EntityRef; + int* m_refCount; + + void add_ref() + { + if (m_refCount) { + ++(*m_refCount); + } + } + + void release() + { + if (m_refCount && --(*m_refCount) == 0) { + if (m_EntityRef.get()) { + m_EntityRef->~EntityRef(); + g_userHeap.Free(m_EntityRef.get()); + } + delete m_refCount; + m_EntityRef = nullptr; + m_refCount = nullptr; + } + } + + public: + + EntityRefWrapper() : m_refCount(new int(1)) + { + m_EntityRef = g_userHeap.AllocPhysical(); + } + + explicit EntityRefWrapper(EntityRef* ref) : m_refCount(new int(1)) + { + m_EntityRef = ref; + } + + EntityRefWrapper(const EntityRefWrapper& other) + : m_EntityRef(other.m_EntityRef), m_refCount(other.m_refCount) + { + add_ref(); + } + + EntityRefWrapper& operator=(const EntityRefWrapper& other) + { + if (this != &other) { + release(); + m_EntityRef = other.m_EntityRef; + m_refCount = other.m_refCount; + add_ref(); + } + return *this; + } + + EntityRefWrapper(EntityRefWrapper&& other) noexcept + : m_EntityRef(std::move(other.m_EntityRef)) + , m_refCount(other.m_refCount) + { + other.m_refCount = nullptr; + } + + EntityRefWrapper& operator=(EntityRefWrapper&& other) noexcept + { + if (this != &other) { + release(); + m_EntityRef = std::move(other.m_EntityRef); + m_refCount = other.m_refCount; + other.m_refCount = nullptr; + } + return *this; + } + + ~EntityRefWrapper() + { + release(); + } + + // Dereference operators + EntityRef* operator->() const { return m_EntityRef.get(); } + EntityRef& operator*() const { return *m_EntityRef.get(); } + + // Getters + EntityRef* get() const { return m_EntityRef.get(); } + int use_count() const { return m_refCount ? *m_refCount : 0; } + bool unique() const { return use_count() == 1; } + + // Reset functionality + void reset(EntityRef* ptr = nullptr) + { + release(); + if (ptr) { + m_EntityRef = ptr; + m_refCount = new int(1); + } + } + + explicit operator bool() const { return m_EntityRef.get() != nullptr; } + + inline void swap(EntityRefWrapper& other) noexcept + { + std::swap(m_EntityRef, other.m_EntityRef); + std::swap(m_refCount, other.m_refCount); + } + }; +} diff --git a/MarathonRecomp/api/Sonicteam/SoX/Physics/Havok/RayCastHavok.h b/MarathonRecomp/api/Sonicteam/SoX/Physics/Havok/RayCastHavok.h new file mode 100644 index 00000000..6acbb580 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/SoX/Physics/Havok/RayCastHavok.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include +#include + +namespace Sonicteam::SoX::Physics::Havok +{ + class RayCastHavok : public Physics::RayCast + { + public: + xpointer m_HavokRayCast; //not sure about base class + }; + + MARATHON_ASSERT_SIZEOF(RayCastHavok, 0xC); +} diff --git a/MarathonRecomp/api/Sonicteam/SoX/Physics/Havok/ShapeCastHavok.h b/MarathonRecomp/api/Sonicteam/SoX/Physics/Havok/ShapeCastHavok.h new file mode 100644 index 00000000..bfcb4305 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/SoX/Physics/Havok/ShapeCastHavok.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include +#include + +namespace Sonicteam::SoX::Physics::Havok +{ + class ShapeCastHavok : public Physics::ShapeCast + { + xpointer m_HavokShape; + }; + + MARATHON_ASSERT_SIZEOF(ShapeCastHavok, 0x10); +} diff --git a/MarathonRecomp/api/Sonicteam/SoX/Physics/IntersectListener.h b/MarathonRecomp/api/Sonicteam/SoX/Physics/IntersectListener.h index 5c94fc07..1539fc97 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/Physics/IntersectListener.h +++ b/MarathonRecomp/api/Sonicteam/SoX/Physics/IntersectListener.h @@ -1,15 +1,11 @@ #pragma once #include -#include +#include namespace Sonicteam::SoX::Physics { - class IntersectListener : public SoX::RefCountObject - { - public: - MARATHON_INSERT_PADDING(0x0C); - }; + class IntersectListener : public ShapeCastListener {}; - MARATHON_ASSERT_SIZEOF(IntersectListener, 0x14); + MARATHON_ASSERT_SIZEOF(IntersectListener, 0x8); } diff --git a/MarathonRecomp/api/Sonicteam/SoX/Physics/RayCast.h b/MarathonRecomp/api/Sonicteam/SoX/Physics/RayCast.h new file mode 100644 index 00000000..b3538b30 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/SoX/Physics/RayCast.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace Sonicteam::SoX::Physics +{ + struct RayCastRay + { + be Flag; + SoX::Math::Vector Field10; + SoX::Math::Vector Field20; + }; + + class RayCast : public SoX::RefCountObject + { + public: + struct Vftable : RefCountObject::Vftable + { + be fpFunc4; + be fpGetName; + be fpFuncC; + be fpFunc10; + be fpFunc14; + }; + + void Func4(RayCastRay* ray) + { + auto vft = (Vftable*)m_pVftable.get(); + GuestToHostFunction(vft->fpFunc4, this, ray); + } + + void Func4(RayCastRay& ray) + { + Func4(guest_heap_var(ray).get()); + } + + void Func8(SoX::RefSharedPointer* world) + { + auto vft = (Vftable*)m_pVftable.get(); + world->get()->AddReference(); + GuestToHostFunction(vft->fpGetName, this, world); + } + + void Func8(SoX::RefSharedPointer& ray) + { + Func8(guest_heap_var>(ray).get()); + } + + void Func14(SoX::Math::Vector* points, SoX::Physics::ShapeCastListener* listener) + { + auto vft = (Vftable*)m_pVftable.get(); + GuestToHostFunction(vft->fpFunc14,this, points, listener); + } + }; +} diff --git a/MarathonRecomp/api/Sonicteam/SoX/Physics/ShapeCast.h b/MarathonRecomp/api/Sonicteam/SoX/Physics/ShapeCast.h new file mode 100644 index 00000000..60a30b1d --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/SoX/Physics/ShapeCast.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include +#include + +namespace Sonicteam::SoX::Physics +{ + class ShapeCast : public SoX::RefCountObject + { + public: + struct Vftable:SoX::RefCountObject::Vftable + { + be m_fpFunc4; + be m_fpFunc8; + be m_fpFuncC; + be m_fpFunc10; + be m_fpFunc14; + be m_fpFunc18; + be m_fpFunc1C; + be m_fpFunc20; + be m_fpFunc24; + be m_fpFunc28; + be m_fpFunc2C; + be m_fpFunc30; + be m_fpSetShape; + be m_fpFunc38; + be m_fpFunc3C; + }; + xpointer m_Shape; + + void Func38(SoX::Math::Vector* points, SoX::Physics::ShapeCastListener* listener) + { + Vftable* vft = (Vftable*)this->m_pVftable.get(); + GuestToHostFunction(vft->m_fpFunc38.get(),this,points, listener); + } + + void Func3C(SoX::Math::Vector* points, SoX::Physics::ShapeCastListener* listener) + { + Vftable* vft = (Vftable*)this->m_pVftable.get(); + GuestToHostFunction(vft->m_fpFunc3C.get(),this,points, listener); + } + }; + + MARATHON_ASSERT_SIZEOF(ShapeCast, 0xC); +} diff --git a/MarathonRecomp/api/Sonicteam/SoX/RefSharedPointer.h b/MarathonRecomp/api/Sonicteam/SoX/RefSharedPointer.h index ac87501e..5fc51657 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/RefSharedPointer.h +++ b/MarathonRecomp/api/Sonicteam/SoX/RefSharedPointer.h @@ -12,22 +12,28 @@ namespace Sonicteam::SoX xpointer m_ptr; public: + + RefSharedPointer() : m_ptr(nullptr) + { + + } + explicit RefSharedPointer(T* value) : m_ptr(value) { if (m_ptr.get()) - m_ptr->AddRef(); + m_ptr->AddReference(); } explicit RefSharedPointer(xpointer value) : m_ptr(value) { if (m_ptr.get()) - m_ptr->AddRef(); + m_ptr->AddReference(); } RefSharedPointer(const RefSharedPointer& other) : m_ptr(other.m_ptr) { if (m_ptr.get()) - m_ptr->AddRef(); + m_ptr->AddReference(); } RefSharedPointer(RefSharedPointer&& other) noexcept : m_ptr(std::move(other.m_ptr)) @@ -43,14 +49,14 @@ namespace Sonicteam::SoX RefSharedPointer& operator=(const RefSharedPointer& other) { - if (this != &other) + if (this != &other) { reset(); m_ptr = other.m_ptr; if (m_ptr.get()) - m_ptr->AddRef(); + m_ptr->AddReference(); } return *this; @@ -58,7 +64,7 @@ namespace Sonicteam::SoX RefSharedPointer& operator=(RefSharedPointer&& other) noexcept { - if (this != &other) + if (this != &other) { reset(); diff --git a/MarathonRecomp/api/Sonicteam/SoX/ResourceManager.h b/MarathonRecomp/api/Sonicteam/SoX/ResourceManager.h new file mode 100644 index 00000000..dfd7b5b7 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/SoX/ResourceManager.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include + +namespace Sonicteam::SoX +{ + struct ResourceManagerMgrTemplate + { + be fpFunc0; // Usually a function pointer to 0x82595818. + be fpFunc4; // Usually a function pointer to 0x82631500. + xpointer pManager; + char Flag01; // 01 (enabled?), referenced in 82581FD4 and 825BDB54 (when template is created). + MARATHON_INSERT_PADDING(3); + char Flag02; // Referenced in 825BDB90 and *Field04, then set Flag02 to 0, for what? + }; + + class ResourceManager : public System::Singleton> + { + public: + struct Vftable + { + be fpDestroy; + }; + + xpointer m_pVftable; + stdx::map, stdx::map>> m_mResources; // m_mResources[IResourceMgr->m_MgrIndex][Resource->m_Name] -> IResource* + MARATHON_INSERT_PADDING(4); + MARATHON_INSERT_PADDING(0x0C); // std::list> + stdx::map, ResourceManagerMgrTemplate> m_mManagers; + MARATHON_INSERT_PADDING(4); + stdx::map, be, MARATHON_STD_MAP_CONST_CHAR_COMPARE> m_mManagerIndices; + }; +} diff --git a/MarathonRecomp/api/Sonicteam/SoX/Scenery/Clump.h b/MarathonRecomp/api/Sonicteam/SoX/Scenery/Clump.h new file mode 100644 index 00000000..091805a3 --- /dev/null +++ b/MarathonRecomp/api/Sonicteam/SoX/Scenery/Clump.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include +#include + +namespace Sonicteam::SoX::Scenery +{ + class Clump : public Drawable + { + public: + MARATHON_INSERT_PADDING(0x10); + }; + + MARATHON_ASSERT_SIZEOF(Clump, 0x80); +} diff --git a/MarathonRecomp/api/Sonicteam/SoX/Scenery/Drawable.h b/MarathonRecomp/api/Sonicteam/SoX/Scenery/Drawable.h index bed99644..3afa31df 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/Scenery/Drawable.h +++ b/MarathonRecomp/api/Sonicteam/SoX/Scenery/Drawable.h @@ -2,15 +2,52 @@ #include #include +#include #include namespace Sonicteam::SoX::Scenery { + class WorldImp; + class Drawable : public RefCountObject, public CameraEventCallback { public: - MARATHON_INSERT_PADDING(0x64); + class frameObserver: SoX::Graphics::FrameObserver + { + xpointer m_pParent; + MARATHON_INSERT_PADDING(0x28); + }; + + struct Vftable : RefCountObject::Vftable + { + be fpUpdateRenderFlag; + be fpOutPosition; // -- ? + be fpOutTransform; // -- ? + be fpFunc10; + be fpUpdateInstance; + be fpGetDrawableNameWeird; // + be fpGetDrawableName; + be fpReset; // should free from deque = no render + be fpFunc24; + }; + + void Reset() + { + MARATHON_CALL_VIRTUAL_FUNCTION(RefCountObject, void, &Vftable::fpReset, this); + } + + xpointer m_pWorld; + MARATHON_INSERT_PADDING(0x8); + be m_DrawableFlag; + MARATHON_INSERT_PADDING(0x4); + frameObserver m_frameObserver; + LinkNode m_lnDrawable; + MARATHON_INSERT_PADDING(4); }; + MARATHON_ASSERT_OFFSETOF(Drawable,m_pWorld, 0xC); + MARATHON_ASSERT_OFFSETOF(Drawable, m_DrawableFlag, 0x18); + MARATHON_ASSERT_OFFSETOF(Drawable, m_frameObserver, 0x20); + MARATHON_ASSERT_OFFSETOF(Drawable, m_lnDrawable, 0x60); MARATHON_ASSERT_SIZEOF(Drawable, 0x70); } diff --git a/MarathonRecomp/api/Sonicteam/SoX/Thread.h b/MarathonRecomp/api/Sonicteam/SoX/Thread.h index 9c2d80d9..4b76b7f5 100644 --- a/MarathonRecomp/api/Sonicteam/SoX/Thread.h +++ b/MarathonRecomp/api/Sonicteam/SoX/Thread.h @@ -1,31 +1,51 @@ #pragma once #include +#include namespace Sonicteam::SoX { class Thread { public: - xpointer m_pVftable; - MARATHON_INSERT_PADDING(8); - xpointer m_pParent; - be m_EventHandleA; - be m_EventHandleB; - MARATHON_INSERT_PADDING(4); - be m_ThreadHandle; - bool m_Field20; + struct Vftable + { + be fpDestroy; + be fpFunc04; + be fpFunc08; + be fpFunc0C; + }; + + xpointer m_pVftable; + LinkNode m_lnThread; + be m_StartEvent; + be m_EndEvent; + be m_ID; + be m_Handle; + bool m_IsExecutable; MARATHON_INSERT_PADDING(3); be m_DeltaTime; - MARATHON_INSERT_PADDING(8); - xpointer m_pName; MARATHON_INSERT_PADDING(4); - bool m_Field38; - bool m_Field39; - MARATHON_INSERT_PADDING(6); + be m_StepCount; + xpointer m_pName; + be m_StepTime; + bool m_IsThreadReady; + bool m_IsWaitForStartEvent; + MARATHON_INSERT_PADDING(2); + be m_WaitForEndMicroSeconds; xpointer m_pContext; MARATHON_INSERT_PADDING(4); + void Func04() + { + GuestToHostFunction(m_pVftable->fpFunc04, this); + } + + void Func08(float deltaTime) + { + GuestToHostFunction(m_pVftable->fpFunc08, this, deltaTime); + } + template T* GetContext() { @@ -33,16 +53,6 @@ namespace Sonicteam::SoX } }; - MARATHON_ASSERT_OFFSETOF(Thread, m_pVftable, 0x00); - MARATHON_ASSERT_OFFSETOF(Thread, m_pParent, 0x0C); - MARATHON_ASSERT_OFFSETOF(Thread, m_EventHandleA, 0x10); - MARATHON_ASSERT_OFFSETOF(Thread, m_EventHandleB, 0x14); - MARATHON_ASSERT_OFFSETOF(Thread, m_ThreadHandle, 0x1C); - MARATHON_ASSERT_OFFSETOF(Thread, m_Field20, 0x20); - MARATHON_ASSERT_OFFSETOF(Thread, m_DeltaTime, 0x24); - MARATHON_ASSERT_OFFSETOF(Thread, m_pName, 0x30); - MARATHON_ASSERT_OFFSETOF(Thread, m_Field38, 0x38); - MARATHON_ASSERT_OFFSETOF(Thread, m_Field39, 0x39); - MARATHON_ASSERT_OFFSETOF(Thread, m_pContext, 0x40); - MARATHON_ASSERT_SIZEOF(Thread, 0x48); + MARATHON_ASSERT_OFFSETOF(Thread, m_StartEvent, 0x10); + MARATHON_ASSERT_OFFSETOF(Thread, m_IsThreadReady, 0x38); } diff --git a/MarathonRecomp/api/Sonicteam/TextBook.h b/MarathonRecomp/api/Sonicteam/TextBook.h index 9d9cea4a..a376e146 100644 --- a/MarathonRecomp/api/Sonicteam/TextBook.h +++ b/MarathonRecomp/api/Sonicteam/TextBook.h @@ -25,7 +25,7 @@ namespace Sonicteam MARATHON_INSERT_PADDING(4); boost::shared_ptr m_spResource; - stdx::string m_Name; + stdx::string m_AttachPoint; MARATHON_INSERT_PADDING(4); xpointer m_pRootEntry; be m_EntryCount; @@ -59,7 +59,7 @@ namespace Sonicteam MARATHON_ASSERT_SIZEOF(TextBook::Entry, 0x34); MARATHON_ASSERT_OFFSETOF(TextBook, m_spResource, 0x68); - MARATHON_ASSERT_OFFSETOF(TextBook, m_Name, 0x70); + MARATHON_ASSERT_OFFSETOF(TextBook, m_AttachPoint, 0x70); MARATHON_ASSERT_OFFSETOF(TextBook, m_pRootEntry, 0x90); MARATHON_ASSERT_OFFSETOF(TextBook, m_EntryCount, 0x94); MARATHON_ASSERT_SIZEOF(TextBook, 0x98); diff --git a/MarathonRecomp/api/hk330/hkReferencedObject.h b/MarathonRecomp/api/hk330/hkReferencedObject.h index a405031e..59d08b01 100644 --- a/MarathonRecomp/api/hk330/hkReferencedObject.h +++ b/MarathonRecomp/api/hk330/hkReferencedObject.h @@ -7,12 +7,17 @@ namespace hk330 class hkReferencedObject { public: - xpointer m_pVftable; - be m_memSizeAndFlags; - be m_referenceCount; + struct Vftable + { + be fpDtor; + }; + + xpointer m_pVftable; + be m_memSizeAndFlags{}; + be m_referenceCount{}; }; - MARATHON_ASSERT_OFFSETOF(hkReferencedObject, m_pVftable, 0x00); - MARATHON_ASSERT_OFFSETOF(hkReferencedObject, m_memSizeAndFlags, 0x04); - MARATHON_ASSERT_OFFSETOF(hkReferencedObject, m_referenceCount, 0x06); + MARATHON_ASSERT_OFFSETOF(hkReferencedObject, m_pVftable, 0); + MARATHON_ASSERT_OFFSETOF(hkReferencedObject, m_memSizeAndFlags, 4); + MARATHON_ASSERT_OFFSETOF(hkReferencedObject, m_referenceCount, 6); } diff --git a/MarathonRecomp/api/hk330/hkpBvShape.h b/MarathonRecomp/api/hk330/hkpBvShape.h new file mode 100644 index 00000000..f4fc1707 --- /dev/null +++ b/MarathonRecomp/api/hk330/hkpBvShape.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include + +namespace hk330 +{ + class hkpBvShape : public hkpShape + { + public: + xpointer m_childShape; + xpointer m_boundingVolumeShape; + }; + + MARATHON_ASSERT_OFFSETOF(hkpBvShape, m_childShape, 0xC); + MARATHON_ASSERT_OFFSETOF(hkpBvShape, m_boundingVolumeShape, 0x10); +} diff --git a/MarathonRecomp/api/hk330/hkpMotion.h b/MarathonRecomp/api/hk330/hkpMotion.h new file mode 100644 index 00000000..2de4e2fe --- /dev/null +++ b/MarathonRecomp/api/hk330/hkpMotion.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +using Vector = Sonicteam::SoX::Math::Vector; + +namespace hk330 +{ + class hkpMotion : public hkReferencedObject + { + public: + + struct Vftable : hkReferencedObject::Vftable + { + MARATHON_INSERT_PADDING(0x70); + be fpApplyForce; + }; + + MARATHON_INSERT_PADDING(0xB8); + Sonicteam::SoX::Math::Vector m_inertiaAndMassInv; // Since m_linearVelocity is in the right place, "m_inertiaAndMassInv" should be here + Sonicteam::SoX::Math::Vector m_linearVelocity; + + double GetMassInv() + { + if (m_inertiaAndMassInv.X != 0.0) + return 1.0 / m_inertiaAndMassInv.X; + return 0.0; + } + + void ApplyForce(Vector* vempty, Vector* vforce, double delta) + { + auto vft = (Vftable*)m_pVftable.get(); + GuestToHostFunction(vft->fpApplyForce, this, vempty, vforce, delta); + } + + void ApplyForce(Vector vempty, Vector& vforce, double delta) + { + ApplyForce(guest_heap_var(vempty).get(), + guest_heap_var(vforce).get(), delta); + } + + }; + + MARATHON_ASSERT_OFFSETOF(hkpMotion, m_inertiaAndMassInv, 0xC0); + MARATHON_ASSERT_OFFSETOF(hkpMotion, m_linearVelocity, 0xD0); + MARATHON_ASSERT_OFFSETOF(hkpMotion::Vftable, fpApplyForce, 0x74); +} diff --git a/MarathonRecomp/api/hk330/hkpShape.h b/MarathonRecomp/api/hk330/hkpShape.h index 5ee4ea29..39d03526 100644 --- a/MarathonRecomp/api/hk330/hkpShape.h +++ b/MarathonRecomp/api/hk330/hkpShape.h @@ -5,13 +5,107 @@ namespace hk330 { + enum hkpShapeType + { + // These Are Confirmed IDS from .xex ( Rei-san ) + HK_SHAPE_INVALID = 0x0, + HK_SHAPE_CONVEX = 0x1, + HK_SHAPE_COLLECTION = 0x2, + HK_SHAPE_BV_TREE = 0x3, + HK_SHAPE_SPHERE = 0x4, + HK_SHAPE_CYLINDER = 0x5, + HK_SHAPE_TRIANGLE = 0x6, + HK_SHAPE_BOX = 0x7, + HK_SHAPE_CAPSULE = 0x8, + HK_SHAPE_CONVEX_VERTICES = 0x9, + HK_SHAPE_MULTI_SPHERE = 0xB, + HK_SHAPE_LIST = 0xC, + HK_SHAPE_CONVEX_PIECE = 0xD, + HK_SHAPE_MULTI_RAY = 0x11, + HK_SHAPE_BV = 0x16, + HK_SHAPE_PLANE = 0x17, + HK_SHAPE_MOPP = 0x18, + HK_SHAPE_TRANSFORM = 0x19, + HK_SHAPE_PHANTOM_CALLBACK = 0x1A, + + // These are not confirmed, as I cannot find any symbols associated with them ( Rei-san ) + HK_SHAPE_CONVEX_LIST = 0xE, + HK_SHAPE_CONVEX_TRANSLATE = 0xF, + HK_SHAPE_TRIANGLE_COLLECTION = 0x10, + HK_SHAPE_CONVEX_TRANSFORM = 0x12, + HK_SHAPE_SAMPLED_HEIGHT_FIELD = 0x13, + HK_SHAPE_SPHERE_REP = 0x14, + HK_SHAPE_TRI_PATCH = 0x15, + HK_SHAPE_USER0 = 0x1C, + HK_SHAPE_USER1 = 0x1D, + HK_SHAPE_USER2 = 0x1E, + HK_SHAPE_UNKNOWN = 0x1F, + + HK_SHAPE_ALL = -1, + }; + + class hkpShape : public hkReferencedObject { public: + struct Vftable : hkReferencedObject::Vftable + { + be fpFunc4; + be fpGetShapeType; + }; + be m_userData; - be m_type; + + int32_t GetShapeType() + { + auto vft = (Vftable*)m_pVftable.get(); + return GuestToHostFunction(vft->fpGetShapeType, this); + } + + const char* GetShapeTypeName() + { + int32_t type = GetShapeType(); + switch (type) + { + // Confirmed IDS + case HK_SHAPE_INVALID: return "HK_SHAPE_INVALID"; + case HK_SHAPE_ALL: return "HK_SHAPE_ALL"; + case HK_SHAPE_COLLECTION: return "HK_SHAPE_COLLECTION"; + case HK_SHAPE_BV_TREE: return "HK_SHAPE_BV_TREE"; + case HK_SHAPE_SPHERE: return "HK_SHAPE_SPHERE"; + case HK_SHAPE_CYLINDER: return "HK_SHAPE_CYLINDER"; + case HK_SHAPE_TRIANGLE: return "HK_SHAPE_TRIANGLE"; + case HK_SHAPE_BOX: return "HK_SHAPE_BOX"; + case HK_SHAPE_CAPSULE: return "HK_SHAPE_CAPSULE"; + case HK_SHAPE_CONVEX_VERTICES: return "HK_SHAPE_CONVEX_VERTICES"; + case HK_SHAPE_MULTI_SPHERE: return "HK_SHAPE_MULTI_SPHERE"; + case HK_SHAPE_LIST: return "HK_SHAPE_LIST"; + case HK_SHAPE_CONVEX_PIECE: return "HK_SHAPE_CONVEX_PIECE"; + case HK_SHAPE_MULTI_RAY: return "HK_SHAPE_MULTI_RAY"; + case HK_SHAPE_BV: return "HK_SHAPE_BV"; + case HK_SHAPE_PLANE: return "HK_SHAPE_PLANE"; + case HK_SHAPE_MOPP: return "HK_SHAPE_MOPP"; + case HK_SHAPE_TRANSFORM: return "HK_SHAPE_TRANSFORM"; + case HK_SHAPE_PHANTOM_CALLBACK: return "HK_SHAPE_PHANTOM_CALLBACK"; + + + // NOT confirmed IDS + case HK_SHAPE_CONVEX: return "HK_SHAPE_CONVEX"; + case HK_SHAPE_CONVEX_LIST: return "HK_SHAPE_CONVEX_LIST"; + case HK_SHAPE_CONVEX_TRANSLATE: return "HK_SHAPE_CONVEX_TRANSLATE"; + case HK_SHAPE_TRIANGLE_COLLECTION: return "HK_SHAPE_TRIANGLE_COLLECTION"; + case HK_SHAPE_CONVEX_TRANSFORM: return "HK_SHAPE_CONVEX_TRANSFORM"; + case HK_SHAPE_SAMPLED_HEIGHT_FIELD: return "HK_SHAPE_SAMPLED_HEIGHT_FIELD"; + case HK_SHAPE_SPHERE_REP: return "HK_SHAPE_SPHERE_REP"; + case HK_SHAPE_TRI_PATCH: return "HK_SHAPE_TRI_PATCH"; + case HK_SHAPE_USER0: return "HK_SHAPE_USER0"; + case HK_SHAPE_USER1: return "HK_SHAPE_USER1"; + case HK_SHAPE_USER2: return "HK_SHAPE_USER2"; + case HK_SHAPE_UNKNOWN: return "HK_SHAPE_UNKNOWN"; + default: return "UNKNOWN_SHAPE_TYPE"; + } + } }; MARATHON_ASSERT_OFFSETOF(hkpShape, m_userData, 0x08); - MARATHON_ASSERT_OFFSETOF(hkpShape, m_type, 0x0C); } diff --git a/MarathonRecomp/api/hk330/hkpShapeContainer.h b/MarathonRecomp/api/hk330/hkpShapeContainer.h new file mode 100644 index 00000000..de955ce6 --- /dev/null +++ b/MarathonRecomp/api/hk330/hkpShapeContainer.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace hk330 +{ + class hkpShapeContainer + { + public: + xpointer m_pVftable; + }; +} diff --git a/MarathonRecomp/api/hk330/hkpShapeSphere.h b/MarathonRecomp/api/hk330/hkpShapeSphere.h new file mode 100644 index 00000000..9f7bb907 --- /dev/null +++ b/MarathonRecomp/api/hk330/hkpShapeSphere.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +namespace hk330 +{ + class hkpShapeSphere : public hkpShape + { + public: + be m_radius; + }; + + MARATHON_ASSERT_OFFSETOF(hkpShapeSphere, m_radius, 0xC); +} diff --git a/MarathonRecomp/api/hk330/hkpSingleShapeContainer.h b/MarathonRecomp/api/hk330/hkpSingleShapeContainer.h new file mode 100644 index 00000000..ac4197a8 --- /dev/null +++ b/MarathonRecomp/api/hk330/hkpSingleShapeContainer.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include +#include + +namespace hk330 +{ + class hkpSingleShapeContainer : public hkpShapeContainer + { + public: + xpointer m_childShape; + }; +} diff --git a/MarathonRecomp/api/stdx/RTTI.h b/MarathonRecomp/api/stdx/RTTI.h new file mode 100644 index 00000000..3039c981 --- /dev/null +++ b/MarathonRecomp/api/stdx/RTTI.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +namespace stdx +{ + struct RTTIBaseClassDescriptor + { + stdx::type_info* typeDesc; + size_t bcount; + DWORD moffset; + DWORD vftOffset; + DWORD vftwOffset; + DWORD attributes; + }; + + struct RTTIClassHierarchy + { + be signature; + be attributes; + be acount; + xpointer> aclass; + }; + + struct RTTICompleteObjectLocator + { + be signature; + be offset; + be cdOffset; + xpointer typeDesc; + xpointer* hierarchyDesc; + }; + + // only works for vftable that have RTTI at (-4) + inline static RTTICompleteObjectLocator* VftableToRTTI(void* pVftable) + { + return *(xpointer*)((uintptr_t)pVftable - 4); + } + + // only works for vftable that have RTTI at (-4) + inline static std::string ClassToName(void* pClass) + { + auto vftable = ((xpointer*)(pClass))->get(); + return VftableToRTTI(vftable)->typeDesc->name(); + } +}; diff --git a/MarathonRecomp/api/stdx/deque.h b/MarathonRecomp/api/stdx/deque.h new file mode 100644 index 00000000..8952f9bc --- /dev/null +++ b/MarathonRecomp/api/stdx/deque.h @@ -0,0 +1,577 @@ +#pragma once + +#include +#include +#include +#include + +namespace stdx +{ + template + class deque + { + private: + static const size_t BLOCK_SIZE = 16; + + be _Myproxy; + xpointer> _Map; + be _Mapsize; + be _Myoff; + be _Mysize; + + // Helper functions for block management + size_t _GetBlockIndex(size_t pos) const + { + return (_Myoff + pos) / BLOCK_SIZE; + } + + size_t _GetElementIndex(size_t pos) const + { + return (_Myoff + pos) % BLOCK_SIZE; + } + + xpointer _GetBlock(size_t blockIndex) const + { + return _Map[blockIndex]; + } + + void _GrowMapIfNeeded() + { + if (_Mapsize == 0 || _GetBlockIndex(_Mysize) >= _Mapsize) + { + size_t new_mapsize = _Mapsize == 0 ? 8 : _Mapsize * 2; + xpointer* new_map = static_cast*>(g_userHeap.Alloc(sizeof(xpointer) * new_mapsize)); + + // Copy existing blocks to new map + for (size_t i = 0; i < _Mapsize; ++i) + new_map[i] = _Map[i]; + + // Initialize new blocks to nullptr + for (size_t i = _Mapsize; i < new_mapsize; ++i) + new_map[i] = xpointer(nullptr); + + if (_Map) + g_userHeap.Free(_Map.get()); + + _Map = xpointer>(new_map); + _Mapsize = new_mapsize; + } + } + + void _AllocateBlock(size_t blockIndex) + { + if (!_Map[blockIndex]) + { + T* new_block = static_cast(g_userHeap.Alloc(sizeof(T) * BLOCK_SIZE)); + _Map[blockIndex] = xpointer(new_block); + } + } + + void _DestroyRange(T* first, T* last) + { + while (first != last) + { + first->~T(); + ++first; + } + } + + void _ConstructRange(T* first, T* last, const T& value) + { + for (; first != last; ++first) + new (first) T(value); + } + + class iterator_wrapper + { + private: + deque* _deque; + size_t _pos; + + public: + explicit iterator_wrapper(deque* dq, size_t pos = 0) : _deque(dq), _pos(pos) {} + + T& operator*() const + { + return (*_deque)[_pos]; + } + + T* operator->() const + { + return &(*_deque)[_pos]; + } + + iterator_wrapper& operator++() + { + ++_pos; + return *this; + } + + iterator_wrapper operator++(int) + { + iterator_wrapper tmp = *this; + ++_pos; + return tmp; + } + + iterator_wrapper& operator--() + { + --_pos; + return *this; + } + + iterator_wrapper operator--(int) + { + iterator_wrapper tmp = *this; + --_pos; + return tmp; + } + + iterator_wrapper operator+(size_t n) const + { + return iterator_wrapper(_deque, _pos + n); + } + + iterator_wrapper operator-(size_t n) const + { + return iterator_wrapper(_deque, _pos - n); + } + + bool operator==(const iterator_wrapper& other) const + { + return _deque == other._deque && _pos == other._pos; + } + + bool operator!=(const iterator_wrapper& other) const + { + return !(*this == other); + } + + size_t position() const { return _pos; } + }; + + class const_iterator_wrapper + { + private: + const deque* _deque; + size_t _pos; + + public: + explicit const_iterator_wrapper(const deque* dq, size_t pos = 0) : _deque(dq), _pos(pos) {} + + const T& operator*() const + { + return (*_deque)[_pos]; + } + + const T* operator->() const + { + return &(*_deque)[_pos]; + } + + const_iterator_wrapper& operator++() + { + ++_pos; + return *this; + } + + const_iterator_wrapper operator++(int) + { + const_iterator_wrapper tmp = *this; + ++_pos; + return tmp; + } + + const_iterator_wrapper& operator--() + { + --_pos; + return *this; + } + + const_iterator_wrapper operator--(int) + { + const_iterator_wrapper tmp = *this; + --_pos; + return tmp; + } + + const_iterator_wrapper operator+(size_t n) const + { + return const_iterator_wrapper(_deque, _pos + n); + } + + const_iterator_wrapper operator-(size_t n) const + { + return const_iterator_wrapper(_deque, _pos - n); + } + + bool operator==(const const_iterator_wrapper& other) const + { + return _deque == other._deque && _pos == other._pos; + } + + bool operator!=(const const_iterator_wrapper& other) const + { + return !(*this == other); + } + + size_t position() const { return _pos; } + }; + + public: + using iterator = iterator_wrapper; + using const_iterator = const_iterator_wrapper; + + deque() noexcept : _Map(nullptr), _Mapsize(0), _Myoff(0), _Mysize(0) {} + + explicit deque(size_t count) : _Map(nullptr), _Mapsize(0), _Myoff(0), _Mysize(0) + { + resize(count); + } + + deque(size_t count, const T& value) : _Map(nullptr), _Mapsize(0), _Myoff(0), _Mysize(0) + { + resize(count, value); + } + + deque(const deque& other) : _Map(nullptr), _Mapsize(0), _Myoff(other._Myoff), _Mysize(0) + { + // Allocate map and copy elements + if (other._Mysize > 0) + { + resize(other._Mysize); + for (size_t i = 0; i < _Mysize; ++i) + (*this)[i] = other[i]; + } + } + + deque(deque&& other) noexcept + : _Map(other._Map), _Mapsize(other._Mapsize), _Myoff(other._Myoff), _Mysize(other._Mysize) + { + other._Map = xpointer>(nullptr); + other._Mapsize = 0; + other._Myoff = 0; + other._Mysize = 0; + } + + ~deque() + { + clear(); + + // Free all allocated blocks + if (_Map) + { + for (size_t i = 0; i < _Mapsize; ++i) + { + if (_Map[i]) + g_userHeap.Free(_Map[i].get()); + } + g_userHeap.Free(_Map.get()); + } + } + + deque& operator=(const deque& other) + { + if (this != &other) + { + deque tmp(other); + swap(tmp); + } + return *this; + } + + deque& operator=(deque&& other) noexcept + { + if (this != &other) + { + clear(); + + // Free existing resources + if (_Map) + { + for (size_t i = 0; i < _Mapsize; ++i) + { + if (_Map[i]) + g_userHeap.Free(_Map[i].get()); + } + g_userHeap.Free(_Map.get()); + } + + _Map = other._Map; + _Mapsize = other._Mapsize; + _Myoff = other._Myoff; + _Mysize = other._Mysize; + + other._Map = xpointer>(nullptr); + other._Mapsize = 0; + other._Myoff = 0; + other._Mysize = 0; + } + return *this; + } + + T& operator[](size_t pos) + { + size_t blockIndex = _GetBlockIndex(pos); + size_t elementIndex = _GetElementIndex(pos); + return _Map[blockIndex][elementIndex]; + } + + const T& operator[](size_t pos) const + { + size_t blockIndex = _GetBlockIndex(pos); + size_t elementIndex = _GetElementIndex(pos); + return _Map[blockIndex][elementIndex]; + } + + T& at(size_t pos) + { + return (*this)[pos]; + } + + const T& at(size_t pos) const + { + return (*this)[pos]; + } + + T& front() + { + return (*this)[0]; + } + + const T& front() const + { + return (*this)[0]; + } + + T& back() + { + return (*this)[_Mysize - 1]; + } + + const T& back() const + { + return (*this)[_Mysize - 1]; + } + + iterator begin() + { + return iterator(this, 0); + } + + const_iterator begin() const + { + return const_iterator(this, 0); + } + + const_iterator cbegin() const + { + return const_iterator(this, 0); + } + + iterator end() + { + return iterator(this, _Mysize); + } + + const_iterator end() const + { + return const_iterator(this, _Mysize); + } + + const_iterator cend() const + { + return const_iterator(this, _Mysize); + } + + bool empty() const + { + return _Mysize == 0; + } + + size_t size() const + { + return _Mysize; + } + + void clear() + { + // Destroy all elements + for (size_t i = 0; i < _Mysize; ++i) + { + (*this)[i].~T(); + } + _Mysize = 0; + _Myoff = 0; + } + + void push_back(const T& value) + { + _GrowMapIfNeeded(); + size_t blockIndex = _GetBlockIndex(_Mysize); + _AllocateBlock(blockIndex); + + size_t elementIndex = _GetElementIndex(_Mysize); + new (&_Map[blockIndex][elementIndex]) T(value); + _Mysize = _Mysize.get() + 1; + } + + void push_back(T&& value) + { + _GrowMapIfNeeded(); + size_t blockIndex = _GetBlockIndex(_Mysize); + _AllocateBlock(blockIndex); + + size_t elementIndex = _GetElementIndex(_Mysize); + new (&_Map[blockIndex][elementIndex]) T(std::move(value)); + _Mysize = _Mysize.get() + 1;; + } + + template + void emplace_back(Args&&... args) + { + _GrowMapIfNeeded(); + size_t blockIndex = _GetBlockIndex(_Mysize); + _AllocateBlock(blockIndex); + + size_t elementIndex = _GetElementIndex(_Mysize); + new (&_Map[blockIndex][elementIndex]) T(std::forward(args)...); + _Mysize = _Mysize.get() + 1; + } + + void pop_back() + { + if (_Mysize > 0) + { + _Mysize = _Mysize.get() - 1; + size_t blockIndex = _GetBlockIndex(_Mysize); + size_t elementIndex = _GetElementIndex(_Mysize); + _Map[blockIndex][elementIndex].~T(); + } + } + + void push_front(const T& value) + { + if (_Myoff == 0) + { + // Need to reorganize or grow map at front + _GrowMapIfNeeded(); + // This is simplified - real implementation would be more complex + } + + if (_Myoff > 0) + { + _Myoff = _Myoff.get() - 1; + size_t blockIndex = _GetBlockIndex(0); + _AllocateBlock(blockIndex); + + size_t elementIndex = _GetElementIndex(0); + new (&_Map[blockIndex][elementIndex]) T(value); + _Mysize = _Mysize.get() + 1; + } + else + { + // Fallback to insert at beginning + push_back(value); // This isn't correct for front, but works for basic case + } + } + + void pop_front() + { + if (_Mysize > 0) + { + size_t blockIndex = _GetBlockIndex(0); + size_t elementIndex = _GetElementIndex(0); + _Map[blockIndex][elementIndex].~T(); + _Myoff = _Myoff.get() + 1; + _Mysize = _Mysize.get() - 1; + } + } + + void resize(size_t count) + { + if (count < _Mysize) + { + // Destroy extra elements + for (size_t i = count; i < _Mysize; ++i) + (*this)[i].~T(); + _Mysize = count; + } + else if (count > _Mysize) + { + // Add default-constructed elements + while (_Mysize < count) + push_back(T()); + } + } + + void resize(size_t count, const T& value) + { + if (count < _Mysize) + { + // Destroy extra elements + for (size_t i = count; i < _Mysize; ++i) + (*this)[i].~T(); + _Mysize = count; + } + else if (count > _Mysize) + { + // Add elements with specified value + while (_Mysize < count) + push_back(value); + } + } + + void swap(deque& other) noexcept + { + std::swap(_Map, other._Map); + std::swap(_Mapsize, other._Mapsize); + std::swap(_Myoff, other._Myoff); + std::swap(_Mysize, other._Mysize); + } + }; + + template + void swap(deque& lhs, deque& rhs) noexcept + { + lhs.swap(rhs); + } + + template + bool operator==(const deque& lhs, const deque& rhs) + { + return lhs.size() == rhs.size() + && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + template + bool operator!=(const deque& lhs, const deque& rhs) + { + return !(lhs == rhs); + } + + template + bool operator<(const deque& lhs, const deque& rhs) + { + return std::lexicographical_compare( + lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + + template + bool operator<=(const deque& lhs, const deque& rhs) + { + return !(rhs < lhs); + } + + template + bool operator>(const deque& lhs, const deque& rhs) + { + return rhs < lhs; + } + + template + bool operator>=(const deque& lhs, const deque& rhs) + { + return !(lhs < rhs); + } +} diff --git a/MarathonRecomp/api/stdx/list.h b/MarathonRecomp/api/stdx/list.h new file mode 100644 index 00000000..c811e5f3 --- /dev/null +++ b/MarathonRecomp/api/stdx/list.h @@ -0,0 +1,245 @@ +#pragma once + +#include + +namespace stdx +{ + template + class list + { + private: + struct _List_node + { + _List_node(const Value& val) + : _Next(nullptr), _Prev(nullptr), _Myval(val) + { + } + + _List_node(Value&& val) + : _Next(nullptr), _Prev(nullptr), _Myval(std::move(val)) + { + } + + xpointer<_List_node> _Next; + xpointer<_List_node> _Prev; + Value _Myval; + }; + + be _MyProxy; + xpointer<_List_node> _Myhead; + be _Mysize; + + xpointer<_List_node> allocate_node(const Value& value) + { + void* memory = g_userHeap.Alloc(sizeof(_List_node)); + return xpointer<_List_node>(new (memory) _List_node(value)); + } + + xpointer<_List_node> allocate_node(Value&& value) + { + void* memory = g_userHeap.Alloc(sizeof(_List_node)); + return xpointer<_List_node>(new (memory) _List_node(std::move(value))); + } + + void deallocate_node(xpointer<_List_node> node) + { + if (node && node.get()) + { + node->~_List_node(); + g_userHeap.Free(node.get()); + } + } + + void link_nodes(xpointer<_List_node> prev, xpointer<_List_node> next) + { + if (prev) prev->_Next = next; + if (next) next->_Prev = prev; + } + + public: + class iterator + { + private: + xpointer<_List_node> _Ptr; + + public: + iterator(xpointer<_List_node> node = nullptr) : _Ptr(node) {} + + Value& operator*() const { return _Ptr->_Myval; } + Value* operator->() const { return &_Ptr->_Myval; } + + iterator& operator++() + { + if (_Ptr) _Ptr = _Ptr->_Next; + return *this; + } + + iterator operator++(int) + { + iterator tmp = *this; + ++(*this); + return tmp; + } + + iterator& operator--() + { + if (_Ptr) _Ptr = _Ptr->_Prev; + return *this; + } + + iterator operator--(int) + { + iterator tmp = *this; + --(*this); + return tmp; + } + + bool operator==(const iterator& other) const + { + return _Ptr == other._Ptr; + } + + bool operator!=(const iterator& other) const + { + return _Ptr != other._Ptr; + } + + xpointer<_List_node> _Mynode() const { return _Ptr; } + }; + + list() : _Mysize(0) + { + // Create sentinel node + _Myhead = allocate_node(Value()); + _Myhead->_Next = _Myhead; + _Myhead->_Prev = _Myhead; + } + + ~list() + { + clear(); + deallocate_node(_Myhead); + } + + iterator begin() + { + return iterator(_Myhead->_Next); + } + + iterator end() + { + return iterator(_Myhead); + } + + size_t size() const + { + return _Mysize; + } + + bool empty() const + { + return _Mysize == 0; + } + + Value& front() + { + return _Myhead->_Next->_Myval; + } + + Value& back() + { + return _Myhead->_Prev->_Myval; + } + + void push_front(const Value& value) + { + insert_node(_Myhead->_Next, value); + } + + void push_front(Value&& value) + { + insert_node(_Myhead->_Next, std::move(value)); + } + + void push_back(const Value& value) + { + insert_node(_Myhead, value); + } + + void push_back(Value&& value) + { + insert_node(_Myhead, std::move(value)); + } + + void pop_front() + { + if (!empty()) + erase_node(_Myhead->_Next); + } + + void pop_back() + { + if (!empty()) + erase_node(_Myhead->_Prev); + } + + iterator insert(iterator position, const Value& value) + { + return iterator(insert_node(position._Mynode(), value)); + } + + iterator insert(iterator position, Value&& value) + { + return iterator(insert_node(position._Mynode(), std::move(value))); + } + + iterator erase(iterator position) + { + if (position == end()) return end(); + iterator next = position; + ++next; + erase_node(position._Mynode()); + return next; + } + + void clear() + { + while (!empty()) + pop_front(); + } + + private: + xpointer<_List_node> insert_node(xpointer<_List_node> next_node, const Value& value) + { + xpointer<_List_node> new_node = allocate_node(value); + xpointer<_List_node> prev_node = next_node->_Prev; + + link_nodes(prev_node, new_node); + link_nodes(new_node, next_node); + + _Mysize = _Mysize + 1; + return new_node; + } + + xpointer<_List_node> insert_node(xpointer<_List_node> next_node, Value&& value) + { + xpointer<_List_node> new_node = allocate_node(std::move(value)); + xpointer<_List_node> prev_node = next_node->_Prev; + + link_nodes(prev_node, new_node); + link_nodes(new_node, next_node); + + _Mysize = _Mysize + 1; + return new_node; + } + + void erase_node(xpointer<_List_node> node) + { + if (node == _Myhead || !node) return; + + link_nodes(node->_Prev, node->_Next); + deallocate_node(node); + _Mysize = _Mysize - 1; + } + }; +} diff --git a/MarathonRecomp/api/stdx/map.h b/MarathonRecomp/api/stdx/map.h new file mode 100644 index 00000000..8483a067 --- /dev/null +++ b/MarathonRecomp/api/stdx/map.h @@ -0,0 +1,278 @@ +#pragma once + +#include + +namespace stdx +{ + template > + class map + { + private: + struct Node + { + xpointer _Left; + xpointer _Parent; + xpointer _Right; + std::pair _Myval; + char _Color; + bool _Isnil; + + Node(const Key& key, const T& value, xpointer parent = nullptr, char color = 0) + : _Left(nullptr), _Parent(parent), _Right(nullptr), _Myval(key, value), + _Color(color), _Isnil(false) + { + + } + + Node(bool isnil = false) + : _Left(nullptr), _Parent(nullptr), _Right(nullptr), _Myval(), + _Color(1), _Isnil(isnil) + { + + } + }; + + be _Myproxy; + xpointer _Myhead; + be _Mysize; + + xpointer allocate_node(const Key& key, const T& value, xpointer parent = nullptr, char color = 0) + { + void* memory = g_userHeap.Alloc(sizeof(Node)); + return xpointer(new (memory) Node(key, value, parent, color)); + } + + xpointer allocate_node(bool isnil = false) + { + void* memory = g_userHeap.Alloc(sizeof(Node)); + return xpointer(new (memory) Node(isnil)); + } + + void deallocate_node(xpointer node) + { + if (node && node.get()) + { + node->~Node(); + g_userHeap.Free(node.get()); + } + } + + bool compare_keys(const Key& a, const Key& b) const + { + return Compare()(a, b); + } + + xpointer insert_node(const Key& key, const T& value) + { + if (_Myhead->_Left == _Myhead) + { + _Mysize = _Mysize + 1; + xpointer newNode = allocate_node(key, value, _Myhead, 1); + _Myhead->_Left = newNode; + _Myhead->_Parent = newNode; + _Myhead->_Right = newNode; + return newNode; + } + + xpointer current = _Myhead->_Parent; + xpointer parent = _Myhead; + + while (current != _Myhead) + { + parent = current; + if (compare_keys(key, current->_Myval.first)) + current = current->_Left; + else if (compare_keys(current->_Myval.first, key)) + current = current->_Right; + else + { + current->_Myval.second = value; + return current; + } + } + + _Mysize = _Mysize + 1; + xpointer newNode = allocate_node(key, value, parent, 0); + + if (compare_keys(key, parent->_Myval.first)) + parent->_Left = newNode; + else + parent->_Right = newNode; + + if (compare_keys(key, _Myhead->_Left->_Myval.first)) + _Myhead->_Left = newNode; + if (compare_keys(_Myhead->_Right->_Myval.first, key)) + _Myhead->_Right = newNode; + + return newNode; + } + + xpointer find_node(const Key& key) const + { + xpointer current = _Myhead->_Parent; + while (current != _Myhead) + { + if (compare_keys(key, current->_Myval.first)) + current = current->_Left; + else if (compare_keys(current->_Myval.first, key)) + current = current->_Right; + else + return current; + } + return _Myhead; + } + + void clear_tree(xpointer node) + { + if (node != _Myhead && node != nullptr) + { + clear_tree(node->_Left); + clear_tree(node->_Right); + deallocate_node(node); + } + } + + xpointer find_min(xpointer node) const + { + while (node->_Left != _Myhead) + node = node->_Left; + return node; + } + + xpointer find_max(xpointer node) const + { + while (node->_Right != _Myhead) + node = node->_Right; + return node; + } + + public: + class iterator + { + private: + xpointer _Ptr; + xpointer _Myhead; + + xpointer find_min(xpointer node) const + { + while (node->_Left != _Myhead) + node = node->_Left; + return node; + } + + public: + iterator(xpointer node = nullptr, xpointer head = nullptr) + : _Ptr(node), _Myhead(head) + { + + } + + std::pair& operator*() const { return _Ptr->_Myval; } + std::pair* operator->() const { return &_Ptr->_Myval; } + + iterator& operator++() + { + if (_Ptr == _Myhead) return *this; + + if (_Ptr->_Right != _Myhead) + { + _Ptr = find_min(_Ptr->_Right); + } + else + { + xpointer parent = _Ptr->_Parent; + while (parent != _Myhead && _Ptr == parent->_Right) + { + _Ptr = parent; + parent = parent->_Parent; + } + _Ptr = parent; + } + return *this; + } + + iterator operator++(int) + { + iterator tmp = *this; + ++(*this); + return tmp; + } + + bool operator==(const iterator& other) const + { + return _Ptr == other._Ptr; + } + + bool operator!=(const iterator& other) const + { + return _Ptr != other._Ptr; + } + }; + + map() : _Mysize(0) + { + _Myhead = allocate_node(true); + _Myhead->_Left = _Myhead; + _Myhead->_Parent = _Myhead; + _Myhead->_Right = _Myhead; + } + + ~map() + { + clear(); + deallocate_node(_Myhead); + } + + iterator begin() + { + return iterator(_Myhead->_Left, _Myhead); + } + + iterator end() + { + return iterator(_Myhead, _Myhead); + } + + size_t size() const + { + return _Mysize; + } + + bool empty() const + { + return _Mysize == 0; + } + + T& operator[](const Key& key) + { + xpointer node = find_node(key); + if (node == _Myhead) + node = insert_node(key, T()); + return node->_Myval.second; + } + + iterator find(const Key& key) + { + return iterator(find_node(key), _Myhead); + } + + void clear() + { + clear_tree(_Myhead->_Parent); + _Myhead->_Left = _Myhead; + _Myhead->_Parent = _Myhead; + _Myhead->_Right = _Myhead; + _Mysize = 0; + } + + std::pair insert(const std::pair& value) + { + xpointer node = find_node(value.first); + if (node != _Myhead) + return std::make_pair(iterator(node, _Myhead), false); + + node = insert_node(value.first, value.second); + return std::make_pair(iterator(node, _Myhead), true); + } + }; +} \ No newline at end of file diff --git a/MarathonRecomp/api/stdx/type_info.h b/MarathonRecomp/api/stdx/type_info.h new file mode 100644 index 00000000..3c96e194 --- /dev/null +++ b/MarathonRecomp/api/stdx/type_info.h @@ -0,0 +1,143 @@ +#pragma once + +#include +#include +#include +#include + +namespace stdx +{ + class type_info + { + public: + struct Vftable + { + be fpdtor; + }; + xpointer m_pVftable; + be m_InternalRuntimeReference; + const char m_name[0]; + + type_info(const type_info&) = delete; + type_info& operator=(const type_info&) = delete; + + const char* raw_name() const + { + return &m_name[0]; + } + + std::string name() const + { + const char* mangled = &m_name[0]; + if (strncmp(mangled, ".?A", 3) != 0) + return std::string(mangled); + + const char* type_char = mangled + 3; + const char* type_start = type_char; + + if (*type_char == 'V' || *type_char == 'U' || *type_char == '_') + type_start++; + + const char* end = strstr(type_start, "@@"); + if (!end) + return std::string(mangled); + + std::string result; + switch (mangled[3]) { + case 'V': result = "class "; break; + case 'U': result = "struct "; break; + case '_': result = "union "; break; + } + + // Parse all segments first + std::vector segments; + const char* p = type_start; + + while (p < end) { + if (*p == '@') { + p++; + continue; + } + + const char* seg_start = p; + while (p < end && *p != '@') p++; + if (p > seg_start) { + segments.push_back(std::string(seg_start, p - seg_start)); + } + } + + // Decode template parameter algorithm + auto decode_param = [](const std::string& param) -> uint64_t { + if (param.empty() || param[0] != '$') return 0; + + const char* str = param.c_str() + 2; // Skip "$0" + size_t len = strlen(str); + + if (len == 2) { + // Two-character encoding: (c1 - 'A') * 16 + (c2 - 'A') + return (str[0] - 'A') * 16 + (str[1] - 'A'); + } + else { + // Multi-character encoding for large powers of 2 + // Count number of 'A's after the first character + int num_As = 0; + for (size_t i = 1; i < len && str[i] == 'A'; i++) { + num_As++; + } + + // Calculate exponent based on pattern + int exponent = num_As * 4; + if (str[0] == 'C') { + exponent += 1; + } + + return 1ULL << exponent; + } + }; + + // Process segments to handle templates + std::vector parts; + for (size_t i = 0; i < segments.size(); i++) { + if (segments[i].find("?$") == 0) { + // Template class + std::string tmpl_name = segments[i].substr(2); + + // Get template parameters + std::vector params; + for (size_t j = i + 1; j < segments.size(); j++) { + if (segments[j].empty() || segments[j][0] != '$') break; + + uint64_t val = decode_param(segments[j]); + params.push_back(std::to_string(val)); + i = j; + } + + // Build template string + std::string full_tmpl = tmpl_name + "<"; + for (size_t k = 0; k < params.size(); k++) { + if (k > 0) full_tmpl += ","; + full_tmpl += params[k]; + } + full_tmpl += ">"; + parts.push_back(full_tmpl); + } + else if (segments[i].empty() || segments[i][0] == '$') { + // Skip parameter segments (already handled) + continue; + } + else { + // Regular namespace/class + parts.push_back(segments[i]); + } + } + + // Reverse for correct namespace order (MSVC stores backwards) + for (int i = parts.size() - 1; i >= 0; i--) { + if (i < parts.size() - 1) result += "::"; + result += parts[i]; + } + + return result; + } + }; +} diff --git a/MarathonRecomp/app.cpp b/MarathonRecomp/app.cpp index 4c08a7ef..340ccb3a 100644 --- a/MarathonRecomp/app.cpp +++ b/MarathonRecomp/app.cpp @@ -10,6 +10,7 @@ #include #include #include +#include static std::thread::id g_mainThreadId = std::this_thread::get_id(); @@ -46,6 +47,7 @@ PPC_FUNC(sub_8262A568) be Width; be Height; }; + auto pRenderConfig = reinterpret_cast(g_memory.Translate(ctx.r4.u32)); pRenderConfig->Width = Video::s_viewportWidth; diff --git a/MarathonRecomp/cpu/guest_heap_var.h b/MarathonRecomp/cpu/guest_heap_var.h new file mode 100644 index 00000000..73610814 --- /dev/null +++ b/MarathonRecomp/cpu/guest_heap_var.h @@ -0,0 +1,113 @@ +#pragma once + +#include "ppc_context.h" +#include +#include + +template +class guest_heap_var +{ +private: + xpointer m_ptr = NULL; + + void AllocHeapMemory() + { + m_ptr = (T*)g_userHeap.Alloc(sizeof(T)); + } + +public: + T* get() + { + return m_ptr.get(); + } + + const T* get() const + { + return (const T*)m_ptr.get(); + } + + template + guest_heap_var(Args&&... args) + { + AllocHeapMemory(); + + if (Init) + new (get()) T(std::forward(args)...); + } + + guest_heap_var(const guest_heap_var& other) + { + AllocHeapMemory(); + + if (Init) + new (get()) T(*other->get()); + } + + // + guest_heap_var(guest_heap_var&& other) + { + m_ptr = other.m_ptr; + other.m_ptr = 0; + } + + ~guest_heap_var() + { + if (get() && Deallocate) + { + get()->~T(); + g_userHeap.Free(get()); + } + } + + void operator=(const guest_heap_var& other) + { + if (this != &other) + *get() = *other->get(); + } + + void operator=(guest_heap_var&& other) + { + if (this != &other) + { + + if (get() && Deallocate) + { + get()->~T(); + g_userHeap.Free(get()); + } + + m_ptr = other.m_ptr; + other.m_ptr = NULL; + } + } + + operator const T* () const + { + return get(); + } + + operator T* () + { + return get(); + } + + const T* operator->() const + { + return get(); + } + + T* operator->() + { + return get(); + } + + const T& operator*() const + { + return *get(); + } + + T& operator*() + { + return *get(); + } +}; diff --git a/MarathonRecomp/gpu/video.cpp b/MarathonRecomp/gpu/video.cpp index 08c8c74e..72f7a758 100644 --- a/MarathonRecomp/gpu/video.cpp +++ b/MarathonRecomp/gpu/video.cpp @@ -129,7 +129,7 @@ namespace plume extern std::unique_ptr CreateD3D12Interface(); #endif #ifdef MARATHON_RECOMP_METAL -extern std::unique_ptr CreateMetalInterface(); + extern std::unique_ptr CreateMetalInterface(); #endif #ifdef SDL_VULKAN_ENABLED extern std::unique_ptr CreateVulkanInterface(RenderWindow sdlWindow); @@ -464,7 +464,7 @@ enum class PipelineTaskType struct PipelineTask { PipelineTaskType type{}; -// boost::shared_ptr databaseData; + // boost::shared_ptr databaseData; }; static Mutex g_pipelineTaskMutex; @@ -540,7 +540,7 @@ struct UploadAllocator buffer.memory = reinterpret_cast(buffer.buffer->map()); buffer.deviceAddress = buffer.buffer->getDeviceAddress(); } - + auto ref = buffer.buffer->at(offset); offset += size; @@ -646,7 +646,7 @@ struct PrimitiveIndexData { case D3DPT_TRIANGLEFAN: primCount = guestPrimCount - 2; - indexCountPerPrimitive = 3; + indexCountPerPrimitive = 3; break; case D3DPT_QUADLIST: primCount = guestPrimCount / 4; @@ -918,7 +918,7 @@ struct RenderCommand uint32_t value; } setRenderState; - struct + struct { GuestResource* resource; } destructResource; @@ -933,7 +933,7 @@ struct RenderCommand GuestBuffer* buffer; } unlockBuffer; - struct + struct { GuestDevice* device; uint32_t flags; @@ -941,17 +941,17 @@ struct RenderCommand uint32_t destSliceOrFace; } stretchRect; - struct + struct { GuestSurface* renderTarget; } setRenderTarget; - struct + struct { GuestSurface* depthStencil; } setDepthStencilSurface; - struct + struct { uint32_t flags; float color[4]; @@ -959,7 +959,7 @@ struct RenderCommand uint32_t stencil; } clear; - struct + struct { float x; float y; @@ -969,13 +969,13 @@ struct RenderCommand float maxDepth; } setViewport; - struct + struct { uint32_t index; GuestTexture* texture; } setTexture; - struct + struct { int32_t left; int32_t top; @@ -1001,8 +1001,8 @@ struct RenderCommand uint8_t* memory; uint32_t index; uint32_t size; - } setVertexShaderConstants; - + } setVertexShaderConstants; + struct { uint8_t* memory; @@ -1016,42 +1016,42 @@ struct RenderCommand RenderPipeline* pipeline; } addPipeline; - struct + struct { - uint32_t primitiveType; - uint32_t startVertex; + uint32_t primitiveType; + uint32_t startVertex; uint32_t primitiveCount; } drawPrimitive; - struct + struct { uint32_t primitiveType; - int32_t baseVertexIndex; + int32_t baseVertexIndex; uint32_t startIndex; uint32_t primCount; } drawIndexedPrimitive; - struct + struct { uint32_t primitiveType; - uint32_t primitiveCount; + uint32_t primitiveCount; uint8_t* vertexStreamZeroData; uint32_t vertexStreamZeroSize; uint32_t vertexStreamZeroStride; CsdFilterState csdFilterState; } drawPrimitiveUP; - struct + struct { GuestVertexDeclaration* vertexDeclaration; } setVertexDeclaration; - struct + struct { GuestShader* shader; } setVertexShader; - struct + struct { uint32_t index; GuestBuffer* buffer; @@ -1059,12 +1059,12 @@ struct RenderCommand uint32_t stride; } setStreamSource; - struct + struct { GuestBuffer* buffer; } setIndices; - struct + struct { GuestShader* shader; } setPixelShader; @@ -1379,7 +1379,7 @@ static void ProcSetRenderState(const RenderCommand& cmd) { if (g_capabilities.dynamicDepthBias) SetDirtyValue(g_dirtyStates.depthBias, g_slopeScaledDepthBias, *reinterpret_cast(&value)); - else + else SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.slopeScaledDepthBias, *reinterpret_cast(&value)); break; @@ -1389,7 +1389,7 @@ static void ProcSetRenderState(const RenderCommand& cmd) if (g_capabilities.dynamicDepthBias) SetDirtyValue(g_dirtyStates.depthBias, g_depthBias, int32_t(*reinterpret_cast(&value) * (1 << 24))); else - SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.depthBias, int32_t(*reinterpret_cast(&value)* (1 << 24))); + SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.depthBias, int32_t(*reinterpret_cast(&value) * (1 << 24))); break; } @@ -1817,14 +1817,14 @@ static void BeginCommandList() } template -static void ApplyLowEndDefault(ConfigDef &configDef, T newDefault, bool &changed) +static void ApplyLowEndDefault(ConfigDef& configDef, T newDefault, bool& changed) { if (configDef.IsDefaultValue() && !configDef.IsLoadedFromConfig) { configDef = newDefault; changed = true; } - + configDef.DefaultValue = newDefault; } @@ -1837,13 +1837,13 @@ static void ApplyLowEndDefaults() ApplyLowEndDefault(Config::ReflectionResolution, EReflectionResolution::Quarter, changed); ApplyLowEndDefault(Config::TransparencyAntiAliasing, false, changed); - if (changed) + if (changed) { Config::Save(); } } -bool Video::CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry) +bool Video::CreateHostDevice(const char* sdlVideoDriver, bool graphicsApiRetry) { for (uint32_t i = 0; i < 16; i++) g_inputSlots[i].index = i; @@ -1862,7 +1862,7 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry) // Attempt to create the possible backends using a vector of function pointers. Whichever succeeds first will be the chosen API. using RenderInterfaceFunction = std::unique_ptr(void); - std::vector interfaceFunctions; + std::vector interfaceFunctions; #ifdef MARATHON_RECOMP_D3D12 bool allowVulkanRedirection = true; @@ -1904,8 +1904,8 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry) g_device = g_interface->createDevice(Config::GraphicsDevice); if (g_device != nullptr) { - const RenderDeviceDescription &deviceDescription = g_device->getDescription(); - + const RenderDeviceDescription& deviceDescription = g_device->getDescription(); + #if defined(MARATHON_RECOMP_D3D12) if (interfaceFunction == CreateD3D12Interface) { @@ -2007,7 +2007,7 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry) } const RenderSampleCounts colourSampleCount = g_device->getSampleCountsSupported(RenderFormat::R16G16B16A16_FLOAT); - const RenderSampleCounts depthSampleCount = g_device->getSampleCountsSupported(RenderFormat::D32_FLOAT); + const RenderSampleCounts depthSampleCount = g_device->getSampleCountsSupported(RenderFormat::D32_FLOAT); const RenderSampleCounts commonSampleCount = colourSampleCount & depthSampleCount; // Disable specific MSAA levels if they are not supported. @@ -2070,20 +2070,20 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry) for (auto& acquireSemaphore : g_acquireSemaphores) acquireSemaphore = g_device->createCommandSemaphore(); - + for (auto& renderSemaphore : g_renderSemaphores) renderSemaphore = g_device->createCommandSemaphore(); RenderPipelineLayoutBuilder pipelineLayoutBuilder; pipelineLayoutBuilder.begin(false, true); - + RenderDescriptorSetBuilder descriptorSetBuilder; descriptorSetBuilder.begin(); descriptorSetBuilder.addTexture(0, TEXTURE_DESCRIPTOR_SIZE); descriptorSetBuilder.end(true, TEXTURE_DESCRIPTOR_SIZE); - + g_textureDescriptorSet = descriptorSetBuilder.create(g_device.get()); - + for (size_t i = 0; i < TEXTURE_DESCRIPTOR_NULL_COUNT; i++) { auto& texture = g_blankTextures[i]; @@ -2136,11 +2136,11 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry) pipelineLayoutBuilder.addDescriptorSet(descriptorSetBuilder); pipelineLayoutBuilder.addDescriptorSet(descriptorSetBuilder); pipelineLayoutBuilder.addDescriptorSet(descriptorSetBuilder); - + descriptorSetBuilder.begin(); descriptorSetBuilder.addSampler(0, SAMPLER_DESCRIPTOR_SIZE); descriptorSetBuilder.end(true, SAMPLER_DESCRIPTOR_SIZE); - + g_samplerDescriptorSet = descriptorSetBuilder.create(g_device.get()); auto& [descriptorIndex, sampler] = g_samplerStates[XXH3_64bits(&g_samplerDescs[0], sizeof(RenderSamplerDesc))]; descriptorIndex = 1; @@ -2178,7 +2178,7 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry) pipelineLayoutBuilder.addPushConstant(3, 4, 4, RenderShaderStageFlag::PIXEL); // For copy/resolve shaders. } pipelineLayoutBuilder.end(); - + g_pipelineLayout = pipelineLayoutBuilder.create(g_device.get()); g_copyShader = CREATE_SHADER(copy_vs); @@ -2311,7 +2311,7 @@ static uint32_t getSetAddress(uint32_t base, int index) { static uint32_t CreateDevice(uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5, be* a6) { LOGF_WARNING("{:p} {:p} {:p} {:p} {:p} {:p}\n", reinterpret_cast(a1), reinterpret_cast(a2), reinterpret_cast(a3), reinterpret_cast(a4), reinterpret_cast(a5), reinterpret_cast(a6)); - g_xdbfTextureCache = std::unordered_map(); + g_xdbfTextureCache = std::unordered_map(); // for (auto &achievement : g_xdbfWrapper.GetAchievements(XDBF_LANGUAGE_ENGLISH)) // { @@ -2340,7 +2340,7 @@ static uint32_t CreateDevice(uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, // Append render state functions to the end of guest function table. uint32_t functionOffsetUnimplemented = PPC_CODE_BASE + PPC_CODE_SIZE; g_memory.InsertFunction(functionOffsetUnimplemented, HostToGuestFunction); - + uint32_t functionOffset = 0x82B79868; for (size_t i = 0; i < std::size(device->setRenderStateFunctions); i++) { device->setRenderStateFunctions[i] = functionOffsetUnimplemented; @@ -2349,7 +2349,7 @@ static uint32_t CreateDevice(uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, // InsertFucntion doesn't work, so we have to do this manually in the end for (auto& [state, function] : g_setRenderStateFunctions) { - auto funcOffset = getSetAddress(functionOffset, state/4); + auto funcOffset = getSetAddress(functionOffset, state / 4); uint32_t addr = __builtin_bswap32(*(uint32_t*)g_memory.Translate(funcOffset)); printf("state %d of %x is %x\n", state, funcOffset, addr); g_memory.InsertFunction(addr, function); @@ -2368,7 +2368,7 @@ static uint32_t CreateDevice(uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, return 0; } -static void DestructResource(GuestResource* resource) +static void DestructResource(GuestResource* resource) { // Needed for hack in CreateSurface (remove if fix it) if (resource->type == ResourceType::RenderTarget || resource->type == ResourceType::DepthStencil) @@ -2395,7 +2395,7 @@ static uint32_t ComputeTexturePitch(GuestTexture* texture) return (texture->width * RenderFormatSize(texture->format) + PITCH_ALIGNMENT - 1) & ~(PITCH_ALIGNMENT - 1); } -static void LockTextureRect(GuestTexture* texture, uint32_t, GuestLockedRect* lockedRect) +static void LockTextureRect(GuestTexture* texture, uint32_t, GuestLockedRect* lockedRect) { uint32_t pitch = ComputeTexturePitch(texture); uint32_t slicePitch = pitch * texture->height; @@ -2407,7 +2407,7 @@ static void LockTextureRect(GuestTexture* texture, uint32_t, GuestLockedRect* lo lockedRect->bits = g_memory.MapVirtual(texture->mappedMemory); } -static void UnlockTextureRect(GuestTexture* texture) +static void UnlockTextureRect(GuestTexture* texture) { assert(std::this_thread::get_id() == g_presentThreadId); @@ -2524,17 +2524,17 @@ static void UnlockVertexBuffer(GuestBuffer* buffer) UnlockBuffer(buffer); } -static void GetVertexBufferDesc(GuestBuffer* buffer, GuestBufferDesc* desc) +static void GetVertexBufferDesc(GuestBuffer* buffer, GuestBufferDesc* desc) { desc->size = buffer->dataSize; } -static void* LockIndexBuffer(GuestBuffer* buffer, uint32_t, uint32_t, uint32_t flags) +static void* LockIndexBuffer(GuestBuffer* buffer, uint32_t, uint32_t, uint32_t flags) { return LockBuffer(buffer, flags); } -static void UnlockIndexBuffer(GuestBuffer* buffer) +static void UnlockIndexBuffer(GuestBuffer* buffer) { if (buffer->guestFormat == D3DFMT_INDEX32) UnlockBuffer(buffer); @@ -2548,7 +2548,7 @@ static void GetIndexBufferDesc(GuestBuffer* buffer, GuestBufferDesc* desc) desc->size = buffer->dataSize; } -static void GetSurfaceDesc(GuestSurface* surface, GuestSurfaceDesc* desc) +static void GetSurfaceDesc(GuestSurface* surface, GuestSurfaceDesc* desc) { if (surface->width == 0 && surface->height == 0) { LOGF_WARNING("{:p} {:d} {:d} \n", reinterpret_cast(desc), surface->width, surface->height); @@ -2561,30 +2561,32 @@ static void GetSurfaceDesc(GuestSurface* surface, GuestSurfaceDesc* desc) // desc->multiSampleType = 0; if (surface->sampleCount == RenderSampleCount::COUNT_1) { desc->multiSampleType = 0; - } else if (surface->sampleCount == RenderSampleCount::COUNT_2) { + } + else if (surface->sampleCount == RenderSampleCount::COUNT_2) { desc->multiSampleType = 1; - } else { + } + else { desc->multiSampleType = 2; } desc->multiSampleQuality = 0; desc->usage = 0; } -static void GetVertexDeclaration(GuestVertexDeclaration* vertexDeclaration, GuestVertexElement* vertexElements, be* count) +static void GetVertexDeclaration(GuestVertexDeclaration* vertexDeclaration, GuestVertexElement* vertexElements, be* count) { memcpy(vertexElements, vertexDeclaration->vertexElements.get(), vertexDeclaration->vertexElementCount * sizeof(GuestVertexElement)); *count = vertexDeclaration->vertexElementCount; } -static uint32_t HashVertexDeclaration(uint32_t vertexDeclaration) +static uint32_t HashVertexDeclaration(uint32_t vertexDeclaration) { // Vertex declarations are cached on host side, so the pointer itself can be used. return vertexDeclaration; } -static const char *DeviceTypeName(RenderDeviceType type) +static const char* DeviceTypeName(RenderDeviceType type) { - switch (type) + switch (type) { case RenderDeviceType::INTEGRATED: return "Integrated"; @@ -2664,31 +2666,31 @@ static void DrawProfiler() ImGui::TableHeadersRow(); auto drawPerfRow = [](const char* name, double ms, double msAvg, bool showFPS = false, double fps = 0, double fpsAvg = 0) - { - ImGui::TableNextColumn(); - ImGui::Text("%s", name); - ImGui::TableNextColumn(); - ImGui::Text("%g ms", ms); - ImGui::TableNextColumn(); - ImGui::Text("%g ms", msAvg); - ImGui::TableNextColumn(); + { + ImGui::TableNextColumn(); + ImGui::Text("%s", name); + ImGui::TableNextColumn(); + ImGui::Text("%g ms", ms); + ImGui::TableNextColumn(); + ImGui::Text("%g ms", msAvg); + ImGui::TableNextColumn(); - if (showFPS) - ImGui::Text("%g FPS", fps); + if (showFPS) + ImGui::Text("%g FPS", fps); - ImGui::TableNextColumn(); + ImGui::TableNextColumn(); - if (showFPS) - ImGui::Text("%g FPS", fpsAvg); - }; + if (showFPS) + ImGui::Text("%g FPS", fpsAvg); + }; // -------- Name ---------------- Current Time --------------------------- Average Time -------- Current FPS ----------------------------- Average FPS ---------- // - drawPerfRow("Application", App::s_deltaTime * 1000.0, applicationAvg, true, 1.0 / App::s_deltaTime, 1000.0 / applicationAvg); - drawPerfRow("GPU Frame", g_gpuFrameProfiler.value.load(), gpuFrameAvg, true, 1000.0 / g_gpuFrameProfiler.value.load(), 1000.0 / gpuFrameAvg ); - drawPerfRow("Present", g_presentProfiler.value.load(), presentAvg, true, 1000.0 / g_presentProfiler.value.load(), 1000.0 / presentAvg ); - drawPerfRow("Present Wait", g_presentWaitProfiler.value.load(), presentWaitAvg ); - drawPerfRow("Frame Fence", g_frameFenceProfiler.value.load(), frameFenceAvg ); - drawPerfRow("Swap Chain Acquire", g_swapChainAcquireProfiler.value.load(), swapChainAcquireAvg ); + drawPerfRow("Application", App::s_deltaTime * 1000.0, applicationAvg, true, 1.0 / App::s_deltaTime, 1000.0 / applicationAvg); + drawPerfRow("GPU Frame", g_gpuFrameProfiler.value.load(), gpuFrameAvg, true, 1000.0 / g_gpuFrameProfiler.value.load(), 1000.0 / gpuFrameAvg); + drawPerfRow("Present", g_presentProfiler.value.load(), presentAvg, true, 1000.0 / g_presentProfiler.value.load(), 1000.0 / presentAvg); + drawPerfRow("Present Wait", g_presentWaitProfiler.value.load(), presentWaitAvg); + drawPerfRow("Frame Fence", g_frameFenceProfiler.value.load(), frameFenceAvg); + drawPerfRow("Swap Chain Acquire", g_swapChainAcquireProfiler.value.load(), swapChainAcquireAvg); ImGui::EndTable(); } @@ -2728,17 +2730,17 @@ static void DrawProfiler() switch (g_backend) { - case Backend::VULKAN: - backend = "Vulkan"; - break; + case Backend::VULKAN: + backend = "Vulkan"; + break; - case Backend::D3D12: - backend = "D3D12"; - break; + case Backend::D3D12: + backend = "D3D12"; + break; - case Backend::METAL: - backend = "Metal"; - break; + case Backend::METAL: + backend = "Metal"; + break; } if (ImGui::BeginTable("GPU", 2)) @@ -2937,7 +2939,7 @@ static void DrawImGui() } } -static void SetFramebuffer(GuestSurface *renderTarget, GuestSurface *depthStencil, bool settingForClear); +static void SetFramebuffer(GuestSurface* renderTarget, GuestSurface* depthStencil, bool settingForClear); static void ProcDrawImGui(const RenderCommand& cmd) { @@ -3006,7 +3008,7 @@ static void ProcDrawImGui(const RenderCommand& cmd) { case ImGuiCallback::SetGradient: setPushConstants(&pushConstants.boundsMin, &callbackData->setGradient, sizeof(callbackData->setGradient)); - break; + break; case ImGuiCallback::SetShaderModifier: setPushConstants(&pushConstants.shaderModifier, &callbackData->setShaderModifier, sizeof(callbackData->setShaderModifier)); break; @@ -3015,7 +3017,7 @@ static void ProcDrawImGui(const RenderCommand& cmd) break; case ImGuiCallback::SetScale: setPushConstants(&pushConstants.scale, &callbackData->setScale, sizeof(callbackData->setScale)); - break; + break; case ImGuiCallback::SetMarqueeFade: setPushConstants(&pushConstants.boundsMin, &callbackData->setMarqueeFade, sizeof(callbackData->setMarqueeFade)); break; @@ -3110,7 +3112,7 @@ void Video::WaitOnSwapChain() static bool g_shouldPrecompilePipelines; static std::atomic g_executedCommandList; -void Video::Present() +void Video::Present() { g_readyForCommands = false; @@ -3126,7 +3128,7 @@ void Video::Present() // All the shaders are available at this point. We can precompile embedded PSOs then. if (g_shouldPrecompilePipelines) { -// EnqueuePipelineTask(PipelineTaskType::PrecompilePipelines, {}); + // EnqueuePipelineTask(PipelineTaskType::PrecompilePipelines, {}); g_shouldPrecompilePipelines = false; } @@ -3160,7 +3162,7 @@ void Video::Present() // Update the GPU profiler with the results from the timestamps of the frame. g_queryPools[g_frame]->queryResults(); - const uint64_t *frameTimestamps = g_queryPools[g_frame]->getResults(); + const uint64_t* frameTimestamps = g_queryPools[g_frame]->getResults(); g_gpuFrameProfiler.Set(double(frameTimestamps[1] - frameTimestamps[0]) / 1000000.0); } @@ -3217,7 +3219,7 @@ static void SetRootDescriptor(const UploadAllocation& allocation, size_t index) } static void ProcExecuteCommandList(const RenderCommand& cmd) -{ +{ if (g_swapChainValid) { auto swapChainTexture = g_swapChain->getTexture(g_backBufferIndex); @@ -3246,11 +3248,11 @@ static void ProcExecuteCommandList(const RenderCommand& cmd) constants.viewportWidth = Video::s_viewportWidth; constants.viewportHeight = Video::s_viewportHeight; - auto &framebuffer = g_backBuffer->framebuffers[swapChainTexture]; + auto& framebuffer = g_backBuffer->framebuffers[swapChainTexture]; if (!framebuffer) { RenderFramebufferDesc desc; - desc.colorAttachments = const_cast(&swapChainTexture); + desc.colorAttachments = const_cast(&swapChainTexture); desc.colorAttachmentsCount = 1; framebuffer = g_device->createFramebuffer(desc); } @@ -3261,7 +3263,7 @@ static void ProcExecuteCommandList(const RenderCommand& cmd) RenderTextureBarrier(swapChainTexture, RenderTextureLayout::COLOR_WRITE) }; - auto &commandList = g_commandLists[g_frame]; + auto& commandList = g_commandLists[g_frame]; commandList->barriers(RenderBarrierStage::GRAPHICS, srcBarriers, std::size(srcBarriers)); commandList->setGraphicsPipelineLayout(g_pipelineLayout.get()); commandList->setPipeline(g_gammaCorrectionPipeline.get()); @@ -3280,15 +3282,15 @@ static void ProcExecuteCommandList(const RenderCommand& cmd) } } - auto &commandList = g_commandLists[g_frame]; + auto& commandList = g_commandLists[g_frame]; commandList->writeTimestamp(g_queryPools[g_frame].get(), 1); commandList->end(); if (g_swapChainValid) { - const RenderCommandList *commandLists[] = { commandList.get() }; - RenderCommandSemaphore *waitSemaphores[] = { g_acquireSemaphores[g_frame].get() }; - RenderCommandSemaphore *signalSemaphores[] = { g_renderSemaphores[g_frame].get() }; + const RenderCommandList* commandLists[] = { commandList.get() }; + RenderCommandSemaphore* waitSemaphores[] = { g_acquireSemaphores[g_frame].get() }; + RenderCommandSemaphore* signalSemaphores[] = { g_renderSemaphores[g_frame].get() }; g_queue->executeCommandLists( commandLists, std::size(commandLists), @@ -3313,13 +3315,13 @@ static void ProcBeginCommandList(const RenderCommand& cmd) BeginCommandList(); } -static GuestSurface* GetBackBuffer() +static GuestSurface* GetBackBuffer() { g_backBuffer->AddRef(); return g_backBuffer; } -static GuestSurface* GetDepthStencil() +static GuestSurface* GetDepthStencil() { g_depthStencil->AddRef(); return g_depthStencil; @@ -3333,26 +3335,26 @@ void Video::ComputeViewportDimensions() switch (Config::AspectRatio) { - case EAspectRatio::Original: + case EAspectRatio::Original: + { + if (aspectRatio > WIDE_ASPECT_RATIO) { - if (aspectRatio > WIDE_ASPECT_RATIO) - { - s_viewportWidth = height * 16 / 9; - s_viewportHeight = height; - } - else - { - s_viewportWidth = width; - s_viewportHeight = width * 9 / 16; - } - - break; + s_viewportWidth = height * 16 / 9; + s_viewportHeight = height; } - - default: + else + { s_viewportWidth = width; - s_viewportHeight = height; - break; + s_viewportHeight = width * 9 / 16; + } + + break; + } + + default: + s_viewportWidth = width; + s_viewportHeight = height; + break; } AspectRatioPatches::ComputeOffsets(); @@ -3400,7 +3402,7 @@ static RenderFormat ConvertFormat(uint32_t format) } } -static GuestTexture* CreateTexture(uint32_t width, uint32_t height, uint32_t depth, uint32_t levels, uint32_t usage, uint32_t format, uint32_t pool, uint32_t type) +static GuestTexture* CreateTexture(uint32_t width, uint32_t height, uint32_t depth, uint32_t levels, uint32_t usage, uint32_t format, uint32_t pool, uint32_t type) { ResourceType resourceType; @@ -3429,7 +3431,8 @@ static GuestTexture* CreateTexture(uint32_t width, uint32_t height, uint32_t dep if (texture->type == ResourceType::ArrayTexture) { desc.arraySize = depth; desc.depth = 1; - } else { + } + else { desc.depth = depth; desc.arraySize = 1; } @@ -3474,7 +3477,7 @@ static GuestTexture* CreateTexture(uint32_t width, uint32_t height, uint32_t dep texture->descriptorIndex = g_textureDescriptorAllocator.allocate(); g_textureDescriptorSet->setTexture(texture->descriptorIndex, texture->texture, RenderTextureLayout::SHADER_READ, texture->textureView.get()); - + #ifdef _DEBUG texture->texture->setName(fmt::format("Texture {:X}", g_memory.MapVirtual(texture))); #endif @@ -3487,7 +3490,7 @@ static RenderHeapType GetBufferHeapType() return g_capabilities.gpuUploadHeap ? RenderHeapType::GPU_UPLOAD : RenderHeapType::DEFAULT; } -static GuestBuffer* CreateVertexBuffer(uint32_t length) +static GuestBuffer* CreateVertexBuffer(uint32_t length) { auto buffer = g_userHeap.AllocPhysical(ResourceType::VertexBuffer); buffer->buffer = g_device->createBuffer(RenderBufferDesc::VertexBuffer(length, GetBufferHeapType(), RenderBufferFlag::INDEX)); @@ -3515,7 +3518,7 @@ static std::vector> g_surfaceCache; // TODO: Singleplayer (possibly) uses the same memory location in EDRAM for HDR and FB0 surfaces, // so we just remember who was created first and use that instead of creating a new one. -static GuestSurface* CreateSurface(uint32_t width, uint32_t height, uint32_t format, uint32_t multiSample, GuestSurfaceCreateParams* params) +static GuestSurface* CreateSurface(uint32_t width, uint32_t height, uint32_t format, uint32_t multiSample, GuestSurfaceCreateParams* params) { GuestSurface* surface = nullptr; uint32_t baseValue = params ? params->base.get() : -1; @@ -3545,7 +3548,8 @@ static GuestSurface* CreateSurface(uint32_t width, uint32_t height, uint32_t for // desc.multisampling.sampleCount = multiSample != 0 && Config::AntiAliasing != EAntiAliasing::None ? int32_t(Config::AntiAliasing.Value) : RenderSampleCount::COUNT_1; if (multiSample == 0) { desc.multisampling.sampleCount = RenderSampleCount::COUNT_1; - } else { + } + else { desc.multisampling.sampleCount = multiSample == 1 ? RenderSampleCount::COUNT_2 : RenderSampleCount::COUNT_4; } desc.format = ConvertFormat(format); @@ -3570,9 +3574,9 @@ static GuestSurface* CreateSurface(uint32_t width, uint32_t height, uint32_t for surface->descriptorIndex = g_textureDescriptorAllocator.allocate(); g_textureDescriptorSet->setTexture(surface->descriptorIndex, surface->textureHolder.get(), RenderTextureLayout::SHADER_READ, surface->textureView.get()); - #ifdef _DEBUG +#ifdef _DEBUG surface->texture->setName(fmt::format("{} {:X}", desc.flags & RenderTextureFlag::RENDER_TARGET ? "Render Target" : "Depth Stencil", g_memory.MapVirtual(surface))); - #endif +#endif if (params) { surface->wasCached = true; g_surfaceCache.emplace_back(surface, baseValue); @@ -3688,7 +3692,7 @@ static void SetDefaultViewport(GuestDevice* device, GuestSurface* surface) } } -static void SetRenderTarget(GuestDevice* device, uint32_t index, GuestSurface* renderTarget) +static void SetRenderTarget(GuestDevice* device, uint32_t index, GuestSurface* renderTarget) { if (index == 0) { @@ -3717,7 +3721,7 @@ static void ProcSetRenderTarget(const RenderCommand& cmd) SetAlphaTestMode((g_pipelineState.specConstants & (SPEC_CONSTANT_ALPHA_TEST | SPEC_CONSTANT_ALPHA_TO_COVERAGE)) != 0); } -static void SetDepthStencilSurface(GuestDevice* device, GuestSurface* depthStencil) +static void SetDepthStencilSurface(GuestDevice* device, GuestSurface* depthStencil) { RenderCommand cmd; cmd.type = RenderCommandType::SetDepthStencilSurface; @@ -4129,11 +4133,11 @@ static void ProcSetViewport(const RenderCommand& cmd) SetDirtyValue(g_dirtyStates.viewport, g_viewport.height, args.height); SetDirtyValue(g_dirtyStates.viewport, g_viewport.minDepth, args.minDepth); SetDirtyValue(g_dirtyStates.viewport, g_viewport.maxDepth, args.maxDepth); - + uint32_t specConstants = g_pipelineState.specConstants; if (args.minDepth > args.maxDepth) specConstants |= SPEC_CONSTANT_REVERSE_Z; - else + else specConstants &= ~SPEC_CONSTANT_REVERSE_Z; SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.specConstants, specConstants); @@ -4141,7 +4145,7 @@ static void ProcSetViewport(const RenderCommand& cmd) g_dirtyStates.scissorRect |= g_dirtyStates.viewport; } -static void SetTexture(GuestDevice* device, uint32_t index, GuestTexture* texture) +static void SetTexture(GuestDevice* device, uint32_t index, GuestTexture* texture) { // printf("SetTexture: %x %d %x\n", device, index, texture); @@ -4201,10 +4205,10 @@ static void ProcSetTexture(const RenderCommand& cmd) shouldSetTexture = false; } } - + if (shouldSetTexture) SetTextureInRenderThread(args.index, args.texture); - + g_textures[args.index] = args.texture; } @@ -4232,7 +4236,7 @@ static void ProcSetScissorRect(const RenderCommand& cmd) static RenderShader* GetOrLinkShader(GuestShader* guestShader, uint32_t specConstants) { if (g_backend != Backend::D3D12 || - guestShader->shaderCacheEntry == nullptr || + guestShader->shaderCacheEntry == nullptr || guestShader->shaderCacheEntry->specConstantsMask == 0) { std::lock_guard lock(guestShader->mutex); @@ -4255,7 +4259,7 @@ static RenderShader* GetOrLinkShader(GuestShader* guestShader, uint32_t specCons } case Backend::D3D12: { - guestShader->shader = g_device->createShader(g_shaderCache.get() + guestShader->shaderCacheEntry->dxilOffset, + guestShader->shader = g_device->createShader(g_shaderCache.get() + guestShader->shaderCacheEntry->dxilOffset, guestShader->shaderCacheEntry->dxilSize, "shaderMain", RenderShaderFormat::DXIL); break; } @@ -4397,7 +4401,7 @@ static RenderShader* GetOrLinkShader(GuestShader* guestShader, uint32_t specCons #ifdef _DEBUG shader->setName(fmt::format("{}:{:x}", guestShader->shaderCacheEntry->filename, guestShader->shaderCacheEntry->hash)); #endif - } + } } #endif @@ -4501,7 +4505,8 @@ static std::unique_ptr CreateGraphicsPipeline(const PipelineStat desc.stencilBackFace.failOp = pipelineState.stencilFailCCW; desc.stencilBackFace.depthFailOp = pipelineState.stencilZFailCCW; desc.stencilBackFace.passOp = pipelineState.stencilPassCCW; - } else { + } + else { desc.stencilBackFace = desc.stencilFrontFace; } desc.slopeScaledDepthBias = pipelineState.slopeScaledDepthBias; @@ -4525,37 +4530,37 @@ static std::unique_ptr CreateGraphicsPipeline(const PipelineStat desc.alphaToCoverageEnabled = pipelineState.enableAlphaToCoverage; desc.inputElements = pipelineState.vertexDeclaration->inputElements.get(); desc.inputElementsCount = pipelineState.vertexDeclaration->inputElementCount; - + RenderSpecConstant specConstant{}; specConstant.value = pipelineState.specConstants; - + if (pipelineState.specConstants != 0) { desc.specConstants = &specConstant; desc.specConstantsCount = 1; } - + RenderInputSlot inputSlots[16]{}; uint32_t inputSlotIndices[16]{}; uint32_t inputSlotCount = 0; - + for (size_t i = 0; i < pipelineState.vertexDeclaration->inputElementCount; i++) { auto& inputElement = pipelineState.vertexDeclaration->inputElements[i]; auto& inputSlotIndex = inputSlotIndices[inputElement.slotIndex]; - + if (inputSlotIndex == NULL) inputSlotIndex = ++inputSlotCount; - + auto& inputSlot = inputSlots[inputSlotIndex - 1]; inputSlot.index = inputElement.slotIndex; inputSlot.stride = pipelineState.vertexStrides[inputElement.slotIndex]; inputSlot.classification = RenderInputSlotClassification::PER_VERTEX_DATA; } - + desc.inputSlots = inputSlots; desc.inputSlotsCount = inputSlotCount; - + auto pipeline = g_device->createGraphicsPipeline(desc); #ifdef ASYNC_PSO_DEBUG @@ -4585,7 +4590,7 @@ static RenderPipeline* CreateGraphicsPipelineInRenderThread(PipelineState pipeli pipeline->setName(fmt::format("{} {} {} {:X}", loading ? "ASYNC" : "", pipelineState.vertexShader->name, pipelineState.pixelShader != nullptr ? pipelineState.pixelShader->name : "", hash)); - + if (!loading) { std::lock_guard lock(g_debugMutex); @@ -4683,7 +4688,7 @@ static RenderPipeline* CreateGraphicsPipelineInRenderThread(PipelineState pipeli g_pipelineStatesToCache.emplace(hash, pipelineState); #endif } - + return pipeline.get(); } @@ -5037,7 +5042,7 @@ static void SetPrimitiveType(uint32_t primitiveType) SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.primitiveTopology, ConvertPrimitiveType(primitiveType)); } -static void DrawPrimitive(GuestDevice* device, uint32_t primitiveType, uint32_t startVertex, uint32_t primitiveCount) +static void DrawPrimitive(GuestDevice* device, uint32_t primitiveType, uint32_t startVertex, uint32_t primitiveCount) { LocalRenderCommandQueue queue; FlushRenderStateForMainThread(device, queue); @@ -5101,7 +5106,7 @@ static void DrawPrimitiveUP(GuestDevice* device, uint32_t primitiveType, uint32_ cmd.drawPrimitiveUP.vertexStreamZeroSize = primitiveCount * vertexStreamZeroStride; cmd.drawPrimitiveUP.vertexStreamZeroStride = vertexStreamZeroStride; cmd.drawPrimitiveUP.csdFilterState = g_csdFilterState; - + queue.submit(); } @@ -5227,7 +5232,7 @@ static RenderFormat ConvertDeclType(uint32_t type) } } -static GuestVertexDeclaration* CreateVertexDeclarationWithoutAddRef(GuestVertexElement* vertexElements) +static GuestVertexDeclaration* CreateVertexDeclarationWithoutAddRef(GuestVertexElement* vertexElements) { size_t vertexElementCount = 0; auto vertexElement = vertexElements; @@ -5466,7 +5471,7 @@ static GuestVertexDeclaration* CreateVertexDeclaration(GuestVertexElement* verte return vertexDeclaration; } -static void SetVertexDeclaration(GuestDevice* device, GuestVertexDeclaration* vertexDeclaration) +static void SetVertexDeclaration(GuestDevice* device, GuestVertexDeclaration* vertexDeclaration) { RenderCommand cmd; cmd.type = RenderCommandType::SetVertexDeclaration; @@ -5556,7 +5561,7 @@ static GuestShader* CreateShader(const be* function, ResourceType reso return shader; } -static GuestShader* CreateVertexShader(const be* function) +static GuestShader* CreateVertexShader(const be* function) { return CreateShader(function, ResourceType::VertexShader); } @@ -5574,7 +5579,7 @@ static void ProcSetVertexShader(const RenderCommand& cmd) GuestShader* shader = cmd.setVertexShader.shader; if (shader != nullptr && - shader->shaderCacheEntry != nullptr) + shader->shaderCacheEntry != nullptr) { if (shader->shaderCacheEntry->hash == 0x3687D038CE7D0BEA || shader->shaderCacheEntry->hash == 0xB4DA7A442DBB16CC) { @@ -5586,7 +5591,7 @@ static void ProcSetVertexShader(const RenderCommand& cmd) SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.vertexShader, shader); } -static void SetStreamSource(GuestDevice* device, uint32_t index, GuestBuffer* buffer, uint32_t offset, uint32_t stride) +static void SetStreamSource(GuestDevice* device, uint32_t index, GuestBuffer* buffer, uint32_t offset, uint32_t stride) { RenderCommand cmd; cmd.type = RenderCommandType::SetStreamSource; @@ -5616,7 +5621,7 @@ static void ProcSetStreamSource(const RenderCommand& cmd) } } -static void SetIndices(GuestDevice* device, GuestBuffer* buffer) +static void SetIndices(GuestDevice* device, GuestBuffer* buffer) { RenderCommand cmd; cmd.type = RenderCommandType::SetIndices; @@ -5832,9 +5837,11 @@ struct BEString uint32_t len = size.get(); if (len == 0) { return alval; - } else if (len < 16) { + } + else if (len < 16) { return bx._Buf; - } else { + } + else { return reinterpret_cast(bx._Ptr.get()); } } @@ -5859,7 +5866,7 @@ struct GuestMyTexture static RenderTextureDimension ConvertTextureDimension(ddspp::TextureType type) { - switch (type) + switch (type) { case ddspp::Texture1D: return RenderTextureDimension::TEXTURE_1D; @@ -5892,7 +5899,7 @@ static RenderTextureViewDimension ConvertTextureViewDimension(ddspp::TextureType } } -static RenderFormat ConvertDXGIFormat(ddspp::DXGIFormat format) +static RenderFormat ConvertDXGIFormat(ddspp::DXGIFormat format) { switch (format) { @@ -5945,7 +5952,7 @@ static RenderFormat ConvertDXGIFormat(ddspp::DXGIFormat format) case ddspp::B8G8R8A8_UNORM: return RenderFormat::B8G8R8A8_UNORM; case ddspp::B8G8R8X8_UNORM: - return RenderFormat::B8G8R8A8_UNORM; + return RenderFormat::B8G8R8A8_UNORM; case ddspp::R16G16_TYPELESS: return RenderFormat::R16G16_TYPELESS; case ddspp::R16G16_FLOAT: @@ -6055,7 +6062,7 @@ static RenderFormat ConvertDXGIFormat(ddspp::DXGIFormat format) static bool LoadTexture(GuestTexture& texture, const uint8_t* data, size_t dataSize, RenderComponentMapping componentMapping) { ddspp::Descriptor ddsDesc; - if (ddspp::decode_header((unsigned char *)(data), ddsDesc) != ddspp::Error) + if (ddspp::decode_header((unsigned char*)(data), ddsDesc) != ddspp::Error) { RenderTextureDesc desc; desc.dimension = ConvertTextureDimension(ddsDesc.type); @@ -6242,13 +6249,13 @@ static void DiffPatchTexture(GuestTexture& texture, uint8_t* data, uint32_t data auto header = reinterpret_cast(g_buttonBcDiff.get()); auto entries = reinterpret_cast(g_buttonBcDiff.get() + header->entriesOffset); auto end = entries + header->entryCount; - + auto hash = XXH3_64bits(data, dataSize); auto findResult = std::lower_bound(entries, end, hash, [](BlockCompressionDiffPatchEntry& lhs, XXH64_hash_t rhs) - { - return lhs.hash < rhs; - }); + { + return lhs.hash < rhs; + }); if (findResult != end && findResult->hash == hash) { @@ -6444,38 +6451,38 @@ static void PipelineCompilerThread() std::unique_ptr ctx; -// while (true) -// { -// PipelineStateQueueItem queueItem; -// g_pipelineStateQueue.wait_dequeue(queueItem); -// -// if (ctx == nullptr) -// ctx = std::make_unique(0); -// -//#ifdef _WIN32 -// int newThreadPriority = threadPriority; -// -// bool loading = *SWA::SGlobals::ms_IsLoading; -// if (loading) -// newThreadPriority = THREAD_PRIORITY_HIGHEST; -// else -// newThreadPriority = THREAD_PRIORITY_LOWEST; -// -// if (newThreadPriority != threadPriority) -// { -// SetThreadPriority(GetCurrentThread(), newThreadPriority); -// threadPriority = newThreadPriority; -// } -//#endif -// -// CompilePipeline(queueItem.pipelineHash, queueItem.pipelineState -//#ifdef ASYNC_PSO_DEBUG -// , queueItem.pipelineName.c_str() -//#endif -// ); -// -// std::this_thread::yield(); -// } + // while (true) + // { + // PipelineStateQueueItem queueItem; + // g_pipelineStateQueue.wait_dequeue(queueItem); + // + // if (ctx == nullptr) + // ctx = std::make_unique(0); + // + //#ifdef _WIN32 + // int newThreadPriority = threadPriority; + // + // bool loading = *SWA::SGlobals::ms_IsLoading; + // if (loading) + // newThreadPriority = THREAD_PRIORITY_HIGHEST; + // else + // newThreadPriority = THREAD_PRIORITY_LOWEST; + // + // if (newThreadPriority != threadPriority) + // { + // SetThreadPriority(GetCurrentThread(), newThreadPriority); + // threadPriority = newThreadPriority; + // } + //#endif + // + // CompilePipeline(queueItem.pipelineHash, queueItem.pipelineState + //#ifdef ASYNC_PSO_DEBUG + // , queueItem.pipelineName.c_str() + //#endif + // ); + // + // std::this_thread::yield(); + // } } static std::vector> g_pipelineCompilerThreads = []() @@ -6497,8 +6504,8 @@ static constexpr uint32_t PARTICLE_MATERIAL_VFTABLE = 0x8211F198; // If nothing was compiled, the local "token" variable will get destructed with RAII instead. struct PipelineTaskTokenPair { -// PipelineTaskToken token; -// std::shared_ptr sharedToken; + // PipelineTaskToken token; + // std::shared_ptr sharedToken; }; // Having this separate, because I don't want to lock a mutex in the render thread before @@ -6581,7 +6588,7 @@ struct Mesh uint32_t vertexSize{}; uint32_t morphTargetVertexSize{}; GuestVertexDeclaration* vertexDeclaration{}; -// Hedgehog::Mirage::CMaterialData* material{}; + // Hedgehog::Mirage::CMaterialData* material{}; MeshLayer layer{}; bool morphModel{}; }; @@ -7241,13 +7248,13 @@ static bool CheckMadeAll(const T& modelData) { if (!CheckMadeAll(mesh.get())) return false; - } + } for (auto& mesh : meshGroup->m_TransparentMeshes) { if (!CheckMadeAll(mesh.get())) return false; - } + } for (auto& mesh : meshGroup->m_PunchThroughMeshes) { @@ -7570,7 +7577,7 @@ static bool CheckMadeAll(const T& modelData) class SDLEventListenerForPSOCaching : public SDLEventListener { public: - bool OnSDLEvent(SDL_Event* event) override + bool OnSDLEvent(SDL_Event* event) override { if (event->type != SDL_QUIT) return false; @@ -7735,14 +7742,14 @@ void VideoConfigValueChangedCallback(IConfigDef* config) if (g_needsResize) Video::ComputeViewportDimensions(); - + // Config options that require pipeline recompilation bool shouldRecompile = config == &Config::AntiAliasing || config == &Config::TransparencyAntiAliasing; -// if (shouldRecompile) -// EnqueuePipelineTask(PipelineTaskType::RecompilePipelines, {}); + // if (shouldRecompile) + // EnqueuePipelineTask(PipelineTaskType::RecompilePipelines, {}); } // There is a bug on AMD where restart indices cause incorrect culling and prevent some triangles from being rendered. @@ -7767,7 +7774,7 @@ static void ConvertToDegenerateTriangles(uint16_t* indices, uint32_t indexCount, stripStart = true; stripSize = 0; } - else + else { if (stripStart && newIndexCount != 0) { diff --git a/MarathonRecomp/gpu/video.h b/MarathonRecomp/gpu/video.h index 09f78f26..67668e65 100644 --- a/MarathonRecomp/gpu/video.h +++ b/MarathonRecomp/gpu/video.h @@ -28,7 +28,7 @@ struct Video static inline uint32_t s_viewportWidth; static inline uint32_t s_viewportHeight; - static bool CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry); + static bool CreateHostDevice(const char* sdlVideoDriver, bool graphicsApiRetry); static void WaitOnSwapChain(); static void Present(); static void StartPipelinePrecompilation(); @@ -101,7 +101,7 @@ struct GuestResource be refCount = 1; ResourceType type; - GuestResource(ResourceType type) : type(type) + GuestResource(ResourceType type) : type(type) { } diff --git a/MarathonRecomp/kernel/function.h b/MarathonRecomp/kernel/function.h index 7c6beee1..7021319d 100644 --- a/MarathonRecomp/kernel/function.h +++ b/MarathonRecomp/kernel/function.h @@ -332,7 +332,7 @@ T GuestToHostFunction(const TFunction& func, TArgs&&... argv) if constexpr (std::is_pointer_v) { - return reinterpret_cast((uint64_t)g_memory.Translate(newCtx.r3.u32)); + return newCtx.r3.u32 == 0 ? reinterpret_cast(0) : reinterpret_cast((uint64_t)g_memory.Translate(newCtx.r3.u32)); } else if constexpr (is_precise_v) { diff --git a/MarathonRecomp/patches/TitleTask_patches.cpp b/MarathonRecomp/patches/TitleTask_patches.cpp index 70e114de..5148afe0 100644 --- a/MarathonRecomp/patches/TitleTask_patches.cpp +++ b/MarathonRecomp/patches/TitleTask_patches.cpp @@ -110,7 +110,7 @@ PPC_FUNC(sub_825126A0) if (g_isSecretDone) break; - if (auto& spInputManager = App::s_pApp->m_pDoc->m_vspInputManager[0]) + if (auto& spInputManager = App::s_pApp->m_pDoc->m_vspInputManagers[0]) { auto& rPadState = spInputManager->m_PadState; @@ -138,7 +138,7 @@ PPC_FUNC(sub_825126A0) case Sonicteam::TitleTask::TitleState_OptionsWait: { - if (auto& spInputManager = App::s_pApp->m_pDoc->m_vspInputManager[0]) + if (auto& spInputManager = App::s_pApp->m_pDoc->m_vspInputManagers[0]) { auto& rPadState = spInputManager->m_PadState; @@ -196,7 +196,7 @@ PPC_FUNC(sub_825126A0) } else { - if (auto& spInputManager = App::s_pApp->m_pDoc->m_vspInputManager[0]) + if (auto& spInputManager = App::s_pApp->m_pDoc->m_vspInputManagers[0]) { auto& rPadState = spInputManager->m_PadState; diff --git a/MarathonRecomp/patches/misc_patches.cpp b/MarathonRecomp/patches/misc_patches.cpp index a8a8e320..ed537bab 100644 --- a/MarathonRecomp/patches/misc_patches.cpp +++ b/MarathonRecomp/patches/misc_patches.cpp @@ -43,8 +43,8 @@ void SetLifeBarAnimation(PPCRegister& r3, PPCRegister& r4, PPCRegister& r5, PPCR // Redirect "life_ber_anime" to "life_bar_anime", as they // actually spelt "bar" correctly in the tag XNCP scene names... - if ((pCsdObject->m_pCsdResource->m_FilePath == "sprite/tagdisplay_1p" || - pCsdObject->m_pCsdResource->m_FilePath == "sprite/tagdisplay_2p") && + if ((pCsdObject->m_pCsdResource->m_MgrResourceName == "sprite/tagdisplay_1p" || + pCsdObject->m_pCsdResource->m_MgrResourceName == "sprite/tagdisplay_2p") && strcmp(pSceneName, "life_ber_anime") == 0) { r4.u32 = g_memory.MapVirtual(s_lifeBarSceneName); @@ -92,12 +92,10 @@ void Load2PDisplayMidAsmHook() {} void PostureDisableEdgeGrabLeftover(PPCRegister& posture) { - if (!Config::DisableEdgeGrabLeftover) + if (!Config::EnablePostureImprovements) return; auto base = g_memory.base; - - *(volatile uint8_t*)(base + (posture.u32 + 0x3C0)) = 1; } void PedestrianAnimationLOD(PPCRegister& val) diff --git a/MarathonRecomp/patches/player_patches.cpp b/MarathonRecomp/patches/player_patches.cpp index 1c69458d..e4c12875 100644 --- a/MarathonRecomp/patches/player_patches.cpp +++ b/MarathonRecomp/patches/player_patches.cpp @@ -3,6 +3,11 @@ #include #include #include +#include +#include + +static float EdgeSmothing = 12.0; +static float Gonst = 0.7f; // Sonicteam::Player::Object::Update PPC_FUNC_IMPL(__imp__sub_82195500); @@ -17,36 +22,46 @@ PPC_FUNC(sub_82195500) { switch (pPlayer->m_SetupModuleIndexPostfix) { - case 1: + case 1: + { + // Toggle debug posture on Select press. + if (pPlayer->m_SetupModuleIndexPrefix == 1 && pInputManager->m_PadState.IsPressed(Sonicteam::SoX::Input::KeyState_Select)) { - // Toggle debug posture on Select press. - if (pPlayer->m_SetupModuleIndexPrefix == 1 && pInputManager->m_PadState.IsPressed(Sonicteam::SoX::Input::KeyState_Select)) - { - pPlayer->m_SetupModuleIndexPostfix = 2; - - LOGN("Debug Mode: Enabled"); - } + pPlayer->m_SetupModuleIndexPostfix = 2; - break; + LOGN("Debug Mode: Enabled"); + } + if (pInputManager->m_PadState.IsDown(Sonicteam::SoX::Input::KeyState_DpadUp)) + { + EdgeSmothing += 1.0 * ctx.f1.f64; + printf("EdgeSmothing %f\n", EdgeSmothing); } - case 2: + if (pInputManager->m_PadState.IsDown(Sonicteam::SoX::Input::KeyState_DpadDown)) { - // Toggle camera volume collision on B press. - if (pInputManager->m_PadState.IsPressed(Sonicteam::SoX::Input::KeyState_B)) - { - auto pGame = App::s_pApp->GetGame(); - auto pZock = pPlayer->GetPlugin("zock"); - auto collisionFilterInfo = pZock->m_spPhantomA->m_pRigidBody->m_collidable.m_broadPhaseHandle.m_collisionFilterInfo == 6 ? 0x383 : 6; + EdgeSmothing -= 1.0 * ctx.f1.f64; + printf("EdgeSmothing %f\n", EdgeSmothing); + } - LOGFN("Camera Volumes: {}", collisionFilterInfo != 6 ? "Enabled" : "Disabled"); + break; + } - pZock->m_spPhantomA->m_pRigidBody->m_collidable.m_broadPhaseHandle.m_collisionFilterInfo = collisionFilterInfo; - pGame->GetPhysicsWorld()->m_pWorld->updateCollisionFilterOnWorld(1, 1); - } + case 2: + { + // Toggle camera volume collision on B press. + if (pInputManager->m_PadState.IsPressed(Sonicteam::SoX::Input::KeyState_B)) + { + auto pGame = App::s_pApp->GetGame(); + auto pZock = pPlayer->GetPlugin("zock"); + auto collisionFilterInfo = pZock->m_spPhantomA->m_pRigidBody->m_collidable.m_broadPhaseHandle.m_collisionFilterInfo == 6 ? 0x383 : 6; + + LOGFN("Camera Volumes: {}", collisionFilterInfo != 6 ? "Enabled" : "Disabled"); - break; + pZock->m_spPhantomA->m_pRigidBody->m_collidable.m_broadPhaseHandle.m_collisionFilterInfo = collisionFilterInfo; + pGame->GetPhysicsWorld()->m_pWorld->updateCollisionFilterOnWorld(1, 1); } + break; + } } } @@ -91,7 +106,8 @@ PPC_FUNC(sub_8221A7D8) pGauge->m_Value = (100.0f / pTailsContext->m_FlightDuration) * pTailsContext->m_FlightTime; } - auto pTailsFlight = pPlayer->m_spStateMachine->GetBase()->GetState(); + auto pTailsFlight = pPlayer->GetStateMachine()->GetState(); + auto pGame = App::s_pApp->GetGame(); auto maturityValue = 1.0f; @@ -149,17 +165,17 @@ void PlayerDebugMode_RegisterLuaSetup(PPCRegister& str, PPCRegister& index) switch (index.u32) { - case 0: - *pString = "SetupModuleDebug"; - break; + case 0: + *pString = "SetupModuleDebug"; + break; - case 1: - *pString = "SetupModule"; - break; + case 1: + *pString = "SetupModule"; + break; - case 2: - *pString = "SetupModuleDebug"; - break; + case 2: + *pString = "SetupModuleDebug"; + break; } } @@ -308,41 +324,41 @@ PPC_FUNC(sub_82217FC0) switch (gemIndex) { - case Gem_Yellow: - { - // Prevent Yellow Gem spam. - if (pSonicContext->m_ThunderGuard) - break; - } - - case Gem_Blue: - case Gem_Green: - case Gem_Sky: - case Gem_White: - case Gem_Super: - { - auto spriteIndex = Sonicteam::Player::State::SonicContext::ms_GemSpriteConversionTable[gemIndex - 1] - 1; + case Gem_Yellow: + { + // Prevent Yellow Gem spam. + if (pSonicContext->m_ThunderGuard) + break; + } - if (pSonicGauge->m_Value >= (&pSonicGauge->c_gauge_green)[spriteIndex].get()) - { - ctx.r3.u64 = 1; - return; - } + case Gem_Blue: + case Gem_Green: + case Gem_Sky: + case Gem_White: + case Gem_Super: + { + auto spriteIndex = Sonicteam::Player::State::SonicContext::ms_GemSpriteConversionTable[gemIndex - 1] - 1; - break; + if (pSonicGauge->m_Value >= (&pSonicGauge->c_gauge_green)[spriteIndex].get()) + { + ctx.r3.u64 = 1; + return; } - case Gem_Red: - case Gem_Purple: - { - if (pSonicContext->m_Field24A == 0) - { - ctx.r3.u64 = 1; - return; - } + break; + } - break; + case Gem_Red: + case Gem_Purple: + { + if (pSonicContext->m_Field24A == 0) + { + ctx.r3.u64 = 1; + return; } + + break; + } } ctx.r3.u64 = 0; @@ -368,34 +384,34 @@ PPC_FUNC(sub_82218068) switch (gemIndex) { - case Gem_Blue: - case Gem_Green: - case Gem_Yellow: - case Gem_Sky: - case Gem_White: - case Gem_Super: - { - pSonicGauge->m_Value = pSonicGauge->m_Value.get() - (&pSonicGauge->c_gauge_green)[spriteIndex].get(); - pSonicGauge->m_GroundedTime = 0.0; - break; - } - - case Gem_Red: - case Gem_Purple: - { - pSonicGauge->m_Value = pSonicGauge->m_Value.get() - (&pSonicGauge->c_gauge_green)[spriteIndex].get() * deltaTime; - pSonicGauge->m_GroundedTime = 0.0; + case Gem_Blue: + case Gem_Green: + case Gem_Yellow: + case Gem_Sky: + case Gem_White: + case Gem_Super: + { + pSonicGauge->m_Value = pSonicGauge->m_Value.get() - (&pSonicGauge->c_gauge_green)[spriteIndex].get(); + pSonicGauge->m_GroundedTime = 0.0; + break; + } - if (pSonicGauge->m_Value <= 0) - { - pSonicGauge->m_Value = 0.0; - pSonicContext->m_Shrink = 0; - pSonicContext->m_SlowTime = 0; - pSonicContext->m_Field24A = 1; - } + case Gem_Red: + case Gem_Purple: + { + pSonicGauge->m_Value = pSonicGauge->m_Value.get() - (&pSonicGauge->c_gauge_green)[spriteIndex].get() * deltaTime; + pSonicGauge->m_GroundedTime = 0.0; - break; + if (pSonicGauge->m_Value <= 0) + { + pSonicGauge->m_Value = 0.0; + pSonicContext->m_Shrink = 0; + pSonicContext->m_SlowTime = 0; + pSonicContext->m_Field24A = 1; } + + break; + } } } @@ -459,7 +475,7 @@ PPC_FUNC(sub_8223F360) g_userHeap.Free(pVariableName); } - + void SonicGauge_FixGemSprite(PPCRegister& r) { auto pGame = (Sonicteam::GameImp*)g_memory.Translate(r.u32); @@ -523,3 +539,155 @@ bool InfiniteLives() { return Config::InfiniteLives; } + +#if MARATHON_POSTURECONTROL_USE_RECREATED_VERSION == 1 +PPC_FUNC_IMPL(__imp__sub_82200538); +PPC_FUNC(sub_82200538) +{ + auto PostureControl = (Sonicteam::Player::PostureControl*)(base + ctx.r3.u32); + PostureControl->RecreatedUpdate(ctx.f1.f64); +} +#endif + +//Experimental Edge OC Fix +PPC_FUNC_IMPL(__imp__sub_82203840); +PPC_FUNC(sub_82203840) +{ + auto pSphere = (Sonicteam::Player::IPostureSupportSphere*)(base + ctx.r3.u32); + auto d1 = (Sonicteam::SoX::Math::Vector*)(base + ctx.r4.u32); + auto d2 = *(Sonicteam::SoX::Math::Vector*)(base + ctx.r5.u32); + auto outFlag1 = (be*)(base + ctx.r6.u32); + + if (!Config::EnablePostureImprovements) + { + __imp__sub_82203840(ctx, base); + return; + } + + Sonicteam::SoX::Math::Vector finalPos = d2; + + if (auto allListener = pSphere->m_spAllListener1.get()) + { + auto PNormal = allListener->m_aContactNormals[0]; + auto sphereCenter = d2 + pSphere->m_CollisionAllAngle; + struct _vector_ { Sonicteam::SoX::Math::Vector p1; Sonicteam::SoX::Math::Vector p2; }; + guest_heap_var<_vector_> points(sphereCenter, sphereCenter); + + allListener->m_Position = sphereCenter; + allListener->m_Radius = pSphere->m_aCollisionAllRadius[pSphere->m_FlagC8]; + allListener->SetPostureRequestFlag(pSphere->m_pPostureRequestFlag.get()->get()); + + pSphere->m_aShapeCollisionAll[pSphere->m_FlagC8]->Func3C( + (Sonicteam::SoX::Math::Vector*)points.get(), + static_cast(allListener) + ); + allListener->Update(); + + if ((uint8_t*)outFlag1 != g_memory.base) *outFlag1 = allListener->GetCollisionFlag(); + + auto contactPos = allListener->GetContactPosition() - pSphere->m_CollisionAllAngle; + int contactCount = allListener->GetCurrentSurfaceContacts(); + + if (contactCount > 0) + { + // PROPER SURFACE ANALYSIS + int floorContacts = 0; + int wallContacts = 0; + Sonicteam::SoX::Math::Vector primaryNormal = allListener->m_aContactNormals[0]; + + for (int i = 0; i < contactCount && i < 6; i++) + { + auto& normal = allListener->m_aContactNormals[i]; + printf("normal Y : %f\n\n", normal.Y.get()); + if (normal.Y > 0.39f) // Floor (pointing up) + { + floorContacts++; + } + else if (normal.Y < -0.5f) // Ceiling (pointing down) + { + // Ceiling contact + } + else // Wall (vertical) + { + wallContacts++; + } + } + + printf("SURFACE: %d floors, %d walls, primaryNormal=(%.2f,%.2f,%.2f)\n", + floorContacts, wallContacts, primaryNormal.X.get(), primaryNormal.Y.get(), primaryNormal.Z.get()); + + finalPos = contactPos; + + if (floorContacts >= 2 && wallContacts == 0) + { + bool isTrueEdge = false; + for (int i = 0; i < contactCount - 1 && !isTrueEdge; i++) + { + for (int j = i + 1; j < contactCount && !isTrueEdge; j++) + { + float dot = allListener->m_aContactNormals[i].Dot(allListener->m_aContactNormals[j]).X; + if (dot < 0.7f) // Significantly different normals + { + isTrueEdge = true; + printf("TRUE EDGE: Applying minimal stabilization (dot=%.3f)\n", dot); + } + else if (dot < 0.98) + { + isTrueEdge = true; + printf("ALT TRUE EDGE: Applying minimal stabilization (dot=%.3f)\n", dot); + } + + } + } + + if (isTrueEdge) + { + // Use the highest Y normal for stabilization + Sonicteam::SoX::Math::Vector bestNormal = primaryNormal; + for (int i = 1; i < contactCount && i < 6; i++) + { + if (allListener->m_aContactNormals[i].Y > bestNormal.Y) + { + bestNormal = allListener->m_aContactNormals[i]; + } + } + + // TINY push in best normal direction + finalPos = d2; + } + else if (floorContacts == 2) + { + // Two similar floor contacts - micro stabilization only + finalPos = finalPos + (primaryNormal * 2.0); + printf("DOUBLE FLOOR: Micro stabilization\n"); + } + } + else if (floorContacts > 0 && wallContacts > 0) + { + // Floor-wall mix - small stabilization + finalPos.Y = finalPos.Y + 0.02f; + printf("FLOOR-WALL: Minimal stabilization\n"); + } + else + { + // Single floor or other cases - use raw contact position + printf("Using raw contact position\n"); + } + } + else + { + finalPos = d2; + } + } + + if (d1) *d1 = finalPos; + + if (pSphere->m_spAllListener1.get()->GetCurrentSurfaceContacts() > 0) + { + ctx.r3.u32 = (uint32_t)(uintptr_t)pSphere->m_spAllListener1.get(); + } + else + { + ctx.r3.u32 = 0; + } +} diff --git a/MarathonRecomp/ui/message_window.cpp b/MarathonRecomp/ui/message_window.cpp index 96023d4d..189c1b99 100644 --- a/MarathonRecomp/ui/message_window.cpp +++ b/MarathonRecomp/ui/message_window.cpp @@ -325,7 +325,7 @@ void MessageWindow::Draw() // Always assume keyboard to prevent mouse from blocking control in-game. isKeyboard = true; - if (auto& spInputManager = App::s_pApp->m_pDoc->m_vspInputManager[0]) + if (auto& spInputManager = App::s_pApp->m_pDoc->m_vspInputManagers[0]) { auto& rPadState = spInputManager->m_PadState; diff --git a/MarathonRecomp/ui/options_menu.cpp b/MarathonRecomp/ui/options_menu.cpp index d478490f..2621f65d 100644 --- a/MarathonRecomp/ui/options_menu.cpp +++ b/MarathonRecomp/ui/options_menu.cpp @@ -1034,7 +1034,7 @@ void OptionsMenu::Draw() { if (s_commonMenu.IsOpen()) { - for (auto& spInputManager : App::s_pApp->m_pDoc->m_vspInputManager) + for (auto& spInputManager : App::s_pApp->m_pDoc->m_vspInputManagers) { auto& rPadState = spInputManager->m_PadState; diff --git a/MarathonRecomp/user/config_def.h b/MarathonRecomp/user/config_def.h index 2b2412c0..d7d6cefc 100644 --- a/MarathonRecomp/user/config_def.h +++ b/MarathonRecomp/user/config_def.h @@ -79,12 +79,13 @@ CONFIG_DEFINE_HIDDEN("Codes", bool, ControllableBoundAttack, false, false); CONFIG_DEFINE_HIDDEN("Codes", bool, ControllableSpinkick, false, false); CONFIG_DEFINE_HIDDEN("Codes", bool, ControllableTeleportDash, false, false); CONFIG_DEFINE_HIDDEN("Codes", bool, DisableDWMRoundedCorners, false, true); -CONFIG_DEFINE_HIDDEN("Codes", bool, DisableEdgeGrabLeftover, false, false); +CONFIG_DEFINE_HIDDEN("Codes", bool, EnablePostureImprovements, false, false); CONFIG_DEFINE_HIDDEN("Codes", bool, DisableKingdomValleyMist, false, false); CONFIG_DEFINE_HIDDEN("Codes", bool, DisableLowResolutionFontOnCustomUI, false, false); CONFIG_DEFINE_HIDDEN("Codes", bool, DisablePushState, false, false); CONFIG_DEFINE_HIDDEN("Codes", bool, DisableTitleInputDelay, false, false); CONFIG_DEFINE_HIDDEN("Codes", bool, EnableDebugMode, false, false); +CONFIG_DEFINE_HIDDEN("Codes", bool, AlwaysResetSpringState, false, false); CONFIG_DEFINE_HIDDEN("Codes", bool, FixPowerUpJingleDuration, false, false); CONFIG_DEFINE_HIDDEN("Codes", bool, HUDToggleKey, false, false); CONFIG_DEFINE_HIDDEN("Codes", bool, InfiniteLives, false, false); diff --git a/vcpkg.json b/vcpkg.json index 6b97ca18..57f49f11 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -10,7 +10,8 @@ "platform": "windows" }, "freetype", - "curl" + "curl", + "directxmath" ], "vcpkg-configuration": { "overlay-triplets": [