summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xCIbuild.sh2
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua39
m---------MCServer/Plugins/Core0
-rw-r--r--src/Bindings/ManualBindings.cpp32
-rw-r--r--src/Bindings/PluginLua.cpp83
-rw-r--r--src/Bindings/PluginLua.h83
-rw-r--r--src/Blocks/BlockPiston.cpp16
-rw-r--r--src/Blocks/BlockPiston.h2
-rw-r--r--src/CheckBasicStyle.lua6
-rw-r--r--src/Entities/ArrowEntity.cpp13
-rw-r--r--src/Entities/Entity.cpp10
-rw-r--r--src/Entities/ProjectileEntity.cpp7
-rw-r--r--src/Generating/BioGen.cpp36
-rw-r--r--src/Generating/IntGen.h68
-rw-r--r--src/World.cpp30
-rw-r--r--src/World.h51
16 files changed, 325 insertions, 153 deletions
diff --git a/CIbuild.sh b/CIbuild.sh
index 755dc7daa..f5a9005da 100755
--- a/CIbuild.sh
+++ b/CIbuild.sh
@@ -11,7 +11,7 @@ cd src
lua CheckBasicStyle.lua
cd ..
make -j 2;
-make -j 2 test;
+make -j 2 test ARGS="-V";
cd MCServer/;
if [ "$TRAVIS_MCSERVER_BUILD_TYPE" != "COVERAGE" ]
then echo stop | $MCSERVER_PATH;
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 92cdb7415..9ee818a2c 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -197,6 +197,7 @@ g_APIDesc =
baMetas = { Notes = "Operations should work on block metas" },
baLight = { Notes = "Operations should work on block (emissive) light" },
baSkyLight = { Notes = "Operations should work on skylight" },
+ msDifference = { Notes = "Block becomes air if Src and Dst are the same. Otherwise it becomes the source block." },
msOverwrite = { Notes = "Src overwrites anything in Dst" },
msFillAir = { Notes = "Dst is overwritten by Src only where Src has air blocks" },
msImprint = { Notes = "Src overwrites Dst anywhere where Dst has non-air blocks" },
@@ -355,9 +356,11 @@ g_APIDesc =
]],
Functions =
{
+ CanBeTerraformed = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns true if the block is suitable to be changed by a generator" },
FullyOccupiesVoxel = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block fully occupies its voxel." },
Get = { Params = "Type", Return = "{{cBlockInfo}}", Notes = "(STATIC) Returns the {{cBlockInfo}} structure for the specified type." },
GetLightValue = { Params = "Type", Return = "number", Notes = "(STATIC) Returns how much light the specified block emits on its own." },
+ GetPlaceSound = { Params = "Type", Return = "", Notes = "(STATIC) Returns the name of the sound that is played when placing the block." },
GetSpreadLightFalloff = { Params = "Type", Return = "number", Notes = "(STATIC) Returns how much light the specified block consumes." },
IsOneHitDig = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block will be destroyed after a single hit." },
IsPistonBreakable = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether a piston can break the specified block." },
@@ -368,12 +371,14 @@ g_APIDesc =
},
Variables =
{
+ m_CanBeTerraformed = { Type = "bool", Notes = "Is this block suited to be terraformed?" },
m_FullyOccupiesVoxel = { Type = "bool", Notes = "Does this block fully occupy its voxel - is it a 'full' block?" },
m_IsSnowable = { Type = "bool", Notes = "Can this block hold snow atop?" },
m_IsSolid = { Type = "bool", Notes = "Is this block solid (player cannot walk through)?" },
m_LightValue = { Type = "number", Notes = "How much light do the blocks emit on their own?" },
m_OneHitDig = { Type = "bool", Notes = "Is a block destroyed after a single hit?" },
m_PistonBreakable = { Type = "bool", Notes = "Can a piston break this block?" },
+ m_PlaceSound = { Type = "string", Notes = "The name of the sound that is placed when a block is placed." },
m_RequiresSpecialTool = { Type = "bool", Notes = "Does this block require a tool to drop?" },
m_SpreadLightFalloff = { Type = "number", Notes = "How much light do the blocks consume?" },
m_Transparent = { Type = "bool", Notes = "Is a block completely transparent? (light doesn't get decreased(?))" },
@@ -447,6 +452,7 @@ g_APIDesc =
GetChunkZ = { Params = "", Return = "number", Notes = "Returns the Z coord of the chunk contained." },
GetHeight = { Params = "RelX, RelZ", Return = "number", Notes = "Returns the height at the specified relative coords" },
GetMaxHeight = { Params = "", Return = "number", Notes = "Returns the maximum height contained in the heightmap." },
+ GetMinHeight = { Params = "", Return = "number", Notes = "Returns the minimum height value in the heightmap." },
IsUsingDefaultBiomes = { Params = "", Return = "bool", Notes = "Returns true if the chunk is set to use default biome generator" },
IsUsingDefaultComposition = { Params = "", Return = "bool", Notes = "Returns true if the chunk is set to use default composition generator" },
IsUsingDefaultFinish = { Params = "", Return = "bool", Notes = "Returns true if the chunk is set to use default finishers" },
@@ -2419,6 +2425,7 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress")
BroadcastChatInfo = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Prepends Yellow [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For informational messages, such as command usage." },
BroadcastChatSuccess = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Prepends Green [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For success messages." },
BroadcastChatWarning = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Prepends Rose [WARN] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For concerning events, such as plugin reload etc." },
+ BroadcastEntityAnimation = { Params = "{{cEntity|TargetEntity}}, Animation, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Sends an animation of an entity to all clienthandles (except ExcludeClient if given)" },
BroadcastParticleEffect = { Params = "ParticleName, X, Y, Z, OffSetX, OffSetY, OffSetZ, ParticleData, ParticleAmmount, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Spawns the specified particles to all players in the world exept the optional ExeptClient. A list of available particles by thinkofdeath can be found {{https://gist.github.com/thinkofdeath/5110835|Here}}" },
BroadcastSoundEffect = { Params = "SoundName, X, Y, Z, Volume, Pitch, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Sends the specified sound effect to all players in this world, except the optional ExceptClient" },
BroadcastSoundParticleEffect = { Params = "EffectID, X, Y, Z, EffectData, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Sends the specified effect to all players in this world, except the optional ExceptClient" },
@@ -2471,15 +2478,20 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress")
},
GetBlockSkyLight = { Params = "BlockX, BlockY, BlockZ", Return = "number", Notes = "Returns the block skylight of the block at the specified coords, or 0 if the appropriate chunk is not loaded." },
GetBlockTypeMeta = { Params = "BlockX, BlockY, BlockZ", Return = "BlockValid, BlockType, BlockMeta", Notes = "Returns the block type and metadata for the block at the specified coords. The first value specifies if the block is in a valid loaded chunk, the other values are valid only if BlockValid is true." },
+ GetDefaultWeatherInterval = { Params = "eWeather", Return = "", Notes = "Returns the default weather interval for the specific weather type. Returns -1 for any unknown weather." },
GetDimension = { Params = "", Return = "eDimension", Notes = "Returns the dimension of the world - dimOverworld, dimNether or dimEnd." },
GetGameMode = { Params = "", Return = "eGameMode", Notes = "Returns the gamemode of the world - gmSurvival, gmCreative or gmAdventure." },
GetGeneratorQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks that are queued in the chunk generator." },
GetHeight = { Params = "BlockX, BlockZ", Return = "number", Notes = "Returns the maximum height of the particula block column in the world. If the chunk is not loaded, it waits for it to load / generate. <b>WARNING</b>: Do not use, Use TryGetHeight() instead for a non-waiting version, otherwise you run the risk of a deadlock!" },
GetIniFileName = { Params = "", Return = "string", Notes = "Returns the name of the world.ini file that the world uses to store the information." },
GetLightingQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks in the lighting thread's queue." },
+ GetLinkedEndWorldName = { Params = "", Return = "string", Notes = "Returns the name of the end world this world is linked to." },
+ GetLinkedNetherWorldName = { Params = "", Return = "string", Notes = "Returns the name of the Netherworld linked to this world." },
+ GetLinkedOverworldName = { Params = "", Return = "string", Notes = "Returns the name of the world this world is linked to." },
GetMapManager = { Params = "", Return = "{{cMapManager}}", Notes = "Returns the {{cMapManager|MapManager}} object used by this world." },
GetMaxCactusHeight = { Params = "", Return = "number", Notes = "Returns the configured maximum height to which cacti will grow naturally." },
GetMaxSugarcaneHeight = { Params = "", Return = "number", Notes = "Returns the configured maximum height to which sugarcane will grow naturally." },
+ GetMaxViewDistance = { Params = "", Return = "number", Notes = "Returns the maximum viewdistance that players can see in this world. The view distance is the amount of chunks around the player that the player can see." },
GetName = { Params = "", Return = "string", Notes = "Returns the name of the world, as specified in the settings.ini file." },
GetNumChunks = { Params = "", Return = "number", Notes = "Returns the number of chunks currently loaded." },
GetScoreBoard = { Params = "", Return = "{{cScoreBoard}}", Notes = "Returns the {{cScoreBoard|ScoreBoard}} object used by this world. " },
@@ -2491,6 +2503,7 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress")
GetStorageSaveQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks queued up for saving" },
GetTicksUntilWeatherChange = { Params = "", Return = "number", Notes = "Returns the number of ticks that will pass before the weather is changed" },
GetTimeOfDay = { Params = "", Return = "number", Notes = "Returns the number of ticks that have passed from the sunrise, 0 .. 24000." },
+ GetTNTShrapnelLevel = { Params = "", Return = "{{Globals#ShrapnelLevel|ShrapnelLevel}}", Notes = "Returns the shrapnel level, representing the block types that are propelled outwards following an explosion. Based on this value and a random picker, blocks are selectively converted to physics entities (FallingSand) and flung outwards." },
GetWeather = { Params = "", Return = "eWeather", Notes = "Returns the current weather in the world (wSunny, wRain, wStorm). To check for weather, use IsWeatherXXX() functions instead." },
GetWorldAge = { Params = "", Return = "number", Notes = "Returns the total age of the world, in ticks. The age always grows, cannot be set by plugins and is unrelated to TimeOfDay." },
GrowCactus = { Params = "BlockX, BlockY, BlockZ, NumBlocksToGrow", Return = "", Notes = "Grows a cactus block at the specified coords, by up to the specified number of blocks. Adheres to the world's maximum cactus growth (GetMaxCactusHeight())." },
@@ -2501,11 +2514,14 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress")
GrowTreeByBiome = { Params = "BlockX, BlockY, BlockZ", Return = "", Notes = "Grows a tree based at the specified coords. The tree type is picked from types available for the biome at those coords." },
GrowTreeFromSapling = { Params = "BlockX, BlockY, BlockZ, SaplingMeta", Return = "", Notes = "Grows a tree based at the specified coords. The tree type is determined from the sapling meta (the sapling itself needn't be present)." },
IsBlockDirectlyWatered = { Params = "BlockX, BlockY, BlockZ", Return = "bool", Notes = "Returns true if the specified block has a water block right next to it (on the X/Z axes)" },
+ IsDaylightCycleEnabled = { Params = "", Return = "bool", Notes = "Returns true if the daylight cycle is enabled." },
IsDeepSnowEnabled = { Params = "", Return = "bool", Notes = "Returns whether the configuration has DeepSnow enabled." },
IsGameModeAdventure = { Params = "", Return = "bool", Notes = "Returns true if the current gamemode is gmAdventure." },
IsGameModeCreative = { Params = "", Return = "bool", Notes = "Returns true if the current gamemode is gmCreative." },
+ IsGameModeSpectator = { Params = "", Return = "bool", Notes = "Returns true if the current gamemode is gmSpectator." },
IsGameModeSurvival = { Params = "", Return = "bool", Notes = "Returns true if the current gamemode is gmSurvival." },
IsPVPEnabled = { Params = "", Return = "bool", Notes = "Returns whether PVP is enabled in the world settings." },
+ IsTrapdoorOpen = { Params = "BlockX, BlockY, BlockZ", Return = "bool", Notes = "Returns false if there is no trapdoor there or if the block isn't a trapdoor or if the chunk wasn't loaded. Returns true if trapdoor is open." },
IsWeatherRain = { Params = "", Return = "bool", Notes = "Returns true if the current world is raining." },
IsWeatherRainAt = { Params = "BlockX, BlockZ", Return = "bool", Notes = "Returns true if the specified location is raining (takes into account biomes)." },
IsWeatherStorm = { Params = "", Return = "bool", Notes = "Returns true if the current world is stormy." },
@@ -2514,6 +2530,7 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress")
IsWeatherSunnyAt = { Params = "BlockX, BlockZ", Return = "bool", Notes = "Returns true if the current weather is sunny at the specified location (takes into account biomes)." },
IsWeatherWet = { Params = "", Return = "bool", Notes = "Returns true if the current world has any precipitation (rain or storm)." },
IsWeatherWetAt = { Params = "BlockX, BlockZ", Return = "bool", Notes = "Returns true if the specified location has any precipitation (rain or storm) (takes into account biomes)." },
+ PrepareChunk = { Params = "ChunkX, ChunkZ, [Callback]", Return = "", Notes = "Queues the chunk for preparing - making sure that it's generated and lit. It is legal to call with no callback. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback(ChunkX, ChunkZ)</pre>" },
QueueBlockForTick = { Params = "BlockX, BlockY, BlockZ, TicksToWait", Return = "", Notes = "Queues the specified block to be ticked after the specified number of gameticks." },
QueueSaveAllChunks = { Params = "", Return = "", Notes = "Queues all chunks to be saved in the world storage thread" },
QueueSetBlock = { Params = "BlockX, BlockY, BlockZ, BlockType, BlockMeta, TickDelay", Return = "", Notes = "Queues the block to be set to the specified blocktype and meta after the specified amount of game ticks. Uses SetBlock() for the actual setting, so simulators are woken up and block entities are handled correctly." },
@@ -2537,18 +2554,28 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress")
SetNextBlockTick = { Params = "BlockX, BlockY, BlockZ", Return = "", Notes = "Sets the blockticking to start at the specified block in the next tick." },
SetCommandBlockCommand = { Params = "BlockX, BlockY, BlockZ, Command", Return = "bool", Notes = "Sets the command to be executed in a command block at the specified coordinates. Returns if command was changed." },
SetCommandBlocksEnabled = { Params = "IsEnabled (bool)", Return = "", Notes = "Sets whether command blocks should be enabled on the (entire) server." },
+ SetDaylightCycleEnabled = { Params = "bool", Return = "", Notes = "Starts or stops the daylight cycle." },
+ SetLinkedEndWorldName = { Params = "string", Return = "", Notes = "Sets the name of the world that the end portal should link to." },
+ SetLinkedNetherWorldName = { Params = "string", Return = "", Notes = "Sets the name of the world that the nether portal should link to." },
+ SetLinkedOverworldName = { Params = "string", Return = "", Notes = "Sets the name of the world that the nether portal should link to?" },
+ SetMaxViewDistance = { Params = "number", Return = "", Notes = "Sets the maximum viewdistance of the players in the world." },
SetShouldUseChatPrefixes = { Params = "", Return = "ShouldUse (bool)", Notes = "Sets whether coloured chat prefixes such as [INFO] is used with the SendMessageXXX() or BroadcastChatXXX(), or simply the entire message is coloured in the respective colour." },
- ShouldUseChatPrefixes = { Params = "", Return = "bool", Notes = "Returns whether coloured chat prefixes are prepended to chat messages or the entire message is simply coloured." },
SetSignLines = { Params = "X, Y, Z, Line1, Line2, Line3, Line4, [{{cPlayer|Player}}]", Return = "", Notes = "Sets the sign text at the specified coords. The sign-updating hooks are called for the change. The Player parameter is used to indicate the player from whom the change has come, it may be nil." },
SetTicksUntilWeatherChange = { Params = "NumTicks", Return = "", Notes = "Sets the number of ticks after which the weather will be changed." },
SetTimeOfDay = { Params = "TimeOfDayTicks", Return = "", Notes = "Sets the time of day, expressed as number of ticks past sunrise, in the range 0 .. 24000." },
+ SetTNTShrapnelLevel = { Params = "{{Globals#ShrapnelLevel|ShrapnelLevel}}", Return = "", Notes = "Sets the Shrampel level of the world." },
+ SetTrapdoorOpen = { Params = "BlockX, BlockY, BlockZ, bool", Return = "", Notes = "Opens or closes a trapdoor at the specific coordinates." },
SetWeather = { Params = "Weather", Return = "", Notes = "Sets the current weather (wSunny, wRain, wStorm) and resets the TicksUntilWeatherChange to the default value for the new weather. The normal weather-changing hooks are called for the change." },
+ ShouldBroadcastAchievementMessages = { Params = "", Return = "bool", Notes = "Returns true if the server should broadcast achievement messages in this world." },
+ ShouldBroadcastDeathMessages = { Params = "", Return = "bool", Notes = "Returns true if the server should broadcast death messages in this world." },
+ ShouldUseChatPrefixes = { Params = "", Return = "bool", Notes = "Returns whether coloured chat prefixes are prepended to chat messages or the entire message is simply coloured." },
ShouldLavaSpawnFire = { Params = "", Return = "bool", Notes = "Returns true if the world is configured to spawn fires near lava (world.ini: [Physics].ShouldLavaSpawnFire value)" },
SpawnItemPickups =
{
{ Params = "{{cItems|Pickups}}, X, Y, Z, FlyAwaySpeed", Return = "", Notes = "Spawns the specified pickups at the position specified. The FlyAway speed is used to initialize the random speed in which the pickups fly away from the spawn position." },
{ Params = "{{cItems|Pickups}}, X, Y, Z, SpeedX, SpeedY, SpeedZ", Return = "", Notes = "Spawns the specified pickups at the position specified. All the pickups fly away from the spawn position using the specified speed." },
},
+ SpawnMinecart = { Params = "X, Y, Z, MinecartType, Item, BlockHeight", Return = "number", Notes = "Spawns a minecart at the specific coordinates. MinecartType is the item type of the minecart. If the minecart is an empty minecart then the given item is the block inside the minecart, and blockheight is the distance of the block and the minecart." },
SpawnMob = { Params = "X, Y, Z, {{cMonster|MonsterType}}", Return = "EntityID", Notes = "Spawns the specified type of mob at the specified coords. Returns the EntityID of the creates entity, or -1 on failure. " },
SpawnFallingBlock = { Params = "X, Y, Z, BlockType, BlockMeta", Return = "EntityID", Notes = "Spawns an {{cFallingBlock|Falling Block}} entity at the specified coords with the given block type/meta" },
SpawnExperienceOrb = { Params = "X, Y, Z, Reward", Return = "EntityID", Notes = "Spawns an {{cExpOrb|experience orb}} at the specified coords, with the given reward" },
@@ -2556,6 +2583,7 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress")
TryGetHeight = { Params = "BlockX, BlockZ", Return = "IsValid, Height", Notes = "Returns true and height of the highest non-air block if the chunk is loaded, or false otherwise." },
UpdateSign = { Params = "X, Y, Z, Line1, Line2, Line3, Line4, [{{cPlayer|Player}}]", Return = "", Notes = "(<b>DEPRECATED</b>) Please use SetSignLines()." },
UseBlockEntity = { Params = "{{cPlayer|Player}}, BlockX, BlockY, BlockZ", Return = "", Notes = "Makes the specified Player use the block entity at the specified coords (open chest UI, etc.) If the cords are in an unloaded chunk or there's no block entity, ignores the call." },
+ VillagersShouldHarvestCrops = { Params = "", Return = "", Notes = "Returns true if villagers can harvest crops." },
WakeUpSimulators = { Params = "BlockX, BlockY, BlockZ", Return = "", Notes = "Wakes up the simulators for the specified block." },
WakeUpSimulatorsInArea = { Params = "MinBlockX, MaxBlockX, MinBlockY, MaxBlockY, MinBlockZ, MaxBlockZ", Return = "", Notes = "Wakes up the simulators for all the blocks in the specified area (edges inclusive)." },
},
@@ -3066,7 +3094,14 @@ end
These constants are used to differentiate the various sources of spreads, such as grass growing.
They are used in the {{OnBlockSpread|HOOK_BLOCK_SPREAD}} hook.
]],
- }
+ },
+ ShrapnelLevel =
+ {
+ Include = "^sl.*",
+ TextBefore = [[
+ The following constants define the block types that are propelled outwards after an explosion.
+ ]],
+ },
},
}, -- Globals
},
diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core
-Subproject 6e9d612b9eb548d888d2bf986488aad762a99be
+Subproject ee3cd9ba917baa94d6b9bfe7c9205609e0722fa
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index 035be55ae..cdc01ae09 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -1299,23 +1299,27 @@ tolua_lerror:
class cLuaWorldTask :
- public cWorld::cTask
+ public cWorld::cTask,
+ public cPluginLua::cResettable
{
public:
cLuaWorldTask(cPluginLua & a_Plugin, int a_FnRef) :
- m_Plugin(a_Plugin),
+ cPluginLua::cResettable(a_Plugin),
m_FnRef(a_FnRef)
{
}
protected:
- cPluginLua & m_Plugin;
int m_FnRef;
// cWorld::cTask overrides:
virtual void Run(cWorld & a_World) override
{
- m_Plugin.Call(m_FnRef, &a_World);
+ cCSLock Lock(m_CSPlugin);
+ if (m_Plugin != nullptr)
+ {
+ m_Plugin->Call(m_FnRef, &a_World);
+ }
}
} ;
@@ -1354,7 +1358,9 @@ static int tolua_cWorld_QueueTask(lua_State * tolua_S)
return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1");
}
- self->QueueTask(make_unique<cLuaWorldTask>(*Plugin, FnRef));
+ auto task = std::make_shared<cLuaWorldTask>(*Plugin, FnRef);
+ Plugin->AddResettable(task);
+ self->QueueTask(task);
return 0;
}
@@ -1363,23 +1369,27 @@ static int tolua_cWorld_QueueTask(lua_State * tolua_S)
class cLuaScheduledWorldTask :
- public cWorld::cTask
+ public cWorld::cTask,
+ public cPluginLua::cResettable
{
public:
cLuaScheduledWorldTask(cPluginLua & a_Plugin, int a_FnRef) :
- m_Plugin(a_Plugin),
+ cPluginLua::cResettable(a_Plugin),
m_FnRef(a_FnRef)
{
}
protected:
- cPluginLua & m_Plugin;
int m_FnRef;
// cWorld::cTask overrides:
virtual void Run(cWorld & a_World) override
{
- m_Plugin.Call(m_FnRef, &a_World);
+ cCSLock Lock(m_CSPlugin);
+ if (m_Plugin != nullptr)
+ {
+ m_Plugin->Call(m_FnRef, &a_World);
+ }
}
};
@@ -1425,7 +1435,9 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S)
int DelayTicks = (int)tolua_tonumber(tolua_S, 2, 0);
- World->ScheduleTask(DelayTicks, new cLuaScheduledWorldTask(*Plugin, FnRef));
+ auto task = std::make_shared<cLuaScheduledWorldTask>(*Plugin, FnRef);
+ Plugin->AddResettable(task);
+ World->ScheduleTask(DelayTicks, task);
return 0;
}
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index 263d1f005..0a2a8411d 100644
--- a/src/Bindings/PluginLua.cpp
+++ b/src/Bindings/PluginLua.cpp
@@ -6,10 +6,11 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#ifdef __APPLE__
-#define LUA_USE_MACOSX
+ #define LUA_USE_MACOSX
#else
-#define LUA_USE_POSIX
+ #define LUA_USE_POSIX
#endif
+
#include "PluginLua.h"
#include "../CommandOutput.h"
#include "PluginManager.h"
@@ -52,24 +53,40 @@ cPluginLua::~cPluginLua()
void cPluginLua::Close(void)
{
- if (m_LuaState.IsValid())
- {
- // Release all the references in the hook map:
- for (cHookMap::iterator itrH = m_HookMap.begin(), endH = m_HookMap.end(); itrH != endH; ++itrH)
- {
- for (cLuaRefs::iterator itrR = itrH->second.begin(), endR = itrH->second.end(); itrR != endR; ++itrR)
- {
- delete *itrR;
- } // for itrR - itrH->second[]
- } // for itrH - m_HookMap[]
- m_HookMap.clear();
-
- m_LuaState.Close();
- }
- else
+ cCSLock Lock(m_CriticalSection);
+
+ // If already closed, bail out:
+ if (!m_LuaState.IsValid())
{
+ ASSERT(m_Resettables.empty());
ASSERT(m_HookMap.empty());
+ return;
}
+
+ // Notify and remove all m_Resettables (unlock the m_CriticalSection while resetting them):
+ cResettablePtrs resettables;
+ std::swap(m_Resettables, resettables);
+ {
+ cCSUnlock Unlock(Lock);
+ for (auto resettable: resettables)
+ {
+ resettable->Reset();
+ }
+ m_Resettables.clear();
+ } // cCSUnlock (m_CriticalSection)
+
+ // Release all the references in the hook map:
+ for (cHookMap::iterator itrH = m_HookMap.begin(), endH = m_HookMap.end(); itrH != endH; ++itrH)
+ {
+ for (cLuaRefs::iterator itrR = itrH->second.begin(), endR = itrH->second.end(); itrR != endR; ++itrR)
+ {
+ delete *itrR;
+ } // for itrR - itrH->second[]
+ } // for itrH - m_HookMap[]
+ m_HookMap.clear();
+
+ // Close the Lua engine:
+ m_LuaState.Close();
}
@@ -1709,6 +1726,16 @@ int cPluginLua::CallFunctionFromForeignState(
+void cPluginLua::AddResettable(cPluginLua::cResettablePtr a_Resettable)
+{
+ cCSLock Lock(m_CriticalSection);
+ m_Resettables.push_back(a_Resettable);
+}
+
+
+
+
+
AString cPluginLua::HandleWebRequest(const HTTPRequest * a_Request)
{
cCSLock Lock(m_CriticalSection);
@@ -1826,3 +1853,25 @@ void cPluginLua::CallbackWindowSlotChanged(int a_FnRef, cWindow & a_Window, int
+
+////////////////////////////////////////////////////////////////////////////////
+// cPluginLua::cResettable:
+
+cPluginLua::cResettable::cResettable(cPluginLua & a_Plugin):
+ m_Plugin(&a_Plugin)
+{
+}
+
+
+
+
+
+void cPluginLua::cResettable::Reset(void)
+{
+ cCSLock Lock(m_CSPlugin);
+ m_Plugin = nullptr;
+}
+
+
+
+
diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h
index 4f3529fc9..c14b02687 100644
--- a/src/Bindings/PluginLua.h
+++ b/src/Bindings/PluginLua.h
@@ -59,6 +59,37 @@ public:
/** RAII lock for m_Plugin.m_CriticalSection */
cCSLock m_Lock;
} ;
+
+
+
+ /** A base class that represents something related to a plugin
+ The plugin can reset this class so that the instance can continue to exist but will not engage the (possibly non-existent) plugin anymore.
+ This is used for scheduled tasks etc., so that they can be queued and reset when the plugin is terminated, without removing them from the queue. */
+ class cResettable
+ {
+ public:
+ /** Creates a new instance bound to the specified plugin. */
+ cResettable(cPluginLua & a_Plugin);
+
+ // Force a virtual destructor in descendants:
+ virtual ~cResettable() {}
+
+ /** Resets the plugin instance stored within.
+ The instance will continue to exist, but should not call into the plugin anymore. */
+ virtual void Reset(void);
+
+ protected:
+ /** The plugin that this instance references.
+ If nullptr, the plugin has already unloaded and the instance should bail out any processing.
+ Protected against multithreaded access by m_CSPlugin. */
+ cPluginLua * m_Plugin;
+
+ /** The mutex protecting m_Plugin against multithreaded access. */
+ cCriticalSection m_CSPlugin;
+ };
+
+ typedef SharedPtr<cResettable> cResettablePtr;
+ typedef std::vector<cResettablePtr> cResettablePtrs;
cPluginLua(const AString & a_PluginDirectory);
@@ -187,42 +218,16 @@ public:
int a_ParamEnd
);
- // The following templates allow calls to arbitrary Lua functions residing in the plugin:
-
- /** Call a Lua function with 0 args */
- template <typename FnT> bool Call(FnT a_Fn)
- {
- cCSLock Lock(m_CriticalSection);
- return m_LuaState.Call(a_Fn);
- }
-
- /** Call a Lua function with 1 arg */
- template <typename FnT, typename ArgT0> bool Call(FnT a_Fn, ArgT0 a_Arg0)
+ /** Call a Lua function residing in the plugin. */
+ template <typename FnT, typename... Args>
+ bool Call(FnT a_Fn, Args && ... a_Args)
{
cCSLock Lock(m_CriticalSection);
- return m_LuaState.Call(a_Fn, a_Arg0);
+ return m_LuaState.Call(a_Fn, a_Args...);
}
- /** Call a Lua function with 2 args */
- template <typename FnT, typename ArgT0, typename ArgT1> bool Call(FnT a_Fn, ArgT0 a_Arg0, ArgT1 a_Arg1)
- {
- cCSLock Lock(m_CriticalSection);
- return m_LuaState.Call(a_Fn, a_Arg0, a_Arg1);
- }
-
- /** Call a Lua function with 3 args */
- template <typename FnT, typename ArgT0, typename ArgT1, typename ArgT2> bool Call(FnT a_Fn, ArgT0 a_Arg0, ArgT1 a_Arg1, ArgT2 a_Arg2)
- {
- cCSLock Lock(m_CriticalSection);
- return m_LuaState.Call(a_Fn, a_Arg0, a_Arg1, a_Arg2);
- }
-
- /** Call a Lua function with 4 args */
- template <typename FnT, typename ArgT0, typename ArgT1, typename ArgT2, typename ArgT3> bool Call(FnT a_Fn, ArgT0 a_Arg0, ArgT1 a_Arg1, ArgT2 a_Arg2, ArgT3 a_Arg3)
- {
- cCSLock Lock(m_CriticalSection);
- return m_LuaState.Call(a_Fn, a_Arg0, a_Arg1, a_Arg2, a_Arg3);
- }
+ /** Adds the specified cResettable instance to m_Resettables, so that it is notified when the plugin is being closed. */
+ void AddResettable(cResettablePtr a_Resettable);
protected:
/** Maps command name into Lua function reference */
@@ -234,15 +239,27 @@ protected:
/** Maps hook types into arrays of Lua function references to call for each hook type */
typedef std::map<int, cLuaRefs> cHookMap;
+
+ /** The mutex protecting m_LuaState and each of the m_Resettables[] against multithreaded use. */
cCriticalSection m_CriticalSection;
+
+ /** The plugin's Lua state. */
cLuaState m_LuaState;
+ /** Objects that need notification when the plugin is about to be unloaded. */
+ cResettablePtrs m_Resettables;
+
+ /** In-game commands that the plugin has registered. */
CommandMap m_Commands;
+
+ /** Console commands that the plugin has registered. */
CommandMap m_ConsoleCommands;
+ /** Hooks that the plugin has registered. */
cHookMap m_HookMap;
- /** Releases all Lua references and closes the LuaState */
+
+ /** Releases all Lua references, notifies and removes all m_Resettables[] and closes the m_LuaState. */
void Close(void);
} ; // tolua_export
diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp
index 8d245cabe..d9f4913d8 100644
--- a/src/Blocks/BlockPiston.cpp
+++ b/src/Blocks/BlockPiston.cpp
@@ -61,6 +61,16 @@ void cBlockPistonHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorld
+void cBlockPistonHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta)
+{
+ // Returning Piston Item without Direction-Metavalue
+ a_Pickups.push_back(cItem(m_BlockType, 1));
+}
+
+
+
+
+
bool cBlockPistonHandler::GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@@ -169,7 +179,7 @@ void cBlockPistonHandler::ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ,
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta | 0x8);
a_World->SetBlock(extx, exty, extz, E_BLOCK_PISTON_EXTENSION, pistonMeta | (IsSticky(pistonBlock) ? 8 : 0), false);
- a_World->ScheduleTask(PISTON_TICK_DELAY, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks));
+ a_World->ScheduleTask(PISTON_TICK_DELAY, std::make_shared<cWorld::cTaskSendBlockToAllPlayers>(ScheduledBlocks));
}
@@ -219,7 +229,7 @@ void cBlockPistonHandler::RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ
std::vector<Vector3i> ScheduledBlocks;
ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ));
ScheduledBlocks.push_back(Vector3i(tempx, tempy, tempz));
- a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks));
+ a_World->ScheduleTask(PISTON_TICK_DELAY + 1, std::make_shared<cWorld::cTaskSendBlockToAllPlayers>(ScheduledBlocks));
return;
}
}
@@ -229,7 +239,7 @@ void cBlockPistonHandler::RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ
std::vector<Vector3i> ScheduledBlocks;
ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ));
- a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks));
+ a_World->ScheduleTask(PISTON_TICK_DELAY + 1, std::make_shared<cWorld::cTaskSendBlockToAllPlayers>(ScheduledBlocks));
}
diff --git a/src/Blocks/BlockPiston.h b/src/Blocks/BlockPiston.h
index f868f4d8e..9a891025a 100644
--- a/src/Blocks/BlockPiston.h
+++ b/src/Blocks/BlockPiston.h
@@ -15,6 +15,8 @@ public:
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override;
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override;
+
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
diff --git a/src/CheckBasicStyle.lua b/src/CheckBasicStyle.lua
index 648a5711b..19156b537 100644
--- a/src/CheckBasicStyle.lua
+++ b/src/CheckBasicStyle.lua
@@ -101,9 +101,9 @@ local g_ViolationPatterns =
{"&&[^(]+!=", "Add parenthesis around comparison"},
{"!=[^)]+||", "Add parenthesis around comparison"},
{"||[^(]+!=", "Add parenthesis around comparison"},
- {"<[^)T][^)]*&&", "Add parenthesis around comparison"}, -- Must take special care of templates: "template <T> fn(Args && ...)"
- {"&&[^(]+<", "Add parenthesis around comparison"},
- {"<[^)T][^)]*||", "Add parenthesis around comparison"}, -- Must take special care of templates: "template <T> fn(Args && ...)"
+ {"<[^)>]*&&", "Add parenthesis around comparison"}, -- Must take special care of templates: "template <T> fn(Args && ...)"
+ -- Cannot check a < following a && due to functions of the form x fn(y&& a, z<b> c)
+ {"<[^)>]*||", "Add parenthesis around comparison"}, -- Must take special care of templates: "template <T> fn(Args && ...)"
{"||[^(]+<", "Add parenthesis around comparison"},
-- Cannot check ">" because of "obj->m_Flag &&". Check at least ">=":
{">=[^)]+&&", "Add parenthesis around comparison"},
diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp
index 0fbbfb681..3c1fabb1b 100644
--- a/src/Entities/ArrowEntity.cpp
+++ b/src/Entities/ArrowEntity.cpp
@@ -72,14 +72,8 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
{
- if (GetSpeed().EqualsEps(Vector3d(0, 0, 0), 0.0000001))
- {
- SetSpeed(GetLookVector().NormalizeCopy() * 0.1); // Ensure that no division by zero happens later
- }
-
Vector3d Hit = a_HitPos;
- Vector3d SinkMovement = (GetSpeed() / 1000);
- Hit += SinkMovement * (0.0005 / SinkMovement.Length()); // Make arrow sink into block a centimetre so it lodges (but not to far so it goes black clientside)
+ Hit += GetSpeed().NormalizeCopy() / 100000; // Make arrow sink into block a bit so it lodges (TODO: investigate how to stop them going so far so that they become black clientside)
super::OnHitSolidBlock(Hit, a_HitFace);
Vector3i BlockHit = Hit.Floor();
@@ -195,11 +189,6 @@ void cArrowEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
if (m_IsInGround)
{
- // When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL
- // Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing)
- // We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync
- // Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position
-
if (!m_HasTeleported) // Sent a teleport already, don't do again
{
if (m_HitGroundTimer > std::chrono::milliseconds(500))
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 1bc4690e1..039c58ee4 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -1263,7 +1263,7 @@ bool cEntity::DetectPortal()
{
if (GetWorld()->GetDimension() == dimOverworld)
{
- if (GetWorld()->GetNetherWorldName().empty() && GetWorld()->GetEndWorldName().empty())
+ if (GetWorld()->GetLinkedNetherWorldName().empty() && GetWorld()->GetLinkedEndWorldName().empty())
{
// Teleportation to either dimension not enabled, don't bother proceeding
return false;
@@ -1314,7 +1314,7 @@ bool cEntity::DetectPortal()
}
else
{
- if (GetWorld()->GetNetherWorldName().empty())
+ if (GetWorld()->GetLinkedNetherWorldName().empty())
{
return false;
}
@@ -1327,7 +1327,7 @@ bool cEntity::DetectPortal()
((cPlayer *)this)->GetClientHandle()->SendRespawn(dimNether);
}
- return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetNetherWorldName(), dimNether, GetWorld()->GetName()), false);
+ return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedNetherWorldName(), dimNether, GetWorld()->GetName()), false);
}
}
case E_BLOCK_END_PORTAL:
@@ -1358,7 +1358,7 @@ bool cEntity::DetectPortal()
}
else
{
- if (GetWorld()->GetEndWorldName().empty())
+ if (GetWorld()->GetLinkedEndWorldName().empty())
{
return false;
}
@@ -1371,7 +1371,7 @@ bool cEntity::DetectPortal()
((cPlayer *)this)->GetClientHandle()->SendRespawn(dimEnd);
}
- return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetEndWorldName(), dimEnd, GetWorld()->GetName()), false);
+ return MoveToWorld(cRoot::Get()->CreateAndInitializeWorld(GetWorld()->GetLinkedEndWorldName(), dimEnd, GetWorld()->GetName()), false);
}
}
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index 4f20bfae6..21ec4e63a 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -334,12 +334,7 @@ AString cProjectileEntity::GetMCAClassName(void) const
void cProjectileEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
-
- // TODO: see BroadcastMovementUpdate; RelativeMove packet jerkiness affects projectiles too (cause of sympton described in cArrowEntity::Tick())
- if (GetProjectileKind() != pkArrow)
- {
- BroadcastMovementUpdate();
- }
+ BroadcastMovementUpdate();
}
diff --git a/src/Generating/BioGen.cpp b/src/Generating/BioGen.cpp
index 265db30ad..867155ad2 100644
--- a/src/Generating/BioGen.cpp
+++ b/src/Generating/BioGen.cpp
@@ -941,21 +941,21 @@ public:
cBioGenGrown(int a_Seed)
{
auto FinalRivers =
- std::make_shared<cIntGenSmooth<8>> (a_Seed + 1,
- std::make_shared<cIntGenZoom <10>> (a_Seed + 2,
- std::make_shared<cIntGenRiver <7>> (a_Seed + 3,
- std::make_shared<cIntGenZoom <9>> (a_Seed + 4,
- std::make_shared<cIntGenSmooth<6>> (a_Seed + 5,
- std::make_shared<cIntGenZoom <8>> (a_Seed + 8,
- std::make_shared<cIntGenSmooth<6>> (a_Seed + 5,
- std::make_shared<cIntGenZoom <8>> (a_Seed + 9,
- std::make_shared<cIntGenSmooth<6>> (a_Seed + 5,
- std::make_shared<cIntGenZoom <8>> (a_Seed + 10,
- std::make_shared<cIntGenSmooth<6>> (a_Seed + 5,
- std::make_shared<cIntGenSmooth<8>> (a_Seed + 6,
- std::make_shared<cIntGenZoom <10>> (a_Seed + 11,
- std::make_shared<cIntGenChoice<2, 7>>(a_Seed + 12
- ))))))))))))));
+
+ std::make_shared<cIntGenChoice<2, 7>>(a_Seed + 12)
+ | MakeIntGen<cIntGenZoom <10>>(a_Seed + 11)
+ | MakeIntGen<cIntGenSmooth<8>>(a_Seed + 6)
+ | MakeIntGen<cIntGenSmooth<6>>(a_Seed + 5)
+ | MakeIntGen<cIntGenZoom <8>>(a_Seed + 10)
+ | MakeIntGen<cIntGenSmooth<6>>(a_Seed + 5)
+ | MakeIntGen<cIntGenZoom <8>>(a_Seed + 9)
+ | MakeIntGen<cIntGenSmooth<6>>(a_Seed + 5)
+ | MakeIntGen<cIntGenZoom <8>>(a_Seed + 8)
+ | MakeIntGen<cIntGenSmooth<6>>(a_Seed + 5)
+ | MakeIntGen<cIntGenZoom <9>>(a_Seed + 4)
+ | MakeIntGen<cIntGenRiver <7>>(a_Seed + 3)
+ | MakeIntGen<cIntGenZoom <10>>(a_Seed + 2)
+ | MakeIntGen<cIntGenSmooth<8>>(a_Seed + 1);
auto alteration =
std::make_shared<cIntGenZoom <8>>(a_Seed,
@@ -1000,9 +1000,9 @@ public:
std::make_shared<cIntGenReplaceRandomly<6>> (a_Seed + 101, bgIce, bgTemperate, 150,
std::make_shared<cIntGenAddIslands <6>> (a_Seed + 2000, 200,
std::make_shared<cIntGenSetRandomly <6>> (a_Seed + 9, 50, bgOcean,
- std::make_shared<cIntGenZoom <6>> (a_Seed + 10,
- std::make_shared<cIntGenLandOcean <5>> (a_Seed + 100, 30
- )))))))))))))))))))))))))))))));
+ std::make_shared<cIntGenLandOcean <5>> (a_Seed + 100, 30)
+ | MakeIntGen<cIntGenZoom <6>> (a_Seed + 10)
+ )))))))))))))))))))))))))))));
m_Gen =
std::make_shared<cIntGenSmooth <16>>(a_Seed,
diff --git a/src/Generating/IntGen.h b/src/Generating/IntGen.h
index b25e378c0..854563f41 100644
--- a/src/Generating/IntGen.h
+++ b/src/Generating/IntGen.h
@@ -31,6 +31,8 @@ by using templates.
#include "../BiomeDef.h"
+#include <tuple>
+
@@ -53,6 +55,9 @@ template <int SizeX, int SizeZ = SizeX>
class cIntGen
{
public:
+
+ typedef cIntGen<SizeX, SizeZ> IntGenType;
+
/** Force a virtual destructor in all descendants.
Descendants contain virtual functions and are referred to via pointer-to-base, so they need a virtual destructor. */
virtual ~cIntGen() {}
@@ -62,9 +67,70 @@ public:
/** Generates the array of templated size into a_Values, based on given min coords. */
virtual void GetInts(int a_MinX, int a_MinZ, Values & a_Values) = 0;
+
+};
+
+// Code adapted from http://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer
+
+template<int... >
+struct sSeq
+{
+};
+
+template<int N, int... S>
+struct sGens : sGens<N - 1, N - 1, S...>
+{
+};
+
+template<int... S>
+struct sGens<0, S...>
+{
+ typedef sSeq<S...> type;
+};
+
+
+template<class Gen, class... Args>
+class cIntGenFactory
+{
+
+public:
+
+ typedef Gen Generator;
+
+ cIntGenFactory(Args&&... a_args) :
+ m_args(std::make_tuple<Args...>(std::forward<Args>(a_args)...))
+ {
+ }
+
+ template <class LhsGen>
+ std::shared_ptr<Gen> construct(LhsGen&& a_Lhs)
+ {
+ return construct_impl<LhsGen>(std::forward<LhsGen>(a_Lhs), typename sGens<sizeof...(Args)>::type());
+ }
+
+
+private:
+ std::tuple<Args...> m_args;
+
+ template <class LhsGen, int... S>
+ std::shared_ptr<Gen> construct_impl(LhsGen&& a_Lhs, sSeq<S...>)
+ {
+ return std::make_shared<Gen>(std::get<S>(m_args)..., std::forward<LhsGen>(a_Lhs));
+ }
+
};
+template<class T, class RhsGen, class... Args>
+std::shared_ptr<RhsGen> operator| (std::shared_ptr<T> a_Lhs, cIntGenFactory<RhsGen, Args...> a_Rhs)
+{
+ return a_Rhs.construct(static_cast<std::shared_ptr<typename T::IntGenType>>(a_Lhs));
+}
+template<class Gen, class... Args>
+cIntGenFactory<Gen, Args...> MakeIntGen(Args&&... a_Args)
+{
+ return cIntGenFactory<Gen, Args...>(std::forward<Args>(a_Args)...);
+}
@@ -688,7 +754,7 @@ public:
int IdxZ = z * SizeX;
for (int x = 0; x < SizeX; x++)
{
- int val = a_Values[x + IdxZ];
+ size_t val = (size_t)a_Values[x + IdxZ];
const cBiomesInGroups & Biomes = (val > bgfRare) ?
rareBiomesInGroups[(val & (bgfRare - 1)) % ARRAYCOUNT(rareBiomesInGroups)] :
biomesInGroups[val % ARRAYCOUNT(biomesInGroups)];
diff --git a/src/World.cpp b/src/World.cpp
index 292ff9b94..7d63a8a52 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -259,9 +259,9 @@ void cWorld::cTickThread::Execute(void)
////////////////////////////////////////////////////////////////////////////////
// cWorld:
-cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AString & a_OverworldName) :
+cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AString & a_LinkedOverworldName) :
m_WorldName(a_WorldName),
- m_OverworldName(a_OverworldName),
+ m_LinkedOverworldName(a_LinkedOverworldName),
m_IniFileName(m_WorldName + "/world.ini"),
m_StorageSchema("Default"),
#ifdef __arm__
@@ -604,12 +604,12 @@ void cWorld::Start(void)
if (GetDimension() == dimOverworld)
{
- m_NetherWorldName = IniFile.GetValueSet("LinkedWorlds", "NetherWorldName", GetName() + "_nether");
- m_EndWorldName = IniFile.GetValueSet("LinkedWorlds", "EndWorldName", GetName() + "_end");
+ m_LinkedNetherWorldName = IniFile.GetValueSet("LinkedWorlds", "NetherWorldName", GetName() + "_nether");
+ m_LinkedEndWorldName = IniFile.GetValueSet("LinkedWorlds", "EndWorldName", GetName() + "_end");
}
else
{
- m_OverworldName = IniFile.GetValueSet("LinkedWorlds", "OverworldName", GetLinkedOverworldName());
+ m_LinkedOverworldName = IniFile.GetValueSet("LinkedWorlds", "OverworldName", GetLinkedOverworldName());
}
// Adjust the enum-backed variables into their respective bounds:
@@ -884,18 +884,18 @@ void cWorld::Stop(void)
IniFile.ReadFile(m_IniFileName);
if (GetDimension() == dimOverworld)
{
- IniFile.SetValue("LinkedWorlds", "NetherWorldName", m_NetherWorldName);
- IniFile.SetValue("LinkedWorlds", "EndWorldName", m_EndWorldName);
+ IniFile.SetValue("LinkedWorlds", "NetherWorldName", m_LinkedNetherWorldName);
+ IniFile.SetValue("LinkedWorlds", "EndWorldName", m_LinkedEndWorldName);
}
else
{
- IniFile.SetValue("LinkedWorlds", "OverworldName", m_OverworldName);
+ IniFile.SetValue("LinkedWorlds", "OverworldName", m_LinkedOverworldName);
}
- IniFile.SetValueI("Physics", "TNTShrapnelLevel", (int)m_TNTShrapnelLevel);
+ IniFile.SetValueI("Physics", "TNTShrapnelLevel", static_cast<int>(m_TNTShrapnelLevel));
IniFile.SetValueB("Mechanics", "CommandBlocksEnabled", m_bCommandBlocksEnabled);
IniFile.SetValueB("Mechanics", "UseChatPrefixes", m_bUseChatPrefixes);
IniFile.SetValueB("General", "IsDaylightCycleEnabled", m_IsDaylightCycleEnabled);
- IniFile.SetValueI("General", "Weather", (int)m_Weather);
+ IniFile.SetValueI("General", "Weather", static_cast<int>(m_Weather));
IniFile.SetValueI("General", "TimeInTicks", GetTimeOfDay());
IniFile.WriteFile(m_IniFileName);
@@ -3167,14 +3167,14 @@ void cWorld::SaveAllChunks(void)
void cWorld::QueueSaveAllChunks(void)
{
- QueueTask(make_unique<cWorld::cTaskSaveAllChunks>());
+ QueueTask(std::make_shared<cWorld::cTaskSaveAllChunks>());
}
-void cWorld::QueueTask(std::unique_ptr<cTask> a_Task)
+void cWorld::QueueTask(cTaskPtr a_Task)
{
cCSLock Lock(m_CSTasks);
m_Tasks.push_back(std::move(a_Task));
@@ -3184,7 +3184,7 @@ void cWorld::QueueTask(std::unique_ptr<cTask> a_Task)
-void cWorld::ScheduleTask(int a_DelayTicks, cTask * a_Task)
+void cWorld::ScheduleTask(int a_DelayTicks, cTaskPtr a_Task)
{
Int64 TargetTick = a_DelayTicks + std::chrono::duration_cast<cTickTimeLong>(m_WorldAge).count();
@@ -3194,11 +3194,11 @@ void cWorld::ScheduleTask(int a_DelayTicks, cTask * a_Task)
{
if ((*itr)->m_TargetTick >= TargetTick)
{
- m_ScheduledTasks.insert(itr, make_unique<cScheduledTask>(TargetTick, a_Task));
+ m_ScheduledTasks.insert(itr, cScheduledTaskPtr(new cScheduledTask(TargetTick, a_Task)));
return;
}
}
- m_ScheduledTasks.push_back(make_unique<cScheduledTask>(TargetTick, a_Task));
+ m_ScheduledTasks.push_back(cScheduledTaskPtr(new cScheduledTask(TargetTick, a_Task)));
}
diff --git a/src/World.h b/src/World.h
index 0decc8c6e..ffc10a9e4 100644
--- a/src/World.h
+++ b/src/World.h
@@ -106,7 +106,8 @@ public:
virtual void Run(cWorld & a_World) = 0;
} ;
- typedef std::vector<std::unique_ptr<cTask>> cTasks;
+ typedef SharedPtr<cTask> cTaskPtr;
+ typedef std::vector<cTaskPtr> cTasks;
class cTaskSaveAllChunks :
@@ -673,14 +674,14 @@ public:
bool ShouldBroadcastAchievementMessages(void) const { return m_BroadcastAchievementMessages; }
- AString GetNetherWorldName(void) const { return m_NetherWorldName; }
- void SetNetherWorldName(const AString & a_Name) { m_NetherWorldName = a_Name; }
+ AString GetLinkedNetherWorldName(void) const { return m_LinkedNetherWorldName; }
+ void SetLinkedNetherWorldName(const AString & a_Name) { m_LinkedNetherWorldName = a_Name; }
- AString GetEndWorldName(void) const { return m_EndWorldName; }
- void SetEndWorldName(const AString & a_Name) { m_EndWorldName = a_Name; }
+ AString GetLinkedEndWorldName(void) const { return m_LinkedEndWorldName; }
+ void SetLinkedEndWorldName(const AString & a_Name) { m_LinkedEndWorldName = a_Name; }
- AString GetLinkedOverworldName(void) const { return m_OverworldName; }
- void SetLinkedOverworldName(const AString & a_Name) { m_OverworldName = a_Name; }
+ AString GetLinkedOverworldName(void) const { return m_LinkedOverworldName; }
+ void SetLinkedOverworldName(const AString & a_Name) { m_LinkedOverworldName = a_Name; }
// tolua_end
@@ -691,11 +692,10 @@ public:
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(std::unique_ptr<cTask> a_Task); // Exported in ManualBindings.cpp
+ void QueueTask(cTaskPtr a_Task); // Exported in ManualBindings.cpp
- /** Queues a task onto the tick thread, with the specified delay.
- The task object will be deleted once the task is finished */
- void ScheduleTask(int a_DelayTicks, cTask * a_Task);
+ /** Queues a task onto the tick thread, with the specified delay. */
+ void ScheduleTask(int a_DelayTicks, cTaskPtr a_Task);
/** Returns the number of chunks loaded */
int GetNumChunks() const; // tolua_export
@@ -867,20 +867,16 @@ private:
{
public:
Int64 m_TargetTick;
- cTask * m_Task;
+ cTaskPtr m_Task;
/** Creates a new scheduled task; takes ownership of the task object passed to it. */
- cScheduledTask(Int64 a_TargetTick, cTask * a_Task) :
+ cScheduledTask(Int64 a_TargetTick, cTaskPtr a_Task) :
m_TargetTick(a_TargetTick),
m_Task(a_Task)
{
}
- virtual ~cScheduledTask()
- {
- delete m_Task;
- m_Task = nullptr;
- }
+ virtual ~cScheduledTask() {}
};
typedef std::unique_ptr<cScheduledTask> cScheduledTaskPtr;
@@ -889,10 +885,9 @@ private:
AString m_WorldName;
- /** The name of the world that a portal in this world should link to
- Only has effect if this world is a nether or end world, as it is used by entities to see which world to teleport to when in a portal
- */
- AString m_OverworldName;
+ /** The name of the overworld that portals in this world should link to.
+ Only has effect if this world is a Nether or End world. */
+ AString m_LinkedOverworldName;
AString m_IniFileName;
@@ -985,11 +980,13 @@ private:
/** The maximum view distance that a player can have in this world. */
int m_MaxViewDistance;
- /** Name of the nether world */
- AString m_NetherWorldName;
+ /** Name of the nether world - where Nether portals should teleport.
+ Only used when this world is an Overworld. */
+ AString m_LinkedNetherWorldName;
- /** Name of the end world */
- AString m_EndWorldName;
+ /** Name of the End world - where End portals should teleport.
+ Only used when this world is an Overworld. */
+ AString m_LinkedEndWorldName;
cChunkGenerator m_Generator;
@@ -1049,7 +1046,7 @@ private:
cSetChunkDataPtrs m_SetChunkDataQueue;
- cWorld(const AString & a_WorldName, eDimension a_Dimension = dimOverworld, const AString & a_OverworldName = "");
+ cWorld(const AString & a_WorldName, eDimension a_Dimension = dimOverworld, const AString & a_LinkedOverworldName = "");
virtual ~cWorld();
void Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec);