Skip to content

Commit fcdda9a

Browse files
committed
Merge pull request #13 from thelink2012/dynarray
Dynamic Visible Entities List
2 parents 301114a + 607d403 commit fcdda9a

File tree

7 files changed

+266
-113
lines changed

7 files changed

+266
-113
lines changed

doc/limit_adjuster_gta3vcsa.ini

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ PedAttractors = unlimited
2121
MatrixList = unlimited
2222
OutsideWorldWaterBlocks = 500
2323
AlphaEntityList = unlimited
24-
InVisibleEntityPtrs = 5000
25-
VisibleEntityPtrs = 5000
24+
VisibleEntityPtrs = unlimited
25+
VisibleLodPtrs = unlimited
2626
StreamingObjectInstancesList = 7500
2727
TimeModels = 1500
2828

@@ -38,8 +38,7 @@ Dummys = 9500
3838
AudioScriptObj = 192
3939
ColModel = 10500
4040
AlphaEntityList = 1250
41-
InVisibleEntityPtrs = 5000
42-
VisibleEntityPtrs = 5000
41+
VisibleEntityPtrs = unlimited
4342
TimeModels = 1500
4443

4544
[GTA3LIMITS]
@@ -51,8 +50,7 @@ Buildings = 35500
5150
Objects = 9500
5251
Dummys = 22802
5352
AlphaEntityList = 1250
54-
InVisibleEntityPtrs = 5000
55-
VisibleEntityPtrs = 5000
53+
VisibleEntityPtrs = unlimited
5654
TimeModels = 1500
5755

