From 6309c6a97fdbabfde978358f5f9a0f61ab74f91f Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Tue, 26 Dec 2017 21:25:57 +0000 Subject: improve rain simulation (#4017) * Uses vanilla logic to decide which blocks rain falls through. * Rain falls infinitely above the world, and stops at y=0. * Entities will now be extinguished if they are under rain-blocking blocks, and fire will now be extinguished by rain similarly. * Create IsWeatherWetAtXYZ to identify wetness at a particular location. * Use new code for enderman rain detection. * Fixes issue #916 * Disable warnings for global constructors in the fire simulator. --- Server/Plugins/APIDump/APIDesc.lua | 34 ++++++++++++---- Server/Plugins/APIDump/Classes/World.lua | 32 +++++++++++---- src/BlockInfo.cpp | 25 ++++++++---- src/BlockInfo.h | 11 +++--- src/Blocks/WorldInterface.h | 2 +- src/Entities/Entity.cpp | 7 +--- src/Mobs/Enderman.cpp | 32 ++------------- src/Mobs/Enderman.h | 6 --- src/Simulator/CMakeLists.txt | 1 - src/Simulator/FireSimulator.cpp | 67 +++++++++++++++++++++----------- src/World.cpp | 28 +++++++++++++ src/World.h | 24 +++++++----- 12 files changed, 168 insertions(+), 101 deletions(-) diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua index 3b37f2fdf..aeb217b7a 100644 --- a/Server/Plugins/APIDump/APIDesc.lua +++ b/Server/Plugins/APIDump/APIDesc.lua @@ -238,7 +238,7 @@ return Type = "boolean", }, }, - Notes = "Returns whether the specified block type will be destroyed after a single hit.", + Notes = "Returns true if the specified block type will be destroyed after a single hit.", }, IsPistonBreakable = { @@ -256,9 +256,9 @@ return Type = "boolean", }, }, - Notes = "Returns whether a piston can break the specified block type.", + Notes = "Returns true if a piston can break the specified block type.", }, - IsSnowable = + IsRainBlocker = { IsStatic = true, Params = @@ -274,9 +274,9 @@ return Type = "boolean", }, }, - Notes = "Returns whether the specified block type can hold snow atop.", + Notes = "Returns true if the specified block type blocks rain from passing through.", }, - IsSolid = + IsSkylightDispersant = { IsStatic = true, Params = @@ -292,9 +292,9 @@ return Type = "boolean", }, }, - Notes = "Returns whether the specified block type is solid.", + Notes = "Returns true if skylight is impeded by passage through a block of the specified type.", }, - IsSkylightDispersant = + IsSnowable = { IsStatic = true, Params = @@ -310,7 +310,25 @@ return Type = "boolean", }, }, - Notes = "Returns true if skylight is impeded by passage through a block of the specified type.", + Notes = "Returns whether the specified block type can hold snow atop.", + }, + IsSolid = + { + IsStatic = true, + Params = + { + { + Name = "BlockType", + Type = "number", + }, + }, + Returns = + { + { + Type = "boolean", + }, + }, + Notes = "Returns whether the specified block type is solid.", }, IsTransparent = { diff --git a/Server/Plugins/APIDump/Classes/World.lua b/Server/Plugins/APIDump/Classes/World.lua index 648bf5aa4..8f1b29012 100644 --- a/Server/Plugins/APIDump/Classes/World.lua +++ b/Server/Plugins/APIDump/Classes/World.lua @@ -2237,7 +2237,7 @@ function OnAllChunksAvailable() All return values from the callbacks are i Type = "boolean", }, }, - Notes = "Returns true if the current world is raining (no thunderstorm).", + Notes = "Returns true if the current weather is rainy.", }, IsWeatherRainAt = { @@ -2258,7 +2258,7 @@ function OnAllChunksAvailable() All return values from the callbacks are i Type = "boolean", }, }, - Notes = "Returns true if the specified location is raining (takes biomes into account - it never rains in a desert).", + Notes = "Returns true if it is rainy at the specified location. This takes into account biomes.", }, IsWeatherStorm = { @@ -2268,7 +2268,7 @@ function OnAllChunksAvailable() All return values from the callbacks are i Type = "boolean", }, }, - Notes = "Returns true if the current world is stormy.", + Notes = "Returns true if the current weather is stormy.", }, IsWeatherStormAt = { @@ -2289,7 +2289,7 @@ function OnAllChunksAvailable() All return values from the callbacks are i Type = "boolean", }, }, - Notes = "Returns true if the specified location is stormy (takes biomes into account - no storm in a desert).", + Notes = "Returns true if it is stormy at the specified location. This takes into account biomes.", }, IsWeatherSunny = { @@ -2320,7 +2320,7 @@ function OnAllChunksAvailable() All return values from the callbacks are i Type = "boolean", }, }, - Notes = "Returns true if the current weather is sunny at the specified location (takes into account biomes).", + Notes = "Returns true if it is sunny at the specified location. This takes into account biomes.", }, IsWeatherWet = { @@ -2330,7 +2330,7 @@ function OnAllChunksAvailable() All return values from the callbacks are i Type = "boolean", }, }, - Notes = "Returns true if the current world has any precipitation (rain or storm).", + Notes = "Returns true if the world currently has any precipitation - rain, storm or snow.", }, IsWeatherWetAt = { @@ -2351,7 +2351,24 @@ function OnAllChunksAvailable() All return values from the callbacks are i Type = "boolean", }, }, - Notes = "Returns true if the specified location has any precipitation (rain or storm) (takes biomes into account, deserts are never wet).", + Notes = "Returns true if it is raining or storming at the specified location. This takes into account biomes.", + }, + IsWeatherWetAtXYZ = + { + Params = + { + { + Name = "Pos", + Type = "Vector3i", + }, + }, + Returns = + { + { + Type = "boolean", + }, + }, + Notes = "Returns true if the specified location has wet weather (rain or storm), using the same logic as IsWeatherWetAt, except that any rain-blocking blocks above the specified position will block the precipitation and this function will return false.", }, PrepareChunk = { @@ -3637,4 +3654,3 @@ World:ForEachEntity( }, }, } - diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp index 3021c5efe..c2f248a26 100644 --- a/src/BlockInfo.cpp +++ b/src/BlockInfo.cpp @@ -464,6 +464,16 @@ cBlockInfo::cBlockInfoArray::cBlockInfoArray() Info[E_BLOCK_YELLOW_SHULKER_BOX ].m_PistonBreakable = true; + /* Blocks that block rain or snow's passage: + * All solid blocks are also rain blockers, and they are set automatically + * at the end of this function. + */ + Info[E_BLOCK_SIGN_POST ].m_IsRainBlocker = true; + Info[E_BLOCK_WALLSIGN ].m_IsRainBlocker = true; + Info[E_BLOCK_WALL_BANNER ].m_IsRainBlocker = true; + Info[E_BLOCK_STANDING_BANNER ].m_IsRainBlocker = true; + + // Blocks that can be snowed over: Info[E_BLOCK_BEDROCK ].m_IsSnowable = true; Info[E_BLOCK_BLOCK_OF_COAL ].m_IsSnowable = true; @@ -554,8 +564,8 @@ cBlockInfo::cBlockInfoArray::cBlockInfoArray() Info[E_BLOCK_BIG_FLOWER ].m_IsSolid = false; Info[E_BLOCK_BROWN_MUSHROOM ].m_IsSolid = false; Info[E_BLOCK_CARROTS ].m_IsSolid = false; - Info[E_BLOCK_CHORUS_PLANT ].m_IsSolid = false; Info[E_BLOCK_CHORUS_FLOWER ].m_IsSolid = false; + Info[E_BLOCK_CHORUS_PLANT ].m_IsSolid = false; Info[E_BLOCK_COBWEB ].m_IsSolid = false; Info[E_BLOCK_CROPS ].m_IsSolid = false; Info[E_BLOCK_DANDELION ].m_IsSolid = false; @@ -575,17 +585,17 @@ cBlockInfo::cBlockInfoArray::cBlockInfoArray() Info[E_BLOCK_POTATOES ].m_IsSolid = false; Info[E_BLOCK_POWERED_RAIL ].m_IsSolid = false; Info[E_BLOCK_RAIL ].m_IsSolid = false; + Info[E_BLOCK_RED_MUSHROOM ].m_IsSolid = false; Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_IsSolid = false; Info[E_BLOCK_REDSTONE_TORCH_ON ].m_IsSolid = false; Info[E_BLOCK_REDSTONE_WIRE ].m_IsSolid = false; - Info[E_BLOCK_RED_MUSHROOM ].m_IsSolid = false; Info[E_BLOCK_REEDS ].m_IsSolid = false; Info[E_BLOCK_SAPLING ].m_IsSolid = false; Info[E_BLOCK_SIGN_POST ].m_IsSolid = false; Info[E_BLOCK_SNOW ].m_IsSolid = false; + Info[E_BLOCK_STANDING_BANNER ].m_IsSolid = false; Info[E_BLOCK_STATIONARY_LAVA ].m_IsSolid = false; Info[E_BLOCK_STATIONARY_WATER ].m_IsSolid = false; - Info[E_BLOCK_STANDING_BANNER ].m_IsSolid = false; Info[E_BLOCK_STONE_BUTTON ].m_IsSolid = false; Info[E_BLOCK_STONE_PRESSURE_PLATE ].m_IsSolid = false; Info[E_BLOCK_TALL_GRASS ].m_IsSolid = false; @@ -974,8 +984,9 @@ cBlockInfo::cBlockInfoArray::cBlockInfoArray() Info[E_BLOCK_RED_SHULKER_BOX ].m_Hardness = 0.2f; Info[E_BLOCK_BLACK_SHULKER_BOX ].m_Hardness = 0.2f; Info[E_BLOCK_STRUCTURE_BLOCK ].m_Hardness = -1.0f; -} - - - + for (size_t i = 0; i < Info.size(); ++i) + { + Info[i].m_IsRainBlocker |= Info[i].m_IsSolid; + } +} diff --git a/src/BlockInfo.h b/src/BlockInfo.h index fd8408638..e7544bf2d 100644 --- a/src/BlockInfo.h +++ b/src/BlockInfo.h @@ -37,7 +37,10 @@ public: /** Can a piston break this block? */ bool m_PistonBreakable; - /** Does a block disperse sky light? (only relevant for transparent blocks) */ + /** Does this block block the passage of rain? */ + bool m_IsRainBlocker; + + /** Does this block disperse sky light? (only relevant for transparent blocks) */ bool m_IsSkylightDispersant; /** Can this block hold snow atop? */ @@ -79,6 +82,7 @@ public: inline static bool IsTransparent (BLOCKTYPE a_Type) { return Get(a_Type).m_Transparent; } inline static bool IsOneHitDig (BLOCKTYPE a_Type) { return Get(a_Type).m_OneHitDig; } inline static bool IsPistonBreakable (BLOCKTYPE a_Type) { return Get(a_Type).m_PistonBreakable; } + inline static bool IsRainBlocker (BLOCKTYPE a_Type) { return Get(a_Type).m_IsRainBlocker; } inline static bool IsSkylightDispersant (BLOCKTYPE a_Type) { return ((Get(a_Type).m_IsSkylightDispersant) || (Get(a_Type).m_SpreadLightFalloff > 1)); @@ -102,6 +106,7 @@ public: , m_Transparent(false) , m_OneHitDig(false) , m_PistonBreakable(false) + , m_IsRainBlocker(false) , m_IsSkylightDispersant(false) , m_IsSnowable(false) , m_IsSolid(true) @@ -149,7 +154,3 @@ inline cBlockHandler * BlockHandler(BLOCKTYPE a_BlockType) { return cBlockInfo::Get(a_BlockType).m_Handler.get(); } - - - - diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h index 19c520ece..344eb9ca3 100644 --- a/src/Blocks/WorldInterface.h +++ b/src/Blocks/WorldInterface.h @@ -65,7 +65,7 @@ public: virtual void SetTimeOfDay(int a_TimeOfDay) = 0; - /** Returns true if it is raining, stormy or snowing at the specified location. This takes into account biomes. */ + /** Returns true if it is raining or storming at the specified location. This takes into account biomes. */ virtual bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) = 0; /** Returns or sets the minumim or maximum netherportal width */ diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 4245f607d..646566ae6 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1172,12 +1172,9 @@ void cEntity::TickBurning(cChunk & a_Chunk) } // Fire is extinguished by rain - if (GetWorld()->IsWeatherWetAt(POSX_TOINT, POSZ_TOINT)) + if (GetWorld()->IsWeatherWetAtXYZ(GetPosition().Floor())) { - if (POSY_TOINT > m_World->GetHeight(POSX_TOINT, POSZ_TOINT)) - { - m_TicksLeftBurning = 0; - } + m_TicksLeftBurning = 0; } // Do the burning damage: diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp index 000496df0..b7013affd 100644 --- a/src/Mobs/Enderman.cpp +++ b/src/Mobs/Enderman.cpp @@ -194,37 +194,13 @@ void cEnderman::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) } // Take damage when touching water, drowning damage seems to be most appropriate - if (CheckRain() || IsSwimming()) + if ( + cChunkDef::IsValidHeight(POSY_TOINT) && + (GetWorld()->IsWeatherWetAtXYZ(GetPosition().Floor()) || IsSwimming()) + ) { EventLosePlayer(); TakeDamage(dtDrowning, nullptr, 1, 0); // TODO teleport to a safe location } } - - - - - -bool cEnderman::CheckRain(void) -{ - if (!GetWorld()->IsWeatherRain()) - { - return false; - } - - Vector3d coords = GetPosition(); - for (int Y = static_cast(coords.y); Y < cChunkDef::Height; ++Y) - { - BLOCKTYPE Block = m_World->GetBlock(static_cast(coords.x), Y, static_cast(coords.z)); - if (Block != E_BLOCK_AIR) - { - return false; - } - } - return true; -} - - - - diff --git a/src/Mobs/Enderman.h b/src/Mobs/Enderman.h index c9ffbeaba..d8731b709 100644 --- a/src/Mobs/Enderman.h +++ b/src/Mobs/Enderman.h @@ -29,8 +29,6 @@ public: /** Returns if the current sky light level is sufficient for the enderman to become aggravated */ bool CheckLight(void); - /** Returns if the enderman gets hit by the rain */ - bool CheckRain(void); private: @@ -39,7 +37,3 @@ private: NIBBLETYPE CarriedMeta; } ; - - - - diff --git a/src/Simulator/CMakeLists.txt b/src/Simulator/CMakeLists.txt index 45972a6ef..5a67dd026 100644 --- a/src/Simulator/CMakeLists.txt +++ b/src/Simulator/CMakeLists.txt @@ -29,7 +29,6 @@ SET (HDRS VaporizeFluidSimulator.h ) - if(NOT MSVC) add_library(Simulator ${SRCS} ${HDRS}) endif() diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp index d5671c5c2..ac7456b0a 100644 --- a/src/Simulator/FireSimulator.cpp +++ b/src/Simulator/FireSimulator.cpp @@ -25,15 +25,22 @@ #define MAX_CHANCE_REPLACE_FUEL 100000 #define MAX_CHANCE_FLAMMABILITY 100000 +// The base chance that in a tick, rain will extinguish a fire block. +#define CHANCE_BASE_RAIN_EXTINGUISH 0.2 +// The additional chance, multiplied by the meta of the fire block, that rain +// will extinguish a fire block in a tick. +#define CHANCE_AGE_M_RAIN_EXTINGUISH 0.03 -static const struct -{ - int x, y, z; -} gCrossCoords[] = +#ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wglobal-constructors" +#endif + +static const Vector3i gCrossCoords[] = { { 1, 0, 0}, {-1, 0, 0}, @@ -45,10 +52,7 @@ static const struct -static const struct -{ - int x, y, z; -} gNeighborCoords[] = +static const Vector3i gNeighborCoords[] = { { 1, 0, 0}, {-1, 0, 0}, @@ -58,6 +62,10 @@ static const struct { 0, 0, -1}, } ; +#ifdef __clang__ + #pragma clang diagnostic pop +#endif + @@ -97,20 +105,39 @@ void cFireSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int x = itr->x; int y = itr->y; int z = itr->z; + auto AbsPos = cChunkDef::RelativeToAbsolute({x, y, z}, a_Chunk->GetPosX(), a_Chunk->GetPosZ()); BLOCKTYPE BlockType = a_Chunk->GetBlock(x, y, z); if (!IsAllowedBlock(BlockType)) { // The block is no longer eligible (not a fire block anymore; a player probably placed a block over the fire) FLOG("FS: Removing block {%d, %d, %d}", - itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width + AbsPos.x, AbsPos.y, AbsPos.z ); itr = Data.erase(itr); continue; } + auto BurnsForever = ((y > 0) && DoesBurnForever(a_Chunk->GetBlock(x, (y - 1), z))); + auto BlockMeta = a_Chunk->GetMeta(x, y, z); + + auto Raining = std::any_of(std::begin(gCrossCoords), std::end(gCrossCoords), + [this, AbsPos](Vector3i cc) + { + return (m_World.IsWeatherWetAtXYZ(AbsPos + cc)); + } + ); + + // Randomly burn out the fire if it is raining: + if (!BurnsForever && Raining && GetRandomProvider().RandBool(CHANCE_BASE_RAIN_EXTINGUISH + (BlockMeta * CHANCE_AGE_M_RAIN_EXTINGUISH))) + { + a_Chunk->SetBlock(x, y, z, E_BLOCK_AIR, 0); + itr = Data.erase(itr); + continue; + } + // Try to spread the fire: - TrySpreadFire(a_Chunk, itr->x, itr->y, itr->z); + TrySpreadFire(a_Chunk, x, y, z); itr->Data -= NumMSecs; if (itr->Data >= 0) @@ -120,30 +147,30 @@ void cFireSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, continue; } - // Burn out the fire one step by increasing the meta: /* FLOG("FS: Fire at {%d, %d, %d} is stepping", itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width ); */ - NIBBLETYPE BlockMeta = a_Chunk->GetMeta(x, y, z); + // Has the fire burnt out? if (BlockMeta == 0x0f) { - // The fire burnt out completely FLOG("FS: Fire at {%d, %d, %d} burnt out, removing the fire block", itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width ); - a_Chunk->SetBlock(itr->x, itr->y, itr->z, E_BLOCK_AIR, 0); - RemoveFuelNeighbors(a_Chunk, itr->x, itr->y, itr->z); + a_Chunk->SetBlock(x, y, z, E_BLOCK_AIR, 0); + RemoveFuelNeighbors(a_Chunk, x, y, z); itr = Data.erase(itr); continue; } - if ((itr->y > 0) && (!DoesBurnForever(a_Chunk->GetBlock(itr->x, itr->y - 1, itr->z)))) + // Burn out the fire one step by increasing the meta: + if (!BurnsForever) { a_Chunk->SetMeta(x, y, z, BlockMeta + 1); } - itr->Data = GetBurnStepTime(a_Chunk, itr->x, itr->y, itr->z); // TODO: Add some randomness into this + + itr->Data = GetBurnStepTime(a_Chunk, x, y, z); // TODO: Add some randomness into this ++itr; } // for itr - Data[] } @@ -283,7 +310,7 @@ int cFireSimulator::GetBurnStepTime(cChunk * a_Chunk, int a_RelX, int a_RelY, in } } // for i - gCrossCoords[] - if (!IsBlockBelowSolid && (a_RelY >= 0)) + if (!IsBlockBelowSolid) { // Checked through everything, nothing was flammable // If block below isn't solid, we can't have fire, it would be a non-fueled fire @@ -427,7 +454,3 @@ bool cFireSimulator::CanStartFireInBlock(cChunk * a_NearChunk, int a_RelX, int a } // for i - Coords[] return false; } - - - - diff --git a/src/World.cpp b/src/World.cpp index 4dd9cbc86..4cf25aee3 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -542,6 +542,34 @@ void cWorld::ChangeWeather(void) +bool cWorld::IsWeatherWetAtXYZ(Vector3i a_Pos) +{ + if ((a_Pos.y < 0) || !IsWeatherWetAt(a_Pos.x, a_Pos.z)) + { + return false; + } + + if (a_Pos.y >= cChunkDef::Height) + { + return true; + } + + for (int y = GetHeight(a_Pos.x, a_Pos.z); y >= a_Pos.y; y--) + { + auto BlockType = GetBlock({a_Pos.x, y, a_Pos.z}); + if (cBlockInfo::IsRainBlocker(BlockType)) + { + return false; + } + } + + return true; +} + + + + + void cWorld::SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ) { return m_ChunkMap->SetNextBlockTick(a_BlockX, a_BlockY, a_BlockZ); diff --git a/src/World.h b/src/World.h index d76f4c258..bce9212af 100644 --- a/src/World.h +++ b/src/World.h @@ -766,7 +766,7 @@ public: /** Returns the current weather. Instead of comparing values directly to the weather constants, use IsWeatherXXX() functions, if possible */ eWeather GetWeather(void) const { return m_Weather; } - /** Returns true if the current weather is sun */ + /** Returns true if the current weather is sunny. */ bool IsWeatherSunny(void) const { return (m_Weather == wSunny); } /** Returns true if it is sunny at the specified location. This takes into account biomes. */ @@ -775,7 +775,7 @@ public: return (IsWeatherSunny() || IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); } - /** Returns true if the current weather is rain */ + /** Returns true if the current weather is rainy. */ bool IsWeatherRain(void) const { return (m_Weather == wRain); } /** Returns true if it is raining at the specified location. This takes into account biomes. */ @@ -784,7 +784,7 @@ public: return (IsWeatherRain() && !IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); } - /** Returns true if the current weather is stormy */ + /** Returns true if the current weather is stormy. */ bool IsWeatherStorm(void) const { return (m_Weather == wStorm); } /** Returns true if the weather is stormy at the specified location. This takes into account biomes. */ @@ -793,15 +793,23 @@ public: return (IsWeatherStorm() && !IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); } - /** Returns true if the current weather has any precipitation - rain, storm or snow */ + /** Returns true if the world currently has any precipitation - rain, storm or snow. */ bool IsWeatherWet(void) const { return !IsWeatherSunny(); } - /** Returns true if it is raining, stormy or snowing at the specified location. This takes into account biomes. */ + /** Returns true if it is raining or storming at the specified location. + This takes into account biomes. */ virtual bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) override { - return (IsWeatherWet() && !IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); + auto Biome = GetBiomeAt(a_BlockX, a_BlockZ); + return (IsWeatherWet() && !IsBiomeNoDownfall(Biome) && !IsBiomeCold(Biome)); } + /** Returns true if the specified location has wet weather (rain or storm), + using the same logic as IsWeatherWetAt, except that any rain-blocking blocks + above the specified position will block the precipitation and this function + will return false. */ + virtual bool IsWeatherWetAtXYZ(Vector3i a_Pos); + /** Returns the seed of the world. */ int GetSeed(void) { return m_Generator.GetSeed(); } @@ -1129,7 +1137,3 @@ private: void SetChunkData(cSetChunkData & a_SetChunkData); }; // tolua_export - - - - -- cgit v1.2.3