1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
|
#pragma once
#include "cEntity.h"
#include "ChunkDef.h"
#define C_CHUNK_USE_INLINE 1
// Do not touch
#if C_CHUNK_USE_INLINE
#define __C_CHUNK_INLINE__ inline
#else
#define __C_CHUNK_INLINE__
#endif
namespace Json
{
class Value;
};
class cWorld;
class cFurnaceEntity;
class cPacket;
class cClientHandle;
class cServer;
class MTRand;
class cPlayer;
class cChunkMap;
typedef std::list<cClientHandle *> cClientHandleList;
// This class is not to be used directly
// Instead, call actions on cChunkMap (such as cChunkMap::SetBlock() etc.)
class cChunk :
public cChunkDef // The inheritance is "misused" here only to inherit the functions and constants defined in cChunkDef
{
public:
cChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkMap * a_ChunkMap, cWorld * a_World);
~cChunk();
bool IsValid(void) const {return m_IsValid; } // Returns true if the chunk block data is valid (loaded / generated)
void SetValid(void); // Also wakes up any calls to cChunkMap::GetHeight()
void MarkRegenerating(void); // Marks all clients attached to this chunk as wanting this chunk
bool IsDirty(void) const {return m_IsDirty; } // Returns true if the chunk has changed since it was last saved
bool HasLoadFailed(void) const {return m_HasLoadFailed; } // Returns true if the chunk failed to load and hasn't been generated since then
bool CanUnload(void);
bool IsLightValid(void) const {return m_IsLightValid; }
/*
To save a chunk, the WSSchema must:
1. Mark the chunk as being saved (MarkSaving() )
2. Get the chunk's data using GetAllData()
3. Mark the chunk as saved (MarkSaved() )
If anywhere inside this sequence another thread mmodifies the chunk, the chunk will not get marked as saved in MarkSaved()
*/
void MarkSaving(void); // Marks the chunk as being saved.
void MarkSaved(void); // Marks the chunk as saved, if it didn't change from the last call to MarkSaving()
void MarkLoaded(void); // Marks the chunk as freshly loaded. Fails if the chunk is already valid
void MarkLoadFailed(void); // Marks the chunk as failed to load. Ignored is the chunk is already valid
/// Gets all chunk data, calls the a_Callback's methods for each data type
void GetAllData(cChunkDataCallback & a_Callback);
/// Sets all chunk data
void SetAllData(
const BLOCKTYPE * a_BlockTypes,
const NIBBLETYPE * a_BlockMeta,
const NIBBLETYPE * a_BlockLight,
const NIBBLETYPE * a_BlockSkyLight,
const cChunkDef::HeightMap * a_HeightMap,
const cChunkDef::BiomeMap & a_BiomeMap,
cEntityList & a_Entities,
cBlockEntityList & a_BlockEntities
);
void SetLight(
const cChunkDef::BlockNibbles & a_BlockLight,
const cChunkDef::BlockNibbles & a_SkyLight
);
/// Copies m_BlockData into a_BlockTypes, only the block types
void GetBlockTypes(BLOCKTYPE * a_BlockTypes);
/// Copies entire block data into a_BlockData, the entire 4 arrays (Type, Meta, Light, SkyLight)
void GetBlockData(BLOCKTYPE * a_BlockData);
/// Returns true if there is a block entity at the coords specified
bool HasBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ);
/// Sets or resets the internal flag that prevents chunk from being unloaded
void Stay(bool a_Stay = true);
void Tick(float a_Dt, MTRand & a_TickRandom);
int GetPosX() { return m_PosX; }
int GetPosY() { return m_PosY; }
int GetPosZ() { return m_PosZ; }
cWorld * GetWorld() { return m_World; }
// OBSOLETE void SendTo( cClientHandle * a_Client );
void SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta );
// SetBlock() does a lot of work (heightmap, tickblocks, blockentities) so a BlockIdx version doesn't make sense
void SetBlock( const Vector3i & a_RelBlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ) { SetBlock( a_RelBlockPos.x, a_RelBlockPos.y, a_RelBlockPos.z, a_BlockType, a_BlockMeta ); }
void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta ); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc.
BLOCKTYPE GetBlock( int a_X, int a_Y, int a_Z );
BLOCKTYPE GetBlock( int a_BlockIdx );
EMCSBiome GetBiomeAt(int a_RelX, int a_RelZ) const {return cChunkDef::GetBiome(m_BiomeMap, a_RelX, a_RelZ); }
void CollectPickupsByPlayer(cPlayer * a_Player);
void UpdateSign(int a_PosX, int a_PosY, int a_PosZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); // Also sends update packets to all clients in the chunk
int GetHeight( int a_X, int a_Z );
void SendBlockTo( int a_X, int a_Y, int a_Z, cClientHandle* a_Client );
/// Adds a client to the chunk; returns true if added, false if already there
bool AddClient (cClientHandle* a_Client );
void RemoveClient (cClientHandle* a_Client );
bool HasClient (cClientHandle* a_Client );
bool HasAnyClients(void); // Returns true if theres any client in the chunk; false otherwise
void AddEntity( cEntity * a_Entity);
void RemoveEntity( cEntity * a_Entity);
void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); // [x, y, z] in world block coords
void CalculateLighting(); // Recalculate right now
void CalculateHeightmap();
// Broadcasts to all clients that have loaded this chunk
void Broadcast( const cPacket & a_Packet, cClientHandle * a_Exclude = NULL) {Broadcast(&a_Packet, a_Exclude); }
void Broadcast( const cPacket * a_Packet, cClientHandle * a_Exclude = NULL);
void PositionToWorldPosition(int a_ChunkX, int a_ChunkY, int a_ChunkZ, int & a_X, int & a_Y, int & a_Z);
Vector3i PositionToWorldPosition( const Vector3i & a_InChunkPos ) { return PositionToWorldPosition( a_InChunkPos.x, a_InChunkPos.y, a_InChunkPos.z ); }
Vector3i PositionToWorldPosition( int a_ChunkX, int a_ChunkY, int a_ChunkZ );
inline void MarkDirty(void)
{
m_IsDirty = true;
m_IsSaving = false;
}
inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); }
inline NIBBLETYPE GetMeta(int a_BlockIdx) {return cChunkDef::GetNibble(m_BlockMeta, a_BlockIdx); }
inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ, a_Meta); }
inline NIBBLETYPE GetLight(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockLight, a_RelX, a_RelY, a_RelZ); }
inline NIBBLETYPE GetSkyLight(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ); }
private:
friend class cChunkMap;
bool m_IsValid; // True if the chunk is loaded / generated
bool m_IsLightValid; // True if the blocklight and skylight are calculated
bool m_IsDirty; // True if the chunk has changed since it was last saved
bool m_IsSaving; // True if the chunk is being saved
bool m_HasLoadFailed; // True if chunk failed to load and hasn't been generated yet since then
cCriticalSection m_CSBlockLists;
std::deque< unsigned int > m_ToTickBlocks;
std::vector< unsigned int > m_PendingSendBlocks;
// A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers
cClientHandleList m_LoadedByClient;
cClientHandleList m_UnloadQuery;
cEntityList m_Entities;
cBlockEntityList m_BlockEntities;
/// Number of times the chunk has been requested to stay (by various cChunkStay objects); if zero, the chunk can be unloaded
int m_StayCount;
int m_PosX, m_PosY, m_PosZ;
cWorld * m_World;
cChunkMap * m_ChunkMap;
// TODO: Make these pointers and don't allocate what isn't needed
BLOCKTYPE m_BlockTypes [cChunkDef::NumBlocks];
NIBBLETYPE m_BlockMeta [cChunkDef::NumBlocks / 2];
NIBBLETYPE m_BlockLight [cChunkDef::NumBlocks / 2];
NIBBLETYPE m_BlockSkyLight[cChunkDef::NumBlocks / 2];
cChunkDef::HeightMap m_HeightMap;
cChunkDef::BiomeMap m_BiomeMap;
int m_BlockTickX, m_BlockTickY, m_BlockTickZ;
void RemoveBlockEntity( cBlockEntity* a_BlockEntity );
void AddBlockEntity( cBlockEntity* a_BlockEntity );
cBlockEntity * GetBlockEntity( int a_X, int a_Y, int a_Z );
cBlockEntity * GetBlockEntity( const Vector3i & a_BlockPos ) { return GetBlockEntity( a_BlockPos.x, a_BlockPos.y, a_BlockPos.z ); }
void SpreadLightOfBlock(NIBBLETYPE * a_LightBuffer, int a_X, int a_Y, int a_Z, char a_Falloff);
void CreateBlockEntities(void);
// Makes a copy of the list
cClientHandleList GetAllClients(void) const {return m_LoadedByClient; }
void TickBlocks(MTRand & a_TickRandom);
void TickMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, int a_BlockIdx, BLOCKTYPE a_BlockType, MTRand & a_TickRandom);
void TickFarmland (int a_RelX, int a_RelY, int a_RelZ);
/// Same as GetBlock(), but relative coords needn't be in this chunk (uses m_ChunkMap in such a case); returns true on success; only usable in Tick()
bool UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
/// Same as SetBlock(), but relative coords needn't be in this chunk (uses m_ChunkMap in such a case); returns true on success; only usable in Tick()
bool UnboundedRelSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
/// Same as FastSetBlock(), but relative coords needn't be in this chunk (uses m_ChunkMap in such a case); returns true on success; only usable in Tick()
bool UnboundedRelFastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
};
typedef cChunk * cChunkPtr;
typedef std::list<cChunkPtr> cChunkPtrList;
#if C_CHUNK_USE_INLINE
#include "cChunk.inl.h"
#endif
|