Merge branch 'master' into chunksparsing/structs
This commit is contained in:
commit
8780b324ff
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -9,4 +9,4 @@
|
||||
url = https://github.com/bearbin/transapi.git
|
||||
[submodule "lib/polarssl"]
|
||||
path = lib/polarssl
|
||||
url = https://github.com/polarssl/polarssl
|
||||
url = https://github.com/mc-server/polarssl
|
||||
|
17
CoverityModel.cpp
Normal file
17
CoverityModel.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
|
||||
extern "C" {
|
||||
struct lua_State;
|
||||
struct tolua_Error
|
||||
{
|
||||
int index;
|
||||
int array;
|
||||
const char* type;
|
||||
};
|
||||
|
||||
void tolua_error (lua_State* L, const char* msg, tolua_Error* err)
|
||||
{
|
||||
__coverity_panic__();
|
||||
}
|
||||
|
||||
}
|
@ -36,14 +36,24 @@ set(SHARED_SRC
|
||||
../../src/StringUtils.cpp
|
||||
../../src/Log.cpp
|
||||
../../src/MCLogger.cpp
|
||||
../../src/Crypto.cpp
|
||||
../../src/PolarSSL++/AesCfb128Decryptor.cpp
|
||||
../../src/PolarSSL++/AesCfb128Encryptor.cpp
|
||||
../../src/PolarSSL++/CtrDrbgContext.cpp
|
||||
../../src/PolarSSL++/EntropyContext.cpp
|
||||
../../src/PolarSSL++/PublicKey.cpp
|
||||
../../src/PolarSSL++/RsaPrivateKey.cpp
|
||||
)
|
||||
set(SHARED_HDR
|
||||
../../src/ByteBuffer.h
|
||||
../../src/StringUtils.h
|
||||
../../src/Log.h
|
||||
../../src/MCLogger.h
|
||||
../../src/Crypto.h
|
||||
../../src/PolarSSL++/AesCfb128Decryptor.h
|
||||
../../src/PolarSSL++/AesCfb128Encryptor.h
|
||||
../../src/PolarSSL++/CtrDrbgContext.h
|
||||
../../src/PolarSSL++/EntropyContext.h
|
||||
../../src/PolarSSL++/PublicKey.h
|
||||
../../src/PolarSSL++/RsaPrivateKey.h
|
||||
)
|
||||
set(SHARED_OSS_SRC
|
||||
../../src/OSSupport/CriticalSection.cpp
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "Connection.h"
|
||||
#include "Server.h"
|
||||
#include <iostream>
|
||||
#include "PolarSSL++/PublicKey.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h> // For _mkdir()
|
||||
@ -471,7 +472,7 @@ bool cConnection::SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a
|
||||
|
||||
|
||||
|
||||
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer)
|
||||
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer)
|
||||
{
|
||||
DataLog(a_Data, a_Size, "Encrypting %d bytes to %s", a_Size, a_Peer);
|
||||
const Byte * Data = (const Byte *)a_Data;
|
||||
@ -495,7 +496,7 @@ bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryp
|
||||
|
||||
|
||||
|
||||
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer)
|
||||
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer)
|
||||
{
|
||||
AString All;
|
||||
a_Data.ReadAll(All);
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
#include "ByteBuffer.h"
|
||||
#include "OSSupport/Timer.h"
|
||||
#include "PolarSSL++/AesCfb128Decryptor.h"
|
||||
#include "PolarSSL++/AesCfb128Encryptor.h"
|
||||
|
||||
|
||||
|
||||
@ -66,8 +68,8 @@ protected:
|
||||
cByteBuffer m_ClientBuffer;
|
||||
cByteBuffer m_ServerBuffer;
|
||||
|
||||
cAESCFBDecryptor m_ServerDecryptor;
|
||||
cAESCFBEncryptor m_ServerEncryptor;
|
||||
cAesCfb128Decryptor m_ServerDecryptor;
|
||||
cAesCfb128Encryptor m_ServerEncryptor;
|
||||
|
||||
AString m_ServerEncryptionBuffer; // Buffer for the data to be sent to the server once encryption is established
|
||||
|
||||
@ -109,10 +111,10 @@ protected:
|
||||
bool SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a_Peer);
|
||||
|
||||
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
|
||||
bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer);
|
||||
bool SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer);
|
||||
|
||||
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
|
||||
bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer);
|
||||
bool SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer);
|
||||
|
||||
/// Decodes packets coming from the client, sends appropriate counterparts to the server; returns false if the connection is to be dropped
|
||||
bool DecodeClientsPackets(const char * a_Data, int a_Size);
|
||||
|
@ -216,6 +216,20 @@ typedef unsigned char Byte;
|
||||
// Pretty much the same as ASSERT() but stays in Release builds
|
||||
#define VERIFY( x ) ( !!(x) || ( LOGERROR("Verification failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), exit(1), 0 ) )
|
||||
|
||||
// Allow both Older versions of MSVC and newer versions of everything use a shared_ptr:
|
||||
// Note that we cannot typedef, because C++ doesn't allow (partial) templates to be typedeffed.
|
||||
#if (defined(_MSC_VER) && (_MSC_VER < 1600))
|
||||
// MSVC before 2010 doesn't have std::shared_ptr, but has std::tr1::shared_ptr, defined in <memory> included earlier
|
||||
#define SharedPtr std::tr1::shared_ptr
|
||||
#elif (__cplusplus >= 201103L)
|
||||
// C++11 has std::shared_ptr in <memory>, included earlier
|
||||
#define SharedPtr std::shared_ptr
|
||||
#else
|
||||
// C++03 has std::tr1::shared_ptr in <tr1/memory>
|
||||
#include <tr1/memory>
|
||||
#define SharedPtr std::tr1::shared_ptr
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@ -232,12 +246,6 @@ public:
|
||||
|
||||
|
||||
|
||||
#include "../../src/Crypto.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define LOGERROR printf
|
||||
#define LOGINFO printf
|
||||
#define LOGWARNING printf
|
||||
|
@ -20,7 +20,7 @@ You need to set the server *not* to verify usernames ("online-mode=false" in ser
|
||||
|
||||
|
||||
ProtoProxy is not much dependent on the protocol - it will work with unknown packets, it just won't parse them into human-readable format.
|
||||
The latest protocol which has been tested is 1.6.1 (#73).
|
||||
The latest protocol which has been tested is 1.7.9 (#5).
|
||||
|
||||
|
||||
*/
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PolarSSL++/RsaPrivateKey.h"
|
||||
|
||||
|
||||
|
||||
|
||||
@ -17,7 +19,7 @@
|
||||
class cServer
|
||||
{
|
||||
SOCKET m_ListenSocket;
|
||||
cRSAPrivateKey m_PrivateKey;
|
||||
cRsaPrivateKey m_PrivateKey;
|
||||
AString m_PublicKeyDER;
|
||||
short m_ConnectPort;
|
||||
|
||||
@ -27,7 +29,7 @@ public:
|
||||
int Init(short a_ListenPort, short a_ConnectPort);
|
||||
void Run(void);
|
||||
|
||||
cRSAPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
|
||||
cRsaPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
|
||||
const AString & GetPublicKeyDER (void) { return m_PublicKeyDER; }
|
||||
|
||||
short GetConnectPort(void) const { return m_ConnectPort; }
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 2cb1a0c4009ecf368ecc74eb428394e10f9e6d00
|
||||
Subproject commit 1ed82759c68f92c4acc7e3f33b850cf9f01c8aba
|
@ -1750,7 +1750,6 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
cLuaChunkStay * ChunkStay = new cLuaChunkStay(*Plugin);
|
||||
|
||||
// Read the params:
|
||||
cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, NULL);
|
||||
@ -1760,8 +1759,12 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S)
|
||||
L.LogStackTrace();
|
||||
return 0;
|
||||
}
|
||||
|
||||
cLuaChunkStay * ChunkStay = new cLuaChunkStay(*Plugin);
|
||||
|
||||
if (!ChunkStay->AddChunks(2))
|
||||
{
|
||||
delete ChunkStay;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1042,7 +1042,7 @@ bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Cha
|
||||
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGIN_MESSAGE];
|
||||
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
|
||||
{
|
||||
m_LuaState.Call((int)(**itr), &a_Client, a_Channel, a_Message);
|
||||
m_LuaState.Call((int)(**itr), &a_Client, a_Channel, a_Message, cLuaState::Return, res);
|
||||
if (res)
|
||||
{
|
||||
return true;
|
||||
|
180
src/BiomeDef.cpp
180
src/BiomeDef.cpp
@ -7,6 +7,88 @@
|
||||
#include "BiomeDef.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// The "map" used for biome <-> string conversions:
|
||||
static struct {
|
||||
EMCSBiome m_Biome;
|
||||
const char * m_String;
|
||||
} g_BiomeMap[] =
|
||||
{
|
||||
{biOcean, "Ocean"} ,
|
||||
{biPlains, "Plains"},
|
||||
{biDesert, "Desert"},
|
||||
{biExtremeHills, "ExtremeHills"},
|
||||
{biForest, "Forest"},
|
||||
{biTaiga, "Taiga"},
|
||||
{biSwampland, "Swampland"},
|
||||
{biRiver, "River"},
|
||||
{biNether, "Hell"},
|
||||
{biNether, "Nether"},
|
||||
{biEnd, "Sky"},
|
||||
{biEnd, "End"},
|
||||
{biFrozenOcean, "FrozenOcean"},
|
||||
{biFrozenRiver, "FrozenRiver"},
|
||||
{biIcePlains, "IcePlains"},
|
||||
{biIcePlains, "Tundra"},
|
||||
{biIceMountains, "IceMountains"},
|
||||
{biMushroomIsland, "MushroomIsland"},
|
||||
{biMushroomShore, "MushroomShore"},
|
||||
{biBeach, "Beach"},
|
||||
{biDesertHills, "DesertHills"},
|
||||
{biForestHills, "ForestHills"},
|
||||
{biTaigaHills, "TaigaHills"},
|
||||
{biExtremeHillsEdge, "ExtremeHillsEdge"},
|
||||
{biJungle, "Jungle"},
|
||||
{biJungleHills, "JungleHills"},
|
||||
|
||||
// Release 1.7 biomes:
|
||||
{biJungleEdge, "JungleEdge"},
|
||||
{biDeepOcean, "DeepOcean"},
|
||||
{biStoneBeach, "StoneBeach"},
|
||||
{biColdBeach, "ColdBeach"},
|
||||
{biBirchForest, "BirchForest"},
|
||||
{biBirchForestHills, "BirchForestHills"},
|
||||
{biRoofedForest, "RoofedForest"},
|
||||
{biColdTaiga, "ColdTaiga"},
|
||||
{biColdTaigaHills, "ColdTaigaHills"},
|
||||
{biMegaTaiga, "MegaTaiga"},
|
||||
{biMegaTaigaHills, "MegaTaigaHills"},
|
||||
{biExtremeHillsPlus, "ExtremeHillsPlus"},
|
||||
{biSavanna, "Savanna"},
|
||||
{biSavannaPlateau, "SavannaPlateau"},
|
||||
{biMesa, "Mesa"},
|
||||
{biMesaPlateauF, "MesaPlateauF"},
|
||||
{biMesaPlateau, "MesaPlateau"},
|
||||
|
||||
// Release 1.7 variants:
|
||||
{biSunflowerPlains, "SunflowerPlains"},
|
||||
{biDesertM, "DesertM"},
|
||||
{biExtremeHillsM, "ExtremeHillsM"},
|
||||
{biFlowerForest, "FlowerForest"},
|
||||
{biTaigaM, "TaigaM"},
|
||||
{biSwamplandM, "SwamplandM"},
|
||||
{biIcePlainsSpikes, "IcePlainsSpikes"},
|
||||
{biJungleM, "JungleM"},
|
||||
{biJungleEdgeM, "JungleEdgeM"},
|
||||
{biBirchForestM, "BirchForestM"},
|
||||
{biBirchForestHillsM, "BirchForestHillsM"},
|
||||
{biRoofedForestM, "RoofedForestM"},
|
||||
{biColdTaigaM, "ColdTaigaM"},
|
||||
{biMegaSpruceTaiga, "MegaSpruceTaiga"},
|
||||
{biMegaSpruceTaigaHills, "MegaSpruceTaigaHills"},
|
||||
{biExtremeHillsPlusM, "ExtremeHillsPlusM"},
|
||||
{biSavannaM, "SavannaM"},
|
||||
{biSavannaPlateauM, "SavannaPlateauM"},
|
||||
{biMesaBryce, "MesaBryce"},
|
||||
{biMesaPlateauFM, "MesaPlateauFM"},
|
||||
{biMesaPlateauM, "MesaPlateauM"},
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
EMCSBiome StringToBiome(const AString & a_BiomeString)
|
||||
{
|
||||
// If it is a number, return it:
|
||||
@ -25,87 +107,11 @@ EMCSBiome StringToBiome(const AString & a_BiomeString)
|
||||
return biInvalidBiome;
|
||||
}
|
||||
|
||||
// Convert using the built-in map:
|
||||
static struct {
|
||||
EMCSBiome m_Biome;
|
||||
const char * m_String;
|
||||
} BiomeMap[] =
|
||||
for (size_t i = 0; i < ARRAYCOUNT(g_BiomeMap); i++)
|
||||
{
|
||||
{biOcean, "Ocean"} ,
|
||||
{biPlains, "Plains"},
|
||||
{biDesert, "Desert"},
|
||||
{biExtremeHills, "ExtremeHills"},
|
||||
{biForest, "Forest"},
|
||||
{biTaiga, "Taiga"},
|
||||
{biSwampland, "Swampland"},
|
||||
{biRiver, "River"},
|
||||
{biNether, "Hell"},
|
||||
{biNether, "Nether"},
|
||||
{biEnd, "Sky"},
|
||||
{biEnd, "End"},
|
||||
{biFrozenOcean, "FrozenOcean"},
|
||||
{biFrozenRiver, "FrozenRiver"},
|
||||
{biIcePlains, "IcePlains"},
|
||||
{biIcePlains, "Tundra"},
|
||||
{biIceMountains, "IceMountains"},
|
||||
{biMushroomIsland, "MushroomIsland"},
|
||||
{biMushroomShore, "MushroomShore"},
|
||||
{biBeach, "Beach"},
|
||||
{biDesertHills, "DesertHills"},
|
||||
{biForestHills, "ForestHills"},
|
||||
{biTaigaHills, "TaigaHills"},
|
||||
{biExtremeHillsEdge, "ExtremeHillsEdge"},
|
||||
{biJungle, "Jungle"},
|
||||
{biJungleHills, "JungleHills"},
|
||||
|
||||
// Release 1.7 biomes:
|
||||
{biJungleEdge, "JungleEdge"},
|
||||
{biDeepOcean, "DeepOcean"},
|
||||
{biStoneBeach, "StoneBeach"},
|
||||
{biColdBeach, "ColdBeach"},
|
||||
{biBirchForest, "BirchForest"},
|
||||
{biBirchForestHills, "BirchForestHills"},
|
||||
{biRoofedForest, "RoofedForest"},
|
||||
{biColdTaiga, "ColdTaiga"},
|
||||
{biColdTaigaHills, "ColdTaigaHills"},
|
||||
{biMegaTaiga, "MegaTaiga"},
|
||||
{biMegaTaigaHills, "MegaTaigaHills"},
|
||||
{biExtremeHillsPlus, "ExtremeHillsPlus"},
|
||||
{biSavanna, "Savanna"},
|
||||
{biSavannaPlateau, "SavannaPlateau"},
|
||||
{biMesa, "Mesa"},
|
||||
{biMesaPlateauF, "MesaPlateauF"},
|
||||
{biMesaPlateau, "MesaPlateau"},
|
||||
|
||||
// Release 1.7 variants:
|
||||
{biSunflowerPlains, "SunflowerPlains"},
|
||||
{biDesertM, "DesertM"},
|
||||
{biExtremeHillsM, "ExtremeHillsM"},
|
||||
{biFlowerForest, "FlowerForest"},
|
||||
{biTaigaM, "TaigaM"},
|
||||
{biSwamplandM, "SwamplandM"},
|
||||
{biIcePlainsSpikes, "IcePlainsSpikes"},
|
||||
{biJungleM, "JungleM"},
|
||||
{biJungleEdgeM, "JungleEdgeM"},
|
||||
{biBirchForestM, "BirchForestM"},
|
||||
{biBirchForestHillsM, "BirchForestHillsM"},
|
||||
{biRoofedForestM, "RoofedForestM"},
|
||||
{biColdTaigaM, "ColdTaigaM"},
|
||||
{biMegaSpruceTaiga, "MegaSpruceTaiga"},
|
||||
{biMegaSpruceTaigaHills, "MegaSpruceTaigaHills"},
|
||||
{biExtremeHillsPlusM, "ExtremeHillsPlusM"},
|
||||
{biSavannaM, "SavannaM"},
|
||||
{biSavannaPlateauM, "SavannaPlateauM"},
|
||||
{biMesaBryce, "MesaBryce"},
|
||||
{biMesaPlateauFM, "MesaPlateauFM"},
|
||||
{biMesaPlateauM, "MesaPlateauM"},
|
||||
} ;
|
||||
|
||||
for (size_t i = 0; i < ARRAYCOUNT(BiomeMap); i++)
|
||||
{
|
||||
if (NoCaseCompare(BiomeMap[i].m_String, a_BiomeString) == 0)
|
||||
if (NoCaseCompare(g_BiomeMap[i].m_String, a_BiomeString) == 0)
|
||||
{
|
||||
return BiomeMap[i].m_Biome;
|
||||
return g_BiomeMap[i].m_Biome;
|
||||
}
|
||||
} // for i - BiomeMap[]
|
||||
return biInvalidBiome;
|
||||
@ -115,6 +121,22 @@ EMCSBiome StringToBiome(const AString & a_BiomeString)
|
||||
|
||||
|
||||
|
||||
AString BiomeToString(int a_Biome)
|
||||
{
|
||||
for (size_t i = 0; i < ARRAYCOUNT(g_BiomeMap); i++)
|
||||
{
|
||||
if (g_BiomeMap[i].m_Biome == a_Biome)
|
||||
{
|
||||
return g_BiomeMap[i].m_String;
|
||||
}
|
||||
}
|
||||
return AString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool IsBiomeNoDownfall(EMCSBiome a_Biome)
|
||||
{
|
||||
switch (a_Biome)
|
||||
|
@ -104,10 +104,13 @@ enum EMCSBiome
|
||||
biMaxVariantBiome = biNumVariantBiomes - 1, // The maximum biome value
|
||||
} ;
|
||||
|
||||
/// Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns biInvalidBiome on failure.
|
||||
/** Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns biInvalidBiome on failure. */
|
||||
extern EMCSBiome StringToBiome(const AString & a_BiomeString);
|
||||
|
||||
/// Returns true if the biome has no downfall - deserts and savannas
|
||||
/** Translates biome enum into biome string. Returns empty string on failure (unknown biome). */
|
||||
extern AString BiomeToString(int a_Biome);
|
||||
|
||||
/** Returns true if the biome has no downfall - deserts and savannas */
|
||||
extern bool IsBiomeNoDownfall(EMCSBiome a_Biome);
|
||||
|
||||
|
||||
|
@ -14,17 +14,29 @@
|
||||
|
||||
|
||||
|
||||
// Disable MSVC warnings: "conditional expression is constant"
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef void (CombinatorFunc)(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta);
|
||||
|
||||
// This wild construct allows us to pass a function argument and still have it inlined by the compiler :)
|
||||
/// Merges two blocktypes and blockmetas of the specified sizes and offsets using the specified combinator function
|
||||
template<typename Combinator> void InternalMergeBlocks(
|
||||
template<bool MetasValid, CombinatorFunc Combinator>
|
||||
void InternalMergeBlocks(
|
||||
BLOCKTYPE * a_DstTypes, const BLOCKTYPE * a_SrcTypes,
|
||||
NIBBLETYPE * a_DstMetas, const NIBBLETYPE * a_SrcMetas,
|
||||
int a_SizeX, int a_SizeY, int a_SizeZ,
|
||||
int a_SrcOffX, int a_SrcOffY, int a_SrcOffZ,
|
||||
int a_DstOffX, int a_DstOffY, int a_DstOffZ,
|
||||
int a_SrcSizeX, int a_SrcSizeY, int a_SrcSizeZ,
|
||||
int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ,
|
||||
Combinator a_Combinator
|
||||
int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ
|
||||
)
|
||||
{
|
||||
UNUSED(a_SrcSizeY);
|
||||
@ -41,7 +53,15 @@ template<typename Combinator> void InternalMergeBlocks(
|
||||
int DstIdx = DstBaseZ + a_DstOffX;
|
||||
for (int x = 0; x < a_SizeX; x++)
|
||||
{
|
||||
a_Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], a_DstMetas[DstIdx], a_SrcMetas[SrcIdx]);
|
||||
if (MetasValid)
|
||||
{
|
||||
Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], a_DstMetas[DstIdx], a_SrcMetas[SrcIdx]);
|
||||
}
|
||||
else
|
||||
{
|
||||
BLOCKTYPE FakeDestMeta = 0;
|
||||
Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], FakeDestMeta, (NIBBLETYPE)0);
|
||||
}
|
||||
++DstIdx;
|
||||
++SrcIdx;
|
||||
} // for x
|
||||
@ -54,10 +74,14 @@ template<typename Combinator> void InternalMergeBlocks(
|
||||
|
||||
|
||||
/// Combinator used for cBlockArea::msOverwrite merging
|
||||
static inline void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||
template<bool MetaValid>
|
||||
void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||
{
|
||||
a_DstType = a_SrcType;
|
||||
a_DstMeta = a_SrcMeta;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = a_SrcMeta;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -65,12 +89,16 @@ static inline void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_S
|
||||
|
||||
|
||||
/// Combinator used for cBlockArea::msFillAir merging
|
||||
static inline void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||
template<bool MetaValid>
|
||||
void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||
{
|
||||
if (a_DstType == E_BLOCK_AIR)
|
||||
{
|
||||
a_DstType = a_SrcType;
|
||||
a_DstMeta = a_SrcMeta;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = a_SrcMeta;
|
||||
}
|
||||
}
|
||||
// "else" is the default, already in place
|
||||
}
|
||||
@ -80,12 +108,16 @@ static inline void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_Src
|
||||
|
||||
|
||||
/// Combinator used for cBlockArea::msImprint merging
|
||||
static inline void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||
template<bool MetaValid>
|
||||
void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||
{
|
||||
if (a_SrcType != E_BLOCK_AIR)
|
||||
{
|
||||
a_DstType = a_SrcType;
|
||||
a_DstMeta = a_SrcMeta;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = a_SrcMeta;
|
||||
}
|
||||
}
|
||||
// "else" is the default, already in place
|
||||
}
|
||||
@ -95,7 +127,8 @@ static inline void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_Src
|
||||
|
||||
|
||||
/// Combinator used for cBlockArea::msLake merging
|
||||
static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||
template<bool MetaValid>
|
||||
void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||
{
|
||||
// Sponge is the NOP block
|
||||
if (a_SrcType == E_BLOCK_SPONGE)
|
||||
@ -107,7 +140,10 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp
|
||||
if (a_SrcType == E_BLOCK_AIR)
|
||||
{
|
||||
a_DstType = E_BLOCK_AIR;
|
||||
a_DstMeta = 0;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -132,7 +168,10 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp
|
||||
case E_BLOCK_STATIONARY_LAVA:
|
||||
{
|
||||
a_DstType = a_SrcType;
|
||||
a_DstMeta = a_SrcMeta;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = a_SrcMeta;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -146,7 +185,10 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp
|
||||
case E_BLOCK_MYCELIUM:
|
||||
{
|
||||
a_DstType = E_BLOCK_STONE;
|
||||
a_DstMeta = 0;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -159,13 +201,17 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp
|
||||
|
||||
|
||||
/** Combinator used for cBlockArea::msSpongePrint merging */
|
||||
static inline void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||
template<bool MetaValid>
|
||||
void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||
{
|
||||
// Sponge overwrites nothing, everything else overwrites anything
|
||||
if (a_SrcType != E_BLOCK_SPONGE)
|
||||
{
|
||||
a_DstType = a_SrcType;
|
||||
a_DstMeta = a_SrcMeta;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = a_SrcMeta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,17 +220,24 @@ static inline void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a
|
||||
|
||||
|
||||
/** Combinator used for cBlockArea::msDifference merging */
|
||||
static inline void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||
template<bool MetaValid>
|
||||
void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||
{
|
||||
if ((a_DstType == a_SrcType) && (a_DstMeta == a_SrcMeta))
|
||||
if ((a_DstType == a_SrcType) && (!MetaValid || (a_DstMeta == a_SrcMeta)))
|
||||
{
|
||||
a_DstType = E_BLOCK_AIR;
|
||||
a_DstMeta = 0;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
a_DstType = a_SrcType;
|
||||
a_DstMeta = a_SrcMeta;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = a_SrcMeta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,16 +246,25 @@ static inline void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_
|
||||
|
||||
|
||||
/** Combinator used for cBlockArea::msMask merging */
|
||||
static inline void MergeCombinatorMask(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||
template<bool MetaValid>
|
||||
void MergeCombinatorMask(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||
{
|
||||
// If the blocks are the same, keep the dest; otherwise replace with air
|
||||
if ((a_SrcType != a_DstType) || (a_SrcMeta != a_DstMeta))
|
||||
if ((a_SrcType != a_DstType) || !MetaValid || (a_SrcMeta != a_DstMeta))
|
||||
{
|
||||
a_DstType = E_BLOCK_AIR;
|
||||
a_DstMeta = 0;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Re-enable previously disabled MSVC warnings
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@ -484,7 +546,7 @@ void cBlockArea::CopyTo(cBlockArea & a_Into) const
|
||||
a_Into.Clear();
|
||||
a_Into.SetSize(m_Size.x, m_Size.y, m_Size.z, GetDataTypes());
|
||||
a_Into.m_Origin = m_Origin;
|
||||
int BlockCount = GetBlockCount();
|
||||
size_t BlockCount = GetBlockCount();
|
||||
if (HasBlockTypes())
|
||||
{
|
||||
memcpy(a_Into.m_BlockTypes, m_BlockTypes, BlockCount * sizeof(BLOCKTYPE));
|
||||
@ -532,7 +594,7 @@ void cBlockArea::DumpToRawFile(const AString & a_FileName)
|
||||
f.Write(&SizeZ, 4);
|
||||
unsigned char DataTypes = (unsigned char)GetDataTypes();
|
||||
f.Write(&DataTypes, 1);
|
||||
int NumBlocks = GetBlockCount();
|
||||
size_t NumBlocks = GetBlockCount();
|
||||
if (HasBlockTypes())
|
||||
{
|
||||
f.Write(m_BlockTypes, NumBlocks * sizeof(BLOCKTYPE));
|
||||
@ -637,155 +699,19 @@ void cBlockArea::Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMa
|
||||
|
||||
void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy)
|
||||
{
|
||||
// Block types are compulsory, block metas are voluntary
|
||||
if (!HasBlockTypes() || !a_Src.HasBlockTypes())
|
||||
{
|
||||
LOGWARNING("%s: cannot merge because one of the areas doesn't have blocktypes.", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
// Dst is *this, Src is a_Src
|
||||
int SrcOffX = std::max(0, -a_RelX); // Offset in Src where to start reading
|
||||
int DstOffX = std::max(0, a_RelX); // Offset in Dst where to start writing
|
||||
int SizeX = std::min(a_Src.GetSizeX() - SrcOffX, GetSizeX() - DstOffX); // How many blocks to copy
|
||||
|
||||
int SrcOffY = std::max(0, -a_RelY); // Offset in Src where to start reading
|
||||
int DstOffY = std::max(0, a_RelY); // Offset in Dst where to start writing
|
||||
int SizeY = std::min(a_Src.GetSizeY() - SrcOffY, GetSizeY() - DstOffY); // How many blocks to copy
|
||||
|
||||
int SrcOffZ = std::max(0, -a_RelZ); // Offset in Src where to start reading
|
||||
int DstOffZ = std::max(0, a_RelZ); // Offset in Dst where to start writing
|
||||
int SizeZ = std::min(a_Src.GetSizeZ() - SrcOffZ, GetSizeZ() - DstOffZ); // How many blocks to copy
|
||||
|
||||
const NIBBLETYPE * SrcMetas = a_Src.GetBlockMetas();
|
||||
NIBBLETYPE * DstMetas = m_BlockMetas;
|
||||
|
||||
bool IsDummyMetas = ((SrcMetas == NULL) || (DstMetas == NULL));
|
||||
|
||||
if (IsDummyMetas)
|
||||
{
|
||||
SrcMetas = new NIBBLETYPE[a_Src.GetBlockCount()];
|
||||
DstMetas = new NIBBLETYPE[GetBlockCount()];
|
||||
MergeByStrategy<true>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas);
|
||||
}
|
||||
|
||||
switch (a_Strategy)
|
||||
else
|
||||
{
|
||||
case msOverwrite:
|
||||
{
|
||||
InternalMergeBlocks(
|
||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||
DstMetas, SrcMetas,
|
||||
SizeX, SizeY, SizeZ,
|
||||
SrcOffX, SrcOffY, SrcOffZ,
|
||||
DstOffX, DstOffY, DstOffZ,
|
||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||
m_Size.x, m_Size.y, m_Size.z,
|
||||
MergeCombinatorOverwrite
|
||||
);
|
||||
break;
|
||||
} // case msOverwrite
|
||||
|
||||
case msFillAir:
|
||||
{
|
||||
InternalMergeBlocks(
|
||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||
DstMetas, SrcMetas,
|
||||
SizeX, SizeY, SizeZ,
|
||||
SrcOffX, SrcOffY, SrcOffZ,
|
||||
DstOffX, DstOffY, DstOffZ,
|
||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||
m_Size.x, m_Size.y, m_Size.z,
|
||||
MergeCombinatorFillAir
|
||||
);
|
||||
break;
|
||||
} // case msFillAir
|
||||
|
||||
case msImprint:
|
||||
{
|
||||
InternalMergeBlocks(
|
||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||
DstMetas, SrcMetas,
|
||||
SizeX, SizeY, SizeZ,
|
||||
SrcOffX, SrcOffY, SrcOffZ,
|
||||
DstOffX, DstOffY, DstOffZ,
|
||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||
m_Size.x, m_Size.y, m_Size.z,
|
||||
MergeCombinatorImprint
|
||||
);
|
||||
break;
|
||||
} // case msImprint
|
||||
|
||||
case msLake:
|
||||
{
|
||||
InternalMergeBlocks(
|
||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||
DstMetas, SrcMetas,
|
||||
SizeX, SizeY, SizeZ,
|
||||
SrcOffX, SrcOffY, SrcOffZ,
|
||||
DstOffX, DstOffY, DstOffZ,
|
||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||
m_Size.x, m_Size.y, m_Size.z,
|
||||
MergeCombinatorLake
|
||||
);
|
||||
break;
|
||||
} // case msLake
|
||||
|
||||
case msSpongePrint:
|
||||
{
|
||||
InternalMergeBlocks(
|
||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||
DstMetas, SrcMetas,
|
||||
SizeX, SizeY, SizeZ,
|
||||
SrcOffX, SrcOffY, SrcOffZ,
|
||||
DstOffX, DstOffY, DstOffZ,
|
||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||
m_Size.x, m_Size.y, m_Size.z,
|
||||
MergeCombinatorSpongePrint
|
||||
);
|
||||
break;
|
||||
} // case msSpongePrint
|
||||
|
||||
case msDifference:
|
||||
{
|
||||
InternalMergeBlocks(
|
||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||
DstMetas, SrcMetas,
|
||||
SizeX, SizeY, SizeZ,
|
||||
SrcOffX, SrcOffY, SrcOffZ,
|
||||
DstOffX, DstOffY, DstOffZ,
|
||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||
m_Size.x, m_Size.y, m_Size.z,
|
||||
MergeCombinatorDifference
|
||||
);
|
||||
break;
|
||||
} // case msDifference
|
||||
|
||||
case msMask:
|
||||
{
|
||||
InternalMergeBlocks(
|
||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||
DstMetas, SrcMetas,
|
||||
SizeX, SizeY, SizeZ,
|
||||
SrcOffX, SrcOffY, SrcOffZ,
|
||||
DstOffX, DstOffY, DstOffZ,
|
||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||
m_Size.x, m_Size.y, m_Size.z,
|
||||
MergeCombinatorMask
|
||||
);
|
||||
break;
|
||||
} // case msMask
|
||||
|
||||
default:
|
||||
{
|
||||
LOGWARNING("Unknown block area merge strategy: %d", a_Strategy);
|
||||
ASSERT(!"Unknown block area merge strategy");
|
||||
break;
|
||||
}
|
||||
} // switch (a_Strategy)
|
||||
|
||||
if (IsDummyMetas)
|
||||
{
|
||||
delete[] SrcMetas;
|
||||
delete[] DstMetas;
|
||||
MergeByStrategy<false>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2051,7 +1977,7 @@ void cBlockArea::ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, i
|
||||
int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX;
|
||||
int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
|
||||
int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ;
|
||||
int BlockCount = NewSizeX * NewSizeY * NewSizeZ;
|
||||
size_t BlockCount = (size_t)NewSizeX * NewSizeY * NewSizeZ;
|
||||
BLOCKTYPE * NewBlockTypes = new BLOCKTYPE[BlockCount];
|
||||
memset(NewBlockTypes, 0, BlockCount * sizeof(BLOCKTYPE));
|
||||
int OldIndex = 0;
|
||||
@ -2081,7 +2007,7 @@ void cBlockArea::ExpandNibbles(NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMa
|
||||
int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX;
|
||||
int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
|
||||
int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ;
|
||||
int BlockCount = NewSizeX * NewSizeY * NewSizeZ;
|
||||
size_t BlockCount = (size_t)NewSizeX * NewSizeY * NewSizeZ;
|
||||
NIBBLETYPE * NewNibbles = new NIBBLETYPE[BlockCount];
|
||||
memset(NewNibbles, 0, BlockCount * sizeof(NIBBLETYPE));
|
||||
int OldIndex = 0;
|
||||
@ -2133,4 +2059,137 @@ void cBlockArea::RelSetData(
|
||||
|
||||
|
||||
|
||||
template<bool MetasValid>
|
||||
void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE * SrcMetas, NIBBLETYPE * DstMetas)
|
||||
{
|
||||
// Block types are compulsory, block metas are voluntary
|
||||
if (!HasBlockTypes() || !a_Src.HasBlockTypes())
|
||||
{
|
||||
LOGWARNING("%s: cannot merge because one of the areas doesn't have blocktypes.", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
// Dst is *this, Src is a_Src
|
||||
int SrcOffX = std::max(0, -a_RelX); // Offset in Src where to start reading
|
||||
int DstOffX = std::max(0, a_RelX); // Offset in Dst where to start writing
|
||||
int SizeX = std::min(a_Src.GetSizeX() - SrcOffX, GetSizeX() - DstOffX); // How many blocks to copy
|
||||
|
||||
int SrcOffY = std::max(0, -a_RelY); // Offset in Src where to start reading
|
||||
int DstOffY = std::max(0, a_RelY); // Offset in Dst where to start writing
|
||||
int SizeY = std::min(a_Src.GetSizeY() - SrcOffY, GetSizeY() - DstOffY); // How many blocks to copy
|
||||
|
||||
int SrcOffZ = std::max(0, -a_RelZ); // Offset in Src where to start reading
|
||||
int DstOffZ = std::max(0, a_RelZ); // Offset in Dst where to start writing
|
||||
int SizeZ = std::min(a_Src.GetSizeZ() - SrcOffZ, GetSizeZ() - DstOffZ); // How many blocks to copy
|
||||
|
||||
switch (a_Strategy)
|
||||
{
|
||||
case cBlockArea::msOverwrite:
|
||||
{
|
||||
InternalMergeBlocks<MetasValid, MergeCombinatorOverwrite<MetasValid> >(
|
||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||
DstMetas, SrcMetas,
|
||||
SizeX, SizeY, SizeZ,
|
||||
SrcOffX, SrcOffY, SrcOffZ,
|
||||
DstOffX, DstOffY, DstOffZ,
|
||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||
m_Size.x, m_Size.y, m_Size.z
|
||||
);
|
||||
break;
|
||||
} // case msOverwrite
|
||||
|
||||
case cBlockArea::msFillAir:
|
||||
{
|
||||
InternalMergeBlocks<MetasValid, MergeCombinatorFillAir<MetasValid> >(
|
||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||
DstMetas, SrcMetas,
|
||||
SizeX, SizeY, SizeZ,
|
||||
SrcOffX, SrcOffY, SrcOffZ,
|
||||
DstOffX, DstOffY, DstOffZ,
|
||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||
m_Size.x, m_Size.y, m_Size.z
|
||||
);
|
||||
break;
|
||||
} // case msFillAir
|
||||
|
||||
case cBlockArea::msImprint:
|
||||
{
|
||||
InternalMergeBlocks<MetasValid, MergeCombinatorImprint<MetasValid> >(
|
||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||
DstMetas, SrcMetas,
|
||||
SizeX, SizeY, SizeZ,
|
||||
SrcOffX, SrcOffY, SrcOffZ,
|
||||
DstOffX, DstOffY, DstOffZ,
|
||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||
m_Size.x, m_Size.y, m_Size.z
|
||||
);
|
||||
break;
|
||||
} // case msImprint
|
||||
|
||||
case cBlockArea::msLake:
|
||||
{
|
||||
InternalMergeBlocks<MetasValid, MergeCombinatorLake<MetasValid> >(
|
||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||
DstMetas, SrcMetas,
|
||||
SizeX, SizeY, SizeZ,
|
||||
SrcOffX, SrcOffY, SrcOffZ,
|
||||
DstOffX, DstOffY, DstOffZ,
|
||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||
m_Size.x, m_Size.y, m_Size.z
|
||||
);
|
||||
break;
|
||||
} // case msLake
|
||||
|
||||
case cBlockArea::msSpongePrint:
|
||||
{
|
||||
InternalMergeBlocks<MetasValid, MergeCombinatorSpongePrint<MetasValid> >(
|
||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||
DstMetas, SrcMetas,
|
||||
SizeX, SizeY, SizeZ,
|
||||
SrcOffX, SrcOffY, SrcOffZ,
|
||||
DstOffX, DstOffY, DstOffZ,
|
||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||
m_Size.x, m_Size.y, m_Size.z
|
||||
);
|
||||
break;
|
||||
} // case msSpongePrint
|
||||
|
||||
case cBlockArea::msDifference:
|
||||
{
|
||||
InternalMergeBlocks<MetasValid, MergeCombinatorDifference<MetasValid> >(
|
||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||
DstMetas, SrcMetas,
|
||||
SizeX, SizeY, SizeZ,
|
||||
SrcOffX, SrcOffY, SrcOffZ,
|
||||
DstOffX, DstOffY, DstOffZ,
|
||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||
m_Size.x, m_Size.y, m_Size.z
|
||||
);
|
||||
break;
|
||||
} // case msDifference
|
||||
|
||||
case cBlockArea::msMask:
|
||||
{
|
||||
InternalMergeBlocks<MetasValid, MergeCombinatorMask<MetasValid> >(
|
||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||
DstMetas, SrcMetas,
|
||||
SizeX, SizeY, SizeZ,
|
||||
SrcOffX, SrcOffY, SrcOffZ,
|
||||
DstOffX, DstOffY, DstOffZ,
|
||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||
m_Size.x, m_Size.y, m_Size.z
|
||||
);
|
||||
break;
|
||||
} // case msMask
|
||||
|
||||
default:
|
||||
{
|
||||
LOGWARNING("Unknown block area merge strategy: %d", a_Strategy);
|
||||
ASSERT(!"Unknown block area merge strategy");
|
||||
break;
|
||||
}
|
||||
} // switch (a_Strategy)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -294,7 +294,7 @@ public:
|
||||
NIBBLETYPE * GetBlockMetas (void) const { return m_BlockMetas; } // NOTE: one byte per block!
|
||||
NIBBLETYPE * GetBlockLight (void) const { return m_BlockLight; } // NOTE: one byte per block!
|
||||
NIBBLETYPE * GetBlockSkyLight(void) const { return m_BlockSkyLight; } // NOTE: one byte per block!
|
||||
int GetBlockCount(void) const { return m_Size.x * m_Size.y * m_Size.z; }
|
||||
size_t GetBlockCount(void) const { return m_Size.x * m_Size.y * m_Size.z; }
|
||||
int MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const;
|
||||
|
||||
protected:
|
||||
@ -360,6 +360,9 @@ protected:
|
||||
int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
|
||||
NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight
|
||||
);
|
||||
|
||||
template<bool MetasValid>
|
||||
void MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE * SrcMetas, NIBBLETYPE * DstMetas);
|
||||
// tolua_begin
|
||||
} ;
|
||||
// tolua_end
|
||||
|
@ -21,7 +21,8 @@
|
||||
cCommandBlockEntity::cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World) :
|
||||
super(E_BLOCK_COMMAND_BLOCK, a_X, a_Y, a_Z, a_World),
|
||||
m_ShouldExecute(false),
|
||||
m_IsPowered(false)
|
||||
m_IsPowered(false),
|
||||
m_Result(0)
|
||||
{}
|
||||
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
cMobHeadEntity::cMobHeadEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
|
||||
super(E_BLOCK_HEAD, a_BlockX, a_BlockY, a_BlockZ, a_World),
|
||||
m_Type(SKULL_TYPE_SKELETON),
|
||||
m_Rotation(SKULL_ROTATION_NORTH),
|
||||
m_Owner("")
|
||||
{
|
||||
}
|
||||
|
@ -324,7 +324,7 @@ eDimension StringToDimension(const AString & a_DimensionString)
|
||||
{ dimOverworld, "Normal"},
|
||||
{ dimOverworld, "World"},
|
||||
{ dimNether, "Nether"},
|
||||
{ dimNether, "Hell"}, // Alternate name for End
|
||||
{ dimNether, "Hell"}, // Alternate name for Nether
|
||||
{ dimEnd, "End"},
|
||||
{ dimEnd, "Sky"}, // Old name for End
|
||||
} ;
|
||||
@ -337,7 +337,8 @@ eDimension StringToDimension(const AString & a_DimensionString)
|
||||
} // for i - DimensionMap[]
|
||||
|
||||
// Not found
|
||||
return (eDimension)-1000;
|
||||
LOGWARNING("Unknown dimension: \"%s\". Setting to Overworld", a_DimensionString.c_str());
|
||||
return dimOverworld;
|
||||
}
|
||||
|
||||
|
||||
|
@ -129,6 +129,7 @@ void cBlockInfo::Initialize(void)
|
||||
ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_Transparent = true;
|
||||
ms_Info[E_BLOCK_ICE ].m_Transparent = true;
|
||||
ms_Info[E_BLOCK_IRON_DOOR ].m_Transparent = true;
|
||||
ms_Info[E_BLOCK_LADDER ].m_Transparent = true;
|
||||
ms_Info[E_BLOCK_LAVA ].m_Transparent = true;
|
||||
ms_Info[E_BLOCK_LEAVES ].m_Transparent = true;
|
||||
ms_Info[E_BLOCK_LEVER ].m_Transparent = true;
|
||||
|
@ -171,7 +171,7 @@ cByteBuffer::~cByteBuffer()
|
||||
|
||||
|
||||
|
||||
bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
|
||||
bool cByteBuffer::Write(const void * a_Bytes, size_t a_Count)
|
||||
{
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
@ -187,13 +187,14 @@ bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
|
||||
}
|
||||
ASSERT(m_BufferSize >= m_WritePos);
|
||||
size_t TillEnd = m_BufferSize - m_WritePos;
|
||||
const char * Bytes = (const char *)a_Bytes;
|
||||
if (TillEnd <= a_Count)
|
||||
{
|
||||
// Need to wrap around the ringbuffer end
|
||||
if (TillEnd > 0)
|
||||
{
|
||||
memcpy(m_Buffer + m_WritePos, a_Bytes, TillEnd);
|
||||
a_Bytes += TillEnd;
|
||||
memcpy(m_Buffer + m_WritePos, Bytes, TillEnd);
|
||||
Bytes += TillEnd;
|
||||
a_Count -= TillEnd;
|
||||
WrittenBytes = TillEnd;
|
||||
}
|
||||
@ -203,7 +204,7 @@ bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
|
||||
// We're guaranteed that we'll fit in a single write op
|
||||
if (a_Count > 0)
|
||||
{
|
||||
memcpy(m_Buffer + m_WritePos, a_Bytes, a_Count);
|
||||
memcpy(m_Buffer + m_WritePos, Bytes, a_Count);
|
||||
m_WritePos += a_Count;
|
||||
WrittenBytes += a_Count;
|
||||
}
|
||||
@ -887,9 +888,7 @@ void cByteBuffer::AdvanceReadPos(size_t a_Count)
|
||||
|
||||
void cByteBuffer::CheckValid(void) const
|
||||
{
|
||||
ASSERT(m_ReadPos >= 0);
|
||||
ASSERT(m_ReadPos < m_BufferSize);
|
||||
ASSERT(m_WritePos >= 0);
|
||||
ASSERT(m_WritePos < m_BufferSize);
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
~cByteBuffer();
|
||||
|
||||
/// Writes the bytes specified to the ringbuffer. Returns true if successful, false if not
|
||||
bool Write(const char * a_Bytes, size_t a_Count);
|
||||
bool Write(const void * a_Bytes, size_t a_Count);
|
||||
|
||||
/// Returns the number of bytes that can be successfully written to the ringbuffer
|
||||
size_t GetFreeSpace(void) const;
|
||||
|
@ -5,7 +5,7 @@ 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 OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++)
|
||||
set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities Generating/Prefabs)
|
||||
|
||||
|
||||
@ -57,6 +57,14 @@ if (NOT MSVC)
|
||||
Entities/Pickup.h
|
||||
Entities/Player.h
|
||||
Entities/ProjectileEntity.h
|
||||
Entities/ArrowEntity.h
|
||||
Entities/ThrownEggEntity.h
|
||||
Entities/ThrownEnderPearlEntity.h
|
||||
Entities/ExpBottleEntity.h
|
||||
Entities/ThrownSnowballEntity.h
|
||||
Entities/FireChargeEntity.h
|
||||
Entities/FireworkEntity.h
|
||||
Entities/GhastFireballEntity.h
|
||||
Entities/TNTEntity.h
|
||||
Entities/ExpOrb.h
|
||||
Entities/HangingEntity.h
|
||||
@ -234,7 +242,7 @@ endif ()
|
||||
if (NOT MSVC)
|
||||
target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks)
|
||||
target_link_libraries(${EXECUTABLE} Protocol Generating Generating_Prefabs WorldStorage)
|
||||
target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities)
|
||||
target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities PolarSSL++)
|
||||
endif ()
|
||||
if (WIN32)
|
||||
target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib)
|
||||
|
@ -246,8 +246,8 @@ public:
|
||||
{
|
||||
if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1))
|
||||
{
|
||||
int Index = MakeIndexNoCheck(x, y, z);
|
||||
if ((size_t)(Index / 2) >= a_Buffer.size())
|
||||
size_t Index = (size_t)MakeIndexNoCheck(x, y, z);
|
||||
if ((Index / 2) >= a_Buffer.size())
|
||||
{
|
||||
return (a_IsSkyLightNibble ? 0xff : 0);
|
||||
}
|
||||
@ -281,7 +281,7 @@ public:
|
||||
{
|
||||
a_Buffer.resize((size_t)((a_BlockIdx / 2) + 1));
|
||||
}
|
||||
a_Buffer[(size_t)(a_BlockIdx / 2)] = PackNibble(a_Buffer, a_BlockIdx, a_Nibble);
|
||||
a_Buffer[(size_t)(a_BlockIdx / 2)] = PackNibble(a_Buffer, (size_t)a_BlockIdx, a_Nibble);
|
||||
}
|
||||
|
||||
|
||||
@ -297,19 +297,19 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
int Index = MakeIndexNoCheck(x, y, z);
|
||||
if ((size_t)(Index / 2) >= a_Buffer.size())
|
||||
size_t Index = (size_t)MakeIndexNoCheck(x, y, z);
|
||||
if ((Index / 2) >= a_Buffer.size())
|
||||
{
|
||||
a_Buffer.resize((size_t)((Index / 2) + 1));
|
||||
a_Buffer.resize(((Index / 2) + 1));
|
||||
}
|
||||
a_Buffer[(size_t)(Index / 2)] = PackNibble(a_Buffer, Index, a_Nibble);
|
||||
a_Buffer[(Index / 2)] = PackNibble(a_Buffer, Index, a_Nibble);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
inline static NIBBLETYPE PackNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int a_Index, NIBBLETYPE a_Nibble)
|
||||
inline static NIBBLETYPE PackNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, size_t a_Index, NIBBLETYPE a_Nibble)
|
||||
{
|
||||
return static_cast<NIBBLETYPE>(
|
||||
(a_Buffer[a_Index / 2] & (0xf0 >> ((a_Index & 1) * 4))) | // The untouched nibble
|
||||
@ -318,7 +318,7 @@ private:
|
||||
}
|
||||
|
||||
|
||||
inline static NIBBLETYPE ExpandNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int a_Index)
|
||||
inline static NIBBLETYPE ExpandNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, size_t a_Index)
|
||||
{
|
||||
return (a_Buffer[a_Index / 2] >> ((a_Index & 1) * 4)) & 0x0f;
|
||||
}
|
||||
|
@ -343,9 +343,8 @@ void cChunkMap::BroadcastAttachEntity(const cEntity & a_Entity, const cEntity *
|
||||
void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
int x, y, z, ChunkX, ChunkZ;
|
||||
int x, z, ChunkX, ChunkZ;
|
||||
x = a_BlockX;
|
||||
y = a_BlockY;
|
||||
z = a_BlockZ;
|
||||
cChunkDef::BlockToChunk(x, z, ChunkX, ChunkZ);
|
||||
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
|
||||
@ -1143,9 +1142,8 @@ BLOCKTYPE cChunkMap::GetBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
// First check if it isn't queued in the m_FastSetBlockQueue:
|
||||
{
|
||||
int X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
|
||||
int ChunkX, ChunkY, ChunkZ;
|
||||
int ChunkX, ChunkZ;
|
||||
cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ);
|
||||
ChunkY = 0;
|
||||
cCSLock Lock(m_CSFastSetBlock);
|
||||
for (sSetBlockList::iterator itr = m_FastSetBlockQueue.begin(); itr != m_FastSetBlockQueue.end(); ++itr)
|
||||
{
|
||||
@ -1652,7 +1650,10 @@ void cChunkMap::AddEntity(cEntity * a_Entity)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ());
|
||||
if ((Chunk == NULL) || !Chunk->IsValid())
|
||||
if (
|
||||
(Chunk == NULL) || // Chunk not present at all
|
||||
(!Chunk->IsValid() && !a_Entity->IsPlayer()) // Chunk present, but no valid data; players need to spawn in such chunks (#953)
|
||||
)
|
||||
{
|
||||
LOGWARNING("Entity at %p (%s, ID %d) spawning in a non-existent chunk, the entity is lost.",
|
||||
a_Entity, a_Entity->GetClass(), a_Entity->GetUniqueID()
|
||||
|
@ -186,6 +186,51 @@ void cClientHandle::GenerateOfflineUUID(void)
|
||||
|
||||
|
||||
|
||||
AString cClientHandle::FormatChatPrefix(bool ShouldAppendChatPrefixes, AString a_ChatPrefixS, AString m_Color1, AString m_Color2)
|
||||
{
|
||||
if (ShouldAppendChatPrefixes)
|
||||
return Printf("%s[%s] %s", m_Color1.c_str(), a_ChatPrefixS.c_str(), m_Color2.c_str());
|
||||
else
|
||||
return Printf("%s", m_Color1.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AString cClientHandle::FormatMessageType(bool ShouldAppendChatPrefixes, eMessageType a_ChatPrefix, const AString &a_AdditionalData)
|
||||
{
|
||||
switch (a_ChatPrefix)
|
||||
{
|
||||
case mtCustom: return AString();
|
||||
case mtFailure: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Rose, cChatColor::White);
|
||||
case mtInformation: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Yellow, cChatColor::White);
|
||||
case mtSuccess: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Green, cChatColor::White);
|
||||
case mtWarning: return FormatChatPrefix(ShouldAppendChatPrefixes, "WARN", cChatColor::Rose, cChatColor::White);
|
||||
case mtFatal: return FormatChatPrefix(ShouldAppendChatPrefixes, "FATAL", cChatColor::Red, cChatColor::White);
|
||||
case mtDeath: return FormatChatPrefix(ShouldAppendChatPrefixes, "DEATH", cChatColor::Gray, cChatColor::White);
|
||||
case mtJoin: return FormatChatPrefix(ShouldAppendChatPrefixes, "JOIN", cChatColor::Yellow, cChatColor::White);
|
||||
case mtLeave: return FormatChatPrefix(ShouldAppendChatPrefixes, "LEAVE", cChatColor::Yellow, cChatColor::White);
|
||||
case mtPrivateMessage:
|
||||
{
|
||||
if (ShouldAppendChatPrefixes)
|
||||
{
|
||||
return Printf("%s[MSG: %s] %s%s", cChatColor::LightBlue.c_str(), a_AdditionalData.c_str(), cChatColor::White.c_str(), cChatColor::Italic.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
return Printf("%s: %s", a_AdditionalData.c_str(), cChatColor::LightBlue.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT(!"Unhandled chat prefix type!");
|
||||
return AString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AString cClientHandle::GenerateOfflineUUID(const AString & a_Username)
|
||||
{
|
||||
// Proper format for a version 3 UUID is:
|
||||
@ -291,6 +336,11 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID)
|
||||
|
||||
// Send scoreboard data
|
||||
World->GetScoreBoard().SendTo(*this);
|
||||
|
||||
// Delay the first ping until the client "settles down"
|
||||
// This should fix #889, "BadCast exception, cannot convert bit to fm" error in client
|
||||
cTimer t1;
|
||||
m_LastPingTime = t1.GetNowTime() + 3000; // Send the first KeepAlive packet in 3 seconds
|
||||
|
||||
cRoot::Get()->GetPluginManager()->CallHookPlayerSpawned(*m_Player);
|
||||
}
|
||||
@ -1849,7 +1899,7 @@ void cClientHandle::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlock
|
||||
void cClientHandle::SendChat(const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData)
|
||||
{
|
||||
bool ShouldAppendChatPrefixes = true;
|
||||
|
||||
|
||||
if (GetPlayer()->GetWorld() == NULL)
|
||||
{
|
||||
cWorld * World = cRoot::Get()->GetWorld(GetPlayer()->GetLoadedWorldName());
|
||||
@ -1868,89 +1918,9 @@ void cClientHandle::SendChat(const AString & a_Message, eMessageType a_ChatPrefi
|
||||
ShouldAppendChatPrefixes = false;
|
||||
}
|
||||
|
||||
AString Message;
|
||||
AString Message = FormatMessageType(ShouldAppendChatPrefixes, a_ChatPrefix, a_AdditionalData);
|
||||
|
||||
switch (a_ChatPrefix)
|
||||
{
|
||||
case mtCustom: break;
|
||||
case mtFailure:
|
||||
{
|
||||
if (ShouldAppendChatPrefixes)
|
||||
Message = Printf("%s[INFO] %s", cChatColor::Rose.c_str(), cChatColor::White.c_str());
|
||||
else
|
||||
Message = Printf("%s", cChatColor::Rose.c_str());
|
||||
break;
|
||||
}
|
||||
case mtInformation:
|
||||
{
|
||||
if (ShouldAppendChatPrefixes)
|
||||
Message = Printf("%s[INFO] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str());
|
||||
else
|
||||
Message = Printf("%s", cChatColor::Yellow.c_str());
|
||||
break;
|
||||
}
|
||||
case mtSuccess:
|
||||
{
|
||||
if (ShouldAppendChatPrefixes)
|
||||
Message = Printf("%s[INFO] %s", cChatColor::Green.c_str(), cChatColor::White.c_str());
|
||||
else
|
||||
Message = Printf("%s", cChatColor::Green.c_str());
|
||||
break;
|
||||
}
|
||||
case mtWarning:
|
||||
{
|
||||
if (ShouldAppendChatPrefixes)
|
||||
Message = Printf("%s[WARN] %s", cChatColor::Rose.c_str(), cChatColor::White.c_str());
|
||||
else
|
||||
Message = Printf("%s", cChatColor::Rose.c_str());
|
||||
break;
|
||||
}
|
||||
case mtFatal:
|
||||
{
|
||||
if (ShouldAppendChatPrefixes)
|
||||
Message = Printf("%s[FATAL] %s", cChatColor::Red.c_str(), cChatColor::White.c_str());
|
||||
else
|
||||
Message = Printf("%s", cChatColor::Red.c_str());
|
||||
break;
|
||||
}
|
||||
case mtDeath:
|
||||
{
|
||||
if (ShouldAppendChatPrefixes)
|
||||
Message = Printf("%s[DEATH] %s", cChatColor::Gray.c_str(), cChatColor::White.c_str());
|
||||
else
|
||||
Message = Printf("%s", cChatColor::Gray.c_str());
|
||||
break;
|
||||
}
|
||||
case mtPrivateMessage:
|
||||
{
|
||||
if (ShouldAppendChatPrefixes)
|
||||
Message = Printf("%s[MSG: %s] %s%s", cChatColor::LightBlue.c_str(), a_AdditionalData.c_str(), cChatColor::White.c_str(), cChatColor::Italic.c_str());
|
||||
else
|
||||
Message = Printf("%s: %s", a_AdditionalData.c_str(), cChatColor::LightBlue.c_str());
|
||||
break;
|
||||
}
|
||||
case mtJoin:
|
||||
{
|
||||
if (ShouldAppendChatPrefixes)
|
||||
Message = Printf("%s[JOIN] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str());
|
||||
else
|
||||
Message = Printf("%s", cChatColor::Yellow.c_str());
|
||||
break;
|
||||
}
|
||||
case mtLeave:
|
||||
{
|
||||
if (ShouldAppendChatPrefixes)
|
||||
Message = Printf("%s[LEAVE] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str());
|
||||
else
|
||||
Message = Printf("%s", cChatColor::Yellow.c_str());
|
||||
break;
|
||||
}
|
||||
default: ASSERT(!"Unhandled chat prefix type!"); return;
|
||||
}
|
||||
|
||||
Message.append(a_Message);
|
||||
|
||||
m_Protocol->SendChat(Message);
|
||||
m_Protocol->SendChat(Message.append(a_Message));
|
||||
}
|
||||
|
||||
|
||||
|
@ -77,6 +77,11 @@ public:
|
||||
This is used for the offline (non-auth) mode, when there's no UUID source.
|
||||
Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. */
|
||||
static AString GenerateOfflineUUID(const AString & a_Username); // tolua_export
|
||||
|
||||
/** Formats the type of message with the proper color and prefix for sending to the client. **/
|
||||
AString FormatMessageType(bool ShouldAppendChatPrefixes, eMessageType a_ChatPrefix, const AString & a_AdditionalData);
|
||||
|
||||
AString FormatChatPrefix(bool ShouldAppendChatPrefixes, AString a_ChatPrefixS, AString m_Color1, AString m_Color2);
|
||||
|
||||
void Kick(const AString & a_Reason); // tolua_export
|
||||
void Authenticate(const AString & a_Name, const AString & a_UUID); // Called by cAuthenticator when the user passes authentication
|
||||
|
509
src/Crypto.cpp
509
src/Crypto.cpp
@ -1,509 +0,0 @@
|
||||
|
||||
// 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;
|
||||
}
|
||||
int res = rsa_pkcs1_encrypt(
|
||||
&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PRIVATE,
|
||||
a_PlainLength, a_PlainData, a_EncryptedData
|
||||
);
|
||||
if (res != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return (int)m_Rsa.len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cPublicKey:
|
||||
|
||||
cPublicKey::cPublicKey(const AString & a_PublicKeyDER)
|
||||
{
|
||||
pk_init(&m_Pk);
|
||||
if (pk_parse_public_key(&m_Pk, (const Byte *)a_PublicKeyDER.data(), a_PublicKeyDER.size()) != 0)
|
||||
{
|
||||
ASSERT(!"Cannot parse PubKey");
|
||||
return;
|
||||
}
|
||||
InitRnd();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cPublicKey::~cPublicKey()
|
||||
{
|
||||
pk_free(&m_Pk);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cPublicKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
|
||||
{
|
||||
size_t DecryptedLen = a_DecryptedMaxLength;
|
||||
int res = pk_decrypt(&m_Pk,
|
||||
a_EncryptedData, a_EncryptedLength,
|
||||
a_DecryptedData, &DecryptedLen, a_DecryptedMaxLength,
|
||||
ctr_drbg_random, &m_Ctr_drbg
|
||||
);
|
||||
if (res != 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
return (int)DecryptedLen;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cPublicKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
|
||||
{
|
||||
size_t EncryptedLength = a_EncryptedMaxLength;
|
||||
int res = pk_encrypt(&m_Pk,
|
||||
a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength,
|
||||
ctr_drbg_random, &m_Ctr_drbg
|
||||
);
|
||||
if (res != 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
return (int)EncryptedLength;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPublicKey::InitRnd(void)
|
||||
{
|
||||
entropy_init(&m_Entropy);
|
||||
const unsigned char pers[] = "rsa_genkey";
|
||||
ctr_drbg_init(&m_Ctr_drbg, entropy_func, &m_Entropy, pers, sizeof(pers) - 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cAESCFBDecryptor:
|
||||
|
||||
cAESCFBDecryptor::cAESCFBDecryptor(void) :
|
||||
m_IVOffset(0),
|
||||
m_IsValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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_IVOffset(0),
|
||||
m_IsValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
198
src/Crypto.h
198
src/Crypto.h
@ -1,198 +0,0 @@
|
||||
|
||||
// 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"
|
||||
#include "polarssl/pk.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);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cPublicKey
|
||||
{
|
||||
public:
|
||||
cPublicKey(const AString & a_PublicKeyDER);
|
||||
~cPublicKey();
|
||||
|
||||
/** Decrypts the data using the stored public key
|
||||
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
||||
Returns the number of bytes decrypted, or negative number for error. */
|
||||
int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
|
||||
|
||||
/** Encrypts the data using the stored public key
|
||||
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
||||
Returns the number of bytes decrypted, or negative number for error. */
|
||||
int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength);
|
||||
|
||||
protected:
|
||||
pk_context m_Pk;
|
||||
entropy_context m_Entropy;
|
||||
ctr_drbg_context m_Ctr_drbg;
|
||||
|
||||
/** Initializes the m_Entropy and m_Ctr_drbg contexts
|
||||
Common part of this object's construction, called from all constructors. */
|
||||
void InitRnd(void);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Decrypts data using the AES / CFB (128) algorithm */
|
||||
class cAESCFBDecryptor
|
||||
{
|
||||
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:
|
||||
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;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
193
src/Entities/ArrowEntity.cpp
Normal file
193
src/Entities/ArrowEntity.cpp
Normal file
@ -0,0 +1,193 @@
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "Player.h"
|
||||
#include "ArrowEntity.h"
|
||||
#include "../Chunk.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5),
|
||||
m_PickupState(psNoPickup),
|
||||
m_DamageCoeff(2),
|
||||
m_IsCritical(false),
|
||||
m_Timer(0),
|
||||
m_HitGroundTimer(0),
|
||||
m_bIsCollected(false),
|
||||
m_HitBlockPos(Vector3i(0, 0, 0))
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
SetMass(0.1);
|
||||
SetYawFromSpeed();
|
||||
SetPitchFromSpeed();
|
||||
LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}",
|
||||
m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(),
|
||||
GetYaw(), GetPitch()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) :
|
||||
super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5),
|
||||
m_PickupState(psInSurvivalOrCreative),
|
||||
m_DamageCoeff(2),
|
||||
m_IsCritical((a_Force >= 1)),
|
||||
m_Timer(0),
|
||||
m_HitGroundTimer(0),
|
||||
m_HasTeleported(false),
|
||||
m_bIsCollected(false),
|
||||
m_HitBlockPos(0, 0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
|
||||
{
|
||||
switch (m_PickupState)
|
||||
{
|
||||
case psNoPickup: return false;
|
||||
case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative());
|
||||
case psInCreative: return a_Player.IsGameModeCreative();
|
||||
}
|
||||
ASSERT(!"Unhandled pickup state");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
if (a_HitFace == BLOCK_FACE_NONE) { return; }
|
||||
|
||||
super::OnHitSolidBlock(a_HitPos, a_HitFace);
|
||||
int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z;
|
||||
|
||||
switch (a_HitFace)
|
||||
{
|
||||
case BLOCK_FACE_XM: // Strangely, bounding boxes / block tracers return the actual block for these two directions, so AddFace not needed
|
||||
case BLOCK_FACE_YM:
|
||||
{
|
||||
break;
|
||||
}
|
||||
default: AddFaceDirection(a_X, a_Y, a_Z, a_HitFace, true);
|
||||
}
|
||||
|
||||
m_HitBlockPos = Vector3i(a_X, a_Y, a_Z);
|
||||
|
||||
// Broadcast arrow hit sound
|
||||
m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer() && !a_EntityHit.IsBoat())
|
||||
{
|
||||
// Not an entity that interacts with an arrow
|
||||
return;
|
||||
}
|
||||
|
||||
int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5);
|
||||
if (m_IsCritical)
|
||||
{
|
||||
Damage += m_World->GetTickRandomNumber(Damage / 2 + 2);
|
||||
}
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1);
|
||||
|
||||
// Broadcast successful hit sound
|
||||
m_World->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cArrowEntity::CollectedBy(cPlayer * a_Dest)
|
||||
{
|
||||
if ((m_IsInGround) && (!m_bIsCollected) && (CanPickup(*a_Dest)))
|
||||
{
|
||||
int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW);
|
||||
if (NumAdded > 0) // Only play effects if there was space in inventory
|
||||
{
|
||||
m_World->BroadcastCollectPickup((const cPickup &)*this, *a_Dest);
|
||||
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
|
||||
m_World->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
m_bIsCollected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
super::Tick(a_Dt, a_Chunk);
|
||||
m_Timer += a_Dt;
|
||||
|
||||
if (m_bIsCollected)
|
||||
{
|
||||
if (m_Timer > 500.f) // 0.5 seconds
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (m_Timer > 1000 * 60 * 5) // 5 minutes
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_IsInGround)
|
||||
{
|
||||
// When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL
|
||||
// Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing)
|
||||
// We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync
|
||||
// Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position
|
||||
|
||||
if (!m_HasTeleported) // Sent a teleport already, don't do again
|
||||
{
|
||||
if (m_HitGroundTimer > 1000.f) // Send after a second, could be less, but just in case
|
||||
{
|
||||
m_World->BroadcastTeleportEntity(*this);
|
||||
m_HasTeleported = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_HitGroundTimer += a_Dt;
|
||||
}
|
||||
}
|
||||
|
||||
int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width;
|
||||
int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width;
|
||||
cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ);
|
||||
|
||||
if (Chunk == NULL)
|
||||
{
|
||||
// Inside an unloaded chunk, abort
|
||||
return;
|
||||
}
|
||||
|
||||
if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed?
|
||||
{
|
||||
m_IsInGround = false; // Yes, begin simulating physics again
|
||||
}
|
||||
}
|
||||
}
|
96
src/Entities/ArrowEntity.h
Normal file
96
src/Entities/ArrowEntity.h
Normal file
@ -0,0 +1,96 @@
|
||||
//
|
||||
// ArrowEntity.h
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ProjectileEntity.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class cArrowEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
/// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field
|
||||
enum ePickupState
|
||||
{
|
||||
psNoPickup = 0,
|
||||
psInSurvivalOrCreative = 1,
|
||||
psInCreative = 2,
|
||||
} ;
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cArrowEntity);
|
||||
|
||||
/// Creates a new arrow with psNoPickup state and default damage modifier coeff
|
||||
cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
/// Creates a new arrow as shot by a player, initializes it from the player object
|
||||
cArrowEntity(cPlayer & a_Player, double a_Force);
|
||||
|
||||
// tolua_begin
|
||||
|
||||
/// Returns whether the arrow can be picked up by players
|
||||
ePickupState GetPickupState(void) const { return m_PickupState; }
|
||||
|
||||
/// Sets a new pickup state
|
||||
void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; }
|
||||
|
||||
/// Returns the damage modifier coeff.
|
||||
double GetDamageCoeff(void) const { return m_DamageCoeff; }
|
||||
|
||||
/// Sets the damage modifier coeff
|
||||
void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; }
|
||||
|
||||
/// Returns true if the specified player can pick the arrow up
|
||||
bool CanPickup(const cPlayer & a_Player) const;
|
||||
|
||||
/// Returns true if the arrow is set as critical
|
||||
bool IsCritical(void) const { return m_IsCritical; }
|
||||
|
||||
/// Sets the IsCritical flag
|
||||
void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; }
|
||||
|
||||
// tolua_end
|
||||
|
||||
protected:
|
||||
|
||||
/// Determines when the arrow can be picked up by players
|
||||
ePickupState m_PickupState;
|
||||
|
||||
/// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow
|
||||
double m_DamageCoeff;
|
||||
|
||||
/// If true, the arrow deals more damage
|
||||
bool m_IsCritical;
|
||||
|
||||
/// Timer for pickup collection animation or five minute timeout
|
||||
float m_Timer;
|
||||
|
||||
/// Timer for client arrow position confirmation via TeleportEntity
|
||||
float m_HitGroundTimer;
|
||||
|
||||
// Whether the arrow has already been teleported into the proper position in the ground.
|
||||
bool m_HasTeleported;
|
||||
|
||||
/// If true, the arrow is in the process of being collected - don't go to anyone else
|
||||
bool m_bIsCollected;
|
||||
|
||||
/// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air
|
||||
Vector3i m_HitBlockPos;
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
virtual void CollectedBy(cPlayer * a_Player) override;
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
}; // tolua_export
|
@ -33,9 +33,12 @@ void cBoat::SpawnOn(cClientHandle & a_ClientHandle)
|
||||
|
||||
|
||||
|
||||
void cBoat::DoTakeDamage(TakeDamageInfo & TDI)
|
||||
bool cBoat::DoTakeDamage(TakeDamageInfo & TDI)
|
||||
{
|
||||
super::DoTakeDamage(TDI);
|
||||
if (!super::DoTakeDamage(TDI))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetHealth() == 0)
|
||||
{
|
||||
@ -50,6 +53,7 @@ void cBoat::DoTakeDamage(TakeDamageInfo & TDI)
|
||||
}
|
||||
Destroy(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
// cEntity overrides:
|
||||
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
|
||||
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||
virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
|
||||
virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void HandleSpeedFromAttachee(float a_Forward, float a_Sideways) override;
|
||||
|
||||
|
@ -53,6 +53,8 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d
|
||||
, m_TicksSinceLastVoidDamage(0)
|
||||
, m_IsSwimming(false)
|
||||
, m_IsSubmerged(false)
|
||||
, m_AirLevel(0)
|
||||
, m_AirTickTimer(0)
|
||||
, m_HeadYaw( 0.0 )
|
||||
, m_Rot(0.0, 0.0, 0.0)
|
||||
, m_Pos(a_X, a_Y, a_Z)
|
||||
@ -60,6 +62,7 @@ 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_InvulnerableTicks(0)
|
||||
{
|
||||
cCSLock Lock(m_CSCount);
|
||||
m_EntityCount++;
|
||||
@ -294,17 +297,23 @@ void cEntity::SetPitchFromSpeed(void)
|
||||
|
||||
|
||||
|
||||
void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
if (cRoot::Get()->GetPluginManager()->CallHookTakeDamage(*this, a_TDI))
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_Health <= 0)
|
||||
{
|
||||
// Can't take damage if already dead
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_InvulnerableTicks > 0)
|
||||
{
|
||||
// Entity is invulnerable
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer()))
|
||||
@ -362,10 +371,13 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
|
||||
m_World->BroadcastEntityStatus(*this, esGenericHurt);
|
||||
|
||||
m_InvulnerableTicks = 10;
|
||||
|
||||
if (m_Health <= 0)
|
||||
{
|
||||
KilledBy(a_TDI.Attacker);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -410,11 +422,8 @@ int cEntity::GetRawDamageAgainst(const cEntity & a_Receiver)
|
||||
|
||||
|
||||
|
||||
int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage)
|
||||
bool cEntity::ArmorCoversAgainst(eDamageType a_DamageType)
|
||||
{
|
||||
// Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
|
||||
|
||||
// Filter out damage types that are not protected by armor:
|
||||
// Ref.: http://www.minecraftwiki.net/wiki/Armor#Effects as of 2012_12_20
|
||||
switch (a_DamageType)
|
||||
{
|
||||
@ -429,9 +438,34 @@ int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_Dama
|
||||
case dtLightning:
|
||||
case dtPlugin:
|
||||
{
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
case dtAttack:
|
||||
case dtArrowAttack:
|
||||
case dtCactusContact:
|
||||
case dtLavaContact:
|
||||
case dtFireContact:
|
||||
case dtEnderPearl:
|
||||
case dtExplosion:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ASSERT(!"Invalid damage type!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage)
|
||||
{
|
||||
// Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
|
||||
|
||||
// Filter out damage types that are not protected by armor:
|
||||
if (!ArmorCoversAgainst(a_DamageType)) return 0;
|
||||
|
||||
// Add up all armor points:
|
||||
// Ref.: http://www.minecraftwiki.net/wiki/Armor#Defense_points as of 2012_12_20
|
||||
@ -540,6 +574,11 @@ void cEntity::SetHealth(int a_Health)
|
||||
|
||||
void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
if (m_InvulnerableTicks > 0)
|
||||
{
|
||||
m_InvulnerableTicks--;
|
||||
}
|
||||
|
||||
if (m_AttachedTo != NULL)
|
||||
{
|
||||
if ((m_Pos - m_AttachedTo->GetPosition()).Length() > 0.5)
|
||||
|
@ -262,14 +262,19 @@ public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
/// Makes this entity take damage specified in the a_TDI. The TDI is sent through plugins first, then applied
|
||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI);
|
||||
/** Makes this entity take damage specified in the a_TDI.
|
||||
The TDI is sent through plugins first, then applied.
|
||||
If it returns false, the entity hasn't receive any damage. */
|
||||
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI);
|
||||
|
||||
// tolua_begin
|
||||
|
||||
/// Returns the hitpoints that this pawn can deal to a_Receiver using its equipped items
|
||||
virtual int GetRawDamageAgainst(const cEntity & a_Receiver);
|
||||
|
||||
/** Returns whether armor will protect against the passed damage type **/
|
||||
virtual bool ArmorCoversAgainst(eDamageType a_DamageType);
|
||||
|
||||
/// Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
|
||||
virtual int GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_RawDamage);
|
||||
|
||||
@ -391,6 +396,12 @@ public:
|
||||
virtual bool IsSubmerged(void) const{ return m_IsSubmerged; }
|
||||
/** Gets remaining air of a monster */
|
||||
int GetAirLevel(void) const { return m_AirLevel; }
|
||||
|
||||
/** Gets the invulnerable ticks from the entity */
|
||||
int GetInvulnerableTicks(void) const { return m_InvulnerableTicks; }
|
||||
|
||||
/** Set the invulnerable ticks from the entity */
|
||||
void SetInvulnerableTicks(int a_InvulnerableTicks) { m_InvulnerableTicks = a_InvulnerableTicks; }
|
||||
|
||||
// tolua_end
|
||||
|
||||
@ -475,29 +486,33 @@ protected:
|
||||
int m_AirTickTimer;
|
||||
|
||||
private:
|
||||
// Measured in degrees, [-180, +180)
|
||||
/** Measured in degrees, [-180, +180) */
|
||||
double m_HeadYaw;
|
||||
|
||||
// Measured in meter/second (m/s)
|
||||
/** Measured in meter/second (m/s) */
|
||||
Vector3d m_Speed;
|
||||
|
||||
// Measured in degrees, [-180, +180)
|
||||
/** Measured in degrees, [-180, +180) */
|
||||
Vector3d m_Rot;
|
||||
|
||||
/// Position of the entity's XZ center and Y bottom
|
||||
/** Position of the entity's XZ center and Y bottom */
|
||||
Vector3d m_Pos;
|
||||
|
||||
// Measured in meter / second
|
||||
/** Measured in meter / second */
|
||||
Vector3d m_WaterSpeed;
|
||||
|
||||
// Measured in Kilograms (Kg)
|
||||
/** Measured in Kilograms (Kg) */
|
||||
double m_Mass;
|
||||
|
||||
/// Width of the entity, in the XZ plane. Since entities are represented as cylinders, this is more of a diameter.
|
||||
/** Width of the entity, in the XZ plane. Since entities are represented as cylinders, this is more of a diameter. */
|
||||
double m_Width;
|
||||
|
||||
/// Height of the entity (Y axis)
|
||||
/** Height of the entity (Y axis) */
|
||||
double m_Height;
|
||||
|
||||
/** If a player hit a entity, the entity receive a invulnerable of 10 ticks.
|
||||
While this ticks, a player can't hit this entity. */
|
||||
int m_InvulnerableTicks;
|
||||
} ; // tolua_export
|
||||
|
||||
typedef std::list<cEntity *> cEntityList;
|
||||
|
27
src/Entities/ExpBottleEntity.cpp
Normal file
27
src/Entities/ExpBottleEntity.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "ExpBottleEntity.h"
|
||||
#include "../World.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cExpBottleEntity::cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkExpBottle, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
// Spawn an experience orb with a reward between 3 and 11.
|
||||
m_World->BroadcastSoundParticleEffect(2002, POSX_TOINT, POSY_TOINT, POSZ_TOINT, 0);
|
||||
m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), 3 + m_World->GetTickRandomNumber(8));
|
||||
|
||||
Destroy();
|
||||
}
|
33
src/Entities/ExpBottleEntity.h
Normal file
33
src/Entities/ExpBottleEntity.h
Normal file
@ -0,0 +1,33 @@
|
||||
//
|
||||
// ExpBottleEntity.h
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ProjectileEntity.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class cExpBottleEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cExpBottleEntity);
|
||||
|
||||
cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
protected:
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
|
||||
}; // tolua_export
|
@ -86,7 +86,9 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
AddSpeedY(MilliDt * -9.8f);
|
||||
AddPosition(GetSpeed() * MilliDt);
|
||||
|
||||
if ((GetSpeedX() != 0) || (GetSpeedZ() != 0))
|
||||
// If not static (One billionth precision) broadcast movement.
|
||||
static const float epsilon = 0.000000001f;
|
||||
if ((fabs(GetSpeedX()) > epsilon) || (fabs(GetSpeedZ()) > epsilon))
|
||||
{
|
||||
BroadcastMovementUpdate();
|
||||
}
|
||||
|
50
src/Entities/FireChargeEntity.cpp
Normal file
50
src/Entities/FireChargeEntity.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "FireChargeEntity.h"
|
||||
#include "../World.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cFireChargeEntity::cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkFireCharge, a_Creator, a_X, a_Y, a_Z, 0.3125, 0.3125)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
SetGravity(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireChargeEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
if (m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
|
||||
{
|
||||
m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireChargeEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
Destroy();
|
||||
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireChargeEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
Destroy();
|
||||
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
||||
|
||||
// TODO: Some entities are immune to hits
|
||||
a_EntityHit.StartBurning(5 * 20); // 5 seconds of burning
|
||||
}
|
36
src/Entities/FireChargeEntity.h
Normal file
36
src/Entities/FireChargeEntity.h
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// FireChargeEntity.h
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ProjectileEntity.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class cFireChargeEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cFireChargeEntity);
|
||||
|
||||
cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
protected:
|
||||
|
||||
void Explode(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
|
||||
} ; // tolua_export
|
73
src/Entities/FireworkEntity.cpp
Normal file
73
src/Entities/FireworkEntity.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "FireworkEntity.h"
|
||||
#include "../World.h"
|
||||
#include "../Chunk.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) :
|
||||
super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
|
||||
m_ExplodeTimer(0),
|
||||
m_FireworkItem(a_Item)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
|
||||
int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
|
||||
int PosY = POSY_TOINT;
|
||||
|
||||
if ((PosY < 0) || (PosY >= cChunkDef::Height))
|
||||
{
|
||||
goto setspeed;
|
||||
}
|
||||
|
||||
if (m_IsInGround)
|
||||
{
|
||||
if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR)
|
||||
{
|
||||
m_IsInGround = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR)
|
||||
{
|
||||
OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setspeed:
|
||||
AddSpeedY(1);
|
||||
AddPosition(GetSpeed() * (a_Dt / 1000));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
super::Tick(a_Dt, a_Chunk);
|
||||
|
||||
if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks)
|
||||
{
|
||||
m_World->BroadcastEntityStatus(*this, esFireworkExploding);
|
||||
Destroy();
|
||||
}
|
||||
|
||||
m_ExplodeTimer++;
|
||||
}
|
40
src/Entities/FireworkEntity.h
Normal file
40
src/Entities/FireworkEntity.h
Normal file
@ -0,0 +1,40 @@
|
||||
//
|
||||
// FireworkEntity.h
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ProjectileEntity.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class cFireworkEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cFireworkEntity);
|
||||
|
||||
cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item);
|
||||
const cItem & GetItem(void) const { return m_FireworkItem; }
|
||||
|
||||
protected:
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
private:
|
||||
|
||||
int m_ExplodeTimer;
|
||||
cItem m_FireworkItem;
|
||||
|
||||
}; // tolua_export
|
44
src/Entities/GhastFireballEntity.cpp
Normal file
44
src/Entities/GhastFireballEntity.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "GhastFireballEntity.h"
|
||||
#include "../World.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cGhastFireballEntity::cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkGhastFireball, a_Creator, a_X, a_Y, a_Z, 1, 1)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
SetGravity(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cGhastFireballEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
m_World->DoExplosionAt(1, a_BlockX, a_BlockY, a_BlockZ, true, esGhastFireball, this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cGhastFireballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
Destroy();
|
||||
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cGhastFireballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
Destroy();
|
||||
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
||||
}
|
38
src/Entities/GhastFireballEntity.h
Normal file
38
src/Entities/GhastFireballEntity.h
Normal file
@ -0,0 +1,38 @@
|
||||
//
|
||||
// GhastFireballEntity.h
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ProjectileEntity.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class cGhastFireballEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cGhastFireballEntity);
|
||||
|
||||
cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
protected:
|
||||
|
||||
void Explode(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
|
||||
// TODO: Deflecting the fireballs by arrow- or sword- hits
|
||||
|
||||
} ; // tolua_export
|
@ -902,18 +902,21 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta)
|
||||
|
||||
|
||||
|
||||
void cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
|
||||
bool cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
|
||||
{
|
||||
if ((TDI.Attacker != NULL) && TDI.Attacker->IsPlayer() && ((cPlayer *)TDI.Attacker)->IsGameModeCreative())
|
||||
{
|
||||
Destroy();
|
||||
TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative
|
||||
super::DoTakeDamage(TDI);
|
||||
return; // No drops for creative
|
||||
SetInvulnerableTicks(0);
|
||||
return super::DoTakeDamage(TDI); // No drops for creative
|
||||
}
|
||||
|
||||
m_LastDamage = TDI.FinalDamage;
|
||||
super::DoTakeDamage(TDI);
|
||||
if (!super::DoTakeDamage(TDI))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
|
||||
@ -952,12 +955,13 @@ void cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
|
||||
default:
|
||||
{
|
||||
ASSERT(!"Unhandled minecart type when spawning pickup!");
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
// cEntity overrides:
|
||||
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
|
||||
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
|
||||
virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
|
||||
virtual void Destroyed() override;
|
||||
|
||||
int LastDamage(void) const { return m_LastDamage; }
|
||||
|
@ -808,14 +808,14 @@ void cPlayer::SetFlying(bool a_IsFlying)
|
||||
|
||||
|
||||
|
||||
void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
if ((a_TDI.DamageType != dtInVoid) && (a_TDI.DamageType != dtPlugin))
|
||||
{
|
||||
if (IsGameModeCreative())
|
||||
{
|
||||
// No damage / health in creative mode if not void or plugin damage
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -828,17 +828,19 @@ void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
if (!m_Team->AllowsFriendlyFire())
|
||||
{
|
||||
// Friendly fire is disabled
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super::DoTakeDamage(a_TDI);
|
||||
|
||||
// Any kind of damage adds food exhaustion
|
||||
AddFoodExhaustion(0.3f);
|
||||
|
||||
SendHealth();
|
||||
if (super::DoTakeDamage(a_TDI))
|
||||
{
|
||||
// Any kind of damage adds food exhaustion
|
||||
AddFoodExhaustion(0.3f);
|
||||
SendHealth();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -897,6 +899,7 @@ void cPlayer::KilledBy(cEntity * a_Killer)
|
||||
void cPlayer::Respawn(void)
|
||||
{
|
||||
m_Health = GetMaxHealth();
|
||||
SetInvulnerableTicks(20);
|
||||
|
||||
// Reset food level:
|
||||
m_FoodLevel = MAX_FOOD_LEVEL;
|
||||
|
@ -498,7 +498,7 @@ protected:
|
||||
virtual void Destroyed(void);
|
||||
|
||||
/** Filters out damage for creative mode/friendly fire */
|
||||
virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
|
||||
virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
|
||||
|
||||
/** Stops players from burning in creative mode */
|
||||
virtual void TickBurning(cChunk & a_Chunk) override;
|
||||
|
@ -4,15 +4,24 @@
|
||||
// Implements the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types
|
||||
|
||||
#include "Globals.h"
|
||||
|
||||
#include "../Bindings/PluginManager.h"
|
||||
#include "ProjectileEntity.h"
|
||||
#include "../ClientHandle.h"
|
||||
#include "Player.h"
|
||||
#include "../LineBlockTracer.h"
|
||||
#include "../BoundingBox.h"
|
||||
#include "../ChunkMap.h"
|
||||
#include "../Chunk.h"
|
||||
|
||||
#include "ArrowEntity.h"
|
||||
#include "ThrownEggEntity.h"
|
||||
#include "ThrownEnderPearlEntity.h"
|
||||
#include "ExpBottleEntity.h"
|
||||
#include "ThrownSnowballEntity.h"
|
||||
#include "FireChargeEntity.h"
|
||||
#include "FireworkEntity.h"
|
||||
#include "GhastFireballEntity.h"
|
||||
|
||||
|
||||
|
||||
|
||||
@ -401,546 +410,3 @@ void cProjectileEntity::CollectedBy(cPlayer * a_Dest)
|
||||
// Overriden in arrow
|
||||
UNUSED(a_Dest);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cArrowEntity:
|
||||
|
||||
cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5),
|
||||
m_PickupState(psNoPickup),
|
||||
m_DamageCoeff(2),
|
||||
m_IsCritical(false),
|
||||
m_Timer(0),
|
||||
m_HitGroundTimer(0),
|
||||
m_bIsCollected(false),
|
||||
m_HitBlockPos(Vector3i(0, 0, 0))
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
SetMass(0.1);
|
||||
SetYawFromSpeed();
|
||||
SetPitchFromSpeed();
|
||||
LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}",
|
||||
m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(),
|
||||
GetYaw(), GetPitch()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) :
|
||||
super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5),
|
||||
m_PickupState(psInSurvivalOrCreative),
|
||||
m_DamageCoeff(2),
|
||||
m_IsCritical((a_Force >= 1)),
|
||||
m_Timer(0),
|
||||
m_HitGroundTimer(0),
|
||||
m_HasTeleported(false),
|
||||
m_bIsCollected(false),
|
||||
m_HitBlockPos(0, 0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
|
||||
{
|
||||
switch (m_PickupState)
|
||||
{
|
||||
case psNoPickup: return false;
|
||||
case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative());
|
||||
case psInCreative: return a_Player.IsGameModeCreative();
|
||||
}
|
||||
ASSERT(!"Unhandled pickup state");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
if (a_HitFace == BLOCK_FACE_NONE) { return; }
|
||||
|
||||
super::OnHitSolidBlock(a_HitPos, a_HitFace);
|
||||
int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z;
|
||||
|
||||
switch (a_HitFace)
|
||||
{
|
||||
case BLOCK_FACE_XM: // Strangely, bounding boxes / block tracers return the actual block for these two directions, so AddFace not needed
|
||||
case BLOCK_FACE_YM:
|
||||
{
|
||||
break;
|
||||
}
|
||||
default: AddFaceDirection(a_X, a_Y, a_Z, a_HitFace, true);
|
||||
}
|
||||
|
||||
m_HitBlockPos = Vector3i(a_X, a_Y, a_Z);
|
||||
|
||||
// Broadcast arrow hit sound
|
||||
m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer() && !a_EntityHit.IsBoat())
|
||||
{
|
||||
// Not an entity that interacts with an arrow
|
||||
return;
|
||||
}
|
||||
|
||||
int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5);
|
||||
if (m_IsCritical)
|
||||
{
|
||||
Damage += m_World->GetTickRandomNumber(Damage / 2 + 2);
|
||||
}
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1);
|
||||
|
||||
// Broadcast successful hit sound
|
||||
m_World->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cArrowEntity::CollectedBy(cPlayer * a_Dest)
|
||||
{
|
||||
if ((m_IsInGround) && (!m_bIsCollected) && (CanPickup(*a_Dest)))
|
||||
{
|
||||
int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW);
|
||||
if (NumAdded > 0) // Only play effects if there was space in inventory
|
||||
{
|
||||
m_World->BroadcastCollectPickup((const cPickup &)*this, *a_Dest);
|
||||
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
|
||||
m_World->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
m_bIsCollected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
super::Tick(a_Dt, a_Chunk);
|
||||
m_Timer += a_Dt;
|
||||
|
||||
if (m_bIsCollected)
|
||||
{
|
||||
if (m_Timer > 500.f) // 0.5 seconds
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (m_Timer > 1000 * 60 * 5) // 5 minutes
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_IsInGround)
|
||||
{
|
||||
// When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL
|
||||
// Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing)
|
||||
// We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync
|
||||
// Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position
|
||||
|
||||
if (!m_HasTeleported) // Sent a teleport already, don't do again
|
||||
{
|
||||
if (m_HitGroundTimer > 1000.f) // Send after a second, could be less, but just in case
|
||||
{
|
||||
m_World->BroadcastTeleportEntity(*this);
|
||||
m_HasTeleported = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_HitGroundTimer += a_Dt;
|
||||
}
|
||||
}
|
||||
|
||||
int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width;
|
||||
int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width;
|
||||
cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ);
|
||||
|
||||
if (Chunk == NULL)
|
||||
{
|
||||
// Inside an unloaded chunk, abort
|
||||
return;
|
||||
}
|
||||
|
||||
if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed?
|
||||
{
|
||||
m_IsInGround = false; // Yes, begin simulating physics again
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cThrownEggEntity:
|
||||
|
||||
cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
TrySpawnChicken(a_HitPos);
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cThrownEggEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
int TotalDamage = 0;
|
||||
// TODO: If entity is Ender Crystal, destroy it
|
||||
|
||||
TrySpawnChicken(a_HitPos);
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
||||
|
||||
Destroy(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cThrownEggEntity::TrySpawnChicken(const Vector3d & a_HitPos)
|
||||
{
|
||||
if (m_World->GetTickRandomNumber(7) == 1)
|
||||
{
|
||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
||||
}
|
||||
else if (m_World->GetTickRandomNumber(32) == 1)
|
||||
{
|
||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cThrownEnderPearlEntity :
|
||||
|
||||
cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
// TODO: Tweak a_HitPos based on block face.
|
||||
TeleportCreator(a_HitPos);
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cThrownEnderPearlEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
int TotalDamage = 0;
|
||||
// TODO: If entity is Ender Crystal, destroy it
|
||||
|
||||
TeleportCreator(a_HitPos);
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
||||
|
||||
Destroy(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cThrownEnderPearlEntity::TeleportCreator(const Vector3d & a_HitPos)
|
||||
{
|
||||
// Teleport the creator here, make them take 5 damage:
|
||||
if (m_Creator != NULL)
|
||||
{
|
||||
m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5);
|
||||
m_Creator->TakeDamage(dtEnderPearl, this, 5, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cThrownSnowballEntity :
|
||||
|
||||
cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
int TotalDamage = 0;
|
||||
if (a_EntityHit.IsMob())
|
||||
{
|
||||
cMonster::eType MobType = ((cMonster &) a_EntityHit).GetMobType();
|
||||
if (MobType == cMonster::mtBlaze)
|
||||
{
|
||||
TotalDamage = 3;
|
||||
}
|
||||
else if (MobType == cMonster::mtEnderDragon)
|
||||
{
|
||||
TotalDamage = 1;
|
||||
}
|
||||
}
|
||||
// TODO: If entity is Ender Crystal, destroy it
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
||||
|
||||
Destroy(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cBottleOEnchantingEntity :
|
||||
|
||||
cExpBottleEntity::cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkExpBottle, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
// Spawn an experience orb with a reward between 3 and 11.
|
||||
m_World->BroadcastSoundParticleEffect(2002, POSX_TOINT, POSY_TOINT, POSZ_TOINT, 0);
|
||||
m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), 3 + m_World->GetTickRandomNumber(8));
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cFireworkEntity :
|
||||
|
||||
cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) :
|
||||
super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
|
||||
m_ExplodeTimer(0),
|
||||
m_FireworkItem(a_Item)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
|
||||
int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
|
||||
int PosY = POSY_TOINT;
|
||||
|
||||
if ((PosY < 0) || (PosY >= cChunkDef::Height))
|
||||
{
|
||||
goto setspeed;
|
||||
}
|
||||
|
||||
if (m_IsInGround)
|
||||
{
|
||||
if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR)
|
||||
{
|
||||
m_IsInGround = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR)
|
||||
{
|
||||
OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setspeed:
|
||||
AddSpeedY(1);
|
||||
AddPosition(GetSpeed() * (a_Dt / 1000));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
super::Tick(a_Dt, a_Chunk);
|
||||
|
||||
if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks)
|
||||
{
|
||||
m_World->BroadcastEntityStatus(*this, esFireworkExploding);
|
||||
Destroy();
|
||||
}
|
||||
|
||||
m_ExplodeTimer++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cGhastFireballEntity :
|
||||
|
||||
cGhastFireballEntity::cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkGhastFireball, a_Creator, a_X, a_Y, a_Z, 1, 1)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
SetGravity(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cGhastFireballEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
m_World->DoExplosionAt(1, a_BlockX, a_BlockY, a_BlockZ, true, esGhastFireball, this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cGhastFireballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
Destroy();
|
||||
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cGhastFireballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
Destroy();
|
||||
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cFireChargeEntity :
|
||||
|
||||
cFireChargeEntity::cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkFireCharge, a_Creator, a_X, a_Y, a_Z, 0.3125, 0.3125)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
SetGravity(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireChargeEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
if (m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
|
||||
{
|
||||
m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireChargeEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
Destroy();
|
||||
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireChargeEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
Destroy();
|
||||
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
||||
|
||||
// TODO: Some entities are immune to hits
|
||||
a_EntityHit.StartBurning(5 * 20); // 5 seconds of burning
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -94,311 +94,4 @@ protected:
|
||||
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void SpawnOn(cClientHandle & a_Client) override;
|
||||
|
||||
// tolua_begin
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cArrowEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
/// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field
|
||||
enum ePickupState
|
||||
{
|
||||
psNoPickup = 0,
|
||||
psInSurvivalOrCreative = 1,
|
||||
psInCreative = 2,
|
||||
} ;
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cArrowEntity);
|
||||
|
||||
/// Creates a new arrow with psNoPickup state and default damage modifier coeff
|
||||
cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
/// Creates a new arrow as shot by a player, initializes it from the player object
|
||||
cArrowEntity(cPlayer & a_Player, double a_Force);
|
||||
|
||||
// tolua_begin
|
||||
|
||||
/// Returns whether the arrow can be picked up by players
|
||||
ePickupState GetPickupState(void) const { return m_PickupState; }
|
||||
|
||||
/// Sets a new pickup state
|
||||
void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; }
|
||||
|
||||
/// Returns the damage modifier coeff.
|
||||
double GetDamageCoeff(void) const { return m_DamageCoeff; }
|
||||
|
||||
/// Sets the damage modifier coeff
|
||||
void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; }
|
||||
|
||||
/// Returns true if the specified player can pick the arrow up
|
||||
bool CanPickup(const cPlayer & a_Player) const;
|
||||
|
||||
/// Returns true if the arrow is set as critical
|
||||
bool IsCritical(void) const { return m_IsCritical; }
|
||||
|
||||
/// Sets the IsCritical flag
|
||||
void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; }
|
||||
|
||||
// tolua_end
|
||||
|
||||
protected:
|
||||
|
||||
/// Determines when the arrow can be picked up by players
|
||||
ePickupState m_PickupState;
|
||||
|
||||
/// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow
|
||||
double m_DamageCoeff;
|
||||
|
||||
/// If true, the arrow deals more damage
|
||||
bool m_IsCritical;
|
||||
|
||||
/// Timer for pickup collection animation or five minute timeout
|
||||
float m_Timer;
|
||||
|
||||
/// Timer for client arrow position confirmation via TeleportEntity
|
||||
float m_HitGroundTimer;
|
||||
|
||||
// Whether the arrow has already been teleported into the proper position in the ground.
|
||||
bool m_HasTeleported;
|
||||
|
||||
/// If true, the arrow is in the process of being collected - don't go to anyone else
|
||||
bool m_bIsCollected;
|
||||
|
||||
/// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air
|
||||
Vector3i m_HitBlockPos;
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
virtual void CollectedBy(cPlayer * a_Player) override;
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
// tolua_begin
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cThrownEggEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cThrownEggEntity);
|
||||
|
||||
cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
protected:
|
||||
|
||||
// tolua_end
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
|
||||
// Randomly decides whether to spawn a chicken where the egg lands.
|
||||
void TrySpawnChicken(const Vector3d & a_HitPos);
|
||||
|
||||
// tolua_begin
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cThrownEnderPearlEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cThrownEnderPearlEntity);
|
||||
|
||||
cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
protected:
|
||||
|
||||
// tolua_end
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
|
||||
// Teleports the creator where the ender pearl lands.
|
||||
void TeleportCreator(const Vector3d & a_HitPos);
|
||||
|
||||
// tolua_begin
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cThrownSnowballEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cThrownSnowballEntity);
|
||||
|
||||
cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
protected:
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
|
||||
// tolua_begin
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cExpBottleEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cExpBottleEntity);
|
||||
|
||||
cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
protected:
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
|
||||
// tolua_begin
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cFireworkEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cFireworkEntity);
|
||||
|
||||
cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item);
|
||||
const cItem & GetItem(void) const { return m_FireworkItem; }
|
||||
|
||||
protected:
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
private:
|
||||
|
||||
int m_ExplodeTimer;
|
||||
cItem m_FireworkItem;
|
||||
|
||||
// tolua_begin
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cGhastFireballEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cGhastFireballEntity);
|
||||
|
||||
cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
protected:
|
||||
|
||||
void Explode(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
|
||||
// TODO: Deflecting the fireballs by arrow- or sword- hits
|
||||
|
||||
// tolua_begin
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cFireChargeEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cFireChargeEntity);
|
||||
|
||||
cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
protected:
|
||||
|
||||
void Explode(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
|
||||
// tolua_begin
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_end
|
||||
|
||||
|
||||
|
||||
} ; // tolua_export
|
||||
|
59
src/Entities/ThrownEggEntity.cpp
Normal file
59
src/Entities/ThrownEggEntity.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "ThrownEggEntity.h"
|
||||
#include "../World.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
TrySpawnChicken(a_HitPos);
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cThrownEggEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
int TotalDamage = 0;
|
||||
// TODO: If entity is Ender Crystal, destroy it
|
||||
|
||||
TrySpawnChicken(a_HitPos);
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
||||
|
||||
Destroy(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cThrownEggEntity::TrySpawnChicken(const Vector3d & a_HitPos)
|
||||
{
|
||||
if (m_World->GetTickRandomNumber(7) == 1)
|
||||
{
|
||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
||||
}
|
||||
else if (m_World->GetTickRandomNumber(32) == 1)
|
||||
{
|
||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
||||
}
|
||||
}
|
37
src/Entities/ThrownEggEntity.h
Normal file
37
src/Entities/ThrownEggEntity.h
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// ThrownEggEntity.h
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ProjectileEntity.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class cThrownEggEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cThrownEggEntity);
|
||||
|
||||
cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
protected:
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
|
||||
// Randomly decides whether to spawn a chicken where the egg lands.
|
||||
void TrySpawnChicken(const Vector3d & a_HitPos);
|
||||
|
||||
} ; // tolua_export
|
54
src/Entities/ThrownEnderPearlEntity.cpp
Normal file
54
src/Entities/ThrownEnderPearlEntity.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "ThrownEnderPearlEntity.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
// TODO: Tweak a_HitPos based on block face.
|
||||
TeleportCreator(a_HitPos);
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cThrownEnderPearlEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
int TotalDamage = 0;
|
||||
// TODO: If entity is Ender Crystal, destroy it
|
||||
|
||||
TeleportCreator(a_HitPos);
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
||||
|
||||
Destroy(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cThrownEnderPearlEntity::TeleportCreator(const Vector3d & a_HitPos)
|
||||
{
|
||||
// Teleport the creator here, make them take 5 damage:
|
||||
if (m_Creator != NULL)
|
||||
{
|
||||
m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5);
|
||||
m_Creator->TakeDamage(dtEnderPearl, this, 5, 0);
|
||||
}
|
||||
}
|
37
src/Entities/ThrownEnderPearlEntity.h
Normal file
37
src/Entities/ThrownEnderPearlEntity.h
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// ThrownEnderPearlEntity.h
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ProjectileEntity.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class cThrownEnderPearlEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cThrownEnderPearlEntity);
|
||||
|
||||
cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
protected:
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
|
||||
// Teleports the creator where the ender pearl lands.
|
||||
void TeleportCreator(const Vector3d & a_HitPos);
|
||||
|
||||
} ; // tolua_export
|
48
src/Entities/ThrownSnowballEntity.cpp
Normal file
48
src/Entities/ThrownSnowballEntity.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "ThrownSnowballEntity.h"
|
||||
#include "../World.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
int TotalDamage = 0;
|
||||
if (a_EntityHit.IsMob())
|
||||
{
|
||||
cMonster::eType MobType = ((cMonster &) a_EntityHit).GetMobType();
|
||||
if (MobType == cMonster::mtBlaze)
|
||||
{
|
||||
TotalDamage = 3;
|
||||
}
|
||||
else if (MobType == cMonster::mtEnderDragon)
|
||||
{
|
||||
TotalDamage = 1;
|
||||
}
|
||||
}
|
||||
// TODO: If entity is Ender Crystal, destroy it
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
||||
|
||||
Destroy(true);
|
||||
}
|
34
src/Entities/ThrownSnowballEntity.h
Normal file
34
src/Entities/ThrownSnowballEntity.h
Normal file
@ -0,0 +1,34 @@
|
||||
//
|
||||
// ThrownSnowballEntity.h
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ProjectileEntity.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class cThrownSnowballEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cThrownSnowballEntity);
|
||||
|
||||
cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
protected:
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
|
||||
} ; // tolua_export
|
@ -91,7 +91,8 @@ int cFastRandom::m_SeedCounter = 0;
|
||||
|
||||
|
||||
cFastRandom::cFastRandom(void) :
|
||||
m_Seed(m_SeedCounter++)
|
||||
m_Seed(m_SeedCounter++),
|
||||
m_Counter(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -283,7 +283,7 @@ void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef)
|
||||
if ((NumElements >= 3) && !CharDef[2].empty())
|
||||
{
|
||||
BlockMeta = (NIBBLETYPE)atoi(CharDef[2].c_str());
|
||||
ASSERT((BlockMeta >= 0) && (BlockMeta <= 15));
|
||||
ASSERT((BlockMeta <= 15));
|
||||
}
|
||||
a_CharMapOut[Src].m_BlockMeta = BlockMeta;
|
||||
} // for itr - Lines[]
|
||||
|
@ -264,7 +264,21 @@ template class SizeChecker<UInt16, 2>;
|
||||
|
||||
// Same as assert but in all Self test builds
|
||||
#ifdef SELF_TEST
|
||||
#define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
|
||||
#define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
|
||||
#endif
|
||||
|
||||
// Allow both Older versions of MSVC and newer versions of everything use a shared_ptr:
|
||||
// Note that we cannot typedef, because C++ doesn't allow (partial) templates to be typedeffed.
|
||||
#if (defined(_MSC_VER) && (_MSC_VER < 1600))
|
||||
// MSVC before 2010 doesn't have std::shared_ptr, but has std::tr1::shared_ptr, defined in <memory> included earlier
|
||||
#define SharedPtr std::tr1::shared_ptr
|
||||
#elif (defined(_MSC_VER) || (__cplusplus >= 201103L))
|
||||
// C++11 has std::shared_ptr in <memory>, included earlier
|
||||
#define SharedPtr std::shared_ptr
|
||||
#else
|
||||
// C++03 has std::tr1::shared_ptr in <tr1/memory>
|
||||
#include <tr1/memory>
|
||||
#define SharedPtr std::tr1::shared_ptr
|
||||
#endif
|
||||
|
||||
|
||||
@ -296,7 +310,7 @@ T Clamp(T a_Value, T a_Min, T a_Max)
|
||||
|
||||
|
||||
#ifndef TOLUA_TEMPLATE_BIND
|
||||
#define TOLUA_TEMPLATE_BIND(x)
|
||||
#define TOLUA_TEMPLATE_BIND(x)
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -64,7 +64,7 @@ public:
|
||||
{
|
||||
if (!IsValidItem(m_ItemType))
|
||||
{
|
||||
if (m_ItemType != E_BLOCK_AIR)
|
||||
if ((m_ItemType != E_BLOCK_AIR) && (m_ItemType != E_ITEM_EMPTY))
|
||||
{
|
||||
LOGWARNING("%s: creating an invalid item type (%d), resetting to empty.", __FUNCTION__, a_ItemType);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Entities/ProjectileEntity.h"
|
||||
#include "../Entities/ArrowEntity.h"
|
||||
|
||||
|
||||
|
||||
|
@ -171,7 +171,6 @@ bool cLineBlockTracer::MoveToNextBlock(void)
|
||||
double CoeffZ = (DestZ - m_StartZ) / m_DiffZ;
|
||||
if (CoeffZ < Coeff)
|
||||
{
|
||||
Coeff = CoeffZ;
|
||||
Direction = dirZ;
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
|
||||
cMCLogger * cMCLogger::s_MCLogger = NULL;
|
||||
bool g_ShouldColorOutput = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h> // Needed for _isatty(), not available on Linux
|
||||
@ -33,7 +32,8 @@ cMCLogger * cMCLogger::GetInstance(void)
|
||||
|
||||
|
||||
|
||||
cMCLogger::cMCLogger(void)
|
||||
cMCLogger::cMCLogger(void):
|
||||
m_ShouldColorOutput(false)
|
||||
{
|
||||
AString FileName;
|
||||
Printf(FileName, "LOG_%d.txt", (int)time(NULL));
|
||||
@ -76,15 +76,15 @@ void cMCLogger::InitLog(const AString & a_FileName)
|
||||
|
||||
#ifdef _WIN32
|
||||
// See whether we are writing to a console the default console attrib:
|
||||
g_ShouldColorOutput = (_isatty(_fileno(stdin)) != 0);
|
||||
if (g_ShouldColorOutput)
|
||||
m_ShouldColorOutput = (_isatty(_fileno(stdin)) != 0);
|
||||
if (m_ShouldColorOutput)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
||||
GetConsoleScreenBufferInfo(g_Console, &sbi);
|
||||
g_DefaultConsoleAttrib = sbi.wAttributes;
|
||||
}
|
||||
#elif defined (__linux) && !defined(ANDROID_NDK)
|
||||
g_ShouldColorOutput = isatty(fileno(stdout));
|
||||
m_ShouldColorOutput = isatty(fileno(stdout));
|
||||
// TODO: Check if the terminal supports colors, somehow?
|
||||
#endif
|
||||
}
|
||||
@ -178,7 +178,7 @@ void cMCLogger::Error(const char * a_Format, va_list a_ArgList)
|
||||
|
||||
void cMCLogger::SetColor(eColorScheme a_Scheme)
|
||||
{
|
||||
if (!g_ShouldColorOutput)
|
||||
if (!m_ShouldColorOutput)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -211,7 +211,7 @@ void cMCLogger::SetColor(eColorScheme a_Scheme)
|
||||
|
||||
void cMCLogger::ResetColor(void)
|
||||
{
|
||||
if (!g_ShouldColorOutput)
|
||||
if (!m_ShouldColorOutput)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ private:
|
||||
cCriticalSection m_CriticalSection;
|
||||
cLog * m_Log;
|
||||
static cMCLogger * s_MCLogger;
|
||||
bool m_ShouldColorOutput;
|
||||
|
||||
|
||||
/// Sets the specified color scheme in the terminal (TODO: if coloring available)
|
||||
|
@ -37,7 +37,7 @@ void cAggressiveMonster::InStateChasing(float a_Dt)
|
||||
}
|
||||
}
|
||||
|
||||
if (((float)m_FinalDestination.x != (float)m_Target->GetPosX()) || ((float)m_FinalDestination.z != (float)m_Target->GetPosZ()))
|
||||
if (!IsMovingToTargetPosition())
|
||||
{
|
||||
MoveToPosition(m_Target->GetPosition());
|
||||
}
|
||||
@ -106,3 +106,18 @@ void cAggressiveMonster::Attack(float a_Dt)
|
||||
|
||||
|
||||
|
||||
bool cAggressiveMonster::IsMovingToTargetPosition()
|
||||
{
|
||||
static const float epsilon = 0.000000000001f;
|
||||
// Difference between destination x and target x is negligible (to 10^-12 precision)
|
||||
if (fabsf((float)m_FinalDestination.x - (float)m_Target->GetPosX()) < epsilon)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Difference between destination z and target z is negligible (to 10^-12 precision)
|
||||
else if (fabsf((float)m_FinalDestination.z - (float)m_Target->GetPosZ()) > epsilon)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -22,6 +22,10 @@ public:
|
||||
virtual void EventSeePlayer(cEntity *) override;
|
||||
virtual void Attack(float a_Dt);
|
||||
|
||||
protected:
|
||||
/** Whether this mob's destination is the same as its target's position. */
|
||||
bool IsMovingToTargetPosition();
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "Blaze.h"
|
||||
#include "../World.h"
|
||||
#include "../Entities/FireChargeEntity.h"
|
||||
|
||||
|
||||
|
||||
|
@ -75,9 +75,12 @@ void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer)
|
||||
|
||||
|
||||
|
||||
void cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
bool cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
super::DoTakeDamage(a_TDI);
|
||||
if (!super::DoTakeDamage(a_TDI))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a_TDI.DamageType == dtLightning)
|
||||
{
|
||||
@ -85,6 +88,7 @@ void cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
}
|
||||
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ public:
|
||||
CLASS_PROTODEF(cCreeper);
|
||||
|
||||
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
virtual void Attack(float a_Dt) override;
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "Ghast.h"
|
||||
#include "../World.h"
|
||||
#include "../Entities/GhastFireballEntity.h"
|
||||
|
||||
|
||||
|
||||
|
@ -457,9 +457,12 @@ int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
|
||||
|
||||
|
||||
|
||||
void cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
bool cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
super::DoTakeDamage(a_TDI);
|
||||
if (!super::DoTakeDamage(a_TDI))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if((m_SoundHurt != "") && (m_Health > 0))
|
||||
m_World->BroadcastSoundEffect(m_SoundHurt, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
|
||||
@ -468,6 +471,7 @@ void cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
m_Target = a_TDI.Attacker;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -761,8 +765,10 @@ cMonster::eFamily cMonster::FamilyFromType(eType a_Type)
|
||||
case mtChicken: return mfPassive;
|
||||
case mtCow: return mfPassive;
|
||||
case mtCreeper: return mfHostile;
|
||||
case mtEnderDragon: return mfNoSpawn;
|
||||
case mtEnderman: return mfHostile;
|
||||
case mtGhast: return mfHostile;
|
||||
case mtGiant: return mfNoSpawn;
|
||||
case mtHorse: return mfPassive;
|
||||
case mtIronGolem: return mfPassive;
|
||||
case mtMagmaCube: return mfHostile;
|
||||
@ -773,17 +779,20 @@ cMonster::eFamily cMonster::FamilyFromType(eType a_Type)
|
||||
case mtSilverfish: return mfHostile;
|
||||
case mtSkeleton: return mfHostile;
|
||||
case mtSlime: return mfHostile;
|
||||
case mtSnowGolem: return mfNoSpawn;
|
||||
case mtSpider: return mfHostile;
|
||||
case mtSquid: return mfWater;
|
||||
case mtVillager: return mfPassive;
|
||||
case mtWitch: return mfHostile;
|
||||
case mtWither: return mfHostile;
|
||||
case mtWither: return mfNoSpawn;
|
||||
case mtWolf: return mfHostile;
|
||||
case mtZombie: return mfHostile;
|
||||
case mtZombiePigman: return mfHostile;
|
||||
} ;
|
||||
|
||||
case mtInvalidType: break;
|
||||
}
|
||||
ASSERT(!"Unhandled mob type");
|
||||
return mfMaxplusone;
|
||||
return mfUnhandled;
|
||||
}
|
||||
|
||||
|
||||
@ -794,10 +803,12 @@ int cMonster::GetSpawnDelay(cMonster::eFamily a_MobFamily)
|
||||
{
|
||||
switch (a_MobFamily)
|
||||
{
|
||||
case mfHostile: return 40;
|
||||
case mfPassive: return 40;
|
||||
case mfAmbient: return 40;
|
||||
case mfWater: return 400;
|
||||
case mfHostile: return 40;
|
||||
case mfPassive: return 40;
|
||||
case mfAmbient: return 40;
|
||||
case mfWater: return 400;
|
||||
case mfNoSpawn: return -1;
|
||||
case mfUnhandled: break;
|
||||
}
|
||||
ASSERT(!"Unhandled mob family");
|
||||
return -1;
|
||||
@ -866,6 +877,7 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
|
||||
case mtEnderDragon: toReturn = new cEnderDragon(); break;
|
||||
case mtEnderman: toReturn = new cEnderman(); break;
|
||||
case mtGhast: toReturn = new cGhast(); break;
|
||||
case mtGiant: toReturn = new cGiant(); break;
|
||||
case mtIronGolem: toReturn = new cIronGolem(); break;
|
||||
case mtMooshroom: toReturn = new cMooshroom(); break;
|
||||
case mtOcelot: toReturn = new cOcelot(); break;
|
||||
|
@ -66,7 +66,8 @@ public:
|
||||
mfAmbient = 2, // Bats
|
||||
mfWater = 3, // Squid
|
||||
|
||||
mfMaxplusone, // Nothing. Be sure this is the last and the others are in order
|
||||
mfNoSpawn,
|
||||
mfUnhandled, // Nothing. Be sure this is the last and the others are in order
|
||||
} ;
|
||||
|
||||
// tolua_end
|
||||
@ -87,7 +88,7 @@ public:
|
||||
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
|
||||
virtual void KilledBy(cEntity * a_Killer) override;
|
||||
|
||||
|
@ -19,9 +19,12 @@ cPassiveAggressiveMonster::cPassiveAggressiveMonster(const AString & a_ConfigNam
|
||||
|
||||
|
||||
|
||||
void cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
bool cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
super::DoTakeDamage(a_TDI);
|
||||
if (!super::DoTakeDamage(a_TDI))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((m_Target != NULL) && (m_Target->IsPlayer()))
|
||||
{
|
||||
@ -30,6 +33,7 @@ void cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
m_EMState = CHASING;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -15,7 +15,7 @@ class cPassiveAggressiveMonster :
|
||||
public:
|
||||
cPassiveAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
|
||||
|
||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -18,13 +18,17 @@ cPassiveMonster::cPassiveMonster(const AString & a_ConfigName, eType a_MobType,
|
||||
|
||||
|
||||
|
||||
void cPassiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
bool cPassiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
super::DoTakeDamage(a_TDI);
|
||||
if (!super::DoTakeDamage(a_TDI))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((a_TDI.Attacker != this) && (a_TDI.Attacker != NULL))
|
||||
{
|
||||
m_EMState = ESCAPING;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ public:
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
/// When hit by someone, run away
|
||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
/** Returns the item that the animal of this class follows when a player holds it in hand
|
||||
Return an empty item not to follow (default). */
|
||||
virtual const cItem GetFollowedItem(void) const { return cItem(); }
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "Skeleton.h"
|
||||
#include "../World.h"
|
||||
#include "../Entities/ArrowEntity.h"
|
||||
|
||||
|
||||
|
||||
|
@ -23,9 +23,13 @@ cVillager::cVillager(eVillagerType VillagerType) :
|
||||
|
||||
|
||||
|
||||
void cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
bool cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
super::DoTakeDamage(a_TDI);
|
||||
if (!super::DoTakeDamage(a_TDI))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((a_TDI.Attacker != NULL) && a_TDI.Attacker->IsPlayer())
|
||||
{
|
||||
if (m_World->GetTickRandomNumber(5) == 3)
|
||||
@ -33,6 +37,7 @@ void cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
m_World->BroadcastEntityStatus(*this, esVillagerAngry);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
CLASS_PROTODEF(cVillager);
|
||||
|
||||
// cEntity overrides
|
||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
virtual void Tick (float a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
// cVillager functions
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
cWither::cWither(void) :
|
||||
super("Wither", mtWither, "mob.wither.hurt", "mob.wither.death", 0.9, 4.0),
|
||||
m_InvulnerableTicks(220)
|
||||
m_WitherInvulnerableTicks(220)
|
||||
{
|
||||
SetMaxHealth(300);
|
||||
}
|
||||
@ -40,24 +40,24 @@ bool cWither::Initialize(cWorld * a_World)
|
||||
|
||||
|
||||
|
||||
void cWither::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
bool cWither::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
if (a_TDI.DamageType == dtDrowning)
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_InvulnerableTicks > 0)
|
||||
if (m_WitherInvulnerableTicks > 0)
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsArmored() && (a_TDI.DamageType == dtRangedAttack))
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
super::DoTakeDamage(a_TDI);
|
||||
return super::DoTakeDamage(a_TDI);
|
||||
}
|
||||
|
||||
|
||||
@ -68,16 +68,16 @@ void cWither::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
super::Tick(a_Dt, a_Chunk);
|
||||
|
||||
if (m_InvulnerableTicks > 0)
|
||||
if (m_WitherInvulnerableTicks > 0)
|
||||
{
|
||||
unsigned int NewTicks = m_InvulnerableTicks - 1;
|
||||
unsigned int NewTicks = m_WitherInvulnerableTicks - 1;
|
||||
|
||||
if (NewTicks == 0)
|
||||
{
|
||||
m_World->DoExplosionAt(7.0, GetPosX(), GetPosY(), GetPosZ(), false, esWitherBirth, this);
|
||||
}
|
||||
|
||||
m_InvulnerableTicks = NewTicks;
|
||||
m_WitherInvulnerableTicks = NewTicks;
|
||||
|
||||
if ((NewTicks % 10) == 0)
|
||||
{
|
||||
|
@ -17,9 +17,9 @@ public:
|
||||
|
||||
CLASS_PROTODEF(cWither);
|
||||
|
||||
unsigned int GetNumInvulnerableTicks(void) const { return m_InvulnerableTicks; }
|
||||
unsigned int GetWitherInvulnerableTicks(void) const { return m_WitherInvulnerableTicks; }
|
||||
|
||||
void SetNumInvulnerableTicks(unsigned int a_Ticks) { m_InvulnerableTicks = a_Ticks; }
|
||||
void SetWitherInvulnerableTicks(unsigned int a_Ticks) { m_WitherInvulnerableTicks = a_Ticks; }
|
||||
|
||||
/** Returns whether the wither is invulnerable to arrows. */
|
||||
bool IsArmored(void) const;
|
||||
@ -27,13 +27,13 @@ public:
|
||||
// cEntity overrides
|
||||
virtual bool Initialize(cWorld * a_World) override;
|
||||
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
private:
|
||||
|
||||
/** The number of ticks of invulnerability left after being initially created. Zero once invulnerability has expired. */
|
||||
unsigned int m_InvulnerableTicks;
|
||||
unsigned int m_WitherInvulnerableTicks;
|
||||
|
||||
} ;
|
||||
|
||||
|
@ -25,14 +25,19 @@ cWolf::cWolf(void) :
|
||||
|
||||
|
||||
|
||||
void cWolf::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
bool cWolf::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
super::DoTakeDamage(a_TDI);
|
||||
if (super::DoTakeDamage(a_TDI))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_IsTame)
|
||||
{
|
||||
m_IsAngry = true;
|
||||
}
|
||||
m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ public:
|
||||
|
||||
CLASS_PROTODEF(cWolf);
|
||||
|
||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void TickFollowPlayer();
|
||||
|
@ -608,6 +608,8 @@ void cCubicNoise::Generate2D(
|
||||
NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY ///< Noise-space coords of the array in the Y direction
|
||||
) const
|
||||
{
|
||||
ASSERT(a_SizeX > 0);
|
||||
ASSERT(a_SizeY > 0);
|
||||
ASSERT(a_SizeX < MAX_SIZE);
|
||||
ASSERT(a_SizeY < MAX_SIZE);
|
||||
ASSERT(a_StartX < a_EndX);
|
||||
@ -744,6 +746,8 @@ void cCubicNoise::CalcFloorFrac(
|
||||
int * a_Same, int & a_NumSame
|
||||
) const
|
||||
{
|
||||
ASSERT(a_Size > 0);
|
||||
|
||||
NOISE_DATATYPE val = a_Start;
|
||||
NOISE_DATATYPE dif = (a_End - a_Start) / (a_Size - 1);
|
||||
for (int i = 0; i < a_Size; i++)
|
||||
|
@ -1,142 +0,0 @@
|
||||
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "BlockingTCPLink.h"
|
||||
#include "Errors.h"
|
||||
|
||||
|
||||
|
||||
|
||||
cBlockingTCPLink::cBlockingTCPLink(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cBlockingTCPLink::~cBlockingTCPLink()
|
||||
{
|
||||
CloseSocket();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cBlockingTCPLink::CloseSocket()
|
||||
{
|
||||
if (!m_Socket.IsValid())
|
||||
{
|
||||
m_Socket.CloseSocket();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBlockingTCPLink::Connect(const char * iAddress, unsigned int iPort)
|
||||
{
|
||||
ASSERT(!m_Socket.IsValid());
|
||||
if (m_Socket.IsValid())
|
||||
{
|
||||
LOGWARN("WARNING: cTCPLink Connect() called while still connected.");
|
||||
m_Socket.CloseSocket();
|
||||
}
|
||||
|
||||
struct hostent *hp;
|
||||
unsigned int addr;
|
||||
struct sockaddr_in server;
|
||||
|
||||
m_Socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (!m_Socket.IsValid())
|
||||
{
|
||||
LOGERROR("cTCPLink: Cannot create a socket");
|
||||
return false;
|
||||
}
|
||||
|
||||
addr = inet_addr(iAddress);
|
||||
hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
|
||||
if (hp == NULL)
|
||||
{
|
||||
//LOGWARN("cTCPLink: gethostbyaddr returned NULL");
|
||||
hp = gethostbyname(iAddress);
|
||||
if (hp == NULL)
|
||||
{
|
||||
LOGWARN("cTCPLink: Could not resolve %s", iAddress);
|
||||
CloseSocket();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&server.sin_addr.s_addr,hp->h_addr, hp->h_length);
|
||||
server.sin_family = AF_INET;
|
||||
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,GetOSErrorString( cSocket::GetLastError() ).c_str() );
|
||||
CloseSocket();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cBlockingTCPLink::Send(char * a_Data, unsigned int a_Size, int a_Flags /* = 0 */ )
|
||||
{
|
||||
UNUSED(a_Flags);
|
||||
|
||||
ASSERT(m_Socket.IsValid());
|
||||
if (!m_Socket.IsValid())
|
||||
{
|
||||
LOGERROR("cBlockingTCPLink: Trying to send data without a valid connection!");
|
||||
return -1;
|
||||
}
|
||||
return m_Socket.Send(a_Data, a_Size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cBlockingTCPLink::SendMessage( const char* a_Message, int a_Flags /* = 0 */ )
|
||||
{
|
||||
UNUSED(a_Flags);
|
||||
|
||||
ASSERT(m_Socket.IsValid());
|
||||
if (!m_Socket.IsValid())
|
||||
{
|
||||
LOGWARN("cBlockingTCPLink: Trying to send message without a valid connection!");
|
||||
return -1;
|
||||
}
|
||||
return m_Socket.Send(a_Message, strlen(a_Message));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cBlockingTCPLink::ReceiveData(AString & oData)
|
||||
{
|
||||
ASSERT(m_Socket.IsValid());
|
||||
if (!m_Socket.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int Received = 0;
|
||||
char Buffer[256];
|
||||
while ((Received = recv(m_Socket, Buffer, sizeof(Buffer), 0)) > 0)
|
||||
{
|
||||
oData.append(Buffer, Received);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,28 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Socket.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cBlockingTCPLink // tolua_export
|
||||
{ // tolua_export
|
||||
public: // tolua_export
|
||||
cBlockingTCPLink(void); // tolua_export
|
||||
~cBlockingTCPLink(); // tolua_export
|
||||
|
||||
bool Connect( const char* a_Address, unsigned int a_Port ); // tolua_export
|
||||
int Send( char* a_Data, unsigned int a_Size, int a_Flags = 0 ); // tolua_export
|
||||
int SendMessage( const char* a_Message, int a_Flags = 0 ); // tolua_export
|
||||
void CloseSocket(); // tolua_export
|
||||
void ReceiveData(AString & oData); // tolua_export
|
||||
protected:
|
||||
|
||||
cSocket m_Socket;
|
||||
}; // tolua_export
|
||||
|
||||
|
||||
|
||||
|
@ -67,11 +67,11 @@ bool cFile::Open(const AString & iFileName, eMode iMode)
|
||||
case fmRead: Mode = "rb"; break;
|
||||
case fmWrite: Mode = "wb"; break;
|
||||
case fmReadWrite: Mode = "rb+"; break;
|
||||
default:
|
||||
{
|
||||
ASSERT(!"Unhandled file mode");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (Mode == NULL)
|
||||
{
|
||||
ASSERT(!"Unhandled file mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -143,7 +143,7 @@ bool cFile::IsEOF(void) const
|
||||
|
||||
|
||||
|
||||
int cFile::Read (void * iBuffer, int iNumBytes)
|
||||
int cFile::Read (void * iBuffer, size_t iNumBytes)
|
||||
{
|
||||
ASSERT(IsOpen());
|
||||
|
||||
@ -159,7 +159,7 @@ int cFile::Read (void * iBuffer, int iNumBytes)
|
||||
|
||||
|
||||
|
||||
int cFile::Write(const void * iBuffer, int iNumBytes)
|
||||
int cFile::Write(const void * iBuffer, size_t iNumBytes)
|
||||
{
|
||||
ASSERT(IsOpen());
|
||||
|
||||
|
@ -80,10 +80,10 @@ public:
|
||||
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 */
|
||||
int Read (void * iBuffer, int iNumBytes);
|
||||
int Read (void * iBuffer, size_t iNumBytes);
|
||||
|
||||
/** 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);
|
||||
int Write(const void * iBuffer, size_t iNumBytes);
|
||||
|
||||
/** Seeks to iPosition bytes from file start, returns old position or -1 for failure; asserts if not open */
|
||||
int Seek (int iPosition);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
|
||||
cGZipFile::cGZipFile(void) :
|
||||
m_File(NULL)
|
||||
m_File(NULL), m_Mode(fmRead)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -295,7 +295,7 @@ bool cSocket::ConnectToLocalhostIPv4(unsigned short a_Port)
|
||||
|
||||
bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Port)
|
||||
{
|
||||
// First try IP Address string to hostent conversion, because it's faster
|
||||
// First try IP Address string to hostent conversion, because it's faster and local:
|
||||
unsigned long addr = inet_addr(a_HostNameOrAddr.c_str());
|
||||
if (addr == INADDR_NONE)
|
||||
{
|
||||
@ -307,10 +307,16 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por
|
||||
CloseSocket();
|
||||
return false;
|
||||
}
|
||||
// Should be optimised to a single word copy
|
||||
memcpy(&addr, hp->h_addr, hp->h_length);
|
||||
}
|
||||
|
||||
// If the socket is not created yet, create one:
|
||||
if (!IsValid())
|
||||
{
|
||||
m_Socket = socket((int)IPv4, SOCK_STREAM, 0);
|
||||
}
|
||||
|
||||
// Connect the socket:
|
||||
sockaddr_in server;
|
||||
server.sin_addr.s_addr = addr;
|
||||
server.sin_family = AF_INET;
|
||||
|
67
src/PolarSSL++/AesCfb128Decryptor.cpp
Normal file
67
src/PolarSSL++/AesCfb128Decryptor.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
|
||||
// AesCfb128Decryptor.cpp
|
||||
|
||||
// Implements the cAesCfb128Decryptor class decrypting data using AES CFB-128
|
||||
|
||||
#include "Globals.h"
|
||||
#include "AesCfb128Decryptor.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cAesCfb128Decryptor::cAesCfb128Decryptor(void) :
|
||||
m_IVOffset(0),
|
||||
m_IsValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cAesCfb128Decryptor::~cAesCfb128Decryptor()
|
||||
{
|
||||
// Clear the leftover in-memory data, so that they can't be accessed by a backdoor
|
||||
memset(&m_Aes, 0, sizeof(m_Aes));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAesCfb128Decryptor::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 cAesCfb128Decryptor::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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
52
src/PolarSSL++/AesCfb128Decryptor.h
Normal file
52
src/PolarSSL++/AesCfb128Decryptor.h
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
// AesCfb128Decryptor.h
|
||||
|
||||
// Declares the cAesCfb128Decryptor class decrypting data using AES CFB-128
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polarssl/aes.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Decrypts data using the AES / CFB 128 algorithm */
|
||||
class cAesCfb128Decryptor
|
||||
{
|
||||
public:
|
||||
Byte test;
|
||||
|
||||
cAesCfb128Decryptor(void);
|
||||
~cAesCfb128Decryptor();
|
||||
|
||||
/** 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;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
68
src/PolarSSL++/AesCfb128Encryptor.cpp
Normal file
68
src/PolarSSL++/AesCfb128Encryptor.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
|
||||
// AesCfb128Encryptor.cpp
|
||||
|
||||
// Implements the cAesCfb128Encryptor class encrypting data using AES CFB-128
|
||||
|
||||
#include "Globals.h"
|
||||
#include "AesCfb128Encryptor.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cAesCfb128Encryptor::cAesCfb128Encryptor(void) :
|
||||
m_IVOffset(0),
|
||||
m_IsValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cAesCfb128Encryptor::~cAesCfb128Encryptor()
|
||||
{
|
||||
// Clear the leftover in-memory data, so that they can't be accessed by a backdoor
|
||||
memset(&m_Aes, 0, sizeof(m_Aes));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAesCfb128Encryptor::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 cAesCfb128Encryptor::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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
50
src/PolarSSL++/AesCfb128Encryptor.h
Normal file
50
src/PolarSSL++/AesCfb128Encryptor.h
Normal file
@ -0,0 +1,50 @@
|
||||
|
||||
// AesCfb128Encryptor.h
|
||||
|
||||
// Declares the cAesCfb128Encryptor class encrypting data using AES CFB-128
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polarssl/aes.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Encrypts data using the AES / CFB (128) algorithm */
|
||||
class cAesCfb128Encryptor
|
||||
{
|
||||
public:
|
||||
cAesCfb128Encryptor(void);
|
||||
~cAesCfb128Encryptor();
|
||||
|
||||
/** 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;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
195
src/PolarSSL++/BlockingSslClientSocket.cpp
Normal file
195
src/PolarSSL++/BlockingSslClientSocket.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
|
||||
// BlockingSslClientSocket.cpp
|
||||
|
||||
// Implements the cBlockingSslClientSocket class representing a blocking TCP socket with client SSL encryption over it
|
||||
|
||||
#include "Globals.h"
|
||||
#include "BlockingSslClientSocket.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cBlockingSslClientSocket::cBlockingSslClientSocket(void) :
|
||||
m_Ssl(*this),
|
||||
m_IsConnected(false)
|
||||
{
|
||||
// Nothing needed yet
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBlockingSslClientSocket::Connect(const AString & a_ServerName, UInt16 a_Port)
|
||||
{
|
||||
// If already connected, report an error:
|
||||
if (m_IsConnected)
|
||||
{
|
||||
// TODO: Handle this better - if connected to the same server and port, and the socket is alive, return success
|
||||
m_LastErrorText = "Already connected";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Connect the underlying socket:
|
||||
m_Socket.CreateSocket(cSocket::IPv4);
|
||||
if (!m_Socket.ConnectIPv4(a_ServerName.c_str(), a_Port))
|
||||
{
|
||||
Printf(m_LastErrorText, "Socket connect failed: %s", m_Socket.GetLastErrorString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize the SSL:
|
||||
int ret = m_Ssl.Initialize(true);
|
||||
if (ret != 0)
|
||||
{
|
||||
Printf(m_LastErrorText, "SSL initialization failed: -0x%x", -ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we have been assigned a trusted CA root cert store, push it into the SSL context:
|
||||
if (m_CACerts.get() != NULL)
|
||||
{
|
||||
m_Ssl.SetCACerts(m_CACerts, m_ExpectedPeerName);
|
||||
}
|
||||
|
||||
ret = m_Ssl.Handshake();
|
||||
if (ret != 0)
|
||||
{
|
||||
Printf(m_LastErrorText, "SSL handshake failed: -0x%x", -ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_IsConnected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBlockingSslClientSocket::SetTrustedRootCertsFromString(const AString & a_CACerts, const AString & a_ExpectedPeerName)
|
||||
{
|
||||
// Warn if used multiple times, but don't signal an error:
|
||||
if (m_CACerts.get() != NULL)
|
||||
{
|
||||
LOGWARNING(
|
||||
"SSL: Trying to set multiple trusted CA root cert stores, only the last one will be used. Name: %s",
|
||||
a_ExpectedPeerName.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
// Parse the cert:
|
||||
m_CACerts.reset(new cX509Cert);
|
||||
int ret = m_CACerts->Parse(a_CACerts.data(), a_CACerts.size());
|
||||
if (ret < 0)
|
||||
{
|
||||
Printf(m_LastErrorText, "CA cert parsing failed: -0x%x", -ret);
|
||||
return false;
|
||||
}
|
||||
m_ExpectedPeerName = a_ExpectedPeerName;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBlockingSslClientSocket::Send(const void * a_Data, size_t a_NumBytes)
|
||||
{
|
||||
ASSERT(m_IsConnected);
|
||||
|
||||
// Keep sending the data until all of it is sent:
|
||||
const char * Data = (const char *)a_Data;
|
||||
size_t NumBytes = a_NumBytes;
|
||||
for (;;)
|
||||
{
|
||||
int res = m_Ssl.WritePlain(a_Data, a_NumBytes);
|
||||
if (res < 0)
|
||||
{
|
||||
ASSERT(res != POLARSSL_ERR_NET_WANT_READ); // This should never happen with callback-based SSL
|
||||
ASSERT(res != POLARSSL_ERR_NET_WANT_WRITE); // This should never happen with callback-based SSL
|
||||
Printf(m_LastErrorText, "Data cannot be written to SSL context: -0x%x", -res);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Data += res;
|
||||
NumBytes -= res;
|
||||
if (NumBytes == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cBlockingSslClientSocket::Receive(void * a_Data, size_t a_MaxBytes)
|
||||
{
|
||||
ASSERT(m_IsConnected);
|
||||
|
||||
int res = m_Ssl.ReadPlain(a_Data, a_MaxBytes);
|
||||
if (res < 0)
|
||||
{
|
||||
Printf(m_LastErrorText, "Data cannot be read form SSL context: -0x%x", -res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cBlockingSslClientSocket::Disconnect(void)
|
||||
{
|
||||
// Ignore if not connected
|
||||
if (!m_IsConnected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_Ssl.NotifyClose();
|
||||
m_Socket.CloseSocket();
|
||||
m_IsConnected = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cBlockingSslClientSocket::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
|
||||
{
|
||||
int res = m_Socket.Receive((char *)a_Buffer, a_NumBytes, 0);
|
||||
if (res < 0)
|
||||
{
|
||||
// PolarSSL's net routines distinguish between connection reset and general failure, we don't need to
|
||||
return POLARSSL_ERR_NET_RECV_FAILED;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cBlockingSslClientSocket::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes)
|
||||
{
|
||||
int res = m_Socket.Send((const char *)a_Buffer, a_NumBytes);
|
||||
if (res < 0)
|
||||
{
|
||||
// PolarSSL's net routines distinguish between connection reset and general failure, we don't need to
|
||||
return POLARSSL_ERR_NET_SEND_FAILED;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
80
src/PolarSSL++/BlockingSslClientSocket.h
Normal file
80
src/PolarSSL++/BlockingSslClientSocket.h
Normal file
@ -0,0 +1,80 @@
|
||||
|
||||
// BlockingSslClientSocket.h
|
||||
|
||||
// Declares the cBlockingSslClientSocket class representing a blocking TCP socket with client SSL encryption over it
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CallbackSslContext.h"
|
||||
#include "../OSSupport/Socket.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cBlockingSslClientSocket :
|
||||
protected cCallbackSslContext::cDataCallbacks
|
||||
{
|
||||
public:
|
||||
cBlockingSslClientSocket(void);
|
||||
|
||||
/** Connects to the specified server and performs SSL handshake.
|
||||
Returns true if successful, false on failure. Sets internal error text on failure. */
|
||||
bool Connect(const AString & a_ServerName, UInt16 a_Port);
|
||||
|
||||
/** Sends the specified data over the connection.
|
||||
Returns true if successful, false on failure. Sets the internal error text on failure. */
|
||||
bool Send(const void * a_Data, size_t a_NumBytes);
|
||||
|
||||
/** Receives data from the connection.
|
||||
Blocks until there is any data available, then returns as much as possible.
|
||||
Returns the number of bytes actually received, negative number on failure.
|
||||
Sets the internal error text on failure. */
|
||||
int Receive(void * a_Data, size_t a_MaxBytes);
|
||||
|
||||
/** Disconnects the connection gracefully, if possible.
|
||||
Note that this also frees the internal SSL context, so all the certificates etc. are lost. */
|
||||
void Disconnect(void);
|
||||
|
||||
/** Sets the root certificates that are to be trusted. Forces the connection to use strict cert
|
||||
verification. Needs to be used before calling Connect().
|
||||
a_ExpectedPeerName is the name that we expect to receive in the SSL peer's cert; verification will fail if
|
||||
the presented name is different (possible MITM).
|
||||
Returns true on success, false on failure. Sets internal error text on failure. */
|
||||
bool SetTrustedRootCertsFromString(const AString & a_CACerts, const AString & a_ExpectedPeerName);
|
||||
|
||||
/** Returns the text of the last error that has occurred in this instance. */
|
||||
const AString & GetLastErrorText(void) const { return m_LastErrorText; }
|
||||
|
||||
protected:
|
||||
/** The SSL context used for the socket */
|
||||
cCallbackSslContext m_Ssl;
|
||||
|
||||
/** The underlying socket to the SSL server */
|
||||
cSocket m_Socket;
|
||||
|
||||
/** The trusted CA root cert store, if we are to verify the cert strictly. Set by SetTrustedRootCertsFromString(). */
|
||||
cX509CertPtr m_CACerts;
|
||||
|
||||
/** The expected SSL peer's name, if we are to verify the cert strictly. Set by SetTrustedRootCertsFromString(). */
|
||||
AString m_ExpectedPeerName;
|
||||
|
||||
/** Text of the last error that has occurred. */
|
||||
AString m_LastErrorText;
|
||||
|
||||
/** Set to true if the connection established successfully. */
|
||||
bool m_IsConnected;
|
||||
|
||||
|
||||
// cCallbackSslContext::cDataCallbacks overrides:
|
||||
virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override;
|
||||
virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
62
src/PolarSSL++/BufferedSslContext.cpp
Normal file
62
src/PolarSSL++/BufferedSslContext.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
|
||||
// BufferedSslContext.cpp
|
||||
|
||||
// Implements the cBufferedSslContext class representing a SSL context with the SSL peer data backed by a cByteBuffer
|
||||
|
||||
#include "Globals.h"
|
||||
#include "BufferedSslContext.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cBufferedSslContext::cBufferedSslContext(size_t a_BufferSize):
|
||||
m_OutgoingData(a_BufferSize),
|
||||
m_IncomingData(a_BufferSize)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cBufferedSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
|
||||
{
|
||||
// Called when PolarSSL wants to read encrypted data from the SSL peer
|
||||
// Read the data from the buffer inside this object, where the owner has stored them using WriteIncoming():
|
||||
size_t NumBytes = std::min(a_NumBytes, m_IncomingData.GetReadableSpace());
|
||||
if (NumBytes == 0)
|
||||
{
|
||||
return POLARSSL_ERR_NET_WANT_READ;
|
||||
}
|
||||
if (!m_IncomingData.ReadBuf(a_Buffer, NumBytes))
|
||||
{
|
||||
m_IncomingData.ResetRead();
|
||||
return POLARSSL_ERR_NET_RECV_FAILED;
|
||||
}
|
||||
m_IncomingData.CommitRead();
|
||||
return (int)NumBytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cBufferedSslContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes)
|
||||
{
|
||||
// Called when PolarSSL wants to write encrypted data to the SSL peer
|
||||
// Write the data into the buffer inside this object, where the owner can later read them using ReadOutgoing():
|
||||
if (!m_OutgoingData.CanWriteBytes(a_NumBytes))
|
||||
{
|
||||
return POLARSSL_ERR_NET_WANT_WRITE;
|
||||
}
|
||||
if (!m_OutgoingData.Write((const char *)a_Buffer, a_NumBytes))
|
||||
{
|
||||
return POLARSSL_ERR_NET_SEND_FAILED;
|
||||
}
|
||||
return (int)a_NumBytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
52
src/PolarSSL++/BufferedSslContext.h
Normal file
52
src/PolarSSL++/BufferedSslContext.h
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
// BufferedSslContext.h
|
||||
|
||||
// Declares the cBufferedSslContext class representing a SSL context with the SSL peer data backed by a cByteBuffer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SslContext.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cBufferedSslContext :
|
||||
public cSslContext
|
||||
{
|
||||
typedef cSslContext super;
|
||||
|
||||
public:
|
||||
/** Creates a new context with the buffers of specified size for the encrypted / decrypted data. */
|
||||
cBufferedSslContext(size_t a_BufferSize = 64000);
|
||||
|
||||
/** Stores the specified data in the "incoming" buffer, to be process by the SSL decryptor.
|
||||
This is the data received from the SSL peer.
|
||||
Returns the number of bytes actually stored. If 0 is returned, owner should check the error state. */
|
||||
size_t WriteIncoming(const void * a_Data, size_t a_NumBytes);
|
||||
|
||||
/** Retrieves data from the "outgoing" buffer, after being processed by the SSL encryptor.
|
||||
This is the data to be sent to the SSL peer.
|
||||
Returns the number of bytes actually retrieved. */
|
||||
size_t ReadOutgoing(void * a_Data, size_t a_DataMaxSize);
|
||||
|
||||
protected:
|
||||
/** Buffer for the data that has been encrypted into the SSL stream and should be sent out. */
|
||||
cByteBuffer m_OutgoingData;
|
||||
|
||||
/** Buffer for the data that has come in and needs to be decrypted from the SSL stream. */
|
||||
cByteBuffer m_IncomingData;
|
||||
|
||||
|
||||
// cSslContext overrides:
|
||||
virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override;
|
||||
virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
41
src/PolarSSL++/CMakeLists.txt
Normal file
41
src/PolarSSL++/CMakeLists.txt
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (MCServer)
|
||||
|
||||
include_directories ("${PROJECT_SOURCE_DIR}/../")
|
||||
|
||||
set(SOURCES
|
||||
AesCfb128Decryptor.cpp
|
||||
AesCfb128Encryptor.cpp
|
||||
BlockingSslClientSocket.cpp
|
||||
BufferedSslContext.cpp
|
||||
CallbackSslContext.cpp
|
||||
CtrDrbgContext.cpp
|
||||
EntropyContext.cpp
|
||||
PublicKey.cpp
|
||||
RsaPrivateKey.cpp
|
||||
Sha1Checksum.cpp
|
||||
SslContext.cpp
|
||||
X509Cert.cpp
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
AesCfb128Decryptor.h
|
||||
AesCfb128Encryptor.h
|
||||
BlockingSslClientSocket.h
|
||||
BufferedSslContext.h
|
||||
CallbackSslContext.h
|
||||
CtrDrbgContext.h
|
||||
EntropyContext.h
|
||||
PublicKey.h
|
||||
RsaPrivateKey.h
|
||||
SslContext.h
|
||||
Sha1Checksum.h
|
||||
X509Cert.h
|
||||
)
|
||||
|
||||
add_library(PolarSSL++ ${SOURCES} ${HEADERS})
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(PolarSSL++ polarssl)
|
||||
endif()
|
59
src/PolarSSL++/CallbackSslContext.cpp
Normal file
59
src/PolarSSL++/CallbackSslContext.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
|
||||
// CallbackSslContext.cpp
|
||||
|
||||
// Declares the cCallbackSslContext class representing a SSL context wrapper that uses callbacks to read and write SSL peer data
|
||||
|
||||
#include "Globals.h"
|
||||
#include "CallbackSslContext.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cCallbackSslContext::cCallbackSslContext(void)
|
||||
{
|
||||
// Nothing needed, but the constructor needs to exist so
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cCallbackSslContext::cCallbackSslContext(cCallbackSslContext::cDataCallbacks & a_Callbacks) :
|
||||
m_Callbacks(&a_Callbacks)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cCallbackSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
|
||||
{
|
||||
if (m_Callbacks == NULL)
|
||||
{
|
||||
LOGWARNING("SSL: Trying to receive data with no callbacks, aborting.");
|
||||
return POLARSSL_ERR_NET_RECV_FAILED;
|
||||
}
|
||||
return m_Callbacks->ReceiveEncrypted(a_Buffer, a_NumBytes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cCallbackSslContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes)
|
||||
{
|
||||
if (m_Callbacks == NULL)
|
||||
{
|
||||
LOGWARNING("SSL: Trying to send data with no callbacks, aborting.");
|
||||
return POLARSSL_ERR_NET_SEND_FAILED;
|
||||
}
|
||||
return m_Callbacks->SendEncrypted(a_Buffer, a_NumBytes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
61
src/PolarSSL++/CallbackSslContext.h
Normal file
61
src/PolarSSL++/CallbackSslContext.h
Normal file
@ -0,0 +1,61 @@
|
||||
|
||||
// CallbackSslContext.h
|
||||
|
||||
// Declares the cCallbackSslContext class representing a SSL context wrapper that uses callbacks to read and write SSL peer data
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SslContext.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cCallbackSslContext :
|
||||
public cSslContext
|
||||
{
|
||||
public:
|
||||
/** Interface used as a data sink for the SSL peer data. */
|
||||
class cDataCallbacks
|
||||
{
|
||||
public:
|
||||
/** Called when PolarSSL wants to read encrypted data from the SSL peer.
|
||||
The returned value is the number of bytes received, or a PolarSSL error on failure.
|
||||
The implementation can return POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE to indicate
|
||||
that there's currently no more data and that there might be more data in the future. In such cases the
|
||||
SSL operation that invoked this call will terminate with the same return value, so that the owner is
|
||||
notified of this condition and can potentially restart the operation later on. */
|
||||
virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) = 0;
|
||||
|
||||
/** Called when PolarSSL wants to write encrypted data to the SSL peer.
|
||||
The returned value is the number of bytes sent, or a PolarSSL error on failure.
|
||||
The implementation can return POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE to indicate
|
||||
that there's currently no more data and that there might be more data in the future. In such cases the
|
||||
SSL operation that invoked this call will terminate with the same return value, so that the owner is
|
||||
notified of this condition and can potentially restart the operation later on. */
|
||||
virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) = 0;
|
||||
} ;
|
||||
|
||||
|
||||
/** Creates a new SSL context with no callbacks assigned */
|
||||
cCallbackSslContext(void);
|
||||
|
||||
/** Creates a new SSL context with the specified callbacks */
|
||||
cCallbackSslContext(cDataCallbacks & a_Callbacks);
|
||||
|
||||
protected:
|
||||
/** The callbacks to use to send and receive SSL peer data */
|
||||
cDataCallbacks * m_Callbacks;
|
||||
|
||||
// cSslContext overrides:
|
||||
virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override;
|
||||
virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user