summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--GETTING-STARTED.md17
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua4
-rw-r--r--MCServer/Plugins/Debuggers/Debuggers.lua47
-rw-r--r--MCServer/Plugins/Debuggers/Info.lua2
-rw-r--r--MCServer/Plugins/DumpInfo/Init.lua13
-rw-r--r--MCServer/Plugins/InfoDump.lua7
-rw-r--r--MCServer/delete_windows_service.cmd4
-rw-r--r--MCServer/install_windows_service.cmd7
-rw-r--r--src/Bindings/PluginLua.cpp249
-rw-r--r--src/BiomeDef.cpp7
-rw-r--r--src/BlockID.cpp29
-rw-r--r--src/Blocks/BlockButton.h6
-rw-r--r--src/Entities/Player.cpp6
-rw-r--r--src/OSSupport/File.cpp102
-rw-r--r--src/OSSupport/File.h16
-rw-r--r--src/Root.cpp28
-rw-r--r--src/Root.h3
-rw-r--r--src/Vector3.h9
-rw-r--r--src/main.cpp233
19 files changed, 720 insertions, 69 deletions
diff --git a/GETTING-STARTED.md b/GETTING-STARTED.md
index d78b2f84f..2e2568e64 100644
--- a/GETTING-STARTED.md
+++ b/GETTING-STARTED.md
@@ -19,7 +19,7 @@ Useful Resources
* [Minecraft Wiki](http://minecraft.gamepedia.com/Minecraft_Wiki)
* [Minecraft Protocol Wiki](http://wiki.vg)
* [Lua API Documentation](http://mc-server.xoft.cz/LuaAPI)
- * [VS2008 Download](http://stackoverflow.com/questions/15318560/visual-c-2008-express-download-link-dead)
+ * [VS2013 Community Edition Download](https://www.visualstudio.com/products/visual-studio-community-vs)
Setting up a Dev Environment
============================
@@ -39,12 +39,12 @@ You'll also need CMake to generate the makefile to build from.
**Windows:**
-If you use Windows, your best bet is the MSVC2008 (available as a free download in the Express edition from MS) or MSVS2013 (ditto), solution files for which can be generated with cmake. You'll also need cmake to generate the project files.
+If you use Windows, your best bet is the MSVC2013 (available as a free download in the Community edition from MS), solution files for which can be generated with cmake. You'll also need cmake to generate the project files.
Setting up the Repo
-------------------
-Next, you'll need to set up the repo. You can make a fork and work on that then PR in, or I can set you up with membership for the repo so you can work on branches here (still use PRs though, they're great tools and for the first few you'll definitely need some changes). If you want membership to the repo, just create an issue and I can set you up.
+Next, you'll need to set up the repo. You should make a fork and work on that, then create a Pull Request so that we can review and merge your code. After you've "earned" an honorable status, we'll give you write access to the repository, so that you can work on branches in the main repo here (still use PRs though, they're great tools for review and discussion).
Once you've cloned, you need to pull down the submodules:
@@ -71,6 +71,8 @@ Code Styles
Mainly follow the code styles in [CONTRIBUTING.md](https://github.com/mc-server/MCServer/blob/master/CONTRIBUTING.md), which is definitely an important read.
+Note that there is a script file, $/src/CheckBasicStyle.lua, that can check some common violations of the coding style. You should run this file to check your code regularly. This script is run during the integration builds and if it fails, the build will fail. Note that you need Lua installed in order to run this script.
+
How to Build
------------------
@@ -85,12 +87,14 @@ Basically, the process is:
**Windows:**
-You need to first generate a project file with `cmake . -DCMAKE_BUILD_TYPE=DEBUG` then execute the `src/Bindings/AllToLua.bat` script file, then just open the solution file in your MSVC of choice and build.
+You need to first generate a solution file by executing `cmake .` on the commandline at the top-level folder of the repository, then just open the solution file in MSVC and build. Note that the first time after generating the solution, you will need to do extra setup in order to be able to fully debug in MSVC:
+- Set the startup project to MCServer: right-click the MCServer project in the Solution Explorer and choose "Set as Startup Project".
+- Set the debugging folder: right-click the MCServer project in the Solution Explorer, choose "Properties". In the dialog, browse to "Configuration Properties" -> "Debugging" and set "Working Directory" to "../MCServer".
How to Run
----------
-The server can be run (on *nix) by a simple `./MCServer` in the `MCServer` directory. On first run it will generate the world and start a server on the default port (configurable in `settings.ini`) so you can connect in minecraft via `localhost`.
+The server can be run (on *nix) by a simple `./MCServer` in the `MCServer` directory. On first run it will generate the world and start a server on the default port (configurable in `settings.ini`) so you can connect in minecraft via `localhost`. Note that if you build a debug version, the executable will be names `MCServer_debug` instead
Where to Get Started
-------------------------------
@@ -116,6 +120,5 @@ You may also want to write some plugins. They are written in lua, with excellent
Special Things
---------------------
-
- * MCServer uses ToLUA for the Lua API, and you'll really have to ask @madmaxoft for how to export stuff and @worktycho for how to add stuff to the auto generated bindings (he just re-worked it with CMake).
+ * Make yourself familiar with the community. Visit the forums: http://forum.mc-server.org
* Ask questions as much as you like, we're here to help :smiley:
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 9ee818a2c..025e9470d 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -973,11 +973,15 @@ cFile:Delete("/usr/bin/virus.exe");
]],
Functions =
{
+ ChangeFileExt = { Params = "FileName, NewExt", Return = "string", Notes = "(STATIC) Returns FileName with its extension changed to NewExt. NewExt may begin with a dot, but needn't, the result is the same in both cases (the first dot, if present, is ignored). FileName may contain path elements, extension is recognized as the last dot after the last path separator in the string." },
Copy = { Params = "SrcFileName, DstFileName", Return = "bool", Notes = "(STATIC) Copies a single file to a new destination. Returns true if successful. Fails if the destination already exists." },
CreateFolder = { Params = "FolderName", Return = "bool", Notes = "(STATIC) Creates a new folder. Returns true if successful." },
Delete = { Params = "FileName", Return = "bool", Notes = "(STATIC) Deletes the specified file. Returns true if successful." },
Exists = { Params = "FileName", Return = "bool", Notes = "(STATIC) Returns true if the specified file exists." },
+ GetExecutableExt = { Params = "", Return = "string", Notes = "(STATIC) Returns the customary executable extension (including the dot) used by the current platform (\".exe\" on Windows, empty string on Linux). " },
GetFolderContents = { Params = "FolderName", Return = "array table of strings", Notes = "(STATIC) Returns the contents of the specified folder, as an array table of strings. Each filesystem object is listed. Use the IsFile() and IsFolder() functions to determine the object type." },
+ GetLastModificationTime = { Params = "Path", Return = "number", Notes = "(STATIC) Returns the last modification time (in current timezone) of the specified file or folder. Returns zero if file not found / not accessible. The returned value is in the same units as values returned by os.time()." },
+ GetPathSeparator = { Params = "", Return = "string", Notes = "(STATIC) Returns the primary path separator used by the current platform. Returns \"\\\" on Windows and \"/\" on Linux. Note that the platform or CRT may support additional path separators, those are not reported." },
GetSize = { Params = "FileName", Return = "number", Notes = "(STATIC) Returns the size of the file, or -1 on failure." },
IsFile = { Params = "Path", Return = "bool", Notes = "(STATIC) Returns true if the specified path points to an existing file." },
IsFolder = { Params = "Path", Return = "bool", Notes = "(STATIC) Returns true if the specified path points to an existing folder." },
diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua
index d0c362ab4..01a5de81e 100644
--- a/MCServer/Plugins/Debuggers/Debuggers.lua
+++ b/MCServer/Plugins/Debuggers/Debuggers.lua
@@ -9,7 +9,7 @@ g_ShowFoodStats = false; -- When true, each player's food stats are sent to the
-function Initialize(Plugin)
+function Initialize(a_Plugin)
--[[
-- Test multiple hook handlers:
cPluginManager.AddHook(cPluginManager.HOOK_TICK, OnTick1);
@@ -45,14 +45,12 @@ function Initialize(Plugin)
-- Bind all the console commands:
RegisterPluginInfoConsoleCommands();
- Plugin:AddWebTab("Debuggers", HandleRequest_Debuggers)
- Plugin:AddWebTab("StressTest", HandleRequest_StressTest)
+ a_Plugin:AddWebTab("Debuggers", HandleRequest_Debuggers)
+ a_Plugin:AddWebTab("StressTest", HandleRequest_StressTest)
-- Enable the following line for BlockArea / Generator interface testing:
-- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED);
- LOG("Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
-
-- TestBlockAreas()
-- TestSQLiteBindings()
-- TestExpatBindings()
@@ -62,6 +60,11 @@ function Initialize(Plugin)
TestStringBase64()
-- TestUUIDFromName()
-- TestRankMgr()
+ TestFileExt()
+ TestFileLastMod()
+
+ local LastSelfMod = cFile:GetLastModificationTime(a_Plugin:GetLocalFolder() .. "/Debuggers.lua")
+ LOG("Debuggers.lua last modified on " .. os.date("%Y-%m-%dT%H:%M:%S", LastSelfMod))
--[[
-- Test cCompositeChat usage in console-logging:
@@ -79,6 +82,40 @@ end;
+function TestFileExt()
+ assert(cFile:ChangeFileExt("fileless_dir/", "new") == "fileless_dir/")
+ assert(cFile:ChangeFileExt("fileless_dir/", ".new") == "fileless_dir/")
+ assert(cFile:ChangeFileExt("pathless_file.ext", "new") == "pathless_file.new")
+ assert(cFile:ChangeFileExt("pathless_file.ext", ".new") == "pathless_file.new")
+ assert(cFile:ChangeFileExt("path/to/file.ext", "new") == "path/to/file.new")
+ assert(cFile:ChangeFileExt("path/to/file.ext", ".new") == "path/to/file.new")
+ assert(cFile:ChangeFileExt("path/to.dir/file", "new") == "path/to.dir/file.new")
+ assert(cFile:ChangeFileExt("path/to.dir/file", ".new") == "path/to.dir/file.new")
+ assert(cFile:ChangeFileExt("path/to.dir/file.ext", "new") == "path/to.dir/file.new")
+ assert(cFile:ChangeFileExt("path/to.dir/file.ext", ".new") == "path/to.dir/file.new")
+ assert(cFile:ChangeFileExt("path/to.dir/file.longext", "new") == "path/to.dir/file.new")
+ assert(cFile:ChangeFileExt("path/to.dir/file.longext", ".new") == "path/to.dir/file.new")
+ assert(cFile:ChangeFileExt("path/to.dir/file.", "new") == "path/to.dir/file.new")
+ assert(cFile:ChangeFileExt("path/to.dir/file.", ".new") == "path/to.dir/file.new")
+end
+
+
+
+
+
+function TestFileLastMod()
+ local f = assert(io.open("test.txt", "w"))
+ f:write("test")
+ f:close()
+ local filetime = cFile:GetLastModificationTime("test.txt")
+ local ostime = os.time()
+ LOG("file time: " .. filetime .. ", OS time: " .. ostime .. ", difference: " .. ostime - filetime)
+end
+
+
+
+
+
function TestPluginCalls()
-- In order to test the inter-plugin communication, we're going to call Core's ReturnColorFromChar() function
-- It is a rather simple function that doesn't need any tables as its params and returns a value, too
diff --git a/MCServer/Plugins/Debuggers/Info.lua b/MCServer/Plugins/Debuggers/Info.lua
index 0370145df..2e170487b 100644
--- a/MCServer/Plugins/Debuggers/Info.lua
+++ b/MCServer/Plugins/Debuggers/Info.lua
@@ -28,7 +28,7 @@ g_PluginInfo =
Handler = HandleCompo,
HelpString = "Tests the cCompositeChat bindings"
},
- ["/cs"] =
+ ["/cstay"] =
{
Permission = "debuggers",
Handler = HandleChunkStay,
diff --git a/MCServer/Plugins/DumpInfo/Init.lua b/MCServer/Plugins/DumpInfo/Init.lua
index 5d9c752b0..1faa8d60f 100644
--- a/MCServer/Plugins/DumpInfo/Init.lua
+++ b/MCServer/Plugins/DumpInfo/Init.lua
@@ -28,17 +28,18 @@ function HandleDumpPluginRequest(a_Request)
Content = Content .. [[
<table>
-<th colspan="2">DumpInfo</th>]]
+ <tr>
+ <th colspan="2">DumpInfo</th>
+ </tr>]]
-- Loop through each plugin that is found.
for PluginName, k in pairs(cPluginManager:Get():GetAllPlugins()) do
-
-- Check if there is a file called 'Info.lua' or 'info.lua'
if (cFile:Exists("Plugins/" .. PluginName .. "/Info.lua")) then
- Content = Content .. "<tr>"
- Content = Content .. "<td>" .. PluginName .. "</td>"
- Content = Content .. "<td> <form method='POST'> <input type='hidden' value='" .. PluginName .. "' name='DumpInfo'> <input type='submit' value='DumpInfo'> </form>"
- Content = Content .. "</td>"
+ Content = Content .. "\n<tr>\n"
+ Content = Content .. "\t<td>" .. PluginName .. "</td>\n"
+ Content = Content .. "\t<td><form method='POST'> <input type='hidden' value='" .. PluginName .. "' name='DumpInfo'> <input type='submit' value='DumpInfo'></form></td>\n"
+ Content = Content .. "</tr>\n"
end
end
diff --git a/MCServer/Plugins/InfoDump.lua b/MCServer/Plugins/InfoDump.lua
index 07a534b88..ab4dfd861 100644
--- a/MCServer/Plugins/InfoDump.lua
+++ b/MCServer/Plugins/InfoDump.lua
@@ -18,6 +18,13 @@ only that one plugin's documentation. This mode of operation doesn't require Lua
+-- If this file is called using the loadfile function the arg variable isn't filled. We have to do it manualy then.
+local arg = arg or {...}
+
+
+
+
+
-- Check Lua version. We use 5.1-specific construct when loading the plugin info, 5.2 is not compatible!
if (_VERSION ~= "Lua 5.1") then
print("Unsupported Lua version. This script requires Lua version 5.1, this Lua is version " .. (_VERSION or "<nil>"))
diff --git a/MCServer/delete_windows_service.cmd b/MCServer/delete_windows_service.cmd
new file mode 100644
index 000000000..ab6238e2f
--- /dev/null
+++ b/MCServer/delete_windows_service.cmd
@@ -0,0 +1,4 @@
+@echo off
+set SERVICENAME="MCServer"
+
+sc delete %SERVICENAME% \ No newline at end of file
diff --git a/MCServer/install_windows_service.cmd b/MCServer/install_windows_service.cmd
new file mode 100644
index 000000000..ba8a8c128
--- /dev/null
+++ b/MCServer/install_windows_service.cmd
@@ -0,0 +1,7 @@
+rem Alter this if you need to install multiple instances.
+@echo off
+set SERVICENAME="MCServer"
+
+set CURRENTDIR=%CD%
+sc create %SERVICENAME% binPath= "%CURRENTDIR%\MCServer.exe /service" start= auto DisplayName= %SERVICENAME%
+sc description %SERVICENAME% "Minecraft server instance" \ No newline at end of file
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;
}