Merge branch 'master' into GeneratingBenchmark2
Conflicts: src/World.h
This commit is contained in:
commit
fec17409d2
33
CONTRIBUTORS
33
CONTRIBUTORS
@ -1,25 +1,30 @@
|
|||||||
Many people have contributed to MCServer, and this list attempts to broadcast at least some of them.
|
Many people have contributed to MCServer, and this list attempts to broadcast at least some of them.
|
||||||
|
|
||||||
faketruth (founder)
|
|
||||||
xoft
|
|
||||||
keyboard
|
|
||||||
STR_Warrior
|
|
||||||
mgueydan
|
|
||||||
tigerw
|
|
||||||
bearbin (Alexander Harkness)
|
bearbin (Alexander Harkness)
|
||||||
Lapayo
|
derouinw
|
||||||
rs2k
|
Diusrex
|
||||||
Duralex
|
Duralex
|
||||||
mtilden
|
FakeTruth (founder)
|
||||||
|
keyboard
|
||||||
|
Lapayo
|
||||||
Luksor
|
Luksor
|
||||||
marmot21
|
marmot21
|
||||||
Sofapriester
|
|
||||||
mborland
|
mborland
|
||||||
|
mgueydan
|
||||||
|
MikeHunsinger
|
||||||
|
mtilden
|
||||||
|
nesco
|
||||||
|
rs2k
|
||||||
SamJBarney
|
SamJBarney
|
||||||
worktycho
|
Sofapriester
|
||||||
Sxw1212
|
STR_Warrior
|
||||||
tonibm19
|
|
||||||
Diusrex
|
|
||||||
structinf (xdot)
|
structinf (xdot)
|
||||||
|
Sxw1212
|
||||||
|
Taugeshtu
|
||||||
|
tigerw (Tiger Wang)
|
||||||
|
tonibm19
|
||||||
|
worktycho
|
||||||
|
xoft
|
||||||
|
|
||||||
|
|
||||||
Please add yourself to this list if you contribute to MCServer.
|
Please add yourself to this list if you contribute to MCServer.
|
||||||
|
@ -813,6 +813,20 @@ cFile:Delete("/usr/bin/virus.exe");
|
|||||||
},
|
},
|
||||||
}, -- cFile
|
}, -- cFile
|
||||||
|
|
||||||
|
cFloater =
|
||||||
|
{
|
||||||
|
Desc = [[
|
||||||
|
When a player uses his/her fishing rod it creates a floater entity. This class manages it.
|
||||||
|
]],
|
||||||
|
Functions =
|
||||||
|
{
|
||||||
|
CanPickup = { Params = "", Return = "bool", Notes = "Returns true if the floater gives an item when the player right clicks." },
|
||||||
|
GetAttachedMobID = { Params = "", Return = "EntityID", Notes = "A floater can get attached to an mob. When it is and this functions gets called it returns the mob ID. If it isn't attached to a mob it returns -1" },
|
||||||
|
GetOwnerID = { Params = "", Return = "EntityID", Notes = "Returns the EntityID of the player who owns the floater." },
|
||||||
|
},
|
||||||
|
Inherits = "cEntity",
|
||||||
|
},
|
||||||
|
|
||||||
cGroup =
|
cGroup =
|
||||||
{
|
{
|
||||||
Desc = [[
|
Desc = [[
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Next, we must obtain a copy of CoreMessaging.lua. This can be found
|
Next, we must obtain a copy of CoreMessaging.lua. This can be found
|
||||||
<a href="https://raw.github.com/mc-server/MCServer/master/MCServer/Plugins/MagicCarpet/coremessaging.lua">here.</a>
|
<a href="https://gist.github.com/bearbin/8715888">here.</a>
|
||||||
This is used to provide messaging support that is compliant with MCServer standards.
|
This is used to provide messaging support that is compliant with MCServer standards.
|
||||||
</p>
|
</p>
|
||||||
<h2>Creating the basic template</h2>
|
<h2>Creating the basic template</h2>
|
||||||
@ -35,19 +35,14 @@
|
|||||||
Format it like so:
|
Format it like so:
|
||||||
</p>
|
</p>
|
||||||
<pre class="prettyprint lang-lua">
|
<pre class="prettyprint lang-lua">
|
||||||
local PLUGIN
|
PLUGIN = nil
|
||||||
|
|
||||||
function Initialize(Plugin)
|
function Initialize(Plugin)
|
||||||
Plugin:SetName("DerpyPlugin")
|
Plugin:SetName("NewPlugin")
|
||||||
Plugin:SetVersion(1)
|
Plugin:SetVersion(1)
|
||||||
|
|
||||||
PLUGIN = Plugin
|
PLUGIN = Plugin
|
||||||
|
|
||||||
-- Hooks
|
|
||||||
|
|
||||||
local PluginManager = cPluginManager:Get()
|
|
||||||
-- Command bindings
|
|
||||||
|
|
||||||
LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
|
LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@ -84,7 +79,7 @@ end
|
|||||||
To register a hook, insert the following code template into the "-- Hooks" area in the previous code example.
|
To register a hook, insert the following code template into the "-- Hooks" area in the previous code example.
|
||||||
</p>
|
</p>
|
||||||
<pre class="prettyprint lang-lua">
|
<pre class="prettyprint lang-lua">
|
||||||
cPluginManager:AddHook(cPluginManager.HOOK_NAME_HERE, FunctionNameToBeCalled)
|
cPluginManager.AddHook(cPluginManager.HOOK_NAME_HERE, FunctionNameToBeCalled)
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
What does this code do?
|
What does this code do?
|
||||||
@ -102,10 +97,7 @@ function Initialize(Plugin)
|
|||||||
Plugin:SetName("DerpyPlugin")
|
Plugin:SetName("DerpyPlugin")
|
||||||
Plugin:SetVersion(1)
|
Plugin:SetVersion(1)
|
||||||
|
|
||||||
cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving)
|
cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving)
|
||||||
|
|
||||||
local PluginManager = cPluginManager:Get()
|
|
||||||
-- Command bindings
|
|
||||||
|
|
||||||
LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
|
LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
|
||||||
return true
|
return true
|
||||||
@ -127,10 +119,10 @@ end
|
|||||||
</p>
|
</p>
|
||||||
<pre class="prettyprint lang-lua">
|
<pre class="prettyprint lang-lua">
|
||||||
-- ADD THIS IF COMMAND DOES NOT REQUIRE A PARAMETER (/explode)
|
-- ADD THIS IF COMMAND DOES NOT REQUIRE A PARAMETER (/explode)
|
||||||
PluginManager:BindCommand("/commandname", "permissionnode", FunctionToCall, " - Description of command")
|
cPluginManager.BindCommand("/commandname", "permissionnode", FunctionToCall, " - Description of command")
|
||||||
|
|
||||||
-- ADD THIS IF COMMAND DOES REQUIRE A PARAMETER (/explode Notch)
|
-- ADD THIS IF COMMAND DOES REQUIRE A PARAMETER (/explode Notch)
|
||||||
PluginManager:BindCommand("/commandname", "permissionnode", FunctionToCall, " ~ Description of command and parameter(s)")
|
cPluginManager.BindCommand("/commandname", "permissionnode", FunctionToCall, " ~ Description of command and parameter(s)")
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
What does it do, and why are there two?
|
What does it do, and why are there two?
|
||||||
@ -197,8 +189,7 @@ function Initialize(Plugin)
|
|||||||
Plugin:SetName("DerpyPluginThatBlowsPeopleUp")
|
Plugin:SetName("DerpyPluginThatBlowsPeopleUp")
|
||||||
Plugin:SetVersion(9001)
|
Plugin:SetVersion(9001)
|
||||||
|
|
||||||
local PluginManager = cPluginManager:Get()
|
cPluginManager.BindCommand("/explode", "derpyplugin.explode", Explode, " ~ Explode a player");
|
||||||
PluginManager:BindCommand("/explode", "derpyplugin.explode", Explode, " ~ Explode a player");
|
|
||||||
|
|
||||||
cPluginManager:AddHook(cPluginManager.HOOK_COLLECTING_PICKUP, OnCollectingPickup)
|
cPluginManager:AddHook(cPluginManager.HOOK_COLLECTING_PICKUP, OnCollectingPickup)
|
||||||
|
|
||||||
|
@ -12,7 +12,9 @@ Installation
|
|||||||
|
|
||||||
To install MCServer, you can either download the repository and compile it, or download a pre-compiled version.
|
To install MCServer, you can either download the repository and compile it, or download a pre-compiled version.
|
||||||
|
|
||||||
After you've cloned the repository, you probably want to pull down the submodules (core plugins, some dependencies). This can be achieved with `git submodule init` and then on a regular basis (to keep up to date) `git submodule update`.
|
If you've cloned the repository using Git, you need to pull down the submodules (core plugins, some dependencies). This can be achieved with `git submodule init` and then on a regular basis (to keep up to date) `git submodule update`.
|
||||||
|
|
||||||
|
If you downloaded a ZIP file of the sources instead, you will need to download PolarSSL, too, from https://github.com/polarssl/polarssl , and unpack it into the `lib/polarssl` folder. You will also need to manually download all the plugins that you want included.
|
||||||
|
|
||||||
Compilation instructions are available in the COMPILING file.
|
Compilation instructions are available in the COMPILING file.
|
||||||
|
|
||||||
|
@ -1302,6 +1302,7 @@ bool cConnection::HandleServerLoginEncryptionKeyRequest(void)
|
|||||||
}
|
}
|
||||||
Log("Got PACKET_ENCRYPTION_KEY_REQUEST from the SERVER:");
|
Log("Got PACKET_ENCRYPTION_KEY_REQUEST from the SERVER:");
|
||||||
Log(" ServerID = %s", ServerID.c_str());
|
Log(" ServerID = %s", ServerID.c_str());
|
||||||
|
DataLog(PublicKey.data(), PublicKey.size(), " Public key (%u bytes)", (unsigned)PublicKey.size());
|
||||||
|
|
||||||
// Reply to the server:
|
// Reply to the server:
|
||||||
SendEncryptionKeyResponse(PublicKey, Nonce);
|
SendEncryptionKeyResponse(PublicKey, Nonce);
|
||||||
@ -2863,14 +2864,25 @@ void cConnection::SendEncryptionKeyResponse(const AString & a_ServerPublicKey, c
|
|||||||
Byte SharedSecret[16];
|
Byte SharedSecret[16];
|
||||||
Byte EncryptedSecret[128];
|
Byte EncryptedSecret[128];
|
||||||
memset(SharedSecret, 0, sizeof(SharedSecret)); // Use all zeroes for the initial secret
|
memset(SharedSecret, 0, sizeof(SharedSecret)); // Use all zeroes for the initial secret
|
||||||
m_Server.GetPrivateKey().Encrypt(SharedSecret, sizeof(SharedSecret), EncryptedSecret, sizeof(EncryptedSecret));
|
cPublicKey PubKey(a_ServerPublicKey);
|
||||||
|
int res = PubKey.Encrypt(SharedSecret, sizeof(SharedSecret), EncryptedSecret, sizeof(EncryptedSecret));
|
||||||
|
if (res < 0)
|
||||||
|
{
|
||||||
|
Log("Shared secret encryption failed: %d (0x%x)", res, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_ServerEncryptor.Init(SharedSecret, SharedSecret);
|
m_ServerEncryptor.Init(SharedSecret, SharedSecret);
|
||||||
m_ServerDecryptor.Init(SharedSecret, SharedSecret);
|
m_ServerDecryptor.Init(SharedSecret, SharedSecret);
|
||||||
|
|
||||||
// Encrypt the nonce:
|
// Encrypt the nonce:
|
||||||
Byte EncryptedNonce[128];
|
Byte EncryptedNonce[128];
|
||||||
m_Server.GetPrivateKey().Encrypt((const Byte *)a_Nonce.data(), a_Nonce.size(), EncryptedNonce, sizeof(EncryptedNonce));
|
res = PubKey.Encrypt((const Byte *)a_Nonce.data(), a_Nonce.size(), EncryptedNonce, sizeof(EncryptedNonce));
|
||||||
|
if (res < 0)
|
||||||
|
{
|
||||||
|
Log("Nonce encryption failed: %d (0x%x)", res, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Send the packet to the server:
|
// Send the packet to the server:
|
||||||
Log("Sending PACKET_ENCRYPTION_KEY_RESPONSE to the SERVER");
|
Log("Sending PACKET_ENCRYPTION_KEY_RESPONSE to the SERVER");
|
||||||
@ -2880,6 +2892,11 @@ void cConnection::SendEncryptionKeyResponse(const AString & a_ServerPublicKey, c
|
|||||||
ToServer.WriteBuf(EncryptedSecret, sizeof(EncryptedSecret));
|
ToServer.WriteBuf(EncryptedSecret, sizeof(EncryptedSecret));
|
||||||
ToServer.WriteBEShort((short)sizeof(EncryptedNonce));
|
ToServer.WriteBEShort((short)sizeof(EncryptedNonce));
|
||||||
ToServer.WriteBuf(EncryptedNonce, sizeof(EncryptedNonce));
|
ToServer.WriteBuf(EncryptedNonce, sizeof(EncryptedNonce));
|
||||||
|
DataLog(EncryptedSecret, sizeof(EncryptedSecret), "Encrypted secret (%u bytes)", (unsigned)sizeof(EncryptedSecret));
|
||||||
|
DataLog(EncryptedNonce, sizeof(EncryptedNonce), "Encrypted nonce (%u bytes)", (unsigned)sizeof(EncryptedNonce));
|
||||||
|
cByteBuffer Len(5);
|
||||||
|
Len.WriteVarInt(ToServer.GetReadableSpace());
|
||||||
|
SERVERSEND(Len);
|
||||||
SERVERSEND(ToServer);
|
SERVERSEND(ToServer);
|
||||||
m_ServerState = csEncryptedUnderstood;
|
m_ServerState = csEncryptedUnderstood;
|
||||||
m_IsServerEncrypted = true;
|
m_IsServerEncrypted = true;
|
||||||
|
@ -289,9 +289,13 @@ bool cLuaState::PushFunction(const cTableRef & a_TableRef)
|
|||||||
if (lua_isnil(m_LuaState, -1) || !lua_isfunction(m_LuaState, -1))
|
if (lua_isnil(m_LuaState, -1) || !lua_isfunction(m_LuaState, -1))
|
||||||
{
|
{
|
||||||
// Not a valid function, bail out
|
// Not a valid function, bail out
|
||||||
lua_pop(m_LuaState, 2);
|
lua_pop(m_LuaState, 3);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pop the table off the stack:
|
||||||
|
lua_remove(m_LuaState, -2);
|
||||||
|
|
||||||
Printf(m_CurrentFunctionName, "<table-callback %s>", a_TableRef.GetFnName());
|
Printf(m_CurrentFunctionName, "<table-callback %s>", a_TableRef.GetFnName());
|
||||||
m_NumCurrentFunctionArgs = 0;
|
m_NumCurrentFunctionArgs = 0;
|
||||||
return true;
|
return true;
|
||||||
|
@ -1429,7 +1429,10 @@ static int tolua_cPluginManager_BindCommand(lua_State * L)
|
|||||||
// Read the arguments to this API call:
|
// Read the arguments to this API call:
|
||||||
tolua_Error tolua_err;
|
tolua_Error tolua_err;
|
||||||
int idx = 1;
|
int idx = 1;
|
||||||
if (tolua_isusertype(L, 1, "cPluginManager", 0, &tolua_err))
|
if (
|
||||||
|
tolua_isusertype (L, 1, "cPluginManager", 0, &tolua_err) ||
|
||||||
|
tolua_isusertable(L, 1, "cPluginManager", 0, &tolua_err)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
@ -2128,26 +2131,40 @@ protected:
|
|||||||
|
|
||||||
static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S)
|
static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S)
|
||||||
{
|
{
|
||||||
// cLineBlockTracer.Trace(World, Callbacks, StartX, StartY, StartZ, EndX, EndY, EndZ)
|
/* Supported function signatures:
|
||||||
|
cLineBlockTracer:Trace(World, Callbacks, StartX, StartY, StartZ, EndX, EndY, EndZ) // Canonical
|
||||||
|
cLineBlockTracer.Trace(World, Callbacks, StartX, StartY, StartZ, EndX, EndY, EndZ)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// If the first param is the cLineBlockTracer class, shift param index by one:
|
||||||
|
int idx = 1;
|
||||||
|
tolua_Error err;
|
||||||
|
if (tolua_isusertable(tolua_S, 1, "cLineBlockTracer", 0, &err))
|
||||||
|
{
|
||||||
|
idx = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check params:
|
||||||
cLuaState L(tolua_S);
|
cLuaState L(tolua_S);
|
||||||
if (
|
if (
|
||||||
!L.CheckParamUserType(1, "cWorld") ||
|
!L.CheckParamUserType(idx, "cWorld") ||
|
||||||
!L.CheckParamTable (2) ||
|
!L.CheckParamTable (idx + 1) ||
|
||||||
!L.CheckParamNumber (3, 8) ||
|
!L.CheckParamNumber (idx + 2, idx + 7) ||
|
||||||
!L.CheckParamEnd (9)
|
!L.CheckParamEnd (idx + 8)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cWorld * World = (cWorld *)tolua_tousertype(L, 1, NULL);
|
// Trace:
|
||||||
cLuaBlockTracerCallbacks Callbacks(L, 2);
|
cWorld * World = (cWorld *)tolua_tousertype(L, idx, NULL);
|
||||||
double StartX = tolua_tonumber(L, 3, 0);
|
cLuaBlockTracerCallbacks Callbacks(L, idx + 1);
|
||||||
double StartY = tolua_tonumber(L, 4, 0);
|
double StartX = tolua_tonumber(L, idx + 2, 0);
|
||||||
double StartZ = tolua_tonumber(L, 5, 0);
|
double StartY = tolua_tonumber(L, idx + 3, 0);
|
||||||
double EndX = tolua_tonumber(L, 6, 0);
|
double StartZ = tolua_tonumber(L, idx + 4, 0);
|
||||||
double EndY = tolua_tonumber(L, 7, 0);
|
double EndX = tolua_tonumber(L, idx + 5, 0);
|
||||||
double EndZ = tolua_tonumber(L, 8, 0);
|
double EndY = tolua_tonumber(L, idx + 6, 0);
|
||||||
|
double EndZ = tolua_tonumber(L, idx + 7, 0);
|
||||||
bool res = cLineBlockTracer::Trace(*World, Callbacks, StartX, StartY, StartZ, EndX, EndY, EndZ);
|
bool res = cLineBlockTracer::Trace(*World, Callbacks, StartX, StartY, StartZ, EndX, EndY, EndZ);
|
||||||
tolua_pushboolean(L, res ? 1 : 0);
|
tolua_pushboolean(L, res ? 1 : 0);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -88,36 +88,55 @@ bool cPluginLua::Initialize(void)
|
|||||||
|
|
||||||
std::string PluginPath = FILE_IO_PREFIX + GetLocalFolder() + "/";
|
std::string PluginPath = FILE_IO_PREFIX + GetLocalFolder() + "/";
|
||||||
|
|
||||||
// Load all files for this plugin, and execute them
|
// List all Lua files for this plugin. Info.lua has a special handling - make it the last to load:
|
||||||
AStringVector Files = cFile::GetFolderContents(PluginPath.c_str());
|
AStringVector Files = cFile::GetFolderContents(PluginPath.c_str());
|
||||||
|
AStringVector LuaFiles;
|
||||||
int numFiles = 0;
|
bool HasInfoLua = false;
|
||||||
for (AStringVector::const_iterator itr = Files.begin(); itr != Files.end(); ++itr)
|
for (AStringVector::const_iterator itr = Files.begin(), end = Files.end(); itr != end; ++itr)
|
||||||
{
|
{
|
||||||
if (itr->rfind(".lua") == AString::npos)
|
if (itr->rfind(".lua") != AString::npos)
|
||||||
{
|
{
|
||||||
continue;
|
if (*itr == "Info.lua")
|
||||||
}
|
|
||||||
AString Path = PluginPath + *itr;
|
|
||||||
if (!m_LuaState.LoadFile(Path))
|
|
||||||
{
|
{
|
||||||
Close();
|
HasInfoLua = true;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
numFiles++;
|
LuaFiles.push_back(*itr);
|
||||||
}
|
}
|
||||||
} // for itr - Files[]
|
}
|
||||||
|
}
|
||||||
|
std::sort(LuaFiles.begin(), LuaFiles.end());
|
||||||
|
|
||||||
if (numFiles == 0)
|
// Warn if there are no Lua files in the plugin folder:
|
||||||
|
if (LuaFiles.empty())
|
||||||
{
|
{
|
||||||
LOGWARNING("No lua files found: plugin %s is missing.", GetName().c_str());
|
LOGWARNING("No lua files found: plugin %s is missing.", GetName().c_str());
|
||||||
Close();
|
Close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call intialize function
|
// Load all files in the list, including the Info.lua as last, if it exists:
|
||||||
|
for (AStringVector::const_iterator itr = LuaFiles.begin(), end = LuaFiles.end(); itr != end; ++itr)
|
||||||
|
{
|
||||||
|
AString Path = PluginPath + *itr;
|
||||||
|
if (!m_LuaState.LoadFile(Path))
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} // for itr - Files[]
|
||||||
|
if (HasInfoLua)
|
||||||
|
{
|
||||||
|
AString Path = PluginPath + "Info.lua";
|
||||||
|
if (!m_LuaState.LoadFile(Path))
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the Initialize function:
|
||||||
bool res = false;
|
bool res = false;
|
||||||
if (!m_LuaState.Call("Initialize", this, cLuaState::Return, res))
|
if (!m_LuaState.Call("Initialize", this, cLuaState::Return, res))
|
||||||
{
|
{
|
||||||
@ -125,7 +144,6 @@ bool cPluginLua::Initialize(void)
|
|||||||
Close();
|
Close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
LOGINFO("Plugin %s: Initialize() call failed, plugin is temporarily disabled.", GetName().c_str());
|
LOGINFO("Plugin %s: Initialize() call failed, plugin is temporarily disabled.", GetName().c_str());
|
||||||
|
@ -767,6 +767,7 @@ public:
|
|||||||
g_BlockIsSolid[E_BLOCK_MELON_STEM] = false;
|
g_BlockIsSolid[E_BLOCK_MELON_STEM] = false;
|
||||||
g_BlockIsSolid[E_BLOCK_NETHER_PORTAL] = false;
|
g_BlockIsSolid[E_BLOCK_NETHER_PORTAL] = false;
|
||||||
g_BlockIsSolid[E_BLOCK_PISTON_EXTENSION] = false;
|
g_BlockIsSolid[E_BLOCK_PISTON_EXTENSION] = false;
|
||||||
|
g_BlockIsSolid[E_BLOCK_POTATOES] = false;
|
||||||
g_BlockIsSolid[E_BLOCK_POWERED_RAIL] = false;
|
g_BlockIsSolid[E_BLOCK_POWERED_RAIL] = false;
|
||||||
g_BlockIsSolid[E_BLOCK_RAIL] = false;
|
g_BlockIsSolid[E_BLOCK_RAIL] = false;
|
||||||
g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_OFF] = false;
|
g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_OFF] = false;
|
||||||
|
@ -54,6 +54,7 @@ public:
|
|||||||
{
|
{
|
||||||
TestRead();
|
TestRead();
|
||||||
TestWrite();
|
TestWrite();
|
||||||
|
TestWrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestRead(void)
|
void TestRead(void)
|
||||||
@ -61,11 +62,11 @@ public:
|
|||||||
cByteBuffer buf(50);
|
cByteBuffer buf(50);
|
||||||
buf.Write("\x05\xac\x02\x00", 4);
|
buf.Write("\x05\xac\x02\x00", 4);
|
||||||
UInt32 v1;
|
UInt32 v1;
|
||||||
ASSERT(buf.ReadVarInt(v1) && (v1 == 5));
|
assert(buf.ReadVarInt(v1) && (v1 == 5));
|
||||||
UInt32 v2;
|
UInt32 v2;
|
||||||
ASSERT(buf.ReadVarInt(v2) && (v2 == 300));
|
assert(buf.ReadVarInt(v2) && (v2 == 300));
|
||||||
UInt32 v3;
|
UInt32 v3;
|
||||||
ASSERT(buf.ReadVarInt(v3) && (v3 == 0));
|
assert(buf.ReadVarInt(v3) && (v3 == 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestWrite(void)
|
void TestWrite(void)
|
||||||
@ -76,9 +77,30 @@ public:
|
|||||||
buf.WriteVarInt(0);
|
buf.WriteVarInt(0);
|
||||||
AString All;
|
AString All;
|
||||||
buf.ReadAll(All);
|
buf.ReadAll(All);
|
||||||
ASSERT(All.size() == 4);
|
assert(All.size() == 4);
|
||||||
ASSERT(memcmp(All.data(), "\x05\xac\x02\x00", All.size()) == 0);
|
assert(memcmp(All.data(), "\x05\xac\x02\x00", All.size()) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestWrap(void)
|
||||||
|
{
|
||||||
|
cByteBuffer buf(3);
|
||||||
|
for (int i = 0; i < 1000; i++)
|
||||||
|
{
|
||||||
|
int FreeSpace = buf.GetFreeSpace();
|
||||||
|
assert(buf.GetReadableSpace() == 0);
|
||||||
|
assert(FreeSpace > 0);
|
||||||
|
assert(buf.Write("a", 1));
|
||||||
|
assert(buf.CanReadBytes(1));
|
||||||
|
assert(buf.GetReadableSpace() == 1);
|
||||||
|
unsigned char v = 0;
|
||||||
|
assert(buf.ReadByte(v));
|
||||||
|
assert(v == 'a');
|
||||||
|
assert(buf.GetReadableSpace() == 0);
|
||||||
|
buf.CommitRead();
|
||||||
|
assert(buf.GetFreeSpace() == FreeSpace); // We're back to normal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} g_ByteBufferTest;
|
} g_ByteBufferTest;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -159,7 +181,7 @@ bool cByteBuffer::Write(const char * a_Bytes, int a_Count)
|
|||||||
int CurReadableSpace = GetReadableSpace();
|
int CurReadableSpace = GetReadableSpace();
|
||||||
int WrittenBytes = 0;
|
int WrittenBytes = 0;
|
||||||
|
|
||||||
if (GetFreeSpace() < a_Count)
|
if (CurFreeSpace < a_Count)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -864,3 +886,4 @@ void cByteBuffer::CheckValid(void) const
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ int cRSAPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte
|
|||||||
ASSERT(!"Invalid a_DecryptedMaxLength!");
|
ASSERT(!"Invalid a_DecryptedMaxLength!");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (a_PlainLength < m_Rsa.len)
|
if (a_EncryptedMaxLength < m_Rsa.len)
|
||||||
{
|
{
|
||||||
LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u",
|
LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u",
|
||||||
__FUNCTION__, (unsigned)a_PlainLength, (unsigned)(m_Rsa.len)
|
__FUNCTION__, (unsigned)a_PlainLength, (unsigned)(m_Rsa.len)
|
||||||
@ -214,16 +214,90 @@ int cRSAPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte
|
|||||||
ASSERT(!"Invalid a_PlainLength!");
|
ASSERT(!"Invalid a_PlainLength!");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
size_t DecryptedLength;
|
|
||||||
int res = rsa_pkcs1_encrypt(
|
int res = rsa_pkcs1_encrypt(
|
||||||
&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PUBLIC,
|
&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PRIVATE,
|
||||||
a_PlainLength, a_PlainData, a_EncryptedData
|
a_PlainLength, a_PlainData, a_EncryptedData
|
||||||
);
|
);
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return (int)DecryptedLength;
|
return (int)m_Rsa.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cPublicKey:
|
||||||
|
|
||||||
|
cPublicKey::cPublicKey(const AString & a_PublicKeyDER)
|
||||||
|
{
|
||||||
|
pk_init(&m_Pk);
|
||||||
|
if (pk_parse_public_key(&m_Pk, (const Byte *)a_PublicKeyDER.data(), a_PublicKeyDER.size()) != 0)
|
||||||
|
{
|
||||||
|
ASSERT(!"Cannot parse PubKey");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
InitRnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cPublicKey::~cPublicKey()
|
||||||
|
{
|
||||||
|
pk_free(&m_Pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int cPublicKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
|
||||||
|
{
|
||||||
|
size_t DecryptedLen = a_DecryptedMaxLength;
|
||||||
|
int res = pk_decrypt(&m_Pk,
|
||||||
|
a_EncryptedData, a_EncryptedLength,
|
||||||
|
a_DecryptedData, &DecryptedLen, a_DecryptedMaxLength,
|
||||||
|
ctr_drbg_random, &m_Ctr_drbg
|
||||||
|
);
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return (int)DecryptedLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int cPublicKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
|
||||||
|
{
|
||||||
|
size_t EncryptedLength = a_EncryptedMaxLength;
|
||||||
|
int res = pk_encrypt(&m_Pk,
|
||||||
|
a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength,
|
||||||
|
ctr_drbg_random, &m_Ctr_drbg
|
||||||
|
);
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return (int)EncryptedLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cPublicKey::InitRnd(void)
|
||||||
|
{
|
||||||
|
entropy_init(&m_Entropy);
|
||||||
|
const unsigned char pers[] = "rsa_genkey";
|
||||||
|
ctr_drbg_init(&m_Ctr_drbg, entropy_func, &m_Entropy, pers, sizeof(pers) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
31
src/Crypto.h
31
src/Crypto.h
@ -14,6 +14,7 @@
|
|||||||
#include "polarssl/entropy.h"
|
#include "polarssl/entropy.h"
|
||||||
#include "polarssl/ctr_drbg.h"
|
#include "polarssl/ctr_drbg.h"
|
||||||
#include "polarssl/sha1.h"
|
#include "polarssl/sha1.h"
|
||||||
|
#include "polarssl/pk.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -62,6 +63,36 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cPublicKey
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cPublicKey(const AString & a_PublicKeyDER);
|
||||||
|
~cPublicKey();
|
||||||
|
|
||||||
|
/** Decrypts the data using the stored public key
|
||||||
|
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
||||||
|
Returns the number of bytes decrypted, or negative number for error. */
|
||||||
|
int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
|
||||||
|
|
||||||
|
/** Encrypts the data using the stored public key
|
||||||
|
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
||||||
|
Returns the number of bytes decrypted, or negative number for error. */
|
||||||
|
int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
pk_context m_Pk;
|
||||||
|
entropy_context m_Entropy;
|
||||||
|
ctr_drbg_context m_Ctr_drbg;
|
||||||
|
|
||||||
|
/** Initializes the m_Entropy and m_Ctr_drbg contexts
|
||||||
|
Common part of this object's construction, called from all constructors. */
|
||||||
|
void InitRnd(void);
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Decrypts data using the AES / CFB (128) algorithm */
|
/** Decrypts data using the AES / CFB (128) algorithm */
|
||||||
class cAESCFBDecryptor
|
class cAESCFBDecryptor
|
||||||
{
|
{
|
||||||
|
@ -679,7 +679,8 @@ super(pkExpBottle, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
|||||||
|
|
||||||
void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
|
void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
|
||||||
{
|
{
|
||||||
// TODO: Spawn experience orbs
|
// Spawn an experience orb with a reward between 3 and 11.
|
||||||
|
m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), 3 + m_World->GetTickRandomNumber(8));
|
||||||
|
|
||||||
Destroy();
|
Destroy();
|
||||||
}
|
}
|
||||||
@ -710,8 +711,6 @@ void cFireworkEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
|
|||||||
SetSpeed(0, 0, 0);
|
SetSpeed(0, 0, 0);
|
||||||
SetPosition(GetPosX(), GetPosY() - 0.5, GetPosZ());
|
SetPosition(GetPosX(), GetPosY() - 0.5, GetPosZ());
|
||||||
|
|
||||||
std::cout << a_HitPos.x << " " << a_HitPos.y << " " << a_HitPos.z << std::endl;
|
|
||||||
|
|
||||||
m_IsInGround = true;
|
m_IsInGround = true;
|
||||||
|
|
||||||
BroadcastMovementUpdate();
|
BroadcastMovementUpdate();
|
||||||
|
@ -562,6 +562,31 @@ cBlockEntity * cChunkDesc::GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkDesc::UpdateHeightmap(void)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
int Height = 0;
|
||||||
|
for (int y = cChunkDef::Height - 1; y > 0; y--)
|
||||||
|
{
|
||||||
|
BLOCKTYPE BlockType = GetBlockType(x, y, z);
|
||||||
|
if (BlockType != E_BLOCK_AIR)
|
||||||
|
{
|
||||||
|
Height = y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // for y
|
||||||
|
SetHeight(x, z, Height);
|
||||||
|
} // for z
|
||||||
|
} // for x
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkDesc::CompressBlockMetas(cChunkDef::BlockNibbles & a_DestMetas)
|
void cChunkDesc::CompressBlockMetas(cChunkDef::BlockNibbles & a_DestMetas)
|
||||||
{
|
{
|
||||||
const NIBBLETYPE * AreaMetas = m_BlockArea.GetBlockMetas();
|
const NIBBLETYPE * AreaMetas = m_BlockArea.GetBlockMetas();
|
||||||
|
@ -30,7 +30,7 @@ class cChunkDesc
|
|||||||
public:
|
public:
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
/// Uncompressed block metas, 1 meta per byte
|
/** Uncompressed block metas, 1 meta per byte */
|
||||||
typedef NIBBLETYPE BlockNibbleBytes[cChunkDef::NumBlocks];
|
typedef NIBBLETYPE BlockNibbleBytes[cChunkDef::NumBlocks];
|
||||||
|
|
||||||
cChunkDesc(int a_ChunkX, int a_ChunkZ);
|
cChunkDesc(int a_ChunkX, int a_ChunkZ);
|
||||||
@ -56,6 +56,8 @@ public:
|
|||||||
void SetBiome(int a_RelX, int a_RelZ, int a_BiomeID);
|
void SetBiome(int a_RelX, int a_RelZ, int a_BiomeID);
|
||||||
EMCSBiome GetBiome(int a_RelX, int a_RelZ);
|
EMCSBiome GetBiome(int a_RelX, int a_RelZ);
|
||||||
|
|
||||||
|
// These operate on the heightmap, so they could get out of sync with the data
|
||||||
|
// Use UpdateHeightmap() to re-sync
|
||||||
void SetHeight(int a_RelX, int a_RelZ, int a_Height);
|
void SetHeight(int a_RelX, int a_RelZ, int a_Height);
|
||||||
int GetHeight(int a_RelX, int a_RelZ);
|
int GetHeight(int a_RelX, int a_RelZ);
|
||||||
|
|
||||||
@ -71,16 +73,16 @@ public:
|
|||||||
void SetUseDefaultFinish(bool a_bUseDefaultFinish);
|
void SetUseDefaultFinish(bool a_bUseDefaultFinish);
|
||||||
bool IsUsingDefaultFinish(void) const;
|
bool IsUsingDefaultFinish(void) const;
|
||||||
|
|
||||||
/// Writes the block area into the chunk, with its origin set at the specified relative coords. Area's data overwrite everything in the chunk.
|
/** Writes the block area into the chunk, with its origin set at the specified relative coords. Area's data overwrite everything in the chunk. */
|
||||||
void WriteBlockArea(const cBlockArea & a_BlockArea, int a_RelX, int a_RelY, int a_RelZ, cBlockArea::eMergeStrategy a_MergeStrategy = cBlockArea::msOverwrite);
|
void WriteBlockArea(const cBlockArea & a_BlockArea, int a_RelX, int a_RelY, int a_RelZ, cBlockArea::eMergeStrategy a_MergeStrategy = cBlockArea::msOverwrite);
|
||||||
|
|
||||||
/// Reads an area from the chunk into a cBlockArea, blocktypes and blockmetas
|
/** Reads an area from the chunk into a cBlockArea, blocktypes and blockmetas */
|
||||||
void ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX, int a_MinRelY, int a_MaxRelY, int a_MinRelZ, int a_MaxRelZ);
|
void ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX, int a_MinRelY, int a_MaxRelY, int a_MinRelZ, int a_MaxRelZ);
|
||||||
|
|
||||||
/// Returns the maximum height value in the heightmap
|
/** Returns the maximum height value in the heightmap */
|
||||||
HEIGHTTYPE GetMaxHeight(void) const;
|
HEIGHTTYPE GetMaxHeight(void) const;
|
||||||
|
|
||||||
/// Fills the relative cuboid with specified block; allows cuboid out of range of this chunk
|
/** Fills the relative cuboid with specified block; allows cuboid out of range of this chunk */
|
||||||
void FillRelCuboid(
|
void FillRelCuboid(
|
||||||
int a_MinX, int a_MaxX,
|
int a_MinX, int a_MaxX,
|
||||||
int a_MinY, int a_MaxY,
|
int a_MinY, int a_MaxY,
|
||||||
@ -88,7 +90,7 @@ public:
|
|||||||
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
|
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Fills the relative cuboid with specified block; allows cuboid out of range of this chunk
|
/** Fills the relative cuboid with specified block; allows cuboid out of range of this chunk */
|
||||||
void FillRelCuboid(const cCuboid & a_RelCuboid, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
|
void FillRelCuboid(const cCuboid & a_RelCuboid, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
|
||||||
{
|
{
|
||||||
FillRelCuboid(
|
FillRelCuboid(
|
||||||
@ -99,7 +101,7 @@ public:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces the specified src blocks in the cuboid by the dst blocks; allows cuboid out of range of this chunk
|
/** Replaces the specified src blocks in the cuboid by the dst blocks; allows cuboid out of range of this chunk */
|
||||||
void ReplaceRelCuboid(
|
void ReplaceRelCuboid(
|
||||||
int a_MinX, int a_MaxX,
|
int a_MinX, int a_MaxX,
|
||||||
int a_MinY, int a_MaxY,
|
int a_MinY, int a_MaxY,
|
||||||
@ -108,7 +110,7 @@ public:
|
|||||||
BLOCKTYPE a_DstType, NIBBLETYPE a_DstMeta
|
BLOCKTYPE a_DstType, NIBBLETYPE a_DstMeta
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Replaces the specified src blocks in the cuboid by the dst blocks; allows cuboid out of range of this chunk
|
/** Replaces the specified src blocks in the cuboid by the dst blocks; allows cuboid out of range of this chunk */
|
||||||
void ReplaceRelCuboid(
|
void ReplaceRelCuboid(
|
||||||
const cCuboid & a_RelCuboid,
|
const cCuboid & a_RelCuboid,
|
||||||
BLOCKTYPE a_SrcType, NIBBLETYPE a_SrcMeta,
|
BLOCKTYPE a_SrcType, NIBBLETYPE a_SrcMeta,
|
||||||
@ -124,7 +126,7 @@ public:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces the blocks in the cuboid by the dst blocks if they are considered non-floor (air, water); allows cuboid out of range of this chunk
|
/** Replaces the blocks in the cuboid by the dst blocks if they are considered non-floor (air, water); allows cuboid out of range of this chunk */
|
||||||
void FloorRelCuboid(
|
void FloorRelCuboid(
|
||||||
int a_MinX, int a_MaxX,
|
int a_MinX, int a_MaxX,
|
||||||
int a_MinY, int a_MaxY,
|
int a_MinY, int a_MaxY,
|
||||||
@ -132,7 +134,7 @@ public:
|
|||||||
BLOCKTYPE a_DstType, NIBBLETYPE a_DstMeta
|
BLOCKTYPE a_DstType, NIBBLETYPE a_DstMeta
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Replaces the blocks in the cuboid by the dst blocks if they are considered non-floor (air, water); allows cuboid out of range of this chunk
|
/** Replaces the blocks in the cuboid by the dst blocks if they are considered non-floor (air, water); allows cuboid out of range of this chunk */
|
||||||
void FloorRelCuboid(
|
void FloorRelCuboid(
|
||||||
const cCuboid & a_RelCuboid,
|
const cCuboid & a_RelCuboid,
|
||||||
BLOCKTYPE a_DstType, NIBBLETYPE a_DstMeta
|
BLOCKTYPE a_DstType, NIBBLETYPE a_DstMeta
|
||||||
@ -146,7 +148,7 @@ public:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fills the relative cuboid with specified block with a random chance; allows cuboid out of range of this chunk
|
/** Fills the relative cuboid with specified block with a random chance; allows cuboid out of range of this chunk */
|
||||||
void RandomFillRelCuboid(
|
void RandomFillRelCuboid(
|
||||||
int a_MinX, int a_MaxX,
|
int a_MinX, int a_MaxX,
|
||||||
int a_MinY, int a_MaxY,
|
int a_MinY, int a_MaxY,
|
||||||
@ -155,7 +157,7 @@ public:
|
|||||||
int a_RandomSeed, int a_ChanceOutOf10k
|
int a_RandomSeed, int a_ChanceOutOf10k
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Fills the relative cuboid with specified block with a random chance; allows cuboid out of range of this chunk
|
/** Fills the relative cuboid with specified block with a random chance; allows cuboid out of range of this chunk */
|
||||||
void RandomFillRelCuboid(
|
void RandomFillRelCuboid(
|
||||||
const cCuboid & a_RelCuboid, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
|
const cCuboid & a_RelCuboid, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
|
||||||
int a_RandomSeed, int a_ChanceOutOf10k
|
int a_RandomSeed, int a_ChanceOutOf10k
|
||||||
@ -170,11 +172,15 @@ public:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the block entity at the specified coords.
|
/** Returns the block entity at the specified coords.
|
||||||
/// If there is no block entity at those coords, tries to create one, based on the block type
|
If there is no block entity at those coords, tries to create one, based on the block type
|
||||||
/// If the blocktype doesn't support a block entity, returns NULL.
|
If the blocktype doesn't support a block entity, returns NULL. */
|
||||||
cBlockEntity * GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ);
|
cBlockEntity * GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ);
|
||||||
|
|
||||||
|
/** Updates the heightmap to match the current contents.
|
||||||
|
Useful for plugins when writing custom block areas into the chunk */
|
||||||
|
void UpdateHeightmap(void);
|
||||||
|
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
// Accessors used by cChunkGenerator::Generator descendants:
|
// Accessors used by cChunkGenerator::Generator descendants:
|
||||||
@ -187,11 +193,11 @@ public:
|
|||||||
inline cEntityList & GetEntities (void) { return m_Entities; }
|
inline cEntityList & GetEntities (void) { return m_Entities; }
|
||||||
inline cBlockEntityList & GetBlockEntities (void) { return m_BlockEntities; }
|
inline cBlockEntityList & GetBlockEntities (void) { return m_BlockEntities; }
|
||||||
|
|
||||||
/// Compresses the metas from the BlockArea format (1 meta per byte) into regular format (2 metas per byte)
|
/** Compresses the metas from the BlockArea format (1 meta per byte) into regular format (2 metas per byte) */
|
||||||
void CompressBlockMetas(cChunkDef::BlockNibbles & a_DestMetas);
|
void CompressBlockMetas(cChunkDef::BlockNibbles & a_DestMetas);
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
/// Verifies that the heightmap corresponds to blocktype contents; if not, asserts on that column
|
/** Verifies that the heightmap corresponds to blocktype contents; if not, asserts on that column */
|
||||||
void VerifyHeightmap(void);
|
void VerifyHeightmap(void);
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cChicken::cChicken(void) :
|
cChicken::cChicken(void) :
|
||||||
super("Chicken", mtChicken, "mob.chicken.hurt", "mob.chicken.hurt", 0.3, 0.4),
|
super("Chicken", mtChicken, "mob.chicken.hurt", "mob.chicken.hurt", 0.3, 0.4),
|
||||||
m_EggDropTimer(0)
|
m_EggDropTimer(0)
|
||||||
|
@ -19,8 +19,9 @@ public:
|
|||||||
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
||||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||||
|
|
||||||
private:
|
virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_SEEDS); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
int m_EggDropTimer;
|
int m_EggDropTimer;
|
||||||
} ;
|
} ;
|
||||||
|
@ -41,5 +41,3 @@ void cCow::OnRightClicked(cPlayer & a_Player)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,6 +19,9 @@ public:
|
|||||||
|
|
||||||
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
||||||
virtual void OnRightClicked(cPlayer & a_Player) override;
|
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||||
|
|
||||||
|
virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_WHEAT); }
|
||||||
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: Milk Cow
|
// TODO: Milk Cow
|
||||||
|
|
||||||
|
|
||||||
@ -30,4 +29,3 @@ void cMooshroom::GetDrops(cItems & a_Drops, cEntity * a_Killer)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@ public:
|
|||||||
CLASS_PROTODEF(cMooshroom);
|
CLASS_PROTODEF(cMooshroom);
|
||||||
|
|
||||||
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
||||||
|
|
||||||
|
virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_WHEAT); }
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "PassiveMonster.h"
|
#include "PassiveMonster.h"
|
||||||
#include "../World.h"
|
#include "../World.h"
|
||||||
|
#include "../Entities/Player.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -39,6 +39,20 @@ void cPassiveMonster::Tick(float a_Dt, cChunk & a_Chunk)
|
|||||||
{
|
{
|
||||||
CheckEventLostPlayer();
|
CheckEventLostPlayer();
|
||||||
}
|
}
|
||||||
|
cItem FollowedItem = GetFollowedItem();
|
||||||
|
if (FollowedItem.IsEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cPlayer * a_Closest_Player = m_World->FindClosestPlayer(GetPosition(), (float)m_SightDistance);
|
||||||
|
if (a_Closest_Player != NULL)
|
||||||
|
{
|
||||||
|
if (a_Closest_Player->GetEquippedItem().IsEqual(FollowedItem))
|
||||||
|
{
|
||||||
|
Vector3d PlayerPos = a_Closest_Player->GetPosition();
|
||||||
|
MoveToPosition(PlayerPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,6 +19,9 @@ public:
|
|||||||
|
|
||||||
/// When hit by someone, run away
|
/// When hit by someone, run away
|
||||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||||
|
/** Returns the item that the animal of this class follows when a player holds it in hand
|
||||||
|
Return an empty item not to follow (default). */
|
||||||
|
virtual const cItem GetFollowedItem(void) const { return cItem(); }
|
||||||
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
@ -73,5 +73,3 @@ void cPig::OnRightClicked(cPlayer & a_Player)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,6 +19,9 @@ public:
|
|||||||
|
|
||||||
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
||||||
virtual void OnRightClicked(cPlayer & a_Player) override;
|
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||||
|
|
||||||
|
virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_CARROT); }
|
||||||
|
|
||||||
bool IsSaddled(void) const { return m_bIsSaddled; }
|
bool IsSaddled(void) const { return m_bIsSaddled; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -97,3 +97,4 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@ public:
|
|||||||
virtual void OnRightClicked(cPlayer & a_Player) override;
|
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||||
|
|
||||||
|
virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_WHEAT); }
|
||||||
|
|
||||||
bool IsSheared(void) const { return m_IsSheared; }
|
bool IsSheared(void) const { return m_IsSheared; }
|
||||||
int GetFurColor(void) const { return m_WoolColor; }
|
int GetFurColor(void) const { return m_WoolColor; }
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include "Villager.h"
|
#include "Villager.h"
|
||||||
#include "../World.h"
|
#include "../World.h"
|
||||||
|
#include "../BlockArea.h"
|
||||||
|
#include "../Blocks/BlockHandler.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -10,7 +12,9 @@
|
|||||||
|
|
||||||
cVillager::cVillager(eVillagerType VillagerType) :
|
cVillager::cVillager(eVillagerType VillagerType) :
|
||||||
super("Villager", mtVillager, "", "", 0.6, 1.8),
|
super("Villager", mtVillager, "", "", 0.6, 1.8),
|
||||||
m_Type(VillagerType)
|
m_Type(VillagerType),
|
||||||
|
m_VillagerAction(false),
|
||||||
|
m_ActionCountDown(-1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,3 +37,153 @@ void cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cVillager::Tick(float a_Dt, cChunk & a_Chunk)
|
||||||
|
{
|
||||||
|
super::Tick(a_Dt, a_Chunk);
|
||||||
|
|
||||||
|
if (m_ActionCountDown > -1)
|
||||||
|
{
|
||||||
|
m_ActionCountDown--;
|
||||||
|
if (m_ActionCountDown == 0)
|
||||||
|
{
|
||||||
|
switch (m_Type)
|
||||||
|
{
|
||||||
|
case vtFarmer:
|
||||||
|
{
|
||||||
|
HandleFarmerPlaceCrops();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_VillagerAction)
|
||||||
|
{
|
||||||
|
switch (m_Type)
|
||||||
|
{
|
||||||
|
case vtFarmer:
|
||||||
|
{
|
||||||
|
HandleFarmerTryHarvestCrops();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_VillagerAction = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't always try to do a special action. Each tick has 1% to do a special action.
|
||||||
|
if (m_World->GetTickRandomNumber(99) != 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m_Type)
|
||||||
|
{
|
||||||
|
case vtFarmer:
|
||||||
|
{
|
||||||
|
HandleFarmerPrepareFarmCrops();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Farmer functions.
|
||||||
|
void cVillager::HandleFarmerPrepareFarmCrops()
|
||||||
|
{
|
||||||
|
if (!m_World->VillagersShouldHarvestCrops())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cBlockArea Surrounding;
|
||||||
|
/// Read a 11x7x11 area.
|
||||||
|
Surrounding.Read(
|
||||||
|
m_World,
|
||||||
|
(int) GetPosX() - 5,
|
||||||
|
(int) GetPosX() + 5,
|
||||||
|
(int) GetPosY() - 3,
|
||||||
|
(int) GetPosY() + 3,
|
||||||
|
(int) GetPosZ() - 5,
|
||||||
|
(int) GetPosZ() + 5
|
||||||
|
);
|
||||||
|
|
||||||
|
for (int I = 0; I < 5; I++)
|
||||||
|
{
|
||||||
|
for (int Y = 0; Y < 6; Y++)
|
||||||
|
{
|
||||||
|
// Pick random coordinates and check for crops.
|
||||||
|
int X = m_World->GetTickRandomNumber(11);
|
||||||
|
int Z = m_World->GetTickRandomNumber(11);
|
||||||
|
|
||||||
|
// A villager can't farm this.
|
||||||
|
if (!IsBlockFarmable(Surrounding.GetRelBlockType(X, Y, Z)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Surrounding.GetRelBlockMeta(X, Y, Z) != 0x7)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_VillagerAction = true;
|
||||||
|
m_CropsPos = Vector3i((int) GetPosX() + X - 5, (int) GetPosY() + Y - 3, (int) GetPosZ() + Z - 5);
|
||||||
|
MoveToPosition(Vector3f((float) (m_CropsPos.x + 0.5), (float) m_CropsPos.y, (float) (m_CropsPos.z + 0.5)));
|
||||||
|
return;
|
||||||
|
} // for Y loop.
|
||||||
|
} // Repeat the procces 5 times.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cVillager::HandleFarmerTryHarvestCrops()
|
||||||
|
{
|
||||||
|
// Harvest the crops if the villager isn't moving and if the crops are closer then 2 blocks.
|
||||||
|
if (!m_bMovingToDestination && (GetPosition() - m_CropsPos).Length() < 2)
|
||||||
|
{
|
||||||
|
// Check if the blocks didn't change while the villager was walking to the coordinates.
|
||||||
|
BLOCKTYPE CropBlock = m_World->GetBlock(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z);
|
||||||
|
if (IsBlockFarmable(CropBlock) && m_World->GetBlockMeta(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z) == 0x7)
|
||||||
|
{
|
||||||
|
cBlockHandler * Handler = cBlockHandler::GetBlockHandler(CropBlock);
|
||||||
|
Handler->DropBlock(m_World, this, m_CropsPos.x, m_CropsPos.y, m_CropsPos.z);
|
||||||
|
m_World->SetBlock(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z, E_BLOCK_AIR, 0);
|
||||||
|
m_ActionCountDown = 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cVillager::HandleFarmerPlaceCrops()
|
||||||
|
{
|
||||||
|
// Check if there is still farmland at the spot where the crops were.
|
||||||
|
if (m_World->GetBlock(m_CropsPos.x, m_CropsPos.y - 1, m_CropsPos.z) == E_BLOCK_FARMLAND)
|
||||||
|
{
|
||||||
|
m_World->SetBlock(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z, E_BLOCK_CROPS, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cVillager::IsBlockFarmable(BLOCKTYPE a_BlockType)
|
||||||
|
{
|
||||||
|
switch (a_BlockType)
|
||||||
|
{
|
||||||
|
case E_BLOCK_CROPS:
|
||||||
|
case E_BLOCK_POTATOES:
|
||||||
|
case E_BLOCK_CARROTS:
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -29,12 +29,36 @@ public:
|
|||||||
|
|
||||||
CLASS_PROTODEF(cVillager);
|
CLASS_PROTODEF(cVillager);
|
||||||
|
|
||||||
|
// Override functions
|
||||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||||
|
virtual void Tick (float a_Dt, cChunk & a_Chunk) override;
|
||||||
|
|
||||||
|
// cVillager functions
|
||||||
|
/** return true if the given blocktype are: crops, potatoes or carrots.*/
|
||||||
|
bool IsBlockFarmable(BLOCKTYPE a_BlockType);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
// Farmer functions
|
||||||
|
/** It searches in a 11x7x11 area for crops. If it found some it will navigate to them.*/
|
||||||
|
void HandleFarmerPrepareFarmCrops();
|
||||||
|
|
||||||
|
/** Looks if the farmer has reached it's destination, and if it's still crops and the destination is closer then 2 blocks it will harvest them.*/
|
||||||
|
void HandleFarmerTryHarvestCrops();
|
||||||
|
|
||||||
|
/** Replaces the crops he harvested.*/
|
||||||
|
void HandleFarmerPlaceCrops();
|
||||||
|
|
||||||
|
// Get and set functions.
|
||||||
int GetVilType(void) const { return m_Type; }
|
int GetVilType(void) const { return m_Type; }
|
||||||
|
Vector3i GetCropsPos(void) const { return m_CropsPos; }
|
||||||
|
bool DoesHaveActionActivated(void) const { return m_VillagerAction; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
int m_ActionCountDown;
|
||||||
int m_Type;
|
int m_Type;
|
||||||
|
bool m_VillagerAction;
|
||||||
|
Vector3i m_CropsPos;
|
||||||
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <arpa/inet.h> //inet_ntoa()
|
#include <arpa/inet.h> // inet_ntoa()
|
||||||
|
#include <sys/ioctl.h> // ioctl()
|
||||||
#else
|
#else
|
||||||
#define socklen_t int
|
#define socklen_t int
|
||||||
#endif
|
#endif
|
||||||
@ -320,7 +321,7 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cSocket::Receive(char* a_Buffer, unsigned int a_Length, unsigned int a_Flags)
|
int cSocket::Receive(char * a_Buffer, unsigned int a_Length, unsigned int a_Flags)
|
||||||
{
|
{
|
||||||
return recv(m_Socket, a_Buffer, a_Length, a_Flags);
|
return recv(m_Socket, a_Buffer, a_Length, a_Flags);
|
||||||
}
|
}
|
||||||
@ -354,3 +355,25 @@ unsigned short cSocket::GetPort(void) const
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cSocket::SetNonBlocking(void)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
u_long NonBlocking = 1;
|
||||||
|
int res = ioctlsocket(m_Socket, FIONBIO, &NonBlocking);
|
||||||
|
#else
|
||||||
|
int NonBlocking = 1;
|
||||||
|
int res = ioctl(m_Socket, FIONBIO, (char *)&NonBlocking);
|
||||||
|
#endif
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
LOGERROR("Cannot set socket to non-blocking. This would make the server deadlock later on, aborting.\nErr: %d, %d, %s",
|
||||||
|
res, GetLastError(), GetLastErrorString().c_str()
|
||||||
|
);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,6 +24,12 @@ public:
|
|||||||
{
|
{
|
||||||
IPv4 = AF_INET,
|
IPv4 = AF_INET,
|
||||||
IPv6 = AF_INET6,
|
IPv6 = AF_INET6,
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
ErrWouldBlock = WSAEWOULDBLOCK,
|
||||||
|
#else
|
||||||
|
ErrWouldBlock = EWOULDBLOCK,
|
||||||
|
#endif
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -111,6 +117,9 @@ public:
|
|||||||
|
|
||||||
const AString & GetIPString(void) const { return m_IPString; }
|
const AString & GetIPString(void) const { return m_IPString; }
|
||||||
|
|
||||||
|
/** Sets the socket into non-blocking mode */
|
||||||
|
void SetNonBlocking(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
xSocket m_Socket;
|
xSocket m_Socket;
|
||||||
AString m_IPString;
|
AString m_IPString;
|
||||||
|
@ -175,6 +175,7 @@ void cSocketThreads::cSocketThread::AddClient(const cSocket & a_Socket, cCallbac
|
|||||||
|
|
||||||
m_Slots[m_NumSlots].m_Client = a_Client;
|
m_Slots[m_NumSlots].m_Client = a_Client;
|
||||||
m_Slots[m_NumSlots].m_Socket = a_Socket;
|
m_Slots[m_NumSlots].m_Socket = a_Socket;
|
||||||
|
m_Slots[m_NumSlots].m_Socket.SetNonBlocking();
|
||||||
m_Slots[m_NumSlots].m_Outgoing.clear();
|
m_Slots[m_NumSlots].m_Outgoing.clear();
|
||||||
m_Slots[m_NumSlots].m_State = sSlot::ssNormal;
|
m_Slots[m_NumSlots].m_State = sSlot::ssNormal;
|
||||||
m_NumSlots++;
|
m_NumSlots++;
|
||||||
@ -213,7 +214,9 @@ bool cSocketThreads::cSocketThread::RemoveClient(const cCallback * a_Client)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Query and queue the last batch of outgoing data:
|
// Query and queue the last batch of outgoing data:
|
||||||
m_Slots[i].m_Client->GetOutgoingData(m_Slots[i].m_Outgoing);
|
AString Data;
|
||||||
|
m_Slots[i].m_Client->GetOutgoingData(Data);
|
||||||
|
m_Slots[i].m_Outgoing.append(Data);
|
||||||
if (m_Slots[i].m_Outgoing.empty())
|
if (m_Slots[i].m_Outgoing.empty())
|
||||||
{
|
{
|
||||||
// No more outgoing data, shut the socket down immediately:
|
// No more outgoing data, shut the socket down immediately:
|
||||||
@ -386,38 +389,28 @@ void cSocketThreads::cSocketThread::Execute(void)
|
|||||||
// The main thread loop:
|
// The main thread loop:
|
||||||
while (!m_ShouldTerminate)
|
while (!m_ShouldTerminate)
|
||||||
{
|
{
|
||||||
// Put all sockets into the Read set:
|
// Read outgoing data from the clients:
|
||||||
fd_set fdRead;
|
QueueOutgoingData();
|
||||||
cSocket::xSocket Highest = m_ControlSocket1.GetSocket();
|
|
||||||
|
|
||||||
PrepareSet(&fdRead, Highest, false);
|
// Put sockets into the sets
|
||||||
|
fd_set fdRead;
|
||||||
|
fd_set fdWrite;
|
||||||
|
cSocket::xSocket Highest = m_ControlSocket1.GetSocket();
|
||||||
|
PrepareSets(&fdRead, &fdWrite, Highest);
|
||||||
|
|
||||||
// Wait for the sockets:
|
// Wait for the sockets:
|
||||||
timeval Timeout;
|
timeval Timeout;
|
||||||
Timeout.tv_sec = 5;
|
Timeout.tv_sec = 5;
|
||||||
Timeout.tv_usec = 0;
|
Timeout.tv_usec = 0;
|
||||||
if (select(Highest + 1, &fdRead, NULL, NULL, &Timeout) == -1)
|
if (select(Highest + 1, &fdRead, &fdWrite, NULL, &Timeout) == -1)
|
||||||
{
|
{
|
||||||
LOG("select(R) call failed in cSocketThread: \"%s\"", cSocket::GetLastErrorString().c_str());
|
LOG("select() call failed in cSocketThread: \"%s\"", cSocket::GetLastErrorString().c_str());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Perform the IO:
|
||||||
ReadFromSockets(&fdRead);
|
ReadFromSockets(&fdRead);
|
||||||
|
|
||||||
// Test sockets for writing:
|
|
||||||
fd_set fdWrite;
|
|
||||||
Highest = m_ControlSocket1.GetSocket();
|
|
||||||
PrepareSet(&fdWrite, Highest, true);
|
|
||||||
Timeout.tv_sec = 0;
|
|
||||||
Timeout.tv_usec = 0;
|
|
||||||
if (select(Highest + 1, NULL, &fdWrite, NULL, &Timeout) == -1)
|
|
||||||
{
|
|
||||||
LOG("select(W) call failed in cSocketThread: \"%s\"", cSocket::GetLastErrorString().c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteToSockets(&fdWrite);
|
WriteToSockets(&fdWrite);
|
||||||
|
|
||||||
CleanUpShutSockets();
|
CleanUpShutSockets();
|
||||||
} // while (!mShouldTerminate)
|
} // while (!mShouldTerminate)
|
||||||
}
|
}
|
||||||
@ -426,10 +419,11 @@ void cSocketThreads::cSocketThread::Execute(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cSocketThreads::cSocketThread::PrepareSet(fd_set * a_Set, cSocket::xSocket & a_Highest, bool a_IsForWriting)
|
void cSocketThreads::cSocketThread::PrepareSets(fd_set * a_Read, fd_set * a_Write, cSocket::xSocket & a_Highest)
|
||||||
{
|
{
|
||||||
FD_ZERO(a_Set);
|
FD_ZERO(a_Read);
|
||||||
FD_SET(m_ControlSocket1.GetSocket(), a_Set);
|
FD_ZERO(a_Write);
|
||||||
|
FD_SET(m_ControlSocket1.GetSocket(), a_Read);
|
||||||
|
|
||||||
cCSLock Lock(m_Parent->m_CS);
|
cCSLock Lock(m_Parent->m_CS);
|
||||||
for (int i = m_NumSlots - 1; i >= 0; --i)
|
for (int i = m_NumSlots - 1; i >= 0; --i)
|
||||||
@ -444,11 +438,16 @@ void cSocketThreads::cSocketThread::PrepareSet(fd_set * a_Set, cSocket::xSocket
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
cSocket::xSocket s = m_Slots[i].m_Socket.GetSocket();
|
cSocket::xSocket s = m_Slots[i].m_Socket.GetSocket();
|
||||||
FD_SET(s, a_Set);
|
FD_SET(s, a_Read);
|
||||||
if (s > a_Highest)
|
if (s > a_Highest)
|
||||||
{
|
{
|
||||||
a_Highest = s;
|
a_Highest = s;
|
||||||
}
|
}
|
||||||
|
if (!m_Slots[i].m_Outgoing.empty())
|
||||||
|
{
|
||||||
|
// There's outgoing data for the socket, put it in the Write set
|
||||||
|
FD_SET(s, a_Write);
|
||||||
|
}
|
||||||
} // for i - m_Slots[]
|
} // for i - m_Slots[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,6 +478,8 @@ void cSocketThreads::cSocketThread::ReadFromSockets(fd_set * a_Read)
|
|||||||
char Buffer[1024];
|
char Buffer[1024];
|
||||||
int Received = m_Slots[i].m_Socket.Receive(Buffer, ARRAYCOUNT(Buffer), 0);
|
int Received = m_Slots[i].m_Socket.Receive(Buffer, ARRAYCOUNT(Buffer), 0);
|
||||||
if (Received <= 0)
|
if (Received <= 0)
|
||||||
|
{
|
||||||
|
if (cSocket::GetLastError() != cSocket::ErrWouldBlock)
|
||||||
{
|
{
|
||||||
// The socket has been closed by the remote party
|
// The socket has been closed by the remote party
|
||||||
switch (m_Slots[i].m_State)
|
switch (m_Slots[i].m_State)
|
||||||
@ -509,6 +510,7 @@ void cSocketThreads::cSocketThread::ReadFromSockets(fd_set * a_Read)
|
|||||||
}
|
}
|
||||||
} // switch (m_Slots[i].m_State)
|
} // switch (m_Slots[i].m_State)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_Slots[i].m_Client != NULL)
|
if (m_Slots[i].m_Client != NULL)
|
||||||
@ -539,7 +541,9 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write)
|
|||||||
// Request another chunk of outgoing data:
|
// Request another chunk of outgoing data:
|
||||||
if (m_Slots[i].m_Client != NULL)
|
if (m_Slots[i].m_Client != NULL)
|
||||||
{
|
{
|
||||||
m_Slots[i].m_Client->GetOutgoingData(m_Slots[i].m_Outgoing);
|
AString Data;
|
||||||
|
m_Slots[i].m_Client->GetOutgoingData(Data);
|
||||||
|
m_Slots[i].m_Outgoing.append(Data);
|
||||||
}
|
}
|
||||||
if (m_Slots[i].m_Outgoing.empty())
|
if (m_Slots[i].m_Outgoing.empty())
|
||||||
{
|
{
|
||||||
@ -553,8 +557,7 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write)
|
|||||||
}
|
}
|
||||||
} // if (outgoing data is empty)
|
} // if (outgoing data is empty)
|
||||||
|
|
||||||
int Sent = m_Slots[i].m_Socket.Send(m_Slots[i].m_Outgoing.data(), m_Slots[i].m_Outgoing.size());
|
if (!SendDataThroughSocket(m_Slots[i].m_Socket, m_Slots[i].m_Outgoing))
|
||||||
if (Sent < 0)
|
|
||||||
{
|
{
|
||||||
int Err = cSocket::GetLastError();
|
int Err = cSocket::GetLastError();
|
||||||
LOGWARNING("Error %d while writing to client \"%s\", disconnecting. \"%s\"", Err, m_Slots[i].m_Socket.GetIPString().c_str(), GetOSErrorString(Err).c_str());
|
LOGWARNING("Error %d while writing to client \"%s\", disconnecting. \"%s\"", Err, m_Slots[i].m_Socket.GetIPString().c_str(), GetOSErrorString(Err).c_str());
|
||||||
@ -565,7 +568,6 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_Slots[i].m_Outgoing.erase(0, Sent);
|
|
||||||
|
|
||||||
if (m_Slots[i].m_Outgoing.empty() && (m_Slots[i].m_State == sSlot::ssWritingRestOut))
|
if (m_Slots[i].m_Outgoing.empty() && (m_Slots[i].m_State == sSlot::ssWritingRestOut))
|
||||||
{
|
{
|
||||||
@ -590,8 +592,41 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cSocketThreads::cSocketThread::SendDataThroughSocket(cSocket & a_Socket, AString & a_Data)
|
||||||
|
{
|
||||||
|
// Send data in smaller chunks, so that the OS send buffers aren't overflown easily
|
||||||
|
while (!a_Data.empty())
|
||||||
|
{
|
||||||
|
size_t NumToSend = std::min(a_Data.size(), (size_t)1024);
|
||||||
|
int Sent = a_Socket.Send(a_Data.data(), NumToSend);
|
||||||
|
if (Sent < 0)
|
||||||
|
{
|
||||||
|
int Err = cSocket::GetLastError();
|
||||||
|
if (Err == cSocket::ErrWouldBlock)
|
||||||
|
{
|
||||||
|
// The OS send buffer is full, leave the outgoing data for the next time
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// An error has occured
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Sent == 0)
|
||||||
|
{
|
||||||
|
a_Socket.CloseSocket();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
a_Data.erase(0, Sent);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cSocketThreads::cSocketThread::CleanUpShutSockets(void)
|
void cSocketThreads::cSocketThread::CleanUpShutSockets(void)
|
||||||
{
|
{
|
||||||
|
cCSLock Lock(m_Parent->m_CS);
|
||||||
for (int i = m_NumSlots - 1; i >= 0; i--)
|
for (int i = m_NumSlots - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
switch (m_Slots[i].m_State)
|
switch (m_Slots[i].m_State)
|
||||||
@ -617,3 +652,32 @@ void cSocketThreads::cSocketThread::CleanUpShutSockets(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cSocketThreads::cSocketThread::QueueOutgoingData(void)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_Parent->m_CS);
|
||||||
|
for (int i = 0; i < m_NumSlots; i++)
|
||||||
|
{
|
||||||
|
if (m_Slots[i].m_Client != NULL)
|
||||||
|
{
|
||||||
|
AString Data;
|
||||||
|
m_Slots[i].m_Client->GetOutgoingData(Data);
|
||||||
|
m_Slots[i].m_Outgoing.append(Data);
|
||||||
|
}
|
||||||
|
if (m_Slots[i].m_Outgoing.empty())
|
||||||
|
{
|
||||||
|
// No outgoing data is ready
|
||||||
|
if (m_Slots[i].m_State == sSlot::ssWritingRestOut)
|
||||||
|
{
|
||||||
|
// The socket doesn't want to be kept alive anymore, and doesn't have any remaining data to send.
|
||||||
|
// Shut it down and then close it after a timeout, or when the other side agrees
|
||||||
|
m_Slots[i].m_State = sSlot::ssShuttingDown;
|
||||||
|
m_Slots[i].m_Socket.ShutdownReadWrite();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,7 +66,8 @@ public:
|
|||||||
/** Called when data is received from the remote party */
|
/** Called when data is received from the remote party */
|
||||||
virtual void DataReceived(const char * a_Data, int a_Size) = 0;
|
virtual void DataReceived(const char * a_Data, int a_Size) = 0;
|
||||||
|
|
||||||
/** Called when data can be sent to remote party; the function is supposed to *append* outgoing data to a_Data */
|
/** Called when data can be sent to remote party
|
||||||
|
The function is supposed to *set* outgoing data to a_Data (overwrite) */
|
||||||
virtual void GetOutgoingData(AString & a_Data) = 0;
|
virtual void GetOutgoingData(AString & a_Data) = 0;
|
||||||
|
|
||||||
/** Called when the socket has been closed for any reason */
|
/** Called when the socket has been closed for any reason */
|
||||||
@ -156,16 +157,27 @@ private:
|
|||||||
|
|
||||||
virtual void Execute(void) override;
|
virtual void Execute(void) override;
|
||||||
|
|
||||||
/** Puts all sockets into the set, along with m_ControlSocket1.
|
/** Prepares the Read and Write socket sets for select()
|
||||||
Only sockets that are able to send and receive data are put in the Set.
|
Puts all sockets into the read set, along with m_ControlSocket1.
|
||||||
Is a_IsForWriting is true, the ssWritingRestOut sockets are added as well. */
|
Only sockets that have outgoing data queued on them are put in the write set.*/
|
||||||
void PrepareSet(fd_set * a_Set, cSocket::xSocket & a_Highest, bool a_IsForWriting);
|
void PrepareSets(fd_set * a_ReadSet, fd_set * a_WriteSet, cSocket::xSocket & a_Highest);
|
||||||
|
|
||||||
void ReadFromSockets(fd_set * a_Read); // Reads from sockets indicated in a_Read
|
/** Reads from sockets indicated in a_Read */
|
||||||
void WriteToSockets (fd_set * a_Write); // Writes to sockets indicated in a_Write
|
void ReadFromSockets(fd_set * a_Read);
|
||||||
|
|
||||||
|
/** Writes to sockets indicated in a_Write */
|
||||||
|
void WriteToSockets (fd_set * a_Write);
|
||||||
|
|
||||||
|
/** Sends data through the specified socket, trying to fill the OS send buffer in chunks.
|
||||||
|
Returns true if there was no error while sending, false if an error has occured.
|
||||||
|
Modifies a_Data to contain only the unsent data. */
|
||||||
|
bool SendDataThroughSocket(cSocket & a_Socket, AString & a_Data);
|
||||||
|
|
||||||
/** Removes those slots in ssShuttingDown2 state, sets those with ssShuttingDown state to ssShuttingDown2 */
|
/** Removes those slots in ssShuttingDown2 state, sets those with ssShuttingDown state to ssShuttingDown2 */
|
||||||
void CleanUpShutSockets(void);
|
void CleanUpShutSockets(void);
|
||||||
|
|
||||||
|
/** Calls each client's callback to retrieve outgoing data for that client. */
|
||||||
|
void QueueOutgoingData(void);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
typedef std::list<cSocketThread *> cSocketThreadList;
|
typedef std::list<cSocketThread *> cSocketThreadList;
|
||||||
|
@ -28,7 +28,7 @@ long long cTimer::GetNowTime(void)
|
|||||||
#else
|
#else
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
return (long long)(now.tv_sec * 1000 + now.tv_usec / 1000);
|
return (long long)now.tv_sec * 1000 + (long long)now.tv_usec / 1000;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,8 +53,14 @@ Implements the 1.7.x protocol classes:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const int MAX_ENC_LEN = 512; // Maximum size of the encrypted message; should be 128, but who knows...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// fwd: main.cpp:
|
// fwd: main.cpp:
|
||||||
extern bool g_ShouldLogComm;
|
extern bool g_ShouldLogCommIn, g_ShouldLogCommOut;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -74,7 +80,7 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd
|
|||||||
m_IsEncrypted(false)
|
m_IsEncrypted(false)
|
||||||
{
|
{
|
||||||
// Create the comm log file, if so requested:
|
// Create the comm log file, if so requested:
|
||||||
if (g_ShouldLogComm)
|
if (g_ShouldLogCommIn || g_ShouldLogCommOut)
|
||||||
{
|
{
|
||||||
cFile::CreateFolder("CommLogs");
|
cFile::CreateFolder("CommLogs");
|
||||||
AString FileName = Printf("CommLogs/%x__%s.log", (unsigned)time(NULL), a_Client->GetIPString().c_str());
|
AString FileName = Printf("CommLogs/%x__%s.log", (unsigned)time(NULL), a_Client->GetIPString().c_str());
|
||||||
@ -979,10 +985,11 @@ void cProtocol172::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, cons
|
|||||||
Pkt.WriteInt(a_BlockX);
|
Pkt.WriteInt(a_BlockX);
|
||||||
Pkt.WriteShort((short)a_BlockY);
|
Pkt.WriteShort((short)a_BlockY);
|
||||||
Pkt.WriteInt(a_BlockZ);
|
Pkt.WriteInt(a_BlockZ);
|
||||||
Pkt.WriteString(a_Line1);
|
// Need to send only up to 15 chars, otherwise the client crashes (#598)
|
||||||
Pkt.WriteString(a_Line2);
|
Pkt.WriteString(a_Line1.substr(0, 15));
|
||||||
Pkt.WriteString(a_Line3);
|
Pkt.WriteString(a_Line2.substr(0, 15));
|
||||||
Pkt.WriteString(a_Line4);
|
Pkt.WriteString(a_Line3.substr(0, 15));
|
||||||
|
Pkt.WriteString(a_Line4.substr(0, 15));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1083,7 +1090,7 @@ void cProtocol172::SendWindowProperty(const cWindow & a_Window, short a_Property
|
|||||||
void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
|
void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
|
||||||
{
|
{
|
||||||
// Write the incoming data into the comm log file:
|
// Write the incoming data into the comm log file:
|
||||||
if (g_ShouldLogComm)
|
if (g_ShouldLogCommIn)
|
||||||
{
|
{
|
||||||
if (m_ReceivedData.GetReadableSpace() > 0)
|
if (m_ReceivedData.GetReadableSpace() > 0)
|
||||||
{
|
{
|
||||||
@ -1092,9 +1099,10 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
|
|||||||
m_ReceivedData.ReadAll(AllData);
|
m_ReceivedData.ReadAll(AllData);
|
||||||
m_ReceivedData.ResetRead();
|
m_ReceivedData.ResetRead();
|
||||||
m_ReceivedData.SkipRead(m_ReceivedData.GetReadableSpace() - OldReadableSpace);
|
m_ReceivedData.SkipRead(m_ReceivedData.GetReadableSpace() - OldReadableSpace);
|
||||||
|
ASSERT(m_ReceivedData.GetReadableSpace() == OldReadableSpace);
|
||||||
AString Hex;
|
AString Hex;
|
||||||
CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
|
CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
|
||||||
m_CommLogFile.Printf("Incoming data, %d (0x%x) bytes unparsed already present in buffer:\n%s\n",
|
m_CommLogFile.Printf("Incoming data, %d (0x%x) unparsed bytes already present in buffer:\n%s\n",
|
||||||
AllData.size(), AllData.size(), Hex.c_str()
|
AllData.size(), AllData.size(), Hex.c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1103,6 +1111,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
|
|||||||
m_CommLogFile.Printf("Incoming data: %d (0x%x) bytes: \n%s\n",
|
m_CommLogFile.Printf("Incoming data: %d (0x%x) bytes: \n%s\n",
|
||||||
a_Size, a_Size, Hex.c_str()
|
a_Size, a_Size, Hex.c_str()
|
||||||
);
|
);
|
||||||
|
m_CommLogFile.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_ReceivedData.Write(a_Data, a_Size))
|
if (!m_ReceivedData.Write(a_Data, a_Size))
|
||||||
@ -1119,12 +1128,14 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
|
|||||||
if (!m_ReceivedData.ReadVarInt(PacketLen))
|
if (!m_ReceivedData.ReadVarInt(PacketLen))
|
||||||
{
|
{
|
||||||
// Not enough data
|
// Not enough data
|
||||||
return;
|
m_ReceivedData.ResetRead();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (!m_ReceivedData.CanReadBytes(PacketLen))
|
if (!m_ReceivedData.CanReadBytes(PacketLen))
|
||||||
{
|
{
|
||||||
// The full packet hasn't been received yet
|
// The full packet hasn't been received yet
|
||||||
return;
|
m_ReceivedData.ResetRead();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
cByteBuffer bb(PacketLen + 1);
|
cByteBuffer bb(PacketLen + 1);
|
||||||
VERIFY(m_ReceivedData.ReadToByteBuffer(bb, (int)PacketLen));
|
VERIFY(m_ReceivedData.ReadToByteBuffer(bb, (int)PacketLen));
|
||||||
@ -1137,11 +1148,11 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
|
|||||||
if (!bb.ReadVarInt(PacketType))
|
if (!bb.ReadVarInt(PacketType))
|
||||||
{
|
{
|
||||||
// Not enough data
|
// Not enough data
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log the packet info into the comm log file:
|
// Log the packet info into the comm log file:
|
||||||
if (g_ShouldLogComm)
|
if (g_ShouldLogCommIn)
|
||||||
{
|
{
|
||||||
AString PacketData;
|
AString PacketData;
|
||||||
bb.ReadAll(PacketData);
|
bb.ReadAll(PacketData);
|
||||||
@ -1173,7 +1184,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
|
|||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
|
|
||||||
// Put a message in the comm log:
|
// Put a message in the comm log:
|
||||||
if (g_ShouldLogComm)
|
if (g_ShouldLogCommIn)
|
||||||
{
|
{
|
||||||
m_CommLogFile.Printf("^^^^^^ Unhandled packet ^^^^^^\n\n\n");
|
m_CommLogFile.Printf("^^^^^^ Unhandled packet ^^^^^^\n\n\n");
|
||||||
}
|
}
|
||||||
@ -1189,7 +1200,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Put a message in the comm log:
|
// Put a message in the comm log:
|
||||||
if (g_ShouldLogComm)
|
if (g_ShouldLogCommIn)
|
||||||
{
|
{
|
||||||
m_CommLogFile.Printf("^^^^^^ Wrong number of bytes read for this packet (exp %d left, got %d left) ^^^^^^\n\n\n",
|
m_CommLogFile.Printf("^^^^^^ Wrong number of bytes read for this packet (exp %d left, got %d left) ^^^^^^\n\n\n",
|
||||||
1, bb.GetReadableSpace()
|
1, bb.GetReadableSpace()
|
||||||
@ -1200,7 +1211,24 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
|
|||||||
ASSERT(!"Read wrong number of bytes!");
|
ASSERT(!"Read wrong number of bytes!");
|
||||||
m_Client->PacketError(PacketType);
|
m_Client->PacketError(PacketType);
|
||||||
}
|
}
|
||||||
} // while (true)
|
} // for(ever)
|
||||||
|
|
||||||
|
// Log any leftover bytes into the logfile:
|
||||||
|
if (g_ShouldLogCommIn && (m_ReceivedData.GetReadableSpace() > 0))
|
||||||
|
{
|
||||||
|
AString AllData;
|
||||||
|
int OldReadableSpace = m_ReceivedData.GetReadableSpace();
|
||||||
|
m_ReceivedData.ReadAll(AllData);
|
||||||
|
m_ReceivedData.ResetRead();
|
||||||
|
m_ReceivedData.SkipRead(m_ReceivedData.GetReadableSpace() - OldReadableSpace);
|
||||||
|
ASSERT(m_ReceivedData.GetReadableSpace() == OldReadableSpace);
|
||||||
|
AString Hex;
|
||||||
|
CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
|
||||||
|
m_CommLogFile.Printf("There are %d (0x%x) bytes of non-parse-able data left in the buffer:\n%s",
|
||||||
|
m_ReceivedData.GetReadableSpace(), m_ReceivedData.GetReadableSpace(), Hex.c_str()
|
||||||
|
);
|
||||||
|
m_CommLogFile.Flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1330,7 +1358,64 @@ void cProtocol172::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
|
|||||||
|
|
||||||
void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffer)
|
void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffer)
|
||||||
{
|
{
|
||||||
// TODO: Add protocol encryption
|
short EncKeyLength, EncNonceLength;
|
||||||
|
a_ByteBuffer.ReadBEShort(EncKeyLength);
|
||||||
|
AString EncKey;
|
||||||
|
if (!a_ByteBuffer.ReadString(EncKey, EncKeyLength))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
a_ByteBuffer.ReadBEShort(EncNonceLength);
|
||||||
|
AString EncNonce;
|
||||||
|
if (!a_ByteBuffer.ReadString(EncNonce, EncNonceLength))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((EncKeyLength > MAX_ENC_LEN) || (EncNonceLength > MAX_ENC_LEN))
|
||||||
|
{
|
||||||
|
LOGD("Too long encryption");
|
||||||
|
m_Client->Kick("Hacked client");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt EncNonce using privkey
|
||||||
|
cRSAPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
|
||||||
|
Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
|
||||||
|
int res = rsaDecryptor.Decrypt((const Byte *)EncNonce.data(), EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce));
|
||||||
|
if (res != 4)
|
||||||
|
{
|
||||||
|
LOGD("Bad nonce length: got %d, exp %d", res, 4);
|
||||||
|
m_Client->Kick("Hacked client");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ntohl(DecryptedNonce[0]) != (unsigned)(uintptr_t)this)
|
||||||
|
{
|
||||||
|
LOGD("Bad nonce value");
|
||||||
|
m_Client->Kick("Hacked client");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt the symmetric encryption key using privkey:
|
||||||
|
Byte DecryptedKey[MAX_ENC_LEN];
|
||||||
|
res = rsaDecryptor.Decrypt((const Byte *)EncKey.data(), EncKey.size(), DecryptedKey, sizeof(DecryptedKey));
|
||||||
|
if (res != 16)
|
||||||
|
{
|
||||||
|
LOGD("Bad key length");
|
||||||
|
m_Client->Kick("Hacked client");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StartEncryption(DecryptedKey);
|
||||||
|
|
||||||
|
// Send login success:
|
||||||
|
{
|
||||||
|
cPacketizer Pkt(*this, 0x02); // Login success packet
|
||||||
|
Pkt.WriteString(Printf("%d", m_Client->GetUniqueID())); // TODO: proper UUID
|
||||||
|
Pkt.WriteString(m_Client->GetUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
m_State = 3; // State = Game
|
||||||
|
m_Client->HandleLogin(4, m_Client->GetUsername());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1342,14 +1427,26 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
|
|||||||
AString Username;
|
AString Username;
|
||||||
a_ByteBuffer.ReadVarUTF8String(Username);
|
a_ByteBuffer.ReadVarUTF8String(Username);
|
||||||
|
|
||||||
// TODO: Protocol encryption should be set up here if not localhost / auth
|
|
||||||
|
|
||||||
if (!m_Client->HandleHandshake(Username))
|
if (!m_Client->HandleHandshake(Username))
|
||||||
{
|
{
|
||||||
// The client is not welcome here, they have been sent a Kick packet already
|
// The client is not welcome here, they have been sent a Kick packet already
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If auth is required, then send the encryption request:
|
||||||
|
if (cRoot::Get()->GetServer()->ShouldAuthenticate())
|
||||||
|
{
|
||||||
|
cPacketizer Pkt(*this, 0x01);
|
||||||
|
Pkt.WriteString(cRoot::Get()->GetServer()->GetServerID());
|
||||||
|
const AString & PubKeyDer = cRoot::Get()->GetServer()->GetPublicKeyDER();
|
||||||
|
Pkt.WriteShort(PubKeyDer.size());
|
||||||
|
Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size());
|
||||||
|
Pkt.WriteShort(4);
|
||||||
|
Pkt.WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
|
||||||
|
m_Client->SetUsername(Username);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Send login success:
|
// Send login success:
|
||||||
{
|
{
|
||||||
cPacketizer Pkt(*this, 0x02); // Login success packet
|
cPacketizer Pkt(*this, 0x02); // Login success packet
|
||||||
@ -1861,6 +1958,27 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProtocol172::StartEncryption(const Byte * a_Key)
|
||||||
|
{
|
||||||
|
m_Encryptor.Init(a_Key, a_Key);
|
||||||
|
m_Decryptor.Init(a_Key, a_Key);
|
||||||
|
m_IsEncrypted = true;
|
||||||
|
|
||||||
|
// Prepare the m_AuthServerID:
|
||||||
|
cSHA1Checksum Checksum;
|
||||||
|
const AString & ServerID = cRoot::Get()->GetServer()->GetServerID();
|
||||||
|
Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length());
|
||||||
|
Checksum.Update(a_Key, 16);
|
||||||
|
Checksum.Update((const Byte *)cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size());
|
||||||
|
Byte Digest[20];
|
||||||
|
Checksum.Finalize(Digest);
|
||||||
|
cSHA1Checksum::DigestToJava(Digest, m_AuthServerID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// cProtocol172::cPacketizer:
|
// cProtocol172::cPacketizer:
|
||||||
|
|
||||||
@ -1881,7 +1999,7 @@ cProtocol172::cPacketizer::~cPacketizer()
|
|||||||
m_Out.CommitRead();
|
m_Out.CommitRead();
|
||||||
|
|
||||||
// Log the comm into logfile:
|
// Log the comm into logfile:
|
||||||
if (g_ShouldLogComm)
|
if (g_ShouldLogCommOut)
|
||||||
{
|
{
|
||||||
AString Hex;
|
AString Hex;
|
||||||
ASSERT(DataToSend.size() > 0);
|
ASSERT(DataToSend.size() > 0);
|
||||||
|
@ -281,6 +281,8 @@ protected:
|
|||||||
|
|
||||||
/// Parses item metadata as read by ReadItem(), into the item enchantments.
|
/// Parses item metadata as read by ReadItem(), into the item enchantments.
|
||||||
void ParseItemMetadata(cItem & a_Item, const AString & a_Metadata);
|
void ParseItemMetadata(cItem & a_Item, const AString & a_Metadata);
|
||||||
|
|
||||||
|
void StartEncryption(const Byte * a_Key);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
|
|
||||||
// Adjust these if a new protocol is added or an old one is removed:
|
// Adjust these if a new protocol is added or an old one is removed:
|
||||||
#define MCS_CLIENT_VERSIONS "1.2.4, 1.2.5, 1.3.1, 1.3.2, 1.4.2, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.5, 1.5.1, 1.5.2, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.7.2"
|
#define MCS_CLIENT_VERSIONS "1.2.4, 1.2.5, 1.3.1, 1.3.2, 1.4.2, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.5, 1.5.1, 1.5.2, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.7.2, 1.7.4"
|
||||||
#define MCS_PROTOCOL_VERSIONS "29, 39, 47, 49, 51, 60, 61, 73, 74, 77, 78, 4"
|
#define MCS_PROTOCOL_VERSIONS "29, 39, 47, 49, 51, 60, 61, 73, 74, 77, 78, 4"
|
||||||
|
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ void cRoot::Start(void)
|
|||||||
long long finishmseconds = Time.GetNowTime();
|
long long finishmseconds = Time.GetNowTime();
|
||||||
finishmseconds -= mseconds;
|
finishmseconds -= mseconds;
|
||||||
|
|
||||||
LOG("Startup complete, took %i ms!", finishmseconds);
|
LOG("Startup complete, took %lld ms!", finishmseconds);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
EnableMenuItem(hmenu, SC_CLOSE, MF_ENABLED); // Re-enable close button
|
EnableMenuItem(hmenu, SC_CLOSE, MF_ENABLED); // Re-enable close button
|
||||||
#endif
|
#endif
|
||||||
|
@ -237,7 +237,8 @@ bool cServer::InitServer(cIniFile & a_SettingsIni)
|
|||||||
m_bIsConnected = true;
|
m_bIsConnected = true;
|
||||||
|
|
||||||
m_ServerID = "-";
|
m_ServerID = "-";
|
||||||
if (a_SettingsIni.GetValueSetB("Authentication", "Authenticate", true))
|
m_ShouldAuthenticate = a_SettingsIni.GetValueSetB("Authentication", "Authenticate", true);
|
||||||
|
if (m_ShouldAuthenticate)
|
||||||
{
|
{
|
||||||
MTRand mtrand1;
|
MTRand mtrand1;
|
||||||
unsigned int r1 = (mtrand1.randInt() % 1147483647) + 1000000000;
|
unsigned int r1 = (mtrand1.randInt() % 1147483647) + 1000000000;
|
||||||
|
28
src/Server.h
28
src/Server.h
@ -71,13 +71,13 @@ public: // tolua_export
|
|||||||
|
|
||||||
bool Command(cClientHandle & a_Client, AString & a_Cmd);
|
bool Command(cClientHandle & a_Client, AString & a_Cmd);
|
||||||
|
|
||||||
/// Executes the console command, sends output through the specified callback
|
/** Executes the console command, sends output through the specified callback */
|
||||||
void ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output);
|
void ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output);
|
||||||
|
|
||||||
/// Lists all available console commands and their helpstrings
|
/** Lists all available console commands and their helpstrings */
|
||||||
void PrintHelp(const AStringVector & a_Split, cCommandOutputCallback & a_Output);
|
void PrintHelp(const AStringVector & a_Split, cCommandOutputCallback & a_Output);
|
||||||
|
|
||||||
/// Binds the built-in console commands with the plugin manager
|
/** Binds the built-in console commands with the plugin manager */
|
||||||
static void BindBuiltInConsoleCommands(void);
|
static void BindBuiltInConsoleCommands(void);
|
||||||
|
|
||||||
void Shutdown(void);
|
void Shutdown(void);
|
||||||
@ -97,13 +97,13 @@ public: // tolua_export
|
|||||||
|
|
||||||
void RemoveClient(const cClientHandle * a_Client); // Removes the clienthandle from m_SocketThreads
|
void RemoveClient(const cClientHandle * a_Client); // Removes the clienthandle from m_SocketThreads
|
||||||
|
|
||||||
/// Don't tick a_Client anymore, it will be ticked from its cPlayer instead
|
/** Don't tick a_Client anymore, it will be ticked from its cPlayer instead */
|
||||||
void ClientMovedToWorld(const cClientHandle * a_Client);
|
void ClientMovedToWorld(const cClientHandle * a_Client);
|
||||||
|
|
||||||
/// Notifies the server that a player was created; the server uses this to adjust the number of players
|
/** Notifies the server that a player was created; the server uses this to adjust the number of players */
|
||||||
void PlayerCreated(const cPlayer * a_Player);
|
void PlayerCreated(const cPlayer * a_Player);
|
||||||
|
|
||||||
/// Notifies the server that a player is being destroyed; the server uses this to adjust the number of players
|
/** Notifies the server that a player is being destroyed; the server uses this to adjust the number of players */
|
||||||
void PlayerDestroying(const cPlayer * a_Player);
|
void PlayerDestroying(const cPlayer * a_Player);
|
||||||
|
|
||||||
/** Returns base64 encoded favicon data (obtained from favicon.png) */
|
/** Returns base64 encoded favicon data (obtained from favicon.png) */
|
||||||
@ -112,11 +112,13 @@ public: // tolua_export
|
|||||||
cRSAPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
|
cRSAPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
|
||||||
const AString & GetPublicKeyDER(void) const { return m_PublicKeyDER; }
|
const AString & GetPublicKeyDER(void) const { return m_PublicKeyDER; }
|
||||||
|
|
||||||
|
bool ShouldAuthenticate(void) const { return m_ShouldAuthenticate; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class cRoot; // so cRoot can create and destroy cServer
|
friend class cRoot; // so cRoot can create and destroy cServer
|
||||||
|
|
||||||
/// When NotifyClientWrite() is called, it is queued for this thread to process (to avoid deadlocks between cSocketThreads, cClientHandle and cChunkMap)
|
/** When NotifyClientWrite() is called, it is queued for this thread to process (to avoid deadlocks between cSocketThreads, cClientHandle and cChunkMap) */
|
||||||
class cNotifyWriteThread :
|
class cNotifyWriteThread :
|
||||||
public cIsThread
|
public cIsThread
|
||||||
{
|
{
|
||||||
@ -140,7 +142,7 @@ private:
|
|||||||
void NotifyClientWrite(const cClientHandle * a_Client);
|
void NotifyClientWrite(const cClientHandle * a_Client);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
/// The server tick thread takes care of the players who aren't yet spawned in a world
|
/** The server tick thread takes care of the players who aren't yet spawned in a world */
|
||||||
class cTickThread :
|
class cTickThread :
|
||||||
public cIsThread
|
public cIsThread
|
||||||
{
|
{
|
||||||
@ -195,18 +197,22 @@ private:
|
|||||||
cTickThread m_TickThread;
|
cTickThread m_TickThread;
|
||||||
cEvent m_RestartEvent;
|
cEvent m_RestartEvent;
|
||||||
|
|
||||||
/// The server ID used for client authentication
|
/** The server ID used for client authentication */
|
||||||
AString m_ServerID;
|
AString m_ServerID;
|
||||||
|
|
||||||
|
/** If true, players will be online-authenticated agains Mojang servers.
|
||||||
|
This setting is the same as the "online-mode" setting in Vanilla. */
|
||||||
|
bool m_ShouldAuthenticate;
|
||||||
|
|
||||||
|
|
||||||
cServer(void);
|
cServer(void);
|
||||||
|
|
||||||
/// Loads, or generates, if missing, RSA keys for protocol encryption
|
/** Loads, or generates, if missing, RSA keys for protocol encryption */
|
||||||
void PrepareKeys(void);
|
void PrepareKeys(void);
|
||||||
|
|
||||||
bool Tick(float a_Dt);
|
bool Tick(float a_Dt);
|
||||||
|
|
||||||
/// Ticks the clients in m_Clients, manages the list in respect to removing clients
|
/** Ticks the clients in m_Clients, manages the list in respect to removing clients */
|
||||||
void TickClients(float a_Dt);
|
void TickClients(float a_Dt);
|
||||||
|
|
||||||
// cListenThread::cCallback overrides:
|
// cListenThread::cCallback overrides:
|
||||||
|
@ -833,7 +833,8 @@ AString Base64Encode(const AString & a_Input)
|
|||||||
|
|
||||||
short GetBEShort(const char * a_Mem)
|
short GetBEShort(const char * a_Mem)
|
||||||
{
|
{
|
||||||
return (((short)a_Mem[0]) << 8) | a_Mem[1];
|
const Byte * Bytes = (const Byte *)a_Mem;
|
||||||
|
return (Bytes[0] << 8) | Bytes[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -842,7 +843,8 @@ short GetBEShort(const char * a_Mem)
|
|||||||
|
|
||||||
int GetBEInt(const char * a_Mem)
|
int GetBEInt(const char * a_Mem)
|
||||||
{
|
{
|
||||||
return (((int)a_Mem[0]) << 24) | (((int)a_Mem[1]) << 16) | (((int)a_Mem[2]) << 8) | a_Mem[3];
|
const Byte * Bytes = (const Byte *)a_Mem;
|
||||||
|
return (Bytes[0] << 24) | (Bytes[1] << 16) | (Bytes[2] << 8) | Bytes[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||||
|
|
||||||
#include "BlockID.h"
|
#include "BlockID.h"
|
||||||
@ -234,7 +233,7 @@ cWorld::cWorld(const AString & a_WorldName) :
|
|||||||
m_WorldName(a_WorldName),
|
m_WorldName(a_WorldName),
|
||||||
m_IniFileName(m_WorldName + "/world.ini"),
|
m_IniFileName(m_WorldName + "/world.ini"),
|
||||||
m_StorageSchema("Default"),
|
m_StorageSchema("Default"),
|
||||||
#ifdef _arm_
|
#ifdef __arm__
|
||||||
m_StorageCompressionFactor(0),
|
m_StorageCompressionFactor(0),
|
||||||
#else
|
#else
|
||||||
m_StorageCompressionFactor(6),
|
m_StorageCompressionFactor(6),
|
||||||
@ -547,6 +546,7 @@ void cWorld::Start(void)
|
|||||||
m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", false);
|
m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", false);
|
||||||
m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true);
|
m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true);
|
||||||
m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false);
|
m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false);
|
||||||
|
m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true);
|
||||||
|
|
||||||
m_GameMode = (eGameMode)IniFile.GetValueSetI("GameMode", "GameMode", m_GameMode);
|
m_GameMode = (eGameMode)IniFile.GetValueSetI("GameMode", "GameMode", m_GameMode);
|
||||||
|
|
||||||
|
@ -139,6 +139,8 @@ public:
|
|||||||
|
|
||||||
bool ShouldLavaSpawnFire(void) const { return m_ShouldLavaSpawnFire; }
|
bool ShouldLavaSpawnFire(void) const { return m_ShouldLavaSpawnFire; }
|
||||||
|
|
||||||
|
bool VillagersShouldHarvestCrops(void) const { return m_VillagersShouldHarvestCrops; }
|
||||||
|
|
||||||
virtual eDimension GetDimension(void) const { return m_Dimension; }
|
virtual eDimension GetDimension(void) const { return m_Dimension; }
|
||||||
|
|
||||||
/** Returns the world height at the specified coords; waits for the chunk to get loaded / generated */
|
/** Returns the world height at the specified coords; waits for the chunk to get loaded / generated */
|
||||||
@ -747,6 +749,7 @@ private:
|
|||||||
bool m_bEnabledPVP;
|
bool m_bEnabledPVP;
|
||||||
bool m_IsDeepSnowEnabled;
|
bool m_IsDeepSnowEnabled;
|
||||||
bool m_ShouldLavaSpawnFire;
|
bool m_ShouldLavaSpawnFire;
|
||||||
|
bool m_VillagersShouldHarvestCrops;
|
||||||
|
|
||||||
std::vector<BlockTickQueueItem *> m_BlockTickQueue;
|
std::vector<BlockTickQueueItem *> m_BlockTickQueue;
|
||||||
std::vector<BlockTickQueueItem *> m_BlockTickQueueCopy; // Second is for safely removing the objects from the queue
|
std::vector<BlockTickQueueItem *> m_BlockTickQueueCopy; // Second is for safely removing the objects from the queue
|
||||||
|
@ -454,8 +454,8 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
|
|||||||
}
|
}
|
||||||
case cMonster::mtWolf:
|
case cMonster::mtWolf:
|
||||||
{
|
{
|
||||||
// TODO:
|
m_Writer.AddString("Owner", ((const cWolf *)a_Monster)->GetOwner());
|
||||||
// _X: CopyPasta error: m_Writer.AddInt("Profession", ((const cVillager *)a_Monster)->GetVilType());
|
m_Writer.AddByte("Sitting", ((const cWolf *)a_Monster)->IsSitting());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case cMonster::mtZombie:
|
case cMonster::mtZombie:
|
||||||
|
@ -611,12 +611,18 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
|
|||||||
|
|
||||||
bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_TagIdx)
|
bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
{
|
{
|
||||||
int ID = a_NBT.FindChildByName(a_TagIdx, "id");
|
int Type = a_NBT.FindChildByName(a_TagIdx, "id");
|
||||||
if ((ID < 0) || (a_NBT.GetType(ID) != TAG_Short))
|
if ((Type < 0) || (a_NBT.GetType(Type) != TAG_Short))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
a_Item.m_ItemType = (ENUM_ITEM_ID)(a_NBT.GetShort(ID));
|
a_Item.m_ItemType = a_NBT.GetShort(Type);
|
||||||
|
if (a_Item.m_ItemType < 0)
|
||||||
|
{
|
||||||
|
LOGD("Encountered an item with negative type (%d). Replacing with an empty item.", a_NBT.GetShort(Type));
|
||||||
|
a_Item.Empty();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int Damage = a_NBT.FindChildByName(a_TagIdx, "Damage");
|
int Damage = a_NBT.FindChildByName(a_TagIdx, "Damage");
|
||||||
if ((Damage < 0) || (a_NBT.GetType(Damage) != TAG_Short))
|
if ((Damage < 0) || (a_NBT.GetType(Damage) != TAG_Short))
|
||||||
@ -1870,7 +1876,16 @@ void cWSSAnvil::LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
int OwnerIdx = a_NBT.FindChildByName(a_TagIdx, "Owner");
|
||||||
|
if (OwnerIdx > 0)
|
||||||
|
{
|
||||||
|
AString OwnerName = a_NBT.GetString(OwnerIdx);
|
||||||
|
if (OwnerName != "")
|
||||||
|
{
|
||||||
|
Monster->SetOwner(OwnerName);
|
||||||
|
Monster->SetIsTame(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
a_Entities.push_back(Monster.release());
|
a_Entities.push_back(Monster.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
34
src/main.cpp
34
src/main.cpp
@ -19,8 +19,11 @@ bool g_SERVER_TERMINATED = false; // Set to true when the server terminates, so
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** If set to true, the protocols will log each player's communication to a separate logfile */
|
/** If set to true, the protocols will log each player's incoming (C->S) communication to a per-connection logfile */
|
||||||
bool g_ShouldLogComm;
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -66,11 +69,13 @@ void NonCtrlHandler(int a_Signal)
|
|||||||
std::signal(a_Signal, SIG_DFL);
|
std::signal(a_Signal, SIG_DFL);
|
||||||
LOGERROR(" D: | MCServer has encountered an error and needs to close");
|
LOGERROR(" D: | MCServer has encountered an error and needs to close");
|
||||||
LOGERROR("Details | SIGABRT: Server self-terminated due to an internal fault");
|
LOGERROR("Details | SIGABRT: Server self-terminated due to an internal fault");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SIGINT:
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
{
|
{
|
||||||
std::signal(SIGTERM, SIG_IGN); // Server is shutting down, wait for it...
|
std::signal(a_Signal, SIG_IGN); // Server is shutting down, wait for it...
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: break;
|
default: break;
|
||||||
@ -224,6 +229,10 @@ int main( int argc, char **argv )
|
|||||||
std::signal(SIGSEGV, NonCtrlHandler);
|
std::signal(SIGSEGV, NonCtrlHandler);
|
||||||
std::signal(SIGTERM, NonCtrlHandler);
|
std::signal(SIGTERM, NonCtrlHandler);
|
||||||
std::signal(SIGINT, NonCtrlHandler);
|
std::signal(SIGINT, NonCtrlHandler);
|
||||||
|
std::signal(SIGABRT, NonCtrlHandler);
|
||||||
|
#ifdef SIGABRT_COMPAT
|
||||||
|
std::signal(SIGABRT_COMPAT, NonCtrlHandler);
|
||||||
|
#endif // SIGABRT_COMPAT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// DEBUG: test the dumpfile creation:
|
// DEBUG: test the dumpfile creation:
|
||||||
@ -237,7 +246,24 @@ int main( int argc, char **argv )
|
|||||||
(NoCaseCompare(argv[i], "/logcomm") == 0)
|
(NoCaseCompare(argv[i], "/logcomm") == 0)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
g_ShouldLogComm = true;
|
g_ShouldLogCommIn = true;
|
||||||
|
g_ShouldLogCommOut = true;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
(NoCaseCompare(argv[i], "/commlogin") == 0) ||
|
||||||
|
(NoCaseCompare(argv[i], "/comminlog") == 0) ||
|
||||||
|
(NoCaseCompare(argv[i], "/logcommin") == 0)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
g_ShouldLogCommIn = true;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
(NoCaseCompare(argv[i], "/commlogout") == 0) ||
|
||||||
|
(NoCaseCompare(argv[i], "/commoutlog") == 0) ||
|
||||||
|
(NoCaseCompare(argv[i], "/logcommout") == 0)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
g_ShouldLogCommOut = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user