5856
[OPTIONS]
@@ -139,11 +137,11 @@ DebugTextKey = 0x74 ; F5 -- Use an VKEY (see http://msdn.microsoft.com/pt-br/li
139137
; ### AlphaEntityList [CanBeUnlimited]
140138
; List of entities (non-vehicle) to be rendered that contains alpha components (textures, object is going from invisible to visible state...)
141139
;
142-
; ### InVisibleEntityPtrs
143-
; ?
140+
; ### VisibleEntityPtrs [CanBeUnlimited]
141+
; List of visible non-lod entities
144142
;
145-
; ### VisibleEntityPtrs
146-
; ?
143+
; ### VisibleLodPtrs [CanBeUnlimited]
144+
; List of visible lod entities
147145
;
148146
; ### OutsideWorldWaterBlocks
149147
; Amount of blocks outside the world boundaries to be rendered

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ utility/PoolAdjuster.hpp
1515
utility/PoolAdjusterDynamic.hpp
1616
utility/DynamicPool.hpp
1717
utility/LinkListAdjuster.hpp
18+
utility/StaticArrayAdjuster.hpp
1819

1920
structs/CPool.h
2021
structs/CLinkList.h

src/InVisibleEntityPtrs.cpp

Lines changed: 153 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,171 @@
11
/*
2-
* (In)Visibible Entities List Adjuster
3-
* Copyright (c) 2014 ThirteenAG <thirteenag@gmail.com>
2+
* Visible Entities List Adjuster
3+
* Copyright (C) 2014 ThirteenAG <thirteenag@gmail.com>
4+
* Copyright (C) 2014 LINK/2012 <dma_2012@hotmail.com>
45
* Licensed under the MIT License (http://opensource.org/licenses/MIT)
56
*/
67
#include "LimitAdjuster.h"
8+
#include "utility/StaticArrayAdjuster.hpp"
9+
#include <injector/assembly.hpp>
710

8-
static std::vector<void*> aInVisibleEntityPtrs;
9-
static std::vector<void*> aVisibleEntityPtrs;
10-
11-
class InVisibleEntityPtrsIII : public SimpleAdjuster
11+
/*
12+
VisibilityPtrsBase
13+
Base for the visibility pointers rellocation
14+
@pDefaultArray is the address of the default array at the data segment
15+
@DefaultArraySize is the default size of that array
16+
@pArrayUsage is the address where the array usage is stored
17+
*/
18+
template<uintptr_t pDefaultArray, size_t DefaultArraySize, uintptr_t pArrayUsage>
19+
struct VisibilityPtrsBase : public StaticArrayAdjuster<void*>
1220
{
13-
public:
14-
const char* GetLimitName() { return GetGVM().IsIII() ? "InVisibleEntityPtrs" : nullptr; }
15-
16-
void ChangeLimit(int, const std::string& value)
17-
{
18-
aInVisibleEntityPtrs.resize(std::stoi(value));
19-
20-
injector::WriteMemory(0x4A7850 + 0x3, &aInVisibleEntityPtrs[0], true);
21-
injector::WriteMemory(0x4A78D3 + 0x3, &aInVisibleEntityPtrs[0], true);
22-
injector::WriteMemory(0x4A7950 + 0x3, &aInVisibleEntityPtrs[0], true);
23-
injector::WriteMemory(0x4A9300 + 0x33 + 0x3, &aInVisibleEntityPtrs[0], true);
24-
injector::WriteMemory(0x4A9BB0 + 0xB8 + 0x3, &aInVisibleEntityPtrs[0], true);
25-
injector::WriteMemory(0x4A9E30 + 0xC5 + 0x3, &aInVisibleEntityPtrs[0], true);
26-
injector::WriteMemory(0x4AA0A0 + 0x6C + 0x3, &aInVisibleEntityPtrs[0], true);
27-
}
28-
29-
} InVisibleEntityPtrsIII;
30-
31-
class VisibleEntityPtrsIII : public SimpleAdjuster
21+
private:
22+
size_t& m_dwUsage; // Reference to the array usage (pArrayUsage)
23+
std::vector<injector::memory_pointer_raw> m_Growers; // List of (mov eax, m_dwUsage) on the code, so we can check if rellocation is necessary
24+
// (Yeah, the three games use this same register and everything)
25+
26+
// Just to access it from the DoGrowFun functor, unique because of the template parameters
27+
static VisibilityPtrsBase*& Instance()
28+
{
29+
static VisibilityPtrsBase* myself;
30+
return myself;
31+
}
32+
33+
public:
34+
35+
VisibilityPtrsBase() :
36+
StaticArrayAdjuster(pDefaultArray, DefaultArraySize),
37+
m_dwUsage(*injector::lazy_ptr<pArrayUsage>().get<size_t>())
38+
{
39+
this->Instance() = this;
40+
}
41+
42+
// Adds a grower address, that's a (mov eax, dwUsage) right before incrementing and adding a element to the array
43+
// The hook this will produce will be used to check if the array needs to grow
44+
void AddGrower(uintptr_t addr)
45+
{
46+
using namespace injector;
47+
m_Growers.push_back(raw_ptr(memory_pointer(addr)));
48+
}
49+
50+
// Called when the limit is found on the ini
51+
virtual void ChangeLimit(int, const std::string& value)
52+
{
53+
if(Adjuster::IsUnlimited(value))
54+
{
55+
// Inline '''assembler''' functor for ensuring the capacity is fine
56+
struct DoGrowFun
57+
{
58+
// All the growing procs for those visibility lists use eax as indexer :)
59+
void operator()(injector::reg_pack& regs)
60+
{
61+
auto m_dwUsage = Instance()->m_dwUsage;
62+
Instance()->EnsureHasCapacityFor(m_dwUsage + 1);
63+
regs.eax = m_dwUsage; // replaces a (mov eax, m_dwUsage)
64+
}
65+
};
66+
67+
// Makes the inline grow functor
68+
for(auto it = m_Growers.begin(); it != m_Growers.end(); ++it)
69+
injector::MakeInline<DoGrowFun>(*it);
70+
}
71+
else
72+
{
73+
this->RellocArray(std::stoi(value));
74+
}
75+
}
76+
77+
// Gets the current usage of this visibility array
78+
virtual bool GetUsage(int, std::string& output)
79+
{
80+
return Adjuster::GetUsage(output, m_dwUsage, this->GetArraySize());
81+
}
82+
};
83+
84+
85+
86+
//
87+
// The actual adjusters
88+
//
89+
90+
struct VisibleEntityPtrsIII : VisibilityPtrsBase<0x6E9920, 2000, 0x940730> // <pDefault, dwMax, dwUsage>
3291
{
33-
public:
34-
const char* GetLimitName() { return GetGVM().IsIII() ? "VisibleEntityPtrs" : nullptr; }
35-
36-
void ChangeLimit(int, const std::string& value)
37-
{
38-
aVisibleEntityPtrs.resize(std::stoi(value));
39-
40-
injector::WriteMemory(0x4A7870 + 0x3, &aVisibleEntityPtrs[0], true);
41-
injector::WriteMemory(0x4A9BB0 + 0x1C7 + 0x3, &aVisibleEntityPtrs[0], true);
42-
injector::WriteMemory(0x4A9E30 + 0x1D7 + 0x3, &aVisibleEntityPtrs[0], true);
43-
injector::WriteMemory(0x4AA0A0 + 0xE3 + 0x3, &aVisibleEntityPtrs[0], true);
44-
}
92+
const char* GetLimitName()
93+
{
94+
return IsIII()? "VisibleEntityPtrs" : nullptr;
95+
}
96+
97+
VisibleEntityPtrsIII()
98+
{
99+
this->AddGrower (0x4A9EEA);
100+
this->AddGrower (0x4A9C5D);
101+
this->AddGrower (0x4A9328);
102+
this->AddGrower (0x4AA101);
103+
this->AddPointer(0x4A7853);
104+
this->AddPointer(0x4A78D6);
105+
this->AddPointer(0x4A7953);
106+
this->AddPointer(0x4A9336);
107+
this->AddPointer(0x4A9C6B);
108+
this->AddPointer(0x4A9EF8);
109+
this->AddPointer(0x4AA10F);
110+
}
111+
45112
} VisibleEntityPtrsIII;
46113

