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.
|
||||
|
||||
faketruth (founder)
|
||||
xoft
|
||||
keyboard
|
||||
STR_Warrior
|
||||
mgueydan
|
||||
tigerw
|
||||
bearbin (Alexander Harkness)
|
||||
Lapayo
|
||||
rs2k
|
||||
derouinw
|
||||
Diusrex
|
||||
Duralex
|
||||
mtilden
|
||||
FakeTruth (founder)
|
||||
keyboard
|
||||
Lapayo
|
||||
Luksor
|
||||
marmot21
|
||||
Sofapriester
|
||||
mborland
|
||||
mgueydan
|
||||
MikeHunsinger
|
||||
mtilden
|
||||
nesco
|
||||
rs2k
|
||||
SamJBarney
|
||||
worktycho
|
||||
Sxw1212
|
||||
tonibm19
|
||||
Diusrex
|
||||
Sofapriester
|
||||
STR_Warrior
|
||||
structinf (xdot)
|
||||
Sxw1212
|
||||
Taugeshtu
|
||||
tigerw (Tiger Wang)
|
||||
tonibm19
|
||||
worktycho
|
||||
xoft
|
||||
|
||||
|
||||
Please add yourself to this list if you contribute to MCServer.
|
||||
|
|
|
@ -813,6 +813,20 @@ cFile:Delete("/usr/bin/virus.exe");
|
|||
},
|
||||
}, -- 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 =
|
||||
{
|
||||
Desc = [[
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
</p>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<h2>Creating the basic template</h2>
|
||||
|
@ -35,19 +35,14 @@
|
|||
Format it like so:
|
||||
</p>
|
||||
<pre class="prettyprint lang-lua">
|
||||
local PLUGIN
|
||||
PLUGIN = nil
|
||||
|
||||
function Initialize(Plugin)
|
||||
Plugin:SetName("DerpyPlugin")
|
||||
Plugin:SetName("NewPlugin")
|
||||
Plugin:SetVersion(1)
|
||||
|
||||
PLUGIN = Plugin
|
||||
|
||||
-- Hooks
|
||||
|
||||
local PluginManager = cPluginManager:Get()
|
||||
-- Command bindings
|
||||
|
||||
LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
|
||||
return true
|
||||
end
|
||||
|
@ -84,7 +79,7 @@ end
|
|||
To register a hook, insert the following code template into the "-- Hooks" area in the previous code example.
|
||||
</p>
|
||||
<pre class="prettyprint lang-lua">
|
||||
cPluginManager:AddHook(cPluginManager.HOOK_NAME_HERE, FunctionNameToBeCalled)
|
||||
cPluginManager.AddHook(cPluginManager.HOOK_NAME_HERE, FunctionNameToBeCalled)
|
||||
</pre>
|
||||
<p>
|
||||
What does this code do?
|
||||
|
@ -102,10 +97,7 @@ function Initialize(Plugin)
|
|||
Plugin:SetName("DerpyPlugin")
|
||||
Plugin:SetVersion(1)
|
||||
|
||||
cPluginManager:AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving)
|
||||
|
||||
local PluginManager = cPluginManager:Get()
|
||||
-- Command bindings
|
||||
cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving)
|
||||
|
||||
LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
|
||||
return true
|
||||
|
@ -127,10 +119,10 @@ end
|
|||
</p>
|
||||
<pre class="prettyprint lang-lua">
|
||||
-- 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)
|
||||
PluginManager:BindCommand("/commandname", "permissionnode", FunctionToCall, " ~ Description of command and parameter(s)")
|
||||
cPluginManager.BindCommand("/commandname", "permissionnode", FunctionToCall, " ~ Description of command and parameter(s)")
|
||||
</pre>
|
||||
<p>
|
||||
What does it do, and why are there two?
|
||||
|
@ -197,8 +189,7 @@ function Initialize(Plugin)
|
|||
Plugin:SetName("DerpyPluginThatBlowsPeopleUp")
|
||||
Plugin:SetVersion(9001)
|
||||
|
||||
local PluginManager = cPluginManager:Get()
|
||||
PluginManager:BindCommand("/explode", "derpyplugin.explode", Explode, " ~ Explode a player");
|
||||
cPluginManager.BindCommand("/explode", "derpyplugin.explode", Explode, " ~ Explode a player");
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
|
|
@ -1302,6 +1302,7 @@ bool cConnection::HandleServerLoginEncryptionKeyRequest(void)
|
|||
}
|
||||
Log("Got PACKET_ENCRYPTION_KEY_REQUEST from the SERVER:");
|
||||
Log(" ServerID = %s", ServerID.c_str());
|
||||
DataLog(PublicKey.data(), PublicKey.size(), " Public key (%u bytes)", (unsigned)PublicKey.size());
|
||||
|
||||
// Reply to the server:
|
||||
SendEncryptionKeyResponse(PublicKey, Nonce);
|
||||
|
@ -2863,14 +2864,25 @@ void cConnection::SendEncryptionKeyResponse(const AString & a_ServerPublicKey, c
|
|||
Byte SharedSecret[16];
|
||||
Byte EncryptedSecret[128];
|
||||
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_ServerDecryptor.Init(SharedSecret, SharedSecret);
|
||||
|
||||
// Encrypt the nonce:
|
||||
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:
|
||||
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.WriteBEShort((short)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);
|
||||
m_ServerState = csEncryptedUnderstood;
|
||||
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))
|
||||
{
|
||||
// Not a valid function, bail out
|
||||
lua_pop(m_LuaState, 2);
|
||||
lua_pop(m_LuaState, 3);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pop the table off the stack:
|
||||
lua_remove(m_LuaState, -2);
|
||||
|
||||
Printf(m_CurrentFunctionName, "<table-callback %s>", a_TableRef.GetFnName());
|
||||
m_NumCurrentFunctionArgs = 0;
|
||||
return true;
|
||||
|
|
|
@ -1429,7 +1429,10 @@ static int tolua_cPluginManager_BindCommand(lua_State * L)
|
|||
// Read the arguments to this API call:
|
||||
tolua_Error tolua_err;
|
||||
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++;
|
||||
}
|
||||
|
@ -2128,26 +2131,40 @@ protected:
|
|||
|
||||
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);
|
||||
if (
|
||||
!L.CheckParamUserType(1, "cWorld") ||
|
||||
!L.CheckParamTable (2) ||
|
||||
!L.CheckParamNumber (3, 8) ||
|
||||
!L.CheckParamEnd (9)
|
||||
!L.CheckParamUserType(idx, "cWorld") ||
|
||||
!L.CheckParamTable (idx + 1) ||
|
||||
!L.CheckParamNumber (idx + 2, idx + 7) ||
|
||||
!L.CheckParamEnd (idx + 8)
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
cWorld * World = (cWorld *)tolua_tousertype(L, 1, NULL);
|
||||
cLuaBlockTracerCallbacks Callbacks(L, 2);
|
||||
double StartX = tolua_tonumber(L, 3, 0);
|
||||
double StartY = tolua_tonumber(L, 4, 0);
|
||||
double StartZ = tolua_tonumber(L, 5, 0);
|
||||
double EndX = tolua_tonumber(L, 6, 0);
|
||||
double EndY = tolua_tonumber(L, 7, 0);
|
||||
double EndZ = tolua_tonumber(L, 8, 0);
|
||||
// Trace:
|
||||
cWorld * World = (cWorld *)tolua_tousertype(L, idx, NULL);
|
||||
cLuaBlockTracerCallbacks Callbacks(L, idx + 1);
|
||||
double StartX = tolua_tonumber(L, idx + 2, 0);
|
||||
double StartY = tolua_tonumber(L, idx + 3, 0);
|
||||
double StartZ = tolua_tonumber(L, idx + 4, 0);
|
||||
double EndX = tolua_tonumber(L, idx + 5, 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);
|
||||
tolua_pushboolean(L, res ? 1 : 0);
|
||||
return 1;
|
||||
|
|
|
@ -88,36 +88,55 @@ bool cPluginLua::Initialize(void)
|
|||
|
||||
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());
|
||||
|
||||
int numFiles = 0;
|
||||
for (AStringVector::const_iterator itr = Files.begin(); itr != Files.end(); ++itr)
|
||||
AStringVector LuaFiles;
|
||||
bool HasInfoLua = false;
|
||||
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")
|
||||
{
|
||||
HasInfoLua = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LuaFiles.push_back(*itr);
|
||||
}
|
||||
}
|
||||
AString Path = PluginPath + *itr;
|
||||
if (!m_LuaState.LoadFile(Path))
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
numFiles++;
|
||||
}
|
||||
} // 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());
|
||||
Close();
|
||||
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;
|
||||
if (!m_LuaState.Call("Initialize", this, cLuaState::Return, res))
|
||||
{
|
||||
|
@ -125,7 +144,6 @@ bool cPluginLua::Initialize(void)
|
|||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!res)
|
||||
{
|
||||
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_NETHER_PORTAL] = 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_RAIL] = false;
|
||||
g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_OFF] = false;
|
||||
|
|
|
@ -54,6 +54,7 @@ public:
|
|||
{
|
||||
TestRead();
|
||||
TestWrite();
|
||||
TestWrap();
|
||||
}
|
||||
|
||||
void TestRead(void)
|
||||
|
@ -61,11 +62,11 @@ public:
|
|||
cByteBuffer buf(50);
|
||||
buf.Write("\x05\xac\x02\x00", 4);
|
||||
UInt32 v1;
|
||||
ASSERT(buf.ReadVarInt(v1) && (v1 == 5));
|
||||
assert(buf.ReadVarInt(v1) && (v1 == 5));
|
||||
UInt32 v2;
|
||||
ASSERT(buf.ReadVarInt(v2) && (v2 == 300));
|
||||
assert(buf.ReadVarInt(v2) && (v2 == 300));
|
||||
UInt32 v3;
|
||||
ASSERT(buf.ReadVarInt(v3) && (v3 == 0));
|
||||
assert(buf.ReadVarInt(v3) && (v3 == 0));
|
||||
}
|
||||
|
||||
void TestWrite(void)
|
||||
|
@ -76,9 +77,30 @@ public:
|
|||
buf.WriteVarInt(0);
|
||||
AString All;
|
||||
buf.ReadAll(All);
|
||||
ASSERT(All.size() == 4);
|
||||
ASSERT(memcmp(All.data(), "\x05\xac\x02\x00", All.size()) == 0);
|
||||
assert(All.size() == 4);
|
||||
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;
|
||||
|
||||
#endif
|
||||
|
@ -159,7 +181,7 @@ bool cByteBuffer::Write(const char * a_Bytes, int a_Count)
|
|||
int CurReadableSpace = GetReadableSpace();
|
||||
int WrittenBytes = 0;
|
||||
|
||||
if (GetFreeSpace() < a_Count)
|
||||
if (CurFreeSpace < a_Count)
|
||||
{
|
||||
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!");
|
||||
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",
|
||||
__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!");
|
||||
return -1;
|
||||
}
|
||||
size_t DecryptedLength;
|
||||
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
|
||||
);
|
||||
if (res != 0)
|
||||
{
|
||||
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/ctr_drbg.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 */
|
||||
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)
|
||||
{
|
||||
// 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();
|
||||
}
|
||||
|
@ -710,8 +711,6 @@ void cFireworkEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
|
|||
SetSpeed(0, 0, 0);
|
||||
SetPosition(GetPosX(), GetPosY() - 0.5, GetPosZ());
|
||||
|
||||
std::cout << a_HitPos.x << " " << a_HitPos.y << " " << a_HitPos.z << std::endl;
|
||||
|
||||
m_IsInGround = true;
|
||||
|
||||
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)
|
||||
{
|
||||
const NIBBLETYPE * AreaMetas = m_BlockArea.GetBlockMetas();
|
||||
|
|
|
@ -30,7 +30,7 @@ class cChunkDesc
|
|||
public:
|
||||
// tolua_end
|
||||
|
||||
/// Uncompressed block metas, 1 meta per byte
|
||||
/** Uncompressed block metas, 1 meta per byte */
|
||||
typedef NIBBLETYPE BlockNibbleBytes[cChunkDef::NumBlocks];
|
||||
|
||||
cChunkDesc(int a_ChunkX, int a_ChunkZ);
|
||||
|
@ -56,6 +56,8 @@ public:
|
|||
void SetBiome(int a_RelX, int a_RelZ, int a_BiomeID);
|
||||
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);
|
||||
int GetHeight(int a_RelX, int a_RelZ);
|
||||
|
||||
|
@ -71,16 +73,16 @@ public:
|
|||
void SetUseDefaultFinish(bool a_bUseDefaultFinish);
|
||||
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);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// Returns the maximum height value in the heightmap
|
||||
/** Returns the maximum height value in the heightmap */
|
||||
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(
|
||||
int a_MinX, int a_MaxX,
|
||||
int a_MinY, int a_MaxY,
|
||||
|
@ -88,7 +90,7 @@ public:
|
|||
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)
|
||||
{
|
||||
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(
|
||||
int a_MinX, int a_MaxX,
|
||||
int a_MinY, int a_MaxY,
|
||||
|
@ -108,7 +110,7 @@ public:
|
|||
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(
|
||||
const cCuboid & a_RelCuboid,
|
||||
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(
|
||||
int a_MinX, int a_MaxX,
|
||||
int a_MinY, int a_MaxY,
|
||||
|
@ -132,7 +134,7 @@ public:
|
|||
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(
|
||||
const cCuboid & a_RelCuboid,
|
||||
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(
|
||||
int a_MinX, int a_MaxX,
|
||||
int a_MinY, int a_MaxY,
|
||||
|
@ -155,7 +157,7 @@ public:
|
|||
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(
|
||||
const cCuboid & a_RelCuboid, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
|
||||
int a_RandomSeed, int a_ChanceOutOf10k
|
||||
|
@ -170,11 +172,15 @@ public:
|
|||
);
|
||||
}
|
||||
|
||||
/// 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 the blocktype doesn't support a block entity, returns NULL.
|
||||
/** 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 the blocktype doesn't support a block entity, returns NULL. */
|
||||
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
|
||||
|
||||
// Accessors used by cChunkGenerator::Generator descendants:
|
||||
|
@ -187,11 +193,11 @@ public:
|
|||
inline cEntityList & GetEntities (void) { return m_Entities; }
|
||||
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);
|
||||
|
||||
#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);
|
||||
#endif // _DEBUG
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
|
||||
|
||||
|
||||
cChicken::cChicken(void) :
|
||||
super("Chicken", mtChicken, "mob.chicken.hurt", "mob.chicken.hurt", 0.3, 0.4),
|
||||
m_EggDropTimer(0)
|
||||
|
|
|
@ -19,8 +19,9 @@ public:
|
|||
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) 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;
|
||||
} ;
|
||||
|
|
|
@ -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 OnRightClicked(cPlayer & a_Player) override;
|
||||
|
||||
virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_WHEAT); }
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
|
||||
|
||||
|
||||
// TODO: Milk Cow
|
||||
|
||||
|
||||
|
@ -30,4 +29,3 @@ void cMooshroom::GetDrops(cItems & a_Drops, cEntity * a_Killer)
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ public:
|
|||
CLASS_PROTODEF(cMooshroom);
|
||||
|
||||
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 "../World.h"
|
||||
|
||||
#include "../Entities/Player.h"
|
||||
|
||||
|
||||
|
||||
|
@ -39,6 +39,20 @@ void cPassiveMonster::Tick(float a_Dt, cChunk & a_Chunk)
|
|||
{
|
||||
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
|
||||
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 OnRightClicked(cPlayer & a_Player) override;
|
||||
|
||||
virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_CARROT); }
|
||||
|
||||
bool IsSaddled(void) const { return m_bIsSaddled; }
|
||||
|
||||
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 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; }
|
||||
int GetFurColor(void) const { return m_WoolColor; }
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "Villager.h"
|
||||
#include "../World.h"
|
||||
#include "../BlockArea.h"
|
||||
#include "../Blocks/BlockHandler.h"
|
||||
|
||||
|
||||
|
||||
|
@ -10,7 +12,9 @@
|
|||
|
||||
cVillager::cVillager(eVillagerType VillagerType) :
|
||||
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);
|
||||
|
||||
// Override functions
|
||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
int GetVilType(void) const { return m_Type; }
|
||||
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; }
|
||||
Vector3i GetCropsPos(void) const { return m_CropsPos; }
|
||||
bool DoesHaveActionActivated(void) const { return m_VillagerAction; }
|
||||
|
||||
private:
|
||||
|
||||
int m_ActionCountDown;
|
||||
int m_Type;
|
||||
bool m_VillagerAction;
|
||||
Vector3i m_CropsPos;
|
||||
|
||||
} ;
|
||||
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
#ifndef _WIN32
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h> //inet_ntoa()
|
||||
#include <arpa/inet.h> // inet_ntoa()
|
||||
#include <sys/ioctl.h> // ioctl()
|
||||
#else
|
||||
#define socklen_t int
|
||||
#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);
|
||||
}
|
||||
|
@ -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,
|
||||
IPv6 = AF_INET6,
|
||||
|
||||
#ifdef _WIN32
|
||||
ErrWouldBlock = WSAEWOULDBLOCK,
|
||||
#else
|
||||
ErrWouldBlock = EWOULDBLOCK,
|
||||
#endif
|
||||
} ;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -111,6 +117,9 @@ public:
|
|||
|
||||
const AString & GetIPString(void) const { return m_IPString; }
|
||||
|
||||
/** Sets the socket into non-blocking mode */
|
||||
void SetNonBlocking(void);
|
||||
|
||||
private:
|
||||
xSocket m_Socket;
|
||||
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_Socket = a_Socket;
|
||||
m_Slots[m_NumSlots].m_Socket.SetNonBlocking();
|
||||
m_Slots[m_NumSlots].m_Outgoing.clear();
|
||||
m_Slots[m_NumSlots].m_State = sSlot::ssNormal;
|
||||
m_NumSlots++;
|
||||
|
@ -213,7 +214,9 @@ bool cSocketThreads::cSocketThread::RemoveClient(const cCallback * a_Client)
|
|||
else
|
||||
{
|
||||
// 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())
|
||||
{
|
||||
// No more outgoing data, shut the socket down immediately:
|
||||
|
@ -386,38 +389,28 @@ void cSocketThreads::cSocketThread::Execute(void)
|
|||
// The main thread loop:
|
||||
while (!m_ShouldTerminate)
|
||||
{
|
||||
// Put all sockets into the Read set:
|
||||
fd_set fdRead;
|
||||
cSocket::xSocket Highest = m_ControlSocket1.GetSocket();
|
||||
// Read outgoing data from the clients:
|
||||
QueueOutgoingData();
|
||||
|
||||
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:
|
||||
timeval Timeout;
|
||||
Timeout.tv_sec = 5;
|
||||
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;
|
||||
}
|
||||
|
||||
// Perform the IO:
|
||||
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);
|
||||
|
||||
CleanUpShutSockets();
|
||||
} // 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_SET(m_ControlSocket1.GetSocket(), a_Set);
|
||||
FD_ZERO(a_Read);
|
||||
FD_ZERO(a_Write);
|
||||
FD_SET(m_ControlSocket1.GetSocket(), a_Read);
|
||||
|
||||
cCSLock Lock(m_Parent->m_CS);
|
||||
for (int i = m_NumSlots - 1; i >= 0; --i)
|
||||
|
@ -444,11 +438,16 @@ void cSocketThreads::cSocketThread::PrepareSet(fd_set * a_Set, cSocket::xSocket
|
|||
continue;
|
||||
}
|
||||
cSocket::xSocket s = m_Slots[i].m_Socket.GetSocket();
|
||||
FD_SET(s, a_Set);
|
||||
FD_SET(s, a_Read);
|
||||
if (s > a_Highest)
|
||||
{
|
||||
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[]
|
||||
}
|
||||
|
||||
|
@ -480,34 +479,37 @@ void cSocketThreads::cSocketThread::ReadFromSockets(fd_set * a_Read)
|
|||
int Received = m_Slots[i].m_Socket.Receive(Buffer, ARRAYCOUNT(Buffer), 0);
|
||||
if (Received <= 0)
|
||||
{
|
||||
// The socket has been closed by the remote party
|
||||
switch (m_Slots[i].m_State)
|
||||
if (cSocket::GetLastError() != cSocket::ErrWouldBlock)
|
||||
{
|
||||
case sSlot::ssNormal:
|
||||
// The socket has been closed by the remote party
|
||||
switch (m_Slots[i].m_State)
|
||||
{
|
||||
// Notify the callback that the remote has closed the socket; keep the slot
|
||||
m_Slots[i].m_Client->SocketClosed();
|
||||
m_Slots[i].m_State = sSlot::ssRemoteClosed;
|
||||
break;
|
||||
}
|
||||
case sSlot::ssWritingRestOut:
|
||||
case sSlot::ssShuttingDown:
|
||||
case sSlot::ssShuttingDown2:
|
||||
{
|
||||
// Force-close the socket and remove the slot:
|
||||
m_Slots[i].m_Socket.CloseSocket();
|
||||
m_Slots[i] = m_Slots[--m_NumSlots];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG("%s: Unexpected socket state: %d (%s)",
|
||||
__FUNCTION__, m_Slots[i].m_Socket.GetSocket(), m_Slots[i].m_Socket.GetIPString().c_str()
|
||||
);
|
||||
ASSERT(!"Unexpected socket state");
|
||||
break;
|
||||
}
|
||||
} // switch (m_Slots[i].m_State)
|
||||
case sSlot::ssNormal:
|
||||
{
|
||||
// Notify the callback that the remote has closed the socket; keep the slot
|
||||
m_Slots[i].m_Client->SocketClosed();
|
||||
m_Slots[i].m_State = sSlot::ssRemoteClosed;
|
||||
break;
|
||||
}
|
||||
case sSlot::ssWritingRestOut:
|
||||
case sSlot::ssShuttingDown:
|
||||
case sSlot::ssShuttingDown2:
|
||||
{
|
||||
// Force-close the socket and remove the slot:
|
||||
m_Slots[i].m_Socket.CloseSocket();
|
||||
m_Slots[i] = m_Slots[--m_NumSlots];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG("%s: Unexpected socket state: %d (%s)",
|
||||
__FUNCTION__, m_Slots[i].m_Socket.GetSocket(), m_Slots[i].m_Socket.GetIPString().c_str()
|
||||
);
|
||||
ASSERT(!"Unexpected socket state");
|
||||
break;
|
||||
}
|
||||
} // switch (m_Slots[i].m_State)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -539,7 +541,9 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write)
|
|||
// Request another chunk of outgoing data:
|
||||
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())
|
||||
{
|
||||
|
@ -553,8 +557,7 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write)
|
|||
}
|
||||
} // 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 (Sent < 0)
|
||||
if (!SendDataThroughSocket(m_Slots[i].m_Socket, m_Slots[i].m_Outgoing))
|
||||
{
|
||||
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());
|
||||
|
@ -565,7 +568,6 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write)
|
|||
}
|
||||
return;
|
||||
}
|
||||
m_Slots[i].m_Outgoing.erase(0, Sent);
|
||||
|
||||
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)
|
||||
{
|
||||
cCSLock Lock(m_Parent->m_CS);
|
||||
for (int i = m_NumSlots - 1; i >= 0; i--)
|
||||
{
|
||||
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 */
|
||||
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;
|
||||
|
||||
/** Called when the socket has been closed for any reason */
|
||||
|
@ -156,16 +157,27 @@ private:
|
|||
|
||||
virtual void Execute(void) override;
|
||||
|
||||
/** Puts all sockets into the set, along with m_ControlSocket1.
|
||||
Only sockets that are able to send and receive data are put in the Set.
|
||||
Is a_IsForWriting is true, the ssWritingRestOut sockets are added as well. */
|
||||
void PrepareSet(fd_set * a_Set, cSocket::xSocket & a_Highest, bool a_IsForWriting);
|
||||
/** Prepares the Read and Write socket sets for select()
|
||||
Puts all sockets into the read set, along with m_ControlSocket1.
|
||||
Only sockets that have outgoing data queued on them are put in the write set.*/
|
||||
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
|
||||
void WriteToSockets (fd_set * a_Write); // Writes to sockets indicated in a_Write
|
||||
/** Reads from sockets indicated in a_Read */
|
||||
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 */
|
||||
void CleanUpShutSockets(void);
|
||||
|
||||
/** Calls each client's callback to retrieve outgoing data for that client. */
|
||||
void QueueOutgoingData(void);
|
||||
} ;
|
||||
|
||||
typedef std::list<cSocketThread *> cSocketThreadList;
|
||||
|
|
|
@ -28,7 +28,7 @@ long long cTimer::GetNowTime(void)
|
|||
#else
|
||||
struct timeval now;
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
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)
|
||||
{
|
||||
// Create the comm log file, if so requested:
|
||||
if (g_ShouldLogComm)
|
||||
if (g_ShouldLogCommIn || g_ShouldLogCommOut)
|
||||
{
|
||||
cFile::CreateFolder("CommLogs");
|
||||
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.WriteShort((short)a_BlockY);
|
||||
Pkt.WriteInt(a_BlockZ);
|
||||
Pkt.WriteString(a_Line1);
|
||||
Pkt.WriteString(a_Line2);
|
||||
Pkt.WriteString(a_Line3);
|
||||
Pkt.WriteString(a_Line4);
|
||||
// Need to send only up to 15 chars, otherwise the client crashes (#598)
|
||||
Pkt.WriteString(a_Line1.substr(0, 15));
|
||||
Pkt.WriteString(a_Line2.substr(0, 15));
|
||||
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)
|
||||
{
|
||||
// Write the incoming data into the comm log file:
|
||||
if (g_ShouldLogComm)
|
||||
if (g_ShouldLogCommIn)
|
||||
{
|
||||
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.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("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()
|
||||
);
|
||||
}
|
||||
|
@ -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",
|
||||
a_Size, a_Size, Hex.c_str()
|
||||
);
|
||||
m_CommLogFile.Flush();
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
// Not enough data
|
||||
return;
|
||||
m_ReceivedData.ResetRead();
|
||||
break;
|
||||
}
|
||||
if (!m_ReceivedData.CanReadBytes(PacketLen))
|
||||
{
|
||||
// The full packet hasn't been received yet
|
||||
return;
|
||||
m_ReceivedData.ResetRead();
|
||||
break;
|
||||
}
|
||||
cByteBuffer bb(PacketLen + 1);
|
||||
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))
|
||||
{
|
||||
// Not enough data
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
// Log the packet info into the comm log file:
|
||||
if (g_ShouldLogComm)
|
||||
if (g_ShouldLogCommIn)
|
||||
{
|
||||
AString PacketData;
|
||||
bb.ReadAll(PacketData);
|
||||
|
@ -1173,7 +1184,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
|
|||
#endif // _DEBUG
|
||||
|
||||
// Put a message in the comm log:
|
||||
if (g_ShouldLogComm)
|
||||
if (g_ShouldLogCommIn)
|
||||
{
|
||||
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:
|
||||
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",
|
||||
1, bb.GetReadableSpace()
|
||||
|
@ -1200,7 +1211,24 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
|
|||
ASSERT(!"Read wrong number of bytes!");
|
||||
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)
|
||||
{
|
||||
// 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;
|
||||
a_ByteBuffer.ReadVarUTF8String(Username);
|
||||
|
||||
// TODO: Protocol encryption should be set up here if not localhost / auth
|
||||
|
||||
if (!m_Client->HandleHandshake(Username))
|
||||
{
|
||||
// The client is not welcome here, they have been sent a Kick packet already
|
||||
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:
|
||||
{
|
||||
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:
|
||||
|
||||
|
@ -1881,7 +1999,7 @@ cProtocol172::cPacketizer::~cPacketizer()
|
|||
m_Out.CommitRead();
|
||||
|
||||
// Log the comm into logfile:
|
||||
if (g_ShouldLogComm)
|
||||
if (g_ShouldLogCommOut)
|
||||
{
|
||||
AString Hex;
|
||||
ASSERT(DataToSend.size() > 0);
|
||||
|
|
|
@ -281,6 +281,8 @@ protected:
|
|||
|
||||
/// Parses item metadata as read by ReadItem(), into the item enchantments.
|
||||
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:
|
||||
#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"
|
||||
|
||||
|
||||
|
|
|
@ -200,7 +200,7 @@ void cRoot::Start(void)
|
|||
long long finishmseconds = Time.GetNowTime();
|
||||
finishmseconds -= mseconds;
|
||||
|
||||
LOG("Startup complete, took %i ms!", finishmseconds);
|
||||
LOG("Startup complete, took %lld ms!", finishmseconds);
|
||||
#ifdef _WIN32
|
||||
EnableMenuItem(hmenu, SC_CLOSE, MF_ENABLED); // Re-enable close button
|
||||
#endif
|
||||
|
|
|
@ -237,7 +237,8 @@ bool cServer::InitServer(cIniFile & a_SettingsIni)
|
|||
m_bIsConnected = true;
|
||||
|
||||
m_ServerID = "-";
|
||||
if (a_SettingsIni.GetValueSetB("Authentication", "Authenticate", true))
|
||||
m_ShouldAuthenticate = a_SettingsIni.GetValueSetB("Authentication", "Authenticate", true);
|
||||
if (m_ShouldAuthenticate)
|
||||
{
|
||||
MTRand mtrand1;
|
||||
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);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// Binds the built-in console commands with the plugin manager
|
||||
/** Binds the built-in console commands with the plugin manager */
|
||||
static void BindBuiltInConsoleCommands(void);
|
||||
|
||||
void Shutdown(void);
|
||||
|
@ -97,13 +97,13 @@ public: // tolua_export
|
|||
|
||||
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);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// 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);
|
||||
|
||||
/** Returns base64 encoded favicon data (obtained from favicon.png) */
|
||||
|
@ -112,11 +112,13 @@ public: // tolua_export
|
|||
cRSAPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
|
||||
const AString & GetPublicKeyDER(void) const { return m_PublicKeyDER; }
|
||||
|
||||
bool ShouldAuthenticate(void) const { return m_ShouldAuthenticate; }
|
||||
|
||||
private:
|
||||
|
||||
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 :
|
||||
public cIsThread
|
||||
{
|
||||
|
@ -140,7 +142,7 @@ private:
|
|||
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 :
|
||||
public cIsThread
|
||||
{
|
||||
|
@ -195,18 +197,22 @@ private:
|
|||
cTickThread m_TickThread;
|
||||
cEvent m_RestartEvent;
|
||||
|
||||
/// The server ID used for client authentication
|
||||
/** The server ID used for client authentication */
|
||||
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);
|
||||
|
||||
/// Loads, or generates, if missing, RSA keys for protocol encryption
|
||||
/** Loads, or generates, if missing, RSA keys for protocol encryption */
|
||||
void PrepareKeys(void);
|
||||
|
||||
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);
|
||||
|
||||
// cListenThread::cCallback overrides:
|
||||
|
|
|
@ -833,7 +833,8 @@ AString Base64Encode(const AString & a_Input)
|
|||
|
||||
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)
|
||||
{
|
||||
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 "BlockID.h"
|
||||
|
@ -234,7 +233,7 @@ cWorld::cWorld(const AString & a_WorldName) :
|
|||
m_WorldName(a_WorldName),
|
||||
m_IniFileName(m_WorldName + "/world.ini"),
|
||||
m_StorageSchema("Default"),
|
||||
#ifdef _arm_
|
||||
#ifdef __arm__
|
||||
m_StorageCompressionFactor(0),
|
||||
#else
|
||||
m_StorageCompressionFactor(6),
|
||||
|
@ -547,6 +546,7 @@ void cWorld::Start(void)
|
|||
m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", false);
|
||||
m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true);
|
||||
m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false);
|
||||
m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true);
|
||||
|
||||
m_GameMode = (eGameMode)IniFile.GetValueSetI("GameMode", "GameMode", m_GameMode);
|
||||
|
||||
|
|
|
@ -139,6 +139,8 @@ public:
|
|||
|
||||
bool ShouldLavaSpawnFire(void) const { return m_ShouldLavaSpawnFire; }
|
||||
|
||||
bool VillagersShouldHarvestCrops(void) const { return m_VillagersShouldHarvestCrops; }
|
||||
|
||||
virtual eDimension GetDimension(void) const { return m_Dimension; }
|
||||
|
||||
/** 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_IsDeepSnowEnabled;
|
||||
bool m_ShouldLavaSpawnFire;
|
||||
bool m_VillagersShouldHarvestCrops;
|
||||
|
||||
std::vector<BlockTickQueueItem *> m_BlockTickQueue;
|
||||
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:
|
||||
{
|
||||
// TODO:
|
||||
// _X: CopyPasta error: m_Writer.AddInt("Profession", ((const cVillager *)a_Monster)->GetVilType());
|
||||
m_Writer.AddString("Owner", ((const cWolf *)a_Monster)->GetOwner());
|
||||
m_Writer.AddByte("Sitting", ((const cWolf *)a_Monster)->IsSitting());
|
||||
break;
|
||||
}
|
||||
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)
|
||||
{
|
||||
int ID = a_NBT.FindChildByName(a_TagIdx, "id");
|
||||
if ((ID < 0) || (a_NBT.GetType(ID) != TAG_Short))
|
||||
int Type = a_NBT.FindChildByName(a_TagIdx, "id");
|
||||
if ((Type < 0) || (a_NBT.GetType(Type) != TAG_Short))
|
||||
{
|
||||
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");
|
||||
if ((Damage < 0) || (a_NBT.GetType(Damage) != TAG_Short))
|
||||
|
@ -1870,7 +1876,16 @@ void cWSSAnvil::LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N
|
|||
{
|
||||
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());
|
||||
}
|
||||
|
||||
|
|
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 */
|
||||
bool g_ShouldLogComm;
|
||||
/** If set to true, the protocols will log each player's incoming (C->S) communication to a per-connection logfile */
|
||||
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);
|
||||
LOGERROR(" D: | MCServer has encountered an error and needs to close");
|
||||
LOGERROR("Details | SIGABRT: Server self-terminated due to an internal fault");
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
case SIGINT:
|
||||
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;
|
||||
}
|
||||
default: break;
|
||||
|
@ -224,6 +229,10 @@ int main( int argc, char **argv )
|
|||
std::signal(SIGSEGV, NonCtrlHandler);
|
||||
std::signal(SIGTERM, NonCtrlHandler);
|
||||
std::signal(SIGINT, NonCtrlHandler);
|
||||
std::signal(SIGABRT, NonCtrlHandler);
|
||||
#ifdef SIGABRT_COMPAT
|
||||
std::signal(SIGABRT_COMPAT, NonCtrlHandler);
|
||||
#endif // SIGABRT_COMPAT
|
||||
#endif
|
||||
|
||||
// DEBUG: test the dumpfile creation:
|
||||
|
@ -237,7 +246,24 @@ int main( int argc, char **argv )
|
|||
(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