Skip to content

Commit cf29919

Browse files
Synchronize changes from 1.6 master branch [ci skip]
77ab3e6 Add LOD support for buildings (#3371)
2 parents df4d660 + 77ab3e6 commit cf29919

File tree

11 files changed

+191
-30
lines changed

11 files changed

+191
-30
lines changed

Client/game_sa/CBuildingSA.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,57 @@
1111

1212
#include "StdInc.h"
1313
#include "CBuildingSA.h"
14+
#include <game/CWorld.h>
15+
#include "CGameSA.h"
16+
17+
extern CGameSA* pGame;
1418

1519
CBuildingSA::CBuildingSA(CBuildingSAInterface* pInterface)
1620
{
1721
SetInterface(pInterface);
1822
}
23+
24+
void CBuildingSA::SetLod(CBuilding* pLod)
25+
{
26+
if (pLod)
27+
{
28+
if (m_pInterface->m_pLod)
29+
{
30+
SetLod(nullptr);
31+
}
32+
33+
CBuildingSAInterface* pLodInterface = dynamic_cast<CBuildingSA*>(pLod)->GetBuildingInterface();
34+
assert(pLodInterface);
35+
36+
// We should recreate buildings...
37+
pGame->GetWorld()->Remove(pLodInterface, CBuilding_SetLod);
38+
pGame->GetWorld()->Remove(m_pInterface, CBuilding_SetLod);
39+
40+
m_pInterface->m_pLod = pLodInterface;
41+
pLodInterface->bUsesCollision = 0;
42+
pLodInterface->numLodChildren = 1;
43+
44+
if (pGame->GetModelInfo(pLodInterface->m_nModelIndex)->GetLODDistance() > 300)
45+
{
46+
pLodInterface->bIsBIGBuilding = 1;
47+
}
48+
49+
// Only this specific order works
50+
pGame->GetWorld()->Add(m_pInterface, CBuilding_SetLod);
51+
pGame->GetWorld()->Add(pLodInterface, CBuilding_SetLod);
52+
}
53+
else
54+
{
55+
CEntitySAInterface* pCurrentLod = m_pInterface->m_pLod;
56+
if (pCurrentLod)
57+
{
58+
pGame->GetWorld()->Remove(pCurrentLod, CBuilding_SetLod);
59+
60+
m_pInterface->m_pLod = nullptr;
61+
pCurrentLod->bIsBIGBuilding = false;
62+
pCurrentLod->numLodChildren = 0;
63+
64+
pGame->GetWorld()->Add(pCurrentLod, CBuilding_SetLod);
65+
}
66+
}
67+
}

Client/game_sa/CBuildingSA.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,7 @@ class CBuildingSA final : public virtual CBuilding, public virtual CEntitySA
2424
public:
2525
CBuildingSA(CBuildingSAInterface* pInterface);
2626

27-
CBuildingSAInterface* GetBuildingInterface() { return reinterpret_cast<CBuildingSAInterface*>(GetInterface()); };
27+
CBuildingSAInterface* GetBuildingInterface() { return static_cast<CBuildingSAInterface*>(GetInterface()); };
28+
29+
void SetLod(CBuilding* pLod) override;
2830
};

Client/mods/deathmatch/logic/CClientBuilding.cpp

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ CClientBuilding::CClientBuilding(class CClientManager* pManager, ElementID ID, u
1818
m_vPos(pos),
1919
m_vRot(rot),
2020
m_interior(interior),
21-
m_pBuilding(nullptr)
21+
m_pBuilding(nullptr),
22+
m_pHighBuilding(nullptr),
23+
m_pLowBuilding(nullptr)
2224
{
2325
m_pManager = pManager;
2426
SetTypeName("building");
@@ -29,6 +31,18 @@ CClientBuilding::CClientBuilding(class CClientManager* pManager, ElementID ID, u
2931
CClientBuilding::~CClientBuilding()
3032
{
3133
m_pBuildingManager->RemoveFromList(this);
34+
}
35+
36+
void CClientBuilding::Unlink()
37+
{
38+
if (m_pHighBuilding)
39+
{
40+
m_pHighBuilding->SetLowLodBuilding();
41+
}
42+
if (m_pLowBuilding)
43+
{
44+
SetLowLodBuilding();
45+
}
3246
Destroy();
3347
}
3448

@@ -93,17 +107,62 @@ void CClientBuilding::Create()
93107
if (m_pBuilding)
94108
return;
95109

110+
if (m_bBeingDeleted)
111+
return;
112+
96113
CVector4D vRot4D;
97114
ConvertZXYEulersToQuaternion(m_vRot, vRot4D);
98115

99116
m_pBuilding = g_pGame->GetPools()->GetBuildingsPool().AddBuilding(this, m_usModelId, &m_vPos, &vRot4D, m_interior);
117+
118+
if (m_pHighBuilding)
119+
{
120+
m_pHighBuilding->GetBuildingEntity()->SetLod(m_pBuilding);
121+
}
100122
}
101123

102124
void CClientBuilding::Destroy()
103125
{
104-
if (m_pBuilding)
126+
if (!m_pBuilding)
127+
return;
128+
129+
if (m_pHighBuilding)
105130
{
106-
g_pGame->GetPools()->GetBuildingsPool().RemoveBuilding(m_pBuilding);
107-
m_pBuilding = nullptr;
131+
m_pHighBuilding->GetBuildingEntity()->SetLod(nullptr);
108132
}
133+
g_pGame->GetPools()->GetBuildingsPool().RemoveBuilding(m_pBuilding);
134+
m_pBuilding = nullptr;
135+
}
136+
137+
bool CClientBuilding::SetLowLodBuilding(CClientBuilding* pLod)
138+
{
139+
if (pLod)
140+
{
141+
// Remove prev LOD
142+
SetLowLodBuilding();
143+
144+
// Unlink old high lod element
145+
CClientBuilding* pOveridedBuilding = pLod->GetHighLodBuilding();
146+
if (pOveridedBuilding && pOveridedBuilding != this)
147+
{
148+
pOveridedBuilding->SetLowLodBuilding();
149+
}
150+
151+
// Add new LOD
152+
m_pLowBuilding = pLod;
153+
m_pBuilding->SetLod(pLod->GetBuildingEntity());
154+
155+
pLod->SetHighLodBuilding(this);
156+
}
157+
else
158+
{
159+
// Remove LOD
160+
if (m_pLowBuilding)
161+
{
162+
m_pLowBuilding->SetHighLodBuilding();
163+
}
164+
m_pBuilding->SetLod(nullptr);
165+
m_pLowBuilding = nullptr;
166+
}
167+
return true;
109168
}

Client/mods/deathmatch/logic/CClientBuilding.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@ class CClientBuilding : public CClientEntity
2323
CClientBuilding(class CClientManager* pManager, ElementID ID, uint16_t usModelId, const CVector &pos, const CVector &rot, uint8_t interior);
2424
~CClientBuilding();
2525

26-
void Unlink(){};
26+
void Unlink();
2727
void GetPosition(CVector& vecPosition) const override { vecPosition = m_vPos; };
2828
void SetPosition(const CVector& vecPosition) override;
2929

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

33+
CBuilding* GetBuildingEntity() const { return m_pBuilding; };
3334
CEntity* GetGameEntity() override { return m_pBuilding; };
3435
const CEntity* GetGameEntity() const override { return m_pBuilding; };
3536

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

50+
51+
CClientBuilding* GetLowLodBuilding() const noexcept { return m_pLowBuilding; };
52+
bool SetLowLodBuilding(CClientBuilding* pLod = nullptr);
53+
bool IsLod() const noexcept { return m_pHighBuilding != nullptr; };
54+
55+
4956
private:
57+
CClientBuilding* GetHighLodBuilding() const { return m_pHighBuilding; };
58+
void SetHighLodBuilding(CClientBuilding* pHighBuilding = nullptr) { m_pHighBuilding = pHighBuilding; };
5059

5160
void Recreate()
5261
{
@@ -62,4 +71,7 @@ class CClientBuilding : public CClientEntity
6271
CVector m_vPos;
6372
CVector m_vRot;
6473
uint8_t m_interior;
74+
75+
CClientBuilding* m_pHighBuilding;
76+
CClientBuilding* m_pLowBuilding;
6577
};

Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3830,7 +3830,12 @@ bool CStaticFunctionDefinitions::SetLowLodElement(CClientEntity& Entity, CClient
38303830
{
38313831
RUN_CHILDREN(SetLowLodElement(**iter, pLowLodEntity))
38323832

3833-
switch (Entity.GetType())
3833+
eClientEntityType entityType = Entity.GetType();
3834+
3835+
if (pLowLodEntity != nullptr && entityType != pLowLodEntity->GetType())
3836+
return false;
3837+
3838+
switch (entityType)
38343839
{
38353840
case CCLIENTOBJECT:
38363841
{
@@ -3840,6 +3845,14 @@ bool CStaticFunctionDefinitions::SetLowLodElement(CClientEntity& Entity, CClient
38403845
return false;
38413846
break;
38423847
}
3848+
case CCLIENTBUILDING:
3849+
{
3850+
CClientBuilding& Building = static_cast<CClientBuilding&>(Entity);
3851+
CClientBuilding* pLowLodBuilding = static_cast<CClientBuilding*>(pLowLodEntity);
3852+
if (!Building.SetLowLodBuilding(pLowLodBuilding))
3853+
return false;
3854+
break;
3855+
}
38433856
default:
38443857
return false;
38453858
}
@@ -3859,6 +3872,12 @@ bool CStaticFunctionDefinitions::GetLowLodElement(CClientEntity& Entity, CClient
38593872
pOutLowLodEntity = Object.GetLowLodObject();
38603873
break;
38613874
}
3875+
case CCLIENTBUILDING:
3876+
{
3877+
CClientBuilding& Building = static_cast<CClientBuilding&>(Entity);
3878+
pOutLowLodEntity = Building.GetLowLodBuilding();
3879+
break;
3880+
}
38623881
default:
38633882
return false;
38643883
}
@@ -3878,6 +3897,12 @@ bool CStaticFunctionDefinitions::IsElementLowLod(CClientEntity& Entity, bool& bO
38783897
bOutIsLowLod = Object.IsLowLod();
38793898
break;
38803899
}
3900+
case CCLIENTBUILDING:
3901+
{
3902+
CClientBuilding& Building = static_cast<CClientBuilding&>(Entity);
3903+
bOutIsLowLod = Building.IsLod();
3904+
break;
3905+
}
38813906
default:
38823907
return false;
38833908
}

Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,31 @@ bool MinClientReqCheck(CScriptArgReader& argStream, const char* szVersionReq, co
10991099
return true;
11001100
}
11011101

1102+
//
1103+
// Check min client is correct
1104+
// Thrown a error if below required
1105+
//
1106+
void MinClientReqCheck(lua_State* luaVM, const char* szVersionReq, const char* szReason)
1107+
{
1108+
CLuaMain* pLuaMain = g_pClientGame->GetLuaManager()->GetVirtualMachine(luaVM);
1109+
if (!pLuaMain)
1110+
return;
1111+
1112+
CResource* pResource = pLuaMain->GetResource();
1113+
if (!pResource)
1114+
return;
1115+
1116+
if (pResource->GetMinClientReq() < szVersionReq)
1117+
{
1118+
#if MTASA_VERSION_TYPE == VERSION_TYPE_RELEASE
1119+
SString err("<min_mta_version> section in the meta.xml is incorrect or missing (expected at least client %s because %s)",
1120+
szVersionReq, szReason);
1121+
throw std::invalid_argument(err);
1122+
#endif
1123+
}
1124+
1125+
}
1126+
11021127
//
11031128
// Read next as preg option flags
11041129
//

Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,7 @@ void MixedReadDxFontString(CScriptArgReader& argStream, eFontType& outFontType,
575575
void MixedReadGuiFontString(CScriptArgReader& argStream, SString& strFontName, const char* szDefaultFontName, CClientGuiFont*& poutGuiFontElement);
576576
void MixedReadMaterialString(CScriptArgReader& argStream, CClientMaterial*& pMaterialElement);
577577
bool ReadMatrix(lua_State* luaVM, uint uiArgIndex, CMatrix& outMatrix);
578+
void MinClientReqCheck(lua_State* luaVM, const char* szVersionReq, const char* szReason);
578579
bool MinClientReqCheck(CScriptArgReader& argStream, const char* szVersionReq, const char* szReason = nullptr);
579580
void ReadPregFlags(CScriptArgReader& argStream, pcrecpp::RE_Options& pOptions);
580581

Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include <lua/CLuaFunctionParser.h>
1515
using std::list;
1616

17+
#define MIN_CLIENT_REQ_LOD_FOR_BUILDING "1.6.0-0.20000"
18+
1719
void CLuaElementDefs::LoadFunctions()
1820
{
1921
constexpr static const std::pair<const char*, lua_CFunction> functions[]{
@@ -95,7 +97,7 @@ void CLuaElementDefs::LoadFunctions()
9597
{"setElementCollidableWith", SetElementCollidableWith},
9698
{"setElementDoubleSided", SetElementDoubleSided},
9799
{"setElementFrozen", SetElementFrozen},
98-
{"setLowLODElement", SetLowLodElement},
100+
{"setLowLODElement", ArgumentParser<SetLowLodElement>},
99101
{"setElementCallPropagationEnabled", SetElementCallPropagationEnabled},
100102
};
101103

@@ -2497,29 +2499,14 @@ int CLuaElementDefs::GetLowLodElement(lua_State* luaVM)
24972499
return 1;
24982500
}
24992501

2500-
int CLuaElementDefs::SetLowLodElement(lua_State* luaVM)
2502+
bool CLuaElementDefs::SetLowLodElement(lua_State* luaVM, CClientEntity* pEntity, std::optional<CClientEntity*> pLowLodEntity)
25012503
{
2502-
// bool setLowLODElement ( element theElement )
2503-
CClientEntity* pEntity;
2504-
CClientEntity* pLowLodEntity;
2505-
2506-
CScriptArgReader argStream(luaVM);
2507-
argStream.ReadUserData(pEntity);
2508-
argStream.ReadUserData(pLowLodEntity, NULL);
2504+
// bool setLowLODElement ( element theElement [, element lowLowElement ] )
25092505

2510-
if (!argStream.HasErrors())
2511-
{
2512-
if (CStaticFunctionDefinitions::SetLowLodElement(*pEntity, pLowLodEntity))
2513-
{
2514-
lua_pushboolean(luaVM, true);
2515-
return 1;
2516-
}
2517-
}
2518-
else
2519-
m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage());
2506+
if (pEntity->GetType() == CCLIENTBUILDING)
2507+
MinClientReqCheck(luaVM, MIN_CLIENT_REQ_LOD_FOR_BUILDING, "target is building");
25202508

2521-
lua_pushboolean(luaVM, false);
2522-
return 1;
2509+
return CStaticFunctionDefinitions::SetLowLodElement(*pEntity, pLowLodEntity.value_or(nullptr));
25232510
}
25242511

25252512
int CLuaElementDefs::IsElementLowLod(lua_State* luaVM)

Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,6 @@ class CLuaElementDefs : public CLuaDefs
9797
LUA_DECLARE(SetElementCollidableWith);
9898
LUA_DECLARE(SetElementDoubleSided);
9999
LUA_DECLARE(SetElementFrozen);
100-
LUA_DECLARE(SetLowLodElement);
100+
static bool SetLowLodElement(lua_State* luaVM, CClientEntity* pEntity, std::optional<CClientEntity*> pLowLodEntity);
101101
LUA_DECLARE(SetElementCallPropagationEnabled);
102102
};

Client/sdk/game/CBuilding.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ class CBuilding : public virtual CEntity
2121
virtual ~CBuilding(){};
2222

2323
virtual CBuildingSAInterface* GetBuildingInterface() = 0;
24+
virtual void SetLod(CBuilding* pLod) = 0;
2425
};

0 commit comments

Comments
 (0)