Skip to content

Commit

Permalink
Add LOD support for buildings (#3371)
Browse files Browse the repository at this point in the history
  • Loading branch information
TheNormalnij authored May 25, 2024
1 parent 74781c6 commit 77ab3e6
Show file tree
Hide file tree
Showing 11 changed files with 191 additions and 30 deletions.
49 changes: 49 additions & 0 deletions Client/game_sa/CBuildingSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,57 @@

#include "StdInc.h"
#include "CBuildingSA.h"
#include <game/CWorld.h>
#include "CGameSA.h"

extern CGameSA* pGame;

CBuildingSA::CBuildingSA(CBuildingSAInterface* pInterface)
{
SetInterface(pInterface);
}

void CBuildingSA::SetLod(CBuilding* pLod)
{
if (pLod)
{
if (m_pInterface->m_pLod)
{
SetLod(nullptr);
}

CBuildingSAInterface* pLodInterface = dynamic_cast<CBuildingSA*>(pLod)->GetBuildingInterface();
assert(pLodInterface);

// We should recreate buildings...
pGame->GetWorld()->Remove(pLodInterface, CBuilding_SetLod);
pGame->GetWorld()->Remove(m_pInterface, CBuilding_SetLod);

m_pInterface->m_pLod = pLodInterface;
pLodInterface->bUsesCollision = 0;
pLodInterface->numLodChildren = 1;

if (pGame->GetModelInfo(pLodInterface->m_nModelIndex)->GetLODDistance() > 300)
{
pLodInterface->bIsBIGBuilding = 1;
}

// Only this specific order works
pGame->GetWorld()->Add(m_pInterface, CBuilding_SetLod);
pGame->GetWorld()->Add(pLodInterface, CBuilding_SetLod);
}
else
{
CEntitySAInterface* pCurrentLod = m_pInterface->m_pLod;
if (pCurrentLod)
{
pGame->GetWorld()->Remove(pCurrentLod, CBuilding_SetLod);

m_pInterface->m_pLod = nullptr;
pCurrentLod->bIsBIGBuilding = false;
pCurrentLod->numLodChildren = 0;

pGame->GetWorld()->Add(pCurrentLod, CBuilding_SetLod);
}
}
}
4 changes: 3 additions & 1 deletion Client/game_sa/CBuildingSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@ class CBuildingSA final : public virtual CBuilding, public virtual CEntitySA
public:
CBuildingSA(CBuildingSAInterface* pInterface);

CBuildingSAInterface* GetBuildingInterface() { return reinterpret_cast<CBuildingSAInterface*>(GetInterface()); };
CBuildingSAInterface* GetBuildingInterface() { return static_cast<CBuildingSAInterface*>(GetInterface()); };

void SetLod(CBuilding* pLod) override;
};
67 changes: 63 additions & 4 deletions Client/mods/deathmatch/logic/CClientBuilding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ CClientBuilding::CClientBuilding(class CClientManager* pManager, ElementID ID, u
m_vPos(pos),
m_vRot(rot),
m_interior(interior),
m_pBuilding(nullptr)
m_pBuilding(nullptr),
m_pHighBuilding(nullptr),
m_pLowBuilding(nullptr)
{
m_pManager = pManager;
SetTypeName("building");
Expand All @@ -29,6 +31,18 @@ CClientBuilding::CClientBuilding(class CClientManager* pManager, ElementID ID, u
CClientBuilding::~CClientBuilding()
{
m_pBuildingManager->RemoveFromList(this);
}

void CClientBuilding::Unlink()
{
if (m_pHighBuilding)
{
m_pHighBuilding->SetLowLodBuilding();
}
if (m_pLowBuilding)
{
SetLowLodBuilding();
}
Destroy();
}

Expand Down Expand Up @@ -93,17 +107,62 @@ void CClientBuilding::Create()
if (m_pBuilding)
return;

if (m_bBeingDeleted)
return;

CVector4D vRot4D;
ConvertZXYEulersToQuaternion(m_vRot, vRot4D);

m_pBuilding = g_pGame->GetPools()->GetBuildingsPool().AddBuilding(this, m_usModelId, &m_vPos, &vRot4D, m_interior);

if (m_pHighBuilding)
{
m_pHighBuilding->GetBuildingEntity()->SetLod(m_pBuilding);
}
}

void CClientBuilding::Destroy()
{
if (m_pBuilding)
if (!m_pBuilding)
return;

if (m_pHighBuilding)
{
g_pGame->GetPools()->GetBuildingsPool().RemoveBuilding(m_pBuilding);
m_pBuilding = nullptr;
m_pHighBuilding->GetBuildingEntity()->SetLod(nullptr);
}
g_pGame->GetPools()->GetBuildingsPool().RemoveBuilding(m_pBuilding);
m_pBuilding = nullptr;
}

bool CClientBuilding::SetLowLodBuilding(CClientBuilding* pLod)
{
if (pLod)
{
// Remove prev LOD
SetLowLodBuilding();

// Unlink old high lod element
CClientBuilding* pOveridedBuilding = pLod->GetHighLodBuilding();
if (pOveridedBuilding && pOveridedBuilding != this)
{
pOveridedBuilding->SetLowLodBuilding();
}

// Add new LOD
m_pLowBuilding = pLod;
m_pBuilding->SetLod(pLod->GetBuildingEntity());

pLod->SetHighLodBuilding(this);
}
else
{
// Remove LOD
if (m_pLowBuilding)
{
m_pLowBuilding->SetHighLodBuilding();
}
m_pBuilding->SetLod(nullptr);
m_pLowBuilding = nullptr;
}
return true;
}
14 changes: 13 additions & 1 deletion Client/mods/deathmatch/logic/CClientBuilding.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ class CClientBuilding : public CClientEntity
CClientBuilding(class CClientManager* pManager, ElementID ID, uint16_t usModelId, const CVector &pos, const CVector &rot, uint8_t interior);
~CClientBuilding();

void Unlink(){};
void Unlink();
void GetPosition(CVector& vecPosition) const override { vecPosition = m_vPos; };
void SetPosition(const CVector& vecPosition) override;

void GetRotationRadians(CVector& vecOutRadians) const override { vecOutRadians = m_vRot; };
void SetRotationRadians(const CVector& vecRadians) override;

CBuilding* GetBuildingEntity() const { return m_pBuilding; };
CEntity* GetGameEntity() override { return m_pBuilding; };
const CEntity* GetGameEntity() const override { return m_pBuilding; };

Expand All @@ -46,7 +47,15 @@ class CClientBuilding : public CClientEntity
void Destroy();
bool IsValid() const noexcept { return m_pBuilding != nullptr; };


CClientBuilding* GetLowLodBuilding() const noexcept { return m_pLowBuilding; };
bool SetLowLodBuilding(CClientBuilding* pLod = nullptr);
bool IsLod() const noexcept { return m_pHighBuilding != nullptr; };


private:
CClientBuilding* GetHighLodBuilding() const { return m_pHighBuilding; };
void SetHighLodBuilding(CClientBuilding* pHighBuilding = nullptr) { m_pHighBuilding = pHighBuilding; };

void Recreate()
{
Expand All @@ -62,4 +71,7 @@ class CClientBuilding : public CClientEntity
CVector m_vPos;
CVector m_vRot;
uint8_t m_interior;

CClientBuilding* m_pHighBuilding;
CClientBuilding* m_pLowBuilding;
};
27 changes: 26 additions & 1 deletion Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3830,7 +3830,12 @@ bool CStaticFunctionDefinitions::SetLowLodElement(CClientEntity& Entity, CClient
{
RUN_CHILDREN(SetLowLodElement(**iter, pLowLodEntity))

switch (Entity.GetType())
eClientEntityType entityType = Entity.GetType();

if (pLowLodEntity != nullptr && entityType != pLowLodEntity->GetType())
return false;

switch (entityType)
{
case CCLIENTOBJECT:
{
Expand All @@ -3840,6 +3845,14 @@ bool CStaticFunctionDefinitions::SetLowLodElement(CClientEntity& Entity, CClient
return false;
break;
}
case CCLIENTBUILDING:
{
CClientBuilding& Building = static_cast<CClientBuilding&>(Entity);
CClientBuilding* pLowLodBuilding = static_cast<CClientBuilding*>(pLowLodEntity);
if (!Building.SetLowLodBuilding(pLowLodBuilding))
return false;
break;
}
default:
return false;
}
Expand All @@ -3859,6 +3872,12 @@ bool CStaticFunctionDefinitions::GetLowLodElement(CClientEntity& Entity, CClient
pOutLowLodEntity = Object.GetLowLodObject();
break;
}
case CCLIENTBUILDING:
{
CClientBuilding& Building = static_cast<CClientBuilding&>(Entity);
pOutLowLodEntity = Building.GetLowLodBuilding();
break;
}
default:
return false;
}
Expand All @@ -3878,6 +3897,12 @@ bool CStaticFunctionDefinitions::IsElementLowLod(CClientEntity& Entity, bool& bO
bOutIsLowLod = Object.IsLowLod();
break;
}
case CCLIENTBUILDING:
{
CClientBuilding& Building = static_cast<CClientBuilding&>(Entity);
bOutIsLowLod = Building.IsLod();
break;
}
default:
return false;
}
Expand Down
25 changes: 25 additions & 0 deletions Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,31 @@ bool MinClientReqCheck(CScriptArgReader& argStream, const char* szVersionReq, co
return true;
}

//
// Check min client is correct
// Thrown a error if below required
//
void MinClientReqCheck(lua_State* luaVM, const char* szVersionReq, const char* szReason)
{
CLuaMain* pLuaMain = g_pClientGame->GetLuaManager()->GetVirtualMachine(luaVM);
if (!pLuaMain)
return;

CResource* pResource = pLuaMain->GetResource();
if (!pResource)
return;

if (pResource->GetMinClientReq() < szVersionReq)
{
#if MTASA_VERSION_TYPE == VERSION_TYPE_RELEASE
SString err("<min_mta_version> section in the meta.xml is incorrect or missing (expected at least client %s because %s)",
szVersionReq, szReason);
throw std::invalid_argument(err);
#endif
}

}

//
// Read next as preg option flags
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,7 @@ void MixedReadDxFontString(CScriptArgReader& argStream, eFontType& outFontType,
void MixedReadGuiFontString(CScriptArgReader& argStream, SString& strFontName, const char* szDefaultFontName, CClientGuiFont*& poutGuiFontElement);
void MixedReadMaterialString(CScriptArgReader& argStream, CClientMaterial*& pMaterialElement);
bool ReadMatrix(lua_State* luaVM, uint uiArgIndex, CMatrix& outMatrix);
void MinClientReqCheck(lua_State* luaVM, const char* szVersionReq, const char* szReason);
bool MinClientReqCheck(CScriptArgReader& argStream, const char* szVersionReq, const char* szReason = nullptr);
void ReadPregFlags(CScriptArgReader& argStream, pcrecpp::RE_Options& pOptions);

Expand Down
29 changes: 8 additions & 21 deletions Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#include <lua/CLuaFunctionParser.h>
using std::list;

#define MIN_CLIENT_REQ_LOD_FOR_BUILDING "1.6.0-0.20000"

void CLuaElementDefs::LoadFunctions()
{
constexpr static const std::pair<const char*, lua_CFunction> functions[]{
Expand Down Expand Up @@ -95,7 +97,7 @@ void CLuaElementDefs::LoadFunctions()
{"setElementCollidableWith", SetElementCollidableWith},
{"setElementDoubleSided", SetElementDoubleSided},
{"setElementFrozen", SetElementFrozen},
{"setLowLODElement", SetLowLodElement},
{"setLowLODElement", ArgumentParser<SetLowLodElement>},
{"setElementCallPropagationEnabled", SetElementCallPropagationEnabled},
};

Expand Down Expand Up @@ -2497,29 +2499,14 @@ int CLuaElementDefs::GetLowLodElement(lua_State* luaVM)
return 1;
}

int CLuaElementDefs::SetLowLodElement(lua_State* luaVM)
bool CLuaElementDefs::SetLowLodElement(lua_State* luaVM, CClientEntity* pEntity, std::optional<CClientEntity*> pLowLodEntity)
{
// bool setLowLODElement ( element theElement )
CClientEntity* pEntity;
CClientEntity* pLowLodEntity;

CScriptArgReader argStream(luaVM);
argStream.ReadUserData(pEntity);
argStream.ReadUserData(pLowLodEntity, NULL);
// bool setLowLODElement ( element theElement [, element lowLowElement ] )

if (!argStream.HasErrors())
{
if (CStaticFunctionDefinitions::SetLowLodElement(*pEntity, pLowLodEntity))
{
lua_pushboolean(luaVM, true);
return 1;
}
}
else
m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage());
if (pEntity->GetType() == CCLIENTBUILDING)
MinClientReqCheck(luaVM, MIN_CLIENT_REQ_LOD_FOR_BUILDING, "target is building");

lua_pushboolean(luaVM, false);
return 1;
return CStaticFunctionDefinitions::SetLowLodElement(*pEntity, pLowLodEntity.value_or(nullptr));
}

int CLuaElementDefs::IsElementLowLod(lua_State* luaVM)
Expand Down
2 changes: 1 addition & 1 deletion Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,6 @@ class CLuaElementDefs : public CLuaDefs
LUA_DECLARE(SetElementCollidableWith);
LUA_DECLARE(SetElementDoubleSided);
LUA_DECLARE(SetElementFrozen);
LUA_DECLARE(SetLowLodElement);
static bool SetLowLodElement(lua_State* luaVM, CClientEntity* pEntity, std::optional<CClientEntity*> pLowLodEntity);
LUA_DECLARE(SetElementCallPropagationEnabled);
};
1 change: 1 addition & 0 deletions Client/sdk/game/CBuilding.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ class CBuilding : public virtual CEntity
virtual ~CBuilding(){};

virtual CBuildingSAInterface* GetBuildingInterface() = 0;
virtual void SetLod(CBuilding* pLod) = 0;
};
2 changes: 1 addition & 1 deletion Client/sdk/game/CWorld.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ enum eDebugCaller
CBuilding_Destructor,
CBuildingPool_Constructor,
CBuildingPool_Destructor,

CBuilding_SetLod,
};

enum eSurfaceProperties
Expand Down

0 comments on commit 77ab3e6

Please sign in to comment.