diff options
Diffstat (limited to '')
-rw-r--r-- | src/Bindings/PluginLua.cpp | 249 | ||||
-rw-r--r-- | src/BiomeDef.cpp | 7 | ||||
-rw-r--r-- | src/BlockID.cpp | 29 | ||||
-rw-r--r-- | src/Blocks/BlockButton.h | 6 | ||||
-rw-r--r-- | src/Entities/Player.cpp | 6 | ||||
-rw-r--r-- | src/OSSupport/File.cpp | 102 | ||||
-rw-r--r-- | src/OSSupport/File.h | 16 | ||||
-rw-r--r-- | src/Root.cpp | 28 | ||||
-rw-r--r-- | src/Root.h | 3 | ||||
-rw-r--r-- | src/Vector3.h | 9 | ||||
-rw-r--r-- | src/main.cpp | 233 |
11 files changed, 638 insertions, 50 deletions
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index 0a2a8411d..9bbac92b0 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -208,6 +208,10 @@ void cPluginLua::OnDisable(void) void cPluginLua::Tick(float a_Dt) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return; + } cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_TICK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { @@ -222,6 +226,10 @@ void cPluginLua::Tick(float a_Dt) bool cPluginLua::OnBlockSpread(cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_SPREAD]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -242,6 +250,10 @@ bool cPluginLua::OnBlockSpread(cWorld & a_World, int a_BlockX, int a_BlockY, int bool cPluginLua::OnBlockToPickups(cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_TO_PICKUPS]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -262,6 +274,10 @@ bool cPluginLua::OnBlockToPickups(cWorld & a_World, cEntity * a_Digger, int a_Bl bool cPluginLua::OnChat(cPlayer & a_Player, AString & a_Message) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHAT]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -282,6 +298,10 @@ bool cPluginLua::OnChat(cPlayer & a_Player, AString & a_Message) bool cPluginLua::OnChunkAvailable(cWorld & a_World, int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_AVAILABLE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -302,6 +322,10 @@ bool cPluginLua::OnChunkAvailable(cWorld & a_World, int a_ChunkX, int a_ChunkZ) bool cPluginLua::OnChunkGenerated(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_GENERATED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -322,6 +346,10 @@ bool cPluginLua::OnChunkGenerated(cWorld & a_World, int a_ChunkX, int a_ChunkZ, bool cPluginLua::OnChunkGenerating(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_GENERATING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -342,6 +370,10 @@ bool cPluginLua::OnChunkGenerating(cWorld & a_World, int a_ChunkX, int a_ChunkZ, bool cPluginLua::OnChunkUnloaded(cWorld & a_World, int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_UNLOADED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -362,6 +394,10 @@ bool cPluginLua::OnChunkUnloaded(cWorld & a_World, int a_ChunkX, int a_ChunkZ) bool cPluginLua::OnChunkUnloading(cWorld & a_World, int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_UNLOADING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -382,6 +418,10 @@ bool cPluginLua::OnChunkUnloading(cWorld & a_World, int a_ChunkX, int a_ChunkZ) bool cPluginLua::OnCollectingPickup(cPlayer & a_Player, cPickup & a_Pickup) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_COLLECTING_PICKUP]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -402,6 +442,10 @@ bool cPluginLua::OnCollectingPickup(cPlayer & a_Player, cPickup & a_Pickup) bool cPluginLua::OnCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CRAFTING_NO_RECIPE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -422,6 +466,10 @@ bool cPluginLua::OnCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid, bool cPluginLua::OnDisconnect(cClientHandle & a_Client, const AString & a_Reason) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_DISCONNECT]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -442,6 +490,10 @@ bool cPluginLua::OnDisconnect(cClientHandle & a_Client, const AString & a_Reason bool cPluginLua::OnEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_ADD_EFFECT]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -462,6 +514,10 @@ bool cPluginLua::OnEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_E bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXECUTE_COMMAND]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -482,6 +538,10 @@ bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Sp bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXPLODED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -519,6 +579,10 @@ bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_Can bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXPLODING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -556,6 +620,10 @@ bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool & bool cPluginLua::OnHandshake(cClientHandle & a_Client, const AString & a_Username) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HANDSHAKE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -576,8 +644,11 @@ bool cPluginLua::OnHandshake(cClientHandle & a_Client, const AString & a_Usernam bool cPluginLua::OnHopperPullingItem(cWorld & a_World, cHopperEntity & a_Hopper, int a_DstSlotNum, cBlockEntityWithItems & a_SrcEntity, int a_SrcSlotNum) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; - cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HOPPER_PULLING_ITEM]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { @@ -597,6 +668,10 @@ bool cPluginLua::OnHopperPullingItem(cWorld & a_World, cHopperEntity & a_Hopper, bool cPluginLua::OnHopperPushingItem(cWorld & a_World, cHopperEntity & a_Hopper, int a_SrcSlotNum, cBlockEntityWithItems & a_DstEntity, int a_DstSlotNum) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HOPPER_PUSHING_ITEM]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -617,6 +692,10 @@ bool cPluginLua::OnHopperPushingItem(cWorld & a_World, cHopperEntity & a_Hopper, bool cPluginLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer, TakeDamageInfo & a_TDI) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_KILLING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -637,6 +716,10 @@ bool cPluginLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer, TakeDamageInf bool cPluginLua::OnLogin(cClientHandle & a_Client, int a_ProtocolVersion, const AString & a_Username) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_LOGIN]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -657,6 +740,10 @@ bool cPluginLua::OnLogin(cClientHandle & a_Client, int a_ProtocolVersion, const bool cPluginLua::OnPlayerAnimation(cPlayer & a_Player, int a_Animation) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_ANIMATION]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -677,6 +764,10 @@ bool cPluginLua::OnPlayerAnimation(cPlayer & a_Player, int a_Animation) bool cPluginLua::OnPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_BREAKING_BLOCK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -697,6 +788,10 @@ bool cPluginLua::OnPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_B bool cPluginLua::OnPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_BROKEN_BLOCK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -717,6 +812,10 @@ bool cPluginLua::OnPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_Blo bool cPluginLua::OnPlayerDestroyed(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_DESTROYED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -737,6 +836,10 @@ bool cPluginLua::OnPlayerDestroyed(cPlayer & a_Player) bool cPluginLua::OnPlayerEating(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_EATING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -757,6 +860,10 @@ bool cPluginLua::OnPlayerEating(cPlayer & a_Player) bool cPluginLua::OnPlayerFoodLevelChange(cPlayer & a_Player, int a_NewFoodLevel) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FOOD_LEVEL_CHANGE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -777,6 +884,10 @@ bool cPluginLua::OnPlayerFoodLevelChange(cPlayer & a_Player, int a_NewFoodLevel) bool cPluginLua::OnPlayerFished(cPlayer & a_Player, const cItems & a_Reward) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FISHED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -797,6 +908,10 @@ bool cPluginLua::OnPlayerFished(cPlayer & a_Player, const cItems & a_Reward) bool cPluginLua::OnPlayerFishing(cPlayer & a_Player, cItems & a_Reward) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FISHING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -817,6 +932,10 @@ bool cPluginLua::OnPlayerFishing(cPlayer & a_Player, cItems & a_Reward) bool cPluginLua::OnPlayerJoined(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_JOINED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -837,6 +956,10 @@ bool cPluginLua::OnPlayerJoined(cPlayer & a_Player) bool cPluginLua::OnPlayerLeftClick(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_LEFT_CLICK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -857,6 +980,10 @@ bool cPluginLua::OnPlayerLeftClick(cPlayer & a_Player, int a_BlockX, int a_Block bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_MOVING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -877,6 +1004,10 @@ bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d & a_OldPositi bool cPluginLua::OnEntityTeleport(cEntity & a_Entity, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_TELEPORT]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -897,6 +1028,10 @@ bool cPluginLua::OnEntityTeleport(cEntity & a_Entity, const Vector3d & a_OldPosi bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACED_BLOCK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -922,6 +1057,10 @@ bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_Blo bool cPluginLua::OnPlayerPlacingBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACING_BLOCK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -947,6 +1086,10 @@ bool cPluginLua::OnPlayerPlacingBlock(cPlayer & a_Player, const sSetBlock & a_Bl bool cPluginLua::OnPlayerRightClick(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_RIGHT_CLICK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -967,6 +1110,10 @@ bool cPluginLua::OnPlayerRightClick(cPlayer & a_Player, int a_BlockX, int a_Bloc bool cPluginLua::OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_RIGHT_CLICKING_ENTITY]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -987,6 +1134,10 @@ bool cPluginLua::OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Ent bool cPluginLua::OnPlayerShooting(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_SHOOTING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1007,6 +1158,10 @@ bool cPluginLua::OnPlayerShooting(cPlayer & a_Player) bool cPluginLua::OnPlayerSpawned(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_SPAWNED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1027,6 +1182,10 @@ bool cPluginLua::OnPlayerSpawned(cPlayer & a_Player) bool cPluginLua::OnPlayerTossingItem(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_TOSSING_ITEM]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1047,6 +1206,10 @@ bool cPluginLua::OnPlayerTossingItem(cPlayer & a_Player) bool cPluginLua::OnPlayerUsedBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USED_BLOCK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1067,6 +1230,10 @@ bool cPluginLua::OnPlayerUsedBlock(cPlayer & a_Player, int a_BlockX, int a_Block bool cPluginLua::OnPlayerUsedItem(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USED_ITEM]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1087,6 +1254,10 @@ bool cPluginLua::OnPlayerUsedItem(cPlayer & a_Player, int a_BlockX, int a_BlockY bool cPluginLua::OnPlayerUsingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USING_BLOCK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1107,6 +1278,10 @@ bool cPluginLua::OnPlayerUsingBlock(cPlayer & a_Player, int a_BlockX, int a_Bloc bool cPluginLua::OnPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USING_ITEM]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1127,6 +1302,10 @@ bool cPluginLua::OnPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_Block bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGIN_MESSAGE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1147,6 +1326,10 @@ bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Cha bool cPluginLua::OnPluginsLoaded(void) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGINS_LOADED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1165,6 +1348,10 @@ bool cPluginLua::OnPluginsLoaded(void) bool cPluginLua::OnPostCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_POST_CRAFTING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1185,6 +1372,10 @@ bool cPluginLua::OnPostCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCra bool cPluginLua::OnPreCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PRE_CRAFTING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1205,6 +1396,10 @@ bool cPluginLua::OnPreCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraf bool cPluginLua::OnProjectileHitBlock(cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_BLOCK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1225,6 +1420,10 @@ bool cPluginLua::OnProjectileHitBlock(cProjectileEntity & a_Projectile, int a_Bl bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity & a_HitEntity) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_ENTITY]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1245,6 +1444,10 @@ bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_ServerDescription, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SERVER_PING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1265,6 +1468,10 @@ bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_Server bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNED_ENTITY]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1285,6 +1492,10 @@ bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity) bool cPluginLua::OnSpawnedMonster(cWorld & a_World, cMonster & a_Monster) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNED_MONSTER]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1305,6 +1516,10 @@ bool cPluginLua::OnSpawnedMonster(cWorld & a_World, cMonster & a_Monster) bool cPluginLua::OnSpawningEntity(cWorld & a_World, cEntity & a_Entity) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNING_ENTITY]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1325,6 +1540,10 @@ bool cPluginLua::OnSpawningEntity(cWorld & a_World, cEntity & a_Entity) bool cPluginLua::OnSpawningMonster(cWorld & a_World, cMonster & a_Monster) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNING_MONSTER]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1345,6 +1564,10 @@ bool cPluginLua::OnSpawningMonster(cWorld & a_World, cMonster & a_Monster) bool cPluginLua::OnTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TDI) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_TAKE_DAMAGE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1370,6 +1593,10 @@ bool cPluginLua::OnUpdatedSign( ) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATED_SIGN]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1395,6 +1622,10 @@ bool cPluginLua::OnUpdatingSign( ) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATING_SIGN]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1415,6 +1646,10 @@ bool cPluginLua::OnUpdatingSign( bool cPluginLua::OnWeatherChanged(cWorld & a_World) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1435,6 +1670,10 @@ bool cPluginLua::OnWeatherChanged(cWorld & a_World) bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1455,6 +1694,10 @@ bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather) bool cPluginLua::OnWorldStarted(cWorld & a_World) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WORLD_STARTED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { @@ -1470,6 +1713,10 @@ bool cPluginLua::OnWorldStarted(cWorld & a_World) bool cPluginLua::OnWorldTick(cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WORLD_TICK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { diff --git a/src/BiomeDef.cpp b/src/BiomeDef.cpp index 3e34ebdbe..a2a06f10c 100644 --- a/src/BiomeDef.cpp +++ b/src/BiomeDef.cpp @@ -338,6 +338,13 @@ int GetSnowStartHeight(EMCSBiome a_Biome) // These biomes don't actualy have any downfall. return 1000; } + + case biNether: + case biEnd: + { + // These shouldn't get any snow at all. + return 9999; + } default: { diff --git a/src/BlockID.cpp b/src/BlockID.cpp index 06f4232d3..7f0db3cfc 100644 --- a/src/BlockID.cpp +++ b/src/BlockID.cpp @@ -26,8 +26,18 @@ class cBlockIDMap typedef std::map<AString, std::pair<short, short>, Comparator> ItemMap; public: + static bool m_bHasRunInit; + cBlockIDMap(void) { + // Dont load items.ini on construct, this will search the wrong path when running as a service. + } + + + void init() + { + m_bHasRunInit = true; + cIniFile Ini; if (!Ini.ReadFile("items.ini")) { @@ -174,7 +184,7 @@ protected: - +bool cBlockIDMap::m_bHasRunInit = false; static cBlockIDMap gsBlockIDMap; @@ -209,6 +219,10 @@ int BlockStringToType(const AString & a_BlockTypeString) return res; } + if (!gsBlockIDMap.m_bHasRunInit) + { + gsBlockIDMap.init(); + } return gsBlockIDMap.Resolve(TrimString(a_BlockTypeString)); } @@ -222,6 +236,11 @@ bool StringToItem(const AString & a_ItemTypeString, cItem & a_Item) { ItemName = ItemName.substr(10); } + + if (!gsBlockIDMap.m_bHasRunInit) + { + gsBlockIDMap.init(); + } return gsBlockIDMap.ResolveItem(ItemName, a_Item); } @@ -231,6 +250,10 @@ bool StringToItem(const AString & a_ItemTypeString, cItem & a_Item) AString ItemToString(const cItem & a_Item) { + if (!gsBlockIDMap.m_bHasRunInit) + { + gsBlockIDMap.init(); + } return gsBlockIDMap.Desolve(a_Item.m_ItemType, a_Item.m_ItemDamage); } @@ -240,6 +263,10 @@ AString ItemToString(const cItem & a_Item) AString ItemTypeToString(short a_ItemType) { + if (!gsBlockIDMap.m_bHasRunInit) + { + gsBlockIDMap.init(); + } return gsBlockIDMap.Desolve(a_ItemType, -1); } diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h index 8e4f04740..d24c7d952 100644 --- a/src/Blocks/BlockButton.h +++ b/src/Blocks/BlockButton.h @@ -61,14 +61,16 @@ public: { switch (a_BlockFace) { + case BLOCK_FACE_YP: return 0x5; case BLOCK_FACE_ZM: return 0x4; case BLOCK_FACE_ZP: return 0x3; case BLOCK_FACE_XM: return 0x2; case BLOCK_FACE_XP: return 0x1; + case BLOCK_FACE_YM: return 0x0; default: { ASSERT(!"Unhandled block face!"); - return 0x0; // No idea, give a special meta (button in centre of block) + return 0x0; } } } @@ -77,10 +79,12 @@ public: { switch (a_Meta & 0x7) { + case 0x0: return BLOCK_FACE_YM; case 0x1: return BLOCK_FACE_XP; case 0x2: return BLOCK_FACE_XM; case 0x3: return BLOCK_FACE_ZP; case 0x4: return BLOCK_FACE_ZM; + case 0x5: return BLOCK_FACE_YP; default: { ASSERT(!"Unhandled block meta!"); diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index c89e7b87c..2549a8481 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1603,6 +1603,9 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) m_ClientHandle->SendRespawn(a_World->GetDimension()); } + // Broadcast for other people that the player is gone. + GetWorld()->BroadcastDestroyEntity(*this); + // Remove player from the old world SetWorldTravellingFrom(GetWorld()); // cChunk handles entity removal GetWorld()->RemovePlayer(this, false); @@ -1619,6 +1622,9 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) { m_ClientHandle->SendWeather(a_World->GetWeather()); } + + // Broadcast the player into the new world. + a_World->BroadcastSpawnEntity(*this); return true; } diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp index 8957dfaef..43105b230 100644 --- a/src/OSSupport/File.cpp +++ b/src/OSSupport/File.cpp @@ -453,6 +453,108 @@ AString cFile::ReadWholeFile(const AString & a_FileName) +AString cFile::ChangeFileExt(const AString & a_FileName, const AString & a_NewExt) +{ + auto res = a_FileName; + + // If the path separator is the last character of the string, return the string unmodified (refers to a folder): + #if defined(_MSC_VER) + // Find either path separator - MSVC CRT accepts slashes as separators, too + auto LastPathSep = res.find_last_of("/\\"); + #elif defined(_WIN32) + // Windows with different CRTs support only the backslash separator + auto LastPathSep = res.rfind('\\'); + #else + // Linux supports only the slash separator + auto LastPathSep = res.rfind('/'); + #endif + if ((LastPathSep != AString::npos) && (LastPathSep + 1 == res.size())) + { + return res; + } + + // Append or replace the extension: + auto DotPos = res.rfind('.'); + if ( + (DotPos == AString::npos) || // No dot found + ((LastPathSep != AString::npos) && (LastPathSep > DotPos)) // Last dot is before the last path separator (-> in folder name) + ) + { + // No extension, just append the new one: + if (!a_NewExt.empty() && (a_NewExt[0] != '.')) + { + // a_NewExt doesn't start with a dot, insert one: + res.push_back('.'); + } + res.append(a_NewExt); + } + else + { + // Replace existing extension: + if (!a_NewExt.empty() && (a_NewExt[0] != '.')) + { + // a_NewExt doesn't start with a dot, keep the current one: + res.erase(DotPos + 1, AString::npos); + } + else + { + res.erase(DotPos, AString::npos); + } + res.append(a_NewExt); + } + return res; +} + + + + + +unsigned cFile::GetLastModificationTime(const AString & a_FileName) +{ + struct stat st; + if (stat(a_FileName.c_str(), &st) < 0) + { + return 0; + } + #ifdef _WIN32 + // Windows returns times in local time already + return static_cast<unsigned>(st.st_mtime); + #else + // Linux returns UTC time, convert to local timezone: + return static_cast<unsigned>(mktime(localtime(&st.st_mtime))); + #endif +} + + + + + +AString cFile::GetPathSeparator(void) +{ + #ifdef _WIN32 + return "\\"; + #else + return "/"; + #endif +} + + + + + +AString cFile::GetExecutableExt(void) +{ + #ifdef _WIN32 + return ".exe"; + #else + return ""; + #endif +} + + + + + int cFile::Printf(const char * a_Fmt, ...) { AString buf; diff --git a/src/OSSupport/File.h b/src/OSSupport/File.h index ac6d1ab21..6ee080480 100644 --- a/src/OSSupport/File.h +++ b/src/OSSupport/File.h @@ -127,6 +127,22 @@ public: /** Returns the entire contents of the specified file as a string. Returns empty string on error. */ static AString ReadWholeFile(const AString & a_FileName); + /** Returns a_FileName with its extension changed to a_NewExt. + a_FileName may contain path specification. */ + static AString ChangeFileExt(const AString & a_FileName, const AString & a_NewExt); + + /** Returns the last modification time (in current timezone) of the specified file. + The value returned is in the same units as the value returned by time() function. + If the file is not found / accessible, zero is returned. */ + static unsigned GetLastModificationTime(const AString & a_FileName); + + /** Returns the path separator used by the current platform. + Note that the platform / CRT may support additional path separators (such as slashes on Windows), these don't get reported. */ + static AString GetPathSeparator(void); + + /** Returns the customary executable extension used by the current platform. */ + static AString GetExecutableExt(void); + // tolua_end /** Returns the list of all items in the specified folder (files, folders, nix pipes, whatever's there). */ diff --git a/src/Root.cpp b/src/Root.cpp index 27d87c717..690bd7357 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -33,7 +33,8 @@ -cRoot* cRoot::s_Root = nullptr; +cRoot * cRoot::s_Root = nullptr; +bool cRoot::m_ShouldStop = false; @@ -48,7 +49,6 @@ cRoot::cRoot(void) : m_WebAdmin(nullptr), m_PluginManager(nullptr), m_MojangAPI(nullptr), - m_bStop(false), m_bRestart(false) { s_Root = this; @@ -71,7 +71,7 @@ void cRoot::InputThread(cRoot & a_Params) { cLogCommandOutputCallback Output; - while (!a_Params.m_bStop && !a_Params.m_bRestart && !m_TerminateEventRaised && std::cin.good()) + while (!cRoot::m_ShouldStop && !a_Params.m_bRestart && !m_TerminateEventRaised && std::cin.good()) { AString Command; std::getline(std::cin, Command); @@ -83,8 +83,12 @@ void cRoot::InputThread(cRoot & a_Params) if (m_TerminateEventRaised || !std::cin.good()) { - // We have come here because the std::cin has received an EOF / a terminate signal has been sent, and the server is still running; stop the server: - a_Params.m_bStop = true; + // We have come here because the std::cin has received an EOF / a terminate signal has been sent, and the server is still running + // Stop the server: + if (!m_RunAsService) // Dont kill if running as a service + { + a_Params.m_ShouldStop = true; + } } } @@ -114,8 +118,8 @@ void cRoot::Start(void) cDeadlockDetect dd; - m_bStop = false; - while (!m_bStop) + m_ShouldStop = false; + while (!m_ShouldStop) { auto BeginTime = std::chrono::steady_clock::now(); m_bRestart = false; @@ -203,14 +207,14 @@ void cRoot::Start(void) EnableMenuItem(hmenu, SC_CLOSE, MF_ENABLED); // Re-enable close button #endif - while (!m_bStop && !m_bRestart && !m_TerminateEventRaised) // These are modified by external threads + while (!m_ShouldStop && !m_bRestart && !m_TerminateEventRaised) // These are modified by external threads { std::this_thread::sleep_for(std::chrono::seconds(1)); } if (m_TerminateEventRaised) { - m_bStop = true; + m_ShouldStop = true; } // Stop the server: @@ -221,7 +225,7 @@ void cRoot::Start(void) } // if (m_Server->Start()) else { - m_bStop = true; + m_ShouldStop = true; } delete m_MojangAPI; m_MojangAPI = nullptr; @@ -456,7 +460,7 @@ void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCall // Some commands are built-in: if (a_Cmd == "stop") { - m_bStop = true; + m_ShouldStop = true; } else if (a_Cmd == "restart") { @@ -488,7 +492,7 @@ void cRoot::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback // cRoot handles stopping and restarting due to our access to controlling variables if (a_Cmd == "stop") { - m_bStop = true; + m_ShouldStop = true; return; } else if (a_Cmd == "restart") diff --git a/src/Root.h b/src/Root.h index fdaf444bd..2f9d1eb2c 100644 --- a/src/Root.h +++ b/src/Root.h @@ -46,6 +46,8 @@ public: // tolua_end static bool m_TerminateEventRaised; + static bool m_RunAsService; + static bool m_ShouldStop; cRoot(void); @@ -197,7 +199,6 @@ private: cHTTPServer m_HTTPServer; - bool m_bStop; bool m_bRestart; void LoadGlobalSettings(); diff --git a/src/Vector3.h b/src/Vector3.h index 1f3f6b955..36f277ba4 100644 --- a/src/Vector3.h +++ b/src/Vector3.h @@ -244,6 +244,15 @@ public: ); } + inline Vector3<T> operator / (const Vector3<T> & a_Rhs) + { + return Vector3<T>( + x / a_Rhs.x, + y / a_Rhs.y, + z / a_Rhs.z + ); + } + inline Vector3<T> operator * (T a_v) const { return Vector3<T>( diff --git a/src/main.cpp b/src/main.cpp index 428e89e93..2e7e107f7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,11 +29,24 @@ bool g_ShouldLogCommIn; /** If set to true, the protocols will log each player's outgoing (S->C) communication to a per-connection logfile */ bool g_ShouldLogCommOut; +/** If set to true, binary will attempt to run as a service on Windows */ +bool cRoot::m_RunAsService = false; -/// If defined, a thorough leak finder will be used (debug MSVC only); leaks will be output to the Output window + +#if defined(_WIN32) + SERVICE_STATUS_HANDLE g_StatusHandle = NULL; + HANDLE g_ServiceThread = INVALID_HANDLE_VALUE; + #define SERVICE_NAME "MCServerService" +#endif + + + + + +/** If defined, a thorough leak finder will be used (debug MSVC only); leaks will be output to the Output window */ // _X 2014_02_20: Disabled for canon repo, it makes the debug version too slow in MSVC2013 // and we haven't had a memory leak for over a year anyway. // #define ENABLE_LEAK_FINDER @@ -160,6 +173,7 @@ LONG WINAPI LastChanceExceptionFilter(__in struct _EXCEPTION_POINTERS * a_Except + #ifdef _WIN32 // Handle CTRL events in windows, including console window close BOOL CtrlHandler(DWORD fdwCtrlType) @@ -181,6 +195,167 @@ BOOL CtrlHandler(DWORD fdwCtrlType) //////////////////////////////////////////////////////////////////////////////// +// universalMain - Main startup logic for both standard running and as a service + +void universalMain() +{ + #ifdef _WIN32 + if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE)) + { + LOGERROR("Could not install the Windows CTRL handler!"); + } + #endif + + // Initialize logging subsystem: + cLogger::InitiateMultithreading(); + + // Initialize LibEvent: + cNetworkSingleton::Get(); + + #if !defined(ANDROID_NDK) + try + #endif + { + cRoot Root; + Root.Start(); + } + #if !defined(ANDROID_NDK) + catch (std::exception & e) + { + LOGERROR("Standard exception: %s", e.what()); + } + catch (...) + { + LOGERROR("Unknown exception!"); + } + #endif + + g_ServerTerminated = true; + + // Shutdown all of LibEvent: + cNetworkSingleton::Get().Terminate(); +} + + + + +#if defined(_WIN32) +//////////////////////////////////////////////////////////////////////////////// +// serviceWorkerThread: Keep the service alive + +DWORD WINAPI serviceWorkerThread(LPVOID lpParam) +{ + UNREFERENCED_PARAMETER(lpParam); + + // Do the normal startup + universalMain(); + + return ERROR_SUCCESS; +} + + + + +//////////////////////////////////////////////////////////////////////////////// +// serviceSetState: Set the internal status of the service + +void serviceSetState(DWORD acceptedControls, DWORD newState, DWORD exitCode) +{ + SERVICE_STATUS serviceStatus; + ZeroMemory(&serviceStatus, sizeof(SERVICE_STATUS)); + serviceStatus.dwCheckPoint = 0; + serviceStatus.dwControlsAccepted = acceptedControls; + serviceStatus.dwCurrentState = newState; + serviceStatus.dwServiceSpecificExitCode = 0; + serviceStatus.dwServiceType = SERVICE_WIN32; + serviceStatus.dwWaitHint = 0; + serviceStatus.dwWin32ExitCode = exitCode; + + if (SetServiceStatus(g_StatusHandle, &serviceStatus) == FALSE) + { + LOGERROR("SetServiceStatus() failed\n"); + } +} + + + + +//////////////////////////////////////////////////////////////////////////////// +// serviceCtrlHandler: Handle stop events from the Service Control Manager + +void WINAPI serviceCtrlHandler(DWORD CtrlCode) +{ + switch (CtrlCode) + { + case SERVICE_CONTROL_STOP: + { + cRoot::m_ShouldStop = true; + serviceSetState(0, SERVICE_STOP_PENDING, 0); + break; + } + + default: + { + break; + } + } +} + + + + +//////////////////////////////////////////////////////////////////////////////// +// serviceMain: Startup logic for running as a service + +void WINAPI serviceMain(DWORD argc, TCHAR *argv[]) +{ + #if defined(_DEBUG) && defined(DEBUG_SERVICE_STARTUP) + Sleep(10000); + #endif + + char applicationFilename[MAX_PATH]; + char applicationDirectory[MAX_PATH]; + + GetModuleFileName(NULL, applicationFilename, sizeof(applicationFilename)); // This binary's file path. + + // Strip off the filename, keep only the path: + strncpy_s(applicationDirectory, sizeof(applicationDirectory), applicationFilename, (strrchr(applicationFilename, '\\') - applicationFilename)); + applicationDirectory[strlen(applicationDirectory)] = '\0'; // Make sure new path is null terminated + + // Services are run by the SCM, and inherit its working directory - usually System32. + // Set the working directory to the same location as the binary. + SetCurrentDirectory(applicationDirectory); + + g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, serviceCtrlHandler); + + if (g_StatusHandle == NULL) + { + OutputDebugStringA("RegisterServiceCtrlHandler() failed\n"); + serviceSetState(0, SERVICE_STOPPED, GetLastError()); + return; + } + + serviceSetState(SERVICE_ACCEPT_STOP, SERVICE_RUNNING, 0); + + g_ServiceThread = CreateThread(NULL, 0, serviceWorkerThread, NULL, 0, NULL); + if (g_ServiceThread == NULL) + { + OutputDebugStringA("CreateThread() failed\n"); + serviceSetState(0, SERVICE_STOPPED, GetLastError()); + return; + } + WaitForSingleObject(g_ServiceThread, INFINITE); // Wait here for a stop signal. + + CloseHandle(g_ServiceThread); + + serviceSetState(0, SERVICE_STOPPED, 0); +} +#endif + + + + +//////////////////////////////////////////////////////////////////////////////// // main: int main( int argc, char **argv) @@ -219,13 +394,6 @@ int main( int argc, char **argv) #endif // _WIN32 && !_WIN64 // End of dump-file magic - #ifdef _WIN32 - if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE)) - { - LOGERROR("Could not install the Windows CTRL handler!"); - } - #endif - #if defined(_DEBUG) && defined(_MSC_VER) _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); @@ -280,42 +448,39 @@ int main( int argc, char **argv) { setvbuf(stdout, nullptr, _IONBF, 0); } + else if (NoCaseCompare(Arg, "/service") == 0) + { + cRoot::m_RunAsService = true; + } } // for i - argv[] - - // Initialize logging subsystem: - cLogger::InitiateMultithreading(); - - // Initialize LibEvent: - cNetworkSingleton::Get(); - - #if !defined(ANDROID_NDK) - try - #endif - { - cRoot Root; - Root.Start(); - } - #if !defined(ANDROID_NDK) - catch (std::exception & e) + + #if defined(_WIN32) + // Attempt to run as a service + if (cRoot::m_RunAsService) { - LOGERROR("Standard exception: %s", e.what()); + SERVICE_TABLE_ENTRY ServiceTable[] = + { + { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)serviceMain }, + { NULL, NULL } + }; + + if (StartServiceCtrlDispatcher(ServiceTable) == FALSE) + { + LOGERROR("Attempted, but failed, service startup."); + return GetLastError(); + } } - catch (...) + else + #endif { - LOGERROR("Unknown exception!"); + // Not running as a service, do normal startup + universalMain(); } - #endif - #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) DeinitLeakFinder(); #endif - g_ServerTerminated = true; - - // Shutdown all of LibEvent: - cNetworkSingleton::Get().Terminate(); - return EXIT_SUCCESS; } |