Chunk is now marked as dirty; saving only dirty chunks; rewritten load / save not to use cChunkPtr; set VC2008 project to level4 warnings; block entities are now loaded and saved properly
git-svn-id: http://mc-server.googlecode.com/svn/trunk@273 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
parent
1c4122313f
commit
423f49d175
@ -48,7 +48,7 @@
|
|||||||
RuntimeLibrary="3"
|
RuntimeLibrary="3"
|
||||||
UsePrecompiledHeader="2"
|
UsePrecompiledHeader="2"
|
||||||
PrecompiledHeaderThrough="Globals.h"
|
PrecompiledHeaderThrough="Globals.h"
|
||||||
WarningLevel="3"
|
WarningLevel="4"
|
||||||
DebugInformationFormat="4"
|
DebugInformationFormat="4"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
@ -536,6 +536,7 @@
|
|||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
/>
|
/>
|
||||||
</FileConfiguration>
|
</FileConfiguration>
|
||||||
<FileConfiguration
|
<FileConfiguration
|
||||||
@ -585,6 +586,7 @@
|
|||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
/>
|
/>
|
||||||
</FileConfiguration>
|
</FileConfiguration>
|
||||||
<FileConfiguration
|
<FileConfiguration
|
||||||
@ -601,6 +603,14 @@
|
|||||||
RelativePath="..\source\StackWalker.h"
|
RelativePath="..\source\StackWalker.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\StringCompression.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\StringCompression.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\StringUtils.cpp"
|
RelativePath="..\source\StringUtils.cpp"
|
||||||
>
|
>
|
||||||
|
@ -476,6 +476,7 @@
|
|||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\source\StringCompression.cpp" />
|
||||||
<ClCompile Include="..\source\StringUtils.cpp" />
|
<ClCompile Include="..\source\StringUtils.cpp" />
|
||||||
<ClCompile Include="..\source\Vector3d.cpp" />
|
<ClCompile Include="..\source\Vector3d.cpp" />
|
||||||
<ClCompile Include="..\source\Vector3f.cpp" />
|
<ClCompile Include="..\source\Vector3f.cpp" />
|
||||||
@ -651,6 +652,7 @@
|
|||||||
<ClInclude Include="..\source\ptr_cChunk.h" />
|
<ClInclude Include="..\source\ptr_cChunk.h" />
|
||||||
<ClInclude Include="..\source\SquirrelBindings.h" />
|
<ClInclude Include="..\source\SquirrelBindings.h" />
|
||||||
<ClInclude Include="..\source\StackWalker.h" />
|
<ClInclude Include="..\source\StackWalker.h" />
|
||||||
|
<ClInclude Include="..\source\StringCompression.h" />
|
||||||
<ClInclude Include="..\source\StringUtils.h" />
|
<ClInclude Include="..\source\StringUtils.h" />
|
||||||
<ClInclude Include="..\source\Vector3d.h" />
|
<ClInclude Include="..\source\Vector3d.h" />
|
||||||
<ClInclude Include="..\source\Vector3f.h" />
|
<ClInclude Include="..\source\Vector3f.h" />
|
||||||
|
@ -910,6 +910,7 @@
|
|||||||
<ClCompile Include="..\source\StackWalker.cpp" />
|
<ClCompile Include="..\source\StackWalker.cpp" />
|
||||||
<ClCompile Include="..\source\WorldStorage.cpp" />
|
<ClCompile Include="..\source\WorldStorage.cpp" />
|
||||||
<ClCompile Include="..\source\WSSCompact.cpp" />
|
<ClCompile Include="..\source\WSSCompact.cpp" />
|
||||||
|
<ClCompile Include="..\source\StringCompression.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\source\cServer.h">
|
<ClInclude Include="..\source\cServer.h">
|
||||||
@ -1404,6 +1405,7 @@
|
|||||||
<ClInclude Include="..\source\LeakFinder.h" />
|
<ClInclude Include="..\source\LeakFinder.h" />
|
||||||
<ClInclude Include="..\source\StackWalker.h" />
|
<ClInclude Include="..\source\StackWalker.h" />
|
||||||
<ClInclude Include="..\source\WorldStorage.h" />
|
<ClInclude Include="..\source\WorldStorage.h" />
|
||||||
|
<ClInclude Include="..\source\StringCompression.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\source\AllToLua.pkg">
|
<None Include="..\source\AllToLua.pkg">
|
||||||
|
@ -8,6 +8,29 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Compiler-dependent stuff:
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
// Non-MS compilers don't know the override keyword
|
||||||
|
#define override
|
||||||
|
#else
|
||||||
|
// MSVC produces warning C4481 on the override keyword usage, so disable the warning altogether
|
||||||
|
#pragma warning(disable:4481)
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// A macro to disallow the copy constructor and operator= functions
|
||||||
|
// This should be used in the private: declarations for any class that shouldn't allow copying itself
|
||||||
|
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||||
|
TypeName(const TypeName &); \
|
||||||
|
void operator=(const TypeName &)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// OS-dependent stuff:
|
// OS-dependent stuff:
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
@ -246,7 +246,8 @@ MCServer : \
|
|||||||
build/cIsThread.o\
|
build/cIsThread.o\
|
||||||
build/cSocketThreads.o\
|
build/cSocketThreads.o\
|
||||||
build/WorldStorage.o\
|
build/WorldStorage.o\
|
||||||
build/WSSCompact.o
|
build/WSSCompact.o\
|
||||||
|
build/StringCompression.o
|
||||||
$(CC) $(LNK_OPTIONS) \
|
$(CC) $(LNK_OPTIONS) \
|
||||||
build/json_reader.o\
|
build/json_reader.o\
|
||||||
build/json_value.o\
|
build/json_value.o\
|
||||||
@ -462,6 +463,7 @@ MCServer : \
|
|||||||
build/cSocketThreads.o\
|
build/cSocketThreads.o\
|
||||||
build/WorldStorage.o\
|
build/WorldStorage.o\
|
||||||
build/WSSCompact.o\
|
build/WSSCompact.o\
|
||||||
|
build/StringCompression.o\
|
||||||
-o MCServer
|
-o MCServer
|
||||||
|
|
||||||
clean :
|
clean :
|
||||||
@ -1550,6 +1552,9 @@ build/WorldStorage.o : source/WorldStorage.cpp
|
|||||||
build/WSSCompact.o : source/WSSCompact.cpp
|
build/WSSCompact.o : source/WSSCompact.cpp
|
||||||
$(CC) $(CC_OPTIONS) source/WSSCompact.cpp -c $(INCLUDE) -o build/WSSCompact.o
|
$(CC) $(CC_OPTIONS) source/WSSCompact.cpp -c $(INCLUDE) -o build/WSSCompact.o
|
||||||
|
|
||||||
|
build/StringCompression.o : source/StringCompression.cpp
|
||||||
|
$(CC) $(CC_OPTIONS) source/StringCompression.cpp -c $(INCLUDE) -o build/StringCompression.o
|
||||||
|
|
||||||
|
|
||||||
# Template: copy and delete the "# "; insert filenames
|
# Template: copy and delete the "# "; insert filenames
|
||||||
# build/.o : source/.cpp
|
# build/.o : source/.cpp
|
||||||
|
@ -12,12 +12,28 @@
|
|||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
// Non-MS compilers don't know the override keyword
|
// Non-MS compilers don't know the override keyword
|
||||||
#define override
|
#define override
|
||||||
|
#else
|
||||||
|
// MSVC produces warning C4481 on the override keyword usage, so disable the warning altogether
|
||||||
|
#pragma warning(disable:4481)
|
||||||
|
|
||||||
|
// Disable some warnings that we don't care about:
|
||||||
|
#pragma warning(disable:4100)
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// A macro to disallow the copy constructor and operator= functions
|
||||||
|
// This should be used in the private: declarations for any class that shouldn't allow copying itself
|
||||||
|
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||||
|
TypeName(const TypeName &); \
|
||||||
|
void operator=(const TypeName &)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// OS-dependent stuff:
|
// OS-dependent stuff:
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
@ -114,8 +130,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// A generic interface used in ForEach() functions
|
/// A generic interface used mainly in ForEach() functions
|
||||||
template <typename Type> class cListCallback
|
template <typename Type> class cItemCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Called for each item in the internal list; return true to stop the loop, or false to continue enumerating
|
/// Called for each item in the internal list; return true to stop the loop, or false to continue enumerating
|
||||||
|
54
source/StringCompression.cpp
Normal file
54
source/StringCompression.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
|
||||||
|
// StringCompression.cpp
|
||||||
|
|
||||||
|
// Implements the wrapping functions for compression and decompression using AString as their data
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "StringCompression.h"
|
||||||
|
#include "zlib.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Compresses a_Data into a_Compressed; return Z_XXX error constants same as zlib's compress2()
|
||||||
|
int CompressString(const char * a_Data, int a_Length, AString & a_Compressed)
|
||||||
|
{
|
||||||
|
uLongf CompressedSize = compressBound(a_Length);
|
||||||
|
|
||||||
|
// HACK: We're assuming that AString returns its internal buffer in its data() call and we're overwriting that buffer!
|
||||||
|
// It saves us one allocation and one memcpy of the entire compressed data
|
||||||
|
// It may not work on some STL implementations! (Confirmed working on MSVC 2008 & 2010)
|
||||||
|
a_Compressed.resize(CompressedSize);
|
||||||
|
int errorcode = compress2( (Bytef*)a_Compressed.data(), &CompressedSize, (const Bytef*)a_Data, a_Length, Z_DEFAULT_COMPRESSION);
|
||||||
|
if (errorcode != Z_OK)
|
||||||
|
{
|
||||||
|
return errorcode;
|
||||||
|
}
|
||||||
|
a_Compressed.resize(CompressedSize);
|
||||||
|
return Z_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Uncompresses a_Data into a_Decompressed; returns Z_XXX error constants same as zlib's decompress()
|
||||||
|
int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed, int a_UncompressedSize)
|
||||||
|
{
|
||||||
|
// HACK: We're assuming that AString returns its internal buffer in its data() call and we're overwriting that buffer!
|
||||||
|
// It saves us one allocation and one memcpy of the entire compressed data
|
||||||
|
// It may not work on some STL implementations! (Confirmed working on MSVC 2008 & 2010)
|
||||||
|
a_Uncompressed.resize(a_UncompressedSize);
|
||||||
|
int errorcode = uncompress((Bytef*)a_Uncompressed.data(), (uLongf *)&a_UncompressedSize, (const Bytef*)a_Data, a_Length);
|
||||||
|
if (errorcode != Z_OK)
|
||||||
|
{
|
||||||
|
return errorcode;
|
||||||
|
}
|
||||||
|
a_Uncompressed.resize(a_UncompressedSize);
|
||||||
|
return Z_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
17
source/StringCompression.h
Normal file
17
source/StringCompression.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
// StringCompression.h
|
||||||
|
|
||||||
|
// Interfaces to the wrapping functions for compression and decompression using AString as their data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Compresses a_Data into a_Compressed; return Z_XXX error constants same as zlib's compress2()
|
||||||
|
extern int CompressString(const char * a_Data, int a_Length, AString & a_Compressed);
|
||||||
|
|
||||||
|
/// Uncompresses a_Data into a_Decompressed; returns Z_XXX error constants same as zlib's decompress()
|
||||||
|
extern int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed, int a_UncompressedSize);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -8,6 +8,11 @@
|
|||||||
#include "cWorld.h"
|
#include "cWorld.h"
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
#include "StringCompression.h"
|
||||||
|
#include "cChestEntity.h"
|
||||||
|
#include "cSignEntity.h"
|
||||||
|
#include "cFurnaceEntity.h"
|
||||||
|
#include "BlockID.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -53,7 +58,7 @@ cWSSCompact::~cWSSCompact()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cWSSCompact::LoadChunk(const cChunkPtr & a_Chunk)
|
bool cWSSCompact::LoadChunk(const cChunkCoords & a_Chunk)
|
||||||
{
|
{
|
||||||
cPAKFile * f = LoadPAKFile(a_Chunk);
|
cPAKFile * f = LoadPAKFile(a_Chunk);
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
@ -62,14 +67,14 @@ bool cWSSCompact::LoadChunk(const cChunkPtr & a_Chunk)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return f->LoadChunk(a_Chunk);
|
return f->LoadChunk(a_Chunk, m_World);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cWSSCompact::SaveChunk(const cChunkPtr & a_Chunk)
|
bool cWSSCompact::SaveChunk(const cChunkCoords & a_Chunk)
|
||||||
{
|
{
|
||||||
cPAKFile * f = LoadPAKFile(a_Chunk);
|
cPAKFile * f = LoadPAKFile(a_Chunk);
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
@ -77,18 +82,18 @@ bool cWSSCompact::SaveChunk(const cChunkPtr & a_Chunk)
|
|||||||
// For some reason we couldn't locate the file
|
// For some reason we couldn't locate the file
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return f->SaveChunk(a_Chunk);
|
return f->SaveChunk(a_Chunk, m_World);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cWSSCompact::cPAKFile * cWSSCompact::LoadPAKFile(const cChunkPtr & a_Chunk)
|
cWSSCompact::cPAKFile * cWSSCompact::LoadPAKFile(const cChunkCoords & a_Chunk)
|
||||||
{
|
{
|
||||||
// We need to retain this weird conversion code, because some edge chunks are in the wrong PAK file
|
// We need to retain this weird conversion code, because some edge chunks are in the wrong PAK file
|
||||||
const int LayerX = (int)(floorf((float)a_Chunk->GetPosX() / 32.0f));
|
const int LayerX = (int)(floorf((float)a_Chunk.m_ChunkX / 32.0f));
|
||||||
const int LayerZ = (int)(floorf((float)a_Chunk->GetPosZ() / 32.0f));
|
const int LayerZ = (int)(floorf((float)a_Chunk.m_ChunkZ / 32.0f));
|
||||||
|
|
||||||
// Is it already cached?
|
// Is it already cached?
|
||||||
for (cPAKFiles::iterator itr = m_PAKFiles.begin(); itr != m_PAKFiles.end(); ++itr)
|
for (cPAKFiles::iterator itr = m_PAKFiles.begin(); itr != m_PAKFiles.end(); ++itr)
|
||||||
@ -207,10 +212,10 @@ cWSSCompact::cPAKFile::~cPAKFile()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cWSSCompact::cPAKFile::LoadChunk(const cChunkPtr & a_Chunk)
|
bool cWSSCompact::cPAKFile::LoadChunk(const cChunkCoords & a_Chunk, cWorld * a_World)
|
||||||
{
|
{
|
||||||
int ChunkX = a_Chunk->GetPosX();
|
int ChunkX = a_Chunk.m_ChunkX;
|
||||||
int ChunkZ = a_Chunk->GetPosZ();
|
int ChunkZ = a_Chunk.m_ChunkZ;
|
||||||
sChunkHeader * Header = NULL;
|
sChunkHeader * Header = NULL;
|
||||||
int Offset = 0;
|
int Offset = 0;
|
||||||
for (sChunkHeaders::iterator itr = m_ChunkHeaders.begin(); itr != m_ChunkHeaders.end(); ++itr)
|
for (sChunkHeaders::iterator itr = m_ChunkHeaders.begin(); itr != m_ChunkHeaders.end(); ++itr)
|
||||||
@ -228,16 +233,16 @@ bool cWSSCompact::cPAKFile::LoadChunk(const cChunkPtr & a_Chunk)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return LoadChunk(a_Chunk, Offset, Header);
|
return LoadChunk(a_Chunk, Offset, Header, a_World);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cWSSCompact::cPAKFile::SaveChunk(const cChunkPtr & a_Chunk)
|
bool cWSSCompact::cPAKFile::SaveChunk(const cChunkCoords & a_Chunk, cWorld * a_World)
|
||||||
{
|
{
|
||||||
if (!SaveChunkToData(a_Chunk))
|
if (!SaveChunkToData(a_Chunk, a_World))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -252,50 +257,63 @@ bool cWSSCompact::cPAKFile::SaveChunk(const cChunkPtr & a_Chunk)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cWSSCompact::cPAKFile::LoadChunk(const cChunkPtr & a_Chunk, int a_Offset, sChunkHeader * a_Header)
|
bool cWSSCompact::cPAKFile::LoadChunk(const cChunkCoords & a_Chunk, int a_Offset, sChunkHeader * a_Header, cWorld * a_World)
|
||||||
{
|
{
|
||||||
|
// Crude data integrity check:
|
||||||
|
if (a_Header->m_UncompressedSize < cChunk::c_BlockDataSize)
|
||||||
|
{
|
||||||
|
LOGWARNING("Chunk [%d, %d] has too short decompressed data (%d out of %d needed), erasing",
|
||||||
|
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ,
|
||||||
|
a_Header->m_UncompressedSize, cChunk::c_BlockDataSize
|
||||||
|
);
|
||||||
|
EraseChunk(a_Chunk);
|
||||||
|
m_NumDirty++;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Decompress the data:
|
// Decompress the data:
|
||||||
uLongf DestSize = a_Header->m_UncompressedSize;
|
AString UncompressedData;
|
||||||
std::auto_ptr<char> BlockData(new char[ DestSize ]);
|
int errorcode = UncompressString(m_DataContents.data() + a_Offset, a_Header->m_CompressedSize, UncompressedData, a_Header->m_UncompressedSize);
|
||||||
int errorcode = uncompress( (Bytef*)BlockData.get(), &DestSize, (Bytef*)m_DataContents.data() + a_Offset, a_Header->m_CompressedSize );
|
|
||||||
if (errorcode != Z_OK)
|
if (errorcode != Z_OK)
|
||||||
{
|
{
|
||||||
LOGERROR("Error %d decompressing data for chunk [%d, %d] from file \"%s\"",
|
LOGERROR("Error %d decompressing data for chunk [%d, %d] from file \"%s\"",
|
||||||
errorcode,
|
errorcode,
|
||||||
a_Chunk->GetPosX(), a_Chunk->GetPosZ(),
|
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ,
|
||||||
m_FileName.c_str()
|
m_FileName.c_str()
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a_Header->m_UncompressedSize != DestSize)
|
if (a_Header->m_UncompressedSize != (int)UncompressedData.size())
|
||||||
{
|
{
|
||||||
LOGWARNING("Uncompressed data size differs (exp %d, got %d) for chunk [%d, %d] from file \"%s\"",
|
LOGWARNING("Uncompressed data size differs (exp %d, got %d) for chunk [%d, %d] from file \"%s\"",
|
||||||
a_Header->m_UncompressedSize, DestSize,
|
a_Header->m_UncompressedSize, UncompressedData.size(),
|
||||||
a_Chunk->GetPosX(), a_Chunk->GetPosZ(),
|
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ,
|
||||||
m_FileName.c_str()
|
m_FileName.c_str()
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
a_Chunk->CopyBlockDataFrom(BlockData.get());
|
cEntityList Entities;
|
||||||
a_Chunk->SetValid();
|
cBlockEntityList BlockEntities;
|
||||||
|
|
||||||
if (DestSize > cChunk::c_BlockDataSize ) // We gots some extra data :D
|
if (a_Header->m_UncompressedSize > cChunk::c_BlockDataSize ) // We gots some extra data :D
|
||||||
{
|
{
|
||||||
LOGINFO("Parsing trailing JSON");
|
LOGINFO("Parsing trailing JSON");
|
||||||
Json::Value root; // will contain the root value after parsing.
|
Json::Value root; // will contain the root value after parsing.
|
||||||
Json::Reader reader;
|
Json::Reader reader;
|
||||||
if ( !reader.parse( BlockData.get() + cChunk::c_BlockDataSize, root, false ) )
|
if ( !reader.parse( UncompressedData.data() + cChunk::c_BlockDataSize, root, false ) )
|
||||||
{
|
{
|
||||||
LOGERROR("Failed to parse trailing JSON!");
|
LOGERROR("Failed to parse trailing JSON!");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
a_Chunk->LoadFromJson( root );
|
LoadEntitiesFromJson(root, Entities, BlockEntities, a_World);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a_World->ChunkDataLoaded(a_Chunk.m_ChunkX, 0, a_Chunk.m_ChunkZ, UncompressedData.data(), Entities, BlockEntities);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,11 +321,10 @@ bool cWSSCompact::cPAKFile::LoadChunk(const cChunkPtr & a_Chunk, int a_Offset, s
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWSSCompact::cPAKFile::EraseChunk(const cChunkPtr & a_Chunk)
|
void cWSSCompact::cPAKFile::EraseChunk(const cChunkCoords & a_Chunk)
|
||||||
{
|
{
|
||||||
int ChunkX = a_Chunk->GetPosX();
|
int ChunkX = a_Chunk.m_ChunkX;
|
||||||
int ChunkZ = a_Chunk->GetPosZ();
|
int ChunkZ = a_Chunk.m_ChunkZ;
|
||||||
sChunkHeader * Header = NULL;
|
|
||||||
int Offset = 0;
|
int Offset = 0;
|
||||||
for (sChunkHeaders::iterator itr = m_ChunkHeaders.begin(); itr != m_ChunkHeaders.end(); ++itr)
|
for (sChunkHeaders::iterator itr = m_ChunkHeaders.begin(); itr != m_ChunkHeaders.end(); ++itr)
|
||||||
{
|
{
|
||||||
@ -326,47 +343,52 @@ void cWSSCompact::cPAKFile::EraseChunk(const cChunkPtr & a_Chunk)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkPtr & a_Chunk)
|
bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld * a_World)
|
||||||
{
|
{
|
||||||
// Erase any existing data for the chunk:
|
|
||||||
EraseChunk(a_Chunk);
|
|
||||||
|
|
||||||
// Serialize the chunk:
|
// Serialize the chunk:
|
||||||
|
cJsonChunkSerializer Serializer;
|
||||||
|
a_World->GetChunkData(a_Chunk.m_ChunkX, 0, a_Chunk.m_ChunkZ, &Serializer);
|
||||||
|
if (Serializer.GetBlockData().empty())
|
||||||
|
{
|
||||||
|
// Chunk not valid
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
AString Data;
|
AString Data;
|
||||||
Data.assign(a_Chunk->pGetBlockData(), cChunk::c_BlockDataSize);
|
std::swap(Serializer.GetBlockData(), Data);
|
||||||
Json::Value root;
|
if (Serializer.HasJsonData())
|
||||||
a_Chunk->SaveToJson( root );
|
|
||||||
if (!root.empty())
|
|
||||||
{
|
{
|
||||||
AString JsonData;
|
AString JsonData;
|
||||||
Json::StyledWriter writer;
|
Json::StyledWriter writer;
|
||||||
JsonData = writer.write( root );
|
JsonData = writer.write(Serializer.GetRoot());
|
||||||
Data.append(JsonData);
|
Data.append(JsonData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compress the data:
|
// Compress the data:
|
||||||
uLongf CompressedSize = compressBound(Data.size());
|
AString CompressedData;
|
||||||
std::auto_ptr<char> Compressed(new char[CompressedSize]);
|
int errorcode = CompressString(Data.data(), Data.size(), CompressedData);
|
||||||
int errorcode = compress2( (Bytef*)Compressed.get(), &CompressedSize, (const Bytef*)Data.data(), Data.size(), Z_DEFAULT_COMPRESSION);
|
|
||||||
if ( errorcode != Z_OK )
|
if ( errorcode != Z_OK )
|
||||||
{
|
{
|
||||||
LOGERROR("Error %i compressing data for chunk [%d, %d]", errorcode, a_Chunk->GetPosX(), a_Chunk->GetPosZ() );
|
LOGERROR("Error %i compressing data for chunk [%d, %d]", errorcode, a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Erase any existing data for the chunk:
|
||||||
|
EraseChunk(a_Chunk);
|
||||||
|
|
||||||
// Save the header:
|
// Save the header:
|
||||||
sChunkHeader * Header = new sChunkHeader;
|
sChunkHeader * Header = new sChunkHeader;
|
||||||
if (Header == NULL)
|
if (Header == NULL)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Header->m_CompressedSize = CompressedSize;
|
Header->m_CompressedSize = (int)CompressedData.size();
|
||||||
Header->m_ChunkX = a_Chunk->GetPosX();
|
Header->m_ChunkX = a_Chunk.m_ChunkX;
|
||||||
Header->m_ChunkZ = a_Chunk->GetPosZ();
|
Header->m_ChunkZ = a_Chunk.m_ChunkZ;
|
||||||
Header->m_UncompressedSize = Data.size();
|
Header->m_UncompressedSize = (int)Data.size();
|
||||||
m_ChunkHeaders.push_back(Header);
|
m_ChunkHeaders.push_back(Header);
|
||||||
|
|
||||||
m_DataContents.append(Compressed.get(), CompressedSize);
|
m_DataContents.append(CompressedData.data(), CompressedData.size());
|
||||||
|
|
||||||
m_NumDirty++;
|
m_NumDirty++;
|
||||||
return true;
|
return true;
|
||||||
@ -402,7 +424,7 @@ void cWSSCompact::cPAKFile::SynchronizeFile(void)
|
|||||||
{
|
{
|
||||||
WRITE(**itr);
|
WRITE(**itr);
|
||||||
}
|
}
|
||||||
if (f.Write(m_DataContents.data(), m_DataContents.size()) != m_DataContents.size())
|
if (f.Write(m_DataContents.data(), m_DataContents.size()) != (int)m_DataContents.size())
|
||||||
{
|
{
|
||||||
LOGERROR("cWSSCompact: ERROR writing chunk contents to file \"%s\" (line %d); file offset %d", m_FileName.c_str(), __LINE__, f.Tell());
|
LOGERROR("cWSSCompact: ERROR writing chunk contents to file \"%s\" (line %d); file offset %d", m_FileName.c_str(), __LINE__, f.Tell());
|
||||||
return;
|
return;
|
||||||
@ -413,3 +435,70 @@ void cWSSCompact::cPAKFile::SynchronizeFile(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSCompact::cPAKFile::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities, cWorld * a_World)
|
||||||
|
{
|
||||||
|
// Load chests
|
||||||
|
Json::Value AllChests = a_Value.get("Chests", Json::nullValue);
|
||||||
|
if (!AllChests.empty())
|
||||||
|
{
|
||||||
|
for (Json::Value::iterator itr = AllChests.begin(); itr != AllChests.end(); ++itr )
|
||||||
|
{
|
||||||
|
Json::Value & Chest = *itr;
|
||||||
|
cChestEntity * ChestEntity = new cChestEntity(0,0,0, a_World);
|
||||||
|
if (!ChestEntity->LoadFromJson( Chest ) )
|
||||||
|
{
|
||||||
|
LOGERROR("ERROR READING CHEST FROM JSON!" );
|
||||||
|
delete ChestEntity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a_BlockEntities.push_back( ChestEntity );
|
||||||
|
}
|
||||||
|
} // for itr - AllChests[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load furnaces
|
||||||
|
Json::Value AllFurnaces = a_Value.get("Furnaces", Json::nullValue);
|
||||||
|
if( !AllFurnaces.empty() )
|
||||||
|
{
|
||||||
|
for( Json::Value::iterator itr = AllFurnaces.begin(); itr != AllFurnaces.end(); ++itr )
|
||||||
|
{
|
||||||
|
Json::Value & Furnace = *itr;
|
||||||
|
cFurnaceEntity * FurnaceEntity = new cFurnaceEntity(0,0,0, a_World);
|
||||||
|
if( !FurnaceEntity->LoadFromJson( Furnace ) )
|
||||||
|
{
|
||||||
|
LOGERROR("ERROR READING FURNACE FROM JSON!" );
|
||||||
|
delete FurnaceEntity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a_BlockEntities.push_back( FurnaceEntity );
|
||||||
|
}
|
||||||
|
} // for itr - AllFurnaces[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load signs
|
||||||
|
Json::Value AllSigns = a_Value.get("Signs", Json::nullValue);
|
||||||
|
if( !AllSigns.empty() )
|
||||||
|
{
|
||||||
|
for( Json::Value::iterator itr = AllSigns.begin(); itr != AllSigns.end(); ++itr )
|
||||||
|
{
|
||||||
|
Json::Value & Sign = *itr;
|
||||||
|
cSignEntity * SignEntity = new cSignEntity( E_BLOCK_SIGN_POST, 0,0,0, a_World);
|
||||||
|
if ( !SignEntity->LoadFromJson( Sign ) )
|
||||||
|
{
|
||||||
|
LOGERROR("ERROR READING SIGN FROM JSON!" );
|
||||||
|
delete SignEntity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a_BlockEntities.push_back( SignEntity );
|
||||||
|
}
|
||||||
|
} // for itr - AllSigns[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,8 +37,8 @@ protected:
|
|||||||
cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ);
|
cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ);
|
||||||
~cPAKFile();
|
~cPAKFile();
|
||||||
|
|
||||||
bool SaveChunk(const cChunkPtr & a_Chunk);
|
bool SaveChunk(const cChunkCoords & a_Chunk, cWorld * a_World);
|
||||||
bool LoadChunk(const cChunkPtr & a_Chunk);
|
bool LoadChunk(const cChunkCoords & a_Chunk, cWorld * a_World);
|
||||||
|
|
||||||
int GetLayerX(void) const {return m_LayerX; }
|
int GetLayerX(void) const {return m_LayerX; }
|
||||||
int GetLayerZ(void) const {return m_LayerZ; }
|
int GetLayerZ(void) const {return m_LayerZ; }
|
||||||
@ -54,10 +54,11 @@ protected:
|
|||||||
|
|
||||||
int m_NumDirty; // Number of chunks that were written into m_DataContents but not into the file
|
int m_NumDirty; // Number of chunks that were written into m_DataContents but not into the file
|
||||||
|
|
||||||
bool LoadChunk(const cChunkPtr & a_Chunk, int a_Offset, sChunkHeader * a_Header);
|
bool LoadChunk(const cChunkCoords & a_Chunk, int a_Offset, sChunkHeader * a_Header, cWorld * a_World);
|
||||||
void EraseChunk(const cChunkPtr & a_Chunk); // Erases the chunk data from m_DataContents and updates m_ChunkHeaders
|
void EraseChunk(const cChunkCoords & a_Chunk); // Erases the chunk data from m_DataContents and updates m_ChunkHeaders
|
||||||
bool SaveChunkToData(const cChunkPtr & a_Chunk); // Saves the chunk to m_DataContents, updates headers and m_NumDirty
|
bool SaveChunkToData(const cChunkCoords & a_Chunk, cWorld * a_World); // Saves the chunk to m_DataContents, updates headers and m_NumDirty
|
||||||
void SynchronizeFile(void); // Writes m_DataContents along with the headers to file, resets m_NumDirty
|
void SynchronizeFile(void); // Writes m_DataContents along with the headers to file, resets m_NumDirty
|
||||||
|
void LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities, cWorld * a_World);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
typedef std::list<cPAKFile *> cPAKFiles;
|
typedef std::list<cPAKFile *> cPAKFiles;
|
||||||
@ -65,11 +66,11 @@ protected:
|
|||||||
cPAKFiles m_PAKFiles; // A MRU cache of PAK files
|
cPAKFiles m_PAKFiles; // A MRU cache of PAK files
|
||||||
|
|
||||||
/// Loads the correct PAK file either from cache or from disk, manages the m_PAKFiles cache
|
/// Loads the correct PAK file either from cache or from disk, manages the m_PAKFiles cache
|
||||||
cPAKFile * LoadPAKFile(const cChunkPtr & a_Chunk);
|
cPAKFile * LoadPAKFile(const cChunkCoords & a_Chunk);
|
||||||
|
|
||||||
// cWSSchema overrides:
|
// cWSSchema overrides:
|
||||||
virtual bool LoadChunk(const cChunkPtr & a_Chunk) override;
|
virtual bool LoadChunk(const cChunkCoords & a_Chunk) override;
|
||||||
virtual bool SaveChunk(const cChunkPtr & a_Chunk) override;
|
virtual bool SaveChunk(const cChunkCoords & a_Chunk) override;
|
||||||
virtual const AString GetName(void) const override {return "compact"; }
|
virtual const AString GetName(void) const override {return "compact"; }
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
#include "WSSCompact.h"
|
#include "WSSCompact.h"
|
||||||
#include "cWorld.h"
|
#include "cWorld.h"
|
||||||
#include "cChunkGenerator.h"
|
#include "cChunkGenerator.h"
|
||||||
|
#include "cEntity.h"
|
||||||
|
#include "cBlockEntity.h"
|
||||||
|
#include "BlockID.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -24,8 +27,8 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
// cWSSchema overrides:
|
// cWSSchema overrides:
|
||||||
virtual bool LoadChunk(const cChunkPtr & a_Chunk) override {return false; }
|
virtual bool LoadChunk(const cChunkCoords & a_Chunk) override {return false; }
|
||||||
virtual bool SaveChunk(const cChunkPtr & a_Chunk) override {return true; }
|
virtual bool SaveChunk(const cChunkCoords & a_Chunk) override {return true; }
|
||||||
virtual const AString GetName(void) const override {return "forgetful"; }
|
virtual const AString GetName(void) const override {return "forgetful"; }
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
@ -33,6 +36,70 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cJsonChunkSerializer:
|
||||||
|
|
||||||
|
cJsonChunkSerializer::cJsonChunkSerializer(void) :
|
||||||
|
m_HasJsonData(false)
|
||||||
|
{
|
||||||
|
m_Root["Chests"] = m_AllChests;
|
||||||
|
m_Root["Furnaces"] = m_AllFurnaces;
|
||||||
|
m_Root["Signs"] = m_AllSigns;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cJsonChunkSerializer::BlockData(const char * a_Data)
|
||||||
|
{
|
||||||
|
m_BlockData.assign(a_Data, cChunk::c_BlockDataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cJsonChunkSerializer::Entity(cEntity * a_Entity)
|
||||||
|
{
|
||||||
|
// TODO: a_Entity->SaveToJson(m_Root);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cJsonChunkSerializer::BlockEntity(cBlockEntity * a_BlockEntity)
|
||||||
|
{
|
||||||
|
const char * SaveInto = NULL;
|
||||||
|
switch (a_BlockEntity->GetBlockType())
|
||||||
|
{
|
||||||
|
case E_BLOCK_CHEST: SaveInto = "Chests"; break;
|
||||||
|
case E_BLOCK_FURNACE: SaveInto = "Furnaces"; break;
|
||||||
|
case E_BLOCK_SIGN_POST: SaveInto = "Signs"; break;
|
||||||
|
case E_BLOCK_WALLSIGN: SaveInto = "Signs"; break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
assert(!"Unhandled blocktype in BlockEntities list while saving to JSON");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // switch (BlockEntity->GetBlockType())
|
||||||
|
if (SaveInto == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value val;
|
||||||
|
a_BlockEntity->SaveToJson(val);
|
||||||
|
m_Root[SaveInto].append(val);
|
||||||
|
m_HasJsonData = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// cWorldStorage:
|
// cWorldStorage:
|
||||||
|
|
||||||
@ -94,12 +161,12 @@ void cWorldStorage::WaitForFinish(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldStorage::QueueLoadChunk(cChunkPtr & a_Chunk)
|
void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
// Queues the chunk for loading; if not loaded, the chunk will be generated
|
// Queues the chunk for loading; if not loaded, the chunk will be generated
|
||||||
cCSLock Lock(m_CSLoadQueue);
|
cCSLock Lock(m_CSLoadQueue);
|
||||||
m_LoadQueue.remove(a_Chunk); // Don't add twice
|
m_LoadQueue.remove (cChunkCoords(a_ChunkX, a_ChunkZ)); // Don't add twice
|
||||||
m_LoadQueue.push_back(a_Chunk);
|
m_LoadQueue.push_back(cChunkCoords(a_ChunkX, a_ChunkZ));
|
||||||
m_Event.Set();
|
m_Event.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,11 +174,11 @@ void cWorldStorage::QueueLoadChunk(cChunkPtr & a_Chunk)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldStorage::QueueSaveChunk(cChunkPtr & a_Chunk)
|
void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSSaveQueue);
|
cCSLock Lock(m_CSSaveQueue);
|
||||||
m_SaveQueue.remove(a_Chunk); // Don't add twice
|
m_SaveQueue.remove (cChunkCoords(a_ChunkX, a_ChunkZ)); // Don't add twice
|
||||||
m_SaveQueue.push_back(a_Chunk);
|
m_SaveQueue.push_back(cChunkCoords(a_ChunkX, a_ChunkZ));
|
||||||
m_Event.Set();
|
m_Event.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +186,7 @@ void cWorldStorage::QueueSaveChunk(cChunkPtr & a_Chunk)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldStorage::UnqueueLoad(const cChunkPtr & a_Chunk)
|
void cWorldStorage::UnqueueLoad(const cChunkCoords & a_Chunk)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSLoadQueue);
|
cCSLock Lock(m_CSLoadQueue);
|
||||||
m_LoadQueue.remove(a_Chunk);
|
m_LoadQueue.remove(a_Chunk);
|
||||||
@ -129,7 +196,7 @@ void cWorldStorage::UnqueueLoad(const cChunkPtr & a_Chunk)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldStorage::UnqueueSave(const cChunkPtr & a_Chunk)
|
void cWorldStorage::UnqueueSave(const cChunkCoords & a_Chunk)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSSaveQueue);
|
cCSLock Lock(m_CSSaveQueue);
|
||||||
m_SaveQueue.remove(a_Chunk);
|
m_SaveQueue.remove(a_Chunk);
|
||||||
@ -189,38 +256,8 @@ void cWorldStorage::Execute(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load 1 chunk:
|
HasMore = LoadOneChunk();
|
||||||
cChunkPtr ToLoad;
|
HasMore = HasMore | SaveOneChunk();
|
||||||
{
|
|
||||||
cCSLock Lock(m_CSLoadQueue);
|
|
||||||
if (m_LoadQueue.size() > 0)
|
|
||||||
{
|
|
||||||
ToLoad = m_LoadQueue.front();
|
|
||||||
m_LoadQueue.pop_front();
|
|
||||||
}
|
|
||||||
HasMore = (m_LoadQueue.size() > 0);
|
|
||||||
}
|
|
||||||
if ((ToLoad != NULL) && !LoadChunk(ToLoad))
|
|
||||||
{
|
|
||||||
// The chunk couldn't be loaded, generate it:
|
|
||||||
m_World->GetGenerator().GenerateChunk(ToLoad->GetPosX(), ToLoad->GetPosZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save 1 chunk:
|
|
||||||
cChunkPtr Save;
|
|
||||||
{
|
|
||||||
cCSLock Lock(m_CSSaveQueue);
|
|
||||||
if (m_SaveQueue.size() > 0)
|
|
||||||
{
|
|
||||||
Save = m_SaveQueue.front();
|
|
||||||
m_SaveQueue.pop_front();
|
|
||||||
}
|
|
||||||
HasMore = HasMore || (m_SaveQueue.size() > 0);
|
|
||||||
}
|
|
||||||
if ((Save != NULL) && (!m_SaveSchema->SaveChunk(Save)))
|
|
||||||
{
|
|
||||||
LOGWARNING("Cannot save chunk [%d, %d]", Save->GetPosX(), Save->GetPosZ());
|
|
||||||
}
|
|
||||||
} while (HasMore);
|
} while (HasMore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,9 +266,62 @@ void cWorldStorage::Execute(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cWorldStorage::LoadChunk(const cChunkPtr & a_Chunk)
|
bool cWorldStorage::LoadOneChunk(void)
|
||||||
{
|
{
|
||||||
if (a_Chunk->IsValid())
|
cChunkCoords ToLoad(0, 0);
|
||||||
|
bool HasMore;
|
||||||
|
bool ShouldLoad = false;
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSLoadQueue);
|
||||||
|
if (m_LoadQueue.size() > 0)
|
||||||
|
{
|
||||||
|
ToLoad = m_LoadQueue.front();
|
||||||
|
m_LoadQueue.pop_front();
|
||||||
|
ShouldLoad = true;
|
||||||
|
}
|
||||||
|
HasMore = (m_LoadQueue.size() > 0);
|
||||||
|
}
|
||||||
|
if (ShouldLoad && !LoadChunk(ToLoad))
|
||||||
|
{
|
||||||
|
// The chunk couldn't be loaded, generate it:
|
||||||
|
m_World->GetGenerator().GenerateChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkZ);
|
||||||
|
}
|
||||||
|
return HasMore;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cWorldStorage::SaveOneChunk(void)
|
||||||
|
{
|
||||||
|
cChunkCoords Save(0, 0);
|
||||||
|
bool HasMore;
|
||||||
|
bool ShouldSave = false;
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSSaveQueue);
|
||||||
|
if (m_SaveQueue.size() > 0)
|
||||||
|
{
|
||||||
|
Save = m_SaveQueue.front();
|
||||||
|
m_SaveQueue.pop_front();
|
||||||
|
ShouldSave = true;
|
||||||
|
}
|
||||||
|
HasMore = (m_SaveQueue.size() > 0);
|
||||||
|
}
|
||||||
|
if (ShouldSave && !m_SaveSchema->SaveChunk(Save))
|
||||||
|
{
|
||||||
|
LOGWARNING("Cannot save chunk [%d, %d]", Save.m_ChunkX, Save.m_ChunkZ);
|
||||||
|
}
|
||||||
|
return HasMore;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cWorldStorage::LoadChunk(const cChunkCoords & a_Chunk)
|
||||||
|
{
|
||||||
|
if (m_World->IsChunkValid(a_Chunk.m_ChunkX, 0, a_Chunk.m_ChunkZ))
|
||||||
{
|
{
|
||||||
// Already loaded (can happen, since the queue is async)
|
// Already loaded (can happen, since the queue is async)
|
||||||
return true;
|
return true;
|
||||||
@ -244,7 +334,7 @@ bool cWorldStorage::LoadChunk(const cChunkPtr & a_Chunk)
|
|||||||
|
|
||||||
for (cWSSchemaList::iterator itr = m_Schemas.begin(); itr != m_Schemas.end(); ++itr)
|
for (cWSSchemaList::iterator itr = m_Schemas.begin(); itr != m_Schemas.end(); ++itr)
|
||||||
{
|
{
|
||||||
if ((*itr)->LoadChunk(a_Chunk))
|
if (((*itr) != m_SaveSchema) && (*itr)->LoadChunk(a_Chunk))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -256,3 +346,4 @@ bool cWorldStorage::LoadChunk(const cChunkPtr & a_Chunk)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
// Interfaces to the cWorldStorage class representing the chunk loading / saving thread
|
// Interfaces to the cWorldStorage class representing the chunk loading / saving thread
|
||||||
// This class decides which storage schema to use for saving; it queries all available schemas for loading
|
// This class decides which storage schema to use for saving; it queries all available schemas for loading
|
||||||
// Also declares the base class for all storage schemas, cWSSchema
|
// Also declares the base class for all storage schemas, cWSSchema
|
||||||
|
// Helper serialization class cJsonChunkSerializer is declared as well
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -15,6 +16,15 @@
|
|||||||
|
|
||||||
#include "cChunk.h"
|
#include "cChunk.h"
|
||||||
#include "cIsThread.h"
|
#include "cIsThread.h"
|
||||||
|
#include <json/json.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fwd:
|
||||||
|
class cEntity;
|
||||||
|
class cBlockEntity;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -27,8 +37,8 @@ public:
|
|||||||
cWSSchema(cWorld * a_World) : m_World(a_World) {}
|
cWSSchema(cWorld * a_World) : m_World(a_World) {}
|
||||||
virtual ~cWSSchema() {} // Force the descendants' destructors to be virtual
|
virtual ~cWSSchema() {} // Force the descendants' destructors to be virtual
|
||||||
|
|
||||||
virtual bool LoadChunk(const cChunkPtr & a_Chunk) = 0;
|
virtual bool LoadChunk(const cChunkCoords & a_Chunk) = 0;
|
||||||
virtual bool SaveChunk(const cChunkPtr & a_Chunk) = 0;
|
virtual bool SaveChunk(const cChunkCoords & a_Chunk) = 0;
|
||||||
virtual const AString GetName(void) const = 0;
|
virtual const AString GetName(void) const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -42,6 +52,41 @@ typedef std::list<cWSSchema *> cWSSchemaList;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Helper class for serializing a chunk into Json
|
||||||
|
class cJsonChunkSerializer :
|
||||||
|
public cChunkDataCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cJsonChunkSerializer(void);
|
||||||
|
|
||||||
|
Json::Value & GetRoot (void) {return m_Root; }
|
||||||
|
AString & GetBlockData(void) {return m_BlockData; }
|
||||||
|
bool HasJsonData (void) const {return m_HasJsonData; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// BlockData is serialized into string
|
||||||
|
AString m_BlockData;
|
||||||
|
|
||||||
|
// Entities and BlockEntities are serialized to Json
|
||||||
|
Json::Value m_Root;
|
||||||
|
Json::Value m_AllChests;
|
||||||
|
Json::Value m_AllFurnaces;
|
||||||
|
Json::Value m_AllSigns;
|
||||||
|
bool m_HasJsonData;
|
||||||
|
|
||||||
|
// cChunkDataCallback overrides:
|
||||||
|
virtual void BlockData (const char * a_Data) override;
|
||||||
|
virtual void Entity (cEntity * a_Entity) override;
|
||||||
|
virtual void BlockEntity(cBlockEntity * a_Entity) override;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// The actual world storage class
|
||||||
class cWorldStorage :
|
class cWorldStorage :
|
||||||
public cIsThread
|
public cIsThread
|
||||||
{
|
{
|
||||||
@ -52,11 +97,11 @@ public:
|
|||||||
cWorldStorage(void);
|
cWorldStorage(void);
|
||||||
~cWorldStorage();
|
~cWorldStorage();
|
||||||
|
|
||||||
void QueueLoadChunk(cChunkPtr & a_Chunk); // Queues the chunk for loading; if not loaded, the chunk will be generated
|
void QueueLoadChunk(int a_ChunkX, int a_ChunkZ); // Queues the chunk for loading; if not loaded, the chunk will be generated
|
||||||
void QueueSaveChunk(cChunkPtr & a_Chunk);
|
void QueueSaveChunk(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
void UnqueueLoad(const cChunkPtr & a_Chunk);
|
void UnqueueLoad(const cChunkCoords & a_Chunk);
|
||||||
void UnqueueSave(const cChunkPtr & a_Chunk);
|
void UnqueueSave(const cChunkCoords & a_Chunk);
|
||||||
|
|
||||||
bool Start(cWorld * a_World, const AString & a_StorageSchemaName); // Hide the cIsThread's Start() method, we need to provide args
|
bool Start(cWorld * a_World, const AString & a_StorageSchemaName); // Hide the cIsThread's Start() method, we need to provide args
|
||||||
void WaitForFinish(void);
|
void WaitForFinish(void);
|
||||||
@ -67,20 +112,31 @@ protected:
|
|||||||
AString m_StorageSchemaName;
|
AString m_StorageSchemaName;
|
||||||
|
|
||||||
cCriticalSection m_CSLoadQueue;
|
cCriticalSection m_CSLoadQueue;
|
||||||
cChunkPtrList m_LoadQueue;
|
cChunkCoordsList m_LoadQueue;
|
||||||
|
|
||||||
cCriticalSection m_CSSaveQueue;
|
cCriticalSection m_CSSaveQueue;
|
||||||
cChunkPtrList m_SaveQueue;
|
cChunkCoordsList m_SaveQueue;
|
||||||
|
|
||||||
cEvent m_Event; // Set when there's any addition to the queues
|
cEvent m_Event; // Set when there's any addition to the queues
|
||||||
|
|
||||||
|
/// All the storage schemas (all used for loading)
|
||||||
cWSSchemaList m_Schemas;
|
cWSSchemaList m_Schemas;
|
||||||
cWSSchema * m_SaveSchema;
|
|
||||||
|
/// The one storage schema used for saving
|
||||||
|
cWSSchema * m_SaveSchema;
|
||||||
|
|
||||||
void InitSchemas(void);
|
void InitSchemas(void);
|
||||||
|
|
||||||
virtual void Execute(void) override;
|
virtual void Execute(void) override;
|
||||||
bool LoadChunk(const cChunkPtr & a_Chunk);
|
|
||||||
|
/// Loads one chunk from the queue (if any queued); returns true if there are more chunks in the load queue
|
||||||
|
bool LoadOneChunk(void);
|
||||||
|
|
||||||
|
/// Saves one chunk from the queue (if any queued); returns true if there are more chunks in the save queue
|
||||||
|
bool SaveOneChunk(void);
|
||||||
|
|
||||||
|
/// Loads the chunk specified; returns true on success, false on failure
|
||||||
|
bool LoadChunk(const cChunkCoords & a_Chunk);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,6 +11,11 @@ enum ENUM_BLOCK_ID;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace Json
|
||||||
|
{
|
||||||
|
class Value;
|
||||||
|
};
|
||||||
|
|
||||||
class cClientHandle;
|
class cClientHandle;
|
||||||
class cPlayer;
|
class cPlayer;
|
||||||
class cWorld;
|
class cWorld;
|
||||||
@ -41,6 +46,8 @@ public:
|
|||||||
|
|
||||||
cWorld * GetWorld(void) const {return m_World; }
|
cWorld * GetWorld(void) const {return m_World; }
|
||||||
|
|
||||||
|
virtual void SaveToJson (Json::Value & a_Value ) = 0;
|
||||||
|
|
||||||
virtual void UsedBy( cPlayer * a_Player ) = 0;
|
virtual void UsedBy( cPlayer * a_Player ) = 0;
|
||||||
virtual void SendTo( cClientHandle* a_Client ) { (void)a_Client; }
|
virtual void SendTo( cClientHandle* a_Client ) { (void)a_Client; }
|
||||||
|
|
||||||
|
@ -186,11 +186,6 @@ void cChestEntity::SendTo( cClientHandle* a_Client, cServer* a_Server )
|
|||||||
|
|
||||||
void cChestEntity::UsedBy( cPlayer * a_Player )
|
void cChestEntity::UsedBy( cPlayer * a_Player )
|
||||||
{
|
{
|
||||||
LOG("Used a chest");
|
|
||||||
// m_Content[0].m_ItemCount = 1;
|
|
||||||
// m_Content[0].m_ItemID = E_ITEM_STONE;
|
|
||||||
// m_Content[0].m_ItemHealth = 0;
|
|
||||||
|
|
||||||
if( !GetWindow() )
|
if( !GetWindow() )
|
||||||
{
|
{
|
||||||
cWindow* Window = new cWindow( this, true );
|
cWindow* Window = new cWindow( this, true );
|
||||||
|
@ -37,10 +37,10 @@ public:
|
|||||||
cItem * GetSlot( int a_Slot );
|
cItem * GetSlot( int a_Slot );
|
||||||
void SetSlot( int a_Slot, cItem & a_Item );
|
void SetSlot( int a_Slot, cItem & a_Item );
|
||||||
|
|
||||||
bool LoadFromFile(cFile & a_File); // deprecated format
|
OBSOLETE bool LoadFromFile(cFile & a_File); // deprecated format
|
||||||
|
|
||||||
bool LoadFromJson( const Json::Value& a_Value );
|
bool LoadFromJson( const Json::Value& a_Value );
|
||||||
void SaveToJson( Json::Value& a_Value );
|
virtual void SaveToJson(Json::Value& a_Value ) override;
|
||||||
|
|
||||||
void SendTo( cClientHandle* a_Client, cServer* a_Server );
|
void SendTo( cClientHandle* a_Client, cServer* a_Server );
|
||||||
|
|
||||||
|
@ -63,6 +63,8 @@ cChunk::cChunk(int a_X, int a_Y, int a_Z, cWorld * a_World)
|
|||||||
, m_BlockTickZ( 0 )
|
, m_BlockTickZ( 0 )
|
||||||
, m_World( a_World )
|
, m_World( a_World )
|
||||||
, m_IsValid(false)
|
, m_IsValid(false)
|
||||||
|
, m_IsDirty(false)
|
||||||
|
, m_IsSaving(false)
|
||||||
{
|
{
|
||||||
// LOGINFO("### new cChunk (%i, %i) at %p, thread 0x%x ###", a_X, a_Z, this, GetCurrentThreadId());
|
// LOGINFO("### new cChunk (%i, %i) at %p, thread 0x%x ###", a_X, a_Z, this, GetCurrentThreadId());
|
||||||
}
|
}
|
||||||
@ -143,7 +145,120 @@ void cChunk::SetValid(bool a_SendToClients)
|
|||||||
bool cChunk::CanUnload(void)
|
bool cChunk::CanUnload(void)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSClients);
|
cCSLock Lock(m_CSClients);
|
||||||
return m_LoadedByClient.empty();
|
return m_LoadedByClient.empty() && !m_IsDirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunk::MarkSaving(void)
|
||||||
|
{
|
||||||
|
m_IsSaving = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunk::MarkSaved(void)
|
||||||
|
{
|
||||||
|
if (!m_IsSaving)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_IsDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunk::MarkLoaded(void)
|
||||||
|
{
|
||||||
|
m_IsDirty = false;
|
||||||
|
m_IsValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunk::GetAllData(cChunkDataCallback * a_Callback)
|
||||||
|
{
|
||||||
|
a_Callback->BlockData(m_BlockData);
|
||||||
|
|
||||||
|
cCSLock Lock(m_CSEntities);
|
||||||
|
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr)
|
||||||
|
{
|
||||||
|
a_Callback->Entity(*itr);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
|
||||||
|
{
|
||||||
|
a_Callback->BlockEntity(*itr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunk::SetAllData(const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities)
|
||||||
|
{
|
||||||
|
memcpy(m_BlockData, a_BlockData, sizeof(m_BlockData));
|
||||||
|
|
||||||
|
// Clear the internal entities:
|
||||||
|
cCSLock Lock(m_CSEntities);
|
||||||
|
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr)
|
||||||
|
{
|
||||||
|
if ((*itr)->GetEntityType() == cEntity::E_PLAYER)
|
||||||
|
{
|
||||||
|
// Move players into the new entity list
|
||||||
|
a_Entities.push_back(*itr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Delete other entities (there should not be any, since we're now loading / generating the chunk)
|
||||||
|
LOGWARNING("cChunk: There is an unexpected entity #%d of type %s in chunk [%d, %d]; it will be deleted",
|
||||||
|
(*itr)->GetUniqueID(), (*itr)->GetClass(),
|
||||||
|
m_PosX, m_PosZ
|
||||||
|
);
|
||||||
|
delete *itr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
|
||||||
|
{
|
||||||
|
delete *itr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap the entity lists:
|
||||||
|
std::swap(a_Entities, m_Entities);
|
||||||
|
std::swap(a_BlockEntities, m_BlockEntities);
|
||||||
|
|
||||||
|
// Create block entities that the loader didn't load; fill them with defaults
|
||||||
|
CreateBlockEntities();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns true if there is a block entity at the coords specified
|
||||||
|
bool cChunk::HasBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||||
|
{
|
||||||
|
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
((*itr)->GetPosX() == a_BlockX) &&
|
||||||
|
((*itr)->GetPosY() == a_BlockY) &&
|
||||||
|
((*itr)->GetPosZ() == a_BlockZ)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // for itr - m_BlockEntities[]
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -405,9 +520,8 @@ char cChunk::GetHeight( int a_X, int a_Z )
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunk::CreateBlockEntities()
|
void cChunk::CreateBlockEntities(void)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSBlockLists);
|
|
||||||
for (int x = 0; x < 16; x++)
|
for (int x = 0; x < 16; x++)
|
||||||
{
|
{
|
||||||
for (int z = 0; z < 16; z++)
|
for (int z = 0; z < 16; z++)
|
||||||
@ -419,20 +533,29 @@ void cChunk::CreateBlockEntities()
|
|||||||
{
|
{
|
||||||
case E_BLOCK_CHEST:
|
case E_BLOCK_CHEST:
|
||||||
{
|
{
|
||||||
m_BlockEntities.push_back( new cChestEntity( x + m_PosX * 16, y + m_PosY * 128, z + m_PosZ * 16, m_World) );
|
if (!HasBlockEntityAt(x + m_PosX * 16, y + m_PosY * 128, z + m_PosZ * 16))
|
||||||
|
{
|
||||||
|
m_BlockEntities.push_back( new cChestEntity( x + m_PosX * 16, y + m_PosY * 128, z + m_PosZ * 16, m_World) );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case E_BLOCK_FURNACE:
|
case E_BLOCK_FURNACE:
|
||||||
{
|
{
|
||||||
m_BlockEntities.push_back( new cFurnaceEntity( x + m_PosX * 16, y + m_PosY * 128, z + m_PosZ * 16, m_World) );
|
if (!HasBlockEntityAt(x + m_PosX * 16, y + m_PosY * 128, z + m_PosZ * 16))
|
||||||
|
{
|
||||||
|
m_BlockEntities.push_back( new cFurnaceEntity( x + m_PosX * 16, y + m_PosY * 128, z + m_PosZ * 16, m_World) );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case E_BLOCK_SIGN_POST:
|
case E_BLOCK_SIGN_POST:
|
||||||
case E_BLOCK_WALLSIGN:
|
case E_BLOCK_WALLSIGN:
|
||||||
{
|
{
|
||||||
m_BlockEntities.push_back( new cSignEntity( BlockType, x + m_PosX * 16, y + m_PosY * 128, z + m_PosZ * 16, m_World) );
|
if (!HasBlockEntityAt(x + m_PosX * 16, y + m_PosY * 128, z + m_PosZ * 16))
|
||||||
|
{
|
||||||
|
m_BlockEntities.push_back( new cSignEntity( BlockType, x + m_PosX * 16, y + m_PosY * 128, z + m_PosZ * 16, m_World) );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} // switch (BlockType)
|
} // switch (BlockType)
|
||||||
@ -678,6 +801,8 @@ void cChunk::SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_Block
|
|||||||
|
|
||||||
assert(IsValid()); // Is this chunk loaded / generated?
|
assert(IsValid()); // Is this chunk loaded / generated?
|
||||||
|
|
||||||
|
MarkDirty();
|
||||||
|
|
||||||
int index = a_Y + (a_Z * 128) + (a_X * 128 * 16);
|
int index = a_Y + (a_Z * 128) + (a_X * 128 * 16);
|
||||||
char OldBlockMeta = GetLight( m_BlockMeta, index );
|
char OldBlockMeta = GetLight( m_BlockMeta, index );
|
||||||
char OldBlockType = m_BlockType[index];
|
char OldBlockType = m_BlockType[index];
|
||||||
@ -742,6 +867,8 @@ void cChunk::FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_B
|
|||||||
|
|
||||||
assert(IsValid());
|
assert(IsValid());
|
||||||
|
|
||||||
|
MarkDirty();
|
||||||
|
|
||||||
const int index = a_Y + (a_Z * 128) + (a_X * 128 * 16);
|
const int index = a_Y + (a_Z * 128) + (a_X * 128 * 16);
|
||||||
const char OldBlock = m_BlockType[index];
|
const char OldBlock = m_BlockType[index];
|
||||||
if (OldBlock == a_BlockType)
|
if (OldBlock == a_BlockType)
|
||||||
@ -868,6 +995,7 @@ void cChunk::CollectPickupsByPlayer(cPlayer * a_Player)
|
|||||||
float SqrDist = DiffX * DiffX + DiffY * DiffY + DiffZ * DiffZ;
|
float SqrDist = DiffX * DiffX + DiffY * DiffY + DiffZ * DiffZ;
|
||||||
if (SqrDist < 1.5f * 1.5f) // 1.5 block
|
if (SqrDist < 1.5f * 1.5f) // 1.5 block
|
||||||
{
|
{
|
||||||
|
MarkDirty();
|
||||||
(reinterpret_cast<cPickup *>(*itr))->CollectedBy( a_Player );
|
(reinterpret_cast<cPickup *>(*itr))->CollectedBy( a_Player );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -893,6 +1021,7 @@ void cChunk::UpdateSign(int a_PosX, int a_PosY, int a_PosZ, const AString & a_Li
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
MarkDirty();
|
||||||
(reinterpret_cast<cSignEntity *>(*itr))->SetLines(a_Line1, a_Line2, a_Line3, a_Line4);
|
(reinterpret_cast<cSignEntity *>(*itr))->SetLines(a_Line1, a_Line2, a_Line3, a_Line4);
|
||||||
(*itr)->SendTo(NULL);
|
(*itr)->SendTo(NULL);
|
||||||
}
|
}
|
||||||
@ -906,6 +1035,7 @@ void cChunk::UpdateSign(int a_PosX, int a_PosY, int a_PosZ, const AString & a_Li
|
|||||||
void cChunk::RemoveBlockEntity( cBlockEntity* a_BlockEntity )
|
void cChunk::RemoveBlockEntity( cBlockEntity* a_BlockEntity )
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSBlockLists);
|
cCSLock Lock(m_CSBlockLists);
|
||||||
|
MarkDirty();
|
||||||
m_BlockEntities.remove( a_BlockEntity );
|
m_BlockEntities.remove( a_BlockEntity );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -924,7 +1054,7 @@ void cChunk::AddClient( cClientHandle* a_Client )
|
|||||||
cCSLock Lock(m_CSEntities);
|
cCSLock Lock(m_CSEntities);
|
||||||
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr )
|
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr )
|
||||||
{
|
{
|
||||||
LOG("Entity at [%i %i %i] spawning for player \"%s\"", m_PosX, m_PosY, m_PosZ, a_Client->GetUsername().c_str() );
|
LOG("Entity #%d (%s) at [%i %i %i] spawning for player \"%s\"", (*itr)->GetUniqueID(), (*itr)->GetClass(), m_PosX, m_PosY, m_PosZ, a_Client->GetUsername().c_str() );
|
||||||
(*itr)->SpawnOn( a_Client );
|
(*itr)->SpawnOn( a_Client );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -986,6 +1116,10 @@ bool cChunk::HasAnyClient(void)
|
|||||||
void cChunk::AddEntity( cEntity * a_Entity )
|
void cChunk::AddEntity( cEntity * a_Entity )
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSEntities);
|
cCSLock Lock(m_CSEntities);
|
||||||
|
if (a_Entity->GetEntityType() != cEntity::E_PLAYER)
|
||||||
|
{
|
||||||
|
MarkDirty();
|
||||||
|
}
|
||||||
m_Entities.push_back( a_Entity );
|
m_Entities.push_back( a_Entity );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1002,6 +1136,10 @@ void cChunk::RemoveEntity(cEntity * a_Entity)
|
|||||||
m_Entities.remove(a_Entity);
|
m_Entities.remove(a_Entity);
|
||||||
SizeAfter = m_Entities.size();
|
SizeAfter = m_Entities.size();
|
||||||
}
|
}
|
||||||
|
if ((a_Entity->GetEntityType() != cEntity::E_PLAYER) && (SizeBefore != SizeAfter))
|
||||||
|
{
|
||||||
|
MarkDirty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1115,6 +1253,7 @@ bool cChunk::LoadFromDisk()
|
|||||||
{
|
{
|
||||||
LOGINFO("Successfully deleted old format file \"%s\"", SourceFile.c_str());
|
LOGINFO("Successfully deleted old format file \"%s\"", SourceFile.c_str());
|
||||||
}
|
}
|
||||||
|
m_IsDirty = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,10 +38,25 @@ class cServer;
|
|||||||
class MTRand;
|
class MTRand;
|
||||||
class cPlayer;
|
class cPlayer;
|
||||||
|
|
||||||
typedef std::list<cFurnaceEntity *> cFurnaceEntityList;
|
|
||||||
typedef std::list<cClientHandle *> cClientHandleList;
|
typedef std::list<cClientHandle *> cClientHandleList;
|
||||||
typedef std::list<cBlockEntity *> cBlockEntityList;
|
typedef std::list<cBlockEntity *> cBlockEntityList;
|
||||||
|
|
||||||
|
/** Interface class used for getting data out of a chunk using the GetAllData() function.
|
||||||
|
Implementation must use the pointers immediately and NOT store any of them for later use
|
||||||
|
*/
|
||||||
|
class cChunkDataCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Called once to export blockdata
|
||||||
|
virtual void BlockData(const char * a_Data) = 0;
|
||||||
|
|
||||||
|
/// Called for each entity in the chunk
|
||||||
|
virtual void Entity(cEntity * a_Entity) = 0;
|
||||||
|
|
||||||
|
/// Called for each blockentity in the chunk
|
||||||
|
virtual void BlockEntity(cBlockEntity * a_Entity) = 0;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -54,14 +69,35 @@ public:
|
|||||||
|
|
||||||
bool IsValid(void) const {return m_IsValid; } // Returns true if the chunk is valid (loaded / generated)
|
bool IsValid(void) const {return m_IsValid; } // Returns true if the chunk is valid (loaded / generated)
|
||||||
void SetValid(bool a_SendToClients = true); // Also wakes up all clients attached to this chunk to let them finish logging in
|
void SetValid(bool a_SendToClients = true); // Also wakes up all clients attached to this chunk to let them finish logging in
|
||||||
|
bool IsDirty(void) const {return m_IsDirty; } // Returns true if the chunk has changed since it was last saved
|
||||||
bool CanUnload(void);
|
bool CanUnload(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
/// 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 char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities);
|
||||||
|
|
||||||
|
/// Returns true if there is a block entity at the coords specified
|
||||||
|
bool HasBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||||
|
|
||||||
void Tick(float a_Dt, MTRand & a_TickRandom);
|
void Tick(float a_Dt, MTRand & a_TickRandom);
|
||||||
|
|
||||||
int GetPosX() { return m_PosX; }
|
int GetPosX() { return m_PosX; }
|
||||||
int GetPosY() { return m_PosY; }
|
int GetPosY() { return m_PosY; }
|
||||||
int GetPosZ() { return m_PosZ; }
|
int GetPosZ() { return m_PosZ; }
|
||||||
cWorld* GetWorld() { return m_World; }
|
cWorld * GetWorld() { return m_World; }
|
||||||
|
|
||||||
void Send( cClientHandle* a_Client );
|
void Send( cClientHandle* a_Client );
|
||||||
void AsyncUnload( cClientHandle* a_Client );
|
void AsyncUnload( cClientHandle* a_Client );
|
||||||
@ -131,6 +167,12 @@ public:
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void MarkDirty(void)
|
||||||
|
{
|
||||||
|
m_IsDirty = true;
|
||||||
|
m_IsSaving = false;
|
||||||
|
}
|
||||||
|
|
||||||
static const int c_NumBlocks = 16*128*16;
|
static const int c_NumBlocks = 16*128*16;
|
||||||
static const int c_BlockDataSize = c_NumBlocks * 2 + (c_NumBlocks/2); // 2.5 * numblocks
|
static const int c_BlockDataSize = c_NumBlocks * 2 + (c_NumBlocks/2); // 2.5 * numblocks
|
||||||
@ -138,15 +180,19 @@ public:
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
bool m_IsValid; // True if the chunk is loaded / generated
|
bool m_IsValid; // True if the chunk is loaded / generated
|
||||||
|
bool m_IsDirty; // True if the chunk has changed since it was last saved
|
||||||
|
bool m_IsSaving; // True if the chunk is being saved
|
||||||
|
|
||||||
cCriticalSection m_CSBlockLists;
|
cCriticalSection m_CSBlockLists;
|
||||||
std::map< unsigned int, int > m_ToTickBlocks;
|
std::map< unsigned int, int > m_ToTickBlocks;
|
||||||
std::vector< unsigned int > m_PendingSendBlocks;
|
std::vector< unsigned int > m_PendingSendBlocks;
|
||||||
|
|
||||||
|
// TODO: This CS will soon not be needed, because all chunk access is protected by its parent ChunkMap's csLayers
|
||||||
cCriticalSection m_CSClients;
|
cCriticalSection m_CSClients;
|
||||||
cClientHandleList m_LoadedByClient;
|
cClientHandleList m_LoadedByClient;
|
||||||
cClientHandleList m_UnloadQuery;
|
cClientHandleList m_UnloadQuery;
|
||||||
|
|
||||||
|
// TODO: This CS will soon not be needed, because all chunk access is protected by its parent ChunkMap's csLayers
|
||||||
cCriticalSection m_CSEntities;
|
cCriticalSection m_CSEntities;
|
||||||
cEntityList m_Entities;
|
cEntityList m_Entities;
|
||||||
cBlockEntityList m_BlockEntities;
|
cBlockEntityList m_BlockEntities;
|
||||||
@ -177,7 +223,7 @@ private:
|
|||||||
void SpreadLightOfBlockY(char* a_LightBuffer, int a_X, int a_Y, int a_Z);
|
void SpreadLightOfBlockY(char* a_LightBuffer, int a_X, int a_Y, int a_Z);
|
||||||
void SpreadLightOfBlockZ(char* a_LightBuffer, int a_X, int a_Y, int a_Z);
|
void SpreadLightOfBlockZ(char* a_LightBuffer, int a_X, int a_Y, int a_Z);
|
||||||
|
|
||||||
void CreateBlockEntities();
|
void CreateBlockEntities(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::tr1::shared_ptr<cChunk> cChunkPtr;
|
typedef std::tr1::shared_ptr<cChunk> cChunkPtr;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
#ifndef __C_CHUNK_INL_H__
|
#ifndef __C_CHUNK_INL_H__
|
||||||
#define __C_CHUNK_INL_H__
|
#define __C_CHUNK_INL_H__
|
||||||
|
|
||||||
@ -5,6 +6,10 @@
|
|||||||
# define MAX(a,b) (((a)>(b))?(a):(b))
|
# define MAX(a,b) (((a)>(b))?(a):(b))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__C_CHUNK_INLINE__
|
__C_CHUNK_INLINE__
|
||||||
char cChunk::GetLight(char* a_Buffer, int a_BlockIdx)
|
char cChunk::GetLight(char* a_Buffer, int a_BlockIdx)
|
||||||
{
|
{
|
||||||
@ -23,6 +28,10 @@ char cChunk::GetLight(char* a_Buffer, int a_BlockIdx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__C_CHUNK_INLINE__
|
__C_CHUNK_INLINE__
|
||||||
char cChunk::GetLight(char* a_Buffer, int x, int y, int z)
|
char cChunk::GetLight(char* a_Buffer, int x, int y, int z)
|
||||||
{
|
{
|
||||||
@ -41,6 +50,10 @@ char cChunk::GetLight(char* a_Buffer, int x, int y, int z)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__C_CHUNK_INLINE__
|
__C_CHUNK_INLINE__
|
||||||
void cChunk::SetLight(char* a_Buffer, int a_BlockIdx, char a_Light)
|
void cChunk::SetLight(char* a_Buffer, int a_BlockIdx, char a_Light)
|
||||||
{
|
{
|
||||||
@ -57,9 +70,14 @@ void cChunk::SetLight(char* a_Buffer, int a_BlockIdx, char a_Light)
|
|||||||
a_Buffer[cindex] &= 0x0f; // Set second half to 0
|
a_Buffer[cindex] &= 0x0f; // Set second half to 0
|
||||||
a_Buffer[cindex] |= (a_Light << 4) & 0xf0;
|
a_Buffer[cindex] |= (a_Light << 4) & 0xf0;
|
||||||
}
|
}
|
||||||
|
MarkDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__C_CHUNK_INLINE__
|
__C_CHUNK_INLINE__
|
||||||
void cChunk::SetLight(char* a_Buffer, int x, int y, int z, char light)
|
void cChunk::SetLight(char* a_Buffer, int x, int y, int z, char light)
|
||||||
{
|
{
|
||||||
@ -76,9 +94,14 @@ void cChunk::SetLight(char* a_Buffer, int x, int y, int z, char light)
|
|||||||
a_Buffer[cindex] &= 0x0f; // Set second half to 0
|
a_Buffer[cindex] &= 0x0f; // Set second half to 0
|
||||||
a_Buffer[cindex] |= (light << 4) & 0xf0;
|
a_Buffer[cindex] |= (light << 4) & 0xf0;
|
||||||
}
|
}
|
||||||
|
MarkDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__C_CHUNK_INLINE__
|
__C_CHUNK_INLINE__
|
||||||
void cChunk::SpreadLightOfBlock(char* a_LightBuffer, int a_X, int a_Y, int a_Z, char a_Falloff)
|
void cChunk::SpreadLightOfBlock(char* a_LightBuffer, int a_X, int a_Y, int a_Z, char a_Falloff)
|
||||||
{
|
{
|
||||||
@ -91,6 +114,10 @@ void cChunk::SpreadLightOfBlock(char* a_LightBuffer, int a_X, int a_Y, int a_Z,
|
|||||||
SetLight( a_LightBuffer, a_X, a_Y, a_Z+1, MAX(GetLight( a_LightBuffer, a_X, a_Y, a_Z+1 ), MAX(0,CurrentLight-a_Falloff) ) );
|
SetLight( a_LightBuffer, a_X, a_Y, a_Z+1, MAX(GetLight( a_LightBuffer, a_X, a_Y, a_Z+1 ), MAX(0,CurrentLight-a_Falloff) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__C_CHUNK_INLINE__
|
__C_CHUNK_INLINE__
|
||||||
void cChunk::SpreadLightOfBlockX(char* a_LightBuffer, int a_X, int a_Y, int a_Z)
|
void cChunk::SpreadLightOfBlockX(char* a_LightBuffer, int a_X, int a_Y, int a_Z)
|
||||||
{
|
{
|
||||||
@ -99,6 +126,10 @@ void cChunk::SpreadLightOfBlockX(char* a_LightBuffer, int a_X, int a_Y, int a_Z)
|
|||||||
SetLight( a_LightBuffer, a_X+1, a_Y, a_Z, MAX(GetLight( a_LightBuffer, a_X+1, a_Y, a_Z ), CurrentLight-1) );
|
SetLight( a_LightBuffer, a_X+1, a_Y, a_Z, MAX(GetLight( a_LightBuffer, a_X+1, a_Y, a_Z ), CurrentLight-1) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__C_CHUNK_INLINE__
|
__C_CHUNK_INLINE__
|
||||||
void cChunk::SpreadLightOfBlockY(char* a_LightBuffer, int a_X, int a_Y, int a_Z)
|
void cChunk::SpreadLightOfBlockY(char* a_LightBuffer, int a_X, int a_Y, int a_Z)
|
||||||
{
|
{
|
||||||
@ -107,6 +138,10 @@ void cChunk::SpreadLightOfBlockY(char* a_LightBuffer, int a_X, int a_Y, int a_Z)
|
|||||||
SetLight( a_LightBuffer, a_X, a_Y+1, a_Z, MAX(GetLight( a_LightBuffer, a_X, a_Y+1, a_Z ), CurrentLight-1) );
|
SetLight( a_LightBuffer, a_X, a_Y+1, a_Z, MAX(GetLight( a_LightBuffer, a_X, a_Y+1, a_Z ), CurrentLight-1) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__C_CHUNK_INLINE__
|
__C_CHUNK_INLINE__
|
||||||
void cChunk::SpreadLightOfBlockZ(char* a_LightBuffer, int a_X, int a_Y, int a_Z)
|
void cChunk::SpreadLightOfBlockZ(char* a_LightBuffer, int a_X, int a_Y, int a_Z)
|
||||||
{
|
{
|
||||||
@ -115,4 +150,8 @@ void cChunk::SpreadLightOfBlockZ(char* a_LightBuffer, int a_X, int a_Y, int a_Z)
|
|||||||
SetLight( a_LightBuffer, a_X, a_Y, a_Z+1, MAX(GetLight( a_LightBuffer, a_X, a_Y, a_Z+1 ), CurrentLight-1) );
|
SetLight( a_LightBuffer, a_X, a_Y, a_Z+1, MAX(GetLight( a_LightBuffer, a_X, a_Y, a_Z+1 ), CurrentLight-1) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -106,7 +106,7 @@ cChunkPtr cChunkMap::GetChunk( int a_ChunkX, int a_ChunkY, int a_ChunkZ )
|
|||||||
cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkZ);
|
cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkZ);
|
||||||
if (!(Chunk->IsValid()))
|
if (!(Chunk->IsValid()))
|
||||||
{
|
{
|
||||||
m_World->GetStorage().QueueLoadChunk(Chunk);
|
m_World->GetStorage().QueueLoadChunk(a_ChunkX, a_ChunkZ);
|
||||||
}
|
}
|
||||||
return Chunk;
|
return Chunk;
|
||||||
}
|
}
|
||||||
@ -174,6 +174,108 @@ void cChunkMap::UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkMap::MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||||
|
if ((Chunk == NULL) || !Chunk->IsValid())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Chunk->MarkDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkMap::MarkChunkSaving(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||||
|
if ((Chunk == NULL) || !Chunk->IsValid())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Chunk->MarkSaving();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkMap::MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||||
|
if ((Chunk == NULL) || !Chunk->IsValid())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Chunk->MarkSaved();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkMap::ChunkDataLoaded(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||||
|
if (Chunk == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Chunk->SetAllData(a_BlockData, a_Entities, a_BlockEntities);
|
||||||
|
Chunk->MarkLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkMap::SetChunkData(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||||
|
if (Chunk == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Chunk->SetAllData(a_BlockData, a_Entities, a_BlockEntities);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkMap::GetChunkData(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback * a_Callback)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||||
|
if ((Chunk == NULL) || !Chunk->IsValid())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Chunk->GetAllData(a_Callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||||
|
return (Chunk != NULL) && Chunk->IsValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkMap::Tick( float a_Dt, MTRand & a_TickRandom )
|
void cChunkMap::Tick( float a_Dt, MTRand & a_TickRandom )
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSLayers);
|
cCSLock Lock(m_CSLayers);
|
||||||
@ -274,9 +376,9 @@ void cChunkMap::cChunkLayer::Save(void)
|
|||||||
cWorld * World = m_Parent->GetWorld();
|
cWorld * World = m_Parent->GetWorld();
|
||||||
for (int i = 0; i < ARRAYCOUNT(m_Chunks); ++i)
|
for (int i = 0; i < ARRAYCOUNT(m_Chunks); ++i)
|
||||||
{
|
{
|
||||||
if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid())
|
if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->IsDirty())
|
||||||
{
|
{
|
||||||
World->GetStorage().QueueSaveChunk(m_Chunks[i]);
|
World->GetStorage().QueueSaveChunk(m_Chunks[i]->GetPosX(), m_Chunks[i]->GetPosZ());
|
||||||
}
|
}
|
||||||
} // for i - m_Chunks[]
|
} // for i - m_Chunks[]
|
||||||
}
|
}
|
||||||
@ -292,9 +394,6 @@ void cChunkMap::cChunkLayer::UnloadUnusedChunks(void)
|
|||||||
{
|
{
|
||||||
if ((m_Chunks[i] != NULL) && (m_Chunks[i]->CanUnload()))
|
if ((m_Chunks[i] != NULL) && (m_Chunks[i]->CanUnload()))
|
||||||
{
|
{
|
||||||
// TODO: Save the chunk if it was changed
|
|
||||||
World->GetStorage().QueueSaveChunk(m_Chunks[i]); // _FT: FIXME: Right now it saves chunks even though it might not have changed.
|
|
||||||
// Also I'm not sure what's going on when I queue this chunks and the next line says reset the pointer.. =/
|
|
||||||
m_Chunks[i].reset();
|
m_Chunks[i].reset();
|
||||||
}
|
}
|
||||||
} // for i - m_Chunks[]
|
} // for i - m_Chunks[]
|
||||||
|
@ -27,7 +27,7 @@ public:
|
|||||||
cChunkMap(cWorld* a_World );
|
cChunkMap(cWorld* a_World );
|
||||||
~cChunkMap();
|
~cChunkMap();
|
||||||
|
|
||||||
// TODO: Get rid of these in favor of the direct action methods:
|
// TODO: Get rid of these (put into Private section) in favor of the direct action methods:
|
||||||
cChunkPtr GetChunk ( int a_ChunkX, int a_ChunkY, int a_ChunkZ ); // Also queues the chunk for loading / generating if not valid
|
cChunkPtr GetChunk ( int a_ChunkX, int a_ChunkY, int a_ChunkZ ); // Also queues the chunk for loading / generating if not valid
|
||||||
cChunkPtr GetChunkNoGen( int a_ChunkX, int a_ChunkY, int a_ChunkZ ); // Also queues the chunk for loading if not valid; doesn't generate
|
cChunkPtr GetChunkNoGen( int a_ChunkX, int a_ChunkY, int a_ChunkZ ); // Also queues the chunk for loading if not valid; doesn't generate
|
||||||
|
|
||||||
@ -36,6 +36,14 @@ public:
|
|||||||
void BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, cPacket * a_Packet, cClientHandle * a_Exclude = NULL);
|
void BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, cPacket * a_Packet, cClientHandle * a_Exclude = NULL);
|
||||||
void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); // a_Player rclked block entity at the coords specified, handle it
|
void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); // a_Player rclked block entity at the coords specified, handle it
|
||||||
|
|
||||||
|
void MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||||
|
void MarkChunkSaving(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||||
|
void MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||||
|
void ChunkDataLoaded(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities);
|
||||||
|
void SetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities);
|
||||||
|
void GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback * a_Callback);
|
||||||
|
bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||||
|
|
||||||
void Tick( float a_Dt, MTRand & a_TickRand );
|
void Tick( float a_Dt, MTRand & a_TickRand );
|
||||||
|
|
||||||
void UnloadUnusedChunks();
|
void UnloadUnusedChunks();
|
||||||
@ -51,7 +59,7 @@ public:
|
|||||||
BlockToChunk(a_X, a_Y, a_Z, a_ChunkX, a_ChunkZ);
|
BlockToChunk(a_X, a_Y, a_Z, a_ChunkX, a_ChunkZ);
|
||||||
|
|
||||||
a_X = a_X - a_ChunkX * 16;
|
a_X = a_X - a_ChunkX * 16;
|
||||||
a_Z = a_Z - a_ChunkZ*16;
|
a_Z = a_Z - a_ChunkZ * 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts absolute block coords to chunk coords:
|
/// Converts absolute block coords to chunk coords:
|
||||||
|
@ -45,6 +45,9 @@ public:
|
|||||||
// Temporarily unlock or re-lock:
|
// Temporarily unlock or re-lock:
|
||||||
void Lock(void);
|
void Lock(void);
|
||||||
void Unlock(void);
|
void Unlock(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(cCSLock);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
@ -58,6 +61,9 @@ class cCSUnlock
|
|||||||
public:
|
public:
|
||||||
cCSUnlock(cCSLock & a_Lock);
|
cCSUnlock(cCSLock & a_Lock);
|
||||||
~cCSUnlock();
|
~cCSUnlock();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(cCSUnlock);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ public:
|
|||||||
bool LoadFromFile(cFile & a_File); // deprecated format
|
bool LoadFromFile(cFile & a_File); // deprecated format
|
||||||
|
|
||||||
bool LoadFromJson(const Json::Value& a_Value );
|
bool LoadFromJson(const Json::Value& a_Value );
|
||||||
void SaveToJson (Json::Value& a_Value );
|
virtual void SaveToJson(Json::Value& a_Value ) override;
|
||||||
|
|
||||||
bool Tick( float a_Dt );
|
bool Tick( float a_Dt );
|
||||||
|
|
||||||
|
@ -922,7 +922,7 @@ bool cPlayer::SaveToDisk()
|
|||||||
LOGERROR("ERROR WRITING PLAYER \"%s\" TO FILE \"%s\" - cannot open file", m_pState->PlayerName.c_str(), SourceFile.c_str());
|
LOGERROR("ERROR WRITING PLAYER \"%s\" TO FILE \"%s\" - cannot open file", m_pState->PlayerName.c_str(), SourceFile.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (f.Write(JsonData.c_str(), JsonData.size()) != JsonData.size())
|
if (f.Write(JsonData.c_str(), JsonData.size()) != (int)JsonData.size())
|
||||||
{
|
{
|
||||||
LOGERROR("ERROR WRITING PLAYER JSON TO FILE \"%s\"", SourceFile.c_str());
|
LOGERROR("ERROR WRITING PLAYER JSON TO FILE \"%s\"", SourceFile.c_str());
|
||||||
return false;
|
return false;
|
||||||
|
@ -23,10 +23,10 @@ public:
|
|||||||
cSignEntity(ENUM_BLOCK_ID a_BlockType, int a_X, int a_Y, int a_Z, cWorld * a_World);
|
cSignEntity(ENUM_BLOCK_ID a_BlockType, int a_X, int a_Y, int a_Z, cWorld * a_World);
|
||||||
virtual ~cSignEntity();
|
virtual ~cSignEntity();
|
||||||
|
|
||||||
bool LoadFromFile(cFile & a_File); // deprecated format
|
OBSOLETE bool LoadFromFile(cFile & a_File); // deprecated format
|
||||||
|
|
||||||
bool LoadFromJson( const Json::Value& a_Value );
|
bool LoadFromJson( const Json::Value& a_Value );
|
||||||
void SaveToJson( Json::Value& a_Value );
|
virtual void SaveToJson(Json::Value& a_Value ) override;
|
||||||
|
|
||||||
void SetLines( const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4 );
|
void SetLines( const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4 );
|
||||||
void SetLine( int a_Index, const AString & a_Line );
|
void SetLine( int a_Index, const AString & a_Line );
|
||||||
|
@ -30,6 +30,10 @@ cWindow::cWindow( cWindowOwner* a_Owner, bool a_bInventoryVisible )
|
|||||||
if( !m_bInventoryVisible ) m_DraggingItem = new cItem();
|
if( !m_bInventoryVisible ) m_DraggingItem = new cItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cWindow::~cWindow()
|
cWindow::~cWindow()
|
||||||
{
|
{
|
||||||
if( !m_bInventoryVisible && m_DraggingItem )
|
if( !m_bInventoryVisible && m_DraggingItem )
|
||||||
@ -39,6 +43,10 @@ cWindow::~cWindow()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cItem* cWindow::GetSlot( int a_Slot )
|
cItem* cWindow::GetSlot( int a_Slot )
|
||||||
{
|
{
|
||||||
if(a_Slot > -1 && a_Slot < m_NumSlots)
|
if(a_Slot > -1 && a_Slot < m_NumSlots)
|
||||||
@ -48,6 +56,10 @@ cItem* cWindow::GetSlot( int a_Slot )
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cItem* cWindow::GetDraggingItem( cPlayer * a_Player /* = 0 */ )
|
cItem* cWindow::GetDraggingItem( cPlayer * a_Player /* = 0 */ )
|
||||||
{
|
{
|
||||||
if( m_bInventoryVisible && a_Player )
|
if( m_bInventoryVisible && a_Player )
|
||||||
@ -61,9 +73,12 @@ cItem* cWindow::GetDraggingItem( cPlayer * a_Player /* = 0 */ )
|
|||||||
return m_DraggingItem;
|
return m_DraggingItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWindow::Clicked( cPacket_WindowClick* a_ClickPacket, cPlayer & a_Player )
|
void cWindow::Clicked( cPacket_WindowClick* a_ClickPacket, cPlayer & a_Player )
|
||||||
{
|
{
|
||||||
//LOG("cWindow click");
|
|
||||||
if( a_ClickPacket->m_WindowID != m_WindowID )
|
if( a_ClickPacket->m_WindowID != m_WindowID )
|
||||||
{
|
{
|
||||||
LOG("WRONG WINDOW ID!");
|
LOG("WRONG WINDOW ID!");
|
||||||
@ -183,6 +198,10 @@ void cWindow::Clicked( cPacket_WindowClick* a_ClickPacket, cPlayer & a_Player )
|
|||||||
if( m_DraggingItem ) LOG("Dragging: %i", m_DraggingItem->m_ItemCount );
|
if( m_DraggingItem ) LOG("Dragging: %i", m_DraggingItem->m_ItemCount );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWindow::Open( cPlayer & a_Player )
|
void cWindow::Open( cPlayer & a_Player )
|
||||||
{
|
{
|
||||||
// If player is already in OpenedBy remove player first
|
// If player is already in OpenedBy remove player first
|
||||||
@ -198,6 +217,10 @@ void cWindow::Open( cPlayer & a_Player )
|
|||||||
a_Player.GetClientHandle()->Send( WindowOpen );
|
a_Player.GetClientHandle()->Send( WindowOpen );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWindow::Close( cPlayer & a_Player )
|
void cWindow::Close( cPlayer & a_Player )
|
||||||
{
|
{
|
||||||
//Checks wheather the player is still holding an item
|
//Checks wheather the player is still holding an item
|
||||||
@ -205,11 +228,9 @@ void cWindow::Close( cPlayer & a_Player )
|
|||||||
{
|
{
|
||||||
LOG("Player holds item! Dropping it...");
|
LOG("Player holds item! Dropping it...");
|
||||||
a_Player.TossItem( true, m_DraggingItem->m_ItemCount );
|
a_Player.TossItem( true, m_DraggingItem->m_ItemCount );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cPacket_WindowClose WindowClose;
|
cPacket_WindowClose WindowClose;
|
||||||
WindowClose.m_Close = (char)m_WindowID;
|
WindowClose.m_Close = (char)m_WindowID;
|
||||||
cClientHandle* ClientHandle = a_Player.GetClientHandle();
|
cClientHandle* ClientHandle = a_Player.GetClientHandle();
|
||||||
if( ClientHandle ) ClientHandle->Send( WindowClose );
|
if( ClientHandle ) ClientHandle->Send( WindowClose );
|
||||||
@ -219,10 +240,12 @@ void cWindow::Close( cPlayer & a_Player )
|
|||||||
{
|
{
|
||||||
Destroy();
|
Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWindow::OwnerDestroyed()
|
void cWindow::OwnerDestroyed()
|
||||||
{
|
{
|
||||||
m_Owner = 0;
|
m_Owner = 0;
|
||||||
@ -233,6 +256,10 @@ void cWindow::OwnerDestroyed()
|
|||||||
(*m_OpenedBy.begin() )->CloseWindow((char)GetWindowType());
|
(*m_OpenedBy.begin() )->CloseWindow((char)GetWindowType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWindow::Destroy()
|
void cWindow::Destroy()
|
||||||
{
|
{
|
||||||
LOG("DESTROY WINDOW");
|
LOG("DESTROY WINDOW");
|
||||||
@ -244,8 +271,16 @@ void cWindow::Destroy()
|
|||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWindow::SendWholeWindow( cClientHandle* a_Client )
|
void cWindow::SendWholeWindow( cClientHandle* a_Client )
|
||||||
{
|
{
|
||||||
cPacket_WholeInventory Inventory( this );
|
cPacket_WholeInventory Inventory( this );
|
||||||
a_Client->Send( Inventory );
|
a_Client->Send( Inventory );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -398,7 +398,6 @@ void cWorld::InitializeSpawn()
|
|||||||
|
|
||||||
void cWorld::Tick(float a_Dt)
|
void cWorld::Tick(float a_Dt)
|
||||||
{
|
{
|
||||||
int randWeather = 0;
|
|
||||||
m_Time += a_Dt / 1000.f;
|
m_Time += a_Dt / 1000.f;
|
||||||
|
|
||||||
CurrentTick++;
|
CurrentTick++;
|
||||||
@ -938,6 +937,78 @@ void cWorld::Broadcast( const cPacket & a_Packet, cClientHandle* a_Exclude)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorld::BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, cPacket * a_Packet, cClientHandle * a_Exclude)
|
||||||
|
{
|
||||||
|
m_ChunkMap->BroadcastToChunkOfBlock(a_X, a_Y, a_Z, a_Packet, a_Exclude);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorld::MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||||
|
{
|
||||||
|
m_ChunkMap->MarkChunkDirty (a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorld::MarkChunkSaving(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||||
|
{
|
||||||
|
m_ChunkMap->MarkChunkSaving(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorld::MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||||
|
{
|
||||||
|
m_ChunkMap->MarkChunkSaved (a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorld::ChunkDataLoaded(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities)
|
||||||
|
{
|
||||||
|
m_ChunkMap->ChunkDataLoaded(a_ChunkX, a_ChunkY, a_ChunkZ, a_BlockData, a_Entities, a_BlockEntities);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorld::SetChunkData(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities)
|
||||||
|
{
|
||||||
|
m_ChunkMap->SetChunkData(a_ChunkX, a_ChunkY, a_ChunkZ, a_BlockData, a_Entities, a_BlockEntities);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorld::GetChunkData(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback * a_Callback)
|
||||||
|
{
|
||||||
|
m_ChunkMap->GetChunkData(a_ChunkX, a_ChunkY, a_ChunkZ, a_Callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cWorld::IsChunkValid(int a_ChunkX, int a_ChunkY, int a_ChunkZ) const
|
||||||
|
{
|
||||||
|
return m_ChunkMap->IsChunkValid(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorld::SetMaxPlayers(int iMax)
|
void cWorld::SetMaxPlayers(int iMax)
|
||||||
{
|
{
|
||||||
m_MaxPlayers = MAX_PLAYERS;
|
m_MaxPlayers = MAX_PLAYERS;
|
||||||
|
@ -33,7 +33,7 @@ class cBlockEntity;
|
|||||||
class cWorldGenerator; // The generator that actually generates the chunks for a single world
|
class cWorldGenerator; // The generator that actually generates the chunks for a single world
|
||||||
class cChunkGenerator; // The thread responsible for generating chunks
|
class cChunkGenerator; // The thread responsible for generating chunks
|
||||||
typedef std::list< cPlayer * > cPlayerList;
|
typedef std::list< cPlayer * > cPlayerList;
|
||||||
typedef cListCallback<cPlayer> cPlayerListCallback;
|
typedef cItemCallback<cPlayer> cPlayerListCallback;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -67,7 +67,15 @@ public:
|
|||||||
|
|
||||||
void Broadcast( const cPacket & a_Packet, cClientHandle* a_Exclude = 0 );
|
void Broadcast( const cPacket & a_Packet, cClientHandle* a_Exclude = 0 );
|
||||||
|
|
||||||
void BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, cPacket * a_Packet, cClientHandle * a_Exclude = NULL) {return m_ChunkMap->BroadcastToChunkOfBlock(a_X, a_Y, a_Z, a_Packet, a_Exclude); }
|
void BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, cPacket * a_Packet, cClientHandle * a_Exclude = NULL);
|
||||||
|
|
||||||
|
void MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||||
|
void MarkChunkSaving(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||||
|
void MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||||
|
void ChunkDataLoaded(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities);
|
||||||
|
void SetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities);
|
||||||
|
void GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback * a_Callback);
|
||||||
|
bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ) const;
|
||||||
|
|
||||||
// MOTD
|
// MOTD
|
||||||
const AString & GetDescription(void) const {return m_Description; }
|
const AString & GetDescription(void) const {return m_Description; }
|
||||||
@ -117,7 +125,7 @@ public:
|
|||||||
inline cWaterSimulator *GetWaterSimulator() { return m_WaterSimulator; }
|
inline cWaterSimulator *GetWaterSimulator() { return m_WaterSimulator; }
|
||||||
inline cLavaSimulator *GetLavaSimulator() { return m_LavaSimulator; }
|
inline cLavaSimulator *GetLavaSimulator() { return m_LavaSimulator; }
|
||||||
|
|
||||||
// TODO: This interface is dangerous!
|
// TODO: This interface is dangerous! Export as a set of specific action functions for Lua: GetChestItem, GetFurnaceItem, SetFurnaceItem, SetSignLines etc.
|
||||||
cBlockEntity * GetBlockEntity( int a_X, int a_Y, int a_Z ); //tolua_export
|
cBlockEntity * GetBlockEntity( int a_X, int a_Y, int a_Z ); //tolua_export
|
||||||
|
|
||||||
/// a_Player is using block entity at [x, y, z], handle that:
|
/// a_Player is using block entity at [x, y, z], handle that:
|
||||||
|
@ -9,9 +9,10 @@
|
|||||||
|
|
||||||
#include "SquirrelBindings.h"
|
#include "SquirrelBindings.h"
|
||||||
#if USE_SQUIRREL
|
#if USE_SQUIRREL
|
||||||
|
#pragma warning(push)
|
||||||
#pragma warning(disable:4100;disable:4127;disable:4510;disable:4610;disable:4244;disable:4512) // Getting A LOT of these warnings from SqPlus
|
#pragma warning(disable:4100;disable:4127;disable:4510;disable:4610;disable:4244;disable:4512) // Getting A LOT of these warnings from SqPlus
|
||||||
#include <sqplus/sqplus.h>
|
#include <sqplus/sqplus.h>
|
||||||
#pragma warning(default:4100;default:4127;default:4510;default:4610;default:4244;default:4512)
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -26,7 +27,10 @@
|
|||||||
|
|
||||||
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
|
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
|
||||||
#define XML_LEAK_FINDER
|
#define XML_LEAK_FINDER
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4100)
|
||||||
#include "LeakFinder.h"
|
#include "LeakFinder.h"
|
||||||
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user