summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt96
-rw-r--r--src/ClientHandle.cpp2
-rw-r--r--src/Crypto.cpp435
-rw-r--r--src/Crypto.h169
-rw-r--r--src/Defines.h2
-rw-r--r--src/Entities/Entity.cpp131
-rw-r--r--src/Entities/Entity.h38
-rw-r--r--src/Entities/Pickup.cpp67
-rw-r--r--src/Entities/Player.cpp131
-rw-r--r--src/Entities/Player.h24
-rw-r--r--src/Generating/ChunkGenerator.cpp9
-rw-r--r--src/Globals.h3
-rw-r--r--src/LeakFinder.cpp11
-rw-r--r--src/MobProximityCounter.cpp4
-rw-r--r--src/Mobs/AggressiveMonster.cpp67
-rw-r--r--src/Mobs/AggressiveMonster.h5
-rw-r--r--src/Mobs/Creeper.cpp53
-rw-r--r--src/Mobs/Creeper.h3
-rw-r--r--src/Mobs/IronGolem.h4
-rw-r--r--src/Mobs/Monster.cpp454
-rw-r--r--src/Mobs/Monster.h90
-rw-r--r--src/Mobs/PassiveAggressiveMonster.cpp3
-rw-r--r--src/Mobs/PassiveMonster.cpp16
-rw-r--r--src/Mobs/Skeleton.cpp11
-rw-r--r--src/Mobs/Squid.h3
-rw-r--r--src/Mobs/Wolf.cpp36
-rw-r--r--src/Mobs/Wolf.h1
-rw-r--r--src/Mobs/Zombie.cpp13
-rw-r--r--src/MonsterConfig.cpp20
-rw-r--r--src/OSSupport/BlockingTCPLink.cpp4
-rw-r--r--src/OSSupport/Errors.cpp53
-rw-r--r--src/OSSupport/Errors.h5
-rw-r--r--src/OSSupport/Event.cpp17
-rw-r--r--src/OSSupport/File.cpp9
-rw-r--r--src/OSSupport/File.h45
-rw-r--r--src/OSSupport/Socket.cpp52
-rw-r--r--src/OSSupport/Socket.h7
-rw-r--r--src/OSSupport/SocketThreads.cpp3
-rw-r--r--src/Protocol/Protocol132.cpp149
-rw-r--r--src/Protocol/Protocol132.h16
-rw-r--r--src/Protocol/Protocol14x.cpp2
-rw-r--r--src/Protocol/Protocol17x.cpp51
-rw-r--r--src/Protocol/Protocol17x.h16
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp2
-rw-r--r--src/ReferenceManager.cpp43
-rw-r--r--src/ReferenceManager.h34
-rw-r--r--src/Server.cpp14
-rw-r--r--src/Server.h14
-rw-r--r--src/World.cpp13
-rw-r--r--src/World.h2
-rw-r--r--src/main.cpp4
51 files changed, 1601 insertions, 855 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a8cc0530d..944150a44 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -4,6 +4,7 @@ project (MCServer)
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/")
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/jsoncpp/include")
+include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/polarssl/include")
set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating)
set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities)
@@ -16,34 +17,64 @@ if (NOT MSVC)
#lib dependecies are not included
- set(BINDING_DEPENDECIES ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/virtual_method_hooks.lua)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/AllToLua.pkg)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} ChunkDef.h BiomeDef.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} OSSupport/File.h Bindings/LuaFunctions.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} Bindings/PluginManager.h Bindings/Plugin.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} Bindings/PluginLua.h Bindings/WebPlugin.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} Bindings/LuaWindow.h BlockID.h StringUtils.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} Defines.h ChatColor.h ClientHandle.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} Entities/Entity.h Entities/Floater.h )
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} Entities/Pawn.h Entities/Player.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} Entities/Pickup.h Entities/ProjectileEntity.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} Entities/TNTEntity.h Entities/Effects.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} Server.h World.h Inventory.h Enchantments.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} Item.h ItemGrid.h BlockEntities/BlockEntity.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} BlockEntities/BlockEntityWithItems.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} BlockEntities/ChestEntity.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} BlockEntities/DropSpenserEntity.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} BlockEntities/DispenserEntity.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} BlockEntities/DropperEntity.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} BlockEntities/FurnaceEntity.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} BlockEntities/HopperEntity.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} BlockEntities/JukeboxEntity.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} BlockEntities/NoteEntity.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} BlockEntities/SignEntity.h WebAdmin.h Root.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} Vector3f.h Vector3d.h Vector3i.h Matrix4f.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} Cuboid.h BoundingBox.h Tracer.h Group.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} BlockArea.h Generating/ChunkDesc.h)
- set(BINDING_DEPENDECIES ${BINDING_DEPENDECIES} CraftingRecipes.h UI/Window.h Mobs/Monster.h)
+ set(BINDING_DEPENDECIES
+ ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/virtual_method_hooks.lua
+ ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/AllToLua.pkg
+ ChunkDef.h
+ BiomeDef.h
+ OSSupport/File.h
+ Bindings/LuaFunctions.h
+ Bindings/PluginManager.h
+ Bindings/Plugin.h
+ Bindings/PluginLua.h
+ Bindings/WebPlugin.h
+ Bindings/LuaWindow.h
+ BlockID.h
+ StringUtils.h
+ Defines.h
+ ChatColor.h
+ ClientHandle.h
+ Entities/Entity.h
+ Entities/Floater.h
+ Entities/Pawn.h
+ Entities/Player.h
+ Entities/Pickup.h
+ Entities/ProjectileEntity.h
+ Entities/TNTEntity.h
+ Entities/Effects.h
+ Server.h
+ World.h
+ Inventory.h
+ Enchantments.h
+ Item.h
+ ItemGrid.h
+ BlockEntities/BlockEntity.h
+ BlockEntities/BlockEntityWithItems.h
+ BlockEntities/ChestEntity.h
+ BlockEntities/DropSpenserEntity.h
+ BlockEntities/DispenserEntity.h
+ BlockEntities/DropperEntity.h
+ BlockEntities/FurnaceEntity.h
+ BlockEntities/HopperEntity.h
+ BlockEntities/JukeboxEntity.h
+ BlockEntities/NoteEntity.h
+ BlockEntities/SignEntity.h
+ WebAdmin.h
+ Root.h
+ Vector3f.h
+ Vector3d.h
+ Vector3i.h
+ Matrix4f.h
+ Cuboid.h
+ BoundingBox.h
+ Tracer.h
+ Group.h
+ BlockArea.h
+ Generating/ChunkDesc.h
+ CraftingRecipes.h
+ UI/Window.h
+ Mobs/Monster.h
+ )
include_directories(Bindings)
include_directories(.)
@@ -64,6 +95,13 @@ if (NOT MSVC)
target_link_libraries(Bindings lua sqlite tolualib)
+ #clear file
+ file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/BindingDependecies.txt)
+ foreach(dependecy ${BINDING_DEPENDECIES})
+ #write each dependecy on a seperate line
+ file(APPEND ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/BindingDependecies.txt "${dependecy}\n")
+ endforeach()
+
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "Bindings.cpp Bindings.h")
foreach(folder ${FOLDERS})
@@ -183,4 +221,4 @@ endif ()
if (WIN32)
target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib)
endif()
-target_link_libraries(${EXECUTABLE} md5 luaexpat iniFile jsoncpp cryptopp zlib lua sqlite)
+target_link_libraries(${EXECUTABLE} md5 luaexpat iniFile jsoncpp polarssl zlib lua sqlite)
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 56ad4e4ba..ad3f15adc 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -611,7 +611,7 @@ void cClientHandle::HandleCommandBlockMessage(const char* a_Data, unsigned int a
}
else
{
- SendChat(Printf("%s[INFO]%s Command blocks are not enabled on this server", cChatColor::Green.c_str(), cChatColor::White.c_str()));
+ SendChat(Printf("%s[INFO]%s Command blocks are not enabled on this server", cChatColor::Yellow.c_str(), cChatColor::White.c_str()));
}
}
diff --git a/src/Crypto.cpp b/src/Crypto.cpp
new file mode 100644
index 000000000..2045d0385
--- /dev/null
+++ b/src/Crypto.cpp
@@ -0,0 +1,435 @@
+
+// Crypto.cpp
+
+// Implements classes that wrap the cryptographic code library
+
+#include "Globals.h"
+#include "Crypto.h"
+
+#include "polarssl/pk.h"
+
+
+
+
+
+/*
+// Self-test the hash formatting for known values:
+// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48
+// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1
+// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6
+
+class Test
+{
+public:
+ Test(void)
+ {
+ AString DigestNotch, DigestJeb, DigestSimon;
+ Byte Digest[20];
+ cSHA1Checksum Checksum;
+ Checksum.Update((const Byte *)"Notch", 5);
+ Checksum.Finalize(Digest);
+ cSHA1Checksum::DigestToJava(Digest, DigestNotch);
+ Checksum.Restart();
+ Checksum.Update((const Byte *)"jeb_", 4);
+ Checksum.Finalize(Digest);
+ cSHA1Checksum::DigestToJava(Digest, DigestJeb);
+ Checksum.Restart();
+ Checksum.Update((const Byte *)"simon", 5);
+ Checksum.Finalize(Digest);
+ cSHA1Checksum::DigestToJava(Digest, DigestSimon);
+ printf("Notch: \"%s\"\n", DigestNotch.c_str());
+ printf("jeb_: \"%s\"\n", DigestJeb.c_str());
+ printf("simon: \"%s\"\n", DigestSimon.c_str());
+ assert(DigestNotch == "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48");
+ assert(DigestJeb == "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1");
+ assert(DigestSimon == "88e16a1019277b15d58faf0541e11910eb756f6");
+ }
+} test;
+*/
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cRSAPrivateKey:
+
+cRSAPrivateKey::cRSAPrivateKey(void)
+{
+ rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
+ InitRnd();
+}
+
+
+
+
+
+cRSAPrivateKey::cRSAPrivateKey(const cRSAPrivateKey & a_Other)
+{
+ rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
+ rsa_copy(&m_Rsa, &a_Other.m_Rsa);
+ InitRnd();
+}
+
+
+
+
+
+cRSAPrivateKey::~cRSAPrivateKey()
+{
+ entropy_free(&m_Entropy);
+ rsa_free(&m_Rsa);
+}
+
+
+
+
+
+void cRSAPrivateKey::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);
+}
+
+
+
+
+
+bool cRSAPrivateKey::Generate(unsigned a_KeySizeBits)
+{
+ if (rsa_gen_key(&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, a_KeySizeBits, 65537) != 0)
+ {
+ // Key generation failed
+ return false;
+ }
+
+ return true;
+}
+
+
+
+
+
+AString cRSAPrivateKey::GetPubKeyDER(void)
+{
+ class cPubKey
+ {
+ public:
+ cPubKey(rsa_context * a_Rsa) :
+ m_IsValid(false)
+ {
+ pk_init(&m_Key);
+ if (pk_init_ctx(&m_Key, pk_info_from_type(POLARSSL_PK_RSA)) != 0)
+ {
+ ASSERT(!"Cannot init PrivKey context");
+ return;
+ }
+ if (rsa_copy(pk_rsa(m_Key), a_Rsa) != 0)
+ {
+ ASSERT(!"Cannot copy PrivKey to PK context");
+ return;
+ }
+ m_IsValid = true;
+ }
+
+ ~cPubKey()
+ {
+ if (m_IsValid)
+ {
+ pk_free(&m_Key);
+ }
+ }
+
+ operator pk_context * (void) { return &m_Key; }
+
+ protected:
+ bool m_IsValid;
+ pk_context m_Key;
+ } PkCtx(&m_Rsa);
+
+ unsigned char buf[3000];
+ int res = pk_write_pubkey_der(PkCtx, buf, sizeof(buf));
+ if (res < 0)
+ {
+ return AString();
+ }
+ return AString((const char *)(buf + sizeof(buf) - res), (size_t)res);
+}
+
+
+
+
+
+int cRSAPrivateKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
+{
+ if (a_EncryptedLength < m_Rsa.len)
+ {
+ LOGD("%s: Invalid a_EncryptedLength: got %u, exp at least %u",
+ __FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
+ );
+ ASSERT(!"Invalid a_DecryptedMaxLength!");
+ return -1;
+ }
+ if (a_DecryptedMaxLength < m_Rsa.len)
+ {
+ LOGD("%s: Invalid a_DecryptedMaxLength: got %u, exp at least %u",
+ __FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
+ );
+ ASSERT(!"Invalid a_DecryptedMaxLength!");
+ return -1;
+ }
+ size_t DecryptedLength;
+ int res = rsa_pkcs1_decrypt(
+ &m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PRIVATE, &DecryptedLength,
+ a_EncryptedData, a_DecryptedData, a_DecryptedMaxLength
+ );
+ if (res != 0)
+ {
+ return -1;
+ }
+ return (int)DecryptedLength;
+}
+
+
+
+
+
+int cRSAPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
+{
+ if (a_EncryptedMaxLength < m_Rsa.len)
+ {
+ LOGD("%s: Invalid a_EncryptedMaxLength: got %u, exp at least %u",
+ __FUNCTION__, (unsigned)a_EncryptedMaxLength, (unsigned)(m_Rsa.len)
+ );
+ ASSERT(!"Invalid a_DecryptedMaxLength!");
+ return -1;
+ }
+ if (a_PlainLength < m_Rsa.len)
+ {
+ LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u",
+ __FUNCTION__, (unsigned)a_PlainLength, (unsigned)(m_Rsa.len)
+ );
+ ASSERT(!"Invalid a_PlainLength!");
+ return -1;
+ }
+ size_t DecryptedLength;
+ int res = rsa_pkcs1_encrypt(
+ &m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PUBLIC,
+ a_PlainLength, a_PlainData, a_EncryptedData
+ );
+ if (res != 0)
+ {
+ return -1;
+ }
+ return (int)DecryptedLength;
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cAESCFBDecryptor:
+
+cAESCFBDecryptor::cAESCFBDecryptor(void) :
+ m_IsValid(false),
+ m_IVOffset(0)
+{
+}
+
+
+
+
+
+cAESCFBDecryptor::~cAESCFBDecryptor()
+{
+ // Clear the leftover in-memory data, so that they can't be accessed by a backdoor
+ memset(&m_Aes, 0, sizeof(m_Aes));
+}
+
+
+
+
+
+void cAESCFBDecryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
+{
+ ASSERT(!IsValid()); // Cannot Init twice
+
+ memcpy(m_IV, a_IV, 16);
+ aes_setkey_enc(&m_Aes, a_Key, 128);
+ m_IsValid = true;
+}
+
+
+
+
+
+void cAESCFBDecryptor::ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length)
+{
+ ASSERT(IsValid()); // Must Init() first
+
+ // PolarSSL doesn't support AES-CFB8, need to implement it manually:
+ for (size_t i = 0; i < a_Length; i++)
+ {
+ Byte Buffer[sizeof(m_IV)];
+ aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
+ for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
+ {
+ m_IV[idx] = m_IV[idx + 1];
+ }
+ m_IV[sizeof(m_IV) - 1] = a_EncryptedIn[i];
+ a_DecryptedOut[i] = a_EncryptedIn[i] ^ Buffer[0];
+ }
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cAESCFBEncryptor:
+
+cAESCFBEncryptor::cAESCFBEncryptor(void) :
+ m_IsValid(false),
+ m_IVOffset(0)
+{
+}
+
+
+
+
+
+cAESCFBEncryptor::~cAESCFBEncryptor()
+{
+ // Clear the leftover in-memory data, so that they can't be accessed by a backdoor
+ memset(&m_Aes, 0, sizeof(m_Aes));
+}
+
+
+
+
+
+void cAESCFBEncryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
+{
+ ASSERT(!IsValid()); // Cannot Init twice
+ ASSERT(m_IVOffset == 0);
+
+ memcpy(m_IV, a_IV, 16);
+ aes_setkey_enc(&m_Aes, a_Key, 128);
+ m_IsValid = true;
+}
+
+
+
+
+
+void cAESCFBEncryptor::ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length)
+{
+ ASSERT(IsValid()); // Must Init() first
+
+ // PolarSSL doesn't do AES-CFB8, so we need to implement it ourselves:
+ for (size_t i = 0; i < a_Length; i++)
+ {
+ Byte Buffer[sizeof(m_IV)];
+ aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
+ for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
+ {
+ m_IV[idx] = m_IV[idx + 1];
+ }
+ a_EncryptedOut[i] = a_PlainIn[i] ^ Buffer[0];
+ m_IV[sizeof(m_IV) - 1] = a_EncryptedOut[i];
+ }
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cSHA1Checksum:
+
+cSHA1Checksum::cSHA1Checksum(void) :
+ m_DoesAcceptInput(true)
+{
+ sha1_starts(&m_Sha1);
+}
+
+
+
+
+
+void cSHA1Checksum::Update(const Byte * a_Data, size_t a_Length)
+{
+ ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
+
+ sha1_update(&m_Sha1, a_Data, a_Length);
+}
+
+
+
+
+
+void cSHA1Checksum::Finalize(cSHA1Checksum::Checksum & a_Output)
+{
+ ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
+
+ sha1_finish(&m_Sha1, a_Output);
+ m_DoesAcceptInput = false;
+}
+
+
+
+
+
+void cSHA1Checksum::DigestToJava(const Checksum & a_Digest, AString & a_Out)
+{
+ Checksum Digest;
+ memcpy(Digest, a_Digest, sizeof(Digest));
+
+ bool IsNegative = (Digest[0] >= 0x80);
+ if (IsNegative)
+ {
+ // Two's complement:
+ bool carry = true; // Add one to the whole number
+ for (int i = 19; i >= 0; i--)
+ {
+ Digest[i] = ~Digest[i];
+ if (carry)
+ {
+ carry = (Digest[i] == 0xff);
+ Digest[i]++;
+ }
+ }
+ }
+ a_Out.clear();
+ a_Out.reserve(40);
+ for (int i = 0; i < 20; i++)
+ {
+ AppendPrintf(a_Out, "%02x", Digest[i]);
+ }
+ while ((a_Out.length() > 0) && (a_Out[0] == '0'))
+ {
+ a_Out.erase(0, 1);
+ }
+ if (IsNegative)
+ {
+ a_Out.insert(0, "-");
+ }
+}
+
+
+
+
+
+
+void cSHA1Checksum::Restart(void)
+{
+ sha1_starts(&m_Sha1);
+ m_DoesAcceptInput = true;
+}
+
+
+
+
diff --git a/src/Crypto.h b/src/Crypto.h
new file mode 100644
index 000000000..a97f34fbf
--- /dev/null
+++ b/src/Crypto.h
@@ -0,0 +1,169 @@
+
+// Crypto.h
+
+// Declares classes that wrap the cryptographic code library
+
+
+
+
+
+#pragma once
+
+#include "polarssl/rsa.h"
+#include "polarssl/aes.h"
+#include "polarssl/entropy.h"
+#include "polarssl/ctr_drbg.h"
+#include "polarssl/sha1.h"
+
+
+
+
+
+/** Encapsulates an RSA private key used in PKI cryptography */
+class cRSAPrivateKey
+{
+public:
+ /** Creates a new empty object, the key is not assigned */
+ cRSAPrivateKey(void);
+
+ /** Deep-copies the key from a_Other */
+ cRSAPrivateKey(const cRSAPrivateKey & a_Other);
+
+ ~cRSAPrivateKey();
+
+ /** Generates a new key within this object, with the specified size in bits.
+ Returns true on success, false on failure. */
+ bool Generate(unsigned a_KeySizeBits = 1024);
+
+ /** Returns the public key part encoded in ASN1 DER encoding */
+ AString GetPubKeyDER(void);
+
+ /** Decrypts the data using RSAES-PKCS#1 algorithm.
+ 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 RSAES-PKCS#1 algorithm.
+ 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:
+ rsa_context m_Rsa;
+ 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
+{
+public:
+ Byte test;
+
+ cAESCFBDecryptor(void);
+ ~cAESCFBDecryptor();
+
+ /** Initializes the decryptor with the specified Key / IV */
+ void Init(const Byte a_Key[16], const Byte a_IV[16]);
+
+ /** Decrypts a_Length bytes of the encrypted data; produces a_Length output bytes */
+ void ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length);
+
+ /** Returns true if the object has been initialized with the Key / IV */
+ bool IsValid(void) const { return m_IsValid; }
+
+protected:
+ aes_context m_Aes;
+
+ /** The InitialVector, used by the CFB mode decryption */
+ Byte m_IV[16];
+
+ /** Current offset in the m_IV, used by the CFB mode decryption */
+ size_t m_IVOffset;
+
+ /** Indicates whether the object has been initialized with the Key / IV */
+ bool m_IsValid;
+} ;
+
+
+
+
+
+/** Encrypts data using the AES / CFB (128) algorithm */
+class cAESCFBEncryptor
+{
+public:
+ Byte test;
+
+ cAESCFBEncryptor(void);
+ ~cAESCFBEncryptor();
+
+ /** Initializes the decryptor with the specified Key / IV */
+ void Init(const Byte a_Key[16], const Byte a_IV[16]);
+
+ /** Encrypts a_Length bytes of the plain data; produces a_Length output bytes */
+ void ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length);
+
+ /** Returns true if the object has been initialized with the Key / IV */
+ bool IsValid(void) const { return m_IsValid; }
+
+protected:
+ aes_context m_Aes;
+
+ /** The InitialVector, used by the CFB mode encryption */
+ Byte m_IV[16];
+
+ /** Current offset in the m_IV, used by the CFB mode encryption */
+ size_t m_IVOffset;
+
+ /** Indicates whether the object has been initialized with the Key / IV */
+ bool m_IsValid;
+} ;
+
+
+
+
+
+/** Calculates a SHA1 checksum for data stream */
+class cSHA1Checksum
+{
+public:
+ typedef Byte Checksum[20]; // The type used for storing the checksum
+
+ cSHA1Checksum(void);
+
+ /** Adds the specified data to the checksum */
+ void Update(const Byte * a_Data, size_t a_Length);
+
+ /** Calculates and returns the final checksum */
+ void Finalize(Checksum & a_Output);
+
+ /** Returns true if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
+ bool DoesAcceptInput(void) const { return m_DoesAcceptInput; }
+
+ /** Converts a raw 160-bit SHA1 digest into a Java Hex representation
+ According to http://wiki.vg/wiki/index.php?title=Protocol_Encryption&oldid=2802
+ */
+ static void DigestToJava(const Checksum & a_Digest, AString & a_JavaOut);
+
+ /** Clears the current context and start a new checksum calculation */
+ void Restart(void);
+
+protected:
+ /** True if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
+ bool m_DoesAcceptInput;
+
+ sha1_context m_Sha1;
+} ;
+
+
+
+
diff --git a/src/Defines.h b/src/Defines.h
index 7a86f499e..0dcc3214a 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -5,8 +5,6 @@
-typedef unsigned char Byte;
-
/// List of slot numbers, used for inventory-painting
typedef std::vector<int> cSlotNums;
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 09fb7052d..e22f689d9 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -4,9 +4,7 @@
#include "../World.h"
#include "../Server.h"
#include "../Root.h"
-#include "../Vector3d.h"
#include "../Matrix4f.h"
-#include "../ReferenceManager.h"
#include "../ClientHandle.h"
#include "../Chunk.h"
#include "../Simulator/FluidSimulator.h"
@@ -32,8 +30,6 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d
, m_MaxHealth(1)
, m_AttachedTo(NULL)
, m_Attachee(NULL)
- , m_Referencers(new cReferenceManager(cReferenceManager::RFMNGR_REFERENCERS))
- , m_References(new cReferenceManager(cReferenceManager::RFMNGR_REFERENCES))
, m_bDirtyHead(true)
, m_bDirtyOrientation(true)
, m_bDirtyPosition(true)
@@ -61,6 +57,8 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d
, m_Mass (0.001) // Default 1g
, m_Width(a_Width)
, m_Height(a_Height)
+ , m_IsSubmerged(false)
+ , m_IsSwimming(false)
{
cCSLock Lock(m_CSCount);
m_EntityCount++;
@@ -100,8 +98,6 @@ cEntity::~cEntity()
LOGWARNING("ERROR: Entity deallocated without being destroyed");
ASSERT(!"Entity deallocated without being destroyed or unlinked");
}
- delete m_Referencers;
- delete m_References;
}
@@ -535,7 +531,17 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
TickInVoid(a_Chunk);
}
- else { m_TicksSinceLastVoidDamage = 0; }
+ else
+ m_TicksSinceLastVoidDamage = 0;
+
+ if (IsMob() || IsPlayer())
+ {
+ // Set swimming state
+ SetSwimState(a_Chunk);
+
+ // Handle drowning
+ HandleAir();
+ }
}
@@ -913,6 +919,87 @@ void cEntity::TickInVoid(cChunk & a_Chunk)
+void cEntity::SetSwimState(cChunk & a_Chunk)
+{
+ int RelY = (int)floor(m_LastPosY + 0.1);
+ if ((RelY < 0) || (RelY >= cChunkDef::Height - 1))
+ {
+ m_IsSwimming = false;
+ m_IsSubmerged = false;
+ return;
+ }
+
+ BLOCKTYPE BlockIn;
+ int RelX = (int)floor(m_LastPosX) - a_Chunk.GetPosX() * cChunkDef::Width;
+ int RelZ = (int)floor(m_LastPosZ) - a_Chunk.GetPosZ() * cChunkDef::Width;
+
+ // Check if the player is swimming:
+ // Use Unbounded, because we're being called *after* processing super::Tick(), which could have changed our chunk
+ if (!a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockIn))
+ {
+ // This sometimes happens on Linux machines
+ // Ref.: http://forum.mc-server.org/showthread.php?tid=1244
+ LOGD("SetSwimState failure: RelX = %d, RelZ = %d, LastPos = {%.02f, %.02f}, Pos = %.02f, %.02f}",
+ RelX, RelY, m_LastPosX, m_LastPosZ, GetPosX(), GetPosZ()
+ );
+ m_IsSwimming = false;
+ m_IsSubmerged = false;
+ return;
+ }
+ m_IsSwimming = IsBlockWater(BlockIn);
+
+ // Check if the player is submerged:
+ VERIFY(a_Chunk.UnboundedRelGetBlockType(RelX, RelY + 1, RelZ, BlockIn));
+ m_IsSubmerged = IsBlockWater(BlockIn);
+}
+
+
+
+
+
+void cEntity::HandleAir(void)
+{
+ // Ref.: http://www.minecraftwiki.net/wiki/Chunk_format
+ // See if the entity is /submerged/ water (block above is water)
+ // Get the type of block the entity is standing in:
+
+ if (IsSubmerged())
+ {
+ SetSpeedY(1); // Float in the water
+
+ // Either reduce air level or damage player
+ if (m_AirLevel < 1)
+ {
+ if (m_AirTickTimer < 1)
+ {
+ // Damage player
+ TakeDamage(dtDrowning, NULL, 1, 1, 0);
+ // Reset timer
+ m_AirTickTimer = DROWNING_TICKS;
+ }
+ else
+ {
+ m_AirTickTimer -= 1;
+ }
+ }
+ else
+ {
+ // Reduce air supply
+ m_AirLevel -= 1;
+ }
+ }
+ else
+ {
+ // Set the air back to maximum
+ m_AirLevel = MAX_AIR_LEVEL;
+ m_AirTickTimer = DROWNING_TICKS;
+ }
+}
+
+
+
+
+
/// Called when the entity starts burning
void cEntity::OnStartedBurning(void)
{
@@ -1430,33 +1517,3 @@ void cEntity::SetPosZ(double a_PosZ)
-
-//////////////////////////////////////////////////////////////////////////
-// Reference stuffs
-void cEntity::AddReference(cEntity * & a_EntityPtr)
-{
- m_References->AddReference(a_EntityPtr);
- a_EntityPtr->ReferencedBy(a_EntityPtr);
-}
-
-
-
-
-
-void cEntity::ReferencedBy(cEntity * & a_EntityPtr)
-{
- m_Referencers->AddReference(a_EntityPtr);
-}
-
-
-
-
-
-void cEntity::Dereference(cEntity * & a_EntityPtr)
-{
- m_Referencers->Dereference(a_EntityPtr);
-}
-
-
-
-
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index 91463bfd6..b2edfc2b4 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -4,6 +4,7 @@
#include "../Item.h"
#include "../Vector3d.h"
#include "../Vector3f.h"
+#include "../Vector3i.h"
@@ -28,12 +29,16 @@
return super::GetClass(); \
}
+#define POSX_TOINT (int)floor(GetPosX())
+#define POSY_TOINT (int)floor(GetPosY())
+#define POSZ_TOINT (int)floor(GetPosZ())
+#define POS_TOINT Vector3i(POSXTOINT, POSYTOINT, POSZTOINT)
+
class cWorld;
-class cReferenceManager;
class cClientHandle;
class cPlayer;
class cChunk;
@@ -110,6 +115,8 @@ public:
BURN_TICKS_PER_DAMAGE = 20, ///< How many ticks to wait between damaging an entity when it is burning
BURN_DAMAGE = 1, ///< How much damage to deal when the entity is burning
BURN_TICKS = 200, ///< How long to keep an entity burning after it has stood in lava / fire
+ MAX_AIR_LEVEL = 300, ///< Maximum air an entity can have
+ DROWNING_TICKS = 20, ///< Number of ticks per heart of damage
} ;
cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
@@ -344,7 +351,14 @@ public:
virtual bool IsRiding (void) const {return false; }
virtual bool IsSprinting(void) const {return false; }
virtual bool IsRclking (void) const {return false; }
- virtual bool IsInvisible(void) const {return false; }
+ virtual bool IsInvisible(void) const { return false; }
+
+ /** Returns whether the player is swimming or not */
+ virtual bool IsSwimming(void) const{ return m_IsSwimming; }
+ /** Return whether the player is under water or not */
+ virtual bool IsSubmerged(void) const{ return m_IsSubmerged; }
+ /** Gets remaining air of a monster */
+ int GetAirLevel(void) const { return m_AirLevel; }
// tolua_end
@@ -373,9 +387,6 @@ protected:
/// The entity which is attached to this entity (rider), NULL if none
cEntity * m_Attachee;
- cReferenceManager* m_Referencers;
- cReferenceManager* m_References;
-
// Flags that signal that we haven't updated the clients with the latest.
bool m_bDirtyHead;
bool m_bDirtyOrientation;
@@ -415,11 +426,18 @@ protected:
virtual void Destroyed(void) {} // Called after the entity has been destroyed
void SetWorld(cWorld * a_World) { m_World = a_World; }
-
- friend class cReferenceManager;
- void AddReference( cEntity*& a_EntityPtr );
- void ReferencedBy( cEntity*& a_EntityPtr );
- void Dereference( cEntity*& a_EntityPtr );
+
+ /** Called in each tick to handle air-related processing i.e. drowning */
+ virtual void HandleAir();
+ /** Called once per tick to set IsSwimming and IsSubmerged */
+ virtual void SetSwimState(cChunk & a_Chunk);
+
+ /** If an entity is currently swimming in or submerged under water */
+ bool m_IsSwimming, m_IsSubmerged;
+
+ /** Air level of a mobile */
+ int m_AirLevel;
+ int m_AirTickTimer;
private:
// Measured in degrees, [-180, +180)
diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp
index 001e386a7..bfe162b69 100644
--- a/src/Entities/Pickup.cpp
+++ b/src/Entities/Pickup.cpp
@@ -6,19 +6,58 @@
#endif
#include "Pickup.h"
+#include "Player.h"
#include "../ClientHandle.h"
-#include "../Inventory.h"
#include "../World.h"
-#include "../Simulator/FluidSimulator.h"
#include "../Server.h"
-#include "Player.h"
#include "../Bindings/PluginManager.h"
-#include "../Item.h"
#include "../Root.h"
#include "../Chunk.h"
-#include "../Vector3d.h"
-#include "../Vector3f.h"
+
+
+
+class cPickupCombiningCallback :
+ public cEntityCallback
+{
+public:
+ cPickupCombiningCallback(Vector3d a_Position, cPickup * a_Pickup) :
+ m_Position(a_Position),
+ m_Pickup(a_Pickup),
+ m_FoundMatchingPickup(false)
+ {
+ }
+
+ virtual bool Item(cEntity * a_Entity) override
+ {
+ if (!a_Entity->IsPickup() || (a_Entity->GetUniqueID() == m_Pickup->GetUniqueID()) || a_Entity->IsDestroyed())
+ {
+ return false;
+ }
+
+ Vector3d EntityPos = a_Entity->GetPosition();
+ double Distance = (EntityPos - m_Position).Length();
+
+ if ((Distance < 1.2) && ((cPickup *)a_Entity)->GetItem().IsEqual(m_Pickup->GetItem()))
+ {
+ m_Pickup->GetItem().AddCount(((cPickup *)a_Entity)->GetItem().m_ItemCount);
+ a_Entity->Destroy();
+ m_FoundMatchingPickup = true;
+ }
+ return false;
+ }
+
+ inline bool FoundMatchingPickup()
+ {
+ return m_FoundMatchingPickup;
+ }
+
+protected:
+ bool m_FoundMatchingPickup;
+
+ Vector3d m_Position;
+ cPickup * m_Pickup;
+};
@@ -26,10 +65,10 @@
cPickup::cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, bool IsPlayerCreated, float a_SpeedX /* = 0.f */, float a_SpeedY /* = 0.f */, float a_SpeedZ /* = 0.f */)
: cEntity(etPickup, a_PosX, a_PosY, a_PosZ, 0.2, 0.2)
- , m_Timer( 0.f )
+ , m_Timer(0.f)
, m_Item(a_Item)
- , m_bCollected( false )
- , m_bIsPlayerCreated( IsPlayerCreated )
+ , m_bCollected(false)
+ , m_bIsPlayerCreated(IsPlayerCreated)
{
SetGravity(-10.5f);
SetMaxHealth(5);
@@ -89,6 +128,16 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
return;
}
}
+
+ if (!IsDestroyed()) // Don't try to combine if someone has tried to combine me
+ {
+ cPickupCombiningCallback PickupCombiningCallback(GetPosition(), this);
+ m_World->ForEachEntity(PickupCombiningCallback); // Not ForEachEntityInChunk, otherwise pickups don't combine across chunk boundaries
+ if (PickupCombiningCallback.FoundMatchingPickup())
+ {
+ m_World->BroadcastEntityMetadata(*this);
+ }
+ }
}
}
}
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 377194efc..82e31ae65 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -7,7 +7,6 @@
#include "../UI/Window.h"
#include "../UI/WindowOwner.h"
#include "../World.h"
-#include "Pickup.h"
#include "../Bindings/PluginManager.h"
#include "../BlockEntities/BlockEntity.h"
#include "../GroupManager.h"
@@ -27,8 +26,6 @@
#include "inifile/iniFile.h"
#include "json/json.h"
-#define float2int(x) ((x)<0 ? ((int)(x))-1 : (int)(x))
-
@@ -36,8 +33,6 @@
cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
: super(etPlayer, 0.6, 1.8)
- , m_AirLevel( MAX_AIR_LEVEL )
- , m_AirTickTimer(DROWNING_TICKS)
, m_bVisible(true)
, m_FoodLevel(MAX_FOOD_LEVEL)
, m_FoodSaturationLevel(5)
@@ -108,9 +103,23 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
a_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ()
);
}
+
m_LastJumpHeight = (float)(GetPosY());
m_LastGroundHeight = (float)(GetPosY());
m_Stance = GetPosY() + 1.62;
+
+ if (m_GameMode == gmNotSet)
+ {
+ cWorld * World = cRoot::Get()->GetWorld(GetLoadedWorldName());
+ if (World == NULL)
+ {
+ World = cRoot::Get()->GetDefaultWorld();
+ }
+ if (World->IsGameModeCreative())
+ {
+ m_CanFly = true;
+ }
+ }
cRoot::Get()->GetServer()->PlayerCreated(this);
}
@@ -197,12 +206,6 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
super::Tick(a_Dt, a_Chunk);
- // Set player swimming state
- SetSwimState(a_Chunk);
-
- // Handle air drowning stuff
- HandleAir();
-
// Handle charging the bow:
if (m_IsChargingBow)
{
@@ -435,7 +438,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
cWorld * World = GetWorld();
if ((GetPosY() >= 0) && (GetPosY() < cChunkDef::Height))
{
- BLOCKTYPE BlockType = World->GetBlock(float2int(GetPosX()), float2int(GetPosY()), float2int(GetPosZ()));
+ BLOCKTYPE BlockType = World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()));
if (BlockType != E_BLOCK_AIR)
{
m_bTouchGround = true;
@@ -460,12 +463,10 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
if (Damage > 0)
{
- if (!IsGameModeCreative())
- {
- TakeDamage(dtFalling, NULL, Damage, Damage, 0);
- }
+ // cPlayer makes sure damage isn't applied in creative, no need to check here
+ TakeDamage(dtFalling, NULL, Damage, Damage, 0);
- // Mojang uses floor() to get X and Z positions, instead of just casting it to an (int)
+ // Fall particles
GetWorld()->BroadcastSoundParticleEffect(2006, (int)floor(GetPosX()), (int)GetPosY() - 1, (int)floor(GetPosZ()), Damage /* Used as particle effect speed modifier */);
}
@@ -787,7 +788,7 @@ void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
{
if (IsGameModeCreative())
{
- // No damage / health in creative mode
+ // No damage / health in creative mode if not void damage
return;
}
}
@@ -1630,27 +1631,12 @@ bool cPlayer::LoadFromDisk()
m_CurrentXp = (short) root.get("xpCurrent", 0).asInt();
m_IsFlying = root.get("isflying", 0).asBool();
- //SetExperience(root.get("experience", 0).asInt());
-
m_GameMode = (eGameMode) root.get("gamemode", eGameMode_NotSet).asInt();
if (m_GameMode == eGameMode_Creative)
{
m_CanFly = true;
}
- else if (m_GameMode == eGameMode_NotSet)
- {
- cWorld * World = cRoot::Get()->GetWorld(GetLoadedWorldName());
- if (World == NULL)
- {
- World = cRoot::Get()->GetDefaultWorld();
- }
-
- if (World->GetGameMode() == eGameMode_Creative)
- {
- m_CanFly = true;
- }
- }
m_Inventory.LoadFromJson(root["inventory"]);
@@ -1767,85 +1753,6 @@ void cPlayer::UseEquippedItem(void)
-void cPlayer::SetSwimState(cChunk & a_Chunk)
-{
- int RelY = (int)floor(m_LastPosY + 0.1);
- if ((RelY < 0) || (RelY >= cChunkDef::Height - 1))
- {
- m_IsSwimming = false;
- m_IsSubmerged = false;
- return;
- }
-
- BLOCKTYPE BlockIn;
- int RelX = (int)floor(m_LastPosX) - a_Chunk.GetPosX() * cChunkDef::Width;
- int RelZ = (int)floor(m_LastPosZ) - a_Chunk.GetPosZ() * cChunkDef::Width;
-
- // Check if the player is swimming:
- // Use Unbounded, because we're being called *after* processing super::Tick(), which could have changed our chunk
- if (!a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockIn))
- {
- // This sometimes happens on Linux machines
- // Ref.: http://forum.mc-server.org/showthread.php?tid=1244
- LOGD("SetSwimState failure: RelX = %d, RelZ = %d, LastPos = {%.02f, %.02f}, Pos = %.02f, %.02f}",
- RelX, RelY, m_LastPosX, m_LastPosZ, GetPosX(), GetPosZ()
- );
- m_IsSwimming = false;
- m_IsSubmerged = false;
- return;
- }
- m_IsSwimming = IsBlockWater(BlockIn);
-
- // Check if the player is submerged:
- VERIFY(a_Chunk.UnboundedRelGetBlockType(RelX, RelY + 1, RelZ, BlockIn));
- m_IsSubmerged = IsBlockWater(BlockIn);
-}
-
-
-
-
-
-void cPlayer::HandleAir(void)
-{
- // Ref.: http://www.minecraftwiki.net/wiki/Chunk_format
- // see if the player is /submerged/ water (block above is water)
- // Get the type of block the player's standing in:
-
- if (IsSubmerged())
- {
- // either reduce air level or damage player
- if (m_AirLevel < 1)
- {
- if (m_AirTickTimer < 1)
- {
- // damage player
- TakeDamage(dtDrowning, NULL, 1, 1, 0);
- // reset timer
- m_AirTickTimer = DROWNING_TICKS;
- }
- else
- {
- m_AirTickTimer -= 1;
- }
- }
- else
- {
- // reduce air supply
- m_AirLevel -= 1;
- }
- }
- else
- {
- // set the air back to maximum
- m_AirLevel = MAX_AIR_LEVEL;
- m_AirTickTimer = DROWNING_TICKS;
- }
-}
-
-
-
-
-
void cPlayer::HandleFood(void)
{
// Ref.: http://www.minecraftwiki.net/wiki/Hunger
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 46d0de69d..50f7560d6 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -31,8 +31,6 @@ public:
MAX_HEALTH = 20,
MAX_FOOD_LEVEL = 20,
EATING_TICKS = 30, ///< Number of ticks it takes to eat an item
- MAX_AIR_LEVEL = 300,
- DROWNING_TICKS = 10, //number of ticks per heart of damage
} ;
// tolua_end
@@ -241,8 +239,6 @@ public:
int GetFoodTickTimer (void) const { return m_FoodTickTimer; }
double GetFoodExhaustionLevel (void) const { return m_FoodExhaustionLevel; }
int GetFoodPoisonedTicksRemaining(void) const { return m_FoodPoisonedTicksRemaining; }
-
- int GetAirLevel (void) const { return m_AirLevel; }
/// Returns true if the player is satiated, i. e. their foodlevel is at the max and they cannot eat anymore
bool IsSatiated(void) const { return (m_FoodLevel >= MAX_FOOD_LEVEL); }
@@ -353,12 +349,6 @@ public:
/// If true the player can fly even when he's not in creative.
void SetCanFly(bool a_CanFly);
- /// Returns whether the player is swimming or not
- virtual bool IsSwimming(void) const{ return m_IsSwimming; }
-
- /// Return whether the player is under water or not
- virtual bool IsSubmerged(void) const{ return m_IsSubmerged; }
-
/// Returns wheter the player can fly or not.
virtual bool CanFly(void) const { return m_CanFly; }
// tolua_end
@@ -389,12 +379,6 @@ protected:
XP_TO_LEVEL30 = 825
} ;
- /// Player's air level (for swimming)
- int m_AirLevel;
-
- /// used to time ticks between damage taken via drowning/suffocation
- int m_AirTickTimer;
-
bool m_bVisible;
// Food-related variables:
@@ -431,7 +415,7 @@ protected:
float m_LastBlockActionTime;
int m_LastBlockActionCnt;
eGameMode m_GameMode;
- std::string m_IP;
+ AString m_IP;
/// The item being dragged by the cursor while in a UI window
cItem m_DraggingItem;
@@ -490,12 +474,6 @@ protected:
/// Called in each tick if the player is fishing to make sure the floater dissapears when the player doesn't have a fishing rod as equipped item.
void HandleFloater(void);
-
- /// Called in each tick to handle air-related processing i.e. drowning
- void HandleAir();
-
- /// Called once per tick to set IsSwimming and IsSubmerged
- void SetSwimState(cChunk & a_Chunk);
/// Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block)
void ApplyFoodExhaustionFromMovement();
diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp
index baa5b76b8..ef38f1399 100644
--- a/src/Generating/ChunkGenerator.cpp
+++ b/src/Generating/ChunkGenerator.cpp
@@ -201,7 +201,7 @@ void cChunkGenerator::Execute(void)
while (!m_ShouldTerminate)
{
cCSLock Lock(m_CS);
- while (m_Queue.size() == 0)
+ while (m_Queue.empty())
{
if ((NumChunksGenerated > 16) && (clock() - LastReportTick > CLOCKS_PER_SEC))
{
@@ -221,6 +221,13 @@ void cChunkGenerator::Execute(void)
LastReportTick = clock();
}
+ if (m_Queue.empty())
+ {
+ // Sometimes the queue remains empty
+ // If so, we can't do any front() operations on it!
+ continue;
+ }
+
cChunkCoords coords = m_Queue.front(); // Get next coord from queue
m_Queue.erase( m_Queue.begin() ); // Remove coordinate from queue
bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT);
diff --git a/src/Globals.h b/src/Globals.h
index d2080b8eb..7e53da80e 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -91,6 +91,9 @@ typedef unsigned long long UInt64;
typedef unsigned int UInt32;
typedef unsigned short UInt16;
+typedef unsigned char Byte;
+
+
diff --git a/src/LeakFinder.cpp b/src/LeakFinder.cpp
index 9d7f185ba..42a5afe56 100644
--- a/src/LeakFinder.cpp
+++ b/src/LeakFinder.cpp
@@ -862,8 +862,10 @@ static int MyAllocHook(int nAllocType, void *pvData,
{
// RequestID was found
size_t temp = g_CurrentMemUsage;
- g_CurrentMemUsage -= nSize ;
- g_pCRTTable->Remove(lRequest);
+ if (g_pCRTTable->Remove(lRequest))
+ {
+ g_CurrentMemUsage -= nSize;
+ }
if (g_CurrentMemUsage > temp)
{
printf("********************************************\n");
@@ -896,8 +898,11 @@ static int MyAllocHook(int nAllocType, void *pvData,
// Try to find the RequestID in the Hash-Table, mark it that it was freed
lReallocRequest = pHead->lRequest;
size_t temp = g_CurrentMemUsage;
- g_CurrentMemUsage -= pHead->nDataSize;
bRet = g_pCRTTable->Remove(lReallocRequest);
+ if (bRet)
+ {
+ g_CurrentMemUsage -= pHead->nDataSize;
+ }
if (g_CurrentMemUsage > temp)
{
printf("********************************************\n");
diff --git a/src/MobProximityCounter.cpp b/src/MobProximityCounter.cpp
index 583a71579..6c44ea458 100644
--- a/src/MobProximityCounter.cpp
+++ b/src/MobProximityCounter.cpp
@@ -59,7 +59,7 @@ cMobProximityCounter::sIterablePair cMobProximityCounter::getMobWithinThosesDist
{
if (toReturn.m_Begin == m_DistanceToMonster.end())
{
- if (a_DistanceMin == -1 || itr->first > a_DistanceMin)
+ if ((a_DistanceMin == 1) || (itr->first > a_DistanceMin))
{
toReturn.m_Begin = itr; // this is the first one with distance > a_DistanceMin;
}
@@ -67,7 +67,7 @@ cMobProximityCounter::sIterablePair cMobProximityCounter::getMobWithinThosesDist
if (toReturn.m_Begin != m_DistanceToMonster.end())
{
- if (a_DistanceMax != -1 && itr->first > a_DistanceMax)
+ if ((a_DistanceMax != 1) && (itr->first > a_DistanceMax))
{
toReturn.m_End = itr; // this is just after the last one with distance < a_DistanceMax
// Note : if we are not going through this, it's ok, toReturn.m_End will be end();
diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp
index cc7e7da2b..f2f0c404c 100644
--- a/src/Mobs/AggressiveMonster.cpp
+++ b/src/Mobs/AggressiveMonster.cpp
@@ -4,7 +4,6 @@
#include "AggressiveMonster.h"
#include "../World.h"
-#include "../Vector3f.h"
#include "../Entities/Player.h"
#include "../MersenneTwister.h"
@@ -13,8 +12,7 @@
cAggressiveMonster::cAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) :
- super(a_ConfigName, a_MobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height),
- m_ChaseTime(999999)
+ super(a_ConfigName, a_MobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height)
{
m_EMPersonality = AGGRESSIVE;
}
@@ -27,32 +25,23 @@ cAggressiveMonster::cAggressiveMonster(const AString & a_ConfigName, eType a_Mob
void cAggressiveMonster::InStateChasing(float a_Dt)
{
super::InStateChasing(a_Dt);
- m_ChaseTime += a_Dt;
+
if (m_Target != NULL)
{
if (m_Target->IsPlayer())
{
- cPlayer * Player = (cPlayer *) m_Target;
- if (Player->IsGameModeCreative())
+ if (((cPlayer *)m_Target)->IsGameModeCreative())
{
m_EMState = IDLE;
return;
}
}
- Vector3f Pos = Vector3f( GetPosition() );
- Vector3f Their = Vector3f( m_Target->GetPosition() );
- if ((Their - Pos).Length() <= m_AttackRange)
+ if (((float)m_FinalDestination.x != (float)m_Target->GetPosX()) || ((float)m_FinalDestination.z != (float)m_Target->GetPosZ()))
{
- Attack(a_Dt);
+ MoveToPosition(m_Target->GetPosition());
}
- MoveToPosition(Their + Vector3f(0, 0.65f, 0));
}
- else if (m_ChaseTime > 5.f)
- {
- m_ChaseTime = 0;
- m_EMState = IDLE;
- }
}
@@ -61,8 +50,11 @@ void cAggressiveMonster::InStateChasing(float a_Dt)
void cAggressiveMonster::EventSeePlayer(cEntity * a_Entity)
{
- super::EventSeePlayer(a_Entity);
- m_EMState = CHASING;
+ if (!((cPlayer *)a_Entity)->IsGameModeCreative())
+ {
+ super::EventSeePlayer(a_Entity);
+ m_EMState = CHASING;
+ }
}
@@ -73,25 +65,32 @@ void cAggressiveMonster::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
- m_SeePlayerInterval += a_Dt;
-
- if (m_SeePlayerInterval > 1)
+ if (m_EMState == CHASING)
+ {
+ CheckEventLostPlayer();
+ }
+ else
{
- int rem = m_World->GetTickRandomNumber(3) + 1; // Check most of the time but miss occasionally
+ CheckEventSeePlayer();
+ }
+}
- m_SeePlayerInterval = 0.0;
- if (rem >= 2)
- {
- if (m_EMState == CHASING)
- {
- CheckEventLostPlayer();
- }
- else
- {
- CheckEventSeePlayer();
- }
- }
+
+
+
+
+void cAggressiveMonster::Attack(float a_Dt)
+{
+ super::Attack(a_Dt);
+
+ if ((m_Target != NULL) && (m_AttackInterval > 3.0))
+ {
+ // Setting this higher gives us more wiggle room for attackrate
+ m_AttackInterval = 0.0;
+ m_Target->TakeDamage(dtMobAttack, this, m_AttackDamage, 0);
}
}
+
+
diff --git a/src/Mobs/AggressiveMonster.h b/src/Mobs/AggressiveMonster.h
index 5a0d93f3d..9cee4e7a7 100644
--- a/src/Mobs/AggressiveMonster.h
+++ b/src/Mobs/AggressiveMonster.h
@@ -13,16 +13,15 @@ class cAggressiveMonster :
typedef cMonster super;
public:
+
cAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
virtual void Tick (float a_Dt, cChunk & a_Chunk) override;
virtual void InStateChasing(float a_Dt) override;
virtual void EventSeePlayer(cEntity *) override;
+ virtual void Attack(float a_Dt) override;
-
-protected:
- float m_ChaseTime;
} ;
diff --git a/src/Mobs/Creeper.cpp b/src/Mobs/Creeper.cpp
index 4e11ae13e..2e1ece865 100644
--- a/src/Mobs/Creeper.cpp
+++ b/src/Mobs/Creeper.cpp
@@ -3,6 +3,7 @@
#include "Creeper.h"
#include "../World.h"
+#include "../Entities/ProjectileEntity.h"
@@ -11,7 +12,8 @@
cCreeper::cCreeper(void) :
super("Creeper", mtCreeper, "mob.creeper.say", "mob.creeper.say", 0.6, 1.8),
m_bIsBlowing(false),
- m_bIsCharged(false)
+ m_bIsCharged(false),
+ m_ExplodingTimer(0)
{
}
@@ -19,11 +21,34 @@ cCreeper::cCreeper(void) :
+void cCreeper::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (!ReachedFinalDestination())
+ {
+ m_ExplodingTimer = 0;
+ m_bIsBlowing = false;
+ m_World->BroadcastEntityMetadata(*this);
+ }
+}
+
+
+
+
+
void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 2, E_ITEM_GUNPOWDER);
- // TODO Check if killed by a skeleton, then drop random music disk
+ if ((a_Killer != NULL) && (a_Killer->IsProjectile()))
+ {
+ if (((cMonster *)((cProjectileEntity *)a_Killer)->GetCreator())->GetMobType() == mtSkeleton)
+ {
+ // 12 music discs. TickRand starts from 0, so range = 11. Disk IDs start at 2256, so add that. There.
+ AddRandomDropItem(a_Drops, 1, 1, (short)m_World->GetTickRandomNumber(11) + 2256);
+ }
+ }
}
@@ -45,3 +70,27 @@ void cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI)
+
+void cCreeper::Attack(float a_Dt)
+{
+ UNUSED(a_Dt);
+
+ m_ExplodingTimer += 1;
+
+ if (!m_bIsBlowing)
+ {
+ m_World->BroadcastSoundEffect("random.fuse", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
+ m_bIsBlowing = true;
+ m_World->BroadcastEntityMetadata(*this);
+ }
+
+ if (m_ExplodingTimer == 20)
+ {
+ m_World->DoExplosionAt((m_bIsCharged ? 5 : 3), GetPosX(), GetPosY(), GetPosZ(), false, esMonster, this);
+ Destroy();
+ }
+}
+
+
+
+
diff --git a/src/Mobs/Creeper.h b/src/Mobs/Creeper.h
index c3d4edeae..0f71e5ad2 100644
--- a/src/Mobs/Creeper.h
+++ b/src/Mobs/Creeper.h
@@ -19,6 +19,8 @@ public:
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ virtual void Attack(float a_Dt) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
bool IsBlowing(void) const {return m_bIsBlowing; }
bool IsCharged(void) const {return m_bIsCharged; }
@@ -26,6 +28,7 @@ public:
private:
bool m_bIsBlowing, m_bIsCharged;
+ int m_ExplodingTimer;
} ;
diff --git a/src/Mobs/IronGolem.h b/src/Mobs/IronGolem.h
index d49ff4cab..41c60438c 100644
--- a/src/Mobs/IronGolem.h
+++ b/src/Mobs/IronGolem.h
@@ -18,6 +18,10 @@ public:
CLASS_PROTODEF(cIronGolem);
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+
+ // Iron golems do not drown
+ virtual void HandleAir(void) override {}
+ virtual void SetSwimState(cChunk & a_Chunk) override {}
} ;
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index 98b6c1d28..42c7d2899 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -8,14 +8,9 @@
#include "../World.h"
#include "../Entities/Player.h"
#include "../Entities/ExpOrb.h"
-#include "../Defines.h"
#include "../MonsterConfig.h"
#include "../MersenneTwister.h"
-#include "../Vector3f.h"
-#include "../Vector3i.h"
-#include "../Vector3d.h"
-#include "../Tracer.h"
#include "../Chunk.h"
#include "../FastRandom.h"
@@ -79,17 +74,15 @@ cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString
, m_AttackRate(3)
, m_IdleInterval(0)
, m_bMovingToDestination(false)
- , m_DestinationTime( 0 )
- , m_DestroyTimer( 0 )
- , m_Jump(0)
+ , m_DestroyTimer(0)
, m_MobType(a_MobType)
, m_SoundHurt(a_SoundHurt)
, m_SoundDeath(a_SoundDeath)
- , m_SeePlayerInterval (0)
- , m_AttackDamage(1.0f)
- , m_AttackRange(2.0f)
+ , m_AttackDamage(1)
+ , m_AttackRange(2)
, m_AttackInterval(0)
, m_BurnsInDaylight(false)
+ , m_LastGroundHeight(POSY_TOINT)
{
if (!a_ConfigName.empty())
{
@@ -110,11 +103,105 @@ void cMonster::SpawnOn(cClientHandle & a_Client)
-void cMonster::MoveToPosition( const Vector3f & a_Position )
+void cMonster::TickPathFinding()
{
+ int PosX = (int)floor(GetPosX());
+ int PosY = (int)floor(GetPosY());
+ int PosZ = (int)floor(GetPosZ());
+
+ m_FinalDestination.y = (double)FindFirstNonAirBlockPosition(m_FinalDestination.x, m_FinalDestination.z);
+
+ std::vector<Vector3d> m_PotentialCoordinates;
+ m_TraversedCoordinates.push_back(Vector3i(PosX, PosY, PosZ));
+
+ static const struct // Define which directions to try to move to
+ {
+ int x, z;
+ } gCrossCoords[] =
+ {
+ { 1, 0},
+ {-1, 0},
+ { 0, 1},
+ { 0,-1},
+ } ;
+
+ for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
+ {
+ if ((gCrossCoords[i].x + PosX == PosX) && (gCrossCoords[i].z + PosZ == PosZ))
+ {
+ continue;
+ }
+
+ if (IsCoordinateInTraversedList(Vector3i(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ)))
+ {
+ continue;
+ }
+
+ BLOCKTYPE BlockAtY = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ);
+ BLOCKTYPE BlockAtYP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 1, gCrossCoords[i].z + PosZ);
+ BLOCKTYPE BlockAtYPP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 2, gCrossCoords[i].z + PosZ);
+ BLOCKTYPE BlockAtYM = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY - 1, gCrossCoords[i].z + PosZ);
+
+ if (!g_BlockIsSolid[BlockAtY] && !g_BlockIsSolid[BlockAtYP] && !IsBlockLava(BlockAtYM))
+ {
+ m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY, gCrossCoords[i].z + PosZ));
+ }
+ else if (g_BlockIsSolid[BlockAtY] && !g_BlockIsSolid[BlockAtYP] && !g_BlockIsSolid[BlockAtYPP] && !IsBlockLava(BlockAtYM))
+ {
+ m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY + 1, gCrossCoords[i].z + PosZ));
+ }
+ }
+
+ if (!m_PotentialCoordinates.empty())
+ {
+ Vector3f ShortestCoords = m_PotentialCoordinates.front();
+ for (std::vector<Vector3d>::const_iterator itr = m_PotentialCoordinates.begin(); itr != m_PotentialCoordinates.end(); ++itr)
+ {
+ Vector3f Distance = m_FinalDestination - ShortestCoords;
+ Vector3f Distance2 = m_FinalDestination - *itr;
+ if (Distance.SqrLength() > Distance2.SqrLength())
+ {
+ ShortestCoords = *itr;
+ }
+ }
+
+ m_Destination = ShortestCoords;
+ m_Destination.z += 0.5f;
+ m_Destination.x += 0.5f;
+ }
+ else
+ {
+ FinishPathFinding();
+ }
+}
+
+
+
+
+
+void cMonster::MoveToPosition(const Vector3f & a_Position)
+{
+ FinishPathFinding();
+
+ m_FinalDestination = a_Position;
m_bMovingToDestination = true;
+ TickPathFinding();
+}
+
+
- m_Destination = a_Position;
+
+bool cMonster::IsCoordinateInTraversedList(Vector3i a_Coords)
+{
+ for (std::vector<Vector3i>::const_iterator itr = m_TraversedCoordinates.begin(); itr != m_TraversedCoordinates.end(); ++itr)
+ {
+ if (itr->Equals(a_Coords))
+ {
+ return true;
+ }
+ }
+
+ return false;
}
@@ -123,10 +210,24 @@ void cMonster::MoveToPosition( const Vector3f & a_Position )
bool cMonster::ReachedDestination()
{
- Vector3f Distance = (m_Destination) - GetPosition();
- if( Distance.SqrLength() < 2.f )
+ if ((m_Destination - GetPosition()).Length() < 0.5f)
+ {
return true;
+ }
+
+ return false;
+}
+
+
+
+bool cMonster::ReachedFinalDestination()
+{
+ if ((GetPosition() - m_FinalDestination).Length() <= m_AttackRange)
+ {
+ return true;
+ }
+
return false;
}
@@ -149,25 +250,35 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
return;
}
+ if ((m_Target != NULL) && m_Target->IsDestroyed())
+ m_Target = NULL;
+
// Burning in daylight
HandleDaylightBurning(a_Chunk);
-
- HandlePhysics(a_Dt,a_Chunk);
- BroadcastMovementUpdate();
a_Dt /= 1000;
if (m_bMovingToDestination)
{
- Vector3f Pos( GetPosition() );
- Vector3f Distance = m_Destination - Pos;
- if( !ReachedDestination() )
+ if (m_bOnGround)
+ {
+ m_Destination.y = FindFirstNonAirBlockPosition(m_Destination.x, m_Destination.z);
+
+ if (DoesPosYRequireJump(m_Destination.y))
+ {
+ m_bOnGround = false;
+ AddPosY(1.5); // Jump!!
+ }
+ }
+
+ Vector3f Distance = m_Destination - GetPosition();
+ if(!ReachedDestination() && !ReachedFinalDestination()) // If we haven't reached any sort of destination, move
{
Distance.y = 0;
Distance.Normalize();
Distance *= 3;
- SetSpeedX( Distance.x );
- SetSpeedZ( Distance.z );
+ SetSpeedX(Distance.x);
+ SetSpeedZ(Distance.z);
if (m_EMState == ESCAPING)
{ //Runs Faster when escaping :D otherwise they just walk away
@@ -177,40 +288,22 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
}
else
{
- m_bMovingToDestination = false;
- }
-
- if( GetSpeed().SqrLength() > 0.f )
- {
- if( m_bOnGround )
+ if (ReachedFinalDestination()) // If we have reached the ultimate, final destination, stop pathfinding and attack if appropriate
+ {
+ FinishPathFinding();
+ }
+ else
{
- Vector3f NormSpeed = Vector3f(GetSpeed()).NormalizeCopy();
- Vector3f NextBlock = Vector3f( GetPosition() ) + NormSpeed;
- int NextHeight;
- if (!m_World->TryGetHeight((int)NextBlock.x, (int)NextBlock.z, NextHeight))
- {
- // The chunk at NextBlock is not loaded
- return;
- }
- if( NextHeight > (GetPosY() - 1.0) && (NextHeight - GetPosY()) < 2.5 )
- {
- m_bOnGround = false;
- SetSpeedY(5.f); // Jump!!
- }
+ TickPathFinding(); // We have reached the next point in our path, calculate another point
}
}
}
- Vector3d Distance = m_Destination - GetPosition();
- if (Distance.SqrLength() > 0.1f)
- {
- double Rotation, Pitch;
- Distance.Normalize();
- VectorToEuler( Distance.x, Distance.y, Distance.z, Rotation, Pitch );
- SetHeadYaw (Rotation);
- SetYaw( Rotation );
- SetPitch( -Pitch );
- }
+ if (ReachedFinalDestination() && (m_Target != NULL))
+ Attack(a_Dt);
+
+ SetPitchAndYawFromDestination();
+ HandleFalling();
switch (m_EMState)
{
@@ -219,21 +312,113 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
// If enemy passive we ignore checks for player visibility
InStateIdle(a_Dt);
break;
- }
-
+ }
case CHASING:
{
// If we do not see a player anymore skip chasing action
InStateChasing(a_Dt);
break;
- }
-
+ }
case ESCAPING:
{
InStateEscaping(a_Dt);
break;
}
} // switch (m_EMState)
+
+ BroadcastMovementUpdate();
+}
+
+
+
+
+void cMonster::SetPitchAndYawFromDestination()
+{
+ Vector3d FinalDestination = m_FinalDestination;
+ if (m_Target != NULL)
+ {
+ if (m_Target->IsPlayer())
+ {
+ FinalDestination.y = ((cPlayer *)m_Target)->GetStance();
+ }
+ else
+ {
+ FinalDestination.y = GetHeight();
+ }
+ }
+
+ Vector3d Distance = FinalDestination - GetPosition();
+ if (Distance.SqrLength() > 0.1f)
+ {
+ {
+ double Rotation, Pitch;
+ Distance.Normalize();
+ VectorToEuler(Distance.x, Distance.y, Distance.z, Rotation, Pitch);
+ SetHeadYaw(Rotation);
+ SetPitch(-Pitch);
+ }
+
+ {
+ Vector3d BodyDistance = m_Destination - GetPosition();
+ double Rotation, Pitch;
+ Distance.Normalize();
+ VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, Rotation, Pitch);
+ SetYaw(Rotation);
+ }
+ }
+}
+
+
+
+
+void cMonster::HandleFalling()
+{
+ if (m_bOnGround)
+ {
+ int Damage = (m_LastGroundHeight - POSY_TOINT) - 3;
+
+ if (Damage > 0)
+ {
+ TakeDamage(dtFalling, NULL, Damage, Damage, 0);
+
+ // Fall particles
+ GetWorld()->BroadcastSoundParticleEffect(2006, POSX_TOINT, POSY_TOINT - 1, POSZ_TOINT, Damage /* Used as particle effect speed modifier */);
+ }
+
+ m_LastGroundHeight = (int)floor(GetPosY());
+ }
+}
+
+
+
+
+int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
+{
+ int PosY = (int)floor(GetPosY());
+
+ if (PosY < 0)
+ PosY = 0;
+ else if (PosY > cChunkDef::Height)
+ PosY = cChunkDef::Height;
+
+ if (!g_BlockIsSolid[m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))])
+ {
+ while (!g_BlockIsSolid[m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))] && (PosY > 0))
+ {
+ PosY--;
+ }
+
+ return PosY + 1;
+ }
+ else
+ {
+ while (g_BlockIsSolid[m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))] && (PosY < cChunkDef::Height))
+ {
+ PosY++;
+ }
+
+ return PosY;
+ }
}
@@ -244,11 +429,13 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
void cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
{
super::DoTakeDamage(a_TDI);
- if((m_SoundHurt != "") && (m_Health > 0)) m_World->BroadcastSoundEffect(m_SoundHurt, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
+
+ if((m_SoundHurt != "") && (m_Health > 0))
+ m_World->BroadcastSoundEffect(m_SoundHurt, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
+
if (a_TDI.Attacker != NULL)
{
m_Target = a_TDI.Attacker;
- AddReference(m_Target);
}
}
@@ -330,55 +517,12 @@ void cMonster::KilledBy(cEntity * a_Killer)
-//----State Logic
-
-const char *cMonster::GetState()
-{
- switch(m_EMState)
- {
- case IDLE: return "Idle";
- case ATTACKING: return "Attacking";
- case CHASING: return "Chasing";
- default: return "Unknown";
- }
-}
-
-
-
-
-
-// for debugging
-void cMonster::SetState(const AString & a_State)
-{
- if (a_State.compare("Idle") == 0)
- {
- m_EMState = IDLE;
- }
- else if (a_State.compare("Attacking") == 0)
- {
- m_EMState = ATTACKING;
- }
- else if (a_State.compare("Chasing") == 0)
- {
- m_EMState = CHASING;
- }
- else
- {
- LOGD("cMonster::SetState(): Invalid state");
- ASSERT(!"Invalid state");
- }
-}
-
-
-
-
-
//Checks to see if EventSeePlayer should be fired
//monster sez: Do I see the player
void cMonster::CheckEventSeePlayer(void)
{
// TODO: Rewrite this to use cWorld's DoWithPlayers()
- cPlayer * Closest = FindClosestPlayer();
+ cPlayer * Closest = m_World->FindClosestPlayer(GetPosition(), (float)m_SightDistance, false);
if (Closest != NULL)
{
@@ -391,14 +535,10 @@ void cMonster::CheckEventSeePlayer(void)
void cMonster::CheckEventLostPlayer(void)
-{
- Vector3f pos;
- cTracer LineOfSight(GetWorld());
-
+{
if (m_Target != NULL)
{
- pos = m_Target->GetPosition();
- if ((pos - GetPosition()).Length() > m_SightDistance || LineOfSight.Trace(GetPosition(),(pos - GetPosition()), (int)(pos - GetPosition()).Length()))
+ if ((m_Target->GetPosition() - GetPosition()).Length() > m_SightDistance)
{
EventLosePlayer();
}
@@ -418,7 +558,6 @@ void cMonster::CheckEventLostPlayer(void)
void cMonster::EventSeePlayer(cEntity * a_SeenPlayer)
{
m_Target = a_SeenPlayer;
- AddReference(m_Target);
}
@@ -427,7 +566,6 @@ void cMonster::EventSeePlayer(cEntity * a_SeenPlayer)
void cMonster::EventLosePlayer(void)
{
- Dereference(m_Target);
m_Target = NULL;
m_EMState = IDLE;
}
@@ -436,28 +574,35 @@ void cMonster::EventLosePlayer(void)
-// What to do if in Idle State
void cMonster::InStateIdle(float a_Dt)
{
+ if (m_bMovingToDestination)
+ {
+ return; // Still getting there
+ }
+
m_IdleInterval += a_Dt;
+
if (m_IdleInterval > 1)
{
- // at this interval the results are predictable
+ // At this interval the results are predictable
int rem = m_World->GetTickRandomNumber(6) + 1;
- // LOGD("Moving: int: %3.3f rem: %i",idle_interval,rem);
- m_IdleInterval -= 1; // So nothing gets dropped when the server hangs for a few seconds
- Vector3f Dist;
- Dist.x = (float)(m_World->GetTickRandomNumber(10) - 5);
- Dist.z = (float)(m_World->GetTickRandomNumber(10) - 5);
+ m_IdleInterval -= 1; // So nothing gets dropped when the server hangs for a few seconds
+
+ Vector3d Dist;
+ Dist.x = (double)m_World->GetTickRandomNumber(10) - 5;
+ Dist.z = (double)m_World->GetTickRandomNumber(10) - 5;
+
if ((Dist.SqrLength() > 2) && (rem >= 3))
{
- m_Destination.x = (float)(GetPosX() + Dist.x);
- m_Destination.z = (float)(GetPosZ() + Dist.z);
- int PosY;
- if (m_World->TryGetHeight((int)m_Destination.x, (int)m_Destination.z, PosY))
+ Vector3d Destination(GetPosX() + Dist.x, 0, GetPosZ() + Dist.z);
+
+ int NextHeight = FindFirstNonAirBlockPosition(Destination.x, Destination.z);
+
+ if (IsNextYPosReachable(NextHeight))
{
- m_Destination.y = (float)PosY + 1.2f;
- MoveToPosition(m_Destination);
+ Destination.y = NextHeight;
+ MoveToPosition(Destination);
}
}
}
@@ -505,22 +650,6 @@ void cMonster::InStateEscaping(float a_Dt)
void cMonster::Attack(float a_Dt)
{
m_AttackInterval += a_Dt * m_AttackRate;
- if ((m_Target != NULL) && (m_AttackInterval > 3.0))
- {
- // Setting this higher gives us more wiggle room for attackrate
- m_AttackInterval = 0.0;
- ((cPawn *)m_Target)->TakeDamage(*this);
- }
-}
-
-
-
-
-
-// Checks for Players close by and if they are visible return the closest
-cPlayer * cMonster::FindClosestPlayer(void)
-{
- return m_World->FindClosestPlayer(GetPosition(), m_SightDistance);
}
@@ -536,42 +665,6 @@ void cMonster::GetMonsterConfig(const AString & a_Name)
-void cMonster::SetAttackRate(int ar)
-{
- m_AttackRate = (float)ar;
-}
-
-
-
-
-
-void cMonster::SetAttackRange(float ar)
-{
- m_AttackRange = ar;
-}
-
-
-
-
-
-void cMonster::SetAttackDamage(float ad)
-{
- m_AttackDamage = ad;
-}
-
-
-
-
-
-void cMonster::SetSightDistance(float sd)
-{
- m_SightDistance = sd;
-}
-
-
-
-
-
AString cMonster::MobTypeToString(cMonster::eType a_MobType)
{
// Mob types aren't sorted, so we need to search linearly:
@@ -635,6 +728,8 @@ cMonster::eType cMonster::StringToMobType(const AString & a_Name)
cMonster::eFamily cMonster::FamilyFromType(eType a_Type)
{
+ // Passive-agressive mobs are counted in mob spawning code as passive
+
switch (a_Type)
{
case mtBat: return mfAmbient;
@@ -699,7 +794,7 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
case mtMagmaCube:
case mtSlime:
{
- toReturn = new cSlime (Random.NextInt(2) + 1);
+ toReturn = new cSlime(Random.NextInt(2) + 1);
break;
}
case mtSkeleton:
@@ -803,6 +898,13 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk)
int RelX = (int)floor(GetPosX()) - GetChunkX() * cChunkDef::Width;
int RelZ = (int)floor(GetPosZ()) - GetChunkZ() * cChunkDef::Width;
+
+ if (!a_Chunk.IsLightValid())
+ {
+ m_World->QueueLightChunk(GetChunkX(), GetChunkZ());
+ return;
+ }
+
if (
(a_Chunk.GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight
(a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand
diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h
index dafb33574..1dd302cdc 100644
--- a/src/Mobs/Monster.h
+++ b/src/Mobs/Monster.h
@@ -10,7 +10,6 @@
-class Vector3f;
class cClientHandle;
class cWorld;
@@ -74,8 +73,6 @@ public:
enum MState{ATTACKING, IDLE, CHASING, ESCAPING} m_EMState;
enum MPersonality{PASSIVE,AGGRESSIVE,COWARDLY} m_EMPersonality;
- float m_SightDistance;
-
/** Creates the mob object.
* If a_ConfigName is not empty, the configuration is loaded using GetMonsterConfig()
* a_MobType is the type of the mob (also used in the protocol ( http://wiki.vg/Entities#Mobs , 2012_12_22))
@@ -100,14 +97,9 @@ public:
eType GetMobType(void) const {return m_MobType; }
eFamily GetMobFamily(void) const;
// tolua_end
-
-
- const char * GetState();
- void SetState(const AString & str);
virtual void CheckEventSeePlayer(void);
virtual void EventSeePlayer(cEntity * a_Player);
- virtual cPlayer * FindClosestPlayer(); // non static is easier. also virtual so other mobs can implement their own searching algo
/// Reads the monster configuration for the specified monster name and assigns it to this object.
void GetMonsterConfig(const AString & a_Name);
@@ -121,11 +113,11 @@ public:
virtual void Attack(float a_Dt);
- int GetAttackRate(){return (int)m_AttackRate;}
- void SetAttackRate(int ar);
- void SetAttackRange(float ar);
- void SetAttackDamage(float ad);
- void SetSightDistance(float sd);
+ int GetAttackRate() { return (int)m_AttackRate; }
+ void SetAttackRate(float a_AttackRate) { m_AttackRate = a_AttackRate; }
+ void SetAttackRange(int a_AttackRange) { m_AttackRange = a_AttackRange; }
+ void SetAttackDamage(int a_AttackDamage) { m_AttackDamage = a_AttackDamage; }
+ void SetSightDistance(int a_SightDistance) { m_SightDistance = a_SightDistance; }
/// Sets whether the mob burns in daylight. Only evaluated at next burn-decision tick
void SetBurnsInDaylight(bool a_BurnsInDaylight) { m_BurnsInDaylight = a_BurnsInDaylight; }
@@ -159,34 +151,80 @@ public:
protected:
- cEntity * m_Target;
- float m_AttackRate;
- float m_IdleInterval;
+ /* ======= PATHFINDING ======= */
- Vector3f m_Destination;
+ /** A pointer to the entity this mobile is aiming to reach */
+ cEntity * m_Target;
+ /** Coordinates of the next position that should be reached */
+ Vector3d m_Destination;
+ /** Coordinates for the ultimate, final destination. */
+ Vector3d m_FinalDestination;
+ /** Returns if the ultimate, final destination has been reached */
+ bool ReachedFinalDestination(void);
+
+ /** Stores if mobile is currently moving towards the ultimate, final destination */
bool m_bMovingToDestination;
- bool m_bPassiveAggressive;
+ /** Finds the first non-air block position (not the highest, as cWorld::GetHeight does)
+ If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1
+ If current Y is solid, goes up to find first nonsolid block, and returns that */
+ int FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ);
+ /** Returns if a monster can actually reach a given height by jumping or walking */
+ inline bool IsNextYPosReachable(int a_PosY)
+ {
+ return (
+ (a_PosY <= (int)floor(GetPosY())) ||
+ DoesPosYRequireJump(a_PosY)
+ );
+ }
+ /** Returns if a monster can reach a given height by jumping */
+ inline bool DoesPosYRequireJump(int a_PosY)
+ {
+ return ((a_PosY > (int)floor(GetPosY())) && (a_PosY == (int)floor(GetPosY()) + 1));
+ }
+
+ /** A semi-temporary list to store the traversed coordinates during active pathfinding so we don't visit them again */
+ std::vector<Vector3i> m_TraversedCoordinates;
+ /** Returns if coordinate is in the traversed list */
+ bool IsCoordinateInTraversedList(Vector3i a_Coords);
+
+ /** Finds the next place to go
+ This is based on the ultimate, final destination and the current position, as well as the traversed coordinates, and any environmental hazards */
+ void TickPathFinding(void);
+ /** Finishes a pathfinding task, be it due to failure or something else */
+ inline void FinishPathFinding(void)
+ {
+ m_TraversedCoordinates.clear();
+ m_bMovingToDestination = false;
+ }
+ /** Sets the body yaw and head yaw/pitch based on next/ultimate destinations */
+ void SetPitchAndYawFromDestination(void);
+
+ /* =========================== */
+ /* ========= FALLING ========= */
- float m_DestinationTime;
+ virtual void HandleFalling(void);
+ int m_LastGroundHeight;
+ /* =========================== */
+
+ float m_IdleInterval;
float m_DestroyTimer;
- float m_Jump;
eType m_MobType;
AString m_SoundHurt;
AString m_SoundDeath;
- float m_SeePlayerInterval;
- float m_AttackDamage;
- float m_AttackRange;
+ float m_AttackRate;
+ int m_AttackDamage;
+ int m_AttackRange;
float m_AttackInterval;
+ int m_SightDistance;
+ void HandleDaylightBurning(cChunk & a_Chunk);
bool m_BurnsInDaylight;
- void AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth = 0);
-
- void HandleDaylightBurning(cChunk & a_Chunk);
+ void AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth = 0);
} ; // tolua_export
diff --git a/src/Mobs/PassiveAggressiveMonster.cpp b/src/Mobs/PassiveAggressiveMonster.cpp
index 28de65905..4b45f9a2a 100644
--- a/src/Mobs/PassiveAggressiveMonster.cpp
+++ b/src/Mobs/PassiveAggressiveMonster.cpp
@@ -25,8 +25,7 @@ void cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
if ((m_Target != NULL) && (m_Target->IsPlayer()))
{
- cPlayer * Player = (cPlayer *) m_Target;
- if (Player->GetGameMode() != 1)
+ if (!((cPlayer *)m_Target)->IsGameModeCreative())
{
m_EMState = CHASING;
}
diff --git a/src/Mobs/PassiveMonster.cpp b/src/Mobs/PassiveMonster.cpp
index 91ceb5a53..d774d3170 100644
--- a/src/Mobs/PassiveMonster.cpp
+++ b/src/Mobs/PassiveMonster.cpp
@@ -2,7 +2,6 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "PassiveMonster.h"
-#include "../MersenneTwister.h"
#include "../World.h"
@@ -36,20 +35,9 @@ void cPassiveMonster::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
- m_SeePlayerInterval += a_Dt;
-
- if (m_SeePlayerInterval > 1) // Check every second
+ if (m_EMState == ESCAPING)
{
- int rem = m_World->GetTickRandomNumber(3) + 1; // Check most of the time but miss occasionally
-
- m_SeePlayerInterval = 0.0;
- if (rem >= 2)
- {
- if (m_EMState == ESCAPING)
- {
- CheckEventLostPlayer();
- }
- }
+ CheckEventLostPlayer();
}
}
diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp
index 509c2191e..4c8e78988 100644
--- a/src/Mobs/Skeleton.cpp
+++ b/src/Mobs/Skeleton.cpp
@@ -30,15 +30,18 @@ void cSkeleton::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cSkeleton::MoveToPosition(const Vector3f & a_Position)
{
- m_Destination = a_Position;
-
// If the destination is in the sun and if it is not night AND the skeleton isn't on fire then block the movement.
- if (!IsOnFire() && m_World->GetTimeOfDay() < 13187 && m_World->GetBlockSkyLight((int) a_Position.x, (int) a_Position.y, (int) a_Position.z) == 15)
+ if (
+ !IsOnFire() &&
+ (m_World->GetTimeOfDay() < 13187) &&
+ (m_World->GetBlockSkyLight((int) a_Position.x, (int) a_Position.y, (int) a_Position.z) == 15)
+ )
{
m_bMovingToDestination = false;
return;
}
- m_bMovingToDestination = true;
+
+ super::MoveToPosition(a_Position);
}
diff --git a/src/Mobs/Squid.h b/src/Mobs/Squid.h
index ad299b95c..a9dba8b70 100644
--- a/src/Mobs/Squid.h
+++ b/src/Mobs/Squid.h
@@ -21,6 +21,9 @@ public:
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ // Squids do not drown (or float)
+ virtual void HandleAir(void) override {}
+ virtual void SetSwimState(cChunk & a_Chunk) override {}
} ;
diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp
index 3d4e97c80..11e3f690a 100644
--- a/src/Mobs/Wolf.cpp
+++ b/src/Mobs/Wolf.cpp
@@ -37,6 +37,26 @@ void cWolf::DoTakeDamage(TakeDamageInfo & a_TDI)
+void cWolf::Attack(float a_Dt)
+{
+ UNUSED(a_Dt);
+
+ if ((m_Target != NULL) && (m_Target->IsPlayer()))
+ {
+ if (((cPlayer *)m_Target)->GetName() != m_OwnerName)
+ {
+ super::Attack(a_Dt);
+ }
+ }
+ else
+ {
+ super::Attack(a_Dt);
+ }
+}
+
+
+
+
void cWolf::OnRightClicked(cPlayer & a_Player)
{
@@ -108,7 +128,7 @@ void cWolf::Tick(float a_Dt, cChunk & a_Chunk)
m_bMovingToDestination = false;
}
- cPlayer * a_Closest_Player = FindClosestPlayer();
+ cPlayer * a_Closest_Player = m_World->FindClosestPlayer(GetPosition(), (float)m_SightDistance);
if (a_Closest_Player != NULL)
{
switch (a_Closest_Player->GetEquippedItem().m_ItemType)
@@ -125,9 +145,7 @@ void cWolf::Tick(float a_Dt, cChunk & a_Chunk)
SetIsBegging(true);
m_World->BroadcastEntityMetadata(*this);
}
- Vector3f a_NewDestination = a_Closest_Player->GetPosition();
- a_NewDestination.y = a_NewDestination.y + 1; // Look at the head of the player, not his feet.
- m_Destination = Vector3f(a_NewDestination);
+ m_FinalDestination = a_Closest_Player->GetPosition();;
m_bMovingToDestination = false;
break;
}
@@ -163,23 +181,19 @@ void cWolf::TickFollowPlayer()
return false;
}
public:
- Vector3f OwnerPos;
+ Vector3d OwnerPos;
} Callback;
if (m_World->DoWithPlayer(m_OwnerName, Callback))
{
// The player is present in the world, follow them:
double Distance = (Callback.OwnerPos - GetPosition()).Length();
- if (Distance < 3)
- {
- m_bMovingToDestination = false;
- }
- else if ((Distance > 30) && (!IsSitting()))
+ if ((Distance > 30) && (!IsSitting()))
{
TeleportToCoords(Callback.OwnerPos.x, Callback.OwnerPos.y, Callback.OwnerPos.z);
}
else
{
- m_Destination = Callback.OwnerPos;
+ MoveToPosition(Callback.OwnerPos);
}
}
}
diff --git a/src/Mobs/Wolf.h b/src/Mobs/Wolf.h
index 040e2cf7a..9e5ad03c7 100644
--- a/src/Mobs/Wolf.h
+++ b/src/Mobs/Wolf.h
@@ -22,6 +22,7 @@ public:
virtual void OnRightClicked(cPlayer & a_Player) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void TickFollowPlayer();
+ virtual void Attack(float a_Dt) override;
// Get functions
bool IsSitting (void) const { return m_IsSitting; }
diff --git a/src/Mobs/Zombie.cpp b/src/Mobs/Zombie.cpp
index a046fcc92..27e8ed5fb 100644
--- a/src/Mobs/Zombie.cpp
+++ b/src/Mobs/Zombie.cpp
@@ -34,15 +34,18 @@ void cZombie::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cZombie::MoveToPosition(const Vector3f & a_Position)
{
- m_Destination = a_Position;
-
- // If the destination is in the sun and if it is not night AND the skeleton isn't on fire then block the movement.
- if ((m_World->GetBlockSkyLight((int) a_Position.x, (int) a_Position.y, (int) a_Position.z) == 15) && (m_World->GetTimeOfDay() < 13187) && !IsOnFire())
+ // If the destination is in the sun and if it is not night AND the zombie isn't on fire then block the movement.
+ if (
+ !IsOnFire() &&
+ (m_World->GetTimeOfDay() < 13187) &&
+ (m_World->GetBlockSkyLight((int)a_Position.x, (int)a_Position.y, (int)a_Position.z) == 15)
+ )
{
m_bMovingToDestination = false;
return;
}
- m_bMovingToDestination = true;
+
+ super::MoveToPosition(a_Position);
}
diff --git a/src/MonsterConfig.cpp b/src/MonsterConfig.cpp
index 6165606f0..c06bd6b6f 100644
--- a/src/MonsterConfig.cpp
+++ b/src/MonsterConfig.cpp
@@ -12,9 +12,9 @@
struct cMonsterConfig::sAttributesStruct
{
AString m_Name;
- double m_SightDistance;
- double m_AttackDamage;
- double m_AttackRange;
+ int m_SightDistance;
+ int m_AttackDamage;
+ int m_AttackRange;
double m_AttackRate;
int m_MaxHealth;
};
@@ -67,9 +67,9 @@ void cMonsterConfig::Initialize()
sAttributesStruct Attributes;
AString Name = MonstersIniFile.GetKeyName(i);
Attributes.m_Name = Name;
- Attributes.m_AttackDamage = MonstersIniFile.GetValueF(Name, "AttackDamage", 0);
- Attributes.m_AttackRange = MonstersIniFile.GetValueF(Name, "AttackRange", 0);
- Attributes.m_SightDistance = MonstersIniFile.GetValueF(Name, "SightDistance", 0);
+ Attributes.m_AttackDamage = MonstersIniFile.GetValueI(Name, "AttackDamage", 0);
+ Attributes.m_AttackRange = MonstersIniFile.GetValueI(Name, "AttackRange", 0);
+ Attributes.m_SightDistance = MonstersIniFile.GetValueI(Name, "SightDistance", 0);
Attributes.m_AttackRate = MonstersIniFile.GetValueF(Name, "AttackRate", 0);
Attributes.m_MaxHealth = MonstersIniFile.GetValueI(Name, "MaxHealth", 1);
m_pState->AttributesList.push_front(Attributes);
@@ -87,10 +87,10 @@ void cMonsterConfig::AssignAttributes(cMonster * a_Monster, const AString & a_Na
{
if (itr->m_Name.compare(a_Name) == 0)
{
- a_Monster->SetAttackDamage ((float)itr->m_AttackDamage);
- a_Monster->SetAttackRange ((float)itr->m_AttackRange);
- a_Monster->SetSightDistance((float)itr->m_SightDistance);
- a_Monster->SetAttackRate ((int)itr->m_AttackRate);
+ a_Monster->SetAttackDamage (itr->m_AttackDamage);
+ a_Monster->SetAttackRange (itr->m_AttackRange);
+ a_Monster->SetSightDistance(itr->m_SightDistance);
+ a_Monster->SetAttackRate ((float)itr->m_AttackRate);
a_Monster->SetMaxHealth (itr->m_MaxHealth);
return;
}
diff --git a/src/OSSupport/BlockingTCPLink.cpp b/src/OSSupport/BlockingTCPLink.cpp
index 08aec0c65..af50eda5d 100644
--- a/src/OSSupport/BlockingTCPLink.cpp
+++ b/src/OSSupport/BlockingTCPLink.cpp
@@ -2,7 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "BlockingTCPLink.h"
-
+#include "Errors.h"
@@ -75,7 +75,7 @@ bool cBlockingTCPLink::Connect(const char * iAddress, unsigned int iPort)
server.sin_port = htons( (unsigned short)iPort);
if (connect(m_Socket, (struct sockaddr *)&server, sizeof(server)))
{
- LOGWARN("cTCPLink: Connection to \"%s:%d\" failed (%s)", iAddress, iPort, cSocket::GetErrorString( cSocket::GetLastError() ).c_str() );
+ LOGWARN("cTCPLink: Connection to \"%s:%d\" failed (%s)", iAddress, iPort,GetOSErrorString( cSocket::GetLastError() ).c_str() );
CloseSocket();
return false;
}
diff --git a/src/OSSupport/Errors.cpp b/src/OSSupport/Errors.cpp
new file mode 100644
index 000000000..2e05f1df1
--- /dev/null
+++ b/src/OSSupport/Errors.cpp
@@ -0,0 +1,53 @@
+
+#include "Globals.h"
+
+#include "Errors.h"
+
+AString GetOSErrorString( int a_ErrNo )
+{
+ char buffer[ 1024 ];
+ AString Out;
+
+ #ifdef _WIN32
+
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, a_ErrNo, 0, buffer, ARRAYCOUNT(buffer), NULL);
+ Printf(Out, "%d: %s", a_ErrNo, buffer);
+ if (!Out.empty() && (Out[Out.length() - 1] == '\n'))
+ {
+ Out.erase(Out.length() - 2);
+ }
+ return Out;
+
+ #else // _WIN32
+
+ // According to http://linux.die.net/man/3/strerror_r there are two versions of strerror_r():
+
+ #if ( _GNU_SOURCE ) && !defined(ANDROID_NDK) // GNU version of strerror_r()
+
+ char * res = strerror_r( errno, buffer, ARRAYCOUNT(buffer) );
+ if( res != NULL )
+ {
+ Printf(Out, "%d: %s", a_ErrNo, res);
+ return Out;
+ }
+
+ #else // XSI version of strerror_r():
+
+ int res = strerror_r( errno, buffer, ARRAYCOUNT(buffer) );
+ if( res == 0 )
+ {
+ Printf(Out, "%d: %s", a_ErrNo, buffer);
+ return Out;
+ }
+
+ #endif // strerror_r() version
+
+ else
+ {
+ Printf(Out, "Error %d while getting error string for error #%d!", errno, a_ErrNo);
+ return Out;
+ }
+
+ #endif // else _WIN32
+}
+
diff --git a/src/OSSupport/Errors.h b/src/OSSupport/Errors.h
new file mode 100644
index 000000000..8ce9deb10
--- /dev/null
+++ b/src/OSSupport/Errors.h
@@ -0,0 +1,5 @@
+
+#pragma once
+
+AString GetOSErrorString(int a_ErrNo);
+
diff --git a/src/OSSupport/Event.cpp b/src/OSSupport/Event.cpp
index cbacbba17..649a0a3cf 100644
--- a/src/OSSupport/Event.cpp
+++ b/src/OSSupport/Event.cpp
@@ -7,7 +7,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Event.h"
-
+#include "Errors.h"
@@ -35,14 +35,16 @@ cEvent::cEvent(void)
m_Event = sem_open(EventName.c_str(), O_CREAT, 777, 0 );
if (m_Event == SEM_FAILED)
{
- LOGERROR("cEvent: Cannot create event, errno = %i. Aborting server.", errno);
+ AString error = GetOSErrorString(errno);
+ LOGERROR("cEvent: Cannot create event, err = %s. Aborting server.", error.c_str());
abort();
}
// Unlink the semaphore immediately - it will continue to function but will not pollute the namespace
// We don't store the name, so can't call this in the destructor
if (sem_unlink(EventName.c_str()) != 0)
{
- LOGWARN("ERROR: Could not unlink cEvent. (%i)", errno);
+ AString error = GetOSErrorString(errno);
+ LOGWARN("ERROR: Could not unlink cEvent. (%s)", error.c_str());
}
}
#endif // *nix
@@ -61,7 +63,8 @@ cEvent::~cEvent()
{
if (sem_close(m_Event) != 0)
{
- LOGERROR("ERROR: Could not close cEvent. (%i)", errno);
+ AString error = GetOSErrorString(errno);
+ LOGERROR("ERROR: Could not close cEvent. (%s)", error.c_str());
}
}
else
@@ -88,7 +91,8 @@ void cEvent::Wait(void)
int res = sem_wait(m_Event);
if (res != 0 )
{
- LOGWARN("cEvent: waiting for the event failed: %i, errno = %i. Continuing, but server may be unstable.", res, errno);
+ AString error = GetOSErrorString(errno);
+ LOGWARN("cEvent: waiting for the event failed: %i, err = %s. Continuing, but server may be unstable.", res, error.c_str());
}
#endif
}
@@ -108,7 +112,8 @@ void cEvent::Set(void)
int res = sem_post(m_Event);
if (res != 0)
{
- LOGWARN("cEvent: Could not set cEvent: %i, errno = %d", res, errno);
+ AString error = GetOSErrorString(errno);
+ LOGWARN("cEvent: Could not set cEvent: %i, err = %s", res, error.c_str());
}
#endif
}
diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp
index 9f7c0d439..0ebd04915 100644
--- a/src/OSSupport/File.cpp
+++ b/src/OSSupport/File.cpp
@@ -450,3 +450,12 @@ int cFile::Printf(const char * a_Fmt, ...)
+
+void cFile::Flush(void)
+{
+ fflush(m_File);
+}
+
+
+
+
diff --git a/src/OSSupport/File.h b/src/OSSupport/File.h
index 01663a229..07fce6661 100644
--- a/src/OSSupport/File.h
+++ b/src/OSSupport/File.h
@@ -18,6 +18,8 @@ Usage:
2, Check if the file was opened using IsOpen()
3, Read / write
4, Destroy the instance
+
+For reading entire files into memory, just use the static cFile::ReadWholeFile()
*/
@@ -55,7 +57,7 @@ public:
static const char PathSeparator = '/';
#endif
- /// The mode in which to open the file
+ /** The mode in which to open the file */
enum eMode
{
fmRead, // Read-only. If the file doesn't exist, object will not be valid
@@ -63,13 +65,13 @@ public:
fmReadWrite // Read/write. If the file already exists, it will be left intact; writing will overwrite the data from the beginning
} ;
- /// Simple constructor - creates an unopened file object, use Open() to open / create a real file
+ /** Simple constructor - creates an unopened file object, use Open() to open / create a real file */
cFile(void);
- /// Constructs and opens / creates the file specified, use IsOpen() to check for success
+ /** Constructs and opens / creates the file specified, use IsOpen() to check for success */
cFile(const AString & iFileName, eMode iMode);
- /// Auto-closes the file, if open
+ /** Auto-closes the file, if open */
~cFile();
bool Open(const AString & iFileName, eMode iMode);
@@ -77,60 +79,63 @@ public:
bool IsOpen(void) const;
bool IsEOF(void) const;
- /// Reads up to iNumBytes bytes into iBuffer, returns the number of bytes actually read, or -1 on failure; asserts if not open
+ /** Reads up to iNumBytes bytes into iBuffer, returns the number of bytes actually read, or -1 on failure; asserts if not open */
int Read (void * iBuffer, int iNumBytes);
- /// Writes up to iNumBytes bytes from iBuffer, returns the number of bytes actually written, or -1 on failure; asserts if not open
+ /** Writes up to iNumBytes bytes from iBuffer, returns the number of bytes actually written, or -1 on failure; asserts if not open */
int Write(const void * iBuffer, int iNumBytes);
- /// Seeks to iPosition bytes from file start, returns old position or -1 for failure; asserts if not open
+ /** Seeks to iPosition bytes from file start, returns old position or -1 for failure; asserts if not open */
int Seek (int iPosition);
- /// Returns the current position (bytes from file start) or -1 for failure; asserts if not open
+ /** Returns the current position (bytes from file start) or -1 for failure; asserts if not open */
int Tell (void) const;
- /// Returns the size of file, in bytes, or -1 for failure; asserts if not open
+ /** Returns the size of file, in bytes, or -1 for failure; asserts if not open */
int GetSize(void) const;
- /// Reads the file from current position till EOF into an AString; returns the number of bytes read or -1 for error
+ /** Reads the file from current position till EOF into an AString; returns the number of bytes read or -1 for error */
int ReadRestOfFile(AString & a_Contents);
// tolua_begin
- /// Returns true if the file specified exists
+ /** Returns true if the file specified exists */
static bool Exists(const AString & a_FileName);
- /// Deletes a file, returns true if successful
+ /** Deletes a file, returns true if successful */
static bool Delete(const AString & a_FileName);
- /// Renames a file or folder, returns true if successful. May fail if dest already exists (libc-dependant)!
+ /** Renames a file or folder, returns true if successful. May fail if dest already exists (libc-dependant)! */
static bool Rename(const AString & a_OrigPath, const AString & a_NewPath);
- /// Copies a file, returns true if successful.
+ /** Copies a file, returns true if successful. */
static bool Copy(const AString & a_SrcFileName, const AString & a_DstFileName);
- /// Returns true if the specified path is a folder
+ /** Returns true if the specified path is a folder */
static bool IsFolder(const AString & a_Path);
- /// Returns true if the specified path is a regular file
+ /** Returns true if the specified path is a regular file */
static bool IsFile(const AString & a_Path);
- /// Returns the size of the file, or a negative number on error
+ /** Returns the size of the file, or a negative number on error */
static int GetSize(const AString & a_FileName);
- /// Creates a new folder with the specified name. Returns true if successful. Path may be relative or absolute
+ /** Creates a new folder with the specified name. Returns true if successful. Path may be relative or absolute */
static bool CreateFolder(const AString & a_FolderPath);
- /// Returns the entire contents of the specified file as a string. Returns empty string on error.
+ /** Returns the entire contents of the specified file as a string. Returns empty string on error. */
static AString ReadWholeFile(const AString & a_FileName);
// tolua_end
- /// Returns the list of all items in the specified folder (files, folders, nix pipes, whatever's there).
+ /** Returns the list of all items in the specified folder (files, folders, nix pipes, whatever's there). */
static AStringVector GetFolderContents(const AString & a_Folder); // Exported in ManualBindings.cpp
int Printf(const char * a_Fmt, ...);
+ /** Flushes all the bufferef output into the file (only when writing) */
+ void Flush(void);
+
private:
#ifdef USE_STDIO_FILE
FILE * m_File;
diff --git a/src/OSSupport/Socket.cpp b/src/OSSupport/Socket.cpp
index d80c9bb3d..4226a7535 100644
--- a/src/OSSupport/Socket.cpp
+++ b/src/OSSupport/Socket.cpp
@@ -105,58 +105,6 @@ void cSocket::ShutdownReadWrite(void)
-
-AString cSocket::GetErrorString( int a_ErrNo )
-{
- char buffer[ 1024 ];
- AString Out;
-
- #ifdef _WIN32
-
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, a_ErrNo, 0, buffer, ARRAYCOUNT(buffer), NULL);
- Printf(Out, "%d: %s", a_ErrNo, buffer);
- if (!Out.empty() && (Out[Out.length() - 1] == '\n'))
- {
- Out.erase(Out.length() - 2);
- }
- return Out;
-
- #else // _WIN32
-
- // According to http://linux.die.net/man/3/strerror_r there are two versions of strerror_r():
-
- #if ( _GNU_SOURCE ) && !defined(ANDROID_NDK) // GNU version of strerror_r()
-
- char * res = strerror_r( errno, buffer, ARRAYCOUNT(buffer) );
- if( res != NULL )
- {
- Printf(Out, "%d: %s", a_ErrNo, res);
- return Out;
- }
-
- #else // XSI version of strerror_r():
-
- int res = strerror_r( errno, buffer, ARRAYCOUNT(buffer) );
- if( res == 0 )
- {
- Printf(Out, "%d: %s", a_ErrNo, buffer);
- return Out;
- }
-
- #endif // strerror_r() version
-
- else
- {
- Printf(Out, "Error %d while getting error string for error #%d!", errno, a_ErrNo);
- return Out;
- }
-
- #endif // else _WIN32
-}
-
-
-
-
int cSocket::GetLastError()
{
#ifdef _WIN32
diff --git a/src/OSSupport/Socket.h b/src/OSSupport/Socket.h
index 91c9ca5fd..4ca3d61f4 100644
--- a/src/OSSupport/Socket.h
+++ b/src/OSSupport/Socket.h
@@ -14,7 +14,7 @@
#endif
-
+#include "Errors.h"
class cSocket
@@ -57,11 +57,10 @@ public:
/// Initializes the network stack. Returns 0 on success, or another number as an error code.
static int WSAStartup(void);
- static AString GetErrorString(int a_ErrNo);
static int GetLastError();
static AString GetLastErrorString(void)
{
- return GetErrorString(GetLastError());
+ return GetOSErrorString(GetLastError());
}
/// Creates a new socket of the specified address family
@@ -115,4 +114,4 @@ public:
private:
xSocket m_Socket;
AString m_IPString;
-}; \ No newline at end of file
+};
diff --git a/src/OSSupport/SocketThreads.cpp b/src/OSSupport/SocketThreads.cpp
index b8069cf00..74932daf8 100644
--- a/src/OSSupport/SocketThreads.cpp
+++ b/src/OSSupport/SocketThreads.cpp
@@ -7,6 +7,7 @@
#include "Globals.h"
#include "SocketThreads.h"
+#include "Errors.h"
@@ -556,7 +557,7 @@ void cSocketThreads::cSocketThread::WriteToSockets(fd_set * a_Write)
if (Sent < 0)
{
int Err = cSocket::GetLastError();
- LOGWARNING("Error %d while writing to client \"%s\", disconnecting. \"%s\"", Err, m_Slots[i].m_Socket.GetIPString().c_str(), cSocket::GetErrorString(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());
m_Slots[i].m_Socket.CloseSocket();
if (m_Slots[i].m_Client != NULL)
{
diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp
index b4ca37d37..f5fd95c7e 100644
--- a/src/Protocol/Protocol132.cpp
+++ b/src/Protocol/Protocol132.cpp
@@ -28,13 +28,14 @@
#pragma warning(disable:4702)
#endif
-#include "cryptopp/randpool.h"
-
#ifdef _MSC_VER
#pragma warning(pop)
#endif
+
+
+
#define HANDLE_PACKET_READ(Proc, Type, Var) \
Type Var; \
{ \
@@ -49,17 +50,6 @@
-typedef unsigned char Byte;
-
-
-
-
-
-using namespace CryptoPP;
-
-
-
-
const int MAX_ENC_LEN = 512; // Maximum size of the encrypted message; should be 128, but who knows...
@@ -93,81 +83,6 @@ enum
-// Converts a raw 160-bit SHA1 digest into a Java Hex representation
-// According to http://wiki.vg/wiki/index.php?title=Protocol_Encryption&oldid=2802
-static void DigestToJava(byte a_Digest[20], AString & a_Out)
-{
- bool IsNegative = (a_Digest[0] >= 0x80);
- if (IsNegative)
- {
- // Two's complement:
- bool carry = true; // Add one to the whole number
- for (int i = 19; i >= 0; i--)
- {
- a_Digest[i] = ~a_Digest[i];
- if (carry)
- {
- carry = (a_Digest[i] == 0xff);
- a_Digest[i]++;
- }
- }
- }
- a_Out.clear();
- a_Out.reserve(40);
- for (int i = 0; i < 20; i++)
- {
- AppendPrintf(a_Out, "%02x", a_Digest[i]);
- }
- while ((a_Out.length() > 0) && (a_Out[0] == '0'))
- {
- a_Out.erase(0, 1);
- }
- if (IsNegative)
- {
- a_Out.insert(0, "-");
- }
-}
-
-
-
-
-
-/*
-// Self-test the hash formatting for known values:
-// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48
-// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1
-// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6
-
-class Test
-{
-public:
- Test(void)
- {
- AString DigestNotch, DigestJeb, DigestSimon;
- byte Digest[20];
- CryptoPP::SHA1 Checksum;
- Checksum.Update((const byte *)"Notch", 5);
- Checksum.Final(Digest);
- DigestToJava(Digest, DigestNotch);
- Checksum.Restart();
- Checksum.Update((const byte *)"jeb_", 4);
- Checksum.Final(Digest);
- DigestToJava(Digest, DigestJeb);
- Checksum.Restart();
- Checksum.Update((const byte *)"simon", 5);
- Checksum.Final(Digest);
- DigestToJava(Digest, DigestSimon);
- printf("Notch: \"%s\"", DigestNotch.c_str());
- printf("jeb_: \"%s\"", DigestJeb.c_str());
- printf("simon: \"%s\"", DigestSimon.c_str());
- }
-} test;
-*/
-
-
-
-
-
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cProtocol132:
@@ -197,11 +112,11 @@ void cProtocol132::DataReceived(const char * a_Data, int a_Size)
{
if (m_IsEncrypted)
{
- byte Decrypted[512];
+ Byte Decrypted[512];
while (a_Size > 0)
{
int NumBytes = (a_Size > (int)sizeof(Decrypted)) ? (int)sizeof(Decrypted) : a_Size;
- m_Decryptor.ProcessData(Decrypted, (byte *)a_Data, NumBytes);
+ m_Decryptor.ProcessData(Decrypted, (Byte *)a_Data, NumBytes);
super::DataReceived((const char *)Decrypted, NumBytes);
a_Size -= NumBytes;
a_Data += NumBytes;
@@ -582,9 +497,7 @@ int cProtocol132::ParseHandshake(void)
return PARSE_OK; // Player is not allowed into the server
}
- // Send a 0xFD Encryption Key Request http://wiki.vg/Protocol#0xFD
- CryptoPP::StringSink sink(m_ServerPublicKey); // GCC won't allow inline instantiation in the following line, damned temporary refs
- cRoot::Get()->GetServer()->GetPublicKey().Save(sink);
+ // Send a 0xfd Encryption Key Request http://wiki.vg/Protocol#0xFD
SendEncryptionKeyRequest();
return PARSE_OK;
@@ -596,7 +509,7 @@ int cProtocol132::ParseHandshake(void)
int cProtocol132::ParseClientStatuses(void)
{
- HANDLE_PACKET_READ(ReadByte, byte, Status);
+ HANDLE_PACKET_READ(ReadByte, Byte, Status);
if ((Status & 1) == 0)
{
m_Client->HandleLogin(39, m_Username);
@@ -714,11 +627,11 @@ void cProtocol132::Flush(void)
int a_Size = m_DataToSend.size();
if (m_IsEncrypted)
{
- byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks)
+ Byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks)
while (a_Size > 0)
{
int NumBytes = (a_Size > (int)sizeof(Encrypted)) ? (int)sizeof(Encrypted) : a_Size;
- m_Encryptor.ProcessData(Encrypted, (byte *)a_Data, NumBytes);
+ m_Encryptor.ProcessData(Encrypted, (Byte *)a_Data, NumBytes);
super::SendData((const char *)Encrypted, NumBytes);
a_Size -= NumBytes;
a_Data += NumBytes;
@@ -880,8 +793,8 @@ void cProtocol132::SendEncryptionKeyRequest(void)
cCSLock Lock(m_CSPacket);
WriteByte(0xfd);
WriteString(cRoot::Get()->GetServer()->GetServerID());
- WriteShort((short)m_ServerPublicKey.size());
- SendData(m_ServerPublicKey.data(), m_ServerPublicKey.size());
+ WriteShort((short)(cRoot::Get()->GetServer()->GetPublicKeyDER().size()));
+ SendData(cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size());
WriteShort(4);
WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
Flush();
@@ -894,13 +807,11 @@ void cProtocol132::SendEncryptionKeyRequest(void)
void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce)
{
// Decrypt EncNonce using privkey
- RSAES<PKCS1v15>::Decryptor rsaDecryptor(cRoot::Get()->GetServer()->GetPrivateKey());
- time_t CurTime = time(NULL);
- CryptoPP::RandomPool rng;
- rng.Put((const byte *)&CurTime, sizeof(CurTime));
+ cRSAPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
+
Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
- DecodingResult res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncNonce.data(), a_EncNonce.size(), (byte *)DecryptedNonce);
- if (!res.isValidCoding || (res.messageLength != 4))
+ int res = rsaDecryptor.Decrypt((const Byte *)a_EncNonce.data(), a_EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce));
+ if (res != 4)
{
LOGD("Bad nonce length");
m_Client->Kick("Hacked client");
@@ -914,9 +825,9 @@ void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const A
}
// Decrypt the symmetric encryption key using privkey:
- byte DecryptedKey[MAX_ENC_LEN];
- res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncKey.data(), a_EncKey.size(), DecryptedKey);
- if (!res.isValidCoding || (res.messageLength != 16))
+ Byte DecryptedKey[MAX_ENC_LEN];
+ res = rsaDecryptor.Decrypt((const Byte *)a_EncKey.data(), a_EncKey.size(), DecryptedKey, sizeof(DecryptedKey));
+ if (res != 16)
{
LOGD("Bad key length");
m_Client->Kick("Hacked client");
@@ -932,6 +843,12 @@ void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const A
Flush();
}
+ #ifdef _DEBUG
+ AString DecryptedKeyHex;
+ CreateHexDump(DecryptedKeyHex, DecryptedKey, res, 16);
+ LOGD("Received encryption key, %d bytes:\n%s", res, DecryptedKeyHex.c_str());
+ #endif
+
StartEncryption(DecryptedKey);
return;
}
@@ -940,21 +857,21 @@ void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const A
-void cProtocol132::StartEncryption(const byte * a_Key)
+void cProtocol132::StartEncryption(const Byte * a_Key)
{
- m_Encryptor.SetKey(a_Key, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(a_Key, 16))(Name::FeedbackSize(), 1));
- m_Decryptor.SetKey(a_Key, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(a_Key, 16))(Name::FeedbackSize(), 1));
+ m_Encryptor.Init(a_Key, a_Key);
+ m_Decryptor.Init(a_Key, a_Key);
m_IsEncrypted = true;
// Prepare the m_AuthServerID:
- CryptoPP::SHA1 Checksum;
+ cSHA1Checksum Checksum;
AString ServerID = cRoot::Get()->GetServer()->GetServerID();
- Checksum.Update((const byte *)ServerID.c_str(), ServerID.length());
+ Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length());
Checksum.Update(a_Key, 16);
- Checksum.Update((const byte *)m_ServerPublicKey.c_str(), m_ServerPublicKey.length());
- byte Digest[20];
- Checksum.Final(Digest);
- DigestToJava(Digest, m_AuthServerID);
+ 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);
}
diff --git a/src/Protocol/Protocol132.h b/src/Protocol/Protocol132.h
index 80fc8740a..89f4636f5 100644
--- a/src/Protocol/Protocol132.h
+++ b/src/Protocol/Protocol132.h
@@ -20,13 +20,12 @@
#pragma warning(disable:4702)
#endif
-#include "cryptopp/modes.h"
-#include "cryptopp/aes.h"
-
#ifdef _MSC_VER
#pragma warning(pop)
#endif
+#include "../Crypto.h"
+
@@ -79,16 +78,15 @@ public:
protected:
bool m_IsEncrypted;
- CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption m_Decryptor;
- CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption m_Encryptor;
+
+ cAESCFBDecryptor m_Decryptor;
+ cAESCFBEncryptor m_Encryptor;
+
AString m_DataToSend;
/// The ServerID used for session authentication; set in StartEncryption(), used in GetAuthServerID()
AString m_AuthServerID;
- /// The server's public key, as used by SendEncryptionKeyRequest() and StartEncryption()
- AString m_ServerPublicKey;
-
virtual void SendData(const char * a_Data, int a_Size) override;
// DEBUG:
@@ -108,7 +106,7 @@ protected:
void HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce);
/// Starts the symmetric encryption with the specified key; also sets m_AuthServerID
- void StartEncryption(const byte * a_Key);
+ void StartEncryption(const Byte * a_Key);
} ;
diff --git a/src/Protocol/Protocol14x.cpp b/src/Protocol/Protocol14x.cpp
index 127ce9d4b..f82e6de45 100644
--- a/src/Protocol/Protocol14x.cpp
+++ b/src/Protocol/Protocol14x.cpp
@@ -33,8 +33,6 @@ Implements the 1.4.x protocol classes representing these protocols:
#pragma warning(disable:4702)
#endif
-#include "cryptopp/randpool.h"
-
#ifdef _MSC_VER
#pragma warning(pop)
#endif
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index d2d0df7f7..9bb2cfbf0 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -53,10 +53,8 @@ Implements the 1.7.x protocol classes:
-#ifdef _DEBUG
// fwd: main.cpp:
extern bool g_ShouldLogComm;
-#endif
@@ -76,14 +74,12 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd
m_IsEncrypted(false)
{
// Create the comm log file, if so requested:
- #ifdef _DEBUG
if (g_ShouldLogComm)
{
cFile::CreateFolder("CommLogs");
AString FileName = Printf("CommLogs/%x__%s.log", (unsigned)time(NULL), a_Client->GetIPString().c_str());
m_CommLogFile.Open(FileName, cFile::fmWrite);
}
- #endif // _DEBUG
}
@@ -94,11 +90,11 @@ void cProtocol172::DataReceived(const char * a_Data, int a_Size)
{
if (m_IsEncrypted)
{
- byte Decrypted[512];
+ Byte Decrypted[512];
while (a_Size > 0)
{
int NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size;
- m_Decryptor.ProcessData(Decrypted, (byte *)a_Data, NumBytes);
+ m_Decryptor.ProcessData(Decrypted, (Byte *)a_Data, NumBytes);
AddReceivedData((const char *)Decrypted, NumBytes);
a_Size -= NumBytes;
a_Data += NumBytes;
@@ -1087,16 +1083,27 @@ 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:
- #ifdef _DEBUG
if (g_ShouldLogComm)
{
+ if (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);
+ 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",
+ AllData.size(), AllData.size(), Hex.c_str()
+ );
+ }
AString Hex;
CreateHexDump(Hex, a_Data, a_Size, 16);
- m_CommLogFile.Printf("Incoming data: %d bytes. %d bytes unparsed already present in buffer.\n%s\n",
- a_Size, m_ReceivedData.GetReadableSpace(), Hex.c_str()
+ m_CommLogFile.Printf("Incoming data: %d (0x%x) bytes: \n%s\n",
+ a_Size, a_Size, Hex.c_str()
);
}
- #endif
if (!m_ReceivedData.Write(a_Data, a_Size))
{
@@ -1134,7 +1141,6 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
}
// Log the packet info into the comm log file:
- #ifdef _DEBUG
if (g_ShouldLogComm)
{
AString PacketData;
@@ -1149,7 +1155,6 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
PacketType, PacketType, PacketLen, PacketLen, m_State, PacketDataHex.c_str()
);
}
- #endif // _DEBUG
if (!HandlePacket(bb, PacketType))
{
@@ -1167,6 +1172,12 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
LOGD("Packet contents:\n%s", Out.c_str());
#endif // _DEBUG
+ // Put a message in the comm log:
+ if (g_ShouldLogComm)
+ {
+ m_CommLogFile.Printf("^^^^^^ Unhandled packet ^^^^^^\n\n\n");
+ }
+
return;
}
@@ -1176,6 +1187,16 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
LOGWARNING("Protocol 1.7: Wrong number of bytes read for packet 0x%x, state %d. Read %u bytes, packet contained %u bytes",
PacketType, m_State, bb.GetUsedSpace() - bb.GetReadableSpace(), PacketLen
);
+
+ // Put a message in the comm log:
+ if (g_ShouldLogComm)
+ {
+ m_CommLogFile.Printf("^^^^^^ Wrong number of bytes read for this packet (exp %d left, got %d left) ^^^^^^\n\n\n",
+ 1, bb.GetReadableSpace()
+ );
+ m_CommLogFile.Flush();
+ }
+
ASSERT(!"Read wrong number of bytes!");
m_Client->PacketError(PacketType);
}
@@ -1715,11 +1736,11 @@ void cProtocol172::SendData(const char * a_Data, int a_Size)
{
if (m_IsEncrypted)
{
- byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks)
+ Byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks)
while (a_Size > 0)
{
int NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size;
- m_Encryptor.ProcessData(Encrypted, (byte *)a_Data, NumBytes);
+ m_Encryptor.ProcessData(Encrypted, (Byte *)a_Data, NumBytes);
m_Client->SendData((const char *)Encrypted, NumBytes);
a_Size -= NumBytes;
a_Data += NumBytes;
@@ -1860,7 +1881,6 @@ cProtocol172::cPacketizer::~cPacketizer()
m_Out.CommitRead();
// Log the comm into logfile:
- #ifdef _DEBUG
if (g_ShouldLogComm)
{
AString Hex;
@@ -1870,7 +1890,6 @@ cProtocol172::cPacketizer::~cPacketizer()
DataToSend[0], DataToSend[0], PacketLen, PacketLen, m_Protocol.m_State, Hex.c_str()
);
}
- #endif // _DEBUG
}
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index b04a1f019..72544b575 100644
--- a/src/Protocol/Protocol17x.h
+++ b/src/Protocol/Protocol17x.h
@@ -26,21 +26,20 @@ Declares the 1.7.x protocol classes:
#pragma warning(disable:4702)
#endif
-#include "cryptopp/modes.h"
-#include "cryptopp/aes.h"
-
#ifdef _MSC_VER
#pragma warning(pop)
#endif
+#include "../Crypto.h"
+
class cProtocol172 :
- public cProtocol // TODO
+ public cProtocol
{
- typedef cProtocol super; // TODO
+ typedef cProtocol super;
public:
@@ -220,13 +219,12 @@ protected:
cByteBuffer m_OutPacketLenBuffer;
bool m_IsEncrypted;
- CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption m_Decryptor;
- CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption m_Encryptor;
- #ifdef _DEBUG
+ cAESCFBDecryptor m_Decryptor;
+ cAESCFBEncryptor m_Encryptor;
+
/** The logfile where the comm is logged, when g_ShouldLogComm is true */
cFile m_CommLogFile;
- #endif
/// Adds the received (unencrypted) data to m_ReceivedData, parses complete packets
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index de5dd3fb9..32409c2aa 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -965,7 +965,7 @@ void cProtocolRecognizer::SendLengthlessServerPing(void)
m_Buffer.ResetRead();
if (m_Buffer.CanReadBytes(2))
{
- byte val;
+ Byte val;
m_Buffer.ReadByte(val); // Packet type - Serverlist ping
m_Buffer.ReadByte(val); // 0x01 magic value
ASSERT(val == 0x01);
diff --git a/src/ReferenceManager.cpp b/src/ReferenceManager.cpp
deleted file mode 100644
index 6a9ed0e43..000000000
--- a/src/ReferenceManager.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "ReferenceManager.h"
-#include "Entities/Entity.h"
-
-
-
-
-
-cReferenceManager::cReferenceManager( ENUM_REFERENCE_MANAGER_TYPE a_Type )
- : m_Type( a_Type )
-{
-}
-
-cReferenceManager::~cReferenceManager()
-{
- if( m_Type == RFMNGR_REFERENCERS )
- {
- for( std::list< cEntity** >::iterator itr = m_References.begin(); itr != m_References.end(); ++itr )
- {
- *(*itr) = 0; // Set referenced pointer to 0
- }
- }
- else
- {
- for( std::list< cEntity** >::iterator itr = m_References.begin(); itr != m_References.end(); ++itr )
- {
- cEntity* Ptr = (*(*itr));
- if( Ptr ) Ptr->Dereference( *(*itr) );
- }
- }
-}
-
-void cReferenceManager::AddReference( cEntity*& a_EntityPtr )
-{
- m_References.push_back( &a_EntityPtr );
-}
-
-void cReferenceManager::Dereference( cEntity*& a_EntityPtr )
-{
- m_References.remove( &a_EntityPtr );
-} \ No newline at end of file
diff --git a/src/ReferenceManager.h b/src/ReferenceManager.h
deleted file mode 100644
index bcd451f72..000000000
--- a/src/ReferenceManager.h
+++ /dev/null
@@ -1,34 +0,0 @@
-
-#pragma once
-
-
-
-
-
-class cEntity;
-
-
-
-
-
-class cReferenceManager
-{
-public:
- enum ENUM_REFERENCE_MANAGER_TYPE
- {
- RFMNGR_REFERENCERS,
- RFMNGR_REFERENCES,
- };
- cReferenceManager( ENUM_REFERENCE_MANAGER_TYPE a_Type );
- ~cReferenceManager();
-
- void AddReference( cEntity*& a_EntityPtr );
- void Dereference( cEntity*& a_EntityPtr );
-private:
- ENUM_REFERENCE_MANAGER_TYPE m_Type;
- std::list< cEntity** > m_References;
-};
-
-
-
-
diff --git a/src/Server.cpp b/src/Server.cpp
index 34ee066cb..3f9f8a4ac 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -194,7 +194,7 @@ bool cServer::InitServer(cIniFile & a_SettingsIni)
m_PlayerCount = 0;
m_PlayerCountDiff = 0;
- m_FaviconData = Base64Encode(cFile::ReadWholeFile("favicon.png")); // Will return empty string if file nonexistant; client doesn't mind
+ m_FaviconData = Base64Encode(cFile::ReadWholeFile(FILE_IO_PREFIX + AString("favicon.png"))); // Will return empty string if file nonexistant; client doesn't mind
if (m_bIsConnected)
{
@@ -284,17 +284,9 @@ int cServer::GetNumPlayers(void)
void cServer::PrepareKeys(void)
{
- // TODO: Save and load key for persistence across sessions
- // But generating the key takes only a moment, do we even need that?
-
LOGD("Generating protocol encryption keypair...");
-
- time_t CurTime = time(NULL);
- CryptoPP::RandomPool rng;
- rng.Put((const byte *)&CurTime, sizeof(CurTime));
- m_PrivateKey.GenerateRandomWithKeySize(rng, 1024);
- CryptoPP::RSA::PublicKey pk(m_PrivateKey);
- m_PublicKey = pk;
+ VERIFY(m_PrivateKey.Generate(1024));
+ m_PublicKeyDER = m_PrivateKey.GetPubKeyDER();
}
diff --git a/src/Server.h b/src/Server.h
index bb55e81b6..15eafc00a 100644
--- a/src/Server.h
+++ b/src/Server.h
@@ -23,8 +23,7 @@
#pragma warning(disable:4702)
#endif
-#include "cryptopp/rsa.h"
-#include "cryptopp/randpool.h"
+#include "Crypto.h"
#ifdef _MSC_VER
#pragma warning(pop)
@@ -110,8 +109,8 @@ public: // tolua_export
/** Returns base64 encoded favicon data (obtained from favicon.png) */
const AString & GetFaviconData(void) const { return m_FaviconData; }
- CryptoPP::RSA::PrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
- CryptoPP::RSA::PublicKey & GetPublicKey (void) { return m_PublicKey; }
+ cRSAPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
+ const AString & GetPublicKeyDER(void) const { return m_PublicKeyDER; }
private:
@@ -180,8 +179,11 @@ private:
bool m_bRestarting;
- CryptoPP::RSA::PrivateKey m_PrivateKey;
- CryptoPP::RSA::PublicKey m_PublicKey;
+ /** The private key used for the assymetric encryption start in the protocols */
+ cRSAPrivateKey m_PrivateKey;
+
+ /** Public key for m_PrivateKey, ASN1-DER-encoded */
+ AString m_PublicKeyDER;
cRCONServer m_RCONServer;
diff --git a/src/World.cpp b/src/World.cpp
index 453a22c2d..5205c2616 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -234,7 +234,11 @@ cWorld::cWorld(const AString & a_WorldName) :
m_WorldName(a_WorldName),
m_IniFileName(m_WorldName + "/world.ini"),
m_StorageSchema("Default"),
+#ifdef _arm_
+ m_StorageCompressionFactor(0),
+#else
m_StorageCompressionFactor(6),
+#endif
m_IsSpawnExplicitlySet(false),
m_WorldAgeSecs(0),
m_TimeOfDaySecs(0),
@@ -2419,7 +2423,7 @@ bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCa
// TODO: This interface is dangerous!
-cPlayer * cWorld::FindClosestPlayer(const Vector3f & a_Pos, float a_SightLimit)
+cPlayer * cWorld::FindClosestPlayer(const Vector3f & a_Pos, float a_SightLimit, bool a_CheckLineOfSight)
{
cTracer LineOfSight(this);
@@ -2434,7 +2438,12 @@ cPlayer * cWorld::FindClosestPlayer(const Vector3f & a_Pos, float a_SightLimit)
if (Distance < ClosestDistance)
{
- if (!LineOfSight.Trace(a_Pos,(Pos - a_Pos),(int)(Pos - a_Pos).Length()))
+ if (a_CheckLineOfSight && !LineOfSight.Trace(a_Pos,(Pos - a_Pos),(int)(Pos - a_Pos).Length()))
+ {
+ ClosestDistance = Distance;
+ ClosestPlayer = *itr;
+ }
+ else
{
ClosestDistance = Distance;
ClosestPlayer = *itr;
diff --git a/src/World.h b/src/World.h
index 61c7604df..933e3ba6f 100644
--- a/src/World.h
+++ b/src/World.h
@@ -239,7 +239,7 @@ public:
bool FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
// TODO: This interface is dangerous - rewrite to DoWithClosestPlayer(pos, sight, action)
- cPlayer * FindClosestPlayer(const Vector3f & a_Pos, float a_SightLimit);
+ cPlayer * FindClosestPlayer(const Vector3f & a_Pos, float a_SightLimit, bool a_CheckLineOfSight = true);
void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player
diff --git a/src/main.cpp b/src/main.cpp
index 902e9e43b..06b344c25 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -19,10 +19,8 @@ bool g_SERVER_TERMINATED = false; // Set to true when the server terminates, so
-#ifdef _DEBUG
/** If set to true, the protocols will log each player's communication to a separate logfile */
bool g_ShouldLogComm;
-#endif
@@ -232,7 +230,6 @@ int main( int argc, char **argv )
// *((int *)0) = 0;
// Check if comm logging is to be enabled:
- #ifdef _DEBUG
for (int i = 0; i < argc; i++)
{
if (
@@ -243,7 +240,6 @@ int main( int argc, char **argv )
g_ShouldLogComm = true;
}
}
- #endif // _DEBUG
#if !defined(ANDROID_NDK)
try