Skip to content

Commit 65fdeb9

Browse files
Optimize performance
Introduces a generic, fixed-size `Bucket` type in place of the inner vector. This does add size generics but I think it's a very good tradeoff considering how performance-sensitive this codepath is.
1 parent 91589b1 commit 65fdeb9

File tree

3 files changed

+97
-57
lines changed

3 files changed

+97
-57
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ CXXHDR=\
115115
src/settings.hpp\
116116
src/Transport.hpp\
117117
src/TableData.hpp\
118+
src/Bucket.hpp\
118119
src/Chunking.hpp\
119120
src/Buddies.hpp\
120121
src/Groups.hpp\

src/Bucket.hpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#pragma once
2+
3+
#include <array>
4+
#include <optional>
5+
6+
template<class T, size_t N>
7+
class Bucket {
8+
std::array<T, N> buf;
9+
size_t sz;
10+
public:
11+
Bucket() {
12+
sz = 0;
13+
}
14+
15+
void add(const T& item) {
16+
if (sz < N) {
17+
buf[sz++] = item;
18+
}
19+
}
20+
21+
std::optional<T> get(size_t idx) const {
22+
if (idx < sz) {
23+
return buf[idx];
24+
}
25+
return std::nullopt;
26+
}
27+
28+
size_t size() const {
29+
return sz;
30+
}
31+
32+
bool isFull() const {
33+
return sz == N;
34+
}
35+
36+
void clear() {
37+
sz = 0;
38+
}
39+
};

src/Chunking.cpp

Lines changed: 57 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "Player.hpp"
44
#include "MobAI.hpp"
55
#include "NPCManager.hpp"
6+
#include "Bucket.hpp"
67

78
#include <assert.h>
89

@@ -12,11 +13,11 @@ using namespace Chunking;
1213
* The initial chunkPos value before a player is placed into the world.
1314
*/
1415
const ChunkPos Chunking::INVALID_CHUNK = {};
15-
constexpr size_t MAX_PC_PER_AROUND = (CN_PACKET_BUFFER_SIZE - 4) / sizeof(sPCAppearanceData);
16-
constexpr size_t MAX_NPC_PER_AROUND = (CN_PACKET_BUFFER_SIZE - 4) / sizeof(sNPCAppearanceData);
17-
constexpr size_t MAX_SHINY_PER_AROUND = (CN_PACKET_BUFFER_SIZE - 4) / sizeof(sShinyAppearanceData);
18-
constexpr size_t MAX_TRANSPORTATION_PER_AROUND = (CN_PACKET_BUFFER_SIZE - 4) / sizeof(sTransportationAppearanceData);
19-
constexpr size_t MAX_IDS_PER_AROUND_DEL = (CN_PACKET_BUFFER_SIZE - 4) / sizeof(int32_t);
16+
constexpr size_t MAX_PC_PER_AROUND = (CN_PACKET_BUFFER_SIZE - sizeof(int32_t)) / sizeof(sPCAppearanceData);
17+
constexpr size_t MAX_NPC_PER_AROUND = (CN_PACKET_BUFFER_SIZE - sizeof(int32_t)) / sizeof(sNPCAppearanceData);
18+
constexpr size_t MAX_SHINY_PER_AROUND = (CN_PACKET_BUFFER_SIZE - sizeof(int32_t)) / sizeof(sShinyAppearanceData);
19+
constexpr size_t MAX_TRANSPORTATION_PER_AROUND = (CN_PACKET_BUFFER_SIZE - sizeof(int32_t)) / sizeof(sTransportationAppearanceData);
20+
constexpr size_t MAX_IDS_PER_AROUND_DEL = (CN_PACKET_BUFFER_SIZE - sizeof(int32_t)) / sizeof(int32_t);
2021

2122
std::map<ChunkPos, Chunk*> Chunking::chunks;
2223

@@ -81,36 +82,32 @@ void Chunking::untrackEntity(ChunkPos chunkPos, const EntityRef ref) {
8182
deleteChunk(chunkPos);
8283
}
8384

