1
1
#include " Chunking.hpp"
2
2
3
+ #include " Player.hpp"
3
4
#include " MobAI.hpp"
4
5
#include " NPCManager.hpp"
6
+ #include " Bucket.hpp"
5
7
6
8
#include < assert.h>
7
9
@@ -11,6 +13,12 @@ using namespace Chunking;
11
13
* The initial chunkPos value before a player is placed into the world.
12
14
*/
13
15
const ChunkPos Chunking::INVALID_CHUNK = {};
16
+ constexpr size_t MAX_PC_PER_AROUND = (CN_PACKET_BODY_SIZE - sizeof (int32_t )) / sizeof (sPCAppearanceData );
17
+ constexpr size_t MAX_NPC_PER_AROUND = (CN_PACKET_BODY_SIZE - sizeof (int32_t )) / sizeof (sNPCAppearanceData );
18
+ constexpr size_t MAX_SHINY_PER_AROUND = (CN_PACKET_BODY_SIZE - sizeof (int32_t )) / sizeof (sShinyAppearanceData );
19
+ constexpr size_t MAX_TRANSPORTATION_PER_AROUND = (CN_PACKET_BODY_SIZE - sizeof (int32_t )) / sizeof (sTransportationAppearanceData );
20
+ constexpr size_t MAX_IDS_PER_AROUND_DEL = (CN_PACKET_BODY_SIZE - sizeof (int32_t )) / sizeof (int32_t );
21
+ constexpr size_t MAX_TRANSPORTATION_IDS_PER_AROUND_DEL = MAX_IDS_PER_AROUND_DEL - 1 ; // 1 less for eTT
14
22
15
23
std::map<ChunkPos, Chunk*> Chunking::chunks;
16
24
@@ -75,11 +83,80 @@ void Chunking::untrackEntity(ChunkPos chunkPos, const EntityRef ref) {
75
83
deleteChunk (chunkPos);
76
84
}
77
85
86
+ template <class T , size_t N>
87
+ static void sendAroundPackets (const EntityRef recipient, std::vector<Bucket<T, N>>& buckets, uint32_t packetId) {
88
+ assert (recipient.kind == EntityKind::PLAYER);
89
+
90
+ uint8_t pktBuf[CN_PACKET_BODY_SIZE];
91
+ for (const auto & bucket : buckets) {
92
+ memset (pktBuf, 0 , CN_PACKET_BODY_SIZE);
93
+ int count = bucket.size ();
94
+ *((int32_t *)pktBuf) = count;
95
+ T* data = (T*)(pktBuf + sizeof (int32_t ));
96
+ for (size_t i = 0 ; i < count; i++) {
97
+ data[i] = bucket.get (i).value ();
98
+ }
99
+ recipient.sock ->sendPacket (pktBuf, packetId, sizeof (int32_t ) + (count * sizeof (T)));
100
+ }
101
+ }
102
+
103
+ template <size_t N>
104
+ static void sendAroundDelPackets (const EntityRef recipient, std::vector<Bucket<int32_t , N>>& buckets, uint32_t packetId) {
105
+ assert (recipient.kind == EntityKind::PLAYER);
106
+
107
+ uint8_t pktBuf[CN_PACKET_BODY_SIZE];
108
+ for (const auto & bucket : buckets) {
109
+ memset (pktBuf, 0 , CN_PACKET_BODY_SIZE);
110
+ int count = bucket.size ();
111
+ assert (count <= N);
112
+
113
+ size_t baseSize;
114
+ if (packetId == P_FE2CL_AROUND_DEL_TRANSPORTATION) {
115
+ sP_FE2CL_AROUND_DEL_TRANSPORTATION * pkt = (sP_FE2CL_AROUND_DEL_TRANSPORTATION *)pktBuf;
116
+ pkt->eTT = 3 ;
117
+ pkt->iCnt = count;
118
+ baseSize = sizeof (sP_FE2CL_AROUND_DEL_TRANSPORTATION );
119
+ } else {
120
+ *((int32_t *)pktBuf) = count;
121
+ baseSize = sizeof (int32_t );
122
+ }
123
+ int32_t * ids = (int32_t *)(pktBuf + baseSize);
124
+
125
+ for (size_t i = 0 ; i < count; i++) {
126
+ ids[i] = bucket.get (i).value ();
127
+ }
128
+ recipient.sock ->sendPacket (pktBuf, packetId, baseSize + (count * sizeof (int32_t )));
129
+ }
130
+ }
131
+
132
+ template <class T , size_t N>
133
+ static void bufferAppearanceData (std::vector<Bucket<T, N>>& buckets, const T& data) {
134
+ if (buckets.empty ())
135
+ buckets.push_back ({});
136
+ auto & bucket = buckets[buckets.size () - 1 ];
137
+ bucket.add (data);
138
+ if (bucket.isFull ())
139
+ buckets.push_back ({});
140
+ }
141
+
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 ({});
146
+ auto & bucket = buckets[buckets.size () - 1 ];
147
+ bucket.add (id);
148
+ if (bucket.isFull ())
149
+ buckets.push_back ({});
150
+ }
151
+
78
152
void Chunking::addEntityToChunks (std::set<Chunk*> chnks, const EntityRef ref) {
79
153
Entity *ent = ref.getEntity ();
80
154
bool alive = ent->isExtant ();
81
155
82
- // TODO: maybe optimize this, potentially using AROUND packets?
156
+ std::vector<Bucket<sPCAppearanceData , MAX_PC_PER_AROUND>> pcAppearances;
157
+ std::vector<Bucket<sNPCAppearanceData , MAX_NPC_PER_AROUND>> npcAppearances;
158
+ std::vector<Bucket<sShinyAppearanceData , MAX_SHINY_PER_AROUND>> shinyAppearances;
159
+ std::vector<Bucket<sTransportationAppearanceData , MAX_TRANSPORTATION_PER_AROUND>> transportationAppearances;
83
160
for (Chunk *chunk : chnks) {
84
161
for (const EntityRef otherRef : chunk->entities ) {
85
162
// skip oneself
@@ -95,7 +172,38 @@ void Chunking::addEntityToChunks(std::set<Chunk*> chnks, const EntityRef ref) {
95
172
96
173
// notify this *player* of the existence of all visible Entities
97
174
if (ref.kind == EntityKind::PLAYER && other->isExtant ()) {
98
- other->enterIntoViewOf (ref.sock );
175
+ sPCAppearanceData pcData;
176
+ sNPCAppearanceData npcData;
177
+ sShinyAppearanceData eggData;
178
+ sTransportationAppearanceData busData;
179
+ switch (otherRef.kind ) {
180
+ case EntityKind::PLAYER:
181
+ pcData = dynamic_cast <Player*>(other)->getAppearanceData ();
182
+ bufferAppearanceData (pcAppearances, pcData);
183
+ break ;
184
+ case EntityKind::SIMPLE_NPC:
185
+ npcData = dynamic_cast <BaseNPC*>(other)->getAppearanceData ();
186
+ bufferAppearanceData (npcAppearances, npcData);
187
+ break ;
188
+ case EntityKind::COMBAT_NPC:
189
+ npcData = dynamic_cast <CombatNPC*>(other)->getAppearanceData ();
190
+ bufferAppearanceData (npcAppearances, npcData);
191
+ break ;
192
+ case EntityKind::MOB:
193
+ npcData = dynamic_cast <Mob*>(other)->getAppearanceData ();
194
+ bufferAppearanceData (npcAppearances, npcData);
195
+ break ;
196
+ case EntityKind::EGG:
197
+ eggData = dynamic_cast <Egg*>(other)->getShinyAppearanceData ();
198
+ bufferAppearanceData (shinyAppearances, eggData);
199
+ break ;
200
+ case EntityKind::BUS:
201
+ busData = dynamic_cast <Bus*>(other)->getTransportationAppearanceData ();
202
+ bufferAppearanceData (transportationAppearances, busData);
203
+ break ;
204
+ default :
205
+ break ;
206
+ }
99
207
}
100
208
101
209
// for mobs, increment playersInView
@@ -105,13 +213,27 @@ void Chunking::addEntityToChunks(std::set<Chunk*> chnks, const EntityRef ref) {
105
213
((Mob*)other)->playersInView ++;
106
214
}
107
215
}
216
+
217
+ if (ref.kind == EntityKind::PLAYER) {
218
+ if (!pcAppearances.empty ())
219
+ sendAroundPackets (ref, pcAppearances, P_FE2CL_PC_AROUND);
220
+ if (!npcAppearances.empty ())
221
+ sendAroundPackets (ref, npcAppearances, P_FE2CL_NPC_AROUND);
222
+ if (!shinyAppearances.empty ())
223
+ sendAroundPackets (ref, shinyAppearances, P_FE2CL_SHINY_AROUND);
224
+ if (!transportationAppearances.empty ())
225
+ sendAroundPackets (ref, transportationAppearances, P_FE2CL_TRANSPORTATION_AROUND);
226
+ }
108
227
}
109
228
110
229
void Chunking::removeEntityFromChunks (std::set<Chunk*> chnks, const EntityRef ref) {
111
230
Entity *ent = ref.getEntity ();
112
231
bool alive = ent->isExtant ();
113
232
114
- // TODO: same as above
233
+ std::vector<Bucket<int32_t , MAX_IDS_PER_AROUND_DEL>> pcDisappearances;
234
+ std::vector<Bucket<int32_t , MAX_IDS_PER_AROUND_DEL>> npcDisappearances;
235
+ std::vector<Bucket<int32_t , MAX_IDS_PER_AROUND_DEL>> shinyDisappearances;
236
+ std::vector<Bucket<int32_t , MAX_TRANSPORTATION_IDS_PER_AROUND_DEL>> transportationDisappearances;
115
237
for (Chunk *chunk : chnks) {
116
238
for (const EntityRef otherRef : chunk->entities ) {
117
239
// skip oneself
@@ -127,7 +249,29 @@ void Chunking::removeEntityFromChunks(std::set<Chunk*> chnks, const EntityRef re
127
249
128
250
// notify this *player* of the departure of all visible Entities
129
251
if (ref.kind == EntityKind::PLAYER && other->isExtant ()) {
130
- other->disappearFromViewOf (ref.sock );
252
+ int32_t id;
253
+ switch (otherRef.kind ) {
254
+ case EntityKind::PLAYER:
255
+ id = dynamic_cast <Player*>(other)->iID ;
256
+ bufferIdForDisappearance (pcDisappearances, id);
257
+ break ;
258
+ case EntityKind::SIMPLE_NPC:
259
+ case EntityKind::COMBAT_NPC:
260
+ case EntityKind::MOB:
261
+ id = dynamic_cast <BaseNPC*>(other)->id ;
262
+ bufferIdForDisappearance (npcDisappearances, id);
263
+ break ;
264
+ case EntityKind::EGG:
265
+ id = dynamic_cast <Egg*>(other)->id ;
266
+ bufferIdForDisappearance (shinyDisappearances, id);
267
+ break ;
268
+ case EntityKind::BUS:
269
+ id = dynamic_cast <Bus*>(other)->id ;
270
+ bufferIdForDisappearance (transportationDisappearances, id);
271
+ break ;
272
+ default :
273
+ break ;
274
+ }
131
275
}
132
276
133
277
// for mobs, decrement playersInView
@@ -137,6 +281,17 @@ void Chunking::removeEntityFromChunks(std::set<Chunk*> chnks, const EntityRef re
137
281
((Mob*)other)->playersInView --;
138
282
}
139
283
}
284
+
285
+ if (ref.kind == EntityKind::PLAYER) {
286
+ if (!pcDisappearances.empty ())
287
+ sendAroundDelPackets (ref, pcDisappearances, P_FE2CL_AROUND_DEL_PC);
288
+ if (!npcDisappearances.empty ())
289
+ sendAroundDelPackets (ref, npcDisappearances, P_FE2CL_AROUND_DEL_NPC);
290
+ if (!shinyDisappearances.empty ())
291
+ sendAroundDelPackets (ref, shinyDisappearances, P_FE2CL_AROUND_DEL_SHINY);
292
+ if (!transportationDisappearances.empty ())
293
+ sendAroundDelPackets (ref, transportationDisappearances, P_FE2CL_AROUND_DEL_TRANSPORTATION);
294
+ }
140
295
}
141
296
142
297
static void emptyChunk (ChunkPos chunkPos) {
0 commit comments