diff --git a/hooks/AlliedRangeRings.hook b/hooks/AlliedRangeRings.hook new file mode 100644 index 00000000..3a06f951 --- /dev/null +++ b/hooks/AlliedRangeRings.hook @@ -0,0 +1,15 @@ +0x007A7858: + jmp asm__ShouldAddUnit + nop + +0x007EF12B: + push esp + mov ecx, esi + call RenderRange__Moho__UserUnit__UserUnit + nop + +0x005BF011: + mov ecx, edi + mov edx, eax + call Hooked_SyncVisionRange + jmp 0x005BF02C diff --git a/hooks/RangeRings.cpp b/hooks/RangeRings.cpp deleted file mode 100644 index 06d89645..00000000 --- a/hooks/RangeRings.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "../define.h" -asm( - ".section h0; .set h0,0x7F944D;" - "call "QU(RangeRings)";" -); diff --git a/include/LuaAPI.h b/include/LuaAPI.h index 8944bf68..2faf78b3 100644 --- a/include/LuaAPI.h +++ b/include/LuaAPI.h @@ -125,7 +125,7 @@ struct TObject { inline TObject() : tt{LUA_TNIL} {} }; -VALIDATE_SIZE(TObject, 8) +VALIDATE_SIZE(TObject, 8); // namespace gpg namespace gpg @@ -150,7 +150,7 @@ class LuaStackObject { LuaState *m_state; int m_stackIndex; }; -VALIDATE_SIZE(LuaStackObject, 8) +VALIDATE_SIZE(LuaStackObject, 8); extern const char *luaT_typenames[] asm("0x00D474D8"); @@ -280,7 +280,7 @@ class LuaObject { // 0x14 bytes LuaObject __Clone(LuaObject &backref) const; void RemoveFromUsedList(); }; -VALIDATE_SIZE(LuaObject, 0x14) +VALIDATE_SIZE(LuaObject, 0x14); enum StandardLibraries { LIB_NONE, LIB_BASE, LIB_OSIO }; class LuaState { // 0x34 bytes @@ -316,7 +316,7 @@ class LuaState { // 0x34 bytes LuaObject *m_prev; // only valid when in used list } m_headObject, m_tailObject; }; -VALIDATE_SIZE(LuaState, 0x34) +VALIDATE_SIZE(LuaState, 0x34); lua_State *__cdecl luaV_settable(lua_State *L, const TObject *t, const TObject *key, diff --git a/include/Maths.h b/include/Maths.h deleted file mode 100644 index 1b0f9c34..00000000 --- a/include/Maths.h +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once -#include - -class Vector3f -{ -public: - float x, y, z; - - Vector3f() : x(0.0f), y(0.0f), z(0.0f) {} - Vector3f(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {} - - Vector3f(const Vector3f &other) : x(other.x), y(other.y), z(other.z) {} - - Vector3f &operator=(const Vector3f &other) - { - if (this != &other) - { - x = other.x; - y = other.y; - z = other.z; - } - return *this; - } - - Vector3f operator+(const Vector3f &other) const - { - return Vector3f(x + other.x, y + other.y, z + other.z); - } - - Vector3f operator-(const Vector3f &other) const - { - return Vector3f(x - other.x, y - other.y, z - other.z); - } - - Vector3f operator*(float scalar) const - { - return Vector3f(x * scalar, y * scalar, z * scalar); - } - - friend Vector3f operator*(float scalar, const Vector3f &vec) - { - return vec * scalar; - } - - float dot(const Vector3f &other) const - { - return x * other.x + y * other.y + z * other.z; - } - - Vector3f cross(const Vector3f &other) const - { - return Vector3f( - y * other.z - z * other.y, - z * other.x - x * other.z, - x * other.y - y * other.x); - } - - float length() const - { - return sqrtf(x * x + y * y + z * z); - } - - Vector3f normalized() const - { - float len = length(); - if (len > 0) - return {x / len, y / len, z / len}; - - return *this; - } - - Vector3f &operator+=(const Vector3f &other) - { - x += other.x; - y += other.y; - z += other.z; - return *this; - } - - Vector3f &operator-=(const Vector3f &other) - { - x -= other.x; - y -= other.y; - z -= other.z; - return *this; - } - - Vector3f &operator*=(float scalar) - { - x *= scalar; - y *= scalar; - z *= scalar; - return *this; - } -}; \ No newline at end of file diff --git a/include/PatchBase.h b/include/PatchBase.h index c7069bfe..de704c47 100644 --- a/include/PatchBase.h +++ b/include/PatchBase.h @@ -6,14 +6,19 @@ (*(type*)addr) #define CSTR(name, addr) \ -extern const char name[] asm(#addr); + extern const char name[] asm(#addr) #define GDecl(name, addr, type) \ - extern type name asm(#addr); + extern type name asm(#addr) #define WDecl(addr, type) \ ((type)*(uintptr_t*)addr) #define VALIDATE_SIZE(struc, size) \ - static_assert(sizeof(struc) == size, "Invalid structure size of " #struc); \ No newline at end of file + static_assert(sizeof(struc) == size, "Invalid structure size of " #struc) + +#pragma clang diagnostic ignored "-Winvalid-offsetof" +#pragma GCC diagnostic ignored "-Winvalid-offsetof" +#define VALIDATE_OFFSET(struc, member, offset) \ + static_assert(offsetof(struc, member) == offset, "Invalid offset of " #member " in " #struc) diff --git a/include/Wm3.h b/include/Wm3.h new file mode 100644 index 00000000..29736509 --- /dev/null +++ b/include/Wm3.h @@ -0,0 +1,156 @@ +#pragma once + +template +struct Vector2 +{ + R x, y; +}; +using Vector2i = Vector2; +using Vector2f = Vector2; + +template +class Vector3 +{ +public: + using value_t = R; + + R x, y, z; + + Vector3() : x(0), y(0), z(0) {} + Vector3(R x_, R y_, R z_) : x(x_), y(y_), z(z_) {} + + Vector3(const Vector3 &other) : x(other.x), y(other.y), z(other.z) {} + + Vector3 &operator=(const Vector3 &other) + { + if (this != &other) + { + x = other.x; + y = other.y; + z = other.z; + } + return *this; + } + + Vector3 operator+(const Vector3 &other) const + { + return Vector3(x + other.x, y + other.y, z + other.z); + } + + Vector3 operator-(const Vector3 &other) const + { + return Vector3(x - other.x, y - other.y, z - other.z); + } + + Vector3 operator*(R scalar) const + { + return Vector3(x * scalar, y * scalar, z * scalar); + } + + friend Vector3 operator*(R scalar, const Vector3 &vec) + { + return vec * scalar; + } + + R dot(const Vector3 &other) const + { + return x * other.x + y * other.y + z * other.z; + } + + Vector3 cross(const Vector3 &other) const + { + return Vector3( + y * other.z - z * other.y, + z * other.x - x * other.z, + x * other.y - y * other.x); + } + + float length() const + { + return sqrtf(x * x + y * y + z * z); + } + + Vector3 normalized() const + { + float len = length(); + if (len > 0) + return {x / len, y / len, z / len}; + + return *this; + } + + Vector3 &operator+=(const Vector3 &other) + { + x += other.x; + y += other.y; + z += other.z; + return *this; + } + + Vector3 &operator-=(const Vector3 &other) + { + x -= other.x; + y -= other.y; + z -= other.z; + return *this; + } + + Vector3 &operator*=(R scalar) + { + x *= scalar; + y *= scalar; + z *= scalar; + return *this; + } +}; +using Vector3f = Vector3; + +template +struct Vector4 +{ // 0x10 bytes + R x, y, z, w; +}; +using Vector4f = Vector4; + +template +struct Quaternion +{ + R x, y, z, w; +}; +using Quaternionf = Quaternion; + +template +struct Rect2 +{ + R x0, z0, x1, z1; +}; +using Rect2i = Rect2; + +template +struct Circle2 +{ + Vector2 Center; + R Radius; + + Circle2(R x, R y, R r): + Center{x, y}, + Radius{r} + {} +}; +using Circle2f = Circle2; + +template +struct Plane3 +{ + Vector3 Normal; + R Constant; +}; +using Plane3f = Plane3; + +template +struct AxisAlignedBox3 +{ + Vector3 Min; + Vector3 Max; +}; +using AxisAlignedBox3f = AxisAlignedBox3; diff --git a/include/crt.h b/include/crt.h new file mode 100644 index 00000000..49c74a7c --- /dev/null +++ b/include/crt.h @@ -0,0 +1,162 @@ +#pragma once + +#include "global.h" + +typedef int unk_t; +typedef int BOOL; +typedef int SOCKET; + +struct FILE +{ + char *_ptr; + int _cnt; + char *_base; + int _flag; + int _file; + int _charbuf; + int _bufsiz; + char *_tmpfname; +}; + +struct typeInfo +{ // 0x8+ bytes + void *vtable; + int zero; + char name[]; +}; + +template +struct pair +{ + S first; + T second; +}; + +struct _Container_base +{ + uint32_t gap; +}; + +template +struct vector : _Container_base +{ // 0x10 bytes + T *begin, *end, *capacity_end; + + T operator[](int i) { return begin[i]; } + size_t size() { return begin ? end - begin : 0; } +}; +VALIDATE_SIZE(vector, 0x10); + +template +struct set : _Container_base +{ + struct _Node + { + _Node *_Left; + _Node *_Parent; + _Node *_Right; + T _Myval; + char _Color; + char _Isnil; + }; + + _Node *_Myhead; + size_t _Mysize; +}; + +template +struct map : _Container_base { + struct _Node { + _Node *_Left; // 0x00 + _Node *_Parent; // 0x04 + _Node *_Right; // 0x08 + struct { + K first; // 0x0C + V second; // 0x10 + } _Myval; + char _Color; // 0x14 + char _Isnil; // 0x19 + }; + + _Node *_Myhead; // 0x04 + size_t _Mysize; // 0x08 + + size_t size() const { + return _Mysize; + } + + struct iterator { + _Node* _Ptr; + iterator(_Node* p) : _Ptr(p) {} + auto* operator->() const { return &(_Ptr->_Myval); } + bool operator==(const iterator& other) const { return _Ptr == other._Ptr; } + bool operator!=(const iterator& other) const { return _Ptr != other._Ptr; } + }; + iterator end() const { + return iterator(_Myhead); + } + + iterator find(const K& key) const { + if (!_Myhead || _Mysize == 0) return end(); + + _Node* node = _Myhead->_Parent; + _Node* result = _Myhead; + + while (node && !node->_Isnil) { + if (key < node->_Myval.first) { + node = node->_Left; + } + else if (key > node->_Myval.first) { + node = node->_Right; + } + else { + result = node; + break; + } + } + + return iterator(result); + } + bool contains(const K& key) const { + return find(key) != end(); + } +}; + + +template +struct list : _Container_base +{ // 0xC bytes + struct _Node + { + _Node *_Next; + _Node *_Prev; + T _Myval; + }; + + _Node *_Myhead; + size_t _Mysize; +}; +VALIDATE_SIZE(list, 0xC); + +#define _DEQUESIZ (sizeof (_Ty) <= 1 ? 16 \ + : sizeof (_Ty) <= 2 ? 8 \ + : sizeof (_Ty) <= 4 ? 4 \ + : sizeof (_Ty) <= 8 ? 2 : 1) /* elements per block (a power of 2) */ + +template +struct deque : _Container_base +{ + struct block + { + _Ty vals[_DEQUESIZ]; + } * _Map; + size_t _Mapsize; + size_t _Myoff; + size_t _Mysize; +}; + +template> +struct queue +{ + _Container c; +}; diff --git a/include/global.h b/include/global.h index 0ea2becb..609c6106 100644 --- a/include/global.h +++ b/include/global.h @@ -16,33 +16,35 @@ #define g_ConsoleLuaState GPtr(0x10A6478, LuaState*) #define g_Device GPtr(0x0F8E284, Device*) -GDecl(ui_ProgressBarColor, 0x0F57BB8, int) -GDecl(ui_SelectTolerance, 0x0F57A90, float) -GDecl(ui_ExtractSnapTolerance, 0x0F57A94, float) -GDecl(ui_DisableCursorFixing, 0x10A6464, bool) -GDecl(ui_RenderIcons, 0x0F57B27, bool) -GDecl(range_RenderSelected, 0x10A640A, bool) -GDecl(range_RenderHighlighted, 0x10A640B, bool) -GDecl(range_RenderBuild, 0x10A6414, bool) -GDecl(d3d_WindowsCursor, 0x10A636E, bool) -GDecl(debugSelect, 0x10A645E, bool) - -CSTR(s_FACTORY, 0xE19824) -CSTR(s_EXPERIMENTAL, 0xE204B8) -CSTR(s_ExpectedButGot, 0xE0A220) // "%s\n expected %d args, but got %d" -CSTR(s_ExpectedBetweenButGot, 0xE0A270) // "%s\n expected between %d and %d args, but got %d" -CSTR(s_Global, 0xE00D90) // "" -CSTR(s_CMauiBitmap, 0xE37438) // "CMauiBitmap" -CSTR(s_UserUnit, 0xE4D090) // "UserUnit" -CSTR(s_ExpectedAGameObject, 0xE09860) // "Expected a game object. (Did you call with '.' instead of ':'?)" -CSTR(s_GameObjectHasBeenDestroyed, 0xE098A0) // "Game object has been destroyed" -CSTR(s_IncorrectTypeOfGameObject, 0xE098C0) // "Incorrect type of game object. (Did you call with '.' instead of ':'?)" -CSTR(s_UnknownColor, 0xE07D14) // "Unknown color: %s" -CSTR(s_c_object, 0xE016DC) // "_c_object" - -GDecl(g_ExeVersion1, 0x876666, const int) -GDecl(g_ExeVersion2, 0x87612d, const int) -GDecl(g_ExeVersion3, 0x4d3d40, const int) +GDecl(ui_ProgressBarColor, 0x0F57BB8, int); +GDecl(ui_SelectTolerance, 0x0F57A90, float); +GDecl(ui_ExtractSnapTolerance, 0x0F57A94, float); +GDecl(ui_DisableCursorFixing, 0x10A6464, bool); +GDecl(ui_RenderIcons, 0x0F57B27, bool); +GDecl(range_RenderSelected, 0x10A640A, bool); +GDecl(range_RenderHighlighted, 0x10A640B, bool); +GDecl(range_RenderBuild, 0x10A6414, bool); +GDecl(d3d_WindowsCursor, 0x10A636E, bool); +GDecl(debugSelect, 0x10A645E, bool); + +CSTR(s_FACTORY, 0xE19824); +CSTR(s_EXPERIMENTAL, 0xE204B8); +CSTR(s_ExpectedButGot, 0xE0A220); // "%s\n expected %d args, but got %d" +CSTR(s_ExpectedBetweenButGot, 0xE0A270); // "%s\n expected between %d and %d args, but got %d" +CSTR(s_Global, 0xE00D90); // "" +CSTR(s_CMauiBitmap, 0xE37438); // "CMauiBitmap" +CSTR(s_UserUnit, 0xE4D090); // "UserUnit" +CSTR(s_ExpectedAGameObject, 0xE09860); // "Expected a game object. (Did you call with '.' instead of ':'?)" +CSTR(s_GameObjectHasBeenDestroyed, 0xE098A0); // "Game object has been destroyed" +CSTR(s_IncorrectTypeOfGameObject, 0xE098C0); // "Incorrect type of game object. (Did you call with '.' instead of ':'?)" +CSTR(s_UnknownColor, 0xE07D14); // "Unknown color: %s" +CSTR(s_c_object, 0xE016DC); // "_c_object" +CSTR(s_addVizError, 0x00E36248); // "Moho::CIntelCounterHandle::AddViz: unsupported counter intel type %i" +CSTR(s_subVizError, 0x00E36290); // "Moho::CIntelCounterHandle::SubViz: unsupported counter intel type %i" + +GDecl(g_ExeVersion1, 0x876666, const int); +GDecl(g_ExeVersion2, 0x87612d, const int); +GDecl(g_ExeVersion3, 0x4d3d40, const int); void AbortF(wchar_t *fmt, ...) asm("0x9C4940"); int LogF(const char *fmt, ...) asm("0x937CB0"); @@ -133,9 +135,9 @@ template struct basic_string { ~basic_string() { clear(); } }; -VALIDATE_SIZE(string, 0x1C) +VALIDATE_SIZE(string, 0x1C); static_assert(string::sso_size == 0x10); -VALIDATE_SIZE(wstring, 0x1C) +VALIDATE_SIZE(wstring, 0x1C); static_assert(wstring::sso_size == 0x8); template @@ -159,4 +161,4 @@ template T &GetField(void *ptr, size_t offset) { return *Offset(ptr, offset); -} \ No newline at end of file +} diff --git a/include/lua/lua.h b/include/lua/lua.h index 0e9f1558..0f1fa1f8 100644 --- a/include/lua/lua.h +++ b/include/lua/lua.h @@ -124,10 +124,9 @@ namespace lua } lua_State; } // namespace lua -// const int a = sizeof(lua::global_State); VALIDATE_SIZE(lua::lua_State, 0x70); VALIDATE_SIZE(lua::global_State, 0x1B8); -static_assert(offsetof(lua::global_State, tmname) == 0x5c, "Invalid tmname offset"); +VALIDATE_OFFSET(lua::global_State, tmname, 0x5c); #define setobj(obj1, obj2) \ { \ @@ -153,4 +152,4 @@ void __cdecl luaD_call(lua::lua_State *L, lua::StkId func, int nResults) asm("0x lua::TObject *__cdecl luaH_set(lua::lua_State *L, lua::Table *t, const lua::TObject *key) asm("0x00927560"); const lua::TObject *__cdecl luaT_gettmbyobj(lua::lua_State *L, const lua::TObject *o, lua::TMS event) asm("0x00928450"); void luaG_runerror(lua::lua_State *L, const char *msg, ...) asm("0x00913270"); -void __cdecl luaG_typeerror(lua::lua_State *L, const lua::TObject *obj, const char *oper) asm("0x009133A0"); \ No newline at end of file +void __cdecl luaG_typeerror(lua::lua_State *L, const lua::TObject *obj, const char *oper) asm("0x009133A0"); diff --git a/include/magic_classes.h b/include/magic_classes.h index 529d4cc5..f63ed10f 100644 --- a/include/magic_classes.h +++ b/include/magic_classes.h @@ -57,7 +57,7 @@ class ConDescReg static_assert(!std::is_same_v, "Not supported type!"); } }; -VALIDATE_SIZE(ConDescReg, 0x10) +VALIDATE_SIZE(ConDescReg, 0x10); //int v; -//ConDescReg myConIntV{"name", "desc", &v}; \ No newline at end of file +//ConDescReg myConIntV{"name", "desc", &v}; diff --git a/include/moho.h b/include/moho.h index b0736215..ea7cf05b 100644 --- a/include/moho.h +++ b/include/moho.h @@ -1,10 +1,418 @@ #pragma once #include "LuaAPI.h" -#include "Maths.h" +#include "Wm3.h" +#include "crt.h" + +using EntId = uint32_t; +using CmdId = uint32_t; + + +template +inline constexpr T min(T a, T b) { + return a > b ? b : a; +} +template +inline constexpr T max(T a, T b) { + return a > b ? a : b; +} +inline constexpr int ifloor(float v) { + return (int) v; +} +inline constexpr int iceil(float v) { + return -ifloor(-v); +} + + + +// hoist all forward declarations +struct CAiBuilderImpl; +struct CAiFormationDBImpl; +struct CAiFormationInstance; +struct CAiPersonality; +struct CAiReconDBImpl; +struct CAiSteeringImpl; +struct CAiTransportImpl; +struct CAniActor; +struct CAniPose; +struct CArmyImpl; +struct CArmyStats; +struct CCommandDB; +struct CDebugCanvas; +struct CDecalBuffer; +struct CD3DBatchTexture; +struct CEconomy; +struct CEffectManagerImpl; +struct CFormationInstance; +struct CInfluenceMap; +struct CSimConVarInstanceBase; +struct CSimSoundManager; +struct CSndParams; +struct CTask; +struct CTaskStage; +struct CTextureScroller; +struct CUnitCommand; +struct CUnitCommandQueue; +struct CUnitMotion; +struct CWldSession; +struct CWldTerrainRes; +struct Entity; +struct EntityDB; +struct EntityOccupationGrid; +struct HSndEntityLoop; +struct IAiCommandDispatch; +struct IAiNavigator; +struct IUnit; +struct MeshInstance; +struct PathTables; +struct PathQueue; +struct RBlueprint; +struct RScmResource; +struct Sim; +struct SParticleBuffer; +struct STIMap; +struct Unit; +struct UserUnit; +struct UserUnitManager; +struct WeakObject; + + + +enum EAiTargetType : __int32 +{ + AITARGET_None = 0, + AITARGET_Entity = 1, + AITARGET_Ground = 2, +}; + +enum ECollisionShape : __int32 +{ + COLSHAPE_None = 0, + COLSHAPE_Box = 1, + COLSHAPE_Sphere = 2, +}; + +// just Moho::EIntel - 1 it appears +enum EEntityAttribute +{ + ENTATTR_Vision = 0, + ENTATTR_WaterVision = 1, + ENTATTR_Radar = 2, + ENTATTR_Sonar = 3, + ENTATTR_Omni = 4, + ENTATTR_RadarStealthField = 5, + ENTATTR_SonarStealthField = 6, + ENTATTR_CloakField = 7, + ENTATTR_Jammer = 8, + ENTATTR_Spoof = 9, + ENTATTR_Cloak = 10, + ENTATTR_RadarStealth = 11, + ENTATTR_SonarStealth = 12, +}; + +enum EEntityType : __int32 +{ + ENTITYTYPE_Unit = 0x100, + ENTITYTYPE_Prop = 0x200, + ENTITYTYPE_Projectile = 0x400, + ENTITYTYPE_Entity = 0x800, +}; + +enum EFireState : __int32 +{ + FIRESTATE_ReturnFire = 0, + FIRESTATE_HoldFire = 1, + FIRESTATE_HoldGround = 2, + FIRESTATE_Mix = -1, +}; + +enum EFootprintFlags : __int8 +{ + FPFLAG_None = 0, + FPFLAG_IgnoreStructures = 1, +}; + +enum EIntel : __int32 +{ + INTEL_None = 0, + INTEL_Vision = 1, + INTEL_WaterVision = 2, + INTEL_Radar = 3, + INTEL_Sonar = 4, + INTEL_Omni = 5, + INTEL_RadarStealthField = 6, + INTEL_SonarStealthField = 7, + INTEL_CloakField = 8, + INTEL_Jammer = 9, + INTEL_Spoof = 10, + INTEL_Cloak = 11, + INTEL_RadarStealth = 12, + INTEL_SonarStealth = 13, +}; + +enum EIntelCounter : __int32 +{ + INTELCOUNTER_RadarStealthField = 0x1, + INTELCOUNTER_SonarStealthField = 0x2, + INTELCOUNTER_CloakField = 0x8, +}; + +enum EJobType : __int32 +{ + JOB_None = 0, + JOB_Build = 1, + JOB_Repair = 2, + JOB_Reclaim = 3, +}; + +enum ELayer : __int32 +{ + LAYER_None = 0x0, + LAYER_Land = 0x1, + LAYER_Seabed = 0x2, + LAYER_Sub = 0x4, + LAYER_Water = 0x8, + LAYER_Air = 0x10, + LAYER_Orbit = 0x20, + LAYER_All = 0x7F, +}; + +enum EOccupancyCaps : unsigned __int8 +{ + OC_LAND = 0x1, + OC_SEABED = 0x2, + OC_SUB = 0x4, + OC_WATER = 0x8, + OC_AIR = 0x10, + OC_ORBIT = 0x20, + OC_ANY = 0xFF, +}; + +enum EReconFlags : __int32 +{ + RECON_None = 0x0, + RECON_Radar = 0x1, + RECON_Sonar = 0x2, + RECON_RadarSonar = 0x3, + RECON_Omni = 0x4, + RECON_AnyPing = 0x7, + RECON_LOSNow = 0x8, + RECON_AnySense = 0xF, + RECON_LOSEver = 0x10, + RECON_Exposed = 0x1C, + RECON_KnownFake = 0x20, + RECON_MaybeDead = 0x40, +}; + +enum ERuleBPUnitBuildRestriction : __int32 +{ + RULEUBR_None = 0, + RULEUBR_Bridge = 1, + RULEUBR_OnMassDeposit = 2, + RULEUBR_OnHydrocarbonDeposit = 3, +}; + +enum ERuleBPUnitCommandCaps : __int32 +{ + RULEUCC_Move = 0x1, + RULEUCC_Stop = 0x2, + RULEUCC_Attack = 0x4, + RULEUCC_Guard = 0x8, + RULEUCC_Patrol = 0x10, + RULEUCC_RetaliateToggle = 0x20, + RULEUCC_Repair = 0x40, + RULEUCC_Capture = 0x80, + RULEUCC_Transport = 0x100, + RULEUCC_CallTransport = 0x200, + RULEUCC_Nuke = 0x400, + RULEUCC_Tactical = 0x800, + RULEUCC_Teleport = 0x1000, + RULEUCC_Ferry = 0x2000, + RULEUCC_SiloBuildTactical = 0x4000, + RULEUCC_SiloBuildNuke = 0x8000, + RULEUCC_Sacrifice = 0x10000, + RULEUCC_Pause = 0x20000, + RULEUCC_Overcharge = 0x40000, + RULEUCC_Dive = 0x80000, + RULEUCC_Reclaim = 0x100000, + RULEUCC_SpecialAction = 0x200000, + RULEUCC_Dock = 0x400000, + RULEUCC_Script = 0x800000, + RULEUCC_Invalid = 0x1000000, +}; + +enum ERuleBPUnitMovementType : __int32 +{ + RULEUMT_None = 0, + RULEUMT_Land = 1, + RULEUMT_Air = 2, + RULEUMT_Water = 3, + RULEUMT_Biped = 4, + RULEUMT_SurfacingSub = 5, + RULEUMT_Amphibious = 6, + RULEUMT_Hover = 7, + RULEUMT_AmphibiousFloating = 8, + RULEUMT_Spec = 9, +}; + +enum ERuleBPUnitToggleCaps : __int32 +{ + RULEUTC_ShieldToggle = 0x1, + RULEUTC_WeaponToggle = 0x2, + RULEUTC_JammingToggle = 0x4, + RULEUTC_IntelToggle = 0x8, + RULEUTC_ProductionToggle = 0x10, + RULEUTC_StealthToggle = 0x20, + RULEUTC_GenericToggle = 0x40, + RULEUTC_SpecialToggle = 0x80, + RULEUTC_CloakToggle = 0x100, +}; + +enum ERuleBPUnitWeaponBallisticArc : __int32 +{ + RULEUBA_None = 0, + RULEUBA_LowArc = 1, + RULEUBA_HighArc = 2, +}; + +enum ERuleBPUnitWeaponTargetType : __int32 +{ + RULEWTT_Unit = 0, + RULEWTT_Projectile = 1, + RULEWTT_Prop = 2, +}; + +enum ESiloType : __int32 +{ + SILOTYPE_Tactical = 0, + SILOTYPE_Nuke = 1, +}; + +enum ETransportClass : __int32 +{ + TRANSPORTCLASS_1 = 1, + TRANSPORTCLASS_2 = 2, + TRANSPORTCLASS_3 = 3, + TRANSPORTCLASS_4 = 4, + TRANSPORTCLASS_SPECIAL = 5, +}; + +enum EUnitState : __int32 +{ + UNITSTATE_Immobile = 1, + UNITSTATE_Moving = 2, + UNITSTATE_Attacking = 3, + UNITSTATE_Guarding = 4, + UNITSTATE_Building = 5, + UNITSTATE_Upgrading = 6, + UNITSTATE_WaitingForTransport = 7, + UNITSTATE_TransportLoading = 8, + UNITSTATE_TransportUnloading = 9, + UNITSTATE_MovingDown = 10, + UNITSTATE_MovingUp = 11, + UNITSTATE_Patrolling = 12, + UNITSTATE_Busy = 13, + UNITSTATE_Attached = 14, + UNITSTATE_BeingReclaimed = 15, + UNITSTATE_Repairing = 16, + UNITSTATE_Diving = 17, + UNITSTATE_Surfacing = 18, + UNITSTATE_Teleporting = 19, + UNITSTATE_Ferrying = 20, + UNITSTATE_WaitForFerry = 21, + UNITSTATE_AssistMoving = 22, + UNITSTATE_PathFinding = 23, + UNITSTATE_ProblemGettingToGoal = 24, + UNITSTATE_NeedToTerminateTask = 25, + UNITSTATE_Capturing = 26, + UNITSTATE_BeingCaptured = 27, + UNITSTATE_Reclaiming = 28, + UNITSTATE_AssistingCommander = 29, + UNITSTATE_Refueling = 30, + UNITSTATE_GuardBusy = 31, + UNITSTATE_ForceSpeedThrough = 32, + UNITSTATE_UnSelectable = 33, + UNITSTATE_DoNotTarget = 34, + UNITSTATE_LandingOnPlatform = 35, + UNITSTATE_CannotFindPlaceToLand = 36, + UNITSTATE_BeingUpgraded = 37, + UNITSTATE_Enhancing = 38, + UNITSTATE_BeingBuilt = 39, + UNITSTATE_NoReclaim = 40, + UNITSTATE_NoCost = 41, + UNITSTATE_BlockCommandQueue = 42, + UNITSTATE_MakingAttackRun = 43, + UNITSTATE_HoldingPattern = 44, + UNITSTATE_SiloBuildingAmmo = 45, +}; + +enum EUnitStateMask : __int64 +{ + UNITSTATEMASK_Immobile = 0x2LL, + UNITSTATEMASK_Moving = 0x4LL, + UNITSTATEMASK_Attacking = 0x8LL, + UNITSTATEMASK_Guarding = 0x10LL, + UNITSTATEMASK_Building = 0x20LL, + UNITSTATEMASK_Upgrading = 0x40LL, + UNITSTATEMASK_WaitingForTransport = 0x80LL, + UNITSTATEMASK_TransportLoading = 0x100LL, + UNITSTATEMASK_TransportUnloading = 0x200LL, + UNITSTATEMASK_MovingDown = 0x400LL, + UNITSTATEMASK_MovingUp = 0x800LL, + UNITSTATEMASK_Patrolling = 0x1000LL, + UNITSTATEMASK_Busy = 0x2000LL, + UNITSTATEMASK_Attached = 0x4000LL, + UNITSTATEMASK_BeingReclaimed = 0x8000LL, + UNITSTATEMASK_Repairing = 0x10000LL, + UNITSTATEMASK_Diving = 0x20000LL, + UNITSTATEMASK_Surfacing = 0x40000LL, + UNITSTATEMASK_Teleporting = 0x80000LL, + UNITSTATEMASK_Ferrying = 0x100000LL, + UNITSTATEMASK_WaitForFerry = 0x200000LL, + UNITSTATEMASK_AssistMoving = 0x400000LL, + UNITSTATEMASK_PathFinding = 0x800000LL, + UNITSTATEMASK_ProblemGettingToGoal = 0x1000000LL, + UNITSTATEMASK_NeedToTerminateTask = 0x2000000LL, + UNITSTATEMASK_Capturing = 0x4000000LL, + UNITSTATEMASK_BeingCaptured = 0x8000000LL, + UNITSTATEMASK_Reclaiming = 0x10000000LL, + UNITSTATEMASK_AssistingCommander = 0x20000000LL, + UNITSTATEMASK_Refueling = 0x40000000LL, + UNITSTATEMASK_GuardBusy = 0x80000000LL, + UNITSTATEMASK_ForceSpeedThrough = 0x100000000LL, + UNITSTATEMASK_UnSelectable = 0x200000000LL, + UNITSTATEMASK_DoNotTarget = 0x400000000LL, + UNITSTATEMASK_LandingOnPlatform = 0x800000000LL, + UNITSTATEMASK_CannotFindPlaceToLand = 0x1000000000LL, + UNITSTATEMASK_BeingUpgraded = 0x2000000000LL, + UNITSTATEMASK_Enhancing = 0x4000000000LL, + UNITSTATEMASK_BeingBuilt = 0x8000000000LL, + UNITSTATEMASK_NoReclaim = 0x10000000000LL, + UNITSTATEMASK_NoCost = 0x20000000000LL, + UNITSTATEMASK_BlockCommandQueue = 0x40000000000LL, + UNITSTATEMASK_MakingAttackRun = 0x80000000000LL, + UNITSTATEMASK_HoldingPattern = 0x100000000000LL, + UNITSTATEMASK_SiloBuildingAmmo = 0x200000000000LL, +}; + +enum EVisibilityMode : __int32 +{ + VIZMODE_Never = 0x1, + VIZMODE_Always = 0x2, + VIZMODE_Intel = 0x4, +}; + +enum UnitWeaponRangeCategory : __int32 +{ + UWRC_Undefined = 0, + UWRC_DirectFire = 1, + UWRC_IndirectFire = 2, + UWRC_AntiAir = 3, + UWRC_AntiNavy = 4, + UWRC_Countermeasure = 5, +}; + -typedef int BOOL; -typedef int unk_t; struct luaFuncDescReg { // 0x1C bytes @@ -16,107 +424,224 @@ struct luaFuncDescReg lua_CFunction FuncPtr; // code address void *ClassPtr; // C++ class type address. NULL if class none }; -VALIDATE_SIZE(luaFuncDescReg, 0x1C) +VALIDATE_SIZE(luaFuncDescReg, 0x1C); -// Probably from visual c++ 9 -struct vtable; -struct typeInfo -{ // 0x8+ bytes - void *vtable; - int zero; - char name[]; +template +struct fastvector +{ + T *mStart; + T *mEnd; + T *mCapacity; + + fastvector() { + this->mStart = &this->mCapacity; + this->mEnd = &this->mCapacity; + this->mCapacity = &this->mCapacity; + } + ~fastvector() { + delete[](this->mStart); + } + + T *begin() { return this->mStart; } + T *end() { return this->mEnd; } + + bool Empty() const { + return this->mStart == this->mEnd; + } + size_t Size() const { + return (this->mEnd - this->mStart) / sizeof(T); + } + size_t Capacity() const { + return (this->mCapacity - this->mStart) / sizeof(T); + } + + T &operator[](size_t idx) { + return this->mStart[idx]; + } +}; + +template +struct fastvector_n : public fastvector +{ + // also stores the original capacity at [0] when not in use + // (i.e. the zeroeth index in the inline vec) + T *mOriginalVec; + T mInlineVec[N]; + + fastvector_n() { + this->mStart = &this->mInlineVec[0]; + this->mEnd = &this->mInlineVec[0]; + this->mCapacity = &this->mInlineVec[N]; + this->mOriginalVec = &this->mInlineVec; + } + ~fastvector_n() { + if (this->mStart != this->mOriginalVec) { + delete[](this->mStart); + this->mStart = this->mOriginalVec; + } + } +}; + +template +struct shared_ptr +{ + T *px; + void *pn; // boost::detail::shared_count + + T &operator*() { + return *this->px; + } + T *operator->() { + return this->px; + } + T *get() { + return this->px; + } + operator bool() { + return this->px != nullptr; + } }; -struct classDesc -{ // 0x30+ bytes - // at 0x4 - uint32_t trueDataOffset; // Subtraction - // at 0xC - void *typeInfo; - // at 0x20 - void *beginParents; // +0x4 - void *endParents; // -0x4 - // at 0x28 - classDesc *parents[]; - // void* typeInfo; +// T extends WeakObject +template +struct WeakPtr +{ + WeakObject *mObj; + WeakPtr *mNext; + + operator T*() { + return this->get(); + } + T &operator*() { + return *this->get(); + } + T *operator->() { + return this->get(); + } + T *get() { + // this couldn't have been how it was done; since Moho::Unit inherits + // Moho::WeakObject from both Moho::IUnit and Moho::Entity, it becomes + // ambiguous and I've had to change all `WeakPtr` to + // `WeakPtr` + return static_cast(this->mObj); + } }; -struct vtable -{ // 0x8+ bytes - // at -0x4 - void *classDesc; - void *methods[]; +struct WeakObject +{ + WeakPtr *mNextUse; }; -template -struct vector -{ // 0x10 bytes - uint32_t pad; - T *begin, *end, *capacity_end; +template +struct TDatListItem +{ + TDatListItem *mPrev; + TDatListItem *mNext; +}; - T operator[](int i) { return begin[i]; } - size_t size() { return begin ? end - begin : 0; } +template +struct TDatList : TDatListItem +{ + TDatListItem *begin() { return this->mPrev; } + TDatListItem *end() { return this->mPrev; } }; -VALIDATE_SIZE(vector, 0x10) -template -struct list -{ // 0xC bytes - T *begin, *end, *capacity_end; +struct BVIntSet +{ + uint32_t mStart; + uint32_t gap; + fastvector_n mBuckets; + + uint32_t BucketFor(uint32_t val) const { + return (val >> 5) - this->mStart; + } + uint32_t MaskFor(uint32_t val) const { + return 1 << (val & 0x1F); + } + + void EnsureBounds(uint32_t lower, uint32_t upper) { + asm( + "push %[lower];" + "push %[self];" + "call 0x00401980;" + : + : [self] "g" (this), [lower] "g" (lower), "c" (upper) + : + ); + } + + void Add(uint32_t val) { + this->EnsureBounds(val, val + 1); + uint32_t bucket = this->BucketFor(val); + this->mBuckets[bucket] |= this->MaskFor(val); + } + + void Clear(uint32_t val) { + uint32_t bucket = this->BucketFor(val); + this->mBuckets[bucket] &= ~this->MaskFor(val); + } - T operator[](int i) { return begin[i]; } - size_t size() { return begin ? end - begin : 0; } + void Set(uint32_t val, bool add) { + if (add) { + this->Add(val); + } else { + this->Clear(val); + } + } }; -VALIDATE_SIZE(list, 0xC) +VALIDATE_SIZE(BVIntSet, 0x20); -template -struct linked_list -{ // 0x8 bytes - T *next; - T *prev; +template +struct BVSet +{ + U mHelper; + BVIntSet mSet; }; -struct moho_set -{ // 0x20 bytes - int baseI; - int unk1; - uint32_t *begin, *end, *capacity_end; - void *unk2; - uint32_t value; // Memory for 'Short Set Optimization' - void *unk3; +struct RRuleGameRules +{ + void *vtable; + CWldTerrainRes *res; +}; - void set(uint32_t item, bool set) - { - auto *itemPtr = &begin[item >> 5 - baseI]; - if (itemPtr >= end) - end = itemPtr + 1; - item = 1 << (item & 0x1F); - if (set) - *itemPtr |= item; - else - *itemPtr &= ~item; - } - bool operator[](int item) - { - auto *itemPtr = &begin[item >> 5 - baseI]; - if (itemPtr >= end) - return false; - return *itemPtr & (1 << (item & 0x1F)); - } +struct CDiskWatchListener +{ + void *vtable; + TDatList v4; + void *mWatch; // CDiskWatch * + vector mEvents; // vector + vector mPatterns; }; -VALIDATE_SIZE(moho_set, 0x20) -typedef int SOCKET; -// GPGCore +struct EntityCategoryHelper +{ + RRuleGameRules *mRules; + uint32_t gap; +}; + +using EntityCategory = BVSet; + +struct SPointVector +{ + Vector3f mPoint; + Vector3f mVector; +}; -struct Vector2f -{ // 0x8 bytes - float x, z; +struct VMatrix4 +{ + Vector4f d[4]; }; -struct Vector4f -{ // 0x10 bytes - float x, y, z, w; +struct VTransform +{ + Quaternionf orient; + Vector3f pos; +}; + +template +struct SMinMax +{ + T mMin, mMax; }; struct RObject @@ -131,24 +656,18 @@ struct ObjectType const static int Info = TInfo; }; -struct CScriptObject : RObject -{ // 0x004C6F8A, 0x34 bytes - linked_list ll; - LuaObject UserData; - LuaObject Table; -}; -VALIDATE_SIZE(CScriptObject, 0x34) - -struct WeakObject -{ // 0x8 bytes? - void *vtable; - void *Unk1; +struct CScriptObject : RObject, WeakObject +{ + int gap; + LuaObject mCObject; + LuaObject mLuaObject; }; +VALIDATE_SIZE(CScriptObject, 0x34); -struct gpg_mutex +struct mutex { - int unk1; - bool unk2; // If value is 0 then NTDLL.RtlEnterCriticalSection is bypassed + void *m_mutex; + bool m_critical_section; }; struct Stream @@ -200,8 +719,6 @@ struct CMauiControl : CScriptObject using Type = ObjectType<0x10C7700, 0xF83314>; }; -struct CWldSession; - struct CUIWorldView : CMauiControl { // 0x004C6F8A, 0x2A8 bytes using Type = ObjectType<0x10C77E4, 0xF8A71C>; @@ -222,23 +739,6 @@ struct CUIWorldView : CMauiControl } }; -struct RBlueprint; - -struct RRuleGameRules -{ // 0x00529158, 0xD0 bytes - void *vtable; - // at 0x2C - // list L1; - // at 0x48 - // list L2; - // at 0xB8 - list Blueprints; - // list L3; - // at 0xC4 - // void *Blueprints; - // void *Start, *End; -}; - struct LaunchInfoNew { // 0x005423CC, 0xA4 bytes void *vtable; @@ -259,12 +759,44 @@ struct LaunchInfoNew int unk4; }; +struct CTaskThread : TDatListItem, WeakObject +{ + CTaskStage *mStage; + CTask *mTask; + int val1; + bool mStaged; +}; + +struct CTaskStage +{ + TDatList mThreads; + CTaskThread *mPrev; + CTaskThread *mNext; + bool unk; +}; + struct REffectBlueprint : RObject { + uint32_t gap; + string mBlueprintId; + bool mHighFidelity; + bool mMedFidelity; + bool mLowFidelity; }; struct RBeamBlueprint : REffectBlueprint { // 0x0050EEFD, 0x84 bytes + float mLength; + float mLifetime; + float mThickness; + float mUShift; + float mVShift; + string mTextureName; + Vector4f mStartColor; + Vector4f mEndColor; + float mLODCutoff; + float mRepeatRate; + int mBlendmode; }; struct RBlueprint : RObject @@ -277,116 +809,574 @@ struct RBlueprint : RObject string source; // example: /units/uel0001/uel0001_unit.bp uint32_t BlueprintOrdinal; }; +VALIDATE_SIZE(RBlueprint, 0x60); + +struct RMeshBlueprintLOD +{ + string mMeshName; + string mAlbedoName; + string mSpecularName; + string mLookupName; + string mSecondaryName; + string mShaderName; + string mStr; + float mLODCutoff; + bool mScrolling; + bool mOcclude; + bool mSilhouette; +}; struct RMeshBlueprint : RBlueprint { // 0x0050DD83, 0x80 bytes - // at 0x70 - float IconFadeInZoom; + vector mLODs; + float mIconFadeInZoom; + float mSortOrder; + float mUniformScale; + bool mStraddleWater; +}; +VALIDATE_SIZE(RMeshBlueprint, 0x80); +struct SFootprint +{ + uint8_t mSizeX; + uint8_t mSizeZ; + EOccupancyCaps mOccupancyCaps; + EFootprintFlags mFlags; + float mMaxSlope; + float mMinWaterDepth; + float mMaxWaterDepth; }; -struct REntityBlueprint : RBlueprint -{ // ~0x17C bytes - // at 0x60 - vector Categories; +struct SNamedFootprint : SFootprint +{ + string mName; + int mIndex; +}; - // at 0xD8 - struct SFootprint - { - char SizeX; - char SizeZ; - char OccupancyCaps; - char Flags; - float MaxSlope; - float MinWaterDepth; - float unk1; - } Footprint, AltFootprint; +struct REntityBlueprint : RBlueprint +{ + vector mCategories; + string mScriptModule; + string mScriptClass; + ECollisionShape mCollisionShape; + float mSizeX; + float mSizeY; + float mSizeZ; + float mAverageDensity; + float mInertiaTensorX; + float mInertiaTensorY; + float mInertiaTensorZ; + float mCollisionOffsetX; + float mCollisionOffsetY; + float mCollisionOffsetZ; + int mDesiredShooterCap; + SFootprint mFootprint; + SFootprint mAltFootprint; + bool mLifeBarRender; + float mLifeBarOffset; + float mLifeBarSize; + float mLifeBarHeight; + float mSelectionSizeX; + float mSelectionSizeY; + float mSelectionSizeZ; + float mSelectionCenterOffsetX; + float mSelectionCenterOffsetY; + float mSelectionCenterOffsetZ; + float mSelectionYOffset; + float mSelectionMeshScaleX; + float mSelectionMeshScaleY; + float mSelectionMeshScaleZ; + float mSelectionMeshUseTopAmount; + float mSelectionThickness; + float mUseOOBTestZoom; + string mStrategicIconName; + char mStrategicIconSortPriority; + WeakPtr mStrategicIconRest; + WeakPtr mStrategicIconSelected; + WeakPtr mStrategicIconOver; + WeakPtr mStrategicIconSelectedOver; }; struct RPropBlueprint : REntityBlueprint { // 0x0050DD83, 0x1AC bytes + + struct RPropBlueprintDisplay + { + string mMeshBlueprint; + float mUniformScale; + } mDisplay; + struct RPropBlueprintDefense + { + float mMaxHealth; + float mHealth; + } mDefense; + struct RPropBlueprintEconomy + { + float mReclaimMassMax; + float mReclaimEnergyMax; + } mEconomy; }; +VALIDATE_SIZE(RPropBlueprint, 0x1AC); struct RProjectileBlueprint : REntityBlueprint { // 0x0050DD83, 0x268 bytes -}; + + string mDevStatus; + struct RProjectileBlueprintDisplay + { + string mMeshBlueprint; + float mUniformScale; + float mMeshScaleRange; + float mMeshScaleVelocity; + float mMeshScaleVelocityRange; + bool mCameraFollowsProjectile; + float mCameraFollowTimeout; + float mStrategicIconSize; + } mDisplay; + struct RProjectileBlueprintEconomy + { + float mBuildCostEnergy; + float mBuildCostMass; + float mBuildTime; + } mEconomy; + struct RProjectileBlueprintPhysics + { + bool mCollideSurface; + bool mCollisionEntity; + bool mTrackTarget; + bool mVelocityAlign; + bool mStayUpright; + bool mLeadTarget; + bool mStayUnderwater; + bool mUseGravity; + float mDetonateAboveHeight; + float mDetonateBelowHeight; + float mTurnRate; + float mTurnRateRange; + float mLifetime; + float mLifeTimeRange; + float mInitialSpeed; + float mInitialSpeedRange; + float mMaxSpeed; + float mMaxSpeedRange; + float mAcceleration; + float mAccelerationRange; + float mPositionX; + float mPositionY; + float mPositionZ; + float mPositionXRange; + float mPositionYRange; + float mPositionZRange; + float mDirectionX; + float mDirectionY; + float mDirectionZ; + float mDirectionXRange; + float mDirectionYRange; + float mDirectionZRange; + float mRotationalVelocity; + float mRotationalVelocityRange; + float mMaxZigZag; + float mZigZagFrequency; + bool mDestroyOnWater; + int mMinBounceCount; + int mMaxBounceCount; + float mBounceVelDamp; + bool mRealisticOrdinance; + bool mStraightDownOrdinance; + } mPhysics; +}; +VALIDATE_SIZE(RProjectileBlueprint, 0x268); struct RUnitBlueprintWeapon { // 0x184 bytes -}; + uint32_t gap[2]; + string mLabel; + string mDisplayName; + UnitWeaponRangeCategory mRangeCategory; + bool mDummyWeapon; + bool mPrefersPrimaryWeaponTarget; + bool mStopOnPrimaryWeaponBusy; + bool mSlavedToBody; + float mSlavedToBodyArcRange; + bool mAutoInitiateAttackCommand; + float mTargetCheckInterval; + bool mAlwaysRecheckTarget; + float mMinRadius; + float mMaxRadius; + float mMaximumBeamLength; + float mEffectiveRadius; + float mMaxHeightDiff; + float mTrackingRadius; + float mHeadingArcCenter; + float mHeadingArcRange; + float mFiringTolerance; + float mFiringRandomness; + float mRequiresEnergy; + float mRequiresMass; + float mMuzzleVelocity; + float mMuzzleVelocityRandom; + float mMuzzleVelocityReduceDistance; + bool mLeadTarget; + float mProjectileLifetime; + float mProjectileLifetimeUsesMultiplier; + float mDamage; + float mDamageRadius; + string mDamageType; + float mRateOfFire; + string mProjectileId; + ERuleBPUnitWeaponBallisticArc mBallisticArc; + string mTargetRestrictOnlyAllow; + string mTargetRestrictOnlyDisallow; + bool mManualFire; + bool mNukeWeapon; + bool mOverChargeWeapon; + bool mNeedPrep; + bool mCountedProjectile; + int mMaxProjectileStorage; + bool mIgnoresAlly; + ERuleBPUnitWeaponTargetType mTargetType; + int mAttackGroundTries; + bool mAimsStraightOnDisable; + bool mTurreted; + bool mYawOnlyOnTarget; + bool mAboveWaterFireOnly; + bool mBelowWaterFireOnly; + bool mAboveWaterTargetsOnly; + bool mBelowWaterTargetsonly; + bool mReTargetOnMiss; + bool mNeedToComputeBombDrop; + float mBombDropThreshold; + bool mUseFiringSolutionInsteadOfAimBone; + bool mIgnoreIfDisabled; + bool mCannotAttackGround; + string mUIMinRangeVisualId; + string mUIMaxRangeVisualId; +}; +VALIDATE_SIZE(RUnitBlueprintWeapon, 0x184); struct RUnitBlueprint : REntityBlueprint { // 0x0050DD83, 0x568 bytes // at 0x17C struct RUnitBlueprintGeneral { - } General; + ERuleBPUnitCommandCaps mCommandCaps; + ERuleBPUnitToggleCaps mToggleCaps; + string mUpgradesTo; + string mUpgradesFrom; + string mUpgradesFromBase; + string mSeedUnit; + int mQuickSelectPriority; + float mCapCost; + int mSelectionPriority; + } mGeneral; // at 0x200 struct RUnitBlueprintDisplay { - } Display; + string mDisplayName; + string mMeshBlueprint; + string mPlaceholderMeshName; + string mIconName; + float mUniformScale; + bool mSpawnRandomRotation; + bool mHideLifebars; + } mDisplay; // at 0x278 struct RUnitBlueprintPhysics { - } Physics; + bool mFlattenSkirt; + float mSkirtOffsetX; + float mSkirtOffsetZ; + float mSkirtSizeX; + float mSkirtSizeZ; + float mMaxGroundVariation; + ERuleBPUnitMovementType mMotionType; + ERuleBPUnitMovementType mAltMotionType; + bool mStandUpright; + bool mSinkLower; + bool mRotateBodyWhileMoving; + float mDiveSurfaceSpeed; + float mMaxSpeed; + float mMaxSpeedReverse; + float mMaxAcceleration; + float mMaxBrake; + float mMaxSteerForce; + float mBankingSlope; + float mRollStability; + float mRollDamping; + float mWobbleFactor; + float mWobbleSpeed; + float mTurnRadius; + float mTurnRate; + float mTurnFacingRate; + bool mRotateOnSpot; + float mRotateOnSpotThreshold; + float mElevation; + float mAttackElevation; + float mCatchUpAcc; + float mBackUpDistance; + float mLayerChangeOffsetHeight; + float mLayerTransitionDuration; + ELayer mBuildOnLayerCaps; + ERuleBPUnitBuildRestriction mBuildRestriction; + SFootprint *mFootprint; + SFootprint *mAltFootprint; + float mFuelUseTime; + float mFuelRechargeRate; + float mGroundCollisionOffset; + vector mOccupRects; + vector mRaisedPlatforms; + } mPhysics; // at 0x330 struct RUnitBlueprintIntel { - } Intel; + unsigned int mVisionRadius; + unsigned int mWaterVisionRadius; + unsigned int mRadarRadius; + unsigned int mSonarRadius; + unsigned int mOmniRadius; + bool mRadarStealth; + bool mSonarStealth; + bool mCloak; + bool mShowIntelOnSelect; + unsigned int mRadarStealthFieldRadius; + unsigned int mSonarStealthFieldRadius; + unsigned int mCloakFieldRadius; + SMinMax mJamRadius; + uint8_t mJammerBlips; + SMinMax mSpoofRadius; + } mIntel; // at 0x368 struct RUnitBlueprintAir { - } Air; + bool mCanFly; + bool mWinged; + bool mFlyInWater; + float mAutoLandTime; + float mMaxAirSpeed; + float mMinAirSpeed; + float mTurnSpeed; + float mCombatTurnSpeed; + float mStartTurnDistance; + float mTightTurnMultiplier; + float mSustainedTurnThreshold; + float mLiftFactor; + float mBankFactor; + bool mBankForward; + float mEngageDistance; + float mBreakOffTriggger; + float mBreakOffDistance; + bool mBreakOffIfNearNewTarget; + float mKMove; + float mKMoveDamping; + float mKLift; + float mKLiftDamping; + float mKTurn; + float mKTurnDamping; + float mKRoll; + float mKRollDamping; + float mCirclingTurnMult; + float mCirclingRadiusChangeMinRatio; + float mCirclingRadiusChangeMaxRatio; + float mCirclingRadiusVsAirMult; + float mCirclingElevationChangeRatio; + float mCirclingFlightChangeFrequency; + bool mCirclingDirChange; + bool mHoverOverAttack; + float mRandomBreakOffDistanceMult; + float mRandomMinChangeCombatStateTime; + float mRandomMaxChangeCombatStateTime; + float mTransportHoverHeight; + float mPredictAheadForBombDrop; + } mAir; // at 0x3F8 struct RUnitBlueprintTransport { - // at 0x400 - int T2ClassSize; - int T3ClassSize; - int GenericClassSize; - int SClassSize; - } Transport; + ETransportClass mTransportClass; + int mClassGenericUpTo; + int mClass2AttachSize; + int mClass3AttachSize; + int mClass4AttachSize; + int mClassSAttachSize; + bool mAirClass; + int mStorageSlots; + int mDockingSlots; + float mRepairsRate; + } mTransport; // at 0x420 struct RUnitBlueprintDefense { - // at 0x43C - string ArmorType; - } Defense; + float mMaxHealth; + float mHealth; + float mRegenRate; + float mAirThreatLevel; + float mSurfaceThreatLevel; + float mSubThreatLevel; + float mEconomyThreatLevel; + string mArmorType; + struct RUnitBlueprintDefenseShield + { + float mShieldSize; + float mRegenAssistMult; + } mShield; + } mDefense; // at 0x460 struct RUnitBlueprintAI { - float GuardScanRadius; - float GuardReturnRadius; - float StagingPlatformScanRadius; - bool ShowAssistRangeOnSelect; - string GuardFormationName; - bool NeedUnpack; - bool InitialAutoMode; - string BeaconName; - vector TargetBones; - float RefuelingMultiplier; - float RefuelingRepairAmount; - float RepairConsumeEnergy; - float RepairConsumeMass; - bool AutoSurfaceToAttack; - float AttackAngle; - } AI; + float mGuardScanRadius; + float mGuardReturnRadius; + float mStagingPlatformScanRadius; + bool mShowAssistRangeOnSelect; + string mGuardFormationName; + bool mNeedUnpack; + bool mInitialAutoMode; + string mBeaconName; + vector mTargetBones; + float mRefuelingMultiplier; + float mRefuelingRepairAmount; + float mRepairConsumeEnergy; + float mRepairConsumeMass; + bool mAutoSurfaceToAttack; + float mAttackAngle; + } mAI; // at 0x4D8 - vector Weapon; - + vector mWeapon; + uint32_t gap; // at 0x4E8 struct RUnitBlueprintEconomy { - // at 0x564 - float MaxBuildDistance; - } Economy; + float mBuildCostEnergy; + float mBuildCostMass; + float mBuildRate; + float mBuildTime; + float mStorageEnergy; + float mStorageMass; + bool mNaturalProducer; + vector mBuildableCategories; + vector mRebuildBonusIds; + uint32_t gap; + EntityCategory mCat; + float mInitialRallyX; + float mInitialRallyZ; + bool mNeedToFaceTargetToBuild; + float mSacrificeMassMult; + float mSacrificeEnergyMult; + float mMaxBuildDistance; + } mEconomy; +}; +VALIDATE_SIZE(RUnitBlueprint, 0x568); + +struct SRuleFootprintsBlueprint +{ + list mFootprints; + uint32_t gap; +}; + +struct REmitterCurveKey +{ + float mX; + float mY; + float mZ; +}; + +struct REmitterBlueprintCurve +{ + void *vtable; + float mXRange; + vector mKeys; +}; + +struct REmitterBlueprint +{ + uint32_t gap1; + string mBlueprintId; + uint32_t gap2; + REmitterBlueprintCurve mSizeCurve; + REmitterBlueprintCurve mXDirectionCurve; + REmitterBlueprintCurve mYDirectionCurve; + REmitterBlueprintCurve mZDirectionCurve; + REmitterBlueprintCurve mEmitRateCurve; + REmitterBlueprintCurve mLifetimeCurve; + REmitterBlueprintCurve mVelocityCurve; + REmitterBlueprintCurve mXAccelCurve; + REmitterBlueprintCurve mYAccelCurve; + REmitterBlueprintCurve mZAccelCurve; + REmitterBlueprintCurve mResistanceCurve; + REmitterBlueprintCurve mStartSizeCurve; + REmitterBlueprintCurve mEndSizeCurve; + REmitterBlueprintCurve mInitialRotationCurve; + REmitterBlueprintCurve mRotationRateCurve; + REmitterBlueprintCurve mFrameRateCurve; + REmitterBlueprintCurve mTextureSelectionCurve; + REmitterBlueprintCurve mXPosCurve; + REmitterBlueprintCurve mYPosCurve; + REmitterBlueprintCurve mZPosCurve; + REmitterBlueprintCurve mRampSelectionCurve; + bool mLocalVelocity; + bool mLocalAcceleration; + bool mGravity; + bool mAlignRotation; + bool mAlignToBone; + bool mEmitIfVisible; + bool mCatchupEmit; + bool mCreateIfVisible; + bool mParticleResistance; + bool mFlat; + bool mInterpolateEmission; + bool mSnapToWaterline; + bool mOnlyEmitOnWater; + float mTextureStripcount; + float mSortOrder; + float mLODCutoff; + float mLifetime; + float mRepeattime; + float mTextureFramecount; + int mBlendmode; + string mTextureName; + string mRampTextureName; +}; + +struct RTrailBlueprint +{ + uint32_t gap[2]; + string mBlueprintId; + bool mHighFidelity; + bool mMedFidelity; + bool mLowFidelity; + float mLifetime; + float mTrailLength; + float mSize; + float mSortOrder; + int mBlendMode; + float mLODCutoff; + bool mEmitIfVisible; + bool mCatchupEmit; + float mTextureRepeatRate; + string mRepeatTexture; + string mRampTexture; +}; + +struct RRuleGameRulesImpl : RRuleGameRules, CDiskWatchListener +{ + mutex mLock; + LuaState *mState; + fastvector mMaps; + SRuleFootprintsBlueprint mFootprints; + map mUnitBlueprints; + map mProjectileBlueprints; + map mPropBlueprints; + map mMeshBlueprints; + map mEmitterBlueprints; + map mBeamBlueprints; + map mTrailBlueprints; + map mBlueprints; + vector mCategories; }; struct CUIManager // : IUIManager @@ -395,15 +1385,337 @@ struct CUIManager // : IUIManager LuaState *LState; // from [10A6478] }; -struct CAiReconDBImpl // : IAiReconDB -{ // 0x005BFFB8, 0xB0 bytes - void *vtable; - // at 0xA8 - bool FogOfWar; +struct Array2D +{ + char *mData; + int mSizeX; + int mSizeY; + + char &at(int x, int y) { return this->mData[x + y * this->mSizeX]; } +}; + +struct BitArray2D +{ + int *mData; + int mSize; + int mWidth; + int mHeight; +}; + +struct SDelayedSubVizInfo +{ + Vector3f mPos; + float mRadius; + int mTick; }; struct CIntelGrid -{ // 0x24 bytes +{ + STIMap *mMapData; + Array2D mGrid; + vector mUpdateList; + int mGridSize; + + Circle2f ToGridCircle(Vector3f *pos, float radius); + void Trace(Circle2f &prev, Circle2f &next); +}; +VALIDATE_SIZE(CIntelGrid, 0x24); + +struct SEconValue +{ + float ENERGY; + float MASS; + + SEconValue(float e = 0, float m = 0) : ENERGY{e}, MASS{m} + {} + + SEconValue operator+(const SEconValue &other) + { + return SEconValue{ENERGY + other.ENERGY, MASS + other.MASS}; + } + + SEconValue &operator+=(const SEconValue &other) + { + ENERGY += other.ENERGY; + MASS += other.MASS; + return *this; + } + SEconValue &operator-=(const SEconValue &other) + { + ENERGY -= other.ENERGY; + MASS -= other.MASS; + return *this; + } + + SEconValue operator*(float mul) + { + return SEconValue{ENERGY * mul, MASS * mul}; + } + + SEconValue &operator=(const SEconValue &other) + { + ENERGY = other.ENERGY; + MASS = other.MASS; + return *this; + } +}; + +struct SEconValueDouble +{ + double ENERGY; + double MASS; +}; + +struct SEconTotals +{ + SEconValue mStored; + SEconValue mIncome; + SEconValue mReclaimed; + SEconValue mLastUseRequested; + SEconValue mLastUseActual; + SEconValueDouble mMaxStorage; +}; + +struct SReconKey +{ + WeakPtr mEnt; + EntId mId; +}; + +struct SSTIUnitConstantData +{ + bool unk; + shared_ptr mRoot; // boost::shared_ptr> + bool mFake; // is jamming blip +}; + +struct UnitWeaponInfo +{ + EntityCategory mCat1; + EntityCategory mCat2; + ELayer mLayer; + float mVal1; + float mVal2; + float mVal3; + string mStr1; + string mStr2; +}; + +struct UnitAttributes +{ + RUnitBlueprint *mBlueprint; + uint32_t gap1; + EntityCategory mRestrictionCategory; + float mElevation; + float mSpeedMult; + float mAccMult; + float mTurnMult; + float mBreakOffTriggerMult; + float mBreakOffDistMult; + float mConsumptionPerSecondEnergy; + float mConsumptionPerSecondMass; + float mProductionPerSecondEnergy; + float mProductionPerSecondMass; + float mBuildRate; + float mRegenRate; + ERuleBPUnitCommandCaps mCommandCaps; + ERuleBPUnitToggleCaps mToggleCaps; + bool mReclaimable; + bool mCapturable; + unk_t unk; +}; + +struct SSTIUnitVariableData +{ + EntId mTarget; + int mCreationTick; + bool mAutoMode; + bool mAutoSurfaceMode; + bool mIsBusy; + float mFuelRatio; + float mShieldRatio; + int mStunTicks; + bool mIsPaused; + bool mIsValidTarget; + bool mRepeatQueue; + EJobType mJobType; + EFireState mFireState; + float mWorkProgress; + int mTacticalSiloBuildCount; + int mNukeSiloBuildCount; + int mTacticalSiloStorageCount; + int mNukeSiloStorageCount; + int mTacticalSiloMaxStorageCount; + int mNukeSiloMaxStorageCount; + EntId unk1; + string mCustomName; + SEconValue mProduced; + SEconValue mResourcesSpent; + SEconValue mMaintainenceCost; + EntId mFocusUnit; + EntId mGuardedUnit; + EntId mTargetBlip; + shared_ptr mPriorSharedPose; + shared_ptr mSharedPose; + int unk4; + fastvector_n mCommands; + fastvector_n mBuildQueue; + fastvector_n mWeaponInfo; + UnitAttributes mAttributes; + unsigned int mScriptbits; + uint32_t gap2; + EUnitStateMask mUnitStates; + bool mDidRefresh; + bool mOverchargePaused; +}; + +struct SPerArmyReconInfo +{ + bool mNeedsFlush; + EReconFlags mReconFlags; + void *mSTIMesh; + shared_ptr mMesh; + shared_ptr mPriorPose; + shared_ptr mPose; + float mHealth; + float mMaxHealth; + float mFractionComplete; + bool mMaybeDead; +}; +VALIDATE_SIZE(SPerArmyReconInfo, 0x34); + +struct CIntelPosHandle +{ + struct vtable_t + { + void (__thiscall *AddViz)(CIntelPosHandle *self); + void (__thiscall *SubViz)(CIntelPosHandle *self); + void (__thiscall *dtr)(CIntelPosHandle *self, bool del); + } *vtable; + static vtable_t vftable asm("0x00E361C4"); + + Vector3f mLastPos; // originally the last position checked; now the last position rastered + float mRadius; // now a float + int mLastTickUpdated; // no longer used + bool mEnabled; + shared_ptr mGrid; // not used for counter intel, as they affect all other armies + + void __thiscall UpdatePos(Vector3f *newPos, int curTick); + void __thiscall Update(Vector3f *newPos); + /*virtual*/ void __thiscall AddViz(); + /*virtual*/ void __thiscall SubViz(); + /*pseudo-virtual*/ void TraceViz(Vector3f *newPos); +}; + +struct CIntelCounterHandle : CIntelPosHandle +{ + using CIntelPosHandle::vtable_t; + static vtable_t vftable asm("0x00E361D4"); + + Sim *mSim; + CAiReconDBImpl *mReconDB; + EIntelCounter mType; + + /*virtual*/ void __thiscall AddViz(); + /*virtual*/ void __thiscall SubViz(); + /*pseudo-virtual*/ void TraceViz(Vector3f *newPos); +}; + +struct CIntel +{ + CIntelPosHandle *mExplorationHandle; // unused + CIntelPosHandle *mVisionHandle; + CIntelPosHandle *mWaterHandle; + CIntelPosHandle *mRadarHandle; + CIntelPosHandle *mSonarHandle; + CIntelPosHandle *mOmniHandle; + CIntelCounterHandle *mRCIHandle; + CIntelCounterHandle *mSCIHandle; + CIntelCounterHandle *mVCIHandle; + bool mJamming; + bool mJammingEnabled; + bool mSpoof; + bool mSpoofEnabled; + bool mCloak; + bool mCloakEnabled; + bool mRadarStealth; + bool mRadarStealthEnabled; + bool mSonarStealth; + bool mSonarStealthEnabled; + + void Update(Vector3f *newPos, int curTick); +}; + +class EntityAttributes +{ + unsigned int mVisionRange; + unsigned int mWaterVisionRange; + unsigned int mRadarRange; + unsigned int mSonarRange; + unsigned int mOmniRange; + unsigned int mRadarStealthRange; + unsigned int mSonarStealthRange; + unsigned int mCloakRange; + +public: + unsigned int GetIntelRadius(EEntityAttribute attribute) const { + switch (attribute) { + case ENTATTR_Vision: + return mVisionRange & 0x7FFFFFFF; + case ENTATTR_WaterVision: + return mWaterVisionRange & 0x7FFFFFFF; + case ENTATTR_Radar: + return mRadarRange & 0x7FFFFFFF; + case ENTATTR_Sonar: + return mSonarRange & 0x7FFFFFFF; + case ENTATTR_Omni: + return mOmniRange & 0x7FFFFFFF; + + case ENTATTR_Cloak: + return mCloakRange & 0x7FFFFFFF; + case ENTATTR_RadarStealth: + return mRadarStealthRange & 0x7FFFFFFF; + case ENTATTR_SonarStealth: + return mSonarStealthRange & 0x7FFFFFFF; + case ENTATTR_RadarStealthField: + case ENTATTR_SonarStealthField: + case ENTATTR_CloakField: + case ENTATTR_Jammer: + case ENTATTR_Spoof: + default: + return 0; + } + } + void SetIntelRadius(EEntityAttribute attribute, unsigned int radius) { + switch (attribute) { + case ENTATTR_Vision: + mVisionRange = radius | (mVisionRange & 0x80000000); + break; + case ENTATTR_WaterVision: + mWaterVisionRange = radius | (mWaterVisionRange & 0x80000000); + break; + case ENTATTR_Radar: + mRadarRange = radius | (mRadarRange & 0x80000000); + break; + case ENTATTR_Sonar: + mSonarRange = radius | (mSonarRange & 0x80000000); + break; + case ENTATTR_Omni: + mOmniRange = radius | (mOmniRange & 0x80000000); + break; + case ENTATTR_Cloak: + mCloakRange = radius | (mCloakRange & 0x80000000); + break; + case ENTATTR_RadarStealth: + mRadarStealthRange = radius | (mRadarStealthRange & 0x80000000); + break; + case ENTATTR_SonarStealth: + mSonarStealthRange = radius | (mSonarStealthRange & 0x80000000); + break; + default: + break; + } + } }; struct IClientManager @@ -430,12 +1742,12 @@ struct SSTICommandSource int protocol; // -1 SinglePlayer, 3 MultiPlayer }; -struct Deposit +struct ResourceDeposit { // 0x14 bytes int X1, Z1, X2, Z2; // Rect int Type; // 1 - Mass, 2 - Energy }; -VALIDATE_SIZE(Deposit, 0x14); +VALIDATE_SIZE(ResourceDeposit, 0x14); struct CSimResources // : ISimResources // : IResources { // 0x007444EF, 0x1C bytes @@ -447,9 +1759,9 @@ struct CSimResources // : ISimResources // : IResources uint8_t pad[0xC]; // at 0x10 - list deposits; + fastvector deposits; }; -VALIDATE_SIZE(CSimResources, 0x1C) +VALIDATE_SIZE(CSimResources, 0x1C); struct SWldSessionInfo { // 0x30 bytes @@ -471,193 +1783,381 @@ struct SWldSessionInfo int unk2; // = 255 possibly cmdSourceIndex }; -struct SimArmyEconomyInfo -{ // 0x60 bytes - void *unk1; - int unk2; - float _incomeEnergy; // div 10 - float _incomeMass; // div 10 - - float baseIncomeEnergy; // div 10 - float baseIncomeMass; // div 10 - float storedEnergy; - float storedMass; - - float incomeEnergy; // div 10 - float incomeMass; // div 10 - float reclaimedEnergy; - float reclaimedMass; - - float requestedEnergy; // div 10 - float requestedMass; // div 10 - float expenseEnergy; // div 10 - float expenseMass; // div 10 +struct SSTIArmyVariableData +{ + SEconTotals mEcon; + bool mResourceSharing; + uint32_t gap1; + BVIntSet mNeutrals; + BVIntSet mAllies; + BVIntSet mEnemies; + bool mIsAlly; + uint32_t gap2; + BVIntSet mValidCommandSources; + uint32_t mPlayerColor; + uint32_t mArmyColor; + string mArmyType; + int mFaction; + bool mUseWholeMap; + vector mVec; + uint32_t gap3; + bool mShowScore; + uint32_t gap4; + EntityCategory mCat; + bool mIsOutOfGame; + Vector2f mArmystart; + int mNoRushTimer; + float mNoRushRadius; + float mNoRushOffSetX; + float mNoRushOffSetY; + float mHasHandicap; + float mHandicap; + uint32_t gap5; +}; +VALIDATE_SIZE(SSTIArmyVariableData, 0x160); + +struct SSTIArmyConstantData +{ + int mIndex; + string mArmyName; + string mPlayerName; + bool mIsCivilian; + shared_ptr mVisionReconGrid; + shared_ptr mWaterReconGrid; + shared_ptr mRadarReconGrid; + shared_ptr mSonarReconGrid; + shared_ptr mOmniReconGrid; + shared_ptr mRCIReconGrid; + shared_ptr mSCIReconGrid; + shared_ptr mVCIReconGrid; +}; +VALIDATE_SIZE(SSTIArmyConstantData, 0x80); + +struct IArmy +{ + SSTIArmyConstantData mConstDat; + SSTIArmyVariableData mVarDat; + + bool IsAlly(int armyIndex) const { + if ( armyIndex == -1 ) + return 0; + auto v3 = (armyIndex >> 5) - mVarDat.mAllies.mStart; + return v3 < mVarDat.mAllies.mBuckets.mEnd - mVarDat.mAllies.mBuckets.mStart + && ((mVarDat.mAllies.mBuckets.mStart[v3] >> (armyIndex & 31)) & 1) != 0; + } +}; +VALIDATE_SIZE(IArmy, 0x1E0); - uint32_t maxEnergy; - int unk3; - uint32_t maxMass; - int unk4; +struct BaseArmy +{ + void *vtable; + unk_t unk; +}; - float unk5; - uint32_t isResourceSharing; - float unk6; - float unk7; +struct SimArmy : BaseArmy, IArmy +{ }; +VALIDATE_SIZE(SimArmy, 0x1E8); -struct BaseArmy -{ // 0x1DC bytes - // struct 0x80 bytes - int armyIndex; - string name; - string nickname; - bool isCivilian; - uint8_t pad1[3]; - uint8_t unk1[0x40]; - // at 0x80 - // struct 0x15C bytes - float storedEnergy; - float storedMass; - float incomeEnergy; // div 10 - float incomeMass; // div 10 - float reclaimedEnergy; - float reclaimedMass; - float requestedEnergy; // div 10 - float requestedMass; // div 10 - float expenseEnergy; // div 10 - float expenseMass; // div 10 - // at 0xA8 - uint32_t maxEnergy; - int unk2; // =0 - uint32_t maxMass; - int unk3; // =0 - bool isResourceSharing; - uint8_t pad2[7]; - // at 0xC0 - moho_set neutrals; - moho_set allies; - moho_set enemies; - // at 0x120 - bool IsAlly; - uint8_t pad3[7]; - moho_set mValidCommandSources; - uint32_t color; - uint32_t iconColor; - string mArmyType; // 'human' for players - // at 0x16C - int faction; - bool unk4; - uint8_t pad4[7]; - uint32_t unk5[4]; - bool showScore; - uint8_t pad5[7]; - uint32_t unk6; - uint32_t pad6; - uint32_t unk7; - uint32_t pad7; - uint32_t unk8[6]; - // at 0x1B8 - bool outOfGame; - uint8_t pad8[3]; - Vector2f StartPosition; - uint32_t unk9; - float noRushRadius; - float noRushOffsetX; - float noRushOffsetY; - float unk10; - float unk11; -}; -VALIDATE_SIZE(BaseArmy, 0x1DC); - -struct UserArmy : BaseArmy +struct UserArmy : IArmy { // 0x210 bytes - // at 0x1DC - uint8_t unk12[8]; + uint32_t gap1; // at 0x1E4 - CWldSession *session; - uint8_t unk13[0x28]; + CWldSession *mSession; + uint32_t gap2[4]; + map mEngineers; + map mFactories; + }; VALIDATE_SIZE(UserArmy, 0x210); -struct Sim; +struct SBuildReserveInfo +{ + WeakPtr mUnit; + WeakPtr mCom; +}; + +struct CAiBrain : CScriptObject +{ + CArmyImpl *mArmy; + CArmyImpl *mCurrentEnemy; + CAiPersonality *mPersonality; + string mCurrentPlan; + vector mAttackVectors; + uint32_t gap; + EntityCategory mCat; + map mBuildStructurePositions; + Sim *mSim2; + CTaskStage *mAiThreads; + CTaskStage *mAttackerThreads; + CTaskStage *mThreads; +}; + +struct CEconStorage +{ + CEconomy *mEconomy; + SEconValue mAmt; +}; + +struct CEconRequest : TDatListItem +{ + SEconValue mPerSecond; + SEconValue mAddWhenSetOff; +}; + +struct CEconomy +{ + Sim *mSim; + int mIndex; + SEconValue mResources; + SEconValue v4; + SEconTotals mTotals; + CEconStorage *extraStorage; + bool mResourceSharing; + TDatList mConsumptionData; +}; + + +struct CAiTarget +{ + EAiTargetType targetType; + TDatList mList; + Vector3f mPosition; + int mTargetPoint; + bool mTargetIsMobile; +}; -struct SimArmy // : IArmy, BaseArmy -{ // 0x006FD332, 0x288 bytes +struct ITask +{ void *vtable; - void *unk1; - // at 0x8, BaseArmy - int armyIndex; - string name; - string nickname; - // at 0x44 - bool isCivilian; - uint8_t pad1[0x40]; - - // at 0x88 Copy from [[self+1F4]+18] - float storedEnergy; - float storedMass; - float incomeEnergy; // div 10 - float incomeMass; // div 10 - float reclaimedEnergy; - float reclaimedMass; - float requestedEnergy; // div 10 - float requestedMass; // div 10 - float expenseEnergy; // div 10 - float expenseMass; // div 10 - - uint32_t maxEnergy; - int unk2; // =0 - uint32_t maxMass; - int unk3; // =0 - bool isResourceSharing; - uint8_t pad2[4]; - // at 0xC8 - moho_set neutrals; - moho_set allies; - moho_set enemies; - // at 0x128 - bool IsAlly; - uint8_t pad3[4]; - // at 0x130 - moho_set mValidCommandSources; - // at 0x150 - uint32_t color; - uint32_t iconColor; - string mArmyType; // 'human' for players - // at 0x174 - int faction; - uint8_t pad4[0x48]; - // at 0x1C0 - bool outOfGame; - // at 0x1C4 - Vector2f StartPosition; - uint8_t pad5[0x4]; - // at 0x1D0 - float noRushRadius; - float noRushOffsetX; - float noRushOffsetY; - uint8_t pad6[0xC]; - // at 0x1E8 - Sim *sim; - void *CAiBrain; - // at 0x1F0 - void *CAiReconDBImpl; - SimArmyEconomyInfo *EconomyInfo; - // at 0x1F8 - string unk4; - uint8_t pad7[0x5C]; - // at 0x270 - float unitCap; - uint8_t pad8[4]; - // at 0x278 - int pathCap_Land; - int pathCap_Sea; - int pathCap_Both; - uint8_t pad9[4]; + unk_t unk; + bool *mDestroyed; + CTaskThread *mTaskThread; + CTask *mSubtask; +}; + +struct CTask : ITask +{ + bool mIsOwning; +}; +VALIDATE_SIZE(CTask, 0x18); + +struct SSTIEntityAttachInfo +{ + EntId mEnt; +}; + +struct SEntAttachInfo +{ + int *v0; + int v1; + int mBone; + int v3; + VTransform mParentOrientation; +}; + +struct SSTIEntityVariableData +{ + shared_ptr mScmResource; + RMeshBlueprint *mMesh; + Vector3f mScale; + float mHealth; + float mMaxHealth; + bool mIsBeingBuilt; + bool mIsDead; + bool mRequestRefreshUI; + VTransform mCurTransform; + VTransform mLastTransform; + float mCurImpactSomething; + float mFractionComplete; + EntId mAttachmentParent; + fastvector_n mAttachInfo; + uint32_t unk; + Vector2f mScroll1; + Vector2f mScroll2; + CSndParams *mAmbientSound; + CSndParams *mRumbleSound; + bool mNotVisibility; + EVisibilityMode mVisibility; + ELayer mLayer; + bool mUsingAltFp; + shared_ptr mUnderlayTexture; + EntityAttributes mAttributes; +}; +VALIDATE_OFFSET(SSTIEntityVariableData, mAttributes, 0xB0); + +struct SSTIEntityConstantData +{ + EntId mId; + REntityBlueprint *mBlueprint; + uint32_t mTickCreated; +}; + +struct PositionHistory +{ + VTransform mHistory[25]; + int mCurrent; +}; + +struct CColPrimitive +{ + void *vtable; +}; + +struct SPhysBody +{ + float mGravity; + float mMass; + Vector3f mInvInertiaTensor; + Vector3f mCollisionOffset; + Vector3f mPos; + Quaternionf mOrientation; + Vector3f mVelocity; + Vector3f mWorldImpulse; +}; + +struct Motor +{ + void *vtable; +}; + +struct MotorFallDown : Motor, CScriptObject +{ + float mDirection; + float mAngle; + float mDepth; + bool mFlag; +}; + +struct MotorSinkAway : Motor, CScriptObject +{ + float mDY; +}; + +template +struct EntitySetTemplate : TDatListItem> +{ + fastvector_n mVec; +}; + +struct CollisionDBRect +{ + unsigned __int16 xPos; + unsigned __int16 xSize; + unsigned __int16 zPos; + unsigned __int16 zSize; +}; + +struct CollisionShapeBase : CollisionDBRect +{ + EntityOccupationGrid *mGrid; + bool mMarked; +}; + +struct Entity : CScriptObject, CTask, CollisionShapeBase +{ + EEntityType mType; + TDatList mTargets; + SSTIEntityConstantData mConstDat; + int32_t gap1; + SSTIEntityVariableData mVarDat; + Sim *mSim; + CArmyImpl *mArmy; + VTransform mLastTrans; + PositionHistory *mPositionHistory; + float mLastImpactSomething; + int mLastTickProcessed; + CColPrimitive *mCollisionShape; + vector mAttachedEntities; + SEntAttachInfo mAttachInfo; + bool unk1; + bool mDestroyQueued; + bool mDestroyed; + string mResId; + CIntel *mIntelManager; + EVisibilityMode mVizToFocusPlayer; + EVisibilityMode mVizToAllies; + EVisibilityMode mVizToEnemies; + EVisibilityMode mVizToNeutrals; + bool mInterfaceCreated; + CTextureScroller *mScroller; + SPhysBody *mPhysBody; + bool unk2; + string mUniqueName; + EntitySetTemplate mShooters; + AxisAlignedBox3f mCollision; + LuaObject mObjPos; + Motor *mMotor; +}; +VALIDATE_OFFSET(Entity, mType, 0x5C); +VALIDATE_OFFSET(Entity, mSim, 0x148); +VALIDATE_SIZE(Entity, 0x270); + +struct Shield : Entity +{}; + +struct ReconBlip : Entity +{ + WeakPtr mCreator; + bool mDeleteWhenStale; + Vector3f mJamOffset; + SSTIUnitConstantData mConstDat; + SSTIUnitVariableData mVarDat; + vector mReconDat; +}; +VALIDATE_OFFSET(ReconBlip, mReconDat, 0x4C0); +VALIDATE_SIZE(ReconBlip, 0x4D0); + +struct CPlatoon : CScriptObject +{ + using Type = ObjectType<0x10C6FCC, 0xF6A1FC>; }; -VALIDATE_SIZE(SimArmy, 0x288); struct CArmyImpl : SimArmy -{ // 0x006FD332, 0x288 bytes +{ + Sim *mSim; + CAiBrain *mBrain; + CAiReconDBImpl *mReconDB; + CEconomy *mEconomy; + string mArmyPlans; + CArmyStats *mArmyStats; + CInfluenceMap *mIMmap; + PathQueue *mPathFinder; + uint32_t gap1[2]; + fastvector_n mPlatoons; + vector> v149; + int v153; + int v154; + float mUnitCap; + bool mIgnoreUnitCap; + uint32_t mPathCapLand; + uint32_t mPathCapSea; + uint32_t mPathCapBoth; + uint32_t unk; +}; +VALIDATE_SIZE(CArmyImpl, 0x288); + +struct CAiReconDBImpl // : IAiReconDB +{ // 0x005BFFB8, 0xB0 bytes + void *vtable; + map mBlipMap; + vector mBlipList; + vector mOrphans; + CArmyImpl *mArmy; + STIMap *mMapData; + Sim *mSim; + CInfluenceMap *mIMap; + shared_ptr mVisionGrid; + shared_ptr mWaterGrid; + shared_ptr mRadarGrid; + shared_ptr mSonarGrid; + shared_ptr mOmniGrid; + shared_ptr mRCIGrid; + shared_ptr mSCIGrid; + shared_ptr mVCIGrid; + EntityCategory unk1; + bool mFogOfWar; + int unk2; }; struct Entities @@ -673,18 +2173,6 @@ struct EntityChain // [[Entities+4]+4] void *entity; }; -struct Sim; -struct Unit; -struct Entity : CScriptObject -{ // 0x270 bytes - // at 0x68 - uint32_t EntityID; // For units x|xx|xxxxxx Type,Army,Num. Uses for UserSync - REntityBlueprint *Blueprint; - uint32_t CreationIndex; // ? - // at 0x110 - bool VisibleAndControl; -}; - struct Projectile : Entity { // 0x004C702B, 0x380 bytes // at 0x6C @@ -698,7 +2186,6 @@ struct Prop : Entity RPropBlueprint *Blueprint; }; -struct CUnitCommand; struct CCommandTask { // 0x34 bytes void *vtable; @@ -786,6 +2273,11 @@ struct CommandQueue bool unk5; }; +struct CEconomyEvent +{ + +}; + struct UnitWeapon //: CScriptEvent { // 0x006D3114, 0x188 bytes void *vtable; @@ -818,245 +2310,460 @@ struct UserUnitWeapon float MaxRadius; }; -struct UnitIntel -{ // 0x20 bytes, AND 7FFFFFFF - int VisionRadius; - int WaterVisionRadius; - int RadarRadius; - int SonarRadius; - int OmniRadius; - int RadarStealthFieldRadius; - int SonarStealthFieldRadius; - int CloakFieldRadius; +struct SSiloBuildInfo +{ + UnitWeapon *mWeapon; + int mAmmo; + int gap; }; -struct Unit : WeakObject -{ // 0x006A5422, 0x6A8 bytes +struct CAiSiloBuildImpl +{ + void *vtable; + Unit *mUnit; + SSiloBuildInfo mSiloInfo[2]; + list mSiloTypes; + CEconRequest *mRequest; + int mState; // Moho::ESiloBuildStage + SEconValue mSegmentCost; + SEconValue mSegmentSpent; + float mSegments; + int mCurSegments; +}; +VALIDATE_SIZE(CAiSiloBuildImpl, 0x4C); + +struct SInfoCache +{ + CFormationInstance *mFormationLayer; + WeakPtr v1; + int v2; + bool v3; + float mTopSpeed; + float v4; + Vector3f v5; +}; + +struct IUnit_vtable +{ + struct vtable_t + { + Unit *(__thiscall *IsUnit1)(IUnit *); + Unit *(__thiscall *IsUnit2)(IUnit *); + UserUnit *(__thiscall *IsUserUnit1)(IUnit *); + UserUnit *(__thiscall *IsUserUnit2)(IUnit *); + EntId &(__thiscall *GetEntityId)(IUnit *, /*out*/ EntId &); + Vector3f *(__thiscall *GetPosition)(IUnit *); + VTransform *(__thiscall *GetTransform)(IUnit *); + RUnitBlueprint *(__thiscall *GetBlueprint)(IUnit *); + LuaObject &(__thiscall *GetLuaObject)(IUnit *, /*out*/ LuaObject &); + double (__thiscall *CalcTransportLoadFactor)(Unit *); + bool (__thiscall *IsDead)(IUnit *); + bool (__thiscall *DestroyQueued)(IUnit *); + bool (__thiscall *IsMobile)(IUnit *); + bool (__thiscall *IsBeingBuilt)(IUnit *); + int (__thiscall *IsNavigatorIdle)(IUnit *); + bool (__thiscall *IsUnitState)(IUnit *, EUnitState); + UnitAttributes *(__thiscall *GetAttributes1)(IUnit *); + UnitAttributes *(__thiscall *GetAttributes2)(IUnit *); + StatItem *(__thiscall *GetStatDefaultStr)(IUnit *, const char *, string &def); + StatItem *(__thiscall *GetStatDefaultNum)(IUnit *, const char *, float &def); + StatItem *(__thiscall *GetStatDefaultInt)(IUnit *, const char *, int &def); + StatItem *(__thiscall *GetStat)(IUnit *, const char *); + } *vtable; +}; + +struct IUnit : IUnit_vtable, WeakObject +{ +}; + +struct Unit : IUnit, Entity +{ using Type = ObjectType<0x010C6FC8, 0x00F6A1E4>; - // WeakObject WeakObject; - // at 0x8 - // Entity Entity; to 0x278 - // at 0x50 - void *self1; - // at 0x70 - uint32_t UnitID; - RUnitBlueprint *Blueprint; - uint32_t CreationIndex; // ? - void *unk1; - void *unk2; - void *RScmResource; - void *RMeshBlueprint; - Vector3f Scale; // at 0x8C - float CurHealth; - float MaxHealth; + + SSTIUnitConstantData mUnitConstDat; + SSTIUnitVariableData mUnitVarDat; + CUnitMotion *mUnitMotion; + CUnitCommandQueue *mCommandQueue; + WeakPtr mCreator; + WeakPtr mTransportedBy; + WeakPtr mFerryUnit; + WeakPtr mFocusEntity; + WeakPtr mTargetBlip; + WeakPtr mGuardedUnit; + Vector3f v96; + uint32_t gap2; + EntitySetTemplate mGuards; + CAiFormationInstance *mGuardFormation; + bool mScheduledCleanUp; + int mCreationTick; + CEconStorage *mExtraStorage; + bool v114; + CEconRequest *mConsumptionData; + bool mConsumptionIsActive; + bool mProductionActive; + bool v116c; + bool v116d; + float mResourceConsumed; + CAniActor *mAniActor; + CAiAttackerImpl *mAttacker; + IAiCommandDispatch *mCommandDispatch; + IAiNavigator *mNavigator; + CAiSteeringImpl *mSteering; + CAiBuilderImpl *mBuilder; + CAiSiloBuildImpl *mSiloBuild; + CAiTransportImpl *mTransport; + bool mIsOccupying; + float mTransportLoadFactor; + map mArmor; + TDatList mEconEvents; + uint8_t mTerrainType; + bool mDebugAIStates; + SInfoCache mInfo; + Rect2i mOccupation; + fastvector_n, 20> mBlipsInRange; + uint32_t mBlipLastUpdateTick; + uint32_t v193; + fastvector_n mReconBlips; + bool mIsNotPod; + bool mIsEngineer; + bool mIsNaval; + bool mIsAir; + bool mUsesGridBasedMotion; + bool mIsMelee; + bool mHasFocus; + int v202; + uint32_t gap3[5]; +}; +VALIDATE_OFFSET(Unit, mUnitMotion, 0x4B0); +VALIDATE_OFFSET(Unit, mArmor, 0x568); +VALIDATE_OFFSET(Unit, mReconBlips, 0x670); +VALIDATE_SIZE(Unit, 0x6A8); + +struct DBEntry +{ + void *mDB; // Moho::SpatialDB * + uint32_t mEntry; +}; + +struct VisionDB +{ + unk_t mVisionDB; + struct Pool + { + void* vtable; + list mList1; + list mList2; + } mPool; + struct Entry + { + Entry *mPrev1; + Entry *mPrev2; + Entry *mNext; + bool unk; + bool mVis; + Circle2f mPrevCicle; + Circle2f mCurCircle; + } *mRoot; + + struct Handle + { + void *vtable; + VisionDB *mDB; + Entry *mNode; + }; +}; + +struct SCreateEntityParams : SSTIEntityConstantData +{}; + +struct UserEntity +{ + void *vtable; + uint32_t unk1[2]; + CWldSession *mSession; + DBEntry mEntry; + VisionDB::Handle *mVisionHandle; + shared_ptr mPose; + shared_ptr v9; + MeshInstance *mMeshInstance; + unk_t unk2[2]; + CSndParams *mAmbientSnd; + HSndEntityLoop *mRumbleSnd; + int mCreationTickMaybe; + SCreateEntityParams mParams; + SSTIEntityVariableData mVarDat; + UserArmy *mArmy; + VTransform mTransform; + float mLastInterpAmt; bool unk3; bool unk4; - bool unk5; - char pad1; - Vector4f Rot1; // at 0xA4 - Vector3f Pos1; - Vector4f Rot2; - Vector4f Pos2; - float FractionComplete; // at 0xE0 - void *unk6; - char unk7[0x18]; - void *unk10; - void *unk12; - void *unk13; - void *unk14; - void *unk15; - void *unk16; - bool VisibleAndControl; // at 0x118 - char pad2[3]; - void *unk18; - void *unk19; - bool unk20; - char pad3[3]; - void *unk21; - UnitIntel UnitIntel; // at 0x130 - Sim *sim; // at 0x150 - SimArmy *owner; - Vector4f Rot3; - Vector3f Pos3; - // at 0x17C - int TickCount1; // Readonly - void *CColPrimitiveBase; - // at 0x248 - Vector3f Pos4; - Vector3f Pos5; - // at 0x294 - float FuelRatio; - float ShieldRatio; // Readonly - // at 0x2A0 - bool Paused; - // at 0x2AC - float WorkProgress; - // at 0x2CC - string customUnitName; - // at 0x380 - UserUnitWeapon *Weapons; - list unk22; // Weapons? - void *unk23; // Weapons? - // at 0x4B0 - void *MotionEngine; // +0xC FuelUseTime - void *CommandQueue; - int Enum; // 0..4 - // at 0x534 - void *workValues; // +0x8 - bool Flag; - // at 0x53C - float WorkRate; - // at 0x544 - void *IAiAttacker; - void *IAiCommandDispatch; - // at 0x558 - void *IAiSiloBuild; - void *IAiTransport; - // at 0x59C - Vector3f Pos6; - // at 0x668 - int tickCount2; // Readonly - // at 0x68E - bool updWeaponRadius; -}; - -struct UserEntity : WeakObject -{ // 0x148 bytes - // at 0x44 - int entityID; - RPropBlueprint *blueprint; - // at 0x58 - RMeshBlueprint *mesh; - // at 0x68 - float curHealth; - float maxHealth; - // at 0x70 - bool isBeingBuilt; - Vector4f rot1; - Vector3f pos1; - // at 0x90 - Vector4f rot2; - Vector4f pos2; - // at 0xB0 - float fractionComplete; - // at 0xD0 - // float x1,y1,x2,y2; - // at 0x100 - UnitIntel unitIntel; - UserArmy *owner; // at 0x120 - Vector4f rot3; - Vector4f pos3; }; +VALIDATE_OFFSET(UserEntity, mVarDat, 0x50); +VALIDATE_OFFSET(UserEntity, mArmy, 0x120); +VALIDATE_SIZE(UserEntity, 0x148); -struct UserUnit : UserEntity +struct UserUnit : UserEntity, IUnit, CScriptObject { // 0x008B8601, 0x3E8 bytes using Type = ObjectType<0x10C77AC, 0xF881E0>; - // at 0x44 - uint32_t UnitID; - RUnitBlueprint *blueprint; - // at 0x1B0 - bool Paused; - // at 0x1BC - float WorkProgress; - // at 0x1DC - string customUnitName; - // at 0x290 - UserUnitWeapon *weapons; -}; -struct CPlatoon : public CScriptObject -{ - using Type = ObjectType<0x10C6FCC, 0xF6A1FC>; + SSTIUnitConstantData mUnitConstDat; + bool unk1; + SSTIUnitVariableData mUnitVarDat; + unk_t mCreator; + unk_t unk2; + UserUnitManager *mManager; + UserUnitManager *mFactoryManager; + map mSelectionSets; + bool unk3; + bool mIsEngineer; + bool mIsFactory; + bool unk4; + unk_t unk5; + unk_t unk6; + + inline ERuleBPUnitToggleCaps GetToggleCaps() { + return this->IUnit::vtable->GetAttributes2(this)->mToggleCaps; + } }; +VALIDATE_OFFSET(UserUnit, mUnitConstDat, 0x184); +VALIDATE_OFFSET(UserUnit, mUnitVarDat, 0x198); +VALIDATE_OFFSET(UserUnit, mManager, 0x3C8); +VALIDATE_SIZE(UserUnit, 0x3E8); struct CMauiBitmap : public CMauiControl { using Type = ObjectType<0x10C7704, 0xF832F4>; }; -struct ReconBlip : Entity -{ // 0x4D0 bytes - Entity entity; - // at 0x270 - void *originUnit; // -0x4 - // at 0x28C - void *StatItem; - void *StatItem2; - // at 0x320 - void *CAniPose; - // at 0x328 - void *CAniPose2; - // at 0x330, size 0x30? - list unk1; - void *unk2; - // at 0x360, size 0x30? - list unk3; - void *unk4; - // at 0x390, size 0x30? - list unk5; // Weapons? - void *unk6; // Weapons? - // at 0x450, size 0x30? - list unk7; - void *unk8; - // at 0x4C4 - void *armyesData[]; // size 0x34 +struct CMersenneTwister +{ + unsigned int mState[624]; + int mPos; + + unsigned int IRand() { + uint32_t i; + asm( + "call 0x0040E9F0" + : + : "d" (this), "a" (i) + : "memory" + ); + return i; + } }; -struct STIMap; +static float int_to_float asm("0x00E4F7B0"); // 2.3283064e-10 +struct CRandomStream +{ + CMersenneTwister mTwister; + float mMarsagliaPair; + bool mHasMarsagliaPair; + + float FRand() { // parity with 0x0040EA70 + return this->mTwister.IRand() * int_to_float; + } + float FRand(float min, float max) { // parity with 0x0051B5C0 + return min + (max - min) * FRand(); + } + float FRandGaussian() { + float val; + asm( + "call 0x0040EEC0;" + : "=t" (val) + : "S" (this) + : "memory" + ); + return val; + } +}; +VALIDATE_SIZE(CRandomStream, 0x9CC); + +struct MD5Block +{ + char mVals[56]; + __int64 mSize; +}; + +struct MD5Digest +{ + int mVals[4]; +}; + +struct MD5Context +{ + MD5Digest mDigest; + MD5Block mBlock; + unsigned int mPos; + int gap; + __int64 mSize; +}; + +struct EntityOccupationGrid +{ + int mWidth; + int mHeight; + int mLastIndex; + int mGridWidth; + vector **mUnits; + vector **mProps; + vector **mEntities; + int unk1; + int unk2; + int unk3; + void **start; + void **end; + int unk4; +}; + +struct COGrid +{ + Sim *mSim; + EntityOccupationGrid mEntityGrid; + BitArray2D mTerrainOccupation; + BitArray2D mWaterOccupation; + BitArray2D mOccupation; +}; +VALIDATE_SIZE(COGrid, 0x68); + +struct SDesyncInfo +{ + int mBeat; + int mArmy; + MD5Digest mHash1; + MD5Digest mHash2; +}; + +struct CGeomSolid3 +{ + fastvector_n mVec; +}; + +struct GeomCamera3 +{ + VTransform mTranform; + VMatrix4 mProjection; + VMatrix4 mView; + VMatrix4 mViewProjection; + VMatrix4 mInverseProjection; + VMatrix4 mInverseView; + VMatrix4 mInverseViewProjection; + uint32_t alignment; + CGeomSolid3 mSolid1; + CGeomSolid3 mSolid2; + float mLOCScale; + VMatrix4 mViewport; + uint32_t unk; +}; +VALIDATE_SIZE(GeomCamera3, 0x2C8); + +struct SSyncFilter +{ + int mFocusArmy; + vector mCams; + uint32_t mGap1[3]; + BVIntSet mSet1; + bool mBool; + uint32_t mGap2[3]; + BVIntSet mSet2; +}; + +struct SPhysConstants +{ + Vector3f mGravity; +}; + +struct SCamShakeParams +{ + float v1; + float v2; + float v3; + float v4; + float v5; + float v6; + float minTime; +}; + +struct RDebugOverlay : TDatListItem +{ + virtual ~RDebugOverlay(); // force vtable +}; +VALIDATE_SIZE(RDebugOverlay, 0xC); + struct Sim // : ICommandSink -{ // 0xAF8 bytes +{ void *vtable; - uint8_t pad1[0x4C]; - // at 0x50 - char dynamicHash[16]; - char hashTrash[0x50]; - char simHashes[16 * 128]; // at 0xB0-8B0 - uint8_t pad2[0x10]; - // at 0x8C0 - void *CEffectManager; // 0x18 bytes - void *CSimSoundManager; // 0x720 bytes - RRuleGameRules *rules; // From CSimDriver.LaunchInfoNew - STIMap *STIMap; // From CSimDriver.LaunchInfoNew - CSimResources *res; - uint8_t pad3[4]; - // at 0x8D8 - LuaState *LState; - uint8_t pad4[0xA]; - // at 0x8E6 - bool cheatsEnabled; - uint8_t pad5[0x10]; - // at 0x8F8 - uint32_t beatCounter1; - void *unk1; // self+0x900 or null - uint32_t beatCounter2; - // at 0x904 - void *unk2; // 0x9CC bytes - void *unk3; // 0x68 bytes - vector armies; - uint8_t pad6[4]; - // at 0x920 - list cmdSources; - // at 0x92C - int ourCmdSource; // Possibly just current in simulation. - uint8_t pad7[0x4C]; - // at 0x97C - void **unk4; // 0x30 bytes - void *CAiFormationDB; // 0x40 bytes - // at 0x984 - void *Entities; - void *unk5; // 0xCD0 bytes - uint8_t pad8[0x10]; - // at 0x99C - void *unk6; // 0xCF0 bytes - uint8_t pad9[0x98]; - // at 0xA38 - void *unk7; // 0xC bytes - uint8_t pad10[0x4C]; - // at 0xA88 - int focusArmyIndex; // Focused army, -1 = observer - uint8_t pad11[0x6C]; -}; -VALIDATE_SIZE(Sim, 0xAF8) + string str0; + FILE *mLog; + string str1; + list list1; + bool mDesyncFreeMaybe; + MD5Context mContext; + MD5Digest mSimHashes[128]; + vector mDesyncs; + CEffectManagerImpl *mEffectManager; + CSimSoundManager *mSoundManager; + RRuleGameRulesImpl *mRules; + STIMap *mMapData; + shared_ptr mSimResources; + LuaState *mLuaState; + bool mGameEnded; + bool mGameOver; + int mPausedBy; + bool mSingleStep; + bool mNeedsToSyncMaybe; + bool mCheatsEnabled; + vector mCheaters; + int mCurBeat; + bool mDidProcess; + unsigned int mCurTick; + CRandomStream *mRandom; + COGrid *mOGrid; + vector mArmiesList; // vector, but this is more useful + vector mCommandSources; + unsigned int mCurCommandSource; + CTaskStage mThread3; + CTaskStage mTaskThread; + CTaskStage mThread1; + shared_ptr mDebugCanvas1; + shared_ptr mDebugCanvas2; + PathTables *mPathTables; + CAiFormationDBImpl *mFormationDB; + EntityDB *mEntityDB; + CCommandDB *mCommandDB; + int mCommandCount; + unk_t unk1; + shared_ptr mParticleBuffer; + CDecalBuffer *mDecalBuffer; + TDatList mDebugOverlays; + vector mSimVars; + vector mSyncVec1; + vector mSyncCamShake; + vector mSyncVec4; + vector mSyncVec5; + Rect2i mPlayableRect1; + Rect2i mPlayableRect2; + vector mPrintField; + vector mSyncVec3; + SPhysConstants *mPhysConstants; + list mShields; + queue mDeletionQueue; + TDatList mCoordEntities; + bool mRequestXMLArmyStatsSubmit; + int mSyncArmy; + bool mDidSync; + struct SyncSizes + { + int mAudioRequests; + int mArmyData; + int mEntityData; + int mSize4; + int mSize5; + } mSyncSizes; + void *unk2; + SSyncFilter mSyncfilter; +}; +VALIDATE_OFFSET(Sim, mRandom, 0x904); +VALIDATE_SIZE(Sim, 0xAF8); struct CWldSession { // 0x0089318A, 0x508 bytes @@ -1097,13 +2804,8 @@ struct CWldSession BOOL isGameOver; uint8_t pad4[0x10]; // at 0x4A0 - struct - { - int unk1; - void **SelList; //+0x10 - int SelCount; - int SelCount2; - } selectedUnits; + ::map> selectedUnits; + size_t mMaxSelectionSize; // at 0x4B0 struct { // size 0x24 @@ -1125,7 +2827,7 @@ struct CWldSession bool relationsArmyColors; uint8_t pad6[0x1C]; }; -VALIDATE_SIZE(CWldSession, 0x508) +VALIDATE_SIZE(CWldSession, 0x508); struct CSimDriver // : ISTIDriver { // 0x0073B59E, 0x230 bytes @@ -1153,40 +2855,49 @@ struct CSimDriver // : ISTIDriver }; VALIDATE_SIZE(CSimDriver, 0x230); -struct CHeightField // : class detail::boost::sp_counted_base -{ // 0x00579121, 0x10 bytes - void *vtable; +struct iGrid_data4 +{ + SMinMax<__int16> *mData; + int mWidth; + int mHeight; }; -struct MapData -{ // 0x1C bytes - uint32_t *TerrainHeights; // Word(TerrainHeights+(Y*SizeX+X)*2) - int SizeX; // +1 - int SizeY; // +1 +struct iGrid_data2 +{ + __int16 *data; + int mWidth; + int mHeight; +}; + +struct iGrid +{ + iGrid_data4 data1; + iGrid_data2 data2; +}; + +struct CHeightField : iGrid_data2 +{ + vector mGrids; +}; +VALIDATE_SIZE(CHeightField, 0x1C); + +struct TerrainTypes +{ + fastvector_n mTypes; }; struct STIMap -{ // 0x1548 bytes - MapData *MapData; - CHeightField *HeightField; - uint32_t unk1[4]; - // at 0x18 - void *beginData; - void *endData; - void *endData2; - void *beginData2; - // at 0x28 - LuaObject Data[0x100]; // Type desc tables - uint8_t *TerrainTypes; // TerrainTypes+(Y*SizeX+X) - int SizeX; - int SizeY; - uint8_t unk2[0x100]; - // at 0x1534 - BOOL Water; - float WaterLevel; - float DepthLevel; - float AbyssLevel; - uint32_t unk3; +{ + shared_ptr mHeightField; + Rect2i mPlayableRect; + TerrainTypes mTerrainTypes; + Array2D mTerrainType; + bool mBlocking[256]; + bool mWaterEnabled; + float mWaterElevation; + float mWaterElevationDeep; + float mWaterElevationAbyss; + int unk; }; VALIDATE_SIZE(STIMap, 0x1548); @@ -1201,6 +2912,7 @@ struct INetConnector { void *vtable; }; + struct CLobby { // 0x004C702B, 0xC8 bytes // at 0x20 @@ -1235,19 +2947,6 @@ struct CLobby } peer_list; // Probably singly-linked list }; -struct sub_10392B10_ret -{ // 0x20 bytes - - void *zero1; - void *zero2; - void *zero3; - int unk1; - - // at 0x10 - bool one1; - bool zero4; -}; - struct CLobbyPeer { // 0x50 bytes @@ -1266,11 +2965,7 @@ struct CLobbyPeer int const3; // enum? float const4; // = 0 int const5; - int unk1; - - // at 0x40 - sub_10392B10_ret *unk2; // made in sub_10394180 - int zero1; + set mConnectedTo; int cmdSourceIndex; // == 255 => Unassigned int playerNo; @@ -1288,7 +2983,7 @@ struct CLobbyPeer struct CClientManagerImpl : IClientManager { // 0x184D0 bytes // at 0x40C - gpg_mutex mLock; + mutex mLock; // at 0x420 list mClients; @@ -1314,9 +3009,9 @@ struct CClientManagerImpl : IClientManager bool unk1; // if value is 1 then KERNEL32.SetEvent is bypassed }; -typedef struct mRequest +struct EjectRequest { - IClient *mRequester; + const char *mRequester; int mAfterBeat; }; @@ -1329,7 +3024,7 @@ struct CClientBase : IClient IClientManager *clientManager; // at 0x30 - moho_set unk1; + BVIntSet unk1; // at 0x50 int mCommandSource; bool mReady; @@ -1346,7 +3041,7 @@ struct CClientBase : IClient bool mEjectPending; bool mEjected; char pad2[2]; - vector mEjectRequests; + vector mEjectRequests; int maxSimRate; // from CalcMaxSimRate }; @@ -1383,15 +3078,15 @@ struct CNetUDPConnection { }; -struct CNetUDPConnetor // : INetConnector +struct CNetUDPConnector // : INetConnector { // 0x18090 bytes void *vtable; void *smth; // Listen socket fd? - gpg_mutex mMutex; + mutex mMutex; // at 0x14 SOCKET mSocket; // at 0x24 - linked_list mConnections; + TDatList mConnections; }; /*Game Types Multiplayer - CLobby::LaunchGame diff --git a/include/utility.h b/include/utility.h index f76e7b0a..b01d295e 100644 --- a/include/utility.h +++ b/include/utility.h @@ -32,7 +32,7 @@ Vector2f ToVector2f(lua_State *l, int index) lua_rawgeti(l, -1, 1); res.x = lua_tonumber(l, -1); lua_rawgeti(l, -2, 2); - res.z = lua_tonumber(l, -1); + res.y = lua_tonumber(l, -1); lua_pop(l, 3); return res; } @@ -53,6 +53,6 @@ void PushVector2(lua_State *l, Vector2f v) lua_createtable(l, 2, 0); lua_pushnumber(l, v.x); lua_rawseti(l, -2, 1); - lua_pushnumber(l, v.z); + lua_pushnumber(l, v.y); lua_rawseti(l, -2, 2); -} \ No newline at end of file +} diff --git a/section/Aim/Aim.cxx b/section/Aim/Aim.cxx index e5d37504..dc494364 100644 --- a/section/Aim/Aim.cxx +++ b/section/Aim/Aim.cxx @@ -1,5 +1,5 @@ #include "global.h" -#include "Maths.h" +#include "Wm3.h" namespace Moho { diff --git a/section/AlliedRangeRings.cpp b/section/AlliedRangeRings.cpp new file mode 100644 index 00000000..cd5ced10 --- /dev/null +++ b/section/AlliedRangeRings.cpp @@ -0,0 +1,14 @@ +extern "C" void __attribute__((naked)) asm__ShouldAddUnit() { + asm volatile(R"( + push ecx; + push edx; + push edi; + push eax; + call _ShouldAddUnit; + add esp, 8; + pop edx; + pop ecx; + test al,al; + je 0x007A789F; + jmp 0x007A7860;)"); +} diff --git a/section/AlliedRangeRings.cxx b/section/AlliedRangeRings.cxx new file mode 100644 index 00000000..220b2f43 --- /dev/null +++ b/section/AlliedRangeRings.cxx @@ -0,0 +1,99 @@ +#include "global.h" +#include "magic_classes.h" +#include "moho.h" + +enum IntelRangeBehavior { + kOwnUnits = 0, + kOwnUnitsAndAlliedBuildings = 1, + kOwnUnitsAndAlliedUnits = 2 +}; + +int intelRangeBehavior = kOwnUnitsAndAlliedBuildings; +ConDescReg conIntelRangeBehavior{"ren_IntelRangeBehavior", + "Only own units = 0; Own units and allied " + "buildings = 1; Own and allied units = 2", + &intelRangeBehavior}; + +extern "C" { + +// This hook disables rendering of ally range rings, except for RADAR, SONAR, +// and OMNI. It also includes an optimization to prevent double rendering. +UserUnit *__thiscall RenderRange__Moho__UserUnit__UserUnit(UserUnit *self, + uintptr_t esp) { + auto session = g_CWldSession; + + // Optimization: To avoid double rendering, skip rendering global rings for + // own-army units; these will be handled by the selection rings renderer. + if (self->mArmy->mConstDat.mIndex == session->focusArmyIndex) { + if (session->selectedUnits.contains(self)) + return nullptr; + else + return self; + } + + // Disables rendering of ally range rings, except for RADAR, SONAR, and OMNI. + // Btw, compiler, I believe in you. We're in a hot path, so please optimize + // and inline the lambda. P.S. I saw the listing — mine handled it, and + // there’s no call there. + auto equals = [](string &str1, const char (&str2)[N]) { + if (str1.strLen != N - 1) + return false; + const char *l = str1.data(); + const char *r = str2; + while (*l == *r && *l) { + ++l; + ++r; + }; + return (*l - *r) == 0; + }; + auto &rangeName = **reinterpret_cast(esp + 0x30); + bool isIntelRange = equals(rangeName, "Radar") || equals(rangeName, "Omni") || + equals(rangeName, "Sonar"); + if (isIntelRange) + return self; + return nullptr; +} + +extern void __fastcall +Hooked_SyncVisionRange(ReconBlip *, Unit *) asm("Hooked_SyncVisionRange"); +void Hooked_SyncVisionRange(ReconBlip *reconBlip, Unit *unit) { + auto &reconAttrib = reconBlip->Entity::mVarDat.mAttributes; + auto &unitAttrib = unit->mVarDat.mAttributes; + reconAttrib.SetIntelRadius(ENTATTR_Vision, + unitAttrib.GetIntelRadius(ENTATTR_Vision)); + + if (unit->mArmy->IsAlly(g_CWldSession->focusArmyIndex)) { + reconAttrib.SetIntelRadius(ENTATTR_Radar, + unitAttrib.GetIntelRadius(ENTATTR_Radar)); + reconAttrib.SetIntelRadius(ENTATTR_Sonar, + unitAttrib.GetIntelRadius(ENTATTR_Sonar)); + reconAttrib.SetIntelRadius(ENTATTR_Omni, + unitAttrib.GetIntelRadius(ENTATTR_Omni)); + } +} + +bool __cdecl ShouldAddUnit(UserArmy *focusArmy, UserUnit *userUnit) { + auto session = g_CWldSession; + if (userUnit->mArmy == focusArmy) + return true; + + if (intelRangeBehavior == kOwnUnits) + return false; + + if (!userUnit->mArmy->IsAlly(session->focusArmyIndex)) + return false; + + auto blueprint = static_cast(userUnit->mParams.mBlueprint); + if (intelRangeBehavior == kOwnUnitsAndAlliedBuildings && + blueprint->mPhysics.mMotionType != RULEUMT_None) + // let's assume this is not a building + return false; + + auto &unitAttrib = userUnit->mVarDat.mAttributes; + bool hasIntel = (unitAttrib.GetIntelRadius(ENTATTR_Radar) | + unitAttrib.GetIntelRadius(ENTATTR_Sonar) | + unitAttrib.GetIntelRadius(ENTATTR_Omni)) != 0; + return hasIntel; +} + +} // extern "C" diff --git a/section/RangeRings.cpp b/section/RangeRings.cpp deleted file mode 100644 index be05c0d9..00000000 --- a/section/RangeRings.cpp +++ /dev/null @@ -1,644 +0,0 @@ -#include "desync_fix_global.h" - -void GlobalRings() -{ - asm( - "sub esp,0x14;" - "push ebx;" - "push ebp;" - "mov ebp,dword ptr [esp+0x2C];" - "mov eax,dword ptr [ebp+0x8];" - "mov ecx,dword ptr [ebp+0x4];" - "push esi;" - "push edi;" - "push eax;" - "push ecx;" - "lea eax,dword ptr [esp+0x3C];" - "mov ebx,ebp;" - ); - asm( - "call -0x1000 +8330320;" - "mov eax,dword ptr [esp+0x30];" - "lea esi,dword ptr [esp+0x34];" - ); - asm( - "call -0x1000 +8327632;" - "mov eax,dword ptr [esp+0x34];" - "cmp eax,dword ptr [0x10BF00C];" - "je ExitLabel2;" - "mov eax,dword ptr [eax+0x28];" - "test eax,eax;" - "mov dword ptr [esp+0x34],eax;" - "je ExitLabel2;" - "mov eax,dword ptr [esp+0x28];" - "mov ebx,dword ptr [eax];" - "cmp ebx,dword ptr [eax+0x4];" - "je ExitLabel2;" - "ContinueLoopThroughUnits:;" - "mov eax,dword ptr [ebx];" - "test eax,eax;" - "je ExitLabel;" - "lea esi,dword ptr [eax-0x8];" - "test esi,esi;" - "je ExitLabel;" - "mov eax,dword ptr [esi];" - "mov edx,dword ptr [eax+0x34];" - "mov ecx,esi;" - "call edx;" - "test al,al;" - "jne ExitLabel;" - "mov eax,dword ptr [esi];" - "mov edx,dword ptr [eax+0xC];" - "mov ecx,esi;" - "call edx;" - "mov edi,eax;" - "test edi,edi;" - "je ExitLabel;" - "mov eax,dword ptr [edi+0x148];" - "mov edx,dword ptr [eax+0x28];" - "lea esi,dword ptr [edi+0x148];" - "mov ecx,esi;" - "call edx;" - "test al,al;" - "jne ExitLabel;" - "mov eax,dword ptr [esi];" - "mov edx,dword ptr [eax+0x2C];" - "mov ecx,esi;" - "call edx;" - "test al,al;" - "jne ExitLabel;" - "mov eax,dword ptr [esi];" - "mov edx,dword ptr [eax+0x1C];" - "mov ecx,esi;" - "call edx;" - "test eax,eax;" - "je ExitLabel;" - "mov edx,dword ptr [esp+0x30];" - "add edx,0x20;" - ); - asm( - "call -0x1000 +5683664;" - "test eax,eax;" - "jbe ExitLabel;" - "mov ecx,dword ptr [esp+0x34];" - "fld dword ptr [esp+0x2C];" - "mov eax,dword ptr [ecx];" - "mov eax,dword ptr [eax+0x8];" - "push ecx;" - "fstp dword ptr [esp];" - "push edi;" - "lea edx,dword ptr [esp+0x18];" - "push edx;" - "call eax;" - "test al,al;" - "je ExitLabel;" - - "xor ecx,ecx;" - "mov esi, dword ptr ds:[0x011FD237];" - "cmp esi, ecx;" - "je FirstTime;" - "mov edx, dword ptr ds:[0x011FD23B];" - "cmp edx, ecx;" - "je FirstTime;" - "mov edi, 0x4;" - "mov eax, dword ptr ds:[ebx];" - "NextItem:;" - "cmp dword ptr ds:[esi], eax;" - "je ExitLabel;" - "inc ecx;" - "sub esi, edi;" - "cmp ecx, edx;" - "jl NextItem;" - - "FirstTime:;" - "lea edx,dword ptr [esp+0x10];" - "mov esi,ebp;" - ); - asm( - "call -0x1000 +8327952;" - "ExitLabel:;" - "mov ecx,dword ptr [esp+0x28];" - "add ebx,0x8;" - "cmp ebx,dword ptr [ecx+0x4];" - "jne ContinueLoopThroughUnits;" - "ExitLabel2:;" - "pop edi;" - "pop esi;" - "pop ebp;" - "pop ebx;" - "add esp,0x14;" - "ret 0x10;" - ); -} - -void GetSelectedUnits() -{ - asm( - "sub esp,0x14;" - "mov eax,dword ptr [ebx+0x4A4];" - "mov eax,dword ptr [eax];" - "push ebp;" - "mov ebp,dword ptr [esp+0x1C];" - "push esi;" - "lea esi,dword ptr [ebx+0x4A0];" - "push edi;" - "push eax;" - "lea edi,dword ptr [esp+0x28];" - ); - asm( - "call -0x1000 +6730544;" - "mov dword ptr [0x011FD23B],0;" - "mov eax,dword ptr [eax];" - "cmp eax,dword ptr [esi+0x4];" - "mov dword ptr [esp+0xC],esi;" - "mov dword ptr [esp+0x10],eax;" - "je exit;" - "continue:;" - "inc dword ptr [0x011FD23B];" - "mov eax,dword ptr [eax+0x10];" - "test eax,eax;" - "je label0;" - "lea ecx,dword ptr [eax-0x8];" - "jmp label1_sel;" - "label0:;" - "xor ecx,ecx;" - "label1_sel:;" - "mov eax,dword ptr [ecx];" - "mov edx,dword ptr [eax+0xC];" - "call edx;" - "test eax,eax;" - "je label2_sel;" - "push eax;" - "push ebp;" - "lea esi,dword ptr [esp+0x1C];" - ); - asm( - "call -0x1000 +8532592;" - "label2_sel:;" - "lea edx,dword ptr [esp+0x10];" - ); - asm( - "call -0x1000 +6733264;" - "mov eax,dword ptr [esp+0x10];" - "mov esi,dword ptr [esp+0xC];" - "push eax;" - "lea edi,dword ptr [esp+0x28];" - ); - asm( - "call -0x1000 +6730544;" - "mov eax,dword ptr [eax];" - "cmp eax,dword ptr [ebx+0x4A4];" - "mov dword ptr [esp+0x10],eax;" - "jne continue;" - "exit:;" - "pop edi;" - "pop esi;" - "pop ebp;" - "add esp,0x14;" - "ret 0x4;" - ); -} - -void SelectionRings() -{ - asm( - "push 0xFFFFFFFF;" - "mov eax,dword ptr [fs:0x0];" - "push 0xBA7B58;" - "push eax;" - "mov dword ptr [fs:0x0],esp;" - "sub esp,0x2C;" - "push ebx;" - "mov ebx,dword ptr [esp+0x40];" - "mov eax,dword ptr [ebx+0x8];" - "push ebp;" - "push esi;" - "push edi;" - "mov edi,ecx;" - "mov ecx,dword ptr [ebx+0x4];" - "push eax;" - "push ecx;" - "lea eax,dword ptr [esp+0x18];" - ); - asm( - "call -0x1000 +8330320;" - "cmp byte ptr [0x10A640A],0x0;" - "je exit1;" - "mov esi,dword ptr [esp+0x50];" - "mov eax,dword ptr [esi+0x14];" - "push 0xB;" - "push 0xE3F864;" - "push eax;" - "push 0x0;" - "mov ecx,esi;" - ); - asm( - "call -0x1000 +4241536;" - "test eax,eax;" - "je exit1;" - "mov ecx,dword ptr [esi+0x14];" - "push 0x8;" - "push 0xE3F8B0;" - "push ecx;" - "push 0x0;" - "mov ecx,esi;" - ); - asm( - "call -0x1000 +4241536;" - "test eax,eax;" - "je exit1;" - "mov eax,dword ptr [edi+0x488];" - "test eax,eax;" - "jl exit1;" - "mov edx,dword ptr [edi+0x3F0];" - "mov eax,dword ptr [edx+eax*0x4];" - "test eax,eax;" - "mov dword ptr [esp+0x10],eax;" - "je exit1;" - "mov eax,esi;" - ); - asm( - "call -0x1000 +8317504;" - "mov ebp,eax;" - "test ebp,ebp;" - "je exit1;" - "lea esi,dword ptr [esp+0x1C];" - ); - asm( - "call -0x1000 +8074688;" - "mov eax,esi;" - "push eax;" - "mov ebx,edi;" - "mov dword ptr [esp+0x48],0x0;" - ); - asm( - "call %[GetSelectedUnits];" - "lea ebx,dword ptr [esp+0x14];" - "mov eax,esi;" - : - : [GetSelectedUnits] "i" (GetSelectedUnits) - : "memory" - ); - asm( - "call -0x1000 +8074736;" - "mov eax,dword ptr [esp+0x18];" - "cmp eax,dword ptr [esp+0x20];" - "je CleanUpExit;" - "LoopStart:;" - "mov eax,dword ptr [eax+0x10];" - "test eax,eax;" - "je ContinueLoop;" - "lea esi,dword ptr [eax-0x8];" - "test esi,esi;" - "je ContinueLoop;" - "mov ecx,dword ptr [esp+0x10];" - "cmp ecx,dword ptr [esi+0x120];" - "jne ContinueLoop;" - "mov edx,dword ptr [esi+0x148];" - "mov eax,dword ptr [edx+0x1C];" - "lea edi,dword ptr [esi+0x148];" - "mov ecx,edi;" - "call eax;" - "test eax,eax;" - "je ContinueLoop;" - "mov edx,dword ptr [edi];" - "mov eax,dword ptr [edx+0x1C];" - "mov ecx,edi;" - "call eax;" - "mov edx,dword ptr [esp+0x50];" - "add edx,0x20;" - ); - asm( - "call -0x1000 +5683664;" - "test eax,eax;" - "jbe ContinueLoop;" - "fld dword ptr [esp+0x54];" - "mov edx,dword ptr [ebp];" - "mov edx,dword ptr [edx+0x8];" - "push ecx;" - "fstp dword ptr [esp];" - "push esi;" - "lea eax,dword ptr [esp+0x30];" - "push eax;" - "mov ecx,ebp;" - "call edx;" - "test al,al;" - "je ContinueLoop;" - - "xor ecx,ecx;" - "xor esi,esi;" - "mov edx, 0x4;" - "mov eax, dword ptr [ebx+0x4];" - "mov eax, dword ptr ds:[eax+0x10];" - "sub esp, 0x60028;" - "mov dword ptr ds:[0x011FD237], esp;" - "LoopOver:;" - "cmp dword ptr ss:[esp], esi;" - "jne isNotZero;" - "mov dword ptr ss:[esp], eax;" - "isNotZero:;" - "cmp dword ptr ss:[esp], eax;" - "je MemWritten;" - "sub esp, edx;" - "inc ecx;" - "jmp LoopOver;" - "MemWritten:;" - "cmp ecx, 1;" - "jl RegClenUp;" - "shl ecx, 2;" - "add esp, ecx;" - "RegClenUp:;" - "add esp, 0x60028;" - - - "mov esi,dword ptr [esp+0x4C];" - "lea edx,dword ptr [esp+0x28];" - ); - asm( - "call -0x1000 +8327952;" - "ContinueLoop:;" - "lea eax,dword ptr [esp+0x14];" - "push eax;" - ); - asm( - "call -0x1000 +8328336;" - "mov eax,dword ptr [esp+0x18];" - "cmp eax,dword ptr [esp+0x20];" - "jne LoopStart;" - "CleanUpExit:;" - "lea eax,dword ptr [esp+0x1C];" - "mov dword ptr [esp+0x44],0xFFFFFFFF;" - ); - asm( - "call -0x1000 +8074544;" - "exit1:;" - "mov ecx,dword ptr [esp+0x3C];" - "pop edi;" - "pop esi;" - "pop ebp;" - "mov dword ptr [fs:0x0],ecx;" - "pop ebx;" - "add esp,0x38;" - "ret 0xC;" - ); -} - - -void RangeRings() -{ - asm( - "push 0xFFFFFFFF;" - "push 0xBBB776;" - "mov eax,dword ptr [fs:0x0];" - "push eax;" - "mov dword ptr [fs:0x0],esp;" - "sub esp,0x188;" - "push ebp;" - "mov ebp,dword ptr [esp+0x19C];" - "push esi;" - "push edi;" - "mov edi,ecx;" - ); - asm( - "call -0x1000 +9336624;" - "xor esi,esi;" - "mov dword ptr [esp+0x18],esi;" - "mov dword ptr [esp+0x1C],esi;" - "mov dword ptr [esp+0x20],esi;" - "mov dword ptr [esp+0x19C],esi;" - "cmp byte ptr [0x10A6414],0x0;" - "je RR_L1;" - "mov eax,dword ptr [esp+0x1A8];" - "push eax;" - "push ebx;" - "lea ecx,dword ptr [esp+0x1C];" - "push ecx;" - "push ebp;" - "mov ecx,edi;" - ); - asm( - "call -0x1000 +8322640;" - "RR_L1:;" - "mov eax,dword ptr [ebp+0x14];" - "cmp eax,esi;" - "je -0x1000 + 8321877;" //STARTREGULARFUNC_NO_OVERLOAD - "mov ecx,dword ptr [ebp+0x18];" - "sub ecx,eax;" - "mov eax,0x78787879;" - "imul ecx;" - "sar edx,0x6;" - "mov eax,edx;" - "shr eax,0x1F;" - "add eax,edx;" - "je -0x1000 + 8321877;" //STARTREGULARFUNC_NO_OVERLOAD - "mov edx,dword ptr [ebx];" - "mov eax,dword ptr [edx+0x8];" - "mov ecx,ebx;" - "call eax;" - "mov edx,dword ptr [ebx];" - "mov eax,dword ptr [edx+0xA4];" - "mov ecx,ebx;" - "call eax;" - "lea ecx,dword ptr [esp+0x3C];" - "push ecx;" - "mov edx,eax;" - ); - asm( - "call -0x1000 +8328144;" - "mov byte ptr [esp+0x19C],0x1;" - "mov eax,dword ptr [ebp+0x14];" - "cmp eax,dword ptr [ebp+0x18];" - "je label3;" - "lea esi,dword ptr [eax+0x78];" - "jmp label4;" - "lea ecx,dword ptr [ecx];" - "label4:;" - "fld dword ptr [esp+0x1AC];" - "lea edx,dword ptr [esp+0x14];" - "push edx;" - "lea eax,dword ptr [esi-0x78];" - "push eax;" - "push ecx;" - "lea ecx,dword ptr [esp+0x48];" - "fstp dword ptr [esp];" - "push ecx;" - ); - asm( - "call %[GlobalRings];" - "lea edx,dword ptr [esp+0x14];" - "push edx;" - "mov edx,dword ptr [esp+0x1AC];" - "push esi;" - "lea eax,dword ptr [esi-0x30];" - "push eax;" - "push edx;" - "lea ecx,dword ptr [esi+0x8];" - "push ebp;" - "mov edx,ebx;" - : - : [GlobalRings] "i" (GlobalRings) - : "memory" - ); - asm( - "call -0x1000 +8324512;" - "mov eax,dword ptr [ebp+0x18];" - "add esi,0x88;" - "lea ecx,dword ptr [esi-0x78];" - "cmp ecx,eax;" - "jne label4;" - "label3:;" - "mov byte ptr [esp+0x19C],0x0;" - - "xor esi,esi;" - "mov edx, dword ptr ds:[0x011FD237];" - "cmp edx, esi;" - "je EXITMEMCLEAN;" - "mov ecx, dword ptr ds:[0x011FD23B];" - "cmp ecx, esi;" - "je EXITMEMCLEAN;" - "mov eax,esi;" - "mov esi,edi;" - "mov edi,edx;" - "std;" - "rep stosd;" - "mov edi,esi;" - "cld;" - - "EXITMEMCLEAN:;" - "mov eax,dword ptr [esp+0x40];" - "mov edx,dword ptr [esp+0x3C];" - "cmp edx,eax;" - "mov esi,eax;" - "je label5;" - "label6:;" - "mov ecx,edx;" - "mov eax,dword ptr [ecx];" - "add edx,0x8;" - "test eax,eax;" - "je label7;" - "cmp dword ptr [eax],ecx;" - "je label8;" - "label9:;" - "mov eax,dword ptr [eax];" - "add eax,0x4;" - "cmp dword ptr [eax],ecx;" - "jne label9;" - "label8:;" - "mov ecx,dword ptr [ecx+0x4];" - "mov dword ptr [eax],ecx;" - "label7:;" - "cmp edx,esi;" - "jne label6;" - "mov edx,dword ptr [esp+0x3C];" - "label5:;" - "cmp edx,dword ptr [esp+0x48];" - "je RR_L2;" - "push edx;" - ); - asm( - "call -0x1000 +11023682;" - "add esp,0x4;" - "RR_L2:;" - "mov ecx,dword ptr [ebp+0x8];" - "mov eax,dword ptr [ecx];" - "cmp eax,ecx;" - "mov dword ptr [esp+0xC],eax;" - "je label10;" - "label11:;" - "fld dword ptr [esp+0x1AC];" - "push ecx;" - "fstp dword ptr [esp];" - "lea esi,dword ptr [eax+0x30];" - "push esi;" - "lea edx,dword ptr [esp+0x1C];" - "push edx;" - "mov ecx,edi;" - ); - asm( - "call %[SelectionRings];" - "lea eax,dword ptr [esp+0x14];" - "push eax;" - "mov eax,dword ptr [esp+0x1AC];" - "lea edx,dword ptr [esi+0x78];" - "push edx;" - "lea ecx,dword ptr [esi+0x80];" - "add esi,0x58;" - "push esi;" - "push eax;" - "push ebp;" - "mov edx,ebx;" - : - : [SelectionRings] "i" (SelectionRings) - : "memory" - ); - asm( - "call -0x1000 +8324512;" - "lea edx,dword ptr [esp+0xC];" - ); - asm( - "call -0x1000 +8335440;" - "mov eax,dword ptr [esp+0xC];" - "cmp eax,dword ptr [ebp+0x8];" - "jne label11;" - "label10:;" - "mov esi,dword ptr [esp+0x1A8];" - "fld dword ptr [esp+0x1AC];" - "push esi;" - "push ecx;" - "fstp dword ptr [esp];" - "push ebx;" - "lea ecx,dword ptr [esp+0x20];" - "push ecx;" - "push ebp;" - "mov eax,edi;" - ); - - asm( - "call -0x1000 +8324128;" - "lea eax,dword ptr [esp+0x14];" - ); - asm( - "call -0x1000 +8323520;" - "movss xmm0,dword ptr [0xDFEC20];" - "movss xmm1,dword ptr [0xDFEB0C];" - "lea edx,dword ptr [esp+0x14];" - "push edx;" - "lea eax,dword ptr [esp+0x10];" - "push eax;" - "lea ecx,dword ptr [esp+0x34];" - "push ecx;" - "push esi;" - "movss dword ptr [esp+0x34],xmm0;" - "movss dword ptr [esp+0x38],xmm1;" - "movss xmm1,dword ptr [0xE4F714];" - "movss dword ptr [esp+0x20],xmm0;" - "movss xmm0,dword ptr [0xE4F8A8];" - "push ebp;" - "lea ecx,dword ptr [esp+0x38];" - "mov edx,ebx;" - "movss dword ptr [esp+0x20],xmm1;" - "movss dword ptr [esp+0x40],xmm0;" - "movss dword ptr [esp+0x44],xmm0;" - "movss dword ptr [esp+0x48],xmm0;" - "movss dword ptr [esp+0x4C],xmm0;" - ); - asm( - "call -0x1000 +8324512;" - "mov eax,dword ptr [esp+0x18];" - "test eax,eax;" - "je label12;" - "push eax;" - ); - asm( - "call -0x1000 +9800288;" - "add esp,0x4;" - "label12:;" - "mov ecx,dword ptr [esp+0x194];" - "pop edi;" - "pop esi;" - "mov dword ptr [fs:0x0],ecx;" - "pop ebp;" - "add esp,0x194;" - "ret 0xC;" - ); -} \ No newline at end of file diff --git a/section/SiloProgress.cpp b/section/SiloProgress.cpp index 0b905b92..c2825b42 100644 --- a/section/SiloProgress.cpp +++ b/section/SiloProgress.cpp @@ -1,206 +1,50 @@ #include "moho.h" +#include -struct struct_Resources // sizeof=0x8 +// overrides `Moho::CAiSiloBuildImpl::SiloTick` switch case 2 at 0x005CF42A +void __stdcall CheckSiloProgress(CAiSiloBuildImpl *self, SEconValue *res) { - float ENERGY; - float MASS; + CEconRequest *cons_data = self->mRequest; - struct_Resources(float e = 0, float m = 0) : ENERGY{e}, MASS{m} - { - } - - struct_Resources operator+(const struct_Resources &other) - { - return struct_Resources{ENERGY + other.ENERGY, MASS + other.MASS}; - } - - struct_Resources &operator+=(const struct_Resources &other) - { - ENERGY += other.ENERGY; - MASS += other.MASS; - return *this; - } - struct_Resources &operator-=(const struct_Resources &other) - { - ENERGY -= other.ENERGY; - MASS -= other.MASS; - return *this; - } - - struct_Resources operator*(float mul) - { - return struct_Resources{ENERGY * mul, MASS * mul}; - } - - struct_Resources &operator=(const struct_Resources &other) - { - ENERGY = other.ENERGY; - MASS = other.MASS; - return *this; - } -}; - -struct struct_ConsumptionData -{ - struct_ConsumptionData *next; - struct_ConsumptionData *prev; - struct_Resources perSecond; - struct_Resources addWhenSetOff; -}; - -struct struct_UnitData -{ - int dword0; - int dword4; - bool autoMode; - bool autoSurfaceMode; - bool isBusy; - bool byteB; - float fuelRatio; - float shieldRatio; - int stunTicks; - bool isPaused; - bool isValidTarget; - bool byte1A; - bool byte1B; - float dword1C; - /*Moho::EFireState*/ int fireState; - float workProgress; - int tacticalSiloBuildCount; - int nukeSiloBuildCount; - int tacticalSiloStorageCount; - int nukeSiloStorageCount; - int tacticalSiloMaxStorageCount; - int nukeSiloMaxStorageCount; - int dword40; - string customName; - float energyProduced; - float massProduced; - struct_Resources spent; - struct_Resources MaintainenceCost; - int focusUnit; - int dword7C; - int dword80; - int dword84; - int dword88; - int dword8C; - int dword90; - Vector3f vec3; - int dwordA0; - int dwordA4; - int gapA8; - bool v0; - bool v1; - bool v2; - bool v3; - bool gapB0[24]; - int dwordC8; - int dwordCC; - int dwordD0; - int dwordD4; - int gapD8; - int gapDC; - int gapE0; - int gapE4; - int gapE8; - float gapEC; - int gapF0; - int gapF4; - int gapF8; - bool gapFC[164]; - /*Moho::UnitAttributes*/ char attributes[0x70]; - unsigned int scriptbits; - bool gap214[4]; - int unitStates1; - int unitStates2; - /*Moho::CUnitMotion*/ void *unitMotion; -}; -VALIDATE_SIZE(struct_UnitData, 0x224); - -struct Moho_Unit -{ - void *vtable; - void *chain; - char entity[0x270]; - /*struct_StatItemRRef*/ char statRref[0x10]; - struct_UnitData unitData; -}; - -struct CAiSiloBuildImpl // sizeof=0x4C -{ - void *vtable; - Moho_Unit *unit; - int vec[3]; - int v5; - int v6; - int v7; - int v8; - int *v9; - int v10; - struct_ConsumptionData *cons_data; - signed __int32 state; - struct_Resources segment_cost; - struct_Resources segment_spent; - float segments; - float curSegments; -}; - -void __stdcall CheckSiloProgress(CAiSiloBuildImpl *silo_build, struct_Resources *res) -{ - struct_ConsumptionData *cons_data = silo_build->cons_data; - - float energy_ratio = cons_data->addWhenSetOff.ENERGY / silo_build->segment_cost.ENERGY; - float mass_ratio = cons_data->addWhenSetOff.MASS / silo_build->segment_cost.MASS; + float energy_ratio = cons_data->mAddWhenSetOff.ENERGY / self->mSegmentCost.ENERGY; + float mass_ratio = cons_data->mAddWhenSetOff.MASS / self->mSegmentCost.MASS; float available_ratio = (mass_ratio > energy_ratio ? energy_ratio : mass_ratio); - *res = cons_data->addWhenSetOff; - cons_data->addWhenSetOff = {0, 0}; + *res = cons_data->mAddWhenSetOff; + cons_data->mAddWhenSetOff = {0, 0}; - auto *unit = silo_build->unit; - unit->unitData.MaintainenceCost = silo_build->segment_cost; - unit->unitData.spent += *res; + auto *unit = self->mUnit; + unit->mUnitVarDat.mMaintainenceCost = self->mSegmentCost; + unit->mUnitVarDat.mResourcesSpent += *res; - silo_build->curSegments += available_ratio; - silo_build->unit->unitData.workProgress = silo_build->curSegments / silo_build->segments; + self->mCurSegments += available_ratio; + unit->mUnitVarDat.mWorkProgress = self->mCurSegments / self->mSegments; - if (silo_build->curSegments >= silo_build->segments) - { - silo_build->state = 3; - } + if (self->mCurSegments >= self->mSegments) + self->mState = 3; } -void __thiscall AddSiloEco(CAiSiloBuildImpl *silo_build, struct_Resources *econ) +// overrides `Moho::CAiSiloBuildImpl::SiloAssistWithResource` at 0x005CF030 +void __thiscall AddSiloEco(CAiSiloBuildImpl *self, SEconValue *econ) { - if (!silo_build->state) + if (self->mState == 0) return; - silo_build->segment_spent += *econ; + self->mSegmentSpent += *econ; - float energy_ratio = silo_build->segment_spent.ENERGY / silo_build->segment_cost.ENERGY; - float mass_ratio = silo_build->segment_spent.MASS / silo_build->segment_cost.MASS; - float available_ratio = (mass_ratio > energy_ratio ? energy_ratio : mass_ratio); - - float needed_segments = silo_build->segments - silo_build->curSegments; + float energy_ratio = self->mSegmentSpent.ENERGY / self->mSegmentCost.ENERGY; + float mass_ratio = self->mSegmentSpent.MASS / self->mSegmentCost.MASS; + float available_ratio = std::min(mass_ratio, energy_ratio); - auto *unit = silo_build->unit; + float needed_segments = self->mSegments - self->mCurSegments; + float used_ratio = std::min(needed_segments, available_ratio); - struct_Resources spent; - if (needed_segments > available_ratio) - { - spent = silo_build->segment_cost * available_ratio; - silo_build->curSegments += available_ratio; - silo_build->unit->unitData.workProgress = silo_build->curSegments / silo_build->segments; - } - else - { - spent = silo_build->segment_cost * needed_segments; - silo_build->curSegments += needed_segments; - silo_build->unit->unitData.workProgress = silo_build->curSegments / silo_build->segments; - } + SEconValue spent = self->mSegmentCost * used_ratio; + self->mCurSegments += used_ratio; + self->mUnit->mUnitVarDat.mWorkProgress = self->mCurSegments / self->mSegments; + self->mUnit->mUnitVarDat.mResourcesSpent += spent; - unit->unitData.spent += spent; + self->mSegmentSpent-= spent; - silo_build->segment_spent -= spent; - - if (silo_build->curSegments >= silo_build->segments) - silo_build->state = 3; -} \ No newline at end of file + if (self->mCurSegments >= self->mSegments) + self->mState = 3; +} diff --git a/section/SimGetDepositsAroundPoint.cpp b/section/SimGetDepositsAroundPoint.cpp index b233705c..31f60dec 100644 --- a/section/SimGetDepositsAroundPoint.cpp +++ b/section/SimGetDepositsAroundPoint.cpp @@ -19,8 +19,8 @@ int SimGetDepositsAroundPoint(lua_State *L) { lua_newtable(L); int i = 1; - auto deposit = g_Sim->res->deposits.begin; - auto endDeposit = g_Sim->res->deposits.end; + auto deposit = g_Sim->mSimResources->deposits.begin(); + auto endDeposit = g_Sim->mSimResources->deposits.end(); for (; deposit < endDeposit; deposit++) { if (Type && Type != deposit->Type) continue; float x = (deposit->X2 + deposit->X1) * 0.5f - X; @@ -44,4 +44,4 @@ int SimGetDepositsAroundPoint(lua_State *L) { #define s_GDAPDesc "(X, Z, Radius, Type)" UIRegFunc SGDAPRegDesc{s_GDAPName,s_GDAPDesc, SimGetDepositsAroundPoint}; -SimRegFunc UGDAPRegDesc{s_GDAPName, s_GDAPDesc, SimGetDepositsAroundPoint}; \ No newline at end of file +SimRegFunc UGDAPRegDesc{s_GDAPName, s_GDAPDesc, SimGetDepositsAroundPoint}; diff --git a/section/SimSetCommandSource.cpp b/section/SimSetCommandSource.cpp index 6f1a72b1..89e37427 100644 --- a/section/SimSetCommandSource.cpp +++ b/section/SimSetCommandSource.cpp @@ -6,8 +6,8 @@ int SimSetCommandSource(lua_State *L) { int sourceI = lua_tonumber(L, 2); bool set_or_unset = lua_toboolean(L, 3); - auto srcSet = &g_Sim->armies[armyI]->mValidCommandSources; - srcSet->set(sourceI, set_or_unset); + auto srcSet = &g_Sim->mArmiesList[armyI]->mVarDat.mValidCommandSources; + srcSet->Set(sourceI, set_or_unset); return 0; }