summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTycho <work.tycho+git@gmail.com>2014-05-01 20:50:40 +0200
committerTycho <work.tycho+git@gmail.com>2014-05-01 20:50:40 +0200
commit8780b324ff075f17358b01bc3615da0397fbe8be (patch)
treed448ab665fd50cca3861e06654f8668a89c8d953 /src
parentAdded Testing capability (diff)
parentFixed MSVC2013 compilation. (diff)
downloadcuberite-8780b324ff075f17358b01bc3615da0397fbe8be.tar
cuberite-8780b324ff075f17358b01bc3615da0397fbe8be.tar.gz
cuberite-8780b324ff075f17358b01bc3615da0397fbe8be.tar.bz2
cuberite-8780b324ff075f17358b01bc3615da0397fbe8be.tar.lz
cuberite-8780b324ff075f17358b01bc3615da0397fbe8be.tar.xz
cuberite-8780b324ff075f17358b01bc3615da0397fbe8be.tar.zst
cuberite-8780b324ff075f17358b01bc3615da0397fbe8be.zip
Diffstat (limited to '')
-rw-r--r--src/Bindings/ManualBindings.cpp5
-rw-r--r--src/Bindings/PluginLua.cpp2
-rw-r--r--src/BiomeDef.cpp180
-rw-r--r--src/BiomeDef.h7
-rw-r--r--src/BlockArea.cpp393
-rw-r--r--src/BlockArea.h5
-rw-r--r--src/BlockEntities/CommandBlockEntity.cpp3
-rw-r--r--src/BlockEntities/MobHeadEntity.cpp2
-rw-r--r--src/BlockID.cpp5
-rw-r--r--src/BlockInfo.cpp1
-rw-r--r--src/ByteBuffer.cpp11
-rw-r--r--src/ByteBuffer.h2
-rw-r--r--src/CMakeLists.txt12
-rw-r--r--src/ChunkDef.h18
-rw-r--r--src/ChunkMap.cpp11
-rw-r--r--src/ClientHandle.cpp136
-rw-r--r--src/ClientHandle.h5
-rw-r--r--src/Crypto.cpp509
-rw-r--r--src/Crypto.h198
-rw-r--r--src/Entities/ArrowEntity.cpp193
-rw-r--r--src/Entities/ArrowEntity.h96
-rw-r--r--src/Entities/Boat.cpp8
-rw-r--r--src/Entities/Boat.h2
-rw-r--r--src/Entities/Entity.cpp55
-rw-r--r--src/Entities/Entity.h35
-rw-r--r--src/Entities/ExpBottleEntity.cpp27
-rw-r--r--src/Entities/ExpBottleEntity.h33
-rw-r--r--src/Entities/FallingBlock.cpp4
-rw-r--r--src/Entities/FireChargeEntity.cpp50
-rw-r--r--src/Entities/FireChargeEntity.h36
-rw-r--r--src/Entities/FireworkEntity.cpp73
-rw-r--r--src/Entities/FireworkEntity.h40
-rw-r--r--src/Entities/GhastFireballEntity.cpp44
-rw-r--r--src/Entities/GhastFireballEntity.h38
-rw-r--r--src/Entities/Minecart.cpp14
-rw-r--r--src/Entities/Minecart.h2
-rw-r--r--src/Entities/Player.cpp21
-rw-r--r--src/Entities/Player.h2
-rw-r--r--src/Entities/ProjectileEntity.cpp554
-rw-r--r--src/Entities/ProjectileEntity.h309
-rw-r--r--src/Entities/ThrownEggEntity.cpp59
-rw-r--r--src/Entities/ThrownEggEntity.h37
-rw-r--r--src/Entities/ThrownEnderPearlEntity.cpp54
-rw-r--r--src/Entities/ThrownEnderPearlEntity.h37
-rw-r--r--src/Entities/ThrownSnowballEntity.cpp48
-rw-r--r--src/Entities/ThrownSnowballEntity.h34
-rw-r--r--src/FastRandom.cpp3
-rw-r--r--src/Generating/Prefab.cpp2
-rw-r--r--src/Globals.h18
-rw-r--r--src/Item.h2
-rw-r--r--src/Items/ItemBow.h2
-rw-r--r--src/LineBlockTracer.cpp1
-rw-r--r--src/MCLogger.cpp14
-rw-r--r--src/MCLogger.h1
-rw-r--r--src/Mobs/AggressiveMonster.cpp17
-rw-r--r--src/Mobs/AggressiveMonster.h4
-rw-r--r--src/Mobs/Blaze.cpp1
-rw-r--r--src/Mobs/Creeper.cpp8
-rw-r--r--src/Mobs/Creeper.h2
-rw-r--r--src/Mobs/Ghast.cpp1
-rw-r--r--src/Mobs/Monster.cpp30
-rw-r--r--src/Mobs/Monster.h5
-rw-r--r--src/Mobs/PassiveAggressiveMonster.cpp8
-rw-r--r--src/Mobs/PassiveAggressiveMonster.h2
-rw-r--r--src/Mobs/PassiveMonster.cpp8
-rw-r--r--src/Mobs/PassiveMonster.h2
-rw-r--r--src/Mobs/Skeleton.cpp1
-rw-r--r--src/Mobs/Villager.cpp9
-rw-r--r--src/Mobs/Villager.h2
-rw-r--r--src/Mobs/Wither.cpp20
-rw-r--r--src/Mobs/Wither.h8
-rw-r--r--src/Mobs/Wolf.cpp9
-rw-r--r--src/Mobs/Wolf.h2
-rw-r--r--src/Noise.cpp4
-rw-r--r--src/OSSupport/BlockingTCPLink.cpp142
-rw-r--r--src/OSSupport/BlockingTCPLink.h28
-rw-r--r--src/OSSupport/File.cpp14
-rw-r--r--src/OSSupport/File.h4
-rw-r--r--src/OSSupport/GZipFile.cpp2
-rw-r--r--src/OSSupport/Socket.cpp10
-rw-r--r--src/PolarSSL++/AesCfb128Decryptor.cpp67
-rw-r--r--src/PolarSSL++/AesCfb128Decryptor.h52
-rw-r--r--src/PolarSSL++/AesCfb128Encryptor.cpp68
-rw-r--r--src/PolarSSL++/AesCfb128Encryptor.h50
-rw-r--r--src/PolarSSL++/BlockingSslClientSocket.cpp195
-rw-r--r--src/PolarSSL++/BlockingSslClientSocket.h80
-rw-r--r--src/PolarSSL++/BufferedSslContext.cpp62
-rw-r--r--src/PolarSSL++/BufferedSslContext.h52
-rw-r--r--src/PolarSSL++/CMakeLists.txt41
-rw-r--r--src/PolarSSL++/CallbackSslContext.cpp59
-rw-r--r--src/PolarSSL++/CallbackSslContext.h61
-rw-r--r--src/PolarSSL++/CtrDrbgContext.cpp49
-rw-r--r--src/PolarSSL++/CtrDrbgContext.h63
-rw-r--r--src/PolarSSL++/EntropyContext.cpp29
-rw-r--r--src/PolarSSL++/EntropyContext.h31
-rw-r--r--src/PolarSSL++/PublicKey.cpp73
-rw-r--r--src/PolarSSL++/PublicKey.h48
-rw-r--r--src/PolarSSL++/RsaPrivateKey.cpp176
-rw-r--r--src/PolarSSL++/RsaPrivateKey.h59
-rw-r--r--src/PolarSSL++/Sha1Checksum.cpp138
-rw-r--r--src/PolarSSL++/Sha1Checksum.h52
-rw-r--r--src/PolarSSL++/SslContext.cpp243
-rw-r--r--src/PolarSSL++/SslContext.h137
-rw-r--r--src/PolarSSL++/X509Cert.cpp38
-rw-r--r--src/PolarSSL++/X509Cert.h41
-rw-r--r--src/Protocol/Authenticator.cpp153
-rw-r--r--src/Protocol/Protocol125.cpp4
-rw-r--r--src/Protocol/Protocol132.cpp20
-rw-r--r--src/Protocol/Protocol132.h7
-rw-r--r--src/Protocol/Protocol17x.cpp19
-rw-r--r--src/Protocol/Protocol17x.h7
-rw-r--r--src/Server.h6
-rw-r--r--src/Statistics.cpp139
-rw-r--r--src/Statistics.h116
-rw-r--r--src/WebAdmin.cpp6
-rw-r--r--src/World.cpp80
-rw-r--r--src/World.h5
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp12
-rw-r--r--src/WorldStorage/WSSAnvil.cpp15
-rw-r--r--src/WorldStorage/WSSCompact.cpp11
120 files changed, 3985 insertions, 2375 deletions
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index 92b410481..b3f75aff1 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -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;
}
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index dcc816839..cb55715a6 100644
--- a/src/Bindings/PluginLua.cpp
+++ b/src/Bindings/PluginLua.cpp
@@ -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;
diff --git a/src/BiomeDef.cpp b/src/BiomeDef.cpp
index 3fba93e8a..9852b3dd9 100644
--- a/src/BiomeDef.cpp
+++ b/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[] =
- {
- {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++)
+ for (size_t i = 0; i < ARRAYCOUNT(g_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)
diff --git a/src/BiomeDef.h b/src/BiomeDef.h
index 474d4df76..67916890d 100644
--- a/src/BiomeDef.h
+++ b/src/BiomeDef.h
@@ -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);
diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp
index 68976ab7a..b4adca1fe 100644
--- a/src/BlockArea.cpp
+++ b/src/BlockArea.cpp
@@ -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)
- {
- 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)
+ else
{
- 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)
+}
+
+
diff --git a/src/BlockArea.h b/src/BlockArea.h
index d17a68fbb..7236f75e9 100644
--- a/src/BlockArea.h
+++ b/src/BlockArea.h
@@ -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
diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp
index 96ca0ac37..146ad915b 100644
--- a/src/BlockEntities/CommandBlockEntity.cpp
+++ b/src/BlockEntities/CommandBlockEntity.cpp
@@ -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)
{}
diff --git a/src/BlockEntities/MobHeadEntity.cpp b/src/BlockEntities/MobHeadEntity.cpp
index c0a1781f6..dc9c18d58 100644
--- a/src/BlockEntities/MobHeadEntity.cpp
+++ b/src/BlockEntities/MobHeadEntity.cpp
@@ -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("")
{
}
diff --git a/src/BlockID.cpp b/src/BlockID.cpp
index 79e122032..bf95d0798 100644
--- a/src/BlockID.cpp
+++ b/src/BlockID.cpp
@@ -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;
}
diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp
index 6fb5aa5b3..def98fdf5 100644
--- a/src/BlockInfo.cpp
+++ b/src/BlockInfo.cpp
@@ -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;
diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp
index c634dc308..c27bc4cad 100644
--- a/src/ByteBuffer.cpp
+++ b/src/ByteBuffer.cpp
@@ -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);
}
diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h
index 44f43e17f..7656a5b13 100644
--- a/src/ByteBuffer.h
+++ b/src/ByteBuffer.h
@@ -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;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9cc5fcb1e..900577526 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -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)
diff --git a/src/ChunkDef.h b/src/ChunkDef.h
index d7b09dd3a..d79f4b92b 100644
--- a/src/ChunkDef.h
+++ b/src/ChunkDef.h
@@ -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;
}
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index 16ad8e2a1..0bb1f6bd9 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -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()
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 63ae98be4..2362abe1e 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -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;
-
- 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);
+ AString Message = FormatMessageType(ShouldAppendChatPrefixes, a_ChatPrefix, a_AdditionalData);
- m_Protocol->SendChat(Message);
+ m_Protocol->SendChat(Message.append(a_Message));
}
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 3d01d8034..9f8d44129 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -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
diff --git a/src/Crypto.cpp b/src/Crypto.cpp
deleted file mode 100644
index 16be5ec35..000000000
--- a/src/Crypto.cpp
+++ /dev/null
@@ -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;
-}
-
-
-
-
diff --git a/src/Crypto.h b/src/Crypto.h
deleted file mode 100644
index a9ec2c6d4..000000000
--- a/src/Crypto.h
+++ /dev/null
@@ -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;
-} ;
-
-
-
-
diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp
new file mode 100644
index 000000000..847b39bbc
--- /dev/null
+++ b/src/Entities/ArrowEntity.cpp
@@ -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
+ }
+ }
+}
diff --git a/src/Entities/ArrowEntity.h b/src/Entities/ArrowEntity.h
new file mode 100644
index 000000000..1fe3032ee
--- /dev/null
+++ b/src/Entities/ArrowEntity.h
@@ -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
diff --git a/src/Entities/Boat.cpp b/src/Entities/Boat.cpp
index 921252253..31bfe3dc3 100644
--- a/src/Entities/Boat.cpp
+++ b/src/Entities/Boat.cpp
@@ -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;
}
diff --git a/src/Entities/Boat.h b/src/Entities/Boat.h
index c4c9afe7a..0fcfbd602 100644
--- a/src/Entities/Boat.h
+++ b/src/Entities/Boat.h
@@ -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;
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index d0dd6fb50..5c675a387 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -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)
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index 86efc5a98..a682701de 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -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;
diff --git a/src/Entities/ExpBottleEntity.cpp b/src/Entities/ExpBottleEntity.cpp
new file mode 100644
index 000000000..202dde942
--- /dev/null
+++ b/src/Entities/ExpBottleEntity.cpp
@@ -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();
+}
diff --git a/src/Entities/ExpBottleEntity.h b/src/Entities/ExpBottleEntity.h
new file mode 100644
index 000000000..b2043d8f1
--- /dev/null
+++ b/src/Entities/ExpBottleEntity.h
@@ -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
diff --git a/src/Entities/FallingBlock.cpp b/src/Entities/FallingBlock.cpp
index e57c45eaf..103e24b77 100644
--- a/src/Entities/FallingBlock.cpp
+++ b/src/Entities/FallingBlock.cpp
@@ -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();
}
diff --git a/src/Entities/FireChargeEntity.cpp b/src/Entities/FireChargeEntity.cpp
new file mode 100644
index 000000000..aba32602f
--- /dev/null
+++ b/src/Entities/FireChargeEntity.cpp
@@ -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
+}
diff --git a/src/Entities/FireChargeEntity.h b/src/Entities/FireChargeEntity.h
new file mode 100644
index 000000000..3924c337c
--- /dev/null
+++ b/src/Entities/FireChargeEntity.h
@@ -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
diff --git a/src/Entities/FireworkEntity.cpp b/src/Entities/FireworkEntity.cpp
new file mode 100644
index 000000000..403a53c84
--- /dev/null
+++ b/src/Entities/FireworkEntity.cpp
@@ -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++;
+}
diff --git a/src/Entities/FireworkEntity.h b/src/Entities/FireworkEntity.h
new file mode 100644
index 000000000..c62ca9402
--- /dev/null
+++ b/src/Entities/FireworkEntity.h
@@ -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
diff --git a/src/Entities/GhastFireballEntity.cpp b/src/Entities/GhastFireballEntity.cpp
new file mode 100644
index 000000000..9e4cb387e
--- /dev/null
+++ b/src/Entities/GhastFireballEntity.cpp
@@ -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));
+}
diff --git a/src/Entities/GhastFireballEntity.h b/src/Entities/GhastFireballEntity.h
new file mode 100644
index 000000000..9e4572c78
--- /dev/null
+++ b/src/Entities/GhastFireballEntity.h
@@ -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
diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp
index db55eb058..7bd440d6d 100644
--- a/src/Entities/Minecart.cpp
+++ b/src/Entities/Minecart.cpp
@@ -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;
}
diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h
index ebdb576e0..1e60f091c 100644
--- a/src/Entities/Minecart.h
+++ b/src/Entities/Minecart.h
@@ -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; }
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index fedb62527..08b7d3984 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -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;
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 78d661015..3029abfe0 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -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;
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index fd3e80e5f..3e48d310c 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -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
-}
-
-
-
-
diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h
index 731dd060e..ae06b072f 100644
--- a/src/Entities/ProjectileEntity.h
+++ b/src/Entities/ProjectileEntity.h
@@ -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
diff --git a/src/Entities/ThrownEggEntity.cpp b/src/Entities/ThrownEggEntity.cpp
new file mode 100644
index 000000000..224019091
--- /dev/null
+++ b/src/Entities/ThrownEggEntity.cpp
@@ -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);
+ }
+}
diff --git a/src/Entities/ThrownEggEntity.h b/src/Entities/ThrownEggEntity.h
new file mode 100644
index 000000000..5ba8f051b
--- /dev/null
+++ b/src/Entities/ThrownEggEntity.h
@@ -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
diff --git a/src/Entities/ThrownEnderPearlEntity.cpp b/src/Entities/ThrownEnderPearlEntity.cpp
new file mode 100644
index 000000000..c37161145
--- /dev/null
+++ b/src/Entities/ThrownEnderPearlEntity.cpp
@@ -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);
+ }
+}
diff --git a/src/Entities/ThrownEnderPearlEntity.h b/src/Entities/ThrownEnderPearlEntity.h
new file mode 100644
index 000000000..ddee5babe
--- /dev/null
+++ b/src/Entities/ThrownEnderPearlEntity.h
@@ -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
diff --git a/src/Entities/ThrownSnowballEntity.cpp b/src/Entities/ThrownSnowballEntity.cpp
new file mode 100644
index 000000000..427f630f7
--- /dev/null
+++ b/src/Entities/ThrownSnowballEntity.cpp
@@ -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);
+}
diff --git a/src/Entities/ThrownSnowballEntity.h b/src/Entities/ThrownSnowballEntity.h
new file mode 100644
index 000000000..a09512e37
--- /dev/null
+++ b/src/Entities/ThrownSnowballEntity.h
@@ -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
diff --git a/src/FastRandom.cpp b/src/FastRandom.cpp
index c45261947..42bf5f3f9 100644
--- a/src/FastRandom.cpp
+++ b/src/FastRandom.cpp
@@ -91,7 +91,8 @@ int cFastRandom::m_SeedCounter = 0;
cFastRandom::cFastRandom(void) :
- m_Seed(m_SeedCounter++)
+ m_Seed(m_SeedCounter++),
+ m_Counter(0)
{
}
diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp
index c0c9e8a13..44d5097de 100644
--- a/src/Generating/Prefab.cpp
+++ b/src/Generating/Prefab.cpp
@@ -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[]
diff --git a/src/Globals.h b/src/Globals.h
index 26a0d87a9..71e9191e4 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -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
diff --git a/src/Item.h b/src/Item.h
index 00316c188..641c681db 100644
--- a/src/Item.h
+++ b/src/Item.h
@@ -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);
}
diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h
index 410c5f512..8c0b3a0a3 100644
--- a/src/Items/ItemBow.h
+++ b/src/Items/ItemBow.h
@@ -9,7 +9,7 @@
#pragma once
-#include "../Entities/ProjectileEntity.h"
+#include "../Entities/ArrowEntity.h"
diff --git a/src/LineBlockTracer.cpp b/src/LineBlockTracer.cpp
index f4f29e833..b03652bab 100644
--- a/src/LineBlockTracer.cpp
+++ b/src/LineBlockTracer.cpp
@@ -171,7 +171,6 @@ bool cLineBlockTracer::MoveToNextBlock(void)
double CoeffZ = (DestZ - m_StartZ) / m_DiffZ;
if (CoeffZ < Coeff)
{
- Coeff = CoeffZ;
Direction = dirZ;
}
}
diff --git a/src/MCLogger.cpp b/src/MCLogger.cpp
index 80fa7b173..583438d65 100644
--- a/src/MCLogger.cpp
+++ b/src/MCLogger.cpp
@@ -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;
}
diff --git a/src/MCLogger.h b/src/MCLogger.h
index c0150c124..114210f63 100644
--- a/src/MCLogger.h
+++ b/src/MCLogger.h
@@ -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)
diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp
index 0901f85a9..447bf3549 100644
--- a/src/Mobs/AggressiveMonster.cpp
+++ b/src/Mobs/AggressiveMonster.cpp
@@ -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;
+}
diff --git a/src/Mobs/AggressiveMonster.h b/src/Mobs/AggressiveMonster.h
index 152260f95..d70ff04a3 100644
--- a/src/Mobs/AggressiveMonster.h
+++ b/src/Mobs/AggressiveMonster.h
@@ -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();
+
} ;
diff --git a/src/Mobs/Blaze.cpp b/src/Mobs/Blaze.cpp
index 84ff8929b..326b42f07 100644
--- a/src/Mobs/Blaze.cpp
+++ b/src/Mobs/Blaze.cpp
@@ -3,6 +3,7 @@
#include "Blaze.h"
#include "../World.h"
+#include "../Entities/FireChargeEntity.h"
diff --git a/src/Mobs/Creeper.cpp b/src/Mobs/Creeper.cpp
index 3471b4cf1..9cf539427 100644
--- a/src/Mobs/Creeper.cpp
+++ b/src/Mobs/Creeper.cpp
@@ -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;
}
diff --git a/src/Mobs/Creeper.h b/src/Mobs/Creeper.h
index 9abca369b..fc7db6716 100644
--- a/src/Mobs/Creeper.h
+++ b/src/Mobs/Creeper.h
@@ -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;
diff --git a/src/Mobs/Ghast.cpp b/src/Mobs/Ghast.cpp
index fe18f5e76..d8a7663f8 100644
--- a/src/Mobs/Ghast.cpp
+++ b/src/Mobs/Ghast.cpp
@@ -3,6 +3,7 @@
#include "Ghast.h"
#include "../World.h"
+#include "../Entities/GhastFireballEntity.h"
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index eb8480268..c66ab4e04 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -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;
diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h
index 70b3783fc..7d7e90eb2 100644
--- a/src/Mobs/Monster.h
+++ b/src/Mobs/Monster.h
@@ -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;
diff --git a/src/Mobs/PassiveAggressiveMonster.cpp b/src/Mobs/PassiveAggressiveMonster.cpp
index 4b45f9a2a..24501b1ba 100644
--- a/src/Mobs/PassiveAggressiveMonster.cpp
+++ b/src/Mobs/PassiveAggressiveMonster.cpp
@@ -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;
}
diff --git a/src/Mobs/PassiveAggressiveMonster.h b/src/Mobs/PassiveAggressiveMonster.h
index 2c5ef30b1..a0da50e8e 100644
--- a/src/Mobs/PassiveAggressiveMonster.h
+++ b/src/Mobs/PassiveAggressiveMonster.h
@@ -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;
} ;
diff --git a/src/Mobs/PassiveMonster.cpp b/src/Mobs/PassiveMonster.cpp
index 904cd63cc..2861d7314 100644
--- a/src/Mobs/PassiveMonster.cpp
+++ b/src/Mobs/PassiveMonster.cpp
@@ -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;
}
diff --git a/src/Mobs/PassiveMonster.h b/src/Mobs/PassiveMonster.h
index 0b3c155da..70574585a 100644
--- a/src/Mobs/PassiveMonster.h
+++ b/src/Mobs/PassiveMonster.h
@@ -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(); }
diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp
index 1685f40c5..1e62d7987 100644
--- a/src/Mobs/Skeleton.cpp
+++ b/src/Mobs/Skeleton.cpp
@@ -3,6 +3,7 @@
#include "Skeleton.h"
#include "../World.h"
+#include "../Entities/ArrowEntity.h"
diff --git a/src/Mobs/Villager.cpp b/src/Mobs/Villager.cpp
index d049acc1e..41283acf4 100644
--- a/src/Mobs/Villager.cpp
+++ b/src/Mobs/Villager.cpp
@@ -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;
}
diff --git a/src/Mobs/Villager.h b/src/Mobs/Villager.h
index 5bba4d4ba..abde48407 100644
--- a/src/Mobs/Villager.h
+++ b/src/Mobs/Villager.h
@@ -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
diff --git a/src/Mobs/Wither.cpp b/src/Mobs/Wither.cpp
index 8f5d28b68..5b6e895e1 100644
--- a/src/Mobs/Wither.cpp
+++ b/src/Mobs/Wither.cpp
@@ -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)
{
diff --git a/src/Mobs/Wither.h b/src/Mobs/Wither.h
index bc78bfaad..08b460009 100644
--- a/src/Mobs/Wither.h
+++ b/src/Mobs/Wither.h
@@ -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;
} ;
diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp
index f02b8a4fc..e6268abc7 100644
--- a/src/Mobs/Wolf.cpp
+++ b/src/Mobs/Wolf.cpp
@@ -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;
}
diff --git a/src/Mobs/Wolf.h b/src/Mobs/Wolf.h
index 5925373e1..fb8a7c995 100644
--- a/src/Mobs/Wolf.h
+++ b/src/Mobs/Wolf.h
@@ -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();
diff --git a/src/Noise.cpp b/src/Noise.cpp
index efbb128c3..13a194938 100644
--- a/src/Noise.cpp
+++ b/src/Noise.cpp
@@ -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++)
diff --git a/src/OSSupport/BlockingTCPLink.cpp b/src/OSSupport/BlockingTCPLink.cpp
deleted file mode 100644
index 07f48b955..000000000
--- a/src/OSSupport/BlockingTCPLink.cpp
+++ /dev/null
@@ -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);
- }
-}
-
-
-
-
diff --git a/src/OSSupport/BlockingTCPLink.h b/src/OSSupport/BlockingTCPLink.h
deleted file mode 100644
index cb5f9e3f4..000000000
--- a/src/OSSupport/BlockingTCPLink.h
+++ /dev/null
@@ -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
-
-
-
-
diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp
index 7f0f0ad2f..33b9cfc3f 100644
--- a/src/OSSupport/File.cpp
+++ b/src/OSSupport/File.cpp
@@ -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());
diff --git a/src/OSSupport/File.h b/src/OSSupport/File.h
index b394c5cb9..2a7ecf0ed 100644
--- a/src/OSSupport/File.h
+++ b/src/OSSupport/File.h
@@ -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);
diff --git a/src/OSSupport/GZipFile.cpp b/src/OSSupport/GZipFile.cpp
index 7a8433f4f..22d887783 100644
--- a/src/OSSupport/GZipFile.cpp
+++ b/src/OSSupport/GZipFile.cpp
@@ -11,7 +11,7 @@
cGZipFile::cGZipFile(void) :
- m_File(NULL)
+ m_File(NULL), m_Mode(fmRead)
{
}
diff --git a/src/OSSupport/Socket.cpp b/src/OSSupport/Socket.cpp
index c29e495c3..98f694a79 100644
--- a/src/OSSupport/Socket.cpp
+++ b/src/OSSupport/Socket.cpp
@@ -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;
diff --git a/src/PolarSSL++/AesCfb128Decryptor.cpp b/src/PolarSSL++/AesCfb128Decryptor.cpp
new file mode 100644
index 000000000..af0d5106e
--- /dev/null
+++ b/src/PolarSSL++/AesCfb128Decryptor.cpp
@@ -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];
+ }
+}
+
+
+
+
+
diff --git a/src/PolarSSL++/AesCfb128Decryptor.h b/src/PolarSSL++/AesCfb128Decryptor.h
new file mode 100644
index 000000000..68c203d70
--- /dev/null
+++ b/src/PolarSSL++/AesCfb128Decryptor.h
@@ -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;
+} ;
+
+
+
+
+
diff --git a/src/PolarSSL++/AesCfb128Encryptor.cpp b/src/PolarSSL++/AesCfb128Encryptor.cpp
new file mode 100644
index 000000000..a641ad48e
--- /dev/null
+++ b/src/PolarSSL++/AesCfb128Encryptor.cpp
@@ -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];
+ }
+}
+
+
+
+
+
diff --git a/src/PolarSSL++/AesCfb128Encryptor.h b/src/PolarSSL++/AesCfb128Encryptor.h
new file mode 100644
index 000000000..9dbb5d2c3
--- /dev/null
+++ b/src/PolarSSL++/AesCfb128Encryptor.h
@@ -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;
+} ;
+
+
+
+
+
diff --git a/src/PolarSSL++/BlockingSslClientSocket.cpp b/src/PolarSSL++/BlockingSslClientSocket.cpp
new file mode 100644
index 000000000..699bc57ee
--- /dev/null
+++ b/src/PolarSSL++/BlockingSslClientSocket.cpp
@@ -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;
+}
+
+
+
+
diff --git a/src/PolarSSL++/BlockingSslClientSocket.h b/src/PolarSSL++/BlockingSslClientSocket.h
new file mode 100644
index 000000000..7af897582
--- /dev/null
+++ b/src/PolarSSL++/BlockingSslClientSocket.h
@@ -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;
+} ;
+
+
+
+
diff --git a/src/PolarSSL++/BufferedSslContext.cpp b/src/PolarSSL++/BufferedSslContext.cpp
new file mode 100644
index 000000000..885b30c68
--- /dev/null
+++ b/src/PolarSSL++/BufferedSslContext.cpp
@@ -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;
+}
+
+
+
+
diff --git a/src/PolarSSL++/BufferedSslContext.h b/src/PolarSSL++/BufferedSslContext.h
new file mode 100644
index 000000000..1b7e1af46
--- /dev/null
+++ b/src/PolarSSL++/BufferedSslContext.h
@@ -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;
+} ;
+
+
+
+
diff --git a/src/PolarSSL++/CMakeLists.txt b/src/PolarSSL++/CMakeLists.txt
new file mode 100644
index 000000000..b0a592760
--- /dev/null
+++ b/src/PolarSSL++/CMakeLists.txt
@@ -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()
diff --git a/src/PolarSSL++/CallbackSslContext.cpp b/src/PolarSSL++/CallbackSslContext.cpp
new file mode 100644
index 000000000..0cc88a14a
--- /dev/null
+++ b/src/PolarSSL++/CallbackSslContext.cpp
@@ -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);
+}
+
+
+
+
+
diff --git a/src/PolarSSL++/CallbackSslContext.h b/src/PolarSSL++/CallbackSslContext.h
new file mode 100644
index 000000000..4e4c1ed7f
--- /dev/null
+++ b/src/PolarSSL++/CallbackSslContext.h
@@ -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;
+};
+
+
+
+
diff --git a/src/PolarSSL++/CtrDrbgContext.cpp b/src/PolarSSL++/CtrDrbgContext.cpp
new file mode 100644
index 000000000..86e6d1ca5
--- /dev/null
+++ b/src/PolarSSL++/CtrDrbgContext.cpp
@@ -0,0 +1,49 @@
+
+// CtrDrbgContext.cpp
+
+// Implements the cCtrDrbgContext class representing a wrapper over CTR-DRBG implementation in PolarSSL
+
+#include "Globals.h"
+#include "CtrDrbgContext.h"
+#include "EntropyContext.h"
+
+
+
+
+
+cCtrDrbgContext::cCtrDrbgContext(void) :
+ m_EntropyContext(new cEntropyContext),
+ m_IsValid(false)
+{
+}
+
+
+
+
+
+cCtrDrbgContext::cCtrDrbgContext(const SharedPtr<cEntropyContext> & a_EntropyContext) :
+ m_EntropyContext(a_EntropyContext),
+ m_IsValid(false)
+{
+}
+
+
+
+
+
+int cCtrDrbgContext::Initialize(const void * a_Custom, size_t a_CustomSize)
+{
+ if (m_IsValid)
+ {
+ // Already initialized
+ return 0;
+ }
+
+ int res = ctr_drbg_init(&m_CtrDrbg, entropy_func, &(m_EntropyContext->m_Entropy), (const unsigned char *)a_Custom, a_CustomSize);
+ m_IsValid = (res == 0);
+ return res;
+}
+
+
+
+
diff --git a/src/PolarSSL++/CtrDrbgContext.h b/src/PolarSSL++/CtrDrbgContext.h
new file mode 100644
index 000000000..65e9a2374
--- /dev/null
+++ b/src/PolarSSL++/CtrDrbgContext.h
@@ -0,0 +1,63 @@
+
+// CtrDrbgContext.h
+
+// Declares the cCtrDrbgContext class representing a wrapper over CTR-DRBG implementation in PolarSSL
+
+
+
+
+
+#pragma once
+
+#include "polarssl/ctr_drbg.h"
+
+
+
+
+
+// fwd: EntropyContext.h
+class cEntropyContext;
+
+
+
+
+
+class cCtrDrbgContext
+{
+ friend class cSslContext;
+ friend class cRsaPrivateKey;
+ friend class cPublicKey;
+
+public:
+ /** Constructs the context with a new entropy context. */
+ cCtrDrbgContext(void);
+
+ /** Constructs the context with the specified entropy context. */
+ cCtrDrbgContext(const SharedPtr<cEntropyContext> & a_EntropyContext);
+
+ /** Initializes the context.
+ a_Custom is optional additional data to use for entropy, nullptr is accepted.
+ Returns 0 if successful, PolarSSL error code on failure. */
+ int Initialize(const void * a_Custom, size_t a_CustomSize);
+
+ /** Returns true if the object is valid (has been initialized properly) */
+ bool IsValid(void) const { return m_IsValid; }
+
+protected:
+ /** The entropy source used for generating the random */
+ SharedPtr<cEntropyContext> m_EntropyContext;
+
+ /** The random generator context */
+ ctr_drbg_context m_CtrDrbg;
+
+ /** Set to true if the object is valid (has been initialized properly) */
+ bool m_IsValid;
+
+
+ /** Returns the internal context ptr. Only use in PolarSSL API calls. */
+ ctr_drbg_context * GetInternal(void) { return &m_CtrDrbg; }
+} ;
+
+
+
+
diff --git a/src/PolarSSL++/EntropyContext.cpp b/src/PolarSSL++/EntropyContext.cpp
new file mode 100644
index 000000000..9c59b3f11
--- /dev/null
+++ b/src/PolarSSL++/EntropyContext.cpp
@@ -0,0 +1,29 @@
+
+// EntropyContext.cpp
+
+// Implements the cEntropyContext class representing a wrapper over entropy contexts in PolarSSL
+
+#include "Globals.h"
+#include "EntropyContext.h"
+
+
+
+
+
+cEntropyContext::cEntropyContext(void)
+{
+ entropy_init(&m_Entropy);
+}
+
+
+
+
+
+cEntropyContext::~cEntropyContext()
+{
+ entropy_free(&m_Entropy);
+}
+
+
+
+
diff --git a/src/PolarSSL++/EntropyContext.h b/src/PolarSSL++/EntropyContext.h
new file mode 100644
index 000000000..bc7fff066
--- /dev/null
+++ b/src/PolarSSL++/EntropyContext.h
@@ -0,0 +1,31 @@
+
+// EntropyContext.h
+
+// Declares the cEntropyContext class representing a wrapper over entropy contexts in PolarSSL
+
+
+
+
+
+#pragma once
+
+#include "polarssl/entropy.h"
+
+
+
+
+
+class cEntropyContext
+{
+ friend class cCtrDrbgContext;
+public:
+ cEntropyContext(void);
+ ~cEntropyContext();
+
+protected:
+ entropy_context m_Entropy;
+} ;
+
+
+
+
diff --git a/src/PolarSSL++/PublicKey.cpp b/src/PolarSSL++/PublicKey.cpp
new file mode 100644
index 000000000..49794a0c8
--- /dev/null
+++ b/src/PolarSSL++/PublicKey.cpp
@@ -0,0 +1,73 @@
+
+// PublicKey.cpp
+
+// Implements the cPublicKey class representing a RSA public key in PolarSSL
+
+#include "Globals.h"
+#include "PublicKey.h"
+
+
+
+
+
+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;
+ }
+ m_CtrDrbg.Initialize("rsa_pubkey", 10);
+}
+
+
+
+
+
+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_CtrDrbg.GetInternal()
+ );
+ 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_CtrDrbg.GetInternal()
+ );
+ if (res != 0)
+ {
+ return res;
+ }
+ return (int)EncryptedLength;
+}
+
+
+
+
+
diff --git a/src/PolarSSL++/PublicKey.h b/src/PolarSSL++/PublicKey.h
new file mode 100644
index 000000000..5a0a57147
--- /dev/null
+++ b/src/PolarSSL++/PublicKey.h
@@ -0,0 +1,48 @@
+
+// PublicKey.h
+
+// Declares the cPublicKey class representing a RSA public key in PolarSSL
+
+
+
+
+
+#pragma once
+
+#include "CtrDrbgContext.h"
+#include "polarssl/pk.h"
+
+
+
+
+
+class cPublicKey
+{
+public:
+ /** Constructs the public key out of the DER-encoded pubkey data */
+ 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:
+ /** The public key PolarSSL representation */
+ pk_context m_Pk;
+
+ /** The random generator used in encryption and decryption */
+ cCtrDrbgContext m_CtrDrbg;
+} ;
+
+
+
+
+
diff --git a/src/PolarSSL++/RsaPrivateKey.cpp b/src/PolarSSL++/RsaPrivateKey.cpp
new file mode 100644
index 000000000..2d5a2a4b1
--- /dev/null
+++ b/src/PolarSSL++/RsaPrivateKey.cpp
@@ -0,0 +1,176 @@
+
+// RsaPrivateKey.cpp
+
+#include "Globals.h"
+#include "RsaPrivateKey.h"
+#include "CtrDrbgContext.h"
+#include "polarssl/pk.h"
+
+
+
+
+
+
+cRsaPrivateKey::cRsaPrivateKey(void)
+{
+ rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
+ m_CtrDrbg.Initialize("RSA", 3);
+}
+
+
+
+
+
+cRsaPrivateKey::cRsaPrivateKey(const cRsaPrivateKey & a_Other)
+{
+ rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
+ rsa_copy(&m_Rsa, &a_Other.m_Rsa);
+ m_CtrDrbg.Initialize("RSA", 3);
+}
+
+
+
+
+
+cRsaPrivateKey::~cRsaPrivateKey()
+{
+ rsa_free(&m_Rsa);
+}
+
+
+
+
+
+bool cRsaPrivateKey::Generate(unsigned a_KeySizeBits)
+{
+ int res = rsa_gen_key(&m_Rsa, ctr_drbg_random, m_CtrDrbg.GetInternal(), a_KeySizeBits, 65537);
+ if (res != 0)
+ {
+ LOG("RSA key generation failed: -0x%x", -res);
+ 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_CtrDrbg.GetInternal(), 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_CtrDrbg.GetInternal(), RSA_PRIVATE,
+ a_PlainLength, a_PlainData, a_EncryptedData
+ );
+ if (res != 0)
+ {
+ return -1;
+ }
+ return (int)m_Rsa.len;
+}
+
+
+
+
+
diff --git a/src/PolarSSL++/RsaPrivateKey.h b/src/PolarSSL++/RsaPrivateKey.h
new file mode 100644
index 000000000..ffacde11b
--- /dev/null
+++ b/src/PolarSSL++/RsaPrivateKey.h
@@ -0,0 +1,59 @@
+
+// RsaPrivateKey.h
+
+// Declares the cRsaPrivateKey class representing a private key for RSA operations.
+
+
+
+
+
+#pragma once
+
+#include "CtrDrbgContext.h"
+#include "polarssl/rsa.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:
+ /** The PolarSSL key context */
+ rsa_context m_Rsa;
+
+ /** The random generator used for generating the key and encryption / decryption */
+ cCtrDrbgContext m_CtrDrbg;
+} ;
+
+
+
+
+
diff --git a/src/PolarSSL++/Sha1Checksum.cpp b/src/PolarSSL++/Sha1Checksum.cpp
new file mode 100644
index 000000000..a1ee9d7b9
--- /dev/null
+++ b/src/PolarSSL++/Sha1Checksum.cpp
@@ -0,0 +1,138 @@
+
+// Sha1Checksum.cpp
+
+// Declares the cSha1Checksum class representing the SHA-1 checksum calculator
+
+#include "Globals.h"
+#include "Sha1Checksum.h"
+
+
+
+
+
+/*
+// Self-test the hash formatting for known values:
+// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48
+// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1
+// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6
+
+static 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;
+*/
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cSha1Checksum:
+
+cSha1Checksum::cSha1Checksum(void) :
+ m_DoesAcceptInput(true)
+{
+ sha1_starts(&m_Sha1);
+}
+
+
+
+
+
+void cSha1Checksum::Update(const Byte * a_Data, size_t a_Length)
+{
+ ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
+
+ sha1_update(&m_Sha1, a_Data, a_Length);
+}
+
+
+
+
+
+void cSha1Checksum::Finalize(cSha1Checksum::Checksum & a_Output)
+{
+ ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
+
+ sha1_finish(&m_Sha1, a_Output);
+ m_DoesAcceptInput = false;
+}
+
+
+
+
+
+void cSha1Checksum::DigestToJava(const Checksum & a_Digest, AString & a_Out)
+{
+ Checksum Digest;
+ memcpy(Digest, a_Digest, sizeof(Digest));
+
+ bool IsNegative = (Digest[0] >= 0x80);
+ if (IsNegative)
+ {
+ // Two's complement:
+ bool carry = true; // Add one to the whole number
+ for (int i = 19; i >= 0; i--)
+ {
+ Digest[i] = ~Digest[i];
+ if (carry)
+ {
+ carry = (Digest[i] == 0xff);
+ Digest[i]++;
+ }
+ }
+ }
+ a_Out.clear();
+ a_Out.reserve(40);
+ for (int i = 0; i < 20; i++)
+ {
+ AppendPrintf(a_Out, "%02x", Digest[i]);
+ }
+ while ((a_Out.length() > 0) && (a_Out[0] == '0'))
+ {
+ a_Out.erase(0, 1);
+ }
+ if (IsNegative)
+ {
+ a_Out.insert(0, "-");
+ }
+}
+
+
+
+
+
+
+void cSha1Checksum::Restart(void)
+{
+ sha1_starts(&m_Sha1);
+ m_DoesAcceptInput = true;
+}
+
+
+
+
diff --git a/src/PolarSSL++/Sha1Checksum.h b/src/PolarSSL++/Sha1Checksum.h
new file mode 100644
index 000000000..68fdbcf1b
--- /dev/null
+++ b/src/PolarSSL++/Sha1Checksum.h
@@ -0,0 +1,52 @@
+
+// Sha1Checksum.h
+
+// Declares the cSha1Checksum class representing the SHA-1 checksum calculator
+
+
+
+
+
+#pragma once
+
+#include "polarssl/sha1.h"
+
+
+
+
+
+/** Calculates a SHA1 checksum for data stream */
+class cSha1Checksum
+{
+public:
+ typedef Byte Checksum[20]; // The type used for storing the checksum
+
+ cSha1Checksum(void);
+
+ /** Adds the specified data to the checksum */
+ void Update(const Byte * a_Data, size_t a_Length);
+
+ /** Calculates and returns the final checksum */
+ void Finalize(Checksum & a_Output);
+
+ /** Returns true if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
+ bool DoesAcceptInput(void) const { return m_DoesAcceptInput; }
+
+ /** Converts a raw 160-bit SHA1 digest into a Java Hex representation
+ According to http://wiki.vg/wiki/index.php?title=Protocol_Encryption&oldid=2802
+ */
+ static void DigestToJava(const Checksum & a_Digest, AString & a_JavaOut);
+
+ /** Clears the current context and start a new checksum calculation */
+ void Restart(void);
+
+protected:
+ /** True if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
+ bool m_DoesAcceptInput;
+
+ sha1_context m_Sha1;
+} ;
+
+
+
+
diff --git a/src/PolarSSL++/SslContext.cpp b/src/PolarSSL++/SslContext.cpp
new file mode 100644
index 000000000..1994cf844
--- /dev/null
+++ b/src/PolarSSL++/SslContext.cpp
@@ -0,0 +1,243 @@
+
+// SslContext.cpp
+
+// Implements the cSslContext class that holds everything a single SSL context needs to function
+
+#include "Globals.h"
+#include "SslContext.h"
+#include "EntropyContext.h"
+#include "CtrDrbgContext.h"
+
+
+
+
+
+cSslContext::cSslContext(void) :
+ m_IsValid(false),
+ m_HasHandshaken(false)
+{
+}
+
+
+
+
+
+cSslContext::~cSslContext()
+{
+ if (m_IsValid)
+ {
+ ssl_free(&m_Ssl);
+ }
+}
+
+
+
+
+
+int cSslContext::Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> & a_CtrDrbg)
+{
+ // Check double-initialization:
+ if (m_IsValid)
+ {
+ LOGWARNING("SSL: Double initialization is not supported.");
+ return POLARSSL_ERR_SSL_MALLOC_FAILED; // There is no return value well-suited for this, reuse this one.
+ }
+
+ // Set the CtrDrbg context, create a new one if needed:
+ m_CtrDrbg = a_CtrDrbg;
+ if (m_CtrDrbg.get() == NULL)
+ {
+ m_CtrDrbg.reset(new cCtrDrbgContext);
+ m_CtrDrbg->Initialize("MCServer", 8);
+ }
+
+ // Initialize PolarSSL's structures:
+ memset(&m_Ssl, 0, sizeof(m_Ssl));
+ int res = ssl_init(&m_Ssl);
+ if (res != 0)
+ {
+ return res;
+ }
+ ssl_set_endpoint(&m_Ssl, a_IsClient ? SSL_IS_CLIENT : SSL_IS_SERVER);
+ ssl_set_authmode(&m_Ssl, SSL_VERIFY_OPTIONAL);
+ ssl_set_rng(&m_Ssl, ctr_drbg_random, &m_CtrDrbg->m_CtrDrbg);
+ ssl_set_bio(&m_Ssl, ReceiveEncrypted, this, SendEncrypted, this);
+
+ #ifdef _DEBUG
+ /*
+ // These functions allow us to debug SSL and certificate problems, but produce way too much output,
+ // so they're disabled until someone needs them
+ ssl_set_dbg(&m_Ssl, &SSLDebugMessage, this);
+ ssl_set_verify(&m_Ssl, &SSLVerifyCert, this);
+ */
+ #endif
+
+ m_IsValid = true;
+ return 0;
+}
+
+
+
+
+
+void cSslContext::SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName)
+{
+ // Store the data in our internal buffers, to avoid losing the pointers later on
+ // PolarSSL will need these after this call returns, and the caller may move / delete the data before that:
+ m_ExpectedPeerName = a_ExpectedPeerName;
+ m_CACerts = a_CACert;
+
+ // Set the trusted CA root cert store:
+ ssl_set_authmode(&m_Ssl, SSL_VERIFY_REQUIRED);
+ ssl_set_ca_chain(&m_Ssl, m_CACerts->GetInternal(), NULL, m_ExpectedPeerName.empty() ? NULL : m_ExpectedPeerName.c_str());
+}
+
+
+
+
+
+int cSslContext::WritePlain(const void * a_Data, size_t a_NumBytes)
+{
+ ASSERT(m_IsValid); // Need to call Initialize() first
+ if (!m_HasHandshaken)
+ {
+ int res = Handshake();
+ if (res != 0)
+ {
+ return res;
+ }
+ }
+
+ return ssl_write(&m_Ssl, (const unsigned char *)a_Data, a_NumBytes);
+}
+
+
+
+
+
+int cSslContext::ReadPlain(void * a_Data, size_t a_MaxBytes)
+{
+ ASSERT(m_IsValid); // Need to call Initialize() first
+ if (!m_HasHandshaken)
+ {
+ int res = Handshake();
+ if (res != 0)
+ {
+ return res;
+ }
+ }
+
+ return ssl_read(&m_Ssl, (unsigned char *)a_Data, a_MaxBytes);
+}
+
+
+
+
+
+int cSslContext::Handshake(void)
+{
+ ASSERT(m_IsValid); // Need to call Initialize() first
+ ASSERT(!m_HasHandshaken); // Must not call twice
+
+ int res = ssl_handshake(&m_Ssl);
+ if (res == 0)
+ {
+ m_HasHandshaken = true;
+ }
+ return res;
+}
+
+
+
+
+
+int cSslContext::NotifyClose(void)
+{
+ return ssl_close_notify(&m_Ssl);
+}
+
+
+
+
+
+#ifdef _DEBUG
+ void cSslContext::SSLDebugMessage(void * a_UserParam, int a_Level, const char * a_Text)
+ {
+ if (a_Level > 3)
+ {
+ // Don't want the trace messages
+ return;
+ }
+
+ // Remove the terminating LF:
+ size_t len = strlen(a_Text) - 1;
+ while ((len > 0) && (a_Text[len] <= 32))
+ {
+ len--;
+ }
+ AString Text(a_Text, len + 1);
+
+ LOGD("SSL (%d): %s", a_Level, Text.c_str());
+ }
+
+
+
+
+
+ int cSslContext::SSLVerifyCert(void * a_This, x509_crt * a_Crt, int a_Depth, int * a_Flags)
+ {
+ char buf[1024];
+ UNUSED(a_This);
+
+ LOG("Verify requested for (Depth %d):", a_Depth);
+ x509_crt_info(buf, sizeof(buf) - 1, "", a_Crt);
+ LOG("%s", buf);
+
+ int Flags = *a_Flags;
+ if ((Flags & BADCERT_EXPIRED) != 0)
+ {
+ LOG(" ! server certificate has expired");
+ }
+
+ if ((Flags & BADCERT_REVOKED) != 0)
+ {
+ LOG(" ! server certificate has been revoked");
+ }
+
+ if ((Flags & BADCERT_CN_MISMATCH) != 0)
+ {
+ LOG(" ! CN mismatch");
+ }
+
+ if ((Flags & BADCERT_NOT_TRUSTED) != 0)
+ {
+ LOG(" ! self-signed or not signed by a trusted CA");
+ }
+
+ if ((Flags & BADCRL_NOT_TRUSTED) != 0)
+ {
+ LOG(" ! CRL not trusted");
+ }
+
+ if ((Flags & BADCRL_EXPIRED) != 0)
+ {
+ LOG(" ! CRL expired");
+ }
+
+ if ((Flags & BADCERT_OTHER) != 0)
+ {
+ LOG(" ! other (unknown) flag");
+ }
+
+ if (Flags == 0)
+ {
+ LOG(" This certificate has no flags");
+ }
+
+ return 0;
+ }
+#endif // _DEBUG
+
+
+
+
diff --git a/src/PolarSSL++/SslContext.h b/src/PolarSSL++/SslContext.h
new file mode 100644
index 000000000..85add5f8b
--- /dev/null
+++ b/src/PolarSSL++/SslContext.h
@@ -0,0 +1,137 @@
+
+// SslContext.h
+
+// Declares the cSslContext class that holds everything a single SSL context needs to function
+
+
+
+
+
+#pragma once
+
+#include "polarssl/ssl.h"
+#include "../ByteBuffer.h"
+#include "X509Cert.h"
+
+
+
+
+
+// fwd:
+class cCtrDrbgContext;
+
+
+
+
+
+/**
+Acts as a generic SSL encryptor / decryptor between the two endpoints. The "owner" of this class is expected
+to create it, initialize it and then provide the means of reading and writing data through the SSL link.
+This is an abstract base class, there are descendants that handle the specific aspects of how the SSL peer
+data comes into the system:
+ - cBufferedSslContext uses a cByteBuffer to read and write the data
+ - cCallbackSslContext uses callbacks to provide the data
+*/
+class cSslContext abstract
+{
+public:
+ /** Creates a new uninitialized context */
+ cSslContext(void);
+
+ ~cSslContext();
+
+ /** Initializes the context for use as a server or client.
+ Returns 0 on success, PolarSSL error on failure. */
+ int Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> & a_CtrDrbg = SharedPtr<cCtrDrbgContext>());
+
+ /** Returns true if the object has been initialized properly. */
+ bool IsValid(void) const { return m_IsValid; }
+
+ /** Sets a cert chain as the trusted cert store for this context.
+ Calling this will switch the context into strict cert verification mode.
+ a_ExpectedPeerName is the CommonName that we expect the SSL peer to have in its cert,
+ if it is different, the verification will fail. An empty string will disable the CN check. */
+ void SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName);
+
+ /** Writes data to be encrypted and sent to the SSL peer. Will perform SSL handshake, if needed.
+ Returns the number of bytes actually written, or PolarSSL error code.
+ If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any
+ cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call
+ this function again with the same parameters. Note that this may repeat a few times before the data is
+ actually written, mainly due to initial handshake. */
+ int WritePlain(const void * a_Data, size_t a_NumBytes);
+
+ /** Reads data decrypted from the SSL stream. Will perform SSL handshake, if needed.
+ Returns the number of bytes actually read, or PolarSSL error code.
+ If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any
+ cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call
+ this function again with the same parameters. Note that this may repeat a few times before the data is
+ actually read, mainly due to initial handshake. */
+ int ReadPlain(void * a_Data, size_t a_MaxBytes);
+
+ /** Performs the SSL handshake.
+ Returns zero on success, PoladSSL error code on failure.
+ If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any
+ cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call
+ this function again. Note that this may repeat a few times before the handshake is completed. */
+ int Handshake(void);
+
+ /** Returns true if the SSL handshake has been completed. */
+ bool HasHandshaken(void) const { return m_HasHandshaken; }
+
+ /** Notifies the SSL peer that the connection is being closed.
+ Returns 0 on success, PolarSSL error code on failure. */
+ int NotifyClose(void);
+
+protected:
+ /** True if the object has been initialized properly. */
+ bool m_IsValid;
+
+ /** The random generator to use */
+ SharedPtr<cCtrDrbgContext> m_CtrDrbg;
+
+ /** The SSL context that PolarSSL uses. */
+ ssl_context m_Ssl;
+
+ /** True if the SSL handshake has been completed. */
+ bool m_HasHandshaken;
+
+ /** A copy of the trusted CA root cert store that is passed to us in SetCACerts(), so that the pointer
+ stays valid even after the call, when PolarSSL finally uses it. */
+ cX509CertPtr m_CACerts;
+
+ /** Buffer for the expected peer name. We need to buffer it because the caller may free the string they
+ give us before PolarSSL consumes the raw pointer it gets to the CN. */
+ AString m_ExpectedPeerName;
+
+
+ /** The callback used by PolarSSL when it wants to read encrypted data. */
+ static int ReceiveEncrypted(void * a_This, unsigned char * a_Buffer, size_t a_NumBytes)
+ {
+ return ((cSslContext *)a_This)->ReceiveEncrypted(a_Buffer, a_NumBytes);
+ }
+
+ /** The callback used by PolarSSL when it wants to write encrypted data. */
+ static int SendEncrypted(void * a_This, const unsigned char * a_Buffer, size_t a_NumBytes)
+ {
+ return ((cSslContext *)a_This)->SendEncrypted(a_Buffer, a_NumBytes);
+ }
+
+ #ifdef _DEBUG
+ /** The callback used by PolarSSL to output debug messages */
+ static void SSLDebugMessage(void * a_UserParam, int a_Level, const char * a_Text);
+
+ /** The callback used by PolarSSL to log information on the cert chain */
+ static int SSLVerifyCert(void * a_This, x509_crt * a_Crt, int a_Depth, int * a_Flags);
+ #endif // _DEBUG
+
+ /** Called when PolarSSL wants to read encrypted data. */
+ virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) = 0;
+
+ /** Called when PolarSSL wants to write encrypted data. */
+ virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) = 0;
+} ;
+
+
+
+
diff --git a/src/PolarSSL++/X509Cert.cpp b/src/PolarSSL++/X509Cert.cpp
new file mode 100644
index 000000000..ecf664855
--- /dev/null
+++ b/src/PolarSSL++/X509Cert.cpp
@@ -0,0 +1,38 @@
+
+// X509Cert.cpp
+
+// Implements the cX509Cert class representing a wrapper over X509 certs in PolarSSL
+
+#include "Globals.h"
+#include "X509Cert.h"
+
+
+
+
+
+cX509Cert::cX509Cert(void)
+{
+ x509_crt_init(&m_Cert);
+}
+
+
+
+
+
+cX509Cert::~cX509Cert()
+{
+ x509_crt_free(&m_Cert);
+}
+
+
+
+
+
+int cX509Cert::Parse(const void * a_CertContents, size_t a_Size)
+{
+ return x509_crt_parse(&m_Cert, (const unsigned char *)a_CertContents, a_Size);
+}
+
+
+
+
diff --git a/src/PolarSSL++/X509Cert.h b/src/PolarSSL++/X509Cert.h
new file mode 100644
index 000000000..991617d24
--- /dev/null
+++ b/src/PolarSSL++/X509Cert.h
@@ -0,0 +1,41 @@
+
+// X509Cert.h
+
+// Declares the cX509Cert class representing a wrapper over X509 certs in PolarSSL
+
+
+
+
+
+#pragma once
+
+#include "polarssl/x509_crt.h"
+
+
+
+
+
+class cX509Cert
+{
+ friend class cSslContext;
+
+public:
+ cX509Cert(void);
+ ~cX509Cert(void);
+
+ /** Parses the certificate chain data into the context.
+ Returns 0 on succes, or PolarSSL error code on failure. */
+ int Parse(const void * a_CertContents, size_t a_Size);
+
+protected:
+ x509_crt m_Cert;
+
+ /** Returns the internal cert ptr. Only use in PolarSSL API calls. */
+ x509_crt * GetInternal(void) { return &m_Cert; }
+} ;
+
+typedef SharedPtr<cX509Cert> cX509CertPtr;
+
+
+
+
diff --git a/src/Protocol/Authenticator.cpp b/src/Protocol/Authenticator.cpp
index e0fcc0007..41d614e58 100644
--- a/src/Protocol/Authenticator.cpp
+++ b/src/Protocol/Authenticator.cpp
@@ -2,7 +2,6 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Authenticator.h"
-#include "../OSSupport/BlockingTCPLink.h"
#include "../Root.h"
#include "../Server.h"
#include "../ClientHandle.h"
@@ -10,13 +9,7 @@
#include "inifile/iniFile.h"
#include "json/json.h"
-#include "polarssl/config.h"
-#include "polarssl/net.h"
-#include "polarssl/ssl.h"
-#include "polarssl/entropy.h"
-#include "polarssl/ctr_drbg.h"
-#include "polarssl/error.h"
-#include "polarssl/certs.h"
+#include "PolarSSL++/BlockingSslClientSocket.h"
#include <sstream>
#include <iomanip>
@@ -148,66 +141,74 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
{
LOGD("Trying to auth user %s", a_UserName.c_str());
- int ret, server_fd = -1;
+ int ret;
unsigned char buf[1024];
- const char *pers = "cAuthenticator";
-
- entropy_context entropy;
- ctr_drbg_context ctr_drbg;
- ssl_context ssl;
- x509_crt cacert;
-
- /* Initialize the RNG and the session data */
- memset(&ssl, 0, sizeof(ssl_context));
- x509_crt_init(&cacert);
-
- entropy_init(&entropy);
- if ((ret = ctr_drbg_init(&ctr_drbg, entropy_func, &entropy, (const unsigned char *)pers, strlen(pers))) != 0)
- {
- LOGWARNING("cAuthenticator: ctr_drbg_init returned %d", ret);
- return false;
- }
/* Initialize certificates */
- // TODO: Grab the sessionserver's root CA and any intermediates and hard-code them here, instead of test_ca_list
- ret = x509_crt_parse(&cacert, (const unsigned char *)test_ca_list, strlen(test_ca_list));
-
- if (ret < 0)
- {
- LOGWARNING("cAuthenticator: x509_crt_parse returned -0x%x", -ret);
- return false;
- }
-
- /* Connect */
- if ((ret = net_connect(&server_fd, m_Server.c_str(), 443)) != 0)
- {
- LOGWARNING("cAuthenticator: Can't connect to %s: %d", m_Server.c_str(), ret);
- return false;
- }
-
- /* Setup */
- if ((ret = ssl_init(&ssl)) != 0)
+ // This is the data of the root certs for Starfield Technologies, the CA that signed sessionserver.mojang.com's cert:
+ // Downloaded from http://certs.starfieldtech.com/repository/
+ static const AString StarfieldCACert(
+ // G2 cert
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx\n"
+ "EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT\n"
+ "HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs\n"
+ "ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw\n"
+ "MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6\n"
+ "b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj\n"
+ "aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp\n"
+ "Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n"
+ "ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg\n"
+ "nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1\n"
+ "HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N\n"
+ "Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN\n"
+ "dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0\n"
+ "HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO\n"
+ "BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G\n"
+ "CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU\n"
+ "sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3\n"
+ "4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg\n"
+ "8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K\n"
+ "pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1\n"
+ "mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0\n"
+ "-----END CERTIFICATE-----\n\n"
+ // Original (G1) cert:
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl\n"
+ "MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp\n"
+ "U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw\n"
+ "NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE\n"
+ "ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp\n"
+ "ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3\n"
+ "DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf\n"
+ "8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN\n"
+ "+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0\n"
+ "X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa\n"
+ "K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA\n"
+ "1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G\n"
+ "A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR\n"
+ "zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0\n"
+ "YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD\n"
+ "bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w\n"
+ "DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3\n"
+ "L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D\n"
+ "eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl\n"
+ "xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp\n"
+ "VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY\n"
+ "WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=\n"
+ "-----END CERTIFICATE-----\n"
+ );
+
+ // Connect the socket:
+ cBlockingSslClientSocket Socket;
+ Socket.SetTrustedRootCertsFromString(StarfieldCACert, m_Server);
+ if (!Socket.Connect(m_Server, 443))
{
- LOGWARNING("cAuthenticator: ssl_init returned %d", ret);
+ LOGWARNING("cAuthenticator: Can't connect to %s: %s", m_Server.c_str(), Socket.GetLastErrorText().c_str());
return false;
}
- ssl_set_endpoint(&ssl, SSL_IS_CLIENT);
- ssl_set_authmode(&ssl, SSL_VERIFY_OPTIONAL);
- ssl_set_ca_chain(&ssl, &cacert, NULL, "PolarSSL Server 1");
- ssl_set_rng(&ssl, ctr_drbg_random, &ctr_drbg);
- ssl_set_bio(&ssl, net_recv, &server_fd, net_send, &server_fd);
-
- /* Handshake */
- while ((ret = ssl_handshake(&ssl)) != 0)
- {
- if ((ret != POLARSSL_ERR_NET_WANT_READ) && (ret != POLARSSL_ERR_NET_WANT_WRITE))
- {
- LOGWARNING("cAuthenticator: ssl_handshake returned -0x%x", -ret);
- return false;
- }
- }
- /* Write the GET request */
+ // Create the GET request:
AString ActualAddress = m_Address;
ReplaceString(ActualAddress, "%USERNAME%", a_UserName);
ReplaceString(ActualAddress, "%SERVERID%", a_ServerId);
@@ -219,23 +220,23 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
Request += "Connection: close\r\n";
Request += "\r\n";
- ret = ssl_write(&ssl, (const unsigned char *)Request.c_str(), Request.size());
- if (ret <= 0)
+ if (!Socket.Send(Request.c_str(), Request.size()))
{
- LOGWARNING("cAuthenticator: ssl_write returned %d", ret);
+ LOGWARNING("cAuthenticator: Writing SSL data failed: %s", Socket.GetLastErrorText().c_str());
return false;
}
- /* Read the HTTP response */
+ // Read the HTTP response:
std::string Response;
for (;;)
{
- memset(buf, 0, sizeof(buf));
- ret = ssl_read(&ssl, buf, sizeof(buf));
+ ret = Socket.Receive(buf, sizeof(buf));
if ((ret == POLARSSL_ERR_NET_WANT_READ) || (ret == POLARSSL_ERR_NET_WANT_WRITE))
{
- continue;
+ // This value should never be returned, it is handled internally by cBlockingSslClientSocket
+ LOGWARNING("cAuthenticator: SSL reading failed internally.");
+ return false;
}
if (ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY)
{
@@ -243,24 +244,18 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
}
if (ret < 0)
{
- LOGWARNING("cAuthenticator: ssl_read returned %d", ret);
- break;
+ LOGWARNING("cAuthenticator: SSL reading failed: -0x%x", -ret);
+ return false;
}
if (ret == 0)
{
- LOGWARNING("cAuthenticator: EOF");
break;
}
- Response.append((const char *)buf, ret);
- }
+ Response.append((const char *)buf, (size_t)ret);
+ }
- ssl_close_notify(&ssl);
- x509_crt_free(&cacert);
- net_close(server_fd);
- ssl_free(&ssl);
- entropy_free(&entropy);
- memset(&ssl, 0, sizeof(ssl));
+ Socket.Disconnect();
// Check the HTTP status line:
AString prefix("HTTP/1.1 200 OK");
diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp
index 3282a827f..35ab72bfc 100644
--- a/src/Protocol/Protocol125.cpp
+++ b/src/Protocol/Protocol125.cpp
@@ -26,7 +26,7 @@ Documentation:
#include "../Root.h"
#include "../Server.h"
-#include "../Entities/ProjectileEntity.h"
+#include "../Entities/ArrowEntity.h"
#include "../Entities/Minecart.h"
#include "../Entities/FallingBlock.h"
@@ -2013,7 +2013,7 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob)
case cMonster::mtWither:
{
WriteByte(0x54); // Int at index 20
- WriteInt((Int32)((const cWither &)a_Mob).GetNumInvulnerableTicks());
+ WriteInt((Int32)((const cWither &)a_Mob).GetWitherInvulnerableTicks());
WriteByte(0x66); // Float at index 6
WriteFloat((float)(a_Mob.GetHealth()));
break;
diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp
index 53d8c1561..f4717f592 100644
--- a/src/Protocol/Protocol132.cpp
+++ b/src/Protocol/Protocol132.cpp
@@ -18,19 +18,7 @@
#include "../WorldStorage/FastNBT.h"
#include "../WorldStorage/EnchantmentSerializer.h"
#include "../StringCompression.h"
-
-#ifdef _MSC_VER
- #pragma warning(push)
- #pragma warning(disable:4127)
- #pragma warning(disable:4244)
- #pragma warning(disable:4231)
- #pragma warning(disable:4189)
- #pragma warning(disable:4702)
-#endif
-
-#ifdef _MSC_VER
- #pragma warning(pop)
-#endif
+#include "PolarSSL++/Sha1Checksum.h"
@@ -819,7 +807,7 @@ void cProtocol132::SendEncryptionKeyRequest(void)
void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce)
{
// Decrypt EncNonce using privkey
- cRSAPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
+ cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
int res = rsaDecryptor.Decrypt((const Byte *)a_EncNonce.data(), a_EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce));
@@ -876,7 +864,7 @@ void cProtocol132::StartEncryption(const Byte * a_Key)
m_IsEncrypted = true;
// Prepare the m_AuthServerID:
- cSHA1Checksum Checksum;
+ cSha1Checksum Checksum;
cServer * Server = cRoot::Get()->GetServer();
AString ServerID = Server->GetServerID();
Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length());
@@ -884,7 +872,7 @@ void cProtocol132::StartEncryption(const Byte * a_Key)
Checksum.Update((const Byte *)Server->GetPublicKeyDER().data(), Server->GetPublicKeyDER().size());
Byte Digest[20];
Checksum.Finalize(Digest);
- cSHA1Checksum::DigestToJava(Digest, m_AuthServerID);
+ cSha1Checksum::DigestToJava(Digest, m_AuthServerID);
}
diff --git a/src/Protocol/Protocol132.h b/src/Protocol/Protocol132.h
index b280c8a41..32bc7d581 100644
--- a/src/Protocol/Protocol132.h
+++ b/src/Protocol/Protocol132.h
@@ -24,7 +24,8 @@
#pragma warning(pop)
#endif
-#include "../Crypto.h"
+#include "PolarSSL++/AesCfb128Decryptor.h"
+#include "PolarSSL++/AesCfb128Encryptor.h"
@@ -79,8 +80,8 @@ public:
protected:
bool m_IsEncrypted;
- cAESCFBDecryptor m_Decryptor;
- cAESCFBEncryptor m_Encryptor;
+ cAesCfb128Decryptor m_Decryptor;
+ cAesCfb128Encryptor m_Encryptor;
AString m_DataToSend;
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index e57b551cb..a6d566625 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -31,6 +31,9 @@ Implements the 1.7.x protocol classes:
#include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/FlowerPotEntity.h"
#include "../CompositeChat.h"
+#include "../Entities/ArrowEntity.h"
+#include "../Entities/FireworkEntity.h"
+#include "PolarSSL++/Sha1Checksum.h"
@@ -637,9 +640,11 @@ void cProtocol172::SendLoginSuccess(void)
{
ASSERT(m_State == 2); // State: login?
- cPacketizer Pkt(*this, 0x02); // Login success packet
- Pkt.WriteString(m_Client->GetUUID());
- Pkt.WriteString(m_Client->GetUsername());
+ {
+ cPacketizer Pkt(*this, 0x02); // Login success packet
+ Pkt.WriteString(m_Client->GetUUID());
+ Pkt.WriteString(m_Client->GetUsername());
+ }
m_State = 3; // State = Game
}
@@ -1686,7 +1691,7 @@ void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe
}
// Decrypt EncNonce using privkey
- cRSAPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
+ cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
int res = rsaDecryptor.Decrypt((const Byte *)EncNonce.data(), EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce));
if (res != 4)
@@ -2289,7 +2294,7 @@ void cProtocol172::StartEncryption(const Byte * a_Key)
m_IsEncrypted = true;
// Prepare the m_AuthServerID:
- cSHA1Checksum Checksum;
+ cSha1Checksum Checksum;
cServer * Server = cRoot::Get()->GetServer();
const AString & ServerID = Server->GetServerID();
Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length());
@@ -2297,7 +2302,7 @@ void cProtocol172::StartEncryption(const Byte * a_Key)
Checksum.Update((const Byte *)Server->GetPublicKeyDER().data(), Server->GetPublicKeyDER().size());
Byte Digest[20];
Checksum.Finalize(Digest);
- cSHA1Checksum::DigestToJava(Digest, m_AuthServerID);
+ cSha1Checksum::DigestToJava(Digest, m_AuthServerID);
}
@@ -2820,7 +2825,7 @@ void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob)
case cMonster::mtWither:
{
WriteByte(0x54); // Int at index 20
- WriteInt(((const cWither &)a_Mob).GetNumInvulnerableTicks());
+ WriteInt(((const cWither &)a_Mob).GetWitherInvulnerableTicks());
WriteByte(0x66); // Float at index 6
WriteFloat((float)(a_Mob.GetHealth()));
break;
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index 6a3e81eff..3f9c93357 100644
--- a/src/Protocol/Protocol17x.h
+++ b/src/Protocol/Protocol17x.h
@@ -30,7 +30,8 @@ Declares the 1.7.x protocol classes:
#pragma warning(pop)
#endif
-#include "../Crypto.h"
+#include "PolarSSL++/AesCfb128Decryptor.h"
+#include "PolarSSL++/AesCfb128Encryptor.h"
@@ -236,8 +237,8 @@ protected:
bool m_IsEncrypted;
- cAESCFBDecryptor m_Decryptor;
- cAESCFBEncryptor m_Encryptor;
+ cAesCfb128Decryptor m_Decryptor;
+ cAesCfb128Decryptor m_Encryptor;
/** The logfile where the comm is logged, when g_ShouldLogComm is true */
cFile m_CommLogFile;
diff --git a/src/Server.h b/src/Server.h
index 51c450ebd..3d76c8ccf 100644
--- a/src/Server.h
+++ b/src/Server.h
@@ -23,7 +23,7 @@
#pragma warning(disable:4702)
#endif
-#include "Crypto.h"
+#include "PolarSSL++/RsaPrivateKey.h"
#ifdef _MSC_VER
#pragma warning(pop)
@@ -109,7 +109,7 @@ public: // tolua_export
/** Returns base64 encoded favicon data (obtained from favicon.png) */
const AString & GetFaviconData(void) const { return m_FaviconData; }
- cRSAPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
+ cRsaPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
const AString & GetPublicKeyDER(void) const { return m_PublicKeyDER; }
bool ShouldAuthenticate(void) const { return m_ShouldAuthenticate; }
@@ -182,7 +182,7 @@ private:
bool m_bRestarting;
/** The private key used for the assymetric encryption start in the protocols */
- cRSAPrivateKey m_PrivateKey;
+ cRsaPrivateKey m_PrivateKey;
/** Public key for m_PrivateKey, ASN1-DER-encoded */
AString m_PublicKeyDER;
diff --git a/src/Statistics.cpp b/src/Statistics.cpp
new file mode 100644
index 000000000..2c980d98e
--- /dev/null
+++ b/src/Statistics.cpp
@@ -0,0 +1,139 @@
+
+// Statistics.cpp
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Statistics.h"
+
+
+
+cStatInfo cStatInfo::ms_Info[statCount] = {
+ // The order must match the order of enum eStatistic
+
+ // http://minecraft.gamepedia.com/Achievements
+
+ /* Type | Name | Prerequisite */
+ cStatInfo(achOpenInv, "openInventory"),
+ cStatInfo(achMineWood, "mineWood", achOpenInv),
+ cStatInfo(achCraftWorkbench, "buildWorkBench", achMineWood),
+ cStatInfo(achCraftPickaxe, "buildPickaxe", achCraftWorkbench),
+ cStatInfo(achCraftFurnace, "buildFurnace", achCraftPickaxe),
+ cStatInfo(achAcquireIron, "acquireIron", achCraftFurnace),
+ cStatInfo(achCraftHoe, "buildHoe", achCraftWorkbench),
+ cStatInfo(achMakeBread, "makeBread", achCraftHoe),
+ cStatInfo(achBakeCake, "bakeCake", achCraftHoe),
+ cStatInfo(achCraftBetterPick, "buildBetterPickaxe", achCraftPickaxe),
+ cStatInfo(achCookFish, "cookFish", achAcquireIron),
+ cStatInfo(achOnARail, "onARail", achAcquireIron),
+ cStatInfo(achCraftSword, "buildSword", achCraftWorkbench),
+ cStatInfo(achKillMonster, "killEnemy", achCraftSword),
+ cStatInfo(achKillCow, "killCow", achCraftSword),
+ cStatInfo(achFlyPig, "flyPig", achKillCow),
+ cStatInfo(achSnipeSkeleton, "snipeSkeleton", achKillMonster),
+ cStatInfo(achDiamonds, "diamonds", achAcquireIron),
+ cStatInfo(achEnterPortal, "portal", achDiamonds),
+ cStatInfo(achReturnToSender, "ghast", achEnterPortal),
+ cStatInfo(achBlazeRod, "blazeRod", achEnterPortal),
+ cStatInfo(achBrewPotion, "potion", achBlazeRod),
+ cStatInfo(achEnterTheEnd, "theEnd", achBlazeRod),
+ cStatInfo(achDefeatDragon, "theEnd2", achEnterTheEnd),
+ cStatInfo(achCraftEnchantTable, "enchantments", achDiamonds),
+ cStatInfo(achOverkill, "overkill", achCraftEnchantTable),
+ cStatInfo(achBookshelf, "bookcase", achCraftEnchantTable),
+ cStatInfo(achExploreAllBiomes, "exploreAllBiomes", achEnterTheEnd),
+ cStatInfo(achSpawnWither, "spawnWither", achDefeatDragon),
+ cStatInfo(achKillWither, "killWither", achSpawnWither),
+ cStatInfo(achFullBeacon, "fullBeacon", achKillWither),
+ cStatInfo(achBreedCow, "breedCow", achKillCow),
+ cStatInfo(achThrowDiamonds, "diamondsToYou", achDiamonds),
+
+ // http://minecraft.gamepedia.com/Statistics
+
+ /* Type | Name */
+ cStatInfo(statGamesQuit, "stat.leaveGame"),
+ cStatInfo(statMinutesPlayed, "stat.playOneMinute"),
+ cStatInfo(statDistWalked, "stat.walkOnCm"),
+ cStatInfo(statDistSwum, "stat.swimOneCm"),
+ cStatInfo(statDistFallen, "stat.fallOneCm"),
+ cStatInfo(statDistClimbed, "stat.climbOneCm"),
+ cStatInfo(statDistFlown, "stat.flyOneCm"),
+ cStatInfo(statDistMinecart, "stat.minecartOneCm"),
+ cStatInfo(statDistBoat, "stat.boatOneCm"),
+ cStatInfo(statDistPig, "stat.pigOneCm"),
+ cStatInfo(statDistHorse, "stat.horseOneCm"),
+ cStatInfo(statJumps, "stat.jump"),
+ cStatInfo(statItemsDropped, "stat.drop"),
+ cStatInfo(statDamageDealt, "stat.damageDealth"),
+ cStatInfo(statDamageTaken, "stat.damageTaken"),
+ cStatInfo(statDeaths, "stat.deaths"),
+ cStatInfo(statMobKills, "stat.mobKills"),
+ cStatInfo(statAnimalsBred, "stat.animalsBred"),
+ cStatInfo(statPlayerKills, "stat.playerKills"),
+ cStatInfo(statFishCaught, "stat.fishCaught"),
+ cStatInfo(statJunkFished, "stat.junkFished"),
+ cStatInfo(statTreasureFished, "stat.treasureFished")
+};
+
+
+
+
+
+
+cStatInfo::cStatInfo()
+ : m_Type(statInvalid)
+ , m_Depends(statInvalid)
+{}
+
+
+
+
+
+cStatInfo::cStatInfo(const eStatistic a_Type, const AString & a_Name, const eStatistic a_Depends)
+ : m_Type(a_Type)
+ , m_Name(a_Name)
+ , m_Depends(a_Depends)
+{}
+
+
+
+
+
+const AString & cStatInfo::GetName(const eStatistic a_Type)
+{
+ ASSERT((a_Type > statInvalid) && (a_Type < statCount));
+
+ return ms_Info[a_Type].m_Name;
+}
+
+
+
+
+
+eStatistic cStatInfo::GetType(const AString & a_Name)
+{
+ for (unsigned int i = 0; i < ARRAYCOUNT(ms_Info); ++i)
+ {
+ if (NoCaseCompare(ms_Info[i].m_Name, a_Name))
+ {
+ return ms_Info[i].m_Type;
+ }
+ }
+
+ return statInvalid;
+}
+
+
+
+
+
+eStatistic cStatInfo::GetPrerequisite(const eStatistic a_Type)
+{
+ ASSERT((a_Type > statInvalid) && (a_Type < statCount));
+
+ return ms_Info[a_Type].m_Depends;
+}
+
+
+
+
+
diff --git a/src/Statistics.h b/src/Statistics.h
new file mode 100644
index 000000000..540df38cc
--- /dev/null
+++ b/src/Statistics.h
@@ -0,0 +1,116 @@
+
+// Statistics.h
+
+
+
+
+#pragma once
+
+
+
+
+enum eStatistic
+{
+ // The order must match the order of cStatInfo::ms_Info
+
+ statInvalid = -1,
+
+ /* Achievements */
+ achOpenInv, /* Taking Inventory */
+ achMineWood, /* Getting Wood */
+ achCraftWorkbench, /* Benchmarking */
+ achCraftPickaxe, /* Time to Mine! */
+ achCraftFurnace, /* Hot Topic */
+ achAcquireIron, /* Acquire Hardware */
+ achCraftHoe, /* Time to Farm! */
+ achMakeBread, /* Bake Bread */
+ achBakeCake, /* The Lie */
+ achCraftBetterPick, /* Getting an Upgrade */
+ achCookFish, /* Delicious Fish */
+ achOnARail, /* On A Rail */
+ achCraftSword, /* Time to Strike! */
+ achKillMonster, /* Monster Hunter */
+ achKillCow, /* Cow Tipper */
+ achFlyPig, /* When Pigs Fly */
+ achSnipeSkeleton, /* Sniper Duel */
+ achDiamonds, /* DIAMONDS! */
+ achEnterPortal, /* We Need to Go Deeper */
+ achReturnToSender, /* Return to Sender */
+ achBlazeRod, /* Into Fire */
+ achBrewPotion, /* Local Brewery */
+ achEnterTheEnd, /* The End? */
+ achDefeatDragon, /* The End. */
+ achCraftEnchantTable, /* Enchanter */
+ achOverkill, /* Overkill */
+ achBookshelf, /* Librarian */
+ achExploreAllBiomes, /* Adventuring Time */
+ achSpawnWither, /* The Beginning? */
+ achKillWither, /* The Beginning. */
+ achFullBeacon, /* Beaconator */
+ achBreedCow, /* Repopulation */
+ achThrowDiamonds, /* Diamonds to you! */
+
+ /* Statistics */
+ statGamesQuit,
+ statMinutesPlayed,
+ statDistWalked,
+ statDistSwum,
+ statDistFallen,
+ statDistClimbed,
+ statDistFlown,
+ statDistDove,
+ statDistMinecart,
+ statDistBoat,
+ statDistPig,
+ statDistHorse,
+ statJumps,
+ statItemsDropped,
+ statDamageDealt,
+ statDamageTaken,
+ statDeaths,
+ statMobKills,
+ statAnimalsBred,
+ statPlayerKills,
+ statFishCaught,
+ statJunkFished,
+ statTreasureFished,
+
+ statCount
+};
+
+
+
+
+
+
+/** Class used to store and query statistic-related information. */
+class cStatInfo
+{
+public:
+
+ cStatInfo();
+
+ cStatInfo(const eStatistic a_Type, const AString & a_Name, const eStatistic a_Depends = statInvalid);
+
+ /** Type -> Name */
+ static const AString & GetName(const eStatistic a_Type);
+
+ /** Name -> Type */
+ static eStatistic GetType(const AString & a_Name);
+
+ /** Returns stat prerequisite. (Used for achievements) */
+ static eStatistic GetPrerequisite(const eStatistic a_Type);
+
+private:
+
+ eStatistic m_Type;
+
+ AString m_Name;
+
+ eStatistic m_Depends;
+
+ static cStatInfo ms_Info[statCount];
+};
+
+
+
diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp
index a3b3cc5be..08e164d78 100644
--- a/src/WebAdmin.cpp
+++ b/src/WebAdmin.cpp
@@ -89,6 +89,7 @@ bool cWebAdmin::Init(void)
m_IniFile.AddHeaderComment(" Password format: Password=*password*; for example:");
m_IniFile.AddHeaderComment(" [User:admin]");
m_IniFile.AddHeaderComment(" Password=admin");
+ m_IniFile.WriteFile("webadmin.ini");
}
if (!m_IniFile.GetValueSetB("WebAdmin", "Enabled", true))
@@ -285,11 +286,6 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque
Content = GetDefaultPage();
}
- if (ShouldWrapInTemplate && (URL.size() > 1))
- {
- Content += "\n<p><a href='" + BaseURL + "'>Go back</a></p>";
- }
-
int MemUsageKiB = cRoot::GetPhysicalRAMUsage();
if (MemUsageKiB > 0)
{
diff --git a/src/World.cpp b/src/World.cpp
index 25ac9b021..5ac8e0a6e 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -316,12 +316,9 @@ int cWorld::GetDefaultWeatherInterval(eWeather a_Weather)
{
return 2400 + (m_TickRand.randInt() % 4800); // 2 - 6 minutes
}
- default:
- {
- LOGWARNING("%s: Missing default weather interval for weather %d.", __FUNCTION__, a_Weather);
- return -1;
- }
- } // switch (Weather)
+ }
+ LOGWARNING("%s: Missing default weather interval for weather %d.", __FUNCTION__, a_Weather);
+ return -1;
}
@@ -521,21 +518,6 @@ void cWorld::Start(void)
}
AString Dimension = IniFile.GetValueSet("General", "Dimension", "Overworld");
m_Dimension = StringToDimension(Dimension);
- switch (m_Dimension)
- {
- case dimNether:
- case dimOverworld:
- case dimEnd:
- {
- break;
- }
- default:
- {
- LOGWARNING("Unknown dimension: \"%s\". Setting to Overworld", Dimension.c_str());
- m_Dimension = dimOverworld;
- break;
- }
- } // switch (m_Dimension)
// Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found
int KeyNum = IniFile.FindKey("SpawnPosition");
@@ -592,12 +574,6 @@ void cWorld::Start(void)
case dimOverworld: DefaultMonsters = "bat, cavespider, chicken, cow, creeper, enderman, horse, mooshroom, ocelot, pig, sheep, silverfish, skeleton, slime, spider, squid, wolf, zombie"; break;
case dimNether: DefaultMonsters = "blaze, ghast, magmacube, skeleton, zombie, zombiepigman"; break;
case dimEnd: DefaultMonsters = "enderman"; break;
- default:
- {
- ASSERT(!"Unhandled world dimension");
- DefaultMonsters = "wither";
- break;
- }
}
m_bAnimals = IniFile.GetValueSetB("Monsters", "AnimalsOn", true);
AString AllMonsters = IniFile.GetValueSet("Monsters", "Types", DefaultMonsters);
@@ -687,6 +663,30 @@ void cWorld::GenerateRandomSpawn(void)
+eWeather cWorld::ChooseNewWeather()
+{
+ // Pick a new weather. Only reasonable transitions allowed:
+ switch (m_Weather)
+ {
+ case eWeather_Sunny:
+ case eWeather_ThunderStorm: return eWeather_Rain;
+
+ case eWeather_Rain:
+ {
+ // 1/8 chance of turning into a thunderstorm
+ return ((m_TickRand.randInt() % 256) < 32) ? eWeather_ThunderStorm : eWeather_Sunny;
+ }
+ }
+
+ LOGWARNING("Unknown current weather: %d. Setting sunny.", m_Weather);
+ ASSERT(!"Unknown weather");
+ return eWeather_Sunny;
+}
+
+
+
+
+
void cWorld::Stop(void)
{
// Delete the clients that have been in this world:
@@ -786,30 +786,8 @@ void cWorld::TickWeather(float a_Dt)
else
{
// Change weather:
-
- // Pick a new weather. Only reasonable transitions allowed:
- eWeather NewWeather = m_Weather;
- switch (m_Weather)
- {
- case eWeather_Sunny: NewWeather = eWeather_Rain; break;
- case eWeather_ThunderStorm: NewWeather = eWeather_Rain; break;
- case eWeather_Rain:
- {
- // 1/8 chance of turning into a thunderstorm
- NewWeather = ((m_TickRand.randInt() % 256) < 32) ? eWeather_ThunderStorm : eWeather_Sunny;
- break;
- }
-
- default:
- {
- LOGWARNING("Unknown current weather: %d. Setting sunny.", m_Weather);
- ASSERT(!"Unknown weather");
- NewWeather = eWeather_Sunny;
- }
- }
-
- SetWeather(NewWeather);
- } // else (m_WeatherInterval > 0)
+ SetWeather(ChooseNewWeather());
+ }
if (m_Weather == eWeather_ThunderStorm)
{
diff --git a/src/World.h b/src/World.h
index e2be4cd35..f789916df 100644
--- a/src/World.h
+++ b/src/World.h
@@ -938,7 +938,10 @@ private:
/** <summary>Generates a random spawnpoint on solid land by walking chunks and finding their biomes</summary> */
void GenerateRandomSpawn(void);
-
+
+ /** Chooses a reasonable transition from the current weather to a new weather **/
+ eWeather ChooseNewWeather(void);
+
/** Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section) */
cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock);
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index 01c3aed2b..7f9b51d87 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -28,7 +28,7 @@
#include "../Entities/Boat.h"
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
-#include "../Entities/ProjectileEntity.h"
+#include "../Entities/ArrowEntity.h"
#include "../Entities/TNTEntity.h"
#include "../Entities/ExpOrb.h"
#include "../Entities/HangingEntity.h"
@@ -516,7 +516,7 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
}
case cMonster::mtWither:
{
- m_Writer.AddInt("Invul", ((const cWither *)a_Monster)->GetNumInvulnerableTicks());
+ m_Writer.AddInt("Invul", ((const cWither *)a_Monster)->GetWitherInvulnerableTicks());
break;
}
case cMonster::mtWolf:
@@ -621,10 +621,10 @@ void cNBTChunkSerializer::AddHangingEntity(cHangingEntity * a_Hanging)
m_Writer.AddInt("TileZ", a_Hanging->GetTileZ());
switch (a_Hanging->GetDirection())
{
- case 0: m_Writer.AddByte("Dir", (unsigned char)2); break;
- case 1: m_Writer.AddByte("Dir", (unsigned char)1); break;
- case 2: m_Writer.AddByte("Dir", (unsigned char)0); break;
- case 3: m_Writer.AddByte("Dir", (unsigned char)3); break;
+ case BLOCK_FACE_YM: m_Writer.AddByte("Dir", (unsigned char)2); break;
+ case BLOCK_FACE_YP: m_Writer.AddByte("Dir", (unsigned char)1); break;
+ case BLOCK_FACE_ZM: m_Writer.AddByte("Dir", (unsigned char)0); break;
+ case BLOCK_FACE_ZP: m_Writer.AddByte("Dir", (unsigned char)3); break;
}
}
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index 66144dbd5..f33178173 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -27,7 +27,6 @@
#include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/FlowerPotEntity.h"
-
#include "../Mobs/Monster.h"
#include "../Mobs/IncludeAllMonsters.h"
@@ -36,7 +35,12 @@
#include "../Entities/FallingBlock.h"
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
-#include "../Entities/ProjectileEntity.h"
+#include "../Entities/ArrowEntity.h"
+#include "../Entities/ThrownEggEntity.h"
+#include "../Entities/ThrownEnderPearlEntity.h"
+#include "../Entities/ThrownSnowballEntity.h"
+#include "../Entities/FireChargeEntity.h"
+#include "../Entities/GhastFireballEntity.h"
#include "../Entities/TNTEntity.h"
#include "../Entities/ExpOrb.h"
#include "../Entities/HangingEntity.h"
@@ -2272,7 +2276,7 @@ void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a
int CurrLine = a_NBT.FindChildByName(a_TagIdx, "Invul");
if (CurrLine > 0)
{
- Monster->SetNumInvulnerableTicks(a_NBT.GetInt(CurrLine));
+ Monster->SetWitherInvulnerableTicks(a_NBT.GetInt(CurrLine));
}
a_Entities.push_back(Monster.release());
@@ -2668,6 +2672,11 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri
return false;
}
+ // Add padding to 4K boundary:
+ size_t BytesWritten = a_Data.size() + MCA_CHUNK_HEADER_LENGTH;
+ static const char Padding[4095] = {0};
+ m_File.Write(Padding, 4096 - (BytesWritten % 4096));
+
// Store the header:
ChunkSize = (a_Data.size() + MCA_CHUNK_HEADER_LENGTH + 4095) / 4096; // Round data size *up* to nearest 4KB sector, make it a sector number
ASSERT(ChunkSize < 256);
diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp
index e6c0163ed..b770c24c0 100644
--- a/src/WorldStorage/WSSCompact.cpp
+++ b/src/WorldStorage/WSSCompact.cpp
@@ -466,7 +466,15 @@ cWSSCompact::cPAKFile::cPAKFile(const AString & a_FileName, int a_LayerX, int a_
for (int i = 0; i < NumChunks; i++)
{
sChunkHeader * Header = new sChunkHeader;
- READ(*Header);
+
+ // Here we do not use the READ macro, as it does not free the resources
+ // allocated with new in case of error.
+ if (f.Read(Header, sizeof(*Header)) != sizeof(*Header))
+ {
+ LOGERROR("ERROR READING %s FROM FILE %s (line %d); file offset %d", "Header", m_FileName.c_str(), __LINE__, f.Tell());
+ delete Header;
+ return;
+ }
m_ChunkHeaders.push_back(Header);
} // for i - chunk headers
@@ -795,7 +803,6 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
++index2;
}
InChunkOffset += index2 / 2;
- index2 = 0;
AString Converted(ConvertedData, ExpectedSize);