47-
class InVisibleEntityPtrsVC : public SimpleAdjuster
48-
{
49-
public:
50-
const char* GetLimitName() { return GetGVM().IsVC() ? "InVisibleEntityPtrs" : nullptr; }
51-
52-
void ChangeLimit(int, const std::string& value)
53-
{
54-
aInVisibleEntityPtrs.resize(std::stoi(value));
55-
56-
injector::WriteMemory(0x4C7560 + 0xBE + 0x3, &aInVisibleEntityPtrs[0], true);
57-
injector::WriteMemory(0x4C7740 + 0xB8 + 0x3, &aInVisibleEntityPtrs[0], true);
58-
injector::WriteMemory(0x4C8540 + 0x78 + 0x3, &aInVisibleEntityPtrs[0], true);
59-
injector::WriteMemory(0x4C9F80 + 0x3, &aInVisibleEntityPtrs[0], true);
60-
injector::WriteMemory(0x4CA1B8 + 0x3, &aInVisibleEntityPtrs[0], true);
61-
injector::WriteMemory(0x4CA200 + 0x3, &aInVisibleEntityPtrs[0], true);
62-
}
63-
} InVisibleEntityPtrsVC;
64-
65-
class VisibleEntityPtrsVC : public SimpleAdjuster
66-
{
67-
public:
68-
const char* GetLimitName() { return GetGVM().IsVC() ? "VisibleEntityPtrs" : nullptr; }
69-
void ChangeLimit(int, const std::string& value)
70-
{
71-
aVisibleEntityPtrs.resize(std::stoi(value));
72-
73-
injector::WriteMemory(0x4C7560 + 0x185 + 0x3, &aVisibleEntityPtrs[0], true);
74-
injector::WriteMemory(0x4C7740 + 0x17F + 0x3, &aVisibleEntityPtrs[0], true);
75-
injector::WriteMemory(0x4CA220 + 0x3, &aVisibleEntityPtrs[0], true);
76-
}
77-
} VisibleEntityPtrsVC;
78114

79-
class InVisibleEntityPtrsSA : public SimpleAdjuster
115+
struct VisibleEntityPtrsVC : VisibilityPtrsBase<0x7D54F8, 2000, 0xA0D1E4> // <pDefault, dwMax, dwUsage>
80116
{
81-
public:
82-
const char* GetLimitName() { return GetGVM().IsSA() ? "InVisibleEntityPtrs" : nullptr; }
83-
84-
void ChangeLimit(int, const std::string& value)
85-
{
86-
aInVisibleEntityPtrs.resize(std::stoi(value));
117+
const char* GetLimitName()
118+
{
119+
return IsVC()? "VisibleEntityPtrs" : nullptr;
120+
}
121+
122+
VisibleEntityPtrsVC()
123+
{
124+
this->AddGrower (0x4C77ED);
125+
this->AddGrower (0x4C7613);
126+
this->AddGrower (0x4C85AD);
127+
this->AddPointer(0x4C7621);
128+
this->AddPointer(0x4C77FB);
129+
this->AddPointer(0x4C85BB);
130+
this->AddPointer(0x4C9F83);
131+
this->AddPointer(0x4CA1BB);
132+
this->AddPointer(0x4CA203);
133+
}
87134

88-
injector::WriteMemory(0x5534B0 + 0x42 + 0x3, &aInVisibleEntityPtrs[0], true);
89-
injector::WriteMemory(0x553920 + 0x3, &aInVisibleEntityPtrs[0], true);
90-
injector::WriteMemory(0x553CB0 + 0x3, &aInVisibleEntityPtrs[0], true);
91-
}
92-
93-
// TODO GetUsage
135+
} VisibleEntityPtrsVC;
94136

95-
} InVisibleEntityPtrsSA;
96137

