Merge branch 'master' into HTTPSizeT
This commit is contained in:
commit
741a64c250
@ -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
|
||||
@ -306,10 +323,26 @@ g_APIDesc =
|
||||
</tr><tr>
|
||||
<td> A </td><td> sponge </td><td> A </td><td> Sponge is the NOP block </td>
|
||||
</tr><tr>
|
||||
<td> * </td><td> B </td><td> B </td><td> Everything else overwrites anything </td>
|
||||
<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
|
||||
|
@ -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...");
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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[]
|
||||
}
|
||||
}
|
||||
} ;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user