84-
template<class T>
85-
static void sendAroundPacket(const EntityRef recipient, std::vector<std::vector<T>>& slices, size_t maxCnt, uint32_t packetId) {
85+
template<class T, size_t N>
86+
static void sendAroundPacket(const EntityRef recipient, std::vector<Bucket<T, N>>& buckets, uint32_t packetId) {
8687
assert(recipient.kind == EntityKind::PLAYER);
8788

8889
uint8_t pktBuf[CN_PACKET_BUFFER_SIZE];
89-
for (const auto& slice : slices) {
90+
for (const auto& bucket : buckets) {
9091
memset(pktBuf, 0, CN_PACKET_BUFFER_SIZE);
91-
int count = slice.size();
92-
assert(count <= maxCnt);
92+
int count = bucket.size();
9393
*((int32_t*)pktBuf) = count;
9494
T* data = (T*)(pktBuf + sizeof(int32_t));
9595
for (size_t i = 0; i < count; i++) {
96-
data[i] = slice[i];
96+
data[i] = bucket.get(i).value();
9797
}
9898
recipient.sock->sendPacket(pktBuf, packetId, sizeof(int32_t) + (count * sizeof(T)));
9999
}
100100
}
101101

102-
static void sendAroundDelPacket(const EntityRef recipient, std::vector<std::vector<int32_t>>& slices, bool isTransportation, uint32_t packetId) {
102+
template<size_t N>
103+
static void sendAroundDelPacket(const EntityRef recipient, std::vector<Bucket<int32_t, N>>& buckets, bool isTransportation, uint32_t packetId) {
103104
assert(recipient.kind == EntityKind::PLAYER);
104105

105-
size_t maxCnt = MAX_IDS_PER_AROUND_DEL;
106-
if (isTransportation)
107-
maxCnt -= 1; // account for eTT. sad.
108-
109106
uint8_t pktBuf[CN_PACKET_BUFFER_SIZE];
110-
for (const auto& slice : slices) {
107+
for (const auto& bucket : buckets) {
111108
memset(pktBuf, 0, CN_PACKET_BUFFER_SIZE);
112-
int count = slice.size();
113-
assert(count <= maxCnt);
109+
int count = bucket.size();
110+
assert(count <= N);
114111

115112
size_t baseSize;
116113
if (isTransportation) {
@@ -125,39 +122,42 @@ static void sendAroundDelPacket(const EntityRef recipient, std::vector<std::vect
125122
int32_t* ids = (int32_t*)(pktBuf + baseSize);
126123

127124
for (size_t i = 0; i < count; i++) {
128-
ids[i] = slice[i];
125+
ids[i] = bucket.get(i).value();
129126
}
130127
recipient.sock->sendPacket(pktBuf, packetId, baseSize + (count * sizeof(int32_t)));
131128
}
132129
}
133130

134-
template<class T>
135-
static void bufferAppearanceData(std::vector<std::vector<T>>& slices, const T& data, size_t maxCnt) {
136-
if (slices.empty())
137-
slices.push_back(std::vector<T>());
138-
std::vector<T>& slice = slices[slices.size() - 1];
139-
slice.push_back(data);
140-
if (slice.size() == maxCnt)
141-
slices.push_back(std::vector<T>());
131+
template<class T, size_t N>
132+
static void bufferAppearanceData(std::vector<Bucket<T, N>>& buckets, const T& data) {
133+
if (buckets.empty())
134+
buckets.push_back(Bucket<T, N>());
135+
Bucket<T, N>& bucket = buckets[buckets.size() - 1];
136+
assert(!bucket.isFull());
137+
bucket.add(data);
138+
if (bucket.isFull())
139+
buckets.push_back(Bucket<T, N>());
142140
}
143141

144-
static void bufferIdForDisappearance(std::vector<std::vector<int32_t>>& slices, int32_t id, size_t maxCnt) {
145-
if (slices.empty())
146-
slices.push_back(std::vector<int32_t>());
147-
std::vector<int32_t>& slice = slices[slices.size() - 1];
148-
slice.push_back(id);
149-
if (slice.size() == maxCnt)
150-
slices.push_back(std::vector<int32_t>());
142+
template<size_t N>
143+
static void bufferIdForDisappearance(std::vector<Bucket<int32_t, N>>& buckets, int32_t id) {
144+
if (buckets.empty())
145+
buckets.push_back(Bucket<int32_t, N>());
146+
Bucket<int32_t, N>& bucket = buckets[buckets.size() - 1];
147+
assert(!bucket.isFull());
148+
bucket.add(id);
149+
if (bucket.isFull())
150+
buckets.push_back(Bucket<int32_t, N>());
151151
}
152152

153153
void Chunking::addEntityToChunks(std::set<Chunk*> chnks, const EntityRef ref) {
154154
Entity *ent = ref.getEntity();
155155
bool alive = ent->isExtant();
156156

157-
std::vector<std::vector<sPCAppearanceData>> pcAppearances;
158-
std::vector<std::vector<sNPCAppearanceData>> npcAppearances;
159-
std::vector<std::vector<sShinyAppearanceData>> shinyAppearances;
160-
std::vector<std::vector<sTransportationAppearanceData>> transportationAppearances;
157+
std::vector<Bucket<sPCAppearanceData, MAX_PC_PER_AROUND>> pcAppearances;
158+
std::vector<Bucket<sNPCAppearanceData, MAX_NPC_PER_AROUND>> npcAppearances;
159+
std::vector<Bucket<sShinyAppearanceData, MAX_SHINY_PER_AROUND>> shinyAppearances;
160+
std::vector<Bucket<sTransportationAppearanceData, MAX_TRANSPORTATION_PER_AROUND>> transportationAppearances;
161161
for (Chunk *chunk : chnks) {
162162
for (const EntityRef otherRef : chunk->entities) {
163163
// skip oneself
@@ -181,27 +181,27 @@ void Chunking::addEntityToChunks(std::set<Chunk*> chnks, const EntityRef ref) {
181181
{
182182
case EntityKind::PLAYER:
183183
pcData = dynamic_cast<Player*>(other)->getAppearanceData();
184-
bufferAppearanceData(pcAppearances, pcData, MAX_PC_PER_AROUND);
184+
bufferAppearanceData(pcAppearances, pcData);
185185
break;
186186
case EntityKind::SIMPLE_NPC:
187187
npcData = dynamic_cast<BaseNPC*>(other)->getAppearanceData();
188-
bufferAppearanceData(npcAppearances, npcData, MAX_NPC_PER_AROUND);
188+
bufferAppearanceData(npcAppearances, npcData);
189189
break;
190190
case EntityKind::COMBAT_NPC:
191191
npcData = dynamic_cast<CombatNPC*>(other)->getAppearanceData();
192-
bufferAppearanceData(npcAppearances, npcData, MAX_NPC_PER_AROUND);
192+
bufferAppearanceData(npcAppearances, npcData);
193193
break;
194194
case EntityKind::MOB:
195195
npcData = dynamic_cast<Mob*>(other)->getAppearanceData();
196-
bufferAppearanceData(npcAppearances, npcData, MAX_NPC_PER_AROUND);
196+
bufferAppearanceData(npcAppearances, npcData);
197197
break;
198198
case EntityKind::EGG:
199199
eggData = dynamic_cast<Egg*>(other)->getShinyAppearanceData();
200-
bufferAppearanceData(shinyAppearances, eggData, MAX_SHINY_PER_AROUND);
200+
bufferAppearanceData(shinyAppearances, eggData);
201201
break;
202202
case EntityKind::BUS:
203203
busData = dynamic_cast<Bus*>(other)->getTransportationAppearanceData();
204-
bufferAppearanceData(transportationAppearances, busData, MAX_TRANSPORTATION_PER_AROUND);
204+
bufferAppearanceData(transportationAppearances, busData);
205205
break;
206206
default:
207207
break;
@@ -220,23 +220,23 @@ void Chunking::addEntityToChunks(std::set<Chunk*> chnks, const EntityRef ref) {
220220
return; // nothing to send
221221

222222
if (!pcAppearances.empty())
223-
sendAroundPacket(ref, pcAppearances, MAX_PC_PER_AROUND, P_FE2CL_PC_AROUND);
223+
sendAroundPacket(ref, pcAppearances, P_FE2CL_PC_AROUND);
224224
if (!npcAppearances.empty())
225-
sendAroundPacket(ref, npcAppearances, MAX_NPC_PER_AROUND, P_FE2CL_NPC_AROUND);
225+
sendAroundPacket(ref, npcAppearances, P_FE2CL_NPC_AROUND);
226226
if (!shinyAppearances.empty())
227-
sendAroundPacket(ref, shinyAppearances, MAX_SHINY_PER_AROUND, P_FE2CL_SHINY_AROUND);
227+
sendAroundPacket(ref, shinyAppearances, P_FE2CL_SHINY_AROUND);
228228
if (!transportationAppearances.empty())
229-
sendAroundPacket(ref, transportationAppearances, MAX_TRANSPORTATION_PER_AROUND, P_FE2CL_TRANSPORTATION_AROUND);
229+
sendAroundPacket(ref, transportationAppearances, P_FE2CL_TRANSPORTATION_AROUND);
230230
}
231231

232232
void Chunking::removeEntityFromChunks(std::set<Chunk*> chnks, const EntityRef ref) {
233233
Entity *ent = ref.getEntity();
234234
bool alive = ent->isExtant();
235235

236-
std::vector<std::vector<int32_t>> pcDisappearances;
237-
std::vector<std::vector<int32_t>> npcDisappearances;
238-
std::vector<std::vector<int32_t>> shinyDisappearances;
239-
std::vector<std::vector<int32_t>> transportationDisappearances;
236+
std::vector<Bucket<int32_t, MAX_IDS_PER_AROUND_DEL>> pcDisappearances;
237+
std::vector<Bucket<int32_t, MAX_IDS_PER_AROUND_DEL>> npcDisappearances;
238+
std::vector<Bucket<int32_t, MAX_IDS_PER_AROUND_DEL>> shinyDisappearances;
239+
std::vector<Bucket<int32_t, MAX_IDS_PER_AROUND_DEL - 1>> transportationDisappearances;
240240
for (Chunk *chunk : chnks) {
241241
for (const EntityRef otherRef : chunk->entities) {
242242
// skip oneself
@@ -257,21 +257,21 @@ void Chunking::removeEntityFromChunks(std::set<Chunk*> chnks, const EntityRef re
257257
{
258258
case EntityKind::PLAYER:
259259
id = dynamic_cast<Player*>(other)->iID;
260-
bufferIdForDisappearance(pcDisappearances, id, MAX_IDS_PER_AROUND_DEL);
260+
bufferIdForDisappearance(pcDisappearances, id);
261261
break;
262262
case EntityKind::SIMPLE_NPC:
263263
case EntityKind::COMBAT_NPC:
264264
case EntityKind::MOB:
265265
id = dynamic_cast<BaseNPC*>(other)->id;
266-
bufferIdForDisappearance(npcDisappearances, id, MAX_IDS_PER_AROUND_DEL);
266+
bufferIdForDisappearance(npcDisappearances, id);
267267
break;
268268
case EntityKind::EGG:
269269
id = dynamic_cast<Egg*>(other)->id;
270-
bufferIdForDisappearance(shinyDisappearances, id, MAX_IDS_PER_AROUND_DEL);
270+
bufferIdForDisappearance(shinyDisappearances, id);
271271
break;
272272
case EntityKind::BUS:
273273
id = dynamic_cast<Bus*>(other)->id;
274-
bufferIdForDisappearance(transportationDisappearances, id, MAX_IDS_PER_AROUND_DEL - 1);
274+
bufferIdForDisappearance(transportationDisappearances, id);
275275
break;
276276
default:
277277
break;

0 commit comments

Comments
 (0)