97-
class VisibleEntityPtrsSA : public SimpleAdjuster
138+
struct VisibleEntityPtrsSA : VisibilityPtrsBase<0xB75898, 1000, 0xB76844> // <pDefault, dwMax, dwUsage>
98139
{
99-
public:
100-
const char* GetLimitName() { return GetGVM().IsSA() ? "VisibleEntityPtrs" : nullptr; }
140+
const char* GetLimitName()
141+
{
142+
return IsSA()? "VisibleEntityPtrs" : nullptr;
143+
}
101144

102-
void ChangeLimit(int, const std::string& value)
103-
{
104-
aVisibleEntityPtrs.resize(std::stoi(value));
105-
106-
injector::WriteMemory(0x5534B0 + 0x76 + 0x3, &aVisibleEntityPtrs[0], true);
107-
injector::WriteMemory(0x553941 + 0x3, &aVisibleEntityPtrs[0], true);
108-
injector::WriteMemory(0x553A50 + 0x3, &aVisibleEntityPtrs[0], true);
109-
injector::WriteMemory(0x553B00 + 0x3, &aVisibleEntityPtrs[0], true);
110-
}
111-
112-
// TODO GetUsage
145+
VisibleEntityPtrsSA()
146+
{
147+
this->AddGrower (0x553521);
148+
this->AddPointer(0x553529);
149+
this->AddPointer(0x553944);
150+
this->AddPointer(0x553A53);
151+
this->AddPointer(0x553B03);
152+
}
113153

114154
} VisibleEntityPtrsSA;
155+
156+
struct VisibleLodPtrsSA : VisibilityPtrsBase<0xB748F8, 1000, 0xB76840> // <pDefault, dwMax, dwUsage>
157+
{
158+
const char* GetLimitName()
159+
{
160+
return IsSA()? "VisibleLodPtrs" : nullptr;
161+
}
162+
163+
VisibleLodPtrsSA()
164+
{
165+
this->AddGrower (0x5534ED);
166+
this->AddPointer(0x5534F5);
167+
this->AddPointer(0x553923);
168+
this->AddPointer(0x553CB3);
169+
}
170+
171+
} VisibleLodPtrsSA;

src/LimitAdjuster.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class Adjuster
4747

4848
//
4949
Adjuster() { GetAdjusters().push_back(this); }
50+
Adjuster(std::nullptr_t){} // Do not register adjuster constructor (may be useful?)
5051
virtual ~Adjuster() { /* No need to remove for now */ }
5152

5253
// Get Game Version Manager
@@ -91,7 +92,7 @@ class Adjuster
9192

9293
// Helper to GetUsage()
9394
template<class T>
94-
static bool GetUsage(std::string& str, const T& usage, const T& max)
95+
static bool GetUsage(std::string& str, T usage, T max)
9596
{
9697
str = std::to_string(usage);
9798
str.append(" / ").append(std::to_string(max));
@@ -117,6 +118,9 @@ class SimpleAdjuster : public Adjuster
117118

118119
public:
119120

121+
SimpleAdjuster() : Adjuster() {} // Register adjuster constructor
122+
SimpleAdjuster(std::nullptr_t) : Adjuster(nullptr) {} // Do not register adjuster constructor (may be useful?)
123+
120124
/*
121125
* Here you should return the name of the limit this adjuster will handle
122126
* Just like the old 'GetLimits' the function may return a null pointer to tell it won't handle any limit

src/dllmain.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ void AdjustLimits(const std::map<std::string, std::string>& section)
184184

185185
static injector::hook_back<void(*)()> DrawHUD;
186186
static uint32_t current_limit = 0; // Index of the first limit we should draw
187-
static const uint32_t limits_per_page = 20; // Max number of limits in one page
187+
static const uint32_t limits_per_page = 18; // Max number of limits in one page
188188
static float currposx; // Current drawing position
189189
static float currposy; // Current drawing position
190190

@@ -306,6 +306,10 @@ bool TestShouldDraw()
306306
// Draw the limits on screen
307307
void DrawLimits()
308308
{
309+
// Perform CHud::Draw
310+
DrawHUD.fun? DrawHUD.fun() : void();
311+
312+
// Draw our list of limits, if it overlaps with the hud (shouldn't) it will be drawn above it
309313
if(TestShouldDraw() && BeginDraw())
310314
{
311315
std::string usage;
@@ -329,9 +333,6 @@ void DrawLimits()
329333

330334
EndDraw();
331335
}
332-
333-
// Go to the replaced function, which is CHud::Draw
334-
return DrawHUD.fun? DrawHUD.fun() : void();
335336
}
336337

337338
// Patches CHud::Draw to draw additional stuff (limits details)

src/injector/assembly.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ namespace injector
123123
template<uintptr_t at, uintptr_t end, class FuncT>
124124
void MakeInline(FuncT func)
125125
{
126-
static FuncT static_func; // Stores the func object
127-
static_func = func; //
126+
static FuncT static_func = func; // Stores the func object
127+
static_func = func; //
128128

129129
// Encapsulates the call to static_func
130130
struct Caps

0 commit comments

Comments
 (0)