diff options
40 files changed, 1793 insertions, 971 deletions
diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core -Subproject c8ef7e9f8ed2bc1ffdbb3756c2024536bf00469 +Subproject e3a45f34303331be77aceacf2ba53e503ad7284 diff --git a/MCServer/Plugins/ProtectionAreas b/MCServer/Plugins/ProtectionAreas -Subproject bef8ff2a883e98db94f842f9db3d256a039b1fc +Subproject 3019c7b396221b987cd3f89d422276f764834ff diff --git a/Nightbuild2008.cmd b/Nightbuild2008.cmd index 0d93380e9..6de8d9f67 100644 --- a/Nightbuild2008.cmd +++ b/Nightbuild2008.cmd @@ -102,7 +102,7 @@ if errorlevel 1 goto haderror :: Copy all the example ini files into the Install folder for zipping: -copy MCServer\*.example.ini Install\*.example.ini +copy MCServer\*.example.ini Install\ :: Use 7-zip to compress the resulting files into a single file: set FILESUFFIX=%MYYEAR%_%MYMONTH%_%MYDAY%_%MYTIME%_%COMMITID% diff --git a/Tools/AnvilStats/.gitignore b/Tools/AnvilStats/.gitignore index 6574e4a3e..96210cfc9 100644 --- a/Tools/AnvilStats/.gitignore +++ b/Tools/AnvilStats/.gitignore @@ -6,3 +6,4 @@ Release/ Profiling *.png world/ +*.html diff --git a/Tools/AnvilStats/AnvilStats.cpp b/Tools/AnvilStats/AnvilStats.cpp index f0b9dd7e6..d98c21985 100644 --- a/Tools/AnvilStats/AnvilStats.cpp +++ b/Tools/AnvilStats/AnvilStats.cpp @@ -8,6 +8,7 @@ #include "Statistics.h" #include "BiomeMap.h" #include "HeightMap.h" +#include "HeightBiomeMap.h" #include "ChunkExtract.h" #include "SpringStats.h" @@ -26,6 +27,7 @@ int main(int argc, char * argv[]) LOG(" 2 - height map"); LOG(" 3 - extract chunks"); LOG(" 4 - count lava- and water- springs"); + LOG(" 5 - biome and height map"); LOG("\nNo method number present, aborting."); return -1; } @@ -48,6 +50,7 @@ int main(int argc, char * argv[]) case 2: Factory = new cHeightMapFactory; break; case 3: Factory = new cChunkExtractFactory(WorldFolder); break; case 4: Factory = new cSpringStatsFactory; break; + case 5: Factory = new cHeightBiomeMapFactory; break; default: { LOG("Unknown method \"%s\", aborting.", argv[1]); diff --git a/Tools/AnvilStats/AnvilStats.vcproj b/Tools/AnvilStats/AnvilStats.vcproj index b6000ea3e..038f32b97 100644 --- a/Tools/AnvilStats/AnvilStats.vcproj +++ b/Tools/AnvilStats/AnvilStats.vcproj @@ -314,6 +314,14 @@ > </File> <File + RelativePath=".\HeightBiomeMap.cpp" + > + </File> + <File + RelativePath=".\HeightBiomeMap.h" + > + </File> + <File RelativePath=".\HeightMap.cpp" > </File> diff --git a/Tools/AnvilStats/HeightBiomeMap.cpp b/Tools/AnvilStats/HeightBiomeMap.cpp new file mode 100644 index 000000000..36918f644 --- /dev/null +++ b/Tools/AnvilStats/HeightBiomeMap.cpp @@ -0,0 +1,230 @@ + +// HeightBiomeMap.cpp + +// Declares the cHeightBiomeMap class representing a stats module that produces an image of heights and biomes combined + +#include "Globals.h" +#include "HeightBiomeMap.h" +#include "HeightMap.h" + + + + + +cHeightBiomeMap::cHeightBiomeMap(void) : + super("HeBi"), + m_MinRegionX(100000), + m_MaxRegionX(-100000), + m_MinRegionZ(100000), + m_MaxRegionZ(-100000) +{ +} + + + + + +bool cHeightBiomeMap::OnNewRegion(int a_RegionX, int a_RegionZ) +{ + if (a_RegionX < m_MinRegionX) + { + m_MinRegionX = a_RegionX; + } + if (a_RegionX > m_MaxRegionX) + { + m_MaxRegionX = a_RegionX; + } + if (a_RegionZ < m_MinRegionZ) + { + m_MinRegionZ = a_RegionZ; + } + if (a_RegionZ > m_MaxRegionZ) + { + m_MaxRegionZ = a_RegionZ; + } + return super::OnNewRegion(a_RegionX, a_RegionZ); +} + + + + + +bool cHeightBiomeMap::OnNewChunk(int a_ChunkX, int a_ChunkZ) +{ + m_CurrentChunkX = a_ChunkX; + m_CurrentChunkZ = a_ChunkZ; + m_CurrentChunkRelX = m_CurrentChunkX - m_CurrentRegionX * 32; + m_CurrentChunkRelZ = m_CurrentChunkZ - m_CurrentRegionZ * 32; + + ASSERT((m_CurrentChunkRelX >= 0) && (m_CurrentChunkRelX < 32)); + ASSERT((m_CurrentChunkRelZ >= 0) && (m_CurrentChunkRelZ < 32)); + + memset(m_BlockTypes, 0, sizeof(m_BlockTypes)); + + return CALLBACK_CONTINUE; +} + + + + + + +bool cHeightBiomeMap::OnBiomes(const unsigned char * a_BiomeData) +{ + memcpy(m_ChunkBiomes, a_BiomeData, sizeof(m_ChunkBiomes)); + + return CALLBACK_CONTINUE; +} + + + + + +bool cHeightBiomeMap::OnHeightMap(const int * a_HeightMapBE) +{ + for (int i = 0; i < ARRAYCOUNT(m_ChunkHeight); i++) + { + m_ChunkHeight[i] = ntohl(a_HeightMapBE[i]); + } // for i - m_ChunkHeight + + return CALLBACK_CONTINUE; +} + + + + + +bool cHeightBiomeMap::OnSection( + unsigned char a_Y, + const BLOCKTYPE * a_BlockTypes, + const NIBBLETYPE * a_BlockAdditional, + const NIBBLETYPE * a_BlockMeta, + const NIBBLETYPE * a_BlockLight, + const NIBBLETYPE * a_BlockSkyLight +) +{ + // Copy the section data into the appropriate place in the internal buffer + memcpy(m_BlockTypes + a_Y * 16 * 16 * 16, a_BlockTypes, 16 * 16 * 16); + return CALLBACK_CONTINUE; +} + + + + + +bool cHeightBiomeMap::OnSectionsFinished(void) +{ + static const int BiomePalette[] = + { + // ARGB: + 0xff0000ff, /* Ocean */ + 0xff00cf3f, /* Plains */ + 0xffffff00, /* Desert */ + 0xff7f7f7f, /* Extreme Hills */ + 0xff00cf00, /* Forest */ + 0xff007f3f, /* Taiga */ + 0xff3f7f00, /* Swampland */ + 0xff003fff, /* River */ + 0xff7f0000, /* Hell */ + 0xff007fff, /* Sky */ + 0xff3f3fff, /* Frozen Ocean */ + 0xff3f3fff, /* Frozen River */ + 0xff7fffcf, /* Ice Plains */ + 0xff3fcf7f, /* Ice Mountains */ + 0xffcf00cf, /* Mushroom Island */ + 0xff7f00ff, /* Mushroom Island Shore */ + 0xffffff3f, /* Beach */ + 0xffcfcf00, /* Desert Hills */ + 0xff00cf3f, /* Forest Hills */ + 0xff006f1f, /* Taiga Hills */ + 0xff7f8f7f, /* Extreme Hills Edge */ + 0xff004f00, /* Jungle */ + 0xff003f00, /* Jungle Hills */ + } ; + + // Remove trees and other unwanted stuff from the heightmap: + for (int z = 0; z < 16; z++) + { + int PixelLine[16]; // line of 16 pixels that is used as a buffer for setting the image pixels + for (int x = 0; x < 16; x++) + { + int Height = m_ChunkHeight[16 * z + x]; + for (int y = Height; y >= 0; y--) + { + if (cHeightMap::IsGround(m_BlockTypes[256 * y + 16 * z + x])) + { + Height = y; + break; // for y + } + } // for y + + // Set the color based on the biome and height: + char Biome = m_ChunkBiomes[16 * z + x]; + PixelLine[x] = ShadeColor(BiomePalette[Biome], Height); + } // for x + + // Set the pixelline into the image: + SetPixelURow(m_CurrentChunkRelX * 16, m_CurrentChunkRelZ * 16 + z, 16, PixelLine); + } // for z + return CALLBACK_ABORT; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cHeightBiomeMapFactory: + +cHeightBiomeMapFactory::~cHeightBiomeMapFactory() +{ + // Get the min and max region coords: + int MinRegionX = 100000; + int MaxRegionX = -100000; + int MinRegionZ = 100000; + int MaxRegionZ = -100000; + for (cCallbacks::iterator itr = m_Callbacks.begin(), end = m_Callbacks.end(); itr != end; ++itr) + { + cHeightBiomeMap * cb = (cHeightBiomeMap *)(*itr); + if (cb->m_MinRegionX < MinRegionX) + { + MinRegionX = cb->m_MinRegionX; + } + if (cb->m_MaxRegionX > MaxRegionX) + { + MaxRegionX = cb->m_MaxRegionX; + } + if (cb->m_MinRegionZ < MinRegionZ) + { + MinRegionZ = cb->m_MinRegionZ; + } + if (cb->m_MaxRegionZ > MaxRegionZ) + { + MaxRegionZ = cb->m_MaxRegionZ; + } + } + + // If the size is small enough, write an HTML file referencing all the images in a table: + if ((MaxRegionX >= MinRegionX) && (MaxRegionZ >= MinRegionZ) && (MaxRegionX - MinRegionX < 100) && (MaxRegionZ - MinRegionZ < 100)) + { + cFile HTML("HeBi.html", cFile::fmWrite); + if (HTML.IsOpen()) + { + HTML.Printf("<html><body><table cellspacing=0 cellpadding=0>\n"); + for (int z = MinRegionZ; z <= MaxRegionZ; z++) + { + HTML.Printf("<tr>"); + for (int x = MinRegionX; x <= MaxRegionX; x++) + { + HTML.Printf("<td><img src=\"HeBi.%d.%d.bmp\" /></td>", x, z); + } + HTML.Printf("</tr>\n"); + } + HTML.Printf("</table></body></html>"); + } + } +} + + + + diff --git a/Tools/AnvilStats/HeightBiomeMap.h b/Tools/AnvilStats/HeightBiomeMap.h new file mode 100644 index 000000000..d38fa4733 --- /dev/null +++ b/Tools/AnvilStats/HeightBiomeMap.h @@ -0,0 +1,81 @@ + +// HeightBiomeMap.h + +// Declares the cHeightBiomeMap class representing a stats module that produces an image of heights and biomes combined + + + + + +#pragma once + +#include "ImageComposingCallback.h" + + + + + +class cHeightBiomeMap : + public cImageComposingCallback +{ + typedef cImageComposingCallback super; + +public: + // Minima and maxima for the regions processed through this callback + int m_MinRegionX, m_MaxRegionX; + int m_MinRegionZ, m_MaxRegionZ; + + cHeightBiomeMap(void); + +protected: + int m_CurrentChunkX; // Absolute chunk coords + int m_CurrentChunkZ; + int m_CurrentChunkRelX; // Chunk offset from the start of the region + int m_CurrentChunkRelZ; + + char m_ChunkBiomes[16 * 16]; ///< Biome-map for the current chunk + int m_ChunkHeight[16 * 16]; ///< Height-map for the current chunk + BLOCKTYPE m_BlockTypes [16 * 16 * 256]; ///< Block data for the current chunk (between OnSection() and OnSectionsFinished() ) + + // cCallback overrides: + virtual bool OnNewRegion(int a_RegionX, int a_RegionZ) override; + virtual bool OnNewChunk(int a_ChunkX, int a_ChunkZ) override; + virtual bool OnHeader(int a_FileOffset, unsigned char a_NumSectors, int a_Timestamp) override { return CALLBACK_CONTINUE; } + virtual bool OnCompressedDataSizePos(int a_CompressedDataSize, int a_DataOffset, char a_CompressionMethod) override { return CALLBACK_CONTINUE; } + virtual bool OnDecompressedData(const char * a_DecompressedNBT, int a_DataSize) override { return CALLBACK_CONTINUE; } + virtual bool OnRealCoords(int a_ChunkX, int a_ChunkZ) override { return CALLBACK_CONTINUE; } + virtual bool OnLastUpdate(Int64 a_LastUpdate) override { return CALLBACK_CONTINUE; } + virtual bool OnTerrainPopulated(bool a_Populated) override { return a_Populated ? CALLBACK_CONTINUE : CALLBACK_ABORT; } // If not populated, we don't want it! + virtual bool OnBiomes(const unsigned char * a_BiomeData) override; + virtual bool OnHeightMap(const int * a_HeightMapBE) override; + virtual bool OnSection( + unsigned char a_Y, + const BLOCKTYPE * a_BlockTypes, + const NIBBLETYPE * a_BlockAdditional, + const NIBBLETYPE * a_BlockMeta, + const NIBBLETYPE * a_BlockLight, + const NIBBLETYPE * a_BlockSkyLight + ) override; + virtual bool OnSectionsFinished(void) override; + +} ; + + + + + +class cHeightBiomeMapFactory : + public cCallbackFactory +{ +public: + virtual ~cHeightBiomeMapFactory(); + + virtual cCallback * CreateNewCallback(void) override + { + return new cHeightBiomeMap; + } +} ; + + + + diff --git a/Tools/AnvilStats/HeightMap.h b/Tools/AnvilStats/HeightMap.h index c0e71cbc1..e1d73f300 100644 --- a/Tools/AnvilStats/HeightMap.h +++ b/Tools/AnvilStats/HeightMap.h @@ -23,6 +23,8 @@ public: void Finish(void); + static bool IsGround(BLOCKTYPE a_BlockType); + protected: int m_CurrentChunkX; // Absolute chunk coords int m_CurrentChunkZ; @@ -55,8 +57,6 @@ protected: virtual bool OnSectionsFinished(void) override; void StartNewRegion(int a_RegionX, int a_RegionZ); - - static bool IsGround(BLOCKTYPE a_BlockType); } ; diff --git a/Tools/AnvilStats/ImageComposingCallback.cpp b/Tools/AnvilStats/ImageComposingCallback.cpp index 138821698..eb43ad49f 100644 --- a/Tools/AnvilStats/ImageComposingCallback.cpp +++ b/Tools/AnvilStats/ImageComposingCallback.cpp @@ -72,7 +72,7 @@ void cImageComposingCallback::OnRegionFinished(int a_RegionX, int a_RegionZ) AString cImageComposingCallback::GetFileName(int a_RegionX, int a_RegionZ) { - return Printf("%s.%d.%d", m_FileNamePrefix.c_str(), a_RegionX, a_RegionZ); + return Printf("%s.%d.%d.bmp", m_FileNamePrefix.c_str(), a_RegionX, a_RegionZ); } @@ -148,7 +148,7 @@ int cImageComposingCallback::GetPixel(int a_RelU, int a_RelV) void cImageComposingCallback::SetPixelURow(int a_RelUStart, int a_RelV, int a_CountU, int * a_Pixels) { - ASSERT((a_RelUStart >= 0) && (a_RelUStart + a_CountU < IMAGE_WIDTH)); + ASSERT((a_RelUStart >= 0) && (a_RelUStart + a_CountU <= IMAGE_WIDTH)); ASSERT((a_RelV >= 0) && (a_RelV < IMAGE_HEIGHT)); ASSERT(a_Pixels != NULL); @@ -163,6 +163,36 @@ void cImageComposingCallback::SetPixelURow(int a_RelUStart, int a_RelV, int a_Co +int cImageComposingCallback::ShadeColor(int a_Color, int a_Shade) +{ + if (a_Shade < 64) + { + return MixColor(0, a_Color, a_Shade * 4); + } + return MixColor(a_Color, 0xffffff, (a_Shade - 64) * 4); +} + + + + + +int cImageComposingCallback::MixColor(int a_Src, int a_Dest, int a_Amount) +{ + int r = a_Src & 0xff; + int g = (a_Src >> 8) & 0xff; + int b = (a_Src >> 16) & 0xff; + int rd = a_Dest & 0xff; + int gd = (a_Dest >> 8) & 0xff; + int bd = (a_Dest >> 16) & 0xff; + int nr = r + (rd - r) * a_Amount / 256; + int ng = g + (gd - g) * a_Amount / 256; + int nb = b + (bd - b) * a_Amount / 256; + return nr | (ng << 8) | (nb << 16); +} + + + + void cImageComposingCallback::SaveImage(const AString & a_FileName) { cFile f(a_FileName, cFile::fmWrite); diff --git a/Tools/AnvilStats/ImageComposingCallback.h b/Tools/AnvilStats/ImageComposingCallback.h index c04dc869f..2936361d6 100644 --- a/Tools/AnvilStats/ImageComposingCallback.h +++ b/Tools/AnvilStats/ImageComposingCallback.h @@ -77,6 +77,16 @@ public: /// Sets a row of pixels. a_Pixels is expected to be a_CountU pixels wide. a_RelUStart + a_CountU is assumed less than image width void SetPixelURow(int a_RelUStart, int a_RelV, int a_CountU, int * a_Pixels); + /** "Shades" the given color based on the shade amount given + Shade amount 0 .. 63 shades the color from black to a_Color. + Shade amount 64 .. 127 shades the color from a_Color to white. + All other shade amounts have undefined results. + */ + static int ShadeColor(int a_Color, int a_Shade); + + /// Mixes the two colors in the specified ratio; a_Ratio is between 0 and 256, 0 returning a_Src + static int MixColor(int a_Src, int a_Dest, int a_Ratio); + protected: /// Prefix for the filenames, when generated by the default GetFileName() function AString m_FileNamePrefix; diff --git a/Tools/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp index 0ebe18fb3..fc8fceb99 100644 --- a/Tools/ProtoProxy/Connection.cpp +++ b/Tools/ProtoProxy/Connection.cpp @@ -1732,16 +1732,45 @@ bool cConnection::HandleServerMapChunkBulk(void) { return false; } - AString Meta; - if (!m_ServerBuffer.ReadString(Meta, ChunkCount * 12)) + + // Read individual chunk metas. + // Need to read them first and only then start logging (in case we don't have the full packet yet) + struct sChunkMeta { - return false; + int m_ChunkX, m_ChunkZ; + short m_PrimaryBitmap; + short m_AddBitmap; + sChunkMeta(int a_ChunkX, int a_ChunkZ, short a_PrimaryBitmap, short a_AddBitmap) : + m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ), m_PrimaryBitmap(a_PrimaryBitmap), m_AddBitmap(a_AddBitmap) + { + } + } ; + typedef std::vector<sChunkMeta> sChunkMetas; + sChunkMetas ChunkMetas; + ChunkMetas.reserve(ChunkCount); + for (short i = 0; i < ChunkCount; i++) + { + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkX); + HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkZ); + HANDLE_SERVER_PACKET_READ(ReadBEShort, short, PrimaryBitmap); + HANDLE_SERVER_PACKET_READ(ReadBEShort, short, AddBitmap); + ChunkMetas.push_back(sChunkMeta(ChunkX, ChunkZ, PrimaryBitmap, AddBitmap)); } + Log("Received a PACKET_MAP_CHUNK_BULK from the server:"); Log(" ChunkCount = %d", ChunkCount); Log(" Compressed size = %d (0x%x)", CompressedSize, CompressedSize); Log(" IsSkyLightSent = %s", IsSkyLightSent ? "true" : "false"); + // Log individual chunk coords: + int idx = 0; + for (sChunkMetas::iterator itr = ChunkMetas.begin(), end = ChunkMetas.end(); itr != end; ++itr, ++idx) + { + Log(" [%d]: [%d, %d], primary bitmap 0x%02x, add bitmap 0x%02x", + idx, itr->m_ChunkX, itr->m_ChunkZ, itr->m_PrimaryBitmap, itr->m_AddBitmap + ); + } // for itr - ChunkMetas[] + // TODO: Save the compressed data into a file for later analysis COPY_TO_CLIENT(); diff --git a/source/Bindings.cpp b/source/Bindings.cpp index e61757e69..35b32d5cb 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 09/07/13 21:26:23. +** Generated automatically by tolua++-1.0.92 on 09/07/13 22:05:18. */ #ifndef __cplusplus @@ -6456,6 +6456,41 @@ static int tolua_AllToLua_cEntity_AddSpeedZ00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: SteerVehicle of class cEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_SteerVehicle00 +static int tolua_AllToLua_cEntity_SteerVehicle00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnoobj(tolua_S,4,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0); + float a_Forward = ((float) tolua_tonumber(tolua_S,2,0)); + float a_Sideways = ((float) tolua_tonumber(tolua_S,3,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SteerVehicle'", NULL); +#endif + { + self->SteerVehicle(a_Forward,a_Sideways); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'SteerVehicle'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: GetUniqueID of class cEntity */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_GetUniqueID00 static int tolua_AllToLua_cEntity_GetUniqueID00(lua_State* tolua_S) @@ -11486,6 +11521,95 @@ static int tolua_AllToLua_cWorld_BroadcastChat00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: BroadcastSoundEffect of class cWorld */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_BroadcastSoundEffect00 +static int tolua_AllToLua_cWorld_BroadcastSoundEffect00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) || + !tolua_iscppstring(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnumber(tolua_S,5,0,&tolua_err) || + !tolua_isnumber(tolua_S,6,0,&tolua_err) || + !tolua_isnumber(tolua_S,7,0,&tolua_err) || + !tolua_isusertype(tolua_S,8,"const cClientHandle",1,&tolua_err) || + !tolua_isnoobj(tolua_S,9,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0); + const AString a_SoundName = ((const AString) tolua_tocppstring(tolua_S,2,0)); + int a_SrcX = ((int) tolua_tonumber(tolua_S,3,0)); + int a_SrcY = ((int) tolua_tonumber(tolua_S,4,0)); + int a_SrcZ = ((int) tolua_tonumber(tolua_S,5,0)); + float a_Volume = ((float) tolua_tonumber(tolua_S,6,0)); + float a_Pitch = ((float) tolua_tonumber(tolua_S,7,0)); + const cClientHandle* a_Exclude = ((const cClientHandle*) tolua_tousertype(tolua_S,8,NULL)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'BroadcastSoundEffect'", NULL); +#endif + { + self->BroadcastSoundEffect(a_SoundName,a_SrcX,a_SrcY,a_SrcZ,a_Volume,a_Pitch,a_Exclude); + tolua_pushcppstring(tolua_S,(const char*)a_SoundName); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'BroadcastSoundEffect'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: BroadcastSoundParticleEffect of class cWorld */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_BroadcastSoundParticleEffect00 +static int tolua_AllToLua_cWorld_BroadcastSoundParticleEffect00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnumber(tolua_S,5,0,&tolua_err) || + !tolua_isnumber(tolua_S,6,0,&tolua_err) || + !tolua_isusertype(tolua_S,7,"const cClientHandle",1,&tolua_err) || + !tolua_isnoobj(tolua_S,8,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0); + int a_EffectID = ((int) tolua_tonumber(tolua_S,2,0)); + int a_SrcX = ((int) tolua_tonumber(tolua_S,3,0)); + int a_SrcY = ((int) tolua_tonumber(tolua_S,4,0)); + int a_SrcZ = ((int) tolua_tonumber(tolua_S,5,0)); + int a_Data = ((int) tolua_tonumber(tolua_S,6,0)); + const cClientHandle* a_Exclude = ((const cClientHandle*) tolua_tousertype(tolua_S,7,NULL)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'BroadcastSoundParticleEffect'", NULL); +#endif + { + self->BroadcastSoundParticleEffect(a_EffectID,a_SrcX,a_SrcY,a_SrcZ,a_Data,a_Exclude); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'BroadcastSoundParticleEffect'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: UnloadUnusedChunks of class cWorld */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_UnloadUnusedChunks00 static int tolua_AllToLua_cWorld_UnloadUnusedChunks00(lua_State* tolua_S) @@ -29236,6 +29360,16 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"E_META_SNOW_LAYER_SIX",E_META_SNOW_LAYER_SIX); tolua_constant(tolua_S,"E_META_SNOW_LAYER_SEVEN",E_META_SNOW_LAYER_SEVEN); tolua_constant(tolua_S,"E_META_SNOW_LAYER_EIGHT",E_META_SNOW_LAYER_EIGHT); + tolua_constant(tolua_S,"E_META_RAIL_ZM_ZP",E_META_RAIL_ZM_ZP); + tolua_constant(tolua_S,"E_META_RAIL_XM_XP",E_META_RAIL_XM_XP); + tolua_constant(tolua_S,"E_META_RAIL_ASCEND_XP",E_META_RAIL_ASCEND_XP); + tolua_constant(tolua_S,"E_META_RAIL_ASCEND_XM",E_META_RAIL_ASCEND_XM); + tolua_constant(tolua_S,"E_META_RAIL_ASCEND_ZM",E_META_RAIL_ASCEND_ZM); + tolua_constant(tolua_S,"E_META_RAIL_ASCEND_ZP",E_META_RAIL_ASCEND_ZP); + tolua_constant(tolua_S,"E_META_RAIL_CURVED_ZP_XP",E_META_RAIL_CURVED_ZP_XP); + tolua_constant(tolua_S,"E_META_RAIL_CURVED_ZP_XM",E_META_RAIL_CURVED_ZP_XM); + tolua_constant(tolua_S,"E_META_RAIL_CURVED_ZM_XM",E_META_RAIL_CURVED_ZM_XM); + tolua_constant(tolua_S,"E_META_RAIL_CURVED_ZM_XP",E_META_RAIL_CURVED_ZM_XP); tolua_constant(tolua_S,"E_META_COAL_NORMAL",E_META_COAL_NORMAL); tolua_constant(tolua_S,"E_META_COAL_CHARCOAL",E_META_COAL_CHARCOAL); tolua_constant(tolua_S,"E_META_DYE_BLACK",E_META_DYE_BLACK); @@ -29583,6 +29717,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"AddSpeedX",tolua_AllToLua_cEntity_AddSpeedX00); tolua_function(tolua_S,"AddSpeedY",tolua_AllToLua_cEntity_AddSpeedY00); tolua_function(tolua_S,"AddSpeedZ",tolua_AllToLua_cEntity_AddSpeedZ00); + tolua_function(tolua_S,"SteerVehicle",tolua_AllToLua_cEntity_SteerVehicle00); tolua_function(tolua_S,"GetUniqueID",tolua_AllToLua_cEntity_GetUniqueID00); tolua_function(tolua_S,"IsDestroyed",tolua_AllToLua_cEntity_IsDestroyed00); tolua_function(tolua_S,"Destroy",tolua_AllToLua_cEntity_Destroy00); @@ -29853,6 +29988,8 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"GetDimension",tolua_AllToLua_cWorld_GetDimension00); tolua_function(tolua_S,"GetHeight",tolua_AllToLua_cWorld_GetHeight00); tolua_function(tolua_S,"BroadcastChat",tolua_AllToLua_cWorld_BroadcastChat00); + tolua_function(tolua_S,"BroadcastSoundEffect",tolua_AllToLua_cWorld_BroadcastSoundEffect00); + tolua_function(tolua_S,"BroadcastSoundParticleEffect",tolua_AllToLua_cWorld_BroadcastSoundParticleEffect00); tolua_function(tolua_S,"UnloadUnusedChunks",tolua_AllToLua_cWorld_UnloadUnusedChunks00); tolua_function(tolua_S,"RegenerateChunk",tolua_AllToLua_cWorld_RegenerateChunk00); tolua_function(tolua_S,"GenerateChunk",tolua_AllToLua_cWorld_GenerateChunk00); diff --git a/source/Bindings.h b/source/Bindings.h index 67e8ad14f..95935fb90 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,8 +1,8 @@ -/* -** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 09/07/13 21:26:23. -*/ - -/* Exported function */ -TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S); - +/*
+** Lua binding: AllToLua
+** Generated automatically by tolua++-1.0.92 on 09/07/13 22:05:19.
+*/
+
+/* Exported function */
+TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S);
+
diff --git a/source/BlockID.cpp b/source/BlockID.cpp index 4d7cd6003..793e5e523 100644 --- a/source/BlockID.cpp +++ b/source/BlockID.cpp @@ -787,7 +787,7 @@ public: g_BlockIsSolid[E_BLOCK_NETHER_PORTAL] = false; g_BlockIsSolid[E_BLOCK_PISTON] = false; g_BlockIsSolid[E_BLOCK_PISTON_EXTENSION] = false; - g_BlockIsSolid[E_BLOCK_RAIL] = false; + g_BlockIsSolid[E_BLOCK_RAIL] = true; g_BlockIsSolid[E_BLOCK_REDSTONE_REPEATER_OFF] = false; g_BlockIsSolid[E_BLOCK_REDSTONE_REPEATER_ON] = false; g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_OFF] = false; diff --git a/source/BlockID.h b/source/BlockID.h index 00aeff4d6..cd3bd78c4 100644 --- a/source/BlockID.h +++ b/source/BlockID.h @@ -560,6 +560,18 @@ enum E_META_SNOW_LAYER_SEVEN = 6, E_META_SNOW_LAYER_EIGHT = 7, + // E_BLOCK_RAIL metas + E_META_RAIL_ZM_ZP = 0, + E_META_RAIL_XM_XP = 1, + E_META_RAIL_ASCEND_XP = 2, + E_META_RAIL_ASCEND_XM = 3, + E_META_RAIL_ASCEND_ZM = 4, + E_META_RAIL_ASCEND_ZP = 5, + E_META_RAIL_CURVED_ZP_XP = 6, + E_META_RAIL_CURVED_ZP_XM = 7, + E_META_RAIL_CURVED_ZM_XM = 8, + E_META_RAIL_CURVED_ZM_XP = 9, + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Item metas: diff --git a/source/Blocks/BlockRail.h b/source/Blocks/BlockRail.h index 65d120923..0e83b952d 100644 --- a/source/Blocks/BlockRail.h +++ b/source/Blocks/BlockRail.h @@ -8,37 +8,6 @@ -/// Meta values for the rail -enum ENUM_RAIL_DIRECTIONS -{ - E_RAIL_NORTH_SOUTH = 0, - E_RAIL_EAST_WEST = 1, - E_RAIL_ASCEND_EAST = 2, - E_RAIL_ASCEND_WEST = 3, - E_RAIL_ASCEND_NORTH = 4, - E_RAIL_ASCEND_SOUTH = 5, - E_RAIL_CURVED_SOUTH_EAST = 6, - E_RAIL_CURVED_SOUTH_WEST = 7, - E_RAIL_CURVED_NORTH_WEST = 8, - E_RAIL_CURVED_NORTH_EAST = 9, - - // Some useful synonyms: - E_RAIL_DIR_X = E_RAIL_EAST_WEST, - E_RAIL_DIR_Z = E_RAIL_NORTH_SOUTH, - E_RAIL_ASCEND_XP = E_RAIL_ASCEND_EAST, - E_RAIL_ASCEND_XM = E_RAIL_ASCEND_WEST, - E_RAIL_ASCEND_ZM = E_RAIL_ASCEND_NORTH, - E_RAIL_ASCEND_ZP = E_RAIL_ASCEND_SOUTH, - E_RAIL_CURVED_XPZP = E_RAIL_CURVED_SOUTH_EAST, - E_RAIL_CURVED_XMZP = E_RAIL_CURVED_SOUTH_WEST, - E_RAIL_CURVED_XMZM = E_RAIL_CURVED_NORTH_WEST, - E_RAIL_CURVED_XPZM = E_RAIL_CURVED_NORTH_EAST, -} ; - - - - - enum ENUM_PURE { E_PURE_UPDOWN = 0, @@ -96,13 +65,13 @@ public: NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); switch (Meta) { - case E_RAIL_ASCEND_EAST: - case E_RAIL_ASCEND_WEST: - case E_RAIL_ASCEND_NORTH: - case E_RAIL_ASCEND_SOUTH: + case E_META_RAIL_ASCEND_XP: + case E_META_RAIL_ASCEND_XM: + case E_META_RAIL_ASCEND_ZM: + case E_META_RAIL_ASCEND_ZP: { // Mapping between the meta and the neighbors that need checking - Meta -= E_RAIL_ASCEND_EAST; // Base index at zero + Meta -= E_META_RAIL_ASCEND_XP; // Base index at zero static const struct { int x, z; @@ -157,12 +126,12 @@ public: } if (RailsCnt == 1) { - if (Neighbors[7]) return E_RAIL_ASCEND_SOUTH; - else if (Neighbors[6]) return E_RAIL_ASCEND_NORTH; - else if (Neighbors[5]) return E_RAIL_ASCEND_WEST; - else if (Neighbors[4]) return E_RAIL_ASCEND_EAST; - else if (Neighbors[0] || Neighbors[1]) return E_RAIL_EAST_WEST; - else if (Neighbors[2] || Neighbors[3]) return E_RAIL_NORTH_SOUTH; + if (Neighbors[7]) return E_META_RAIL_ASCEND_ZP; + else if (Neighbors[6]) return E_META_RAIL_ASCEND_ZM; + else if (Neighbors[5]) return E_META_RAIL_ASCEND_XM; + else if (Neighbors[4]) return E_META_RAIL_ASCEND_XP; + else if (Neighbors[0] || Neighbors[1]) return E_META_RAIL_XM_XP; + else if (Neighbors[2] || Neighbors[3]) return E_META_RAIL_ZM_ZP; ASSERT(!"Weird neighbor count"); return Meta; } @@ -175,16 +144,16 @@ public: } if (RailsCnt > 1) { - if (Neighbors[3] && Neighbors[0]) return E_RAIL_CURVED_SOUTH_EAST; - else if (Neighbors[3] && Neighbors[1]) return E_RAIL_CURVED_SOUTH_WEST; - else if (Neighbors[2] && Neighbors[0]) return E_RAIL_CURVED_NORTH_EAST; - else if (Neighbors[2] && Neighbors[1]) return E_RAIL_CURVED_NORTH_WEST; - else if (Neighbors[7] && Neighbors[2]) return E_RAIL_ASCEND_SOUTH; - else if (Neighbors[3] && Neighbors[6]) return E_RAIL_ASCEND_NORTH; - else if (Neighbors[5] && Neighbors[0]) return E_RAIL_ASCEND_WEST; - else if (Neighbors[4] && Neighbors[1]) return E_RAIL_ASCEND_EAST; - else if (Neighbors[0] && Neighbors[1]) return E_RAIL_EAST_WEST; - else if (Neighbors[2] && Neighbors[3]) return E_RAIL_NORTH_SOUTH; + if (Neighbors[3] && Neighbors[0]) return E_META_RAIL_CURVED_ZP_XP; + else if (Neighbors[3] && Neighbors[1]) return E_META_RAIL_CURVED_ZP_XM; + else if (Neighbors[2] && Neighbors[0]) return E_META_RAIL_CURVED_ZM_XP; + else if (Neighbors[2] && Neighbors[1]) return E_META_RAIL_CURVED_ZM_XM; + else if (Neighbors[7] && Neighbors[2]) return E_META_RAIL_ASCEND_ZP; + else if (Neighbors[3] && Neighbors[6]) return E_META_RAIL_ASCEND_ZM; + else if (Neighbors[5] && Neighbors[0]) return E_META_RAIL_ASCEND_XM; + else if (Neighbors[4] && Neighbors[1]) return E_META_RAIL_ASCEND_XP; + else if (Neighbors[0] && Neighbors[1]) return E_META_RAIL_XM_XP; + else if (Neighbors[2] && Neighbors[3]) return E_META_RAIL_ZM_ZP; ASSERT(!"Weird neighbor count"); } return Meta; @@ -200,7 +169,7 @@ public: NIBBLETYPE Meta = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); switch (Meta) { - case E_RAIL_NORTH_SOUTH: + case E_META_RAIL_ZM_ZP: { if ( IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH, E_PURE_DOWN) || @@ -212,7 +181,7 @@ public: break; } - case E_RAIL_EAST_WEST: + case E_META_RAIL_XM_XP: { if ( IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST, E_PURE_DOWN) || @@ -224,7 +193,7 @@ public: break; } - case E_RAIL_ASCEND_EAST: + case E_META_RAIL_ASCEND_XP: { if ( IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_EAST) || @@ -236,7 +205,7 @@ public: break; } - case E_RAIL_ASCEND_WEST: + case E_META_RAIL_ASCEND_XM: { if ( IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST) || @@ -248,7 +217,7 @@ public: break; } - case E_RAIL_ASCEND_NORTH: + case E_META_RAIL_ASCEND_ZM: { if ( IsNotConnected(a_World, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NORTH) || @@ -260,7 +229,7 @@ public: break; } - case E_RAIL_ASCEND_SOUTH: + case E_META_RAIL_ASCEND_ZP: { if ( IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH) || @@ -272,7 +241,7 @@ public: break; } - case E_RAIL_CURVED_SOUTH_EAST: + case E_META_RAIL_CURVED_ZP_XP: { if ( IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_SOUTH) || @@ -284,7 +253,7 @@ public: break; } - case E_RAIL_CURVED_SOUTH_WEST: + case E_META_RAIL_CURVED_ZP_XM: { if ( IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_SOUTH) || @@ -296,7 +265,7 @@ public: break; } - case E_RAIL_CURVED_NORTH_WEST: + case E_META_RAIL_CURVED_ZM_XM: { if ( IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH) || @@ -308,7 +277,7 @@ public: break; } - case E_RAIL_CURVED_NORTH_EAST: + case E_META_RAIL_CURVED_ZM_XP: { if ( IsNotConnected(a_World, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH) || @@ -356,11 +325,11 @@ public: case BLOCK_FACE_NORTH: { if ( - (Meta == E_RAIL_NORTH_SOUTH) || - (Meta == E_RAIL_ASCEND_NORTH) || - (Meta == E_RAIL_ASCEND_SOUTH) || - (Meta == E_RAIL_CURVED_SOUTH_EAST) || - (Meta == E_RAIL_CURVED_SOUTH_WEST) + (Meta == E_META_RAIL_ZM_ZP) || + (Meta == E_META_RAIL_ASCEND_ZM) || + (Meta == E_META_RAIL_ASCEND_ZP) || + (Meta == E_META_RAIL_CURVED_ZP_XP) || + (Meta == E_META_RAIL_CURVED_ZP_XM) ) { return false; @@ -371,11 +340,11 @@ public: case BLOCK_FACE_SOUTH: { if ( - (Meta == E_RAIL_NORTH_SOUTH) || - (Meta == E_RAIL_ASCEND_NORTH) || - (Meta == E_RAIL_ASCEND_SOUTH) || - (Meta == E_RAIL_CURVED_NORTH_EAST) || - (Meta == E_RAIL_CURVED_NORTH_WEST) + (Meta == E_META_RAIL_ZM_ZP) || + (Meta == E_META_RAIL_ASCEND_ZM) || + (Meta == E_META_RAIL_ASCEND_ZP) || + (Meta == E_META_RAIL_CURVED_ZM_XP) || + (Meta == E_META_RAIL_CURVED_ZM_XM) ) { return false; @@ -386,11 +355,11 @@ public: case BLOCK_FACE_EAST: { if ( - (Meta == E_RAIL_EAST_WEST) || - (Meta == E_RAIL_ASCEND_EAST) || - (Meta == E_RAIL_ASCEND_WEST) || - (Meta == E_RAIL_CURVED_SOUTH_WEST) || - (Meta == E_RAIL_CURVED_NORTH_WEST) + (Meta == E_META_RAIL_XM_XP) || + (Meta == E_META_RAIL_ASCEND_XP) || + (Meta == E_META_RAIL_ASCEND_XM) || + (Meta == E_META_RAIL_CURVED_ZP_XM) || + (Meta == E_META_RAIL_CURVED_ZM_XM) ) { return false; @@ -400,11 +369,11 @@ public: case BLOCK_FACE_WEST: { if ( - (Meta == E_RAIL_EAST_WEST) || - (Meta == E_RAIL_ASCEND_EAST) || - (Meta == E_RAIL_ASCEND_WEST) || - (Meta == E_RAIL_CURVED_SOUTH_EAST) || - (Meta == E_RAIL_CURVED_NORTH_EAST) + (Meta == E_META_RAIL_XM_XP) || + (Meta == E_META_RAIL_ASCEND_XP) || + (Meta == E_META_RAIL_ASCEND_XM) || + (Meta == E_META_RAIL_CURVED_ZP_XP) || + (Meta == E_META_RAIL_CURVED_ZM_XP) ) { return false; diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp index 555ecb952..3d819ee18 100644 --- a/source/ClientHandle.cpp +++ b/source/ClientHandle.cpp @@ -1090,6 +1090,15 @@ void cClientHandle::HandleSlotSelected(short a_SlotNum) +void cClientHandle::HandleSteerVehicle(float a_Forward, float a_Sideways) +{ + m_Player->SteerVehicle(a_Forward, a_Sideways); +} + + + + + void cClientHandle::HandleWindowClose(char a_WindowID) { m_Player->CloseWindowIfID(a_WindowID); @@ -1938,9 +1947,9 @@ void cClientHandle::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, -void cClientHandle::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType) +void cClientHandle::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) // VehicleTypeType is specific to Minecarts { - m_Protocol->SendSpawnVehicle(a_Vehicle, a_VehicleType); + m_Protocol->SendSpawnVehicle(a_Vehicle, a_VehicleType, a_VehicleSubType); } diff --git a/source/ClientHandle.h b/source/ClientHandle.h index 9fae93d95..9a2092361 100644 --- a/source/ClientHandle.h +++ b/source/ClientHandle.h @@ -125,7 +125,7 @@ public: void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock); void SendSpawnMob (const cMonster & a_Mob); void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch); - void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType); + void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType); void SendTabCompletionResults(const AStringVector & a_Results); void SendTeleportEntity (const cEntity & a_Entity); void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ); @@ -177,6 +177,7 @@ public: void HandleRespawn (void); void HandleRightClick (int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem); void HandleSlotSelected (short a_SlotNum); + void HandleSteerVehicle (float Forward, float Sideways); void HandleTabCompletion (const AString & a_Text); void HandleUpdateSign ( int a_BlockX, int a_BlockY, int a_BlockZ, diff --git a/source/Entities/Entity.cpp b/source/Entities/Entity.cpp index a07811a96..1a593b3d1 100644 --- a/source/Entities/Entity.cpp +++ b/source/Entities/Entity.cpp @@ -536,6 +536,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width); int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width); BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ ); + BLOCKTYPE BlockBelow = NextChunk->GetBlock( RelBlockX, BlockY - 1, RelBlockZ ); if (!g_BlockIsSolid[BlockIn]) // Making sure we are not inside a solid block { if (m_bOnGround) // check if it's still on the ground @@ -578,18 +579,28 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) } else { - // Friction - if (NextSpeed.SqrLength() > 0.0004f) + // TODO: This condition belongs to minecarts, without it, they derails too much. + // But it shouldn't be here for other entities. We need a complete minecart physics overhaul. + if ( + (BlockBelow != E_BLOCK_RAIL) && + (BlockBelow != E_BLOCK_DETECTOR_RAIL) && + (BlockBelow != E_BLOCK_POWERED_RAIL) && + (BlockBelow != E_BLOCK_ACTIVATOR_RAIL) + ) { - NextSpeed.x *= 0.7f / (1 + a_Dt); - if (fabs(NextSpeed.x) < 0.05) + // Friction + if (NextSpeed.SqrLength() > 0.0004f) { - NextSpeed.x = 0; - } - NextSpeed.z *= 0.7f / (1 + a_Dt); - if (fabs(NextSpeed.z) < 0.05) - { - NextSpeed.z = 0; + NextSpeed.x *= 0.6666; + if (fabs(NextSpeed.x) < 0.05) + { + NextSpeed.x = 0; + } + NextSpeed.z *= 0.6666; + if (fabs(NextSpeed.z) < 0.05) + { + NextSpeed.z = 0; + } } } } @@ -1249,6 +1260,25 @@ void cEntity::AddSpeedZ(double a_AddSpeedZ) +void cEntity::SteerVehicle(float a_Forward, float a_Sideways) +{ + if (m_AttachedTo == NULL) + { + return; + } + if ((a_Forward != 0) || (a_Sideways != 0)) + { + Vector3d LookVector = GetLookVector(); + double AddSpeedX = LookVector.x * a_Forward + LookVector.z * a_Sideways; + double AddSpeedZ = LookVector.z * a_Forward - LookVector.x * a_Sideways; + m_AttachedTo->AddSpeed(AddSpeedX, 0, AddSpeedZ); + } +} + + + + + ////////////////////////////////////////////////////////////////////////// // Get look vector (this is NOT a rotation!) Vector3d cEntity::GetLookVector(void) const diff --git a/source/Entities/Entity.h b/source/Entities/Entity.h index 0e30f230c..b063838eb 100644 --- a/source/Entities/Entity.h +++ b/source/Entities/Entity.h @@ -185,6 +185,8 @@ public: void AddSpeedX (double a_AddSpeedX); void AddSpeedY (double a_AddSpeedY); void AddSpeedZ (double a_AddSpeedZ); + + void SteerVehicle(float a_Forward, float a_Sideways); inline int GetUniqueID(void) const { return m_UniqueID; } inline bool IsDestroyed(void) const { return !m_IsInitialized; } @@ -361,7 +363,7 @@ protected: bool m_bOnGround; float m_Gravity; - + // Last Position. double m_LastPosX, m_LastPosY, m_LastPosZ; diff --git a/source/Entities/Minecart.cpp b/source/Entities/Minecart.cpp index 808579582..0c0b7b58a 100644 --- a/source/Entities/Minecart.cpp +++ b/source/Entities/Minecart.cpp @@ -2,6 +2,7 @@ // Minecart.cpp // Implements the cMinecart class representing a minecart in the world +// Indiana Jones! #include "Globals.h" #include "Minecart.h" @@ -17,6 +18,9 @@ cMinecart::cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z) : super(etMinecart, a_X, a_Y, a_Z, 0.98, 0.7), m_Payload(a_Payload) { + SetMass(20.f); + SetMaxHealth(6); + SetHealth(6); } @@ -24,30 +28,329 @@ cMinecart::cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z) : void cMinecart::SpawnOn(cClientHandle & a_ClientHandle) { - char Type = 0; - switch (m_Payload) //Wiki.vg is outdated on this!! + char SubType = 0; + switch (m_Payload) { - case mpNone: Type = 9; break; //? - case mpChest: Type = 10; break; - case mpFurnace: Type = 11; break; //? - case mpTNT: Type = 12; break; //? - case mpHopper: Type = 13; break; //? + case mpNone: SubType = 0; break; + case mpChest: SubType = 1; break; + case mpFurnace: SubType = 2; break; + case mpTNT: SubType = 3; break; + case mpHopper: SubType = 5; break; default: { ASSERT(!"Unknown payload, cannot spawn on client"); return; } } - a_ClientHandle.SendSpawnVehicle(*this, Type); + a_ClientHandle.SendSpawnVehicle(*this, 10, SubType); // 10 = Minecarts, SubType = What type of Minecart } -void cMinecart::Tick(float a_Dt, cChunk & a_Chunk) +void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk) { - // TODO: the physics + if ((GetPosY() > 0) && (GetPosY() < cChunkDef::Height)) + { + BLOCKTYPE BelowType = GetWorld()->GetBlock(floor(GetPosX()), floor(GetPosY() -1 ), floor(GetPosZ())); + + if ( + (BelowType == E_BLOCK_RAIL) || + (BelowType == E_BLOCK_POWERED_RAIL) || + (BelowType == E_BLOCK_DETECTOR_RAIL) || + (BelowType == E_BLOCK_ACTIVATOR_RAIL) + ) + { + HandleRailPhysics(a_Dt, a_Chunk); + } + else + { + super::HandlePhysics(a_Dt, a_Chunk); + BroadcastMovementUpdate(); + } + } + else + { + super::HandlePhysics(a_Dt, a_Chunk); + BroadcastMovementUpdate(); + } +} + + + + + +static const double MAX_SPEED = 8; +static const double MAX_SPEED_NEGATIVE = (0 - MAX_SPEED); +void cMinecart::HandleRailPhysics(float a_Dt, cChunk & a_Chunk) +{ + + super::HandlePhysics(a_Dt, a_Chunk); // Main physics handling + + /* + NOTE: Please bear in mind that taking away from negatives make them even more negative, + adding to negatives make them positive, etc. + */ + + // Get block meta below the cart + NIBBLETYPE BelowMeta = GetWorld()->GetBlockMeta(floor(GetPosX()), floor(GetPosY() -1 ), floor(GetPosZ())); + double SpeedX = GetSpeedX(), SpeedY = GetSpeedY(), SpeedZ = GetSpeedZ(); // Get current speed + + switch (BelowMeta) + { + case E_META_RAIL_ZM_ZP: // NORTHSOUTH + { + SetRotation(270); + SpeedY = 0; // Don't move vertically as on ground + SpeedX = 0; // Correct diagonal movement from curved rails + + // Set Y as current Y rounded up to bypass friction + SetPosY(floor(GetPosY())); + + if (SpeedZ != 0) // Don't do anything if cart is stationary + { + if (SpeedZ > 0) + { + // Going SOUTH, slow down + SpeedZ = SpeedZ - 0.1; + } + else + { + // Going NORTH, slow down + SpeedZ = SpeedZ + 0.1; + } + } + break; + } + + case E_META_RAIL_XM_XP: // EASTWEST + { + SetRotation(180); + SpeedY = 0; + SpeedZ = 0; + + SetPosY(floor(GetPosY())); + + if (SpeedX != 0) + { + if (SpeedX > 0) + { + SpeedX = SpeedX - 0.1; + } + else + { + SpeedX = SpeedX + 0.1; + } + } + break; + } + + case E_META_RAIL_ASCEND_ZM: // ASCEND NORTH + { + SetRotation(270); + SetPosY(floor(GetPosY()) + 0.2); // It seems it doesn't work without levitation :/ + SpeedX = 0; + + if (SpeedZ >= 0) + { + // SpeedZ POSITIVE, going SOUTH + if (SpeedZ <= MAX_SPEED) // Speed limit + { + SpeedZ = SpeedZ + 0.5; // Speed up + SpeedY = (0 - SpeedZ); // Downward movement is negative (0 minus positive numbers is negative) + } + else + { + SpeedZ = MAX_SPEED; // Enforce speed limit + SpeedY = (0 - SpeedZ); + } + } + else + { + // SpeedZ NEGATIVE, going NORTH + SpeedZ = SpeedZ + 0.4; // Slow down + SpeedY = (0 - SpeedZ); // Upward movement is positive (0 minus negative number is positive number) + } + break; + } + + case E_META_RAIL_ASCEND_ZP: // ASCEND SOUTH + { + SetRotation(270); + SetPosY(floor(GetPosY()) + 0.2); + SpeedX = 0; + + if (SpeedZ > 0) + { + // SpeedZ POSITIVE, going SOUTH + SpeedZ = SpeedZ - 0.4; // Slow down + SpeedY = SpeedZ; // Upward movement positive + } + else + { + if (SpeedZ >= MAX_SPEED_NEGATIVE) // Speed limit + { + // SpeedZ NEGATIVE, going NORTH + SpeedZ = SpeedZ - 0.5; // Speed up + SpeedY = SpeedZ; // Downward movement negative + } + else + { + SpeedZ = MAX_SPEED_NEGATIVE; // Enforce speed limit + SpeedY = SpeedZ; + } + } + break; + } + + case E_META_RAIL_ASCEND_XM: // ASCEND EAST + { + SetRotation(180); + SetPosY(floor(GetPosY()) + 0.2); + SpeedZ = 0; + + if (SpeedX >= 0) + { + if (SpeedX <= MAX_SPEED) + { + SpeedX = SpeedX + 0.5; + SpeedY = (0 - SpeedX); + } + else + { + SpeedX = MAX_SPEED; + SpeedY = (0 - SpeedX); + } + } + else + { + SpeedX = SpeedX + 0.4; + SpeedY = (0 - SpeedX); + } + break; + } + + case E_META_RAIL_ASCEND_XP: // ASCEND WEST + { + SetRotation(180); + SetPosY(floor(GetPosY()) + 0.2); + SpeedZ = 0; + + if (SpeedX > 0) + { + SpeedX = SpeedX - 0.4; + SpeedY = SpeedX; + } + else + { + if (SpeedX >= MAX_SPEED_NEGATIVE) + { + SpeedX = SpeedX - 0.5; + SpeedY = SpeedX; + } + else + { + SpeedX = MAX_SPEED_NEGATIVE; + SpeedY = SpeedX; + } + } + break; + } + + case E_META_RAIL_CURVED_ZM_XM: // Ends pointing NORTH and WEST + { + SetRotation(315); // Set correct rotation server side + SetPosY(floor(GetPosY()) + 0.2); // Levitate dat cart + + if (SpeedZ > 0) // Cart moving south + { + SpeedX = (0 - SpeedZ); // Diagonally move southwest (which will make cart hit a southwest rail) + } + else if (SpeedX > 0) // Cart moving east + { + SpeedZ = (0 - SpeedX); // Diagonally move northeast + } + break; + } + + case E_META_RAIL_CURVED_ZM_XP: // Curved NORTH EAST + { + SetRotation(225); + SetPosY(floor(GetPosY()) + 0.2); + + if (SpeedZ > 0) + { + SpeedX = SpeedZ; + } + else if (SpeedX < 0) + { + SpeedZ = SpeedX; + } + break; + } + + case E_META_RAIL_CURVED_ZP_XM: // Curved SOUTH WEST + { + SetRotation(135); + SetPosY(floor(GetPosY()) + 0.2); + + if (SpeedZ < 0) + { + SpeedX = SpeedZ; + } + else if (SpeedX > 0) + { + SpeedZ = SpeedX; + } + break; + } + + case E_META_RAIL_CURVED_ZP_XP: // Curved SOUTH EAST + { + SetRotation(45); + SetPosY(floor(GetPosY()) + 0.2); + + if (SpeedZ < 0) + { + SpeedX = (0 - SpeedZ); + } + else if (SpeedX < 0) + { + SpeedZ = (0 - SpeedX); + } + break; + } + + default: + { + ASSERT(!"Unhandled rail meta!"); // Dun dun DUN! + break; + } + } + + // Set speed to speed variables + SetSpeedX(SpeedX); + SetSpeedY(SpeedY); + SetSpeedZ(SpeedZ); + + + // Broadcast position to client + BroadcastMovementUpdate(); +} + + + + + +void cMinecart::DoTakeDamage(TakeDamageInfo & TDI) +{ + super::DoTakeDamage(TDI); + + if (GetHealth() == 0) + { + Destroy(true); + } } diff --git a/source/Entities/Minecart.h b/source/Entities/Minecart.h index c1a0e84a0..f98b02bb5 100644 --- a/source/Entities/Minecart.h +++ b/source/Entities/Minecart.h @@ -36,7 +36,10 @@ public: // cEntity overrides: virtual void SpawnOn(cClientHandle & a_ClientHandle) override; - virtual void Tick(float a_Dt, cChunk & a_Chunk) override; + virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; + void HandleRailPhysics(float a_Dt, cChunk & a_Chunk); + virtual void DoTakeDamage(TakeDamageInfo & TDI) override; + ePayload GetPayload(void) const { return m_Payload; } diff --git a/source/Mobs/Monster.cpp b/source/Mobs/Monster.cpp index 9ae91f1e0..a42ae30ee 100644 --- a/source/Mobs/Monster.cpp +++ b/source/Mobs/Monster.cpp @@ -15,6 +15,7 @@ #include "../Vector3i.h" #include "../Vector3d.h" #include "../Tracer.h" +#include "../Chunk.h" // #include "../../iniFile/iniFile.h" @@ -25,6 +26,8 @@ cMonster::cMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) : super(etMob, a_Width, a_Height) , m_Target(NULL) + , m_AttackRate(3) + , idle_interval(0) , m_bMovingToDestination(false) , m_DestinationTime( 0 ) , m_DestroyTimer( 0 ) @@ -39,8 +42,7 @@ cMonster::cMonster(const AString & a_ConfigName, char a_ProtocolMobType, const A , m_AttackDamage(1.0f) , m_AttackRange(5.0f) , m_AttackInterval(0) - , m_AttackRate(3) - , idle_interval(0) + , m_BurnsInDaylight(false) { if (!a_ConfigName.empty()) { @@ -100,6 +102,9 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk) return; } + // Burning in daylight + HandleDaylightBurning(a_Chunk); + HandlePhysics(a_Dt,a_Chunk); BroadcastMovementUpdate(); @@ -473,3 +478,35 @@ void cMonster::AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned + +void cMonster::HandleDaylightBurning(cChunk & a_Chunk) +{ + if (!m_BurnsInDaylight) + { + return; + } + + int RelY = (int)floor(GetPosY()); + if ((RelY < 0) || (RelY >= cChunkDef::Height)) + { + // Outside the world + return; + } + + int RelX = (int)floor(GetPosX()) - a_Chunk.GetPosX() * cChunkDef::Width; + int RelZ = (int)floor(GetPosZ()) - a_Chunk.GetPosZ() * cChunkDef::Width; + if ( + (a_Chunk.GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight + (a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand + (GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime + !IsOnFire() // Not already burning + ) + { + // Burn for 100 ticks, then decide again + StartBurning(100); + } +} + + + + diff --git a/source/Mobs/Monster.h b/source/Mobs/Monster.h index 755678d39..5f33d4450 100644 --- a/source/Mobs/Monster.h +++ b/source/Mobs/Monster.h @@ -107,6 +107,9 @@ public: void SetAttackDamage(float ad); void SetSightDistance(float sd); + /// Sets whether the mob burns in daylight. Only evaluated at next burn-decision tick + void SetBurnsInDaylight(bool a_BurnsInDaylight) { a_BurnsInDaylight = a_BurnsInDaylight; } + enum MState{ATTACKING, IDLE, CHASING, ESCAPING} m_EMState; enum MPersonality{PASSIVE,AGGRESSIVE,COWARDLY} m_EMPersonality; @@ -134,8 +137,12 @@ protected: float m_AttackDamage; float m_AttackRange; float m_AttackInterval; + + bool m_BurnsInDaylight; void AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth = 0); + + void HandleDaylightBurning(cChunk & a_Chunk); } ; // tolua_export diff --git a/source/Mobs/Skeleton.cpp b/source/Mobs/Skeleton.cpp index bec912afa..10dad4065 100644 --- a/source/Mobs/Skeleton.cpp +++ b/source/Mobs/Skeleton.cpp @@ -11,23 +11,7 @@ cSkeleton::cSkeleton(void) : super("Skeleton", 51, "mob.skeleton.hurt", "mob.skeleton.death", 0.6, 1.8) { -} - - - - - -void cSkeleton::Tick(float a_Dt, cChunk & a_Chunk) -{ - cMonster::Tick(a_Dt, a_Chunk); - - // TODO Outsource - // TODO should do SkyLight check, mobs in the dark don´t burn - if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && !IsOnFire()) - { - // Burn for 10 ticks, then decide again - StartBurning(10); - } + SetBurnsInDaylight(true); } diff --git a/source/Mobs/Skeleton.h b/source/Mobs/Skeleton.h index bc541bac2..d0a2da490 100644 --- a/source/Mobs/Skeleton.h +++ b/source/Mobs/Skeleton.h @@ -17,7 +17,6 @@ public: CLASS_PROTODEF(cSkeleton); - virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; } ; diff --git a/source/Mobs/Zombie.cpp b/source/Mobs/Zombie.cpp index a6e39d6df..9b238baef 100644 --- a/source/Mobs/Zombie.cpp +++ b/source/Mobs/Zombie.cpp @@ -3,7 +3,7 @@ #include "Zombie.h" #include "../World.h" - +#include "../LineBlockTracer.h" @@ -11,22 +11,7 @@ cZombie::cZombie(void) : super("Zombie", 54, "mob.zombie.hurt", "mob.zombie.death", 0.6, 1.8) { -} - - - - - -void cZombie::Tick(float a_Dt, cChunk & a_Chunk) -{ - super::Tick(a_Dt, a_Chunk); - - // TODO Same as in cSkeleton :D - if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && !IsOnFire()) - { - // Burn for 10 ticks, then decide again - StartBurning(10); - } + SetBurnsInDaylight(true); } diff --git a/source/Mobs/Zombie.h b/source/Mobs/Zombie.h index 61f8e3bb8..4835a53c4 100644 --- a/source/Mobs/Zombie.h +++ b/source/Mobs/Zombie.h @@ -12,11 +12,10 @@ class cZombie : typedef cAggressiveMonster super; public: - cZombie(); + cZombie(void); CLASS_PROTODEF(cZombie); - virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; } ; diff --git a/source/OSSupport/Event.cpp b/source/OSSupport/Event.cpp index 32f780946..cbacbba17 100644 --- a/source/OSSupport/Event.cpp +++ b/source/OSSupport/Event.cpp @@ -116,50 +116,3 @@ void cEvent::Set(void) - -cEvent::eWaitResult cEvent::Wait(int a_TimeoutMilliSec) -{ - #ifdef _WIN32 - DWORD res = WaitForSingleObject(m_Event, (DWORD)a_TimeoutMilliSec); - switch (res) - { - case WAIT_OBJECT_0: - { - // The semaphore was signalled - return wrSignalled; - } - case WAIT_TIMEOUT: - { - // The timeout was hit - return wrTimeout; - } - default: - { - LOGWARNING("cEvent: timed-waiting for the event failed: %d, GLE = %d. Continuing, but server may be unstable.", res, GetLastError()); - return wrError; - } - } - #else - timespec timeout; - timeout.tv_sec = time(NULL) + a_TimeoutMilliSec / 1000; - timeout.tv_nsec = (a_TimeoutMilliSec % 1000) * 1000000; - int res = sem_timedwait(m_Event, &timeout); - if (res == 0) - { - // The semaphore was signalled - return wrSignalled; - } - int err = errno; - if (err == ETIMEDOUT) - { - // The timeout was hit - return wrTimeout; - } - LOGWARNING("cEvent: timed-waiting for the event failed: %i, errno = %i. Continuing, but server may be unstable.", res, err); - return wrError; - #endif -} - - - - diff --git a/source/OSSupport/Event.h b/source/OSSupport/Event.h index 803d73b7e..71f418c0c 100644 --- a/source/OSSupport/Event.h +++ b/source/OSSupport/Event.h @@ -19,22 +19,12 @@ class cEvent { public: - enum eWaitResult - { - wrSignalled, - wrTimeout, - wrError, - } ; - cEvent(void); ~cEvent(); void Wait(void); void Set (void); - /// Waits for the semaphore with a timeout - eWaitResult Wait(int a_TimeoutMilliSec); - private: #ifdef _WIN32 diff --git a/source/Protocol/Protocol.h b/source/Protocol/Protocol.h index 0953071b1..5071f5961 100644 --- a/source/Protocol/Protocol.h +++ b/source/Protocol/Protocol.h @@ -89,7 +89,7 @@ public: virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) = 0; virtual void SendSpawnMob (const cMonster & a_Mob) = 0; virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) = 0; - virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType) = 0; + virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) = 0; virtual void SendTabCompletionResults(const AStringVector & a_Results) = 0; virtual void SendTeleportEntity (const cEntity & a_Entity) = 0; virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0; diff --git a/source/Protocol/Protocol125.cpp b/source/Protocol/Protocol125.cpp index c4c15819d..4577e0c16 100644 --- a/source/Protocol/Protocol125.cpp +++ b/source/Protocol/Protocol125.cpp @@ -747,7 +747,7 @@ void cProtocol125::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, -void cProtocol125::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType) +void cProtocol125::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) { cCSLock Lock(m_CSPacket); WriteByte (PACKET_SPAWN_OBJECT); @@ -758,10 +758,13 @@ void cProtocol125::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp WriteInt ((int)(a_Vehicle.GetPosZ() * 32)); WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256)); WriteByte ((Byte)((a_Vehicle.GetRotation() / 360.f) * 256)); - WriteInt (1); - WriteShort((short)(a_Vehicle.GetSpeedX() * 400)); - WriteShort((short)(a_Vehicle.GetSpeedY() * 400)); - WriteShort((short)(a_Vehicle.GetSpeedZ() * 400)); + WriteInt (a_VehicleSubType); + if (a_VehicleSubType != 0) + { + WriteShort((short)(a_Vehicle.GetSpeedX() * 400)); + WriteShort((short)(a_Vehicle.GetSpeedY() * 400)); + WriteShort((short)(a_Vehicle.GetSpeedZ() * 400)); + } Flush(); } diff --git a/source/Protocol/Protocol125.h b/source/Protocol/Protocol125.h index ec6e12a0d..c5c8cd1a0 100644 --- a/source/Protocol/Protocol125.h +++ b/source/Protocol/Protocol125.h @@ -66,7 +66,7 @@ public: virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; virtual void SendSpawnMob (const cMonster & a_Mob) override; virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override; - virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType) override; + virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override; virtual void SendTabCompletionResults(const AStringVector & a_Results) override; virtual void SendTeleportEntity (const cEntity & a_Entity) override; virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; diff --git a/source/Protocol/Protocol14x.cpp b/source/Protocol/Protocol14x.cpp index 881a55717..ba9d7c01a 100644 --- a/source/Protocol/Protocol14x.cpp +++ b/source/Protocol/Protocol14x.cpp @@ -229,21 +229,24 @@ void cProtocol146::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, -void cProtocol146::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType) +void cProtocol146::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) { cCSLock Lock(m_CSPacket); - WriteByte(PACKET_SPAWN_OBJECT); - WriteInt (a_Vehicle.GetUniqueID()); - WriteByte(a_VehicleType); - WriteInt ((int)(a_Vehicle.GetPosX() * 32)); - WriteInt ((int)(a_Vehicle.GetPosY() * 32)); - WriteInt ((int)(a_Vehicle.GetPosZ() * 32)); + WriteByte (PACKET_SPAWN_OBJECT); + WriteInt (a_Vehicle.GetUniqueID()); + WriteByte (a_VehicleType); + WriteInt ((int)(a_Vehicle.GetPosX() * 32)); + WriteInt ((int)(a_Vehicle.GetPosY() * 32)); + WriteInt ((int)(a_Vehicle.GetPosZ() * 32)); WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256)); WriteByte ((Byte)((a_Vehicle.GetRotation() / 360.f) * 256)); - WriteInt (1); - WriteShort((short)(a_Vehicle.GetSpeedX() * 400)); - WriteShort((short)(a_Vehicle.GetSpeedY() * 400)); - WriteShort((short)(a_Vehicle.GetSpeedZ() * 400)); + WriteInt (a_VehicleSubType); + if (a_VehicleSubType != 0) + { + WriteShort((short)(a_Vehicle.GetSpeedX() * 400)); + WriteShort((short)(a_Vehicle.GetSpeedY() * 400)); + WriteShort((short)(a_Vehicle.GetSpeedZ() * 400)); + } Flush(); } diff --git a/source/Protocol/Protocol14x.h b/source/Protocol/Protocol14x.h index c3193a3e7..ca497bbc1 100644 --- a/source/Protocol/Protocol14x.h +++ b/source/Protocol/Protocol14x.h @@ -55,7 +55,7 @@ public: virtual void SendPickupSpawn (const cPickup & a_Pickup) override; virtual void SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) override; virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override; - virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType) override; + virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override; } ; diff --git a/source/Protocol/Protocol16x.cpp b/source/Protocol/Protocol16x.cpp index 3a640da21..be5b45f19 100644 --- a/source/Protocol/Protocol16x.cpp +++ b/source/Protocol/Protocol16x.cpp @@ -213,6 +213,10 @@ int cProtocol161::ParseSteerVehicle(void) { m_Client->HandleUnmount(); } + else + { + m_Client->HandleSteerVehicle(Forward, Sideways); + } return PARSE_OK; } diff --git a/source/Protocol/ProtocolRecognizer.cpp b/source/Protocol/ProtocolRecognizer.cpp index ef2ed91f6..853018329 100644 --- a/source/Protocol/ProtocolRecognizer.cpp +++ b/source/Protocol/ProtocolRecognizer.cpp @@ -502,10 +502,10 @@ void cProtocolRecognizer::SendSpawnObject(const cEntity & a_Entity, char a_Objec -void cProtocolRecognizer::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType) +void cProtocolRecognizer::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) { ASSERT(m_Protocol != NULL); - m_Protocol->SendSpawnVehicle(a_Vehicle, a_VehicleType); + m_Protocol->SendSpawnVehicle(a_Vehicle, a_VehicleType, a_VehicleSubType); } diff --git a/source/Protocol/ProtocolRecognizer.h b/source/Protocol/ProtocolRecognizer.h index 94bbb184f..2178d5e61 100644 --- a/source/Protocol/ProtocolRecognizer.h +++ b/source/Protocol/ProtocolRecognizer.h @@ -96,7 +96,7 @@ public: virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; virtual void SendSpawnMob (const cMonster & a_Mob) override; virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override; - virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType) override; + virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override; virtual void SendTabCompletionResults(const AStringVector & a_Results) override; virtual void SendTeleportEntity (const cEntity & a_Entity) override; virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; diff --git a/source/World.h b/source/World.h index 1f475a4ac..315904f79 100644 --- a/source/World.h +++ b/source/World.h @@ -1,728 +1,728 @@ - -#pragma once - -#ifndef _WIN32 - #include "BlockID.h" -#else - enum ENUM_ITEM_ID; -#endif - -#define MAX_PLAYERS 65535 - -#include "Simulator/SimulatorManager.h" -#include "MersenneTwister.h" -#include "ChunkMap.h" -#include "WorldStorage/WorldStorage.h" -#include "Generating/ChunkGenerator.h" -#include "Vector3i.h" -#include "Vector3f.h" -#include "ChunkSender.h" -#include "Defines.h" -#include "LightingThread.h" -#include "Item.h" -#include "Mobs/Monster.h" -#include "Entities/ProjectileEntity.h" - - - - - -class cRedstone; -class cFireSimulator; -class cFluidSimulator; -class cSandSimulator; -class cRedstoneSimulator; -class cItem; -class cPlayer; -class cClientHandle; -class cEntity; -class cBlockEntity; -class cWorldGenerator; // The generator that actually generates the chunks for a single world -class cChunkGenerator; // The thread responsible for generating chunks -class cChestEntity; -class cDispenserEntity; -class cFurnaceEntity; - -typedef std::list< cPlayer * > cPlayerList; - -typedef cItemCallback<cPlayer> cPlayerListCallback; -typedef cItemCallback<cEntity> cEntityCallback; -typedef cItemCallback<cChestEntity> cChestCallback; -typedef cItemCallback<cDispenserEntity> cDispenserCallback; -typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; - - - - - - -// tolua_begin -class cWorld -{ -public: - - // tolua_end - - /// A simple RAII locker for the chunkmap - locks the chunkmap in its constructor, unlocks it in the destructor - class cLock : - public cCSLock - { - typedef cCSLock super; - public: - cLock(cWorld & a_World); - } ; - - /// A common ancestor for all tasks queued onto the tick thread - class cTask - { - public: - virtual void Run(cWorld & a_World) = 0; - } ; - - typedef std::vector<cTask *> cTasks; - - class cTaskSaveAllChunks : - public cTask - { - protected: - // cTask overrides: - virtual void Run(cWorld & a_World) override; - } ; - - - // tolua_begin - - static const char * GetClassStatic(void) - { - return "cWorld"; - } - - /// Return time in seconds - inline static float GetTime(void) - { - LOGWARNING("cWorld:GetTime() is obsolete, use GetWorldAge() or GetTimeOfDay() for a specific world instead."); - return 0; - } - - int GetTicksUntilWeatherChange(void) const { return m_WeatherInterval; } - Int64 GetWorldAge(void) const { return m_WorldAge; } - Int64 GetTimeOfDay(void) const { return m_TimeOfDay; } - - void SetTicksUntilWeatherChange(int a_WeatherInterval) - { - m_WeatherInterval = a_WeatherInterval; - } - - void SetTimeOfDay(Int64 a_TimeOfDay) - { - m_TimeOfDay = a_TimeOfDay; - m_TimeOfDaySecs = (double)a_TimeOfDay / 20.0; - BroadcastTimeUpdate(); - } - - void SetWorldTime(Int64 a_TimeOfDay) - { - LOGWARNING("cWorld:SetWorldTime() is obsolete, use SetTimeOfDay() instead"); - SetTimeOfDay(a_TimeOfDay); - } - - /// Returns the current game mode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable - eGameMode GetGameMode(void) const { return m_GameMode; } - - /// Returns true if the world is in Creative mode - bool IsGameModeCreative(void) const { return (m_GameMode == gmCreative); } - - /// Returns true if the world is in Survival mode - bool IsGameModeSurvival(void) const { return (m_GameMode == gmSurvival); } - - /// Returns true if the world is in Adventure mode - bool IsGameModeAdventure(void) const { return (m_GameMode == gmAdventure); } - - bool IsPVPEnabled(void) const { return m_bEnabledPVP; } - bool IsDeepSnowEnabled(void) const { return m_IsDeepSnowEnabled; } - - eDimension GetDimension(void) const { return m_Dimension; } - - /// Returns the world height at the specified coords; waits for the chunk to get loaded / generated - int GetHeight(int a_BlockX, int a_BlockZ); - - // tolua_end - - /// Retrieves the world height at the specified coords; returns false if chunk not loaded / generated - bool TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height); // Exported in ManualBindings.cpp - - // Broadcast respective packets to all clients of the chunk where the event is taking place - // (Please keep these alpha-sorted) - void BroadcastAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle); - void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL); - void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = NULL); - void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); ///< If there is a block entity at the specified coods, sends it to all clients except a_Exclude - void BroadcastChat (const AString & a_Message, const cClientHandle * a_Exclude = NULL); // tolua_export - void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL); - void BroadcastCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL); - void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastPlayerAnimation (const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude = NULL); - void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL); - void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // a_Src coords are Block * 8 - void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); - void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); - void BroadcastTimeUpdate (const cClientHandle * a_Exclude = NULL); - void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ); - void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = NULL); - - /// If there is a block entity at the specified coords, sends it to the client specified - void SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client); - - void MarkChunkDirty (int a_ChunkX, int a_ChunkZ); - void MarkChunkSaving(int a_ChunkX, int a_ChunkZ); - void MarkChunkSaved (int a_ChunkX, int a_ChunkZ); - - /** Sets the chunk data as either loaded from the storage or generated. - a_BlockLight and a_BlockSkyLight are optional, if not present, chunk will be marked as unlighted. - a_BiomeMap is optional, if not present, biomes will be calculated by the generator - a_HeightMap is optional, if not present, will be calculated. - If a_MarkDirty is set, the chunk is set as dirty (used after generating) - */ - void SetChunkData( - int a_ChunkX, int a_ChunkZ, - 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, - bool a_MarkDirty - ); - - void ChunkLighted( - int a_ChunkX, int a_ChunkZ, - const cChunkDef::BlockNibbles & a_BlockLight, - const cChunkDef::BlockNibbles & a_SkyLight - ); - - bool GetChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback); - - /// Gets the chunk's blocks, only the block types - bool GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes); - - bool IsChunkValid (int a_ChunkX, int a_ChunkZ) const; - bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) const; - - void UnloadUnusedChunks(void); // tolua_export - - void CollectPickupsByPlayer(cPlayer * a_Player); - - void AddPlayer( cPlayer* a_Player ); - void RemovePlayer( cPlayer* a_Player ); - - /// Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true - bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << - - /// Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. Callback return ignored - bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << - - /// Finds a player from a partial or complete player name and calls the callback - case-insensitive - bool FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << - - // TODO: This interface is dangerous - rewrite to DoWithClosestPlayer(pos, sight, action) - cPlayer * FindClosestPlayer(const Vector3f & a_Pos, float a_SightLimit); - - void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player - - /// Adds the entity into its appropriate chunk; takes ownership of the entity ptr - void AddEntity(cEntity * a_Entity); - - bool HasEntity(int a_UniqueID); - - /// Removes the entity, the entity ptr ownership is assumed taken by the caller - void RemoveEntity(cEntity * a_Entity); - - /// Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true - bool ForEachEntity(cEntityCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true - bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. - bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Compares clients of two chunks, calls the callback accordingly - void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback); - - /// Adds client to a chunk, if not already present; returns true if added, false if present - bool AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); - - /// Removes client from the chunk specified - void RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); - - /// Removes the client from all chunks it is present in - void RemoveClientFromChunks(cClientHandle * a_Client); - - /// Sends the chunk to the client specified, if the chunk is valid. If not valid, the request is postponed (ChunkSender will send that chunk when it becomes valid+lighted) - void SendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); - - /// Removes client from ChunkSender's queue of chunks to be sent - void RemoveClientFromChunkSender(cClientHandle * a_Client); - - /// Touches the chunk, causing it to be loaded or generated - void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - - /// Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) - bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - - /// Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid() - void LoadChunks(const cChunkCoordsList & a_Chunks); - - /// Marks the chunk as failed-to-load: - void ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - - /// Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as UpdateSign() - bool SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp - - /// Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as SetSignLines() - bool UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp - - /// Marks (a_Stay == true) or unmarks (a_Stay == false) chunks as non-unloadable. To be used only by cChunkStay! - void ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay = true); - - /// Regenerate the given chunk: - void RegenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export - - /// Generates the given chunk, if not already generated - void GenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export - - /// Queues a chunk for lighting; a_Callback is called after the chunk is lighted - void QueueLightChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback = NULL); - - bool IsChunkLighted(int a_ChunkX, int a_ChunkZ); - - /// Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully - bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback); - - // tolua_begin - - /** Sets the block at the specified coords to the specified value. - Full processing, incl. updating neighbors, is performed. - */ - void SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); - - /** Sets the block at the specified coords to the specified value. - The replacement doesn't trigger block updates. - The replaced blocks aren't checked for block entities (block entity is leaked if it exists at this block) - */ - void FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); - - /** Queues a SetBlock() with the specified parameters after the specified number of ticks. - Calls SetBlock(), so performs full processing of the replaced block. - */ - void QueueSetBlock(int a_BlockX, int a_BLockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_TickDelay); - - BLOCKTYPE GetBlock (int a_BlockX, int a_BlockY, int a_BlockZ); - NIBBLETYPE GetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ); - void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData); - NIBBLETYPE GetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ); - NIBBLETYPE GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ); - bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); - bool GetBlockInfo (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight); - // TODO: NIBBLETYPE GetBlockActualLight(int a_BlockX, int a_BlockY, int a_BlockZ); - - // Vector3i variants: - void FastSetBlock(const Vector3i & a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ) { FastSetBlock( a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta ); } - BLOCKTYPE GetBlock (const Vector3i & a_Pos ) { return GetBlock( a_Pos.x, a_Pos.y, a_Pos.z ); } - NIBBLETYPE GetBlockMeta(const Vector3i & a_Pos ) { return GetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z ); } - void SetBlockMeta(const Vector3i & a_Pos, NIBBLETYPE a_MetaData ) { SetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z, a_MetaData ); } - // tolua_end - - /** Writes the block area into the specified coords. - Returns true if all chunks have been processed. - Prefer cBlockArea::Write() instead, this is the internal implementation; cBlockArea does error checking, too. - a_DataTypes is a bitmask of cBlockArea::baXXX constants ORed together. - */ - bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes); - - // tolua_begin - - /// Spawns item pickups for each item in the list. May compress pickups if too many entities: - void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0); - - /// Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified: - void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ); - - /// Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided - void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff = 1); - - // tolua_end - - /// Replaces world blocks with a_Blocks, if they are of type a_FilterBlockType - void ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType); - - /// Retrieves block types of the specified blocks. If a chunk is not loaded, doesn't modify the block. Returns true if all blocks were read. - bool GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure); - - // tolua_begin - bool DigBlock (int a_X, int a_Y, int a_Z); - void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player ); - - double GetSpawnX(void) const { return m_SpawnX; } - double GetSpawnY(void) const { return m_SpawnY; } - double GetSpawnZ(void) const { return m_SpawnZ; } - - /// Wakes up the simulators for the specified block - void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ); - - /// Wakes up the simulators for the specified area of blocks - void WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ); - - // tolua_end - - inline cSimulatorManager * GetSimulatorManager(void) { return m_SimulatorManager; } - - inline cFluidSimulator * GetWaterSimulator(void) { return m_WaterSimulator; } - inline cFluidSimulator * GetLavaSimulator (void) { return m_LavaSimulator; } - - /// Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true - bool ForEachChestInChunk (int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true - bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback); - - /// Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true - bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback); - - /// Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true - bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback); - - /// Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true - bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp - - /** Does an explosion with the specified strength at the specified coordinate - a_SourceData exact type depends on the a_Source: - | esOther | void * | - | esPrimedTNT | cTNTEntity * | - | esCreeper | cCreeper * | - | esBed | cVector3i * | - | esEnderCrystal | Vector3i * | - | esGhastFireball | cGhastFireballEntity * | - | esWitherSkullBlack | TBD | - | esWitherSkullBlue | TBD | - | esWitherBirth | TBD | - | esPlugin | void * | - */ - void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export - - /// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found - bool DoWithChestAt (int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found - bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found - bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found - bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found - bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found - bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // tolua_export - - /// a_Player is using block entity at [x, y, z], handle that: - void UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) {m_ChunkMap->UseBlockEntity(a_Player, a_BlockX, a_BlockY, a_BlockZ); } - - /// Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback - bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback); - - void GrowTree (int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export - void GrowTreeFromSapling(int a_BlockX, int a_BlockY, int a_BlockZ, char a_SaplingMeta); // tolua_export - void GrowTreeByBiome (int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export - - void GrowTreeImage(const sSetBlockVector & a_Blocks); - - // tolua_begin - - /// Grows the plant at the specified block to its ripe stage (bonemeal used); returns false if the block is not growable. If a_IsBonemeal is true, block is not grown if not allowed in world.ini - bool GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsByBonemeal = false); - - /// Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config - void GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow); - - /// Grows a melon or a pumpkin next to the block specified (assumed to be the stem) - void GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockType); - - /// Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config - void GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow); - - /// Returns the biome at the specified coords. Reads the biome from the chunk, if loaded, otherwise uses the world generator to provide the biome value - int GetBiomeAt(int a_BlockX, int a_BlockZ); - - /// Returns the name of the world - const AString & GetName(void) const { return m_WorldName; } - - /// Returns the name of the world.ini file used by this world - const AString & GetIniFileName(void) const {return m_IniFileName; } - - // tolua_end - - inline static void AbsoluteToRelative( int & a_X, int & a_Y, int & a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ ) - { - // TODO: Use floor() instead of weird if statements - // Also fix Y - a_ChunkX = a_X/cChunkDef::Width; - if(a_X < 0 && a_X % cChunkDef::Width != 0) a_ChunkX--; - a_ChunkY = 0; - a_ChunkZ = a_Z/cChunkDef::Width; - if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--; - - a_X = a_X - a_ChunkX*cChunkDef::Width; - a_Y = a_Y - a_ChunkY*cChunkDef::Height; - a_Z = a_Z - a_ChunkZ*cChunkDef::Width; - } - - inline static void BlockToChunk( int a_X, int a_Y, int a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ ) - { - // TODO: Use floor() instead of weird if statements - // Also fix Y - (void)a_Y; // not unused anymore - a_ChunkX = a_X/cChunkDef::Width; - if(a_X < 0 && a_X % cChunkDef::Width != 0) a_ChunkX--; - a_ChunkY = 0; - a_ChunkZ = a_Z/cChunkDef::Width; - if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--; - } - - /// Saves all chunks immediately. Dangerous interface, may deadlock, use QueueSaveAllChunks() instead - void SaveAllChunks(void); // tolua_export - - /// Queues a task to save all chunks onto the tick thread. The prefferred way of saving chunks from external sources - void QueueSaveAllChunks(void); // tolua_export - - /// Queues a task onto the tick thread. The task object will be deleted once the task is finished - void QueueTask(cTask * a_Task); - - /// Returns the number of chunks loaded - int GetNumChunks() const; // tolua_export - - /// Returns the number of chunks loaded and dirty, and in the lighting queue - void GetChunkStats(int & a_NumValid, int & a_NumDirty, int & a_NumInLightingQueue); - - // Various queues length queries (cannot be const, they lock their CS): - inline int GetGeneratorQueueLength (void) { return m_Generator.GetQueueLength(); } // tolua_export - inline int GetLightingQueueLength (void) { return m_Lighting.GetQueueLength(); } // tolua_export - inline int GetStorageLoadQueueLength(void) { return m_Storage.GetLoadQueueLength(); } // tolua_export - inline int GetStorageSaveQueueLength(void) { return m_Storage.GetSaveQueueLength(); } // tolua_export - - void InitializeSpawn(void); - - /// Starts threads that belong to this world - void Start(void); - - /// Stops threads that belong to this world (part of deinit) - void Stop(void); - - void TickQueuedBlocks(float a_Dt); - - struct BlockTickQueueItem - { - int X; - int Y; - int Z; - float ToWait; - }; - - void QueueBlockForTick(int a_BlockX, int a_BlockY, int a_BlockZ, float a_TimeToWait); // tolua_export - - // tolua_begin - /// Casts a thunderbolt at the specified coords - void CastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ); - - /// Sets the specified weather; resets weather interval; asks and notifies plugins of the change - void SetWeather (eWeather a_NewWeather); - - /// Forces a weather change in the next game tick - void ChangeWeather (void); - - /// Returns the current weather - eWeather GetWeather (void) const { return m_Weather; }; - // tolua_end - - cChunkGenerator & GetGenerator(void) { return m_Generator; } - cWorldStorage & GetStorage (void) { return m_Storage; } - cChunkMap * GetChunkMap (void) { return m_ChunkMap; } - - /// Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call - void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export - - int GetMaxSugarcaneHeight(void) const { return m_MaxSugarcaneHeight; } // tolua_export - int GetMaxCactusHeight (void) const { return m_MaxCactusHeight; } // tolua_export - - bool IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export - - /// Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise - int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export - - /// Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise - int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed = NULL); // tolua_export - - /// Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! - int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); } - - /// Appends all usernames starting with a_Text (case-insensitive) into Results - void TabCompleteUserName(const AString & a_Text, AStringVector & a_Results); - -private: - - friend class cRoot; - - class cTickThread : - public cIsThread - { - typedef cIsThread super; - public: - cTickThread(cWorld & a_World); - - protected: - cWorld & m_World; - - // cIsThread overrides: - virtual void Execute(void) override; - } ; - - - AString m_WorldName; - AString m_IniFileName; - - /// Name of the storage schema used to load and save chunks - AString m_StorageSchema; - - /// The dimension of the world, used by the client to provide correct lighting scheme - eDimension m_Dimension; - - /// This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe) - MTRand m_TickRand; - - double m_SpawnX; - double m_SpawnY; - double m_SpawnZ; - - double m_WorldAgeSecs; // World age, in seconds. Is only incremented, cannot be set by plugins. - double m_TimeOfDaySecs; // Time of day in seconds. Can be adjusted. Is wrapped to zero each day. - Int64 m_WorldAge; // World age in ticks, calculated off of m_WorldAgeSecs - Int64 m_TimeOfDay; // Time in ticks, calculated off of m_TimeOfDaySecs - Int64 m_LastTimeUpdate; // The tick in which the last time update has been sent. - Int64 m_LastUnload; // The last WorldAge (in ticks) in which unloading was triggerred - Int64 m_LastSave; // The last WorldAge (in ticks) in which save-all was triggerred - Int64 m_LastSpawnMonster; // The last WorldAge (in ticks) in which a monster was spawned - - eGameMode m_GameMode; - bool m_bEnabledPVP; - bool m_IsDeepSnowEnabled; - - // The cRedstone class simulates redstone and needs access to m_RSList - // friend class cRedstone; - std::vector<int> m_RSList; - - std::vector<BlockTickQueueItem *> m_BlockTickQueue; - std::vector<BlockTickQueueItem *> m_BlockTickQueueCopy; //Second is for safely removing the objects from the queue - - cSimulatorManager * m_SimulatorManager; - cSandSimulator * m_SandSimulator; - cFluidSimulator * m_WaterSimulator; - cFluidSimulator * m_LavaSimulator; - cFireSimulator * m_FireSimulator; - cRedstoneSimulator * m_RedstoneSimulator; - - cCriticalSection m_CSPlayers; - cPlayerList m_Players; - - cWorldStorage m_Storage; - - unsigned int m_MaxPlayers; - - cChunkMap * m_ChunkMap; - - bool m_bAnimals; - Int64 m_SpawnMonsterRate; - - eWeather m_Weather; - int m_WeatherInterval; - - int m_MaxCactusHeight; - int m_MaxSugarcaneHeight; - bool m_IsCactusBonemealable; - bool m_IsCarrotsBonemealable; - bool m_IsCropsBonemealable; - bool m_IsGrassBonemealable; - bool m_IsMelonStemBonemealable; - bool m_IsMelonBonemealable; - bool m_IsPotatoesBonemealable; - bool m_IsPumpkinStemBonemealable; - bool m_IsPumpkinBonemealable; - bool m_IsSaplingBonemealable; - bool m_IsSugarcaneBonemealable; - - cCriticalSection m_CSFastSetBlock; - sSetBlockList m_FastSetBlockQueue; - - cChunkGenerator m_Generator; - - cChunkSender m_ChunkSender; - cLightingThread m_Lighting; - cTickThread m_TickThread; - - /// Guards the m_Tasks - cCriticalSection m_CSTasks; - - /// Tasks that have been queued onto the tick thread; guarded by m_CSTasks - cTasks m_Tasks; - - /// Guards m_Clients - cCriticalSection m_CSClients; - - /// List of clients in this world, these will be ticked by this world - cClientHandleList m_Clients; - - /// Clients that are scheduled for removal (ticked in another world), waiting for TickClients() to remove them - cClientHandleList m_ClientsToRemove; - - /// Clients that are scheduled for adding, waiting for TickClients to add them - cClientHandleList m_ClientsToAdd; - - - cWorld(const AString & a_WorldName); - ~cWorld(); - - void Tick(float a_Dt); - - /// Handles the weather in each tick - void TickWeather(float a_Dt); - - /// Handles the mob spawning each tick - void TickSpawnMobs(float a_Dt); - - /// Executes all tasks queued onto the tick thread - void TickQueuedTasks(void); - - /// Ticks all clients that are in this world - void TickClients(float a_Dt); - - /// Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section) - cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock); -}; // tolua_export - - - - +
+#pragma once
+
+#ifndef _WIN32
+ #include "BlockID.h"
+#else
+ enum ENUM_ITEM_ID;
+#endif
+
+#define MAX_PLAYERS 65535
+
+#include "Simulator/SimulatorManager.h"
+#include "MersenneTwister.h"
+#include "ChunkMap.h"
+#include "WorldStorage/WorldStorage.h"
+#include "Generating/ChunkGenerator.h"
+#include "Vector3i.h"
+#include "Vector3f.h"
+#include "ChunkSender.h"
+#include "Defines.h"
+#include "LightingThread.h"
+#include "Item.h"
+#include "Mobs/Monster.h"
+#include "Entities/ProjectileEntity.h"
+
+
+
+
+
+class cRedstone;
+class cFireSimulator;
+class cFluidSimulator;
+class cSandSimulator;
+class cRedstoneSimulator;
+class cItem;
+class cPlayer;
+class cClientHandle;
+class cEntity;
+class cBlockEntity;
+class cWorldGenerator; // The generator that actually generates the chunks for a single world
+class cChunkGenerator; // The thread responsible for generating chunks
+class cChestEntity;
+class cDispenserEntity;
+class cFurnaceEntity;
+
+typedef std::list< cPlayer * > cPlayerList;
+
+typedef cItemCallback<cPlayer> cPlayerListCallback;
+typedef cItemCallback<cEntity> cEntityCallback;
+typedef cItemCallback<cChestEntity> cChestCallback;
+typedef cItemCallback<cDispenserEntity> cDispenserCallback;
+typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
+
+
+
+
+
+
+// tolua_begin
+class cWorld
+{
+public:
+
+ // tolua_end
+
+ /// A simple RAII locker for the chunkmap - locks the chunkmap in its constructor, unlocks it in the destructor
+ class cLock :
+ public cCSLock
+ {
+ typedef cCSLock super;
+ public:
+ cLock(cWorld & a_World);
+ } ;
+
+ /// A common ancestor for all tasks queued onto the tick thread
+ class cTask
+ {
+ public:
+ virtual void Run(cWorld & a_World) = 0;
+ } ;
+
+ typedef std::vector<cTask *> cTasks;
+
+ class cTaskSaveAllChunks :
+ public cTask
+ {
+ protected:
+ // cTask overrides:
+ virtual void Run(cWorld & a_World) override;
+ } ;
+
+
+ // tolua_begin
+
+ static const char * GetClassStatic(void)
+ {
+ return "cWorld";
+ }
+
+ /// Return time in seconds
+ inline static float GetTime(void)
+ {
+ LOGWARNING("cWorld:GetTime() is obsolete, use GetWorldAge() or GetTimeOfDay() for a specific world instead.");
+ return 0;
+ }
+
+ int GetTicksUntilWeatherChange(void) const { return m_WeatherInterval; }
+ Int64 GetWorldAge(void) const { return m_WorldAge; }
+ Int64 GetTimeOfDay(void) const { return m_TimeOfDay; }
+
+ void SetTicksUntilWeatherChange(int a_WeatherInterval)
+ {
+ m_WeatherInterval = a_WeatherInterval;
+ }
+
+ void SetTimeOfDay(Int64 a_TimeOfDay)
+ {
+ m_TimeOfDay = a_TimeOfDay;
+ m_TimeOfDaySecs = (double)a_TimeOfDay / 20.0;
+ BroadcastTimeUpdate();
+ }
+
+ void SetWorldTime(Int64 a_TimeOfDay)
+ {
+ LOGWARNING("cWorld:SetWorldTime() is obsolete, use SetTimeOfDay() instead");
+ SetTimeOfDay(a_TimeOfDay);
+ }
+
+ /// Returns the current game mode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable
+ eGameMode GetGameMode(void) const { return m_GameMode; }
+
+ /// Returns true if the world is in Creative mode
+ bool IsGameModeCreative(void) const { return (m_GameMode == gmCreative); }
+
+ /// Returns true if the world is in Survival mode
+ bool IsGameModeSurvival(void) const { return (m_GameMode == gmSurvival); }
+
+ /// Returns true if the world is in Adventure mode
+ bool IsGameModeAdventure(void) const { return (m_GameMode == gmAdventure); }
+
+ bool IsPVPEnabled(void) const { return m_bEnabledPVP; }
+ bool IsDeepSnowEnabled(void) const { return m_IsDeepSnowEnabled; }
+
+ eDimension GetDimension(void) const { return m_Dimension; }
+
+ /// Returns the world height at the specified coords; waits for the chunk to get loaded / generated
+ int GetHeight(int a_BlockX, int a_BlockZ);
+
+ // tolua_end
+
+ /// Retrieves the world height at the specified coords; returns false if chunk not loaded / generated
+ bool TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height); // Exported in ManualBindings.cpp
+
+ // Broadcast respective packets to all clients of the chunk where the event is taking place
+ // (Please keep these alpha-sorted)
+ void BroadcastAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle);
+ void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL);
+ void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = NULL);
+ void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); ///< If there is a block entity at the specified coods, sends it to all clients except a_Exclude
+ void BroadcastChat (const AString & a_Message, const cClientHandle * a_Exclude = NULL); // tolua_export
+ void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL);
+ void BroadcastCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL);
+ void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastPlayerAnimation (const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude = NULL);
+ void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL);
+ void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // tolua_export a_Src coords are Block * 8
+ void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); // tolua_export
+ void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL);
+ void BroadcastTimeUpdate (const cClientHandle * a_Exclude = NULL);
+ void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ );
+ void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = NULL);
+
+ /// If there is a block entity at the specified coords, sends it to the client specified
+ void SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client);
+
+ void MarkChunkDirty (int a_ChunkX, int a_ChunkZ);
+ void MarkChunkSaving(int a_ChunkX, int a_ChunkZ);
+ void MarkChunkSaved (int a_ChunkX, int a_ChunkZ);
+
+ /** Sets the chunk data as either loaded from the storage or generated.
+ a_BlockLight and a_BlockSkyLight are optional, if not present, chunk will be marked as unlighted.
+ a_BiomeMap is optional, if not present, biomes will be calculated by the generator
+ a_HeightMap is optional, if not present, will be calculated.
+ If a_MarkDirty is set, the chunk is set as dirty (used after generating)
+ */
+ void SetChunkData(
+ int a_ChunkX, int a_ChunkZ,
+ 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,
+ bool a_MarkDirty
+ );
+
+ void ChunkLighted(
+ int a_ChunkX, int a_ChunkZ,
+ const cChunkDef::BlockNibbles & a_BlockLight,
+ const cChunkDef::BlockNibbles & a_SkyLight
+ );
+
+ bool GetChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback);
+
+ /// Gets the chunk's blocks, only the block types
+ bool GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes);
+
+ bool IsChunkValid (int a_ChunkX, int a_ChunkZ) const;
+ bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) const;
+
+ void UnloadUnusedChunks(void); // tolua_export
+
+ void CollectPickupsByPlayer(cPlayer * a_Player);
+
+ void AddPlayer( cPlayer* a_Player );
+ void RemovePlayer( cPlayer* a_Player );
+
+ /// Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true
+ bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
+
+ /// Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. Callback return ignored
+ bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
+
+ /// Finds a player from a partial or complete player name and calls the callback - case-insensitive
+ bool FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
+
+ // TODO: This interface is dangerous - rewrite to DoWithClosestPlayer(pos, sight, action)
+ cPlayer * FindClosestPlayer(const Vector3f & a_Pos, float a_SightLimit);
+
+ void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player
+
+ /// Adds the entity into its appropriate chunk; takes ownership of the entity ptr
+ void AddEntity(cEntity * a_Entity);
+
+ bool HasEntity(int a_UniqueID);
+
+ /// Removes the entity, the entity ptr ownership is assumed taken by the caller
+ void RemoveEntity(cEntity * a_Entity);
+
+ /// Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true
+ bool ForEachEntity(cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true
+ bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false.
+ bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Compares clients of two chunks, calls the callback accordingly
+ void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback);
+
+ /// Adds client to a chunk, if not already present; returns true if added, false if present
+ bool AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
+
+ /// Removes client from the chunk specified
+ void RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
+
+ /// Removes the client from all chunks it is present in
+ void RemoveClientFromChunks(cClientHandle * a_Client);
+
+ /// Sends the chunk to the client specified, if the chunk is valid. If not valid, the request is postponed (ChunkSender will send that chunk when it becomes valid+lighted)
+ void SendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
+
+ /// Removes client from ChunkSender's queue of chunks to be sent
+ void RemoveClientFromChunkSender(cClientHandle * a_Client);
+
+ /// Touches the chunk, causing it to be loaded or generated
+ void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
+
+ /// Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before)
+ bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
+
+ /// Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid()
+ void LoadChunks(const cChunkCoordsList & a_Chunks);
+
+ /// Marks the chunk as failed-to-load:
+ void ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
+
+ /// Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as UpdateSign()
+ bool SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp
+
+ /// Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as SetSignLines()
+ bool UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp
+
+ /// Marks (a_Stay == true) or unmarks (a_Stay == false) chunks as non-unloadable. To be used only by cChunkStay!
+ void ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay = true);
+
+ /// Regenerate the given chunk:
+ void RegenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export
+
+ /// Generates the given chunk, if not already generated
+ void GenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export
+
+ /// Queues a chunk for lighting; a_Callback is called after the chunk is lighted
+ void QueueLightChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback = NULL);
+
+ bool IsChunkLighted(int a_ChunkX, int a_ChunkZ);
+
+ /// Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully
+ bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback);
+
+ // tolua_begin
+
+ /** Sets the block at the specified coords to the specified value.
+ Full processing, incl. updating neighbors, is performed.
+ */
+ void SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
+
+ /** Sets the block at the specified coords to the specified value.
+ The replacement doesn't trigger block updates.
+ The replaced blocks aren't checked for block entities (block entity is leaked if it exists at this block)
+ */
+ void FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
+
+ /** Queues a SetBlock() with the specified parameters after the specified number of ticks.
+ Calls SetBlock(), so performs full processing of the replaced block.
+ */
+ void QueueSetBlock(int a_BlockX, int a_BLockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_TickDelay);
+
+ BLOCKTYPE GetBlock (int a_BlockX, int a_BlockY, int a_BlockZ);
+ NIBBLETYPE GetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ);
+ void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData);
+ NIBBLETYPE GetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ);
+ NIBBLETYPE GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ);
+ bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
+ bool GetBlockInfo (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);
+ // TODO: NIBBLETYPE GetBlockActualLight(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ // Vector3i variants:
+ void FastSetBlock(const Vector3i & a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ) { FastSetBlock( a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta ); }
+ BLOCKTYPE GetBlock (const Vector3i & a_Pos ) { return GetBlock( a_Pos.x, a_Pos.y, a_Pos.z ); }
+ NIBBLETYPE GetBlockMeta(const Vector3i & a_Pos ) { return GetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z ); }
+ void SetBlockMeta(const Vector3i & a_Pos, NIBBLETYPE a_MetaData ) { SetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z, a_MetaData ); }
+ // tolua_end
+
+ /** Writes the block area into the specified coords.
+ Returns true if all chunks have been processed.
+ Prefer cBlockArea::Write() instead, this is the internal implementation; cBlockArea does error checking, too.
+ a_DataTypes is a bitmask of cBlockArea::baXXX constants ORed together.
+ */
+ bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes);
+
+ // tolua_begin
+
+ /// Spawns item pickups for each item in the list. May compress pickups if too many entities:
+ void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0);
+
+ /// Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified:
+ void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ);
+
+ /// Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided
+ void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff = 1);
+
+ // tolua_end
+
+ /// Replaces world blocks with a_Blocks, if they are of type a_FilterBlockType
+ void ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType);
+
+ /// Retrieves block types of the specified blocks. If a chunk is not loaded, doesn't modify the block. Returns true if all blocks were read.
+ bool GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure);
+
+ // tolua_begin
+ bool DigBlock (int a_X, int a_Y, int a_Z);
+ void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player );
+
+ double GetSpawnX(void) const { return m_SpawnX; }
+ double GetSpawnY(void) const { return m_SpawnY; }
+ double GetSpawnZ(void) const { return m_SpawnZ; }
+
+ /// Wakes up the simulators for the specified block
+ void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ /// Wakes up the simulators for the specified area of blocks
+ void WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ);
+
+ // tolua_end
+
+ inline cSimulatorManager * GetSimulatorManager(void) { return m_SimulatorManager; }
+
+ inline cFluidSimulator * GetWaterSimulator(void) { return m_WaterSimulator; }
+ inline cFluidSimulator * GetLavaSimulator (void) { return m_LavaSimulator; }
+
+ /// Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true
+ bool ForEachChestInChunk (int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true
+ bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback);
+
+ /// Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true
+ bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback);
+
+ /// Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true
+ bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback);
+
+ /// Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true
+ bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /** Does an explosion with the specified strength at the specified coordinate
+ a_SourceData exact type depends on the a_Source:
+ | esOther | void * |
+ | esPrimedTNT | cTNTEntity * |
+ | esCreeper | cCreeper * |
+ | esBed | cVector3i * |
+ | esEnderCrystal | Vector3i * |
+ | esGhastFireball | cGhastFireball * |
+ | esWitherSkullBlack | TBD |
+ | esWitherSkullBlue | TBD |
+ | esWitherBirth | TBD |
+ | esPlugin | void * |
+ */
+ void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export
+
+ /// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found
+ bool DoWithChestAt (int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found
+ bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found
+ bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found
+ bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found
+ bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found
+ bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // tolua_export
+
+ /// a_Player is using block entity at [x, y, z], handle that:
+ void UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) {m_ChunkMap->UseBlockEntity(a_Player, a_BlockX, a_BlockY, a_BlockZ); }
+
+ /// Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback
+ bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback);
+
+ void GrowTree (int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
+ void GrowTreeFromSapling(int a_BlockX, int a_BlockY, int a_BlockZ, char a_SaplingMeta); // tolua_export
+ void GrowTreeByBiome (int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
+
+ void GrowTreeImage(const sSetBlockVector & a_Blocks);
+
+ // tolua_begin
+
+ /// Grows the plant at the specified block to its ripe stage (bonemeal used); returns false if the block is not growable. If a_IsBonemeal is true, block is not grown if not allowed in world.ini
+ bool GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsByBonemeal = false);
+
+ /// Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config
+ void GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow);
+
+ /// Grows a melon or a pumpkin next to the block specified (assumed to be the stem)
+ void GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockType);
+
+ /// Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config
+ void GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow);
+
+ /// Returns the biome at the specified coords. Reads the biome from the chunk, if loaded, otherwise uses the world generator to provide the biome value
+ int GetBiomeAt(int a_BlockX, int a_BlockZ);
+
+ /// Returns the name of the world
+ const AString & GetName(void) const { return m_WorldName; }
+
+ /// Returns the name of the world.ini file used by this world
+ const AString & GetIniFileName(void) const {return m_IniFileName; }
+
+ // tolua_end
+
+ inline static void AbsoluteToRelative( int & a_X, int & a_Y, int & a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ )
+ {
+ // TODO: Use floor() instead of weird if statements
+ // Also fix Y
+ a_ChunkX = a_X/cChunkDef::Width;
+ if(a_X < 0 && a_X % cChunkDef::Width != 0) a_ChunkX--;
+ a_ChunkY = 0;
+ a_ChunkZ = a_Z/cChunkDef::Width;
+ if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--;
+
+ a_X = a_X - a_ChunkX*cChunkDef::Width;
+ a_Y = a_Y - a_ChunkY*cChunkDef::Height;
+ a_Z = a_Z - a_ChunkZ*cChunkDef::Width;
+ }
+
+ inline static void BlockToChunk( int a_X, int a_Y, int a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ )
+ {
+ // TODO: Use floor() instead of weird if statements
+ // Also fix Y
+ (void)a_Y; // not unused anymore
+ a_ChunkX = a_X/cChunkDef::Width;
+ if(a_X < 0 && a_X % cChunkDef::Width != 0) a_ChunkX--;
+ a_ChunkY = 0;
+ a_ChunkZ = a_Z/cChunkDef::Width;
+ if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--;
+ }
+
+ /// Saves all chunks immediately. Dangerous interface, may deadlock, use QueueSaveAllChunks() instead
+ void SaveAllChunks(void); // tolua_export
+
+ /// Queues a task to save all chunks onto the tick thread. The prefferred way of saving chunks from external sources
+ void QueueSaveAllChunks(void); // tolua_export
+
+ /// Queues a task onto the tick thread. The task object will be deleted once the task is finished
+ void QueueTask(cTask * a_Task);
+
+ /// Returns the number of chunks loaded
+ int GetNumChunks() const; // tolua_export
+
+ /// Returns the number of chunks loaded and dirty, and in the lighting queue
+ void GetChunkStats(int & a_NumValid, int & a_NumDirty, int & a_NumInLightingQueue);
+
+ // Various queues length queries (cannot be const, they lock their CS):
+ inline int GetGeneratorQueueLength (void) { return m_Generator.GetQueueLength(); } // tolua_export
+ inline int GetLightingQueueLength (void) { return m_Lighting.GetQueueLength(); } // tolua_export
+ inline int GetStorageLoadQueueLength(void) { return m_Storage.GetLoadQueueLength(); } // tolua_export
+ inline int GetStorageSaveQueueLength(void) { return m_Storage.GetSaveQueueLength(); } // tolua_export
+
+ void InitializeSpawn(void);
+
+ /// Starts threads that belong to this world
+ void Start(void);
+
+ /// Stops threads that belong to this world (part of deinit)
+ void Stop(void);
+
+ void TickQueuedBlocks(float a_Dt);
+
+ struct BlockTickQueueItem
+ {
+ int X;
+ int Y;
+ int Z;
+ float ToWait;
+ };
+
+ void QueueBlockForTick(int a_BlockX, int a_BlockY, int a_BlockZ, float a_TimeToWait); // tolua_export
+
+ // tolua_begin
+ /// Casts a thunderbolt at the specified coords
+ void CastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ /// Sets the specified weather; resets weather interval; asks and notifies plugins of the change
+ void SetWeather (eWeather a_NewWeather);
+
+ /// Forces a weather change in the next game tick
+ void ChangeWeather (void);
+
+ /// Returns the current weather
+ eWeather GetWeather (void) const { return m_Weather; };
+ // tolua_end
+
+ cChunkGenerator & GetGenerator(void) { return m_Generator; }
+ cWorldStorage & GetStorage (void) { return m_Storage; }
+ cChunkMap * GetChunkMap (void) { return m_ChunkMap; }
+
+ /// Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call
+ void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
+
+ int GetMaxSugarcaneHeight(void) const { return m_MaxSugarcaneHeight; } // tolua_export
+ int GetMaxCactusHeight (void) const { return m_MaxCactusHeight; } // tolua_export
+
+ bool IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
+
+ /// Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise
+ int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export
+
+ /// Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise
+ int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed = NULL); // tolua_export
+
+ /// Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread!
+ int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); }
+
+ /// Appends all usernames starting with a_Text (case-insensitive) into Results
+ void TabCompleteUserName(const AString & a_Text, AStringVector & a_Results);
+
+private:
+
+ friend class cRoot;
+
+ class cTickThread :
+ public cIsThread
+ {
+ typedef cIsThread super;
+ public:
+ cTickThread(cWorld & a_World);
+
+ protected:
+ cWorld & m_World;
+
+ // cIsThread overrides:
+ virtual void Execute(void) override;
+ } ;
+
+
+ AString m_WorldName;
+ AString m_IniFileName;
+
+ /// Name of the storage schema used to load and save chunks
+ AString m_StorageSchema;
+
+ /// The dimension of the world, used by the client to provide correct lighting scheme
+ eDimension m_Dimension;
+
+ /// This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe)
+ MTRand m_TickRand;
+
+ double m_SpawnX;
+ double m_SpawnY;
+ double m_SpawnZ;
+
+ double m_WorldAgeSecs; // World age, in seconds. Is only incremented, cannot be set by plugins.
+ double m_TimeOfDaySecs; // Time of day in seconds. Can be adjusted. Is wrapped to zero each day.
+ Int64 m_WorldAge; // World age in ticks, calculated off of m_WorldAgeSecs
+ Int64 m_TimeOfDay; // Time in ticks, calculated off of m_TimeOfDaySecs
+ Int64 m_LastTimeUpdate; // The tick in which the last time update has been sent.
+ Int64 m_LastUnload; // The last WorldAge (in ticks) in which unloading was triggerred
+ Int64 m_LastSave; // The last WorldAge (in ticks) in which save-all was triggerred
+ Int64 m_LastSpawnMonster; // The last WorldAge (in ticks) in which a monster was spawned
+
+ eGameMode m_GameMode;
+ bool m_bEnabledPVP;
+ bool m_IsDeepSnowEnabled;
+
+ // The cRedstone class simulates redstone and needs access to m_RSList
+ // friend class cRedstone;
+ std::vector<int> m_RSList;
+
+ std::vector<BlockTickQueueItem *> m_BlockTickQueue;
+ std::vector<BlockTickQueueItem *> m_BlockTickQueueCopy; //Second is for safely removing the objects from the queue
+
+ cSimulatorManager * m_SimulatorManager;
+ cSandSimulator * m_SandSimulator;
+ cFluidSimulator * m_WaterSimulator;
+ cFluidSimulator * m_LavaSimulator;
+ cFireSimulator * m_FireSimulator;
+ cRedstoneSimulator * m_RedstoneSimulator;
+
+ cCriticalSection m_CSPlayers;
+ cPlayerList m_Players;
+
+ cWorldStorage m_Storage;
+
+ unsigned int m_MaxPlayers;
+
+ cChunkMap * m_ChunkMap;
+
+ bool m_bAnimals;
+ Int64 m_SpawnMonsterRate;
+
+ eWeather m_Weather;
+ int m_WeatherInterval;
+
+ int m_MaxCactusHeight;
+ int m_MaxSugarcaneHeight;
+ bool m_IsCactusBonemealable;
+ bool m_IsCarrotsBonemealable;
+ bool m_IsCropsBonemealable;
+ bool m_IsGrassBonemealable;
+ bool m_IsMelonStemBonemealable;
+ bool m_IsMelonBonemealable;
+ bool m_IsPotatoesBonemealable;
+ bool m_IsPumpkinStemBonemealable;
+ bool m_IsPumpkinBonemealable;
+ bool m_IsSaplingBonemealable;
+ bool m_IsSugarcaneBonemealable;
+
+ cCriticalSection m_CSFastSetBlock;
+ sSetBlockList m_FastSetBlockQueue;
+
+ cChunkGenerator m_Generator;
+
+ cChunkSender m_ChunkSender;
+ cLightingThread m_Lighting;
+ cTickThread m_TickThread;
+
+ /// Guards the m_Tasks
+ cCriticalSection m_CSTasks;
+
+ /// Tasks that have been queued onto the tick thread; guarded by m_CSTasks
+ cTasks m_Tasks;
+
+ /// Guards m_Clients
+ cCriticalSection m_CSClients;
+
+ /// List of clients in this world, these will be ticked by this world
+ cClientHandleList m_Clients;
+
+ /// Clients that are scheduled for removal (ticked in another world), waiting for TickClients() to remove them
+ cClientHandleList m_ClientsToRemove;
+
+ /// Clients that are scheduled for adding, waiting for TickClients to add them
+ cClientHandleList m_ClientsToAdd;
+
+
+ cWorld(const AString & a_WorldName);
+ ~cWorld();
+
+ void Tick(float a_Dt);
+
+ /// Handles the weather in each tick
+ void TickWeather(float a_Dt);
+
+ /// Handles the mob spawning each tick
+ void TickSpawnMobs(float a_Dt);
+
+ /// Executes all tasks queued onto the tick thread
+ void TickQueuedTasks(void);
+
+ /// Ticks all clients that are in this world
+ void TickClients(float a_Dt);
+
+ /// Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section)
+ cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock);
+}; // tolua_export
+
+
+
+
|