1
0

Merge branch 'master' into HTTPSizeT

This commit is contained in:
Tycho 2014-04-02 06:37:24 -07:00
commit 741a64c250
14 changed files with 375 additions and 18 deletions

View File

@ -200,6 +200,8 @@ g_APIDesc =
msFillAir = { Notes = "Dst is overwritten by Src only where Src has air blocks" },
msImprint = { Notes = "Src overwrites Dst anywhere where Dst has non-air blocks" },
msLake = { Notes = "Special mode for merging lake images" },
msSpongePrint = { Notes = "Similar to msImprint, sponge block doesn't overwrite anything, all other blocks overwrite everything"},
msMask = { Notes = "The blocks that are exactly the same are kept in Dst, all differing blocks are replaced by air"},
},
ConstantGroups =
{
@ -247,6 +249,9 @@ g_APIDesc =
<tr>
<td> A </td><td> B </td><td> B </td><td> A </td><td> B </td>
</tr>
<tr>
<td> A </td><td> A </td><td> A </td><td> A </td><td> A </td>
</td>
</tbody></table>
<p>
@ -261,6 +266,19 @@ g_APIDesc =
<h3>Special strategies</h3>
<p>For each strategy, evaluate the table rows from top downwards, the first match wins.</p>
<p>
<strong>msDifference</strong> - changes all the blocks which are the same to air. Otherwise the source block gets placed.
</p>
<table><tbody<tr>
<th colspan="2"> area block </th><th> </th><th> Notes </th>
</tr><tr>
<td> * </td><td> B </td><td> B </td><td> The blocks are different so we use block B </td>
</tr><tr>
<td> B </td><td> B </td><td> Air </td><td> The blocks are the same so we get air. </td>
</tr>
</tbody></table>
<p>
<strong>msLake</strong> - used for merging areas with lava and water lakes, in the appropriate generator.
</p>
@ -293,7 +311,6 @@ g_APIDesc =
</tr>
</tbody></table>
<p>
<strong>msSpongePrint</strong> - used for most prefab-generators to merge the prefabs. Similar to
msImprint, but uses the sponge block as the NOP block instead, so that the prefabs may carve out air
@ -309,7 +326,23 @@ g_APIDesc =
<td> * </td><td> B </td><td> B </td><td> Everything else overwrites anything </td>
</tr>
</tbody></table>
]],
<p>
<strong>msMask</strong> - the blocks that are the same in the other area are kept, all the
differing blocks are replaced with air. Meta is used in the comparison, too, two blocks of the
same type but different meta are considered different and thus replaced with air.
</p>
<table><tbody><tr>
<th colspan="2"> area block </th><th> </th><th> Notes </th>
</tr><tr>
<th> this </th><th> Src </th><th> result </th><th> </th>
</tr><tr>
<td> A </td><td> A </td><td> A </td><td> Same blocks are kept </td>
</tr><tr>
<td> A </td><td> non-A </td><td> air </td><td> Differing blocks are replaced with air </td>
</tr>
</tbody></table>
]],
}, -- Merge strategies
}, -- AdditionalInfo
}, -- cBlockArea

View File

@ -69,12 +69,13 @@ function Initialize(Plugin)
LOG("Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
-- TestBlockAreas();
-- TestSQLiteBindings();
-- TestExpatBindings();
-- TestPluginCalls();
-- TestBlockAreas()
-- TestSQLiteBindings()
-- TestExpatBindings()
-- TestPluginCalls()
TestBlockAreasString()
TestStringBase64()
--[[
-- Test cCompositeChat usage in console-logging:
@ -252,6 +253,24 @@ end
function TestStringBase64()
-- Create a binary string:
local s = ""
for i = 0, 255 do
s = s .. string.char(i)
end
-- Roundtrip through Base64:
local Base64 = Base64Encode(s)
local UnBase64 = Base64Decode(Base64)
assert(UnBase64 == s)
end
function TestSQLiteBindings()
LOG("Testing SQLite bindings...");

View File

@ -190,6 +190,50 @@ static int tolua_LOGERROR(lua_State * tolua_S)
static int tolua_Base64Encode(lua_State * tolua_S)
{
cLuaState L(tolua_S);
if (
!L.CheckParamString(1) ||
!L.CheckParamEnd(2)
)
{
return 0;
}
AString Src;
L.GetStackValue(1, Src);
AString res = Base64Encode(Src);
L.Push(res);
return 1;
}
static int tolua_Base64Decode(lua_State * tolua_S)
{
cLuaState L(tolua_S);
if (
!L.CheckParamString(1) ||
!L.CheckParamEnd(2)
)
{
return 0;
}
AString Src;
L.GetStackValue(1, Src);
AString res = Base64Decode(Src);
L.Push(res);
return 1;
}
cPluginLua * GetLuaPlugin(lua_State * L)
{
// Get the plugin identification out of LuaState:
@ -2869,6 +2913,8 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "LOGWARN", tolua_LOGWARN);
tolua_function(tolua_S, "LOGWARNING", tolua_LOGWARN);
tolua_function(tolua_S, "LOGERROR", tolua_LOGERROR);
tolua_function(tolua_S, "Base64Encode", tolua_Base64Encode);
tolua_function(tolua_S, "Base64Decode", tolua_Base64Decode);
tolua_beginmodule(tolua_S, "cFile");
tolua_function(tolua_S, "GetFolderContents", tolua_cFile_GetFolderContents);

View File

@ -173,6 +173,40 @@ 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)
{
if ((a_DstType == a_SrcType) && (a_DstMeta == a_SrcMeta))
{
a_DstType = E_BLOCK_AIR;
a_DstMeta = 0;
}
else
{
a_DstType = a_SrcType;
a_DstMeta = a_SrcMeta;
}
}
/** Combinator used for cBlockArea::msMask merging */
static inline 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))
{
a_DstType = E_BLOCK_AIR;
a_DstMeta = 0;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cBlockArea:
@ -710,6 +744,36 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R
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);

View File

@ -52,6 +52,8 @@ public:
msImprint,
msLake,
msSpongePrint,
msDifference,
msMask,
} ;
cBlockArea(void);
@ -153,6 +155,14 @@ public:
| A | sponge | A | Sponge is the NOP block
| * | B | B | Everything else overwrites anything
msMask:
Combines two areas, the blocks that are the same are kept, differing ones are reset to air
| area block | |
| this | Src | result |
+------+-------+--------+
| A | A | A | Same blocks are kept
| A | non-A | air | Everything else is replaced with air
*/
void Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy);

View File

@ -22,14 +22,99 @@ public:
a_Pickups.push_back(cItem(E_ITEM_HEAD, 1, 0));
}
bool TrySpawnWither(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
bool TrySpawnWither(cChunkInterface & a_ChunkInterface, cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ)
{
if (a_BlockY < 2)
{
return false;
}
// TODO 2014-03-24 xdot
class cCallback : public cMobHeadCallback
{
bool m_IsWither;
virtual bool Item (cMobHeadEntity * a_MobHeadEntity)
{
m_IsWither = (a_MobHeadEntity->GetType() == SKULL_TYPE_WITHER);
return false;
}
public:
cCallback () : m_IsWither(false) {}
bool IsWither(void) const { return m_IsWither; }
void Reset(void) { m_IsWither = false; }
} CallbackA, CallbackB;
a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, CallbackA);
if (!CallbackA.IsWither())
{
return false;
}
CallbackA.Reset();
BLOCKTYPE BlockY1 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
BLOCKTYPE BlockY2 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ);
if ((BlockY1 != E_BLOCK_SOULSAND) || (BlockY2 != E_BLOCK_SOULSAND))
{
return false;
}
a_World->DoWithMobHeadAt(a_BlockX - 1, a_BlockY, a_BlockZ, CallbackA);
a_World->DoWithMobHeadAt(a_BlockX + 1, a_BlockY, a_BlockZ, CallbackB);
BLOCKTYPE Block1 = a_ChunkInterface.GetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ);
BLOCKTYPE Block2 = a_ChunkInterface.GetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ);
if ((Block1 == E_BLOCK_SOULSAND) && (Block2 == E_BLOCK_SOULSAND) && CallbackA.IsWither() && CallbackB.IsWither())
{
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
// Block entities
a_World->SetBlock(a_BlockX + 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
a_World->SetBlock(a_BlockX - 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
// Spawn the wither:
a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither);
return true;
}
CallbackA.Reset();
CallbackB.Reset();
a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ - 1, CallbackA);
a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ + 1, CallbackB);
Block1 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1);
Block2 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1);
if ((Block1 == E_BLOCK_SOULSAND) && (Block2 == E_BLOCK_SOULSAND) && CallbackA.IsWither() && CallbackB.IsWither())
{
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
// Block entities
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ + 1, E_BLOCK_AIR, 0);
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ - 1, E_BLOCK_AIR, 0);
// Spawn the wither:
a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither);
return true;
}
return false;
}
@ -75,7 +160,24 @@ public:
World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta);
TrySpawnWither(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
if (a_BlockMeta == SKULL_TYPE_WITHER)
{
static const Vector3i Coords[] =
{
Vector3i( 0, 0, 0),
Vector3i( 1, 0, 0),
Vector3i(-1, 0, 0),
Vector3i( 0, 0, 1),
Vector3i( 0, 0, -1),
};
for (size_t i = 0; i < ARRAYCOUNT(Coords); ++i)
{
if (TrySpawnWither(a_ChunkInterface, World, a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z))
{
break;
}
} // for i - Coords[]
}
}
} ;

View File

@ -13,8 +13,27 @@ cWither::cWither(void) :
m_InvulnerableTicks(220)
{
SetMaxHealth(300);
}
bool cWither::IsArmored(void) const
{
return GetHealth() <= (GetMaxHealth() / 2);
}
bool cWither::Initialize(cWorld * a_World)
{
// Set health before BroadcastSpawnEntity()
SetHealth(GetMaxHealth() / 3);
return super::Initialize(a_World);
}
@ -33,6 +52,11 @@ void cWither::DoTakeDamage(TakeDamageInfo & a_TDI)
return;
}
if (IsArmored() && (a_TDI.DamageType == dtRangedAttack))
{
return;
}
super::DoTakeDamage(a_TDI);
}
@ -60,6 +84,8 @@ void cWither::Tick(float a_Dt, cChunk & a_Chunk)
Heal(10);
}
}
m_World->BroadcastEntityMetadata(*this);
}

View File

@ -21,7 +21,11 @@ public:
void SetNumInvulnerableTicks(unsigned int a_Ticks) { m_InvulnerableTicks = a_Ticks; }
/** Returns whether the wither is invulnerable to arrows. */
bool IsArmored(void) const;
// 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 void Tick(float a_Dt, cChunk & a_Chunk) override;

View File

@ -1951,6 +1951,14 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob)
WriteByte(((const cWitch &)a_Mob).IsAngry() ? 1 : 0); // Aggravated? Doesn't seem to do anything
break;
}
case cMonster::mtWither:
{
WriteByte(0x54); // Int at index 20
WriteInt(((const cWither &)a_Mob).GetNumInvulnerableTicks());
WriteByte(0x66); // Float at index 6
WriteFloat((float)(a_Mob.GetHealth()));
break;
}
case cMonster::mtSlime:
case cMonster::mtMagmaCube:
{

View File

@ -2535,6 +2535,7 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
WriteByte(Frame.GetRotation());
break;
}
default: break;
}
}
@ -2660,6 +2661,15 @@ void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob)
break;
}
case cMonster::mtWither:
{
WriteByte(0x54); // Int at index 20
WriteInt(((const cWither &)a_Mob).GetNumInvulnerableTicks());
WriteByte(0x66); // Float at index 6
WriteFloat((float)(a_Mob.GetHealth()));
break;
}
case cMonster::mtSlime:
{
WriteByte(0x10);

View File

@ -53,7 +53,7 @@ int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed
int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed)
int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Compressed)
{
// Compress a_Data into a_Compressed using GZIP; return Z_XXX error constants same as zlib's compress2()
@ -83,6 +83,7 @@ int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed
{
// Some data has been compressed. Consume the buffer and continue compressing
a_Compressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
strm.next_out = (Bytef *)Buffer;
strm.avail_out = sizeof(Buffer);
if (strm.avail_in == 0)
{
@ -116,7 +117,7 @@ int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed
extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_Uncompressed)
extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed)
{
// Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib
@ -139,13 +140,14 @@ extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_U
for (;;)
{
res = inflate(&strm, Z_FINISH);
res = inflate(&strm, Z_NO_FLUSH);
switch (res)
{
case Z_OK:
{
// Some data has been uncompressed. Consume the buffer and continue uncompressing
a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
strm.next_out = (Bytef *)Buffer;
strm.avail_out = sizeof(Buffer);
if (strm.avail_in == 0)
{

View File

@ -16,10 +16,10 @@ extern int CompressString(const char * a_Data, int a_Length, AString & a_Compres
extern int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed, int a_UncompressedSize);
/// Compresses a_Data into a_Compressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib
extern int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed);
extern int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Compressed);
/// Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib
extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_Uncompressed);
extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed);

View File

@ -79,10 +79,10 @@ extern AString URLDecode(const AString & a_String); // Cannot export to Lua aut
extern AString ReplaceAllCharOccurrences(const AString & a_String, char a_From, char a_To); // Needn't export to Lua, since Lua doesn't have chars anyway
/// Decodes a Base64-encoded string into the raw data
extern AString Base64Decode(const AString & a_Base64String);
extern AString Base64Decode(const AString & a_Base64String); // Exported manually due to embedded NULs and extra parameter
/// Encodes a string into Base64
extern AString Base64Encode(const AString & a_Input);
extern AString Base64Encode(const AString & a_Input); // Exported manually due to embedded NULs and extra parameter
/// Reads two bytes from the specified memory location and interprets them as BigEndian short
extern short GetBEShort(const char * a_Mem);

View File

@ -14,6 +14,39 @@
#ifdef SELF_TEST
static class cSchematicStringSelfTest
{
public:
cSchematicStringSelfTest(void)
{
cBlockArea ba;
ba.Create(21, 256, 21);
ba.RelLine(0, 0, 0, 9, 8, 7, cBlockArea::baTypes | cBlockArea::baMetas, E_BLOCK_WOODEN_STAIRS, 1);
AString Schematic;
if (!cSchematicFileSerializer::SaveToSchematicString(ba, Schematic))
{
assert_test(!"Schematic failed to save!");
}
cBlockArea ba2;
if (!cSchematicFileSerializer::LoadFromSchematicString(ba2, Schematic))
{
assert_test(!"Schematic failed to load!");
}
}
} g_SelfTest;
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cSchematicFileSerializer:
bool cSchematicFileSerializer::LoadFromSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName)
{
// Un-GZip the contents: