summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
m---------MCServer/Plugins/Core0
m---------MCServer/Plugins/ProtectionAreas0
-rw-r--r--Nightbuild2008.cmd2
-rw-r--r--Tools/AnvilStats/.gitignore1
-rw-r--r--Tools/AnvilStats/AnvilStats.cpp3
-rw-r--r--Tools/AnvilStats/AnvilStats.vcproj8
-rw-r--r--Tools/AnvilStats/HeightBiomeMap.cpp230
-rw-r--r--Tools/AnvilStats/HeightBiomeMap.h81
-rw-r--r--Tools/AnvilStats/HeightMap.h4
-rw-r--r--Tools/AnvilStats/ImageComposingCallback.cpp34
-rw-r--r--Tools/AnvilStats/ImageComposingCallback.h10
-rw-r--r--Tools/ProtoProxy/Connection.cpp35
-rw-r--r--source/Bindings.cpp139
-rw-r--r--source/Bindings.h16
-rw-r--r--source/BlockID.cpp2
-rw-r--r--source/BlockID.h12
-rw-r--r--source/Blocks/BlockRail.h133
-rw-r--r--source/ClientHandle.cpp13
-rw-r--r--source/ClientHandle.h3
-rw-r--r--source/Entities/Entity.cpp50
-rw-r--r--source/Entities/Entity.h4
-rw-r--r--source/Entities/Minecart.cpp323
-rw-r--r--source/Entities/Minecart.h5
-rw-r--r--source/Mobs/Monster.cpp41
-rw-r--r--source/Mobs/Monster.h7
-rw-r--r--source/Mobs/Skeleton.cpp18
-rw-r--r--source/Mobs/Skeleton.h1
-rw-r--r--source/Mobs/Zombie.cpp19
-rw-r--r--source/Mobs/Zombie.h3
-rw-r--r--source/OSSupport/Event.cpp47
-rw-r--r--source/OSSupport/Event.h10
-rw-r--r--source/Protocol/Protocol.h2
-rw-r--r--source/Protocol/Protocol125.cpp13
-rw-r--r--source/Protocol/Protocol125.h2
-rw-r--r--source/Protocol/Protocol14x.cpp25
-rw-r--r--source/Protocol/Protocol14x.h2
-rw-r--r--source/Protocol/Protocol16x.cpp4
-rw-r--r--source/Protocol/ProtocolRecognizer.cpp4
-rw-r--r--source/Protocol/ProtocolRecognizer.h2
-rw-r--r--source/World.h1456
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
+
+
+
+