Merge remote-tracking branch 'origin/master' into awesometnt
Conflicts: src/Items/ItemLighter.h src/Simulator/IncrementalRedstoneSimulator.cpp
This commit is contained in:
commit
e672988577
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
build/
|
||||
nbproject/
|
||||
ipch/
|
||||
Win32/
|
||||
MCServer/MCServer
|
||||
|
@ -1,7 +1,7 @@
|
||||
Code Stuff
|
||||
----------
|
||||
|
||||
* We use C++03
|
||||
* We use C++03 with some C++11 extensions (ask if you think that something would be useful)
|
||||
* Use the provided wrappers for OS stuff:
|
||||
- Threading is done by inheriting from `cIsThread`, thread synchronization through `cCriticalSection`, `cSemaphore` and `cEvent`, file access and filesystem operations through the `cFile` class, high-precision timers through `cTimer`, high-precision sleep through `cSleep`
|
||||
* No magic numbers, use named constants:
|
||||
|
@ -2025,8 +2025,9 @@ end
|
||||
Desc = "This class manages a TNT entity.",
|
||||
Functions =
|
||||
{
|
||||
GetCounterTime = { Return = "number", Notes = "Returns the time until the entity explodes." },
|
||||
GetMaxFuseTime = { Return = "number", Notes = "Returns how long the fuse was." },
|
||||
Explode = { Return = "", Notes = "Explode the tnt." },
|
||||
GetFuseTicks = { Return = "number", Notes = "Returns the fuse ticks until the tnt will explode." },
|
||||
SetFuseTicks = { Return = "number", Notes = "Set the fuse ticks until the tnt will explode." },
|
||||
},
|
||||
Inherits = "cEntity",
|
||||
},
|
||||
@ -2261,7 +2262,7 @@ end
|
||||
SpawnMob = { Params = "X, Y, Z, {{cMonster|MonsterType}}", Return = "EntityID", Notes = "Spawns the specified type of mob at the specified coords. Returns the EntityID of the creates entity, or -1 on failure. " },
|
||||
SpawnFallingBlock = { Params = "X, Y, Z, BlockType, BlockMeta", Return = "EntityID", Notes = "Spawns an {{cFallingBlock|Falling Block}} entity at the specified coords with the given block type/meta" },
|
||||
SpawnExperienceOrb = { Params = "X, Y, Z, Reward", Return = "EntityID", Notes = "Spawns an {{cExpOrb|experience orb}} at the specified coords, with the given reward" },
|
||||
SpawnPrimedTNT = { Params = "X, Y, Z, FuseTimeSecs, InitialVelocityCoeff", Return = "", Notes = "Spawns a {{cTNTEntity|primed TNT entity}} at the specified coords, with the given fuse time. The entity gets a random speed multiplied by the InitialVelocityCoeff, 1 being the default value." },
|
||||
SpawnPrimedTNT = { Params = "X, Y, Z, FuseTicks, InitialVelocityCoeff", Return = "", Notes = "Spawns a {{cTNTEntity|primed TNT entity}} at the specified coords, with the given fuse ticks. The entity gets a random speed multiplied by the InitialVelocityCoeff, 1 being the default value." },
|
||||
TryGetHeight = { Params = "BlockX, BlockZ", Return = "IsValid, Height", Notes = "Returns true and height of the highest non-air block if the chunk is loaded, or false otherwise." },
|
||||
UpdateSign = { Params = "X, Y, Z, Line1, Line2, Line3, Line4, [{{cPlayer|Player}}]", Return = "", Notes = "Sets the sign text at the specified coords. The sign-updating hooks are called for the change. The Player parameter is used to indicate the player from whom the change has come, it may be nil. Same as SetSignLiens()" },
|
||||
UseBlockEntity = { Params = "{{cPlayer|Player}}, BlockX, BlockY, BlockZ", Return = "", Notes = "Makes the specified Player use the block entity at the specified coords (open chest UI, etc.) If the cords are in an unloaded chunk or there's no block entity, ignores the call." },
|
||||
|
@ -39,6 +39,7 @@
|
||||
#
|
||||
|
||||
# Need to list each of the four log types, otherwise all logs would get converted into apple planks (^0)
|
||||
|
||||
ApplePlanks, 4 = AppleLog, *
|
||||
ConiferPlanks, 4 = ConiferLog, *
|
||||
BirchPlanks, 4 = BirchLog, *
|
||||
@ -434,6 +435,55 @@ GoldNugget, 9 = GoldIngot, *
|
||||
EnchantmentTable = Obsidian, 1:3, 2:3, 3:3, 2:2 | Diamond, 1:2, 3:2 | Book, 2:1
|
||||
|
||||
|
||||
#******************************************************#
|
||||
# Fireworks & Co.
|
||||
# (Best not to add non-vanilla items to this as it will cause internal firework data handling code to log warnings)
|
||||
|
||||
# Ballistic firework rockets - plain and with firework star, all with 1 - 3 gunpowder
|
||||
FireworkRocket = Paper, * | Gunpowder, *
|
||||
FireworkRocket = Paper, * | Gunpowder, * | Gunpowder, *
|
||||
FireworkRocket = Paper, * | Gunpowder, * | Gunpowder, * | Gunpowder, *
|
||||
FireworkRocket = FireworkStar, * | Paper, * | Gunpowder, *
|
||||
FireworkRocket = FireworkStar, * | Paper, * | Gunpowder, * | Gunpowder, *
|
||||
FireworkRocket = FireworkStar, * | Paper, * | Gunpowder, * | Gunpowder, * | Gunpowder, *
|
||||
|
||||
# Radioactive firework stars
|
||||
# Plain powder and dye
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, *
|
||||
|
||||
# Powder and effect, with effect combining
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Diamond, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Glowdust, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Glowdust, * | Diamond, *
|
||||
|
||||
# Powder and shape (no shape combining possible)
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Firecharge, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Goldnugget, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Feather, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | SkeletonHead ^-1, *
|
||||
|
||||
# Power and shape (no shape combining possible), combined with effect
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Firecharge, * | Diamond, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Firecharge, * | Glowdust, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Goldnugget, * | Diamond, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Goldnugget, * | Glowdust, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Feather, * | Diamond, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Feather, * | Glowdust, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | SkeletonHead ^-1, * | Diamond, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | SkeletonHead ^-1, * | Glowdust, *
|
||||
|
||||
# Power and shape (no shape combining possible), combined with effect (with effect combining)
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Firecharge, * | Glowdust, * | Diamond, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Goldnugget, * | Glowdust, * | Diamond, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Feather, * | Glowdust, * | Diamond, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | SkeletonHead ^-1, * | Glowdust, * | Diamond, *
|
||||
|
||||
# Star fade colour-change
|
||||
FireworkStar = FireworkStar, * | Dye ^-1, *
|
||||
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, *
|
||||
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
|
||||
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
|
||||
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
|
||||
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
|
||||
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
|
||||
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
|
||||
|
@ -116,7 +116,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
|
||||
{
|
||||
double TNTX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width);
|
||||
double TNTZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width);
|
||||
m_World->SpawnPrimedTNT(TNTX, DispY + 0.5, TNTZ, 4, 0); // 4 seconds fuse, no initial velocity
|
||||
m_World->SpawnPrimedTNT(TNTX, DispY + 0.5, TNTZ, 80, 0); // 80 ticks fuse, no initial velocity
|
||||
m_Contents.ChangeSlotCount(a_SlotNum, -1);
|
||||
}
|
||||
break;
|
||||
|
@ -65,8 +65,8 @@ public:
|
||||
enum
|
||||
{
|
||||
// Chunk dimensions:
|
||||
Width = 16,
|
||||
Height = 256,
|
||||
Width = 16U,
|
||||
Height = 256U,
|
||||
NumBlocks = Width * Height * Width,
|
||||
|
||||
/// If the data is collected into a single buffer, how large it needs to be:
|
||||
@ -132,7 +132,7 @@ public:
|
||||
}
|
||||
|
||||
|
||||
inline static unsigned int MakeIndexNoCheck(int x, int y, int z)
|
||||
inline static unsigned int MakeIndexNoCheck(unsigned int x, unsigned int y, unsigned int z)
|
||||
{
|
||||
#if AXIS_ORDER == AXIS_ORDER_XZY
|
||||
// For some reason, NOT using the Horner schema is faster. Weird.
|
||||
@ -240,7 +240,7 @@ public:
|
||||
{
|
||||
if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1))
|
||||
{
|
||||
int Index = MakeIndexNoCheck(x, y, z);
|
||||
unsigned int Index = MakeIndexNoCheck(x, y, z);
|
||||
return (a_Buffer[Index / 2] >> ((Index & 1) * 4)) & 0x0f;
|
||||
}
|
||||
ASSERT(!"cChunkDef::GetNibble(): coords out of chunk range!");
|
||||
@ -256,7 +256,7 @@ public:
|
||||
return;
|
||||
}
|
||||
a_Buffer[a_BlockIdx / 2] = (
|
||||
(a_Buffer[a_BlockIdx / 2] & (0xf0 >> ((a_BlockIdx & 1) * 4))) | // The untouched nibble
|
||||
(a_Buffer[a_BlockIdx / 2] & (0xf0 >> (static_cast<NIBBLETYPE>(a_BlockIdx & 1) * 4))) | // The untouched nibble
|
||||
((a_Nibble & 0x0f) << ((a_BlockIdx & 1) * 4)) // The nibble being set
|
||||
);
|
||||
}
|
||||
@ -282,13 +282,13 @@ public:
|
||||
}
|
||||
|
||||
|
||||
inline static char GetNibble(const NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos )
|
||||
inline static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos )
|
||||
{
|
||||
return GetNibble(a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z );
|
||||
}
|
||||
|
||||
|
||||
inline static void SetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos, char a_Value )
|
||||
inline static void SetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos, NIBBLETYPE a_Value )
|
||||
{
|
||||
SetNibble( a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Value );
|
||||
}
|
||||
@ -306,6 +306,9 @@ The virtual methods are called in the same order as they're declared here.
|
||||
class cChunkDataCallback abstract
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~cChunkDataCallback() {}
|
||||
|
||||
/** Called before any other callbacks to inform of the current coords
|
||||
(only in processes where multiple chunks can be processed, such as cWorld::ForEachChunkInRect()).
|
||||
If false is returned, the chunk is skipped.
|
||||
|
@ -52,6 +52,9 @@
|
||||
/** Maximum number of explosions to send this tick, server will start dropping if exceeded */
|
||||
#define MAX_EXPLOSIONS_PER_TICK 20
|
||||
|
||||
/** Maximum number of block change interactions a player can perform per tick - exceeding this causes a kick */
|
||||
#define MAX_BLOCK_CHANGE_INTERACTIONS 20
|
||||
|
||||
/** How many ticks before the socket is closed after the client is destroyed (#31) */
|
||||
static const int TICKS_BEFORE_CLOSE = 20;
|
||||
|
||||
@ -700,6 +703,14 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
|
||||
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status
|
||||
);
|
||||
|
||||
m_NumBlockChangeInteractionsThisTick++;
|
||||
|
||||
if (!CheckBlockInteractionsRate())
|
||||
{
|
||||
Kick("Too many blocks were destroyed per unit time - hacked client?");
|
||||
return;
|
||||
}
|
||||
|
||||
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
|
||||
if (PlgMgr->CallHookPlayerLeftClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status))
|
||||
{
|
||||
@ -707,12 +718,6 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
|
||||
m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CheckBlockInteractionsRate())
|
||||
{
|
||||
// Too many interactions per second, simply ignore. Probably a hacked client, so don't even send bak the block
|
||||
return;
|
||||
}
|
||||
|
||||
switch (a_Status)
|
||||
{
|
||||
@ -944,7 +949,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||
cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
|
||||
BlockHandler->OnCancelRightClick(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||
|
||||
if (a_BlockFace > -1)
|
||||
if (a_BlockFace != BLOCK_FACE_NONE)
|
||||
{
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
||||
@ -955,7 +960,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||
|
||||
if (!CheckBlockInteractionsRate())
|
||||
{
|
||||
LOGD("Too many block interactions, aborting placement");
|
||||
Kick("Too many blocks were placed/interacted with per unit time - hacked client?");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1634,28 +1639,12 @@ bool cClientHandle::CheckBlockInteractionsRate(void)
|
||||
{
|
||||
ASSERT(m_Player != NULL);
|
||||
ASSERT(m_Player->GetWorld() != NULL);
|
||||
/*
|
||||
// TODO: _X 2012_11_01: This needs a total re-thinking and rewriting
|
||||
int LastActionCnt = m_Player->GetLastBlockActionCnt();
|
||||
if ((m_Player->GetWorld()->GetTime() - m_Player->GetLastBlockActionTime()) < 0.1)
|
||||
|
||||
if (m_NumBlockChangeInteractionsThisTick > MAX_BLOCK_CHANGE_INTERACTIONS)
|
||||
{
|
||||
// Limit the number of block interactions per tick
|
||||
m_Player->SetLastBlockActionTime(); //Player tried to interact with a block. Reset last block interation time.
|
||||
m_Player->SetLastBlockActionCnt(LastActionCnt + 1);
|
||||
if (m_Player->GetLastBlockActionCnt() > MAXBLOCKCHANGEINTERACTIONS)
|
||||
{
|
||||
// Kick if more than MAXBLOCKCHANGEINTERACTIONS per tick
|
||||
LOGWARN("Player %s tried to interact with a block too quickly! (could indicate bot) Was Kicked.", m_Username.c_str());
|
||||
Kick("You're a baaaaaad boy!");
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Player->SetLastBlockActionCnt(0); // Reset count
|
||||
m_Player->SetLastBlockActionTime(); // Player tried to interact with a block. Reset last block interation time.
|
||||
}
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1728,8 +1717,9 @@ void cClientHandle::Tick(float a_Dt)
|
||||
}
|
||||
}
|
||||
|
||||
// Reset explosion counter:
|
||||
// Reset explosion & block change counters:
|
||||
m_NumExplosionsThisTick = 0;
|
||||
m_NumBlockChangeInteractionsThisTick = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -46,7 +46,6 @@ class cClientHandle : // tolua_export
|
||||
public cSocketThreads::cCallback
|
||||
{ // tolua_export
|
||||
public:
|
||||
static const int MAXBLOCKCHANGEINTERACTIONS = 20; // 5 didn't help, 10 still doesn't work in Creative, 20 seems to have done the trick
|
||||
|
||||
#if defined(ANDROID_NDK)
|
||||
static const int DEFAULT_VIEW_DISTANCE = 4; // The default ViewDistance (used when no value is set in Settings.ini)
|
||||
@ -321,6 +320,9 @@ private:
|
||||
|
||||
/** Number of explosions sent this tick */
|
||||
int m_NumExplosionsThisTick;
|
||||
|
||||
/** Number of place or break interactions this tick */
|
||||
int m_NumBlockChangeInteractionsThisTick;
|
||||
|
||||
static int s_ClientCount;
|
||||
int m_UniqueID;
|
||||
|
@ -1,4 +1,4 @@
|
||||
|
||||
|
||||
// CraftingRecipes.cpp
|
||||
|
||||
// Interfaces to the cCraftingRecipes class representing the storage of crafting recipes
|
||||
@ -762,9 +762,94 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::MatchRecipe(const cItem * a_Crafti
|
||||
Recipe->m_Ingredients.push_back(*itrS);
|
||||
}
|
||||
Recipe->m_Ingredients.insert(Recipe->m_Ingredients.end(), MatchedSlots.begin(), MatchedSlots.end());
|
||||
|
||||
// We use Recipe instead of a_Recipe because we want the wildcard ingredients' slot numbers as well, which was just added previously
|
||||
HandleFireworks(a_CraftingGrid, Recipe.get(), a_GridStride, a_OffsetX, a_OffsetY);
|
||||
|
||||
return Recipe.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCraftingRecipes::HandleFireworks(const cItem * a_CraftingGrid, cCraftingRecipes::cRecipe * a_Recipe, int a_GridStride, int a_OffsetX, int a_OffsetY)
|
||||
{
|
||||
// TODO: add support for more than one dye in the recipe
|
||||
// A manual and temporary solution (listing everything) is in crafting.txt for fade colours, but a programmatic solutions needs to be done for everything else
|
||||
|
||||
if (a_Recipe->m_Result.m_ItemType == E_ITEM_FIREWORK_ROCKET)
|
||||
{
|
||||
for (cRecipeSlots::const_iterator itr = a_Recipe->m_Ingredients.begin(); itr != a_Recipe->m_Ingredients.end(); ++itr)
|
||||
{
|
||||
switch (itr->m_Item.m_ItemType)
|
||||
{
|
||||
case E_ITEM_FIREWORK_STAR:
|
||||
{
|
||||
// Result was a rocket, found a star - copy star data to rocket data
|
||||
int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
|
||||
a_Recipe->m_Result.m_FireworkItem.CopyFrom(a_CraftingGrid[GridID].m_FireworkItem);
|
||||
break;
|
||||
}
|
||||
case E_ITEM_GUNPOWDER:
|
||||
{
|
||||
// Gunpowder - increase flight time
|
||||
a_Recipe->m_Result.m_FireworkItem.m_FlightTimeInTicks += 20;
|
||||
break;
|
||||
}
|
||||
case E_ITEM_PAPER: break;
|
||||
default: LOG("Unexpected item in firework rocket a_Recipe, was the crafting file fireworks section changed?"); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (a_Recipe->m_Result.m_ItemType == E_ITEM_FIREWORK_STAR)
|
||||
{
|
||||
std::vector<int> DyeColours;
|
||||
bool FoundStar = false;
|
||||
|
||||
for (cRecipeSlots::const_iterator itr = a_Recipe->m_Ingredients.begin(); itr != a_Recipe->m_Ingredients.end(); ++itr)
|
||||
{
|
||||
switch (itr->m_Item.m_ItemType)
|
||||
{
|
||||
case E_ITEM_FIREWORK_STAR:
|
||||
{
|
||||
// Result was star, found another star - probably adding fade colours, but copy data over anyhow
|
||||
FoundStar = true;
|
||||
int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
|
||||
a_Recipe->m_Result.m_FireworkItem.CopyFrom(a_CraftingGrid[GridID].m_FireworkItem);
|
||||
break;
|
||||
}
|
||||
case E_ITEM_DYE:
|
||||
{
|
||||
int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
|
||||
DyeColours.push_back(cFireworkItem::GetVanillaColourCodeFromDye(a_CraftingGrid[GridID].m_ItemDamage));
|
||||
break;
|
||||
}
|
||||
case E_ITEM_GUNPOWDER: break;
|
||||
case E_ITEM_DIAMOND: a_Recipe->m_Result.m_FireworkItem.m_HasTrail = true; break;
|
||||
case E_ITEM_GLOWSTONE_DUST: a_Recipe->m_Result.m_FireworkItem.m_HasFlicker = true; break;
|
||||
|
||||
case E_ITEM_FIRE_CHARGE: a_Recipe->m_Result.m_FireworkItem.m_Type = 1; break;
|
||||
case E_ITEM_GOLD_NUGGET: a_Recipe->m_Result.m_FireworkItem.m_Type = 2; break;
|
||||
case E_ITEM_FEATHER: a_Recipe->m_Result.m_FireworkItem.m_Type = 4; break;
|
||||
case E_ITEM_HEAD: a_Recipe->m_Result.m_FireworkItem.m_Type = 3; break;
|
||||
default: LOG("Unexpected item in firework star a_Recipe, was the crafting file fireworks section changed?"); break; // ermahgerd BARD ardmins
|
||||
}
|
||||
}
|
||||
|
||||
if (FoundStar && (!DyeColours.empty()))
|
||||
{
|
||||
// Found a star and a dye? Fade colours.
|
||||
a_Recipe->m_Result.m_FireworkItem.m_FadeColours = DyeColours;
|
||||
}
|
||||
else if (!DyeColours.empty())
|
||||
{
|
||||
// Only dye? Normal colours.
|
||||
a_Recipe->m_Result.m_FireworkItem.m_Colours = DyeColours;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -165,6 +165,9 @@ protected:
|
||||
|
||||
/// Checks if the grid matches the specified recipe, offset by the specified offsets. Returns a matched cRecipe * if so, or NULL if not matching. Caller must delete the return value!
|
||||
cRecipe * MatchRecipe(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight, int a_GridStride, const cRecipe * a_Recipe, int a_OffsetX, int a_OffsetY);
|
||||
|
||||
/** Searches for anything firework related, and does the data setting if appropriate */
|
||||
void HandleFireworks(const cItem * a_CraftingGrid, cCraftingRecipes::cRecipe * a_Recipe, int a_GridStride, int a_OffsetX, int a_OffsetY);
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -10,18 +10,11 @@
|
||||
#include "../BlockEntities/BlockEntity.h"
|
||||
#include "../GroupManager.h"
|
||||
#include "../Group.h"
|
||||
#include "../ChatColor.h"
|
||||
#include "../Item.h"
|
||||
#include "../Tracer.h"
|
||||
#include "../Root.h"
|
||||
#include "../OSSupport/Timer.h"
|
||||
#include "../MersenneTwister.h"
|
||||
#include "../Chunk.h"
|
||||
#include "../Items/ItemHandler.h"
|
||||
|
||||
#include "../Vector3d.h"
|
||||
#include "../Vector3f.h"
|
||||
|
||||
#include "inifile/iniFile.h"
|
||||
#include "json/json.h"
|
||||
|
||||
@ -45,10 +38,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
|
||||
, m_Inventory(*this)
|
||||
, m_CurrentWindow(NULL)
|
||||
, m_InventoryWindow(NULL)
|
||||
, m_TimeLastPickupCheck(0.f)
|
||||
, m_Color('-')
|
||||
, m_LastBlockActionTime(0)
|
||||
, m_LastBlockActionCnt(0)
|
||||
, m_GameMode(eGameMode_NotSet)
|
||||
, m_IP("")
|
||||
, m_ClientHandle(a_Client)
|
||||
@ -86,7 +76,6 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
|
||||
m_LastPlayerListTime = t1.GetNowTime();
|
||||
|
||||
m_TimeLastTeleportPacket = 0;
|
||||
m_TimeLastPickupCheck = 0;
|
||||
|
||||
m_PlayerName = a_PlayerName;
|
||||
m_bDirtyPosition = true; // So chunks are streamed to player at spawn
|
||||
@ -1047,27 +1036,6 @@ void cPlayer::CloseWindowIfID(char a_WindowID, bool a_CanRefuse)
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetLastBlockActionTime()
|
||||
{
|
||||
if (m_World != NULL)
|
||||
{
|
||||
m_LastBlockActionTime = m_World->GetWorldAge() / 20.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetLastBlockActionCnt( int a_LastBlockActionCnt )
|
||||
{
|
||||
m_LastBlockActionCnt = a_LastBlockActionCnt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetGameMode(eGameMode a_GameMode)
|
||||
{
|
||||
if ((a_GameMode < gmMin) || (a_GameMode >= gmMax))
|
||||
|
@ -50,7 +50,7 @@ public:
|
||||
/// Returns the curently equipped weapon; empty item if none
|
||||
virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); }
|
||||
|
||||
/// Returns the currently equipped helmet; empty item if nonte
|
||||
/// Returns the currently equipped helmet; empty item if none
|
||||
virtual cItem GetEquippedHelmet(void) const override { return m_Inventory.GetEquippedHelmet(); }
|
||||
|
||||
/// Returns the currently equipped chestplate; empty item if none
|
||||
@ -165,11 +165,6 @@ public:
|
||||
// tolua_end
|
||||
|
||||
void SetIP(const AString & a_IP);
|
||||
|
||||
float GetLastBlockActionTime() { return m_LastBlockActionTime; }
|
||||
int GetLastBlockActionCnt() { return m_LastBlockActionCnt; }
|
||||
void SetLastBlockActionCnt( int );
|
||||
void SetLastBlockActionTime();
|
||||
|
||||
// Sets the current gamemode, doesn't check validity, doesn't send update packets to client
|
||||
void LoginSetGameMode(eGameMode a_GameMode);
|
||||
@ -416,12 +411,8 @@ protected:
|
||||
cWindow * m_CurrentWindow;
|
||||
cWindow * m_InventoryWindow;
|
||||
|
||||
float m_TimeLastPickupCheck;
|
||||
|
||||
char m_Color;
|
||||
|
||||
float m_LastBlockActionTime;
|
||||
int m_LastBlockActionCnt;
|
||||
eGameMode m_GameMode;
|
||||
AString m_IP;
|
||||
|
||||
|
@ -214,7 +214,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve
|
||||
|
||||
|
||||
|
||||
cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed)
|
||||
cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item, const Vector3d * a_Speed)
|
||||
{
|
||||
Vector3d Speed;
|
||||
if (a_Speed != NULL)
|
||||
@ -231,8 +231,15 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator,
|
||||
case pkGhastFireball: return new cGhastFireballEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkFireCharge: return new cFireChargeEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkExpBottle: return new cExpBottleEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkFirework: return new cFireworkEntity (a_Creator, a_X, a_Y, a_Z );
|
||||
// TODO: the rest
|
||||
case pkFirework:
|
||||
{
|
||||
if (a_Item.m_FireworkItem.m_Colours.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new cFireworkEntity(a_Creator, a_X, a_Y, a_Z, a_Item);
|
||||
}
|
||||
}
|
||||
|
||||
LOGWARNING("%s: Unknown projectile kind: %d", __FUNCTION__, a_Kind);
|
||||
@ -276,6 +283,7 @@ AString cProjectileEntity::GetMCAClassName(void) const
|
||||
case pkExpBottle: return "ThrownExpBottle";
|
||||
case pkSplashPotion: return "ThrownPotion";
|
||||
case pkWitherSkull: return "WitherSkull";
|
||||
case pkFirework: return "Firework";
|
||||
case pkFishingFloat: return ""; // Unknown, perhaps MC doesn't save this?
|
||||
}
|
||||
ASSERT(!"Unhandled projectile entity kind!");
|
||||
@ -693,8 +701,10 @@ void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_H
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cFireworkEntity :
|
||||
|
||||
cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z) :
|
||||
super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
@ -702,30 +712,20 @@ super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||
|
||||
|
||||
|
||||
void cFireworkEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
if ((a_HitFace != BLOCK_FACE_BOTTOM) && (a_HitFace != BLOCK_FACE_NONE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetSpeed(0, 0, 0);
|
||||
SetPosition(GetPosX(), GetPosY() - 0.5, GetPosZ());
|
||||
|
||||
m_IsInGround = true;
|
||||
|
||||
BroadcastMovementUpdate();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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((int)GetPosX(), (int)GetPosY() + 1, (int)GetPosZ()) == E_BLOCK_AIR)
|
||||
if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR)
|
||||
{
|
||||
m_IsInGround = false;
|
||||
}
|
||||
@ -734,28 +734,35 @@ void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Vector3d PerTickSpeed = GetSpeed() / 20;
|
||||
Vector3d Pos = GetPosition();
|
||||
|
||||
// Trace the tick's worth of movement as a line:
|
||||
Vector3d NextPos = Pos + PerTickSpeed;
|
||||
cProjectileTracerCallback TracerCallback(this);
|
||||
if (!cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos))
|
||||
else
|
||||
{
|
||||
// Something has been hit, abort all other processing
|
||||
return;
|
||||
if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR)
|
||||
{
|
||||
OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff
|
||||
|
||||
// Update the position:
|
||||
SetPosition(NextPos);
|
||||
setspeed:
|
||||
AddSpeedY(1);
|
||||
AddPosition(GetSpeed() * (a_Dt / 1000));
|
||||
}
|
||||
|
||||
// Add slowdown and gravity effect to the speed:
|
||||
Vector3d NewSpeed(GetSpeed());
|
||||
NewSpeed.y += 2;
|
||||
NewSpeed *= TracerCallback.GetSlowdownCoeff();
|
||||
SetSpeed(NewSpeed);
|
||||
|
||||
|
||||
|
||||
|
||||
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, ENTITY_STATUS_FIREWORK_EXPLODE);
|
||||
Destroy();
|
||||
}
|
||||
|
||||
m_ExplodeTimer++;
|
||||
}
|
||||
|
||||
|
||||
|
@ -46,7 +46,7 @@ public:
|
||||
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
|
||||
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height);
|
||||
|
||||
static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed = NULL);
|
||||
static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item, const Vector3d * a_Speed = NULL);
|
||||
|
||||
/// Called by the physics blocktracer when the entity hits a solid block, the hit position and the face hit (BLOCK_FACE_) is given
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace);
|
||||
@ -305,13 +305,19 @@ public:
|
||||
|
||||
CLASS_PROTODEF(cFireworkEntity);
|
||||
|
||||
cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z);
|
||||
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 OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
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
|
||||
|
||||
|
@ -8,10 +8,9 @@
|
||||
|
||||
|
||||
|
||||
cTNTEntity::cTNTEntity(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec) :
|
||||
cTNTEntity::cTNTEntity(double a_X, double a_Y, double a_Z, int a_FuseTicks) :
|
||||
super(etTNT, a_X, a_Y, a_Z, 0.98, 0.98),
|
||||
m_Counter(0),
|
||||
m_MaxFuseTime(a_FuseTimeInSec)
|
||||
m_FuseTicks(a_FuseTicks)
|
||||
{
|
||||
}
|
||||
|
||||
@ -19,10 +18,9 @@ cTNTEntity::cTNTEntity(double a_X, double a_Y, double a_Z, double a_FuseTimeInSe
|
||||
|
||||
|
||||
|
||||
cTNTEntity::cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec) :
|
||||
cTNTEntity::cTNTEntity(const Vector3d & a_Pos, int a_FuseTicks) :
|
||||
super(etTNT, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98),
|
||||
m_Counter(0),
|
||||
m_MaxFuseTime(a_FuseTimeInSec)
|
||||
m_FuseTicks(a_FuseTicks)
|
||||
{
|
||||
}
|
||||
|
||||
@ -42,18 +40,27 @@ void cTNTEntity::SpawnOn(cClientHandle & a_ClientHandle)
|
||||
|
||||
|
||||
|
||||
void cTNTEntity::Explode(void)
|
||||
{
|
||||
m_FuseTicks = 0;
|
||||
Destroy(true);
|
||||
LOGD("BOOM at {%f,%f,%f}", GetPosX(), GetPosY(), GetPosZ());
|
||||
m_World->DoExplosionAt(4.0, GetPosX() + 0.49, GetPosY() + 0.49, GetPosZ() + 0.49, true, esPrimedTNT, this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cTNTEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
super::Tick(a_Dt, a_Chunk);
|
||||
BroadcastMovementUpdate();
|
||||
float delta_time = a_Dt / 1000; // Convert miliseconds to seconds
|
||||
m_Counter += delta_time;
|
||||
if (m_Counter > m_MaxFuseTime) // Check if we go KABOOOM
|
||||
|
||||
m_FuseTicks -= 1;
|
||||
if (m_FuseTicks <= 0)
|
||||
{
|
||||
Destroy(true);
|
||||
LOGD("BOOM at {%f,%f,%f}", GetPosX(), GetPosY(), GetPosZ());
|
||||
m_World->DoExplosionAt(4.0, GetPosX() + 0.49, GetPosY() + 0.49, GetPosZ() + 0.49, true, esPrimedTNT, this);
|
||||
return;
|
||||
Explode();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,19 +16,28 @@ public:
|
||||
// tolua_end
|
||||
CLASS_PROTODEF(cTNTEntity);
|
||||
|
||||
cTNTEntity(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec);
|
||||
cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec);
|
||||
cTNTEntity(double a_X, double a_Y, double a_Z, int a_FuseTicks = 80);
|
||||
cTNTEntity(const Vector3d & a_Pos, int a_FuseTicks = 80);
|
||||
|
||||
// cEntity overrides:
|
||||
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
double GetCounterTime(void) const { return m_Counter; } // tolua_export
|
||||
double GetMaxFuseTime(void) const { return m_MaxFuseTime; } // tolua_export
|
||||
|
||||
// tolua_begin
|
||||
|
||||
/** Explode the tnt */
|
||||
void Explode(void);
|
||||
|
||||
/** Returns the fuse ticks until the tnt will explode */
|
||||
int GetFuseTicks(void) const { return m_FuseTicks; }
|
||||
|
||||
/** Set the fuse ticks until the tnt will explode */
|
||||
void SetFuseTicks(int a_FuseTicks) { m_FuseTicks = a_FuseTicks; }
|
||||
|
||||
// tolua_end
|
||||
|
||||
protected:
|
||||
double m_Counter; ///< How much time has elapsed since the object was created, in seconds
|
||||
double m_MaxFuseTime; ///< How long the fuse is, in seconds
|
||||
int m_FuseTicks; ///< How much ticks is left, while the tnt will explode
|
||||
}; // tolua_export
|
||||
|
||||
|
||||
|
22
src/Item.cpp
22
src/Item.cpp
@ -1,4 +1,4 @@
|
||||
|
||||
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "Item.h"
|
||||
@ -139,6 +139,16 @@ void cItem::GetJson(Json::Value & a_OutValue) const
|
||||
{
|
||||
a_OutValue["Lore"] = m_Lore;
|
||||
}
|
||||
|
||||
if ((m_ItemType == E_ITEM_FIREWORK_ROCKET) || (m_ItemType == E_ITEM_FIREWORK_STAR))
|
||||
{
|
||||
a_OutValue["Flicker"] = m_FireworkItem.m_HasFlicker;
|
||||
a_OutValue["Trail"] = m_FireworkItem.m_HasTrail;
|
||||
a_OutValue["Type"] = m_FireworkItem.m_Type;
|
||||
a_OutValue["FlightTimeInTicks"] = m_FireworkItem.m_FlightTimeInTicks;
|
||||
a_OutValue["Colours"] = m_FireworkItem.ColoursToString(m_FireworkItem);
|
||||
a_OutValue["FadeColours"] = m_FireworkItem.FadeColoursToString(m_FireworkItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,6 +167,16 @@ void cItem::FromJson(const Json::Value & a_Value)
|
||||
m_Enchantments.AddFromString(a_Value.get("ench", "").asString());
|
||||
m_CustomName = a_Value.get("Name", "").asString();
|
||||
m_Lore = a_Value.get("Lore", "").asString();
|
||||
|
||||
if ((m_ItemType == E_ITEM_FIREWORK_ROCKET) || (m_ItemType == E_ITEM_FIREWORK_STAR))
|
||||
{
|
||||
m_FireworkItem.m_HasFlicker = a_Value.get("Flicker", false).asBool();
|
||||
m_FireworkItem.m_HasTrail = a_Value.get("Trail", false).asBool();
|
||||
m_FireworkItem.m_Type = (NIBBLETYPE)a_Value.get("Type", 0).asInt();
|
||||
m_FireworkItem.m_FlightTimeInTicks = (short)a_Value.get("FlightTimeInTicks", 0).asInt();
|
||||
m_FireworkItem.ColoursFromString(a_Value.get("Colours", "").asString(), m_FireworkItem);
|
||||
m_FireworkItem.FadeColoursFromString(a_Value.get("FadeColours", "").asString(), m_FireworkItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
16
src/Item.h
16
src/Item.h
@ -11,6 +11,7 @@
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Enchantments.h"
|
||||
#include "WorldStorage/FireworksSerializer.h"
|
||||
|
||||
|
||||
|
||||
@ -38,7 +39,8 @@ public:
|
||||
m_ItemCount(0),
|
||||
m_ItemDamage(0),
|
||||
m_CustomName(""),
|
||||
m_Lore("")
|
||||
m_Lore(""),
|
||||
m_FireworkItem()
|
||||
{
|
||||
}
|
||||
|
||||
@ -57,7 +59,8 @@ public:
|
||||
m_ItemDamage (a_ItemDamage),
|
||||
m_Enchantments(a_Enchantments),
|
||||
m_CustomName (a_CustomName),
|
||||
m_Lore (a_Lore)
|
||||
m_Lore (a_Lore),
|
||||
m_FireworkItem()
|
||||
{
|
||||
if (!IsValidItem(m_ItemType))
|
||||
{
|
||||
@ -77,7 +80,8 @@ public:
|
||||
m_ItemDamage (a_CopyFrom.m_ItemDamage),
|
||||
m_Enchantments(a_CopyFrom.m_Enchantments),
|
||||
m_CustomName (a_CopyFrom.m_CustomName),
|
||||
m_Lore (a_CopyFrom.m_Lore)
|
||||
m_Lore (a_CopyFrom.m_Lore),
|
||||
m_FireworkItem(a_CopyFrom.m_FireworkItem)
|
||||
{
|
||||
}
|
||||
|
||||
@ -90,6 +94,7 @@ public:
|
||||
m_Enchantments.Clear();
|
||||
m_CustomName = "";
|
||||
m_Lore = "";
|
||||
m_FireworkItem.EmptyData();
|
||||
}
|
||||
|
||||
|
||||
@ -115,7 +120,8 @@ public:
|
||||
(m_ItemDamage == a_Item.m_ItemDamage) &&
|
||||
(m_Enchantments == a_Item.m_Enchantments) &&
|
||||
(m_CustomName == a_Item.m_CustomName) &&
|
||||
(m_Lore == a_Item.m_Lore)
|
||||
(m_Lore == a_Item.m_Lore) &&
|
||||
m_FireworkItem.IsEqualTo(a_Item.m_FireworkItem)
|
||||
);
|
||||
}
|
||||
|
||||
@ -177,6 +183,8 @@ public:
|
||||
cEnchantments m_Enchantments;
|
||||
AString m_CustomName;
|
||||
AString m_Lore;
|
||||
|
||||
cFireworkItem m_FireworkItem;
|
||||
};
|
||||
// tolua_end
|
||||
|
||||
|
@ -33,9 +33,9 @@ public:
|
||||
case E_BLOCK_TNT:
|
||||
{
|
||||
// Activate the TNT:
|
||||
a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f);
|
||||
a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 1.0f);
|
||||
a_World->SetBlock(a_BlockX,a_BlockY,a_BlockZ, E_BLOCK_AIR, 0);
|
||||
a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom
|
||||
a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -35,7 +35,7 @@ public:
|
||||
|
||||
Vector3d Pos = a_Player->GetThrowStartPos();
|
||||
Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff;
|
||||
a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &Speed);
|
||||
a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, a_Player->GetEquippedItem(), &Speed);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -127,13 +127,13 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, a_Player->GetEquippedItem());
|
||||
|
||||
if (!a_Player->IsGameModeCreative())
|
||||
{
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
}
|
||||
|
||||
a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -68,17 +68,28 @@ void cSheep::OnRightClicked(cPlayer & a_Player)
|
||||
|
||||
void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
// The sheep should not move when he's eating so only handle the physics.
|
||||
super::Tick(a_Dt, a_Chunk);
|
||||
int PosX = POSX_TOINT;
|
||||
int PosY = POSY_TOINT - 1;
|
||||
int PosZ = POSZ_TOINT;
|
||||
|
||||
if ((PosY <= 0) || (PosY > cChunkDef::Height))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_TimeToStopEating > 0)
|
||||
{
|
||||
HandlePhysics(a_Dt, a_Chunk);
|
||||
m_bMovingToDestination = false; // The sheep should not move when he's eating
|
||||
m_TimeToStopEating--;
|
||||
|
||||
if (m_TimeToStopEating == 0)
|
||||
{
|
||||
if (m_World->GetBlock((int) GetPosX(), (int) GetPosY() - 1, (int) GetPosZ()) == E_BLOCK_GRASS)
|
||||
if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS) // Make sure grass hasn't been destroyed in the meantime
|
||||
{
|
||||
// The sheep ate the grass so we change it to dirt.
|
||||
m_World->SetBlock((int) GetPosX(), (int) GetPosY() - 1, (int) GetPosZ(), E_BLOCK_DIRT, 0);
|
||||
// The sheep ate the grass so we change it to dirt
|
||||
m_World->SetBlock(PosX, PosY, PosZ, E_BLOCK_DIRT, 0);
|
||||
GetWorld()->BroadcastSoundParticleEffect(2001, PosX, PosY, PosX, E_BLOCK_GRASS);
|
||||
m_IsSheared = false;
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
}
|
||||
@ -86,12 +97,11 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
}
|
||||
else
|
||||
{
|
||||
super::Tick(a_Dt, a_Chunk);
|
||||
if (m_World->GetTickRandomNumber(600) == 1)
|
||||
{
|
||||
if (m_World->GetBlock((int) GetPosX(), (int) GetPosY() - 1, (int) GetPosZ()) == E_BLOCK_GRASS)
|
||||
if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS)
|
||||
{
|
||||
m_World->BroadcastEntityStatus(*this, 10);
|
||||
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_SHEEP_EATING);
|
||||
m_TimeToStopEating = 40;
|
||||
}
|
||||
}
|
||||
|
@ -2079,36 +2079,47 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
|
||||
// Load enchantments and custom display names from the NBT data:
|
||||
for (int tag = NBT.GetFirstChild(NBT.GetRoot()); tag >= 0; tag = NBT.GetNextSibling(tag))
|
||||
{
|
||||
if (
|
||||
(NBT.GetType(tag) == TAG_List) &&
|
||||
(
|
||||
(NBT.GetName(tag) == "ench") ||
|
||||
(NBT.GetName(tag) == "StoredEnchantments")
|
||||
)
|
||||
)
|
||||
AString TagName = NBT.GetName(tag);
|
||||
switch (NBT.GetType(tag))
|
||||
{
|
||||
EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag);
|
||||
}
|
||||
else if ((NBT.GetType(tag) == TAG_Compound) && (NBT.GetName(tag) == "display")) // Custom name and lore tag
|
||||
{
|
||||
for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag))
|
||||
case TAG_List:
|
||||
{
|
||||
if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag
|
||||
if ((TagName == "ench") || (TagName == "StoredEnchantments")) // Enchantments tags
|
||||
{
|
||||
a_Item.m_CustomName = NBT.GetString(displaytag);
|
||||
}
|
||||
else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag
|
||||
{
|
||||
AString Lore;
|
||||
|
||||
for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings
|
||||
{
|
||||
AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a newline, used internally by MCS to display a new line in the client; don't forget to c_str ;)
|
||||
}
|
||||
|
||||
a_Item.m_Lore = Lore;
|
||||
EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TAG_Compound:
|
||||
{
|
||||
if (TagName == "display") // Custom name and lore tag
|
||||
{
|
||||
for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag))
|
||||
{
|
||||
if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag
|
||||
{
|
||||
a_Item.m_CustomName = NBT.GetString(displaytag);
|
||||
}
|
||||
else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag
|
||||
{
|
||||
AString Lore;
|
||||
|
||||
for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings
|
||||
{
|
||||
AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a newline, used internally by MCS to display a new line in the client; don't forget to c_str ;)
|
||||
}
|
||||
|
||||
a_Item.m_Lore = Lore;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((TagName == "Fireworks") || (TagName == "Explosion"))
|
||||
{
|
||||
cFireworkItem::ParseFromNBT(a_Item.m_FireworkItem, NBT, tag, (ENUM_ITEM_ID)a_Item.m_ItemType);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: LOGD("Unimplemented NBT data when parsing!"); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2272,7 +2283,7 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
|
||||
WriteByte (a_Item.m_ItemCount);
|
||||
WriteShort(a_Item.m_ItemDamage);
|
||||
|
||||
if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty())
|
||||
if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty() && (a_Item.m_ItemType != E_ITEM_FIREWORK_ROCKET) && (a_Item.m_ItemType != E_ITEM_FIREWORK_STAR))
|
||||
{
|
||||
WriteShort(-1);
|
||||
return;
|
||||
@ -2311,6 +2322,10 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
|
||||
}
|
||||
Writer.EndCompound();
|
||||
}
|
||||
if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR))
|
||||
{
|
||||
cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, Writer, (ENUM_ITEM_ID)a_Item.m_ItemType);
|
||||
}
|
||||
Writer.Finish();
|
||||
AString Compressed;
|
||||
CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
|
||||
@ -2487,10 +2502,22 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
|
||||
}
|
||||
case cEntity::etProjectile:
|
||||
{
|
||||
if (((cProjectileEntity &)a_Entity).GetProjectileKind() == cProjectileEntity::pkArrow)
|
||||
cProjectileEntity & Projectile = (cProjectileEntity &)a_Entity;
|
||||
switch (Projectile.GetProjectileKind())
|
||||
{
|
||||
WriteByte(0x10);
|
||||
WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0);
|
||||
case cProjectileEntity::pkArrow:
|
||||
{
|
||||
WriteByte(0x10);
|
||||
WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0);
|
||||
break;
|
||||
}
|
||||
case cProjectileEntity::pkFirework:
|
||||
{
|
||||
WriteByte(0xA8);
|
||||
WriteItem(((const cFireworkEntity &)a_Entity).GetItem());
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -839,7 +839,7 @@ void cIncrementalRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_
|
||||
{
|
||||
m_World.BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f);
|
||||
m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
|
||||
m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom
|
||||
m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1725,10 +1725,10 @@ int cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType
|
||||
|
||||
|
||||
|
||||
void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff)
|
||||
void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTicks, double a_InitialVelocityCoeff)
|
||||
{
|
||||
UNUSED(a_InitialVelocityCoeff);
|
||||
cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTimeInSec);
|
||||
cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTicks);
|
||||
TNT->Initialize(this);
|
||||
TNT->SetSpeed(
|
||||
a_InitialVelocityCoeff * (GetTickRandomNumber(2) - 1), /** -1, 0, 1 */
|
||||
@ -2983,9 +2983,9 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster)
|
||||
|
||||
|
||||
|
||||
int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed)
|
||||
int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem a_Item, const Vector3d * a_Speed)
|
||||
{
|
||||
cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Speed);
|
||||
cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed);
|
||||
if (Projectile == NULL)
|
||||
{
|
||||
return -1;
|
||||
@ -3008,18 +3008,18 @@ void cWorld::TabCompleteUserName(const AString & a_Text, AStringVector & a_Resul
|
||||
cCSLock Lock(m_CSPlayers);
|
||||
for (cPlayerList::iterator itr = m_Players.begin(), end = m_Players.end(); itr != end; ++itr)
|
||||
{
|
||||
size_t LastSpace = a_Text.find_last_of(" "); //Find the position of the last space
|
||||
size_t LastSpace = a_Text.find_last_of(" "); // Find the position of the last space
|
||||
|
||||
std::string LastWord = a_Text.substr(LastSpace + 1, a_Text.length()); //Find the last word
|
||||
std::string PlayerName ((*itr)->GetName());
|
||||
std::size_t Found = PlayerName.find(LastWord); //Try to find last word in playername
|
||||
AString LastWord = a_Text.substr(LastSpace + 1, a_Text.length()); // Find the last word
|
||||
AString PlayerName ((*itr)->GetName());
|
||||
size_t Found = PlayerName.find(LastWord); // Try to find last word in playername
|
||||
|
||||
if (Found!=0)
|
||||
if (Found == AString::npos)
|
||||
{
|
||||
continue; //No match
|
||||
continue; // No match
|
||||
}
|
||||
|
||||
a_Results.push_back((*itr)->GetName()); //Match!
|
||||
a_Results.push_back(PlayerName); // Match!
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -445,7 +445,7 @@ public:
|
||||
int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward);
|
||||
|
||||
/** Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided */
|
||||
void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff = 1);
|
||||
void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTimeInSec = 80, double a_InitialVelocityCoeff = 1);
|
||||
|
||||
// tolua_end
|
||||
|
||||
@ -711,7 +711,7 @@ public:
|
||||
int SpawnMobFinalize(cMonster* a_Monster);
|
||||
|
||||
/** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise */
|
||||
int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed = NULL); // tolua_export
|
||||
int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem a_Item, const Vector3d * a_Speed = NULL); // tolua_export
|
||||
|
||||
/** Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! */
|
||||
int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); }
|
||||
|
@ -309,7 +309,7 @@ protected:
|
||||
eTagType m_ItemType; // for TAG_List, the element type
|
||||
} ;
|
||||
|
||||
static const int MAX_STACK = 50; // Highliy doubtful that an NBT would be constructed this many levels deep
|
||||
static const int MAX_STACK = 50; // Highly doubtful that an NBT would be constructed this many levels deep
|
||||
|
||||
// These two fields emulate a stack. A raw array is used due to speed issues - no reallocations are allowed.
|
||||
sParent m_Stack[MAX_STACK];
|
||||
|
252
src/WorldStorage/FireworksSerializer.cpp
Normal file
252
src/WorldStorage/FireworksSerializer.cpp
Normal file
@ -0,0 +1,252 @@
|
||||
|
||||
#include "Globals.h"
|
||||
#include "FireworksSerializer.h"
|
||||
#include "WorldStorage/FastNBT.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireworkItem::WriteToNBTCompound(const cFireworkItem & a_FireworkItem, cFastNBTWriter & a_Writer, const ENUM_ITEM_ID a_Type)
|
||||
{
|
||||
switch (a_Type)
|
||||
{
|
||||
case E_ITEM_FIREWORK_ROCKET:
|
||||
{
|
||||
a_Writer.BeginCompound("Fireworks");
|
||||
a_Writer.AddByte("Flight", a_FireworkItem.m_FlightTimeInTicks / 20);
|
||||
a_Writer.BeginList("Explosions", TAG_Compound);
|
||||
a_Writer.BeginCompound("");
|
||||
a_Writer.AddByte("Flicker", a_FireworkItem.m_HasFlicker);
|
||||
a_Writer.AddByte("Trail", a_FireworkItem.m_HasTrail);
|
||||
a_Writer.AddByte("Type", a_FireworkItem.m_Type);
|
||||
a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size());
|
||||
a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size());
|
||||
a_Writer.EndCompound();
|
||||
a_Writer.EndList();
|
||||
a_Writer.EndCompound();
|
||||
break;
|
||||
}
|
||||
case E_ITEM_FIREWORK_STAR:
|
||||
{
|
||||
a_Writer.BeginCompound("Explosion");
|
||||
a_Writer.AddByte("Flicker", a_FireworkItem.m_HasFlicker);
|
||||
a_Writer.AddByte("Trail", a_FireworkItem.m_HasTrail);
|
||||
a_Writer.AddByte("Type", a_FireworkItem.m_Type);
|
||||
if (!a_FireworkItem.m_Colours.empty())
|
||||
{
|
||||
a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size());
|
||||
}
|
||||
if (!a_FireworkItem.m_FadeColours.empty())
|
||||
{
|
||||
a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size());
|
||||
}
|
||||
a_Writer.EndCompound();
|
||||
break;
|
||||
}
|
||||
default: ASSERT(!"Unhandled firework item!"); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNBT & a_NBT, int a_TagIdx, const ENUM_ITEM_ID a_Type)
|
||||
{
|
||||
if (a_TagIdx < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (a_Type)
|
||||
{
|
||||
case E_ITEM_FIREWORK_STAR:
|
||||
{
|
||||
for (int explosiontag = a_NBT.GetFirstChild(a_TagIdx); explosiontag >= 0; explosiontag = a_NBT.GetNextSibling(explosiontag))
|
||||
{
|
||||
eTagType TagType = a_NBT.GetType(explosiontag);
|
||||
if (TagType == TAG_Byte) // Custon name tag
|
||||
{
|
||||
AString ExplosionName = a_NBT.GetName(explosiontag);
|
||||
|
||||
if (ExplosionName == "Flicker")
|
||||
{
|
||||
a_FireworkItem.m_HasFlicker = (a_NBT.GetByte(explosiontag) == 1);
|
||||
}
|
||||
else if (ExplosionName == "Trail")
|
||||
{
|
||||
a_FireworkItem.m_HasTrail = (a_NBT.GetByte(explosiontag) == 1);
|
||||
}
|
||||
else if (ExplosionName == "Type")
|
||||
{
|
||||
a_FireworkItem.m_Type = a_NBT.GetByte(explosiontag);
|
||||
}
|
||||
}
|
||||
else if (TagType == TAG_IntArray)
|
||||
{
|
||||
AString ExplosionName = a_NBT.GetName(explosiontag);
|
||||
|
||||
if (ExplosionName == "Colors")
|
||||
{
|
||||
// Divide by four as data length returned in bytes
|
||||
int DataLength = a_NBT.GetDataLength(explosiontag) / 4;
|
||||
if (DataLength == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const int * ColourData = (const int *)(a_NBT.GetData(explosiontag));
|
||||
for (int i = 0; i < DataLength; i++)
|
||||
{
|
||||
a_FireworkItem.m_Colours.push_back(ntohl(ColourData[i]));
|
||||
}
|
||||
}
|
||||
else if (ExplosionName == "FadeColors")
|
||||
{
|
||||
int DataLength = a_NBT.GetDataLength(explosiontag) / 4;
|
||||
if (DataLength == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const int * FadeColourData = (const int *)(a_NBT.GetData(explosiontag));
|
||||
for (int i = 0; i < DataLength; i++)
|
||||
{
|
||||
a_FireworkItem.m_FadeColours.push_back(ntohl(FadeColourData[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case E_ITEM_FIREWORK_ROCKET:
|
||||
{
|
||||
for (int fireworkstag = a_NBT.GetFirstChild(a_TagIdx); fireworkstag >= 0; fireworkstag = a_NBT.GetNextSibling(fireworkstag))
|
||||
{
|
||||
eTagType TagType = a_NBT.GetType(fireworkstag);
|
||||
if (TagType == TAG_Byte) // Custon name tag
|
||||
{
|
||||
if (a_NBT.GetName(fireworkstag) == "Flight")
|
||||
{
|
||||
a_FireworkItem.m_FlightTimeInTicks = a_NBT.GetByte(fireworkstag) * 20;
|
||||
}
|
||||
}
|
||||
else if ((TagType == TAG_List) && (a_NBT.GetName(fireworkstag) == "Explosions"))
|
||||
{
|
||||
int ExplosionsChild = a_NBT.GetFirstChild(fireworkstag);
|
||||
if ((a_NBT.GetType(ExplosionsChild) == TAG_Compound) && (a_NBT.GetName(ExplosionsChild).empty()))
|
||||
{
|
||||
ParseFromNBT(a_FireworkItem, a_NBT, ExplosionsChild, E_ITEM_FIREWORK_STAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: ASSERT(!"Unhandled firework item!"); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AString cFireworkItem::ColoursToString(const cFireworkItem & a_FireworkItem)
|
||||
{
|
||||
AString Result;
|
||||
|
||||
for (std::vector<int>::const_iterator itr = a_FireworkItem.m_Colours.begin(); itr != a_FireworkItem.m_Colours.end(); ++itr)
|
||||
{
|
||||
AppendPrintf(Result, "%i;", *itr);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireworkItem::ColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem)
|
||||
{
|
||||
AStringVector Split = StringSplit(a_String, ";");
|
||||
|
||||
for (size_t itr = 0; itr < Split.size(); ++itr)
|
||||
{
|
||||
if (Split[itr].empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
a_FireworkItem.m_Colours.push_back(atoi(Split[itr].c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AString cFireworkItem::FadeColoursToString(const cFireworkItem & a_FireworkItem)
|
||||
{
|
||||
AString Result;
|
||||
|
||||
for (std::vector<int>::const_iterator itr = a_FireworkItem.m_FadeColours.begin(); itr != a_FireworkItem.m_FadeColours.end(); ++itr)
|
||||
{
|
||||
AppendPrintf(Result, "%i;", *itr);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireworkItem::FadeColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem)
|
||||
{
|
||||
AStringVector Split = StringSplit(a_String, ";");
|
||||
|
||||
for (size_t itr = 0; itr < Split.size(); ++itr)
|
||||
{
|
||||
if (Split[itr].empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
a_FireworkItem.m_FadeColours.push_back(atoi(Split[itr].c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cFireworkItem::GetVanillaColourCodeFromDye(short a_DyeMeta)
|
||||
{
|
||||
/*
|
||||
Colours are supposed to be calculated via: R << 16 + G << 8 + B
|
||||
However, the RGB values fireworks use aren't the same as the ones for dyes (the ones listed in the MC Wiki)
|
||||
Therefore, here is a list of numbers gotten via the Protocol Proxy
|
||||
*/
|
||||
|
||||
switch (a_DyeMeta)
|
||||
{
|
||||
case E_META_DYE_BLACK: return 0x1E1B1B;
|
||||
case E_META_DYE_RED: return 0xB3312C;
|
||||
case E_META_DYE_GREEN: return 0x3B511A;
|
||||
case E_META_DYE_BROWN: return 0x51301A;
|
||||
case E_META_DYE_BLUE: return 0x253192;
|
||||
case E_META_DYE_PURPLE: return 0x7B2FBE;
|
||||
case E_META_DYE_CYAN: return 0x287697;
|
||||
case E_META_DYE_LIGHTGRAY: return 0xABABAB;
|
||||
case E_META_DYE_GRAY: return 0x434343;
|
||||
case E_META_DYE_PINK: return 0xD88198;
|
||||
case E_META_DYE_LIGHTGREEN: return 0x41CD34;
|
||||
case E_META_DYE_YELLOW: return 0xDECF2A;
|
||||
case E_META_DYE_LIGHTBLUE: return 0x6689D3;
|
||||
case E_META_DYE_MAGENTA: return 0xC354CD;
|
||||
case E_META_DYE_ORANGE: return 0xEB8844;
|
||||
case E_META_DYE_WHITE: return 0xF0F0F0;
|
||||
default: ASSERT(!"Unhandled dye meta whilst trying to get colour code for fireworks!"); return 0;
|
||||
}
|
||||
}
|
92
src/WorldStorage/FireworksSerializer.h
Normal file
92
src/WorldStorage/FireworksSerializer.h
Normal file
@ -0,0 +1,92 @@
|
||||
|
||||
// FireworksSerializer.h
|
||||
|
||||
// Declares the cFireworkItem class representing a firework or firework star
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
|
||||
class cFastNBTWriter;
|
||||
class cParsedNBT;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cFireworkItem
|
||||
{
|
||||
public:
|
||||
cFireworkItem(void) :
|
||||
m_HasFlicker(false),
|
||||
m_HasTrail(false),
|
||||
m_Type(0),
|
||||
m_FlightTimeInTicks(0)
|
||||
{
|
||||
}
|
||||
|
||||
inline void CopyFrom(const cFireworkItem & a_Item)
|
||||
{
|
||||
m_FlightTimeInTicks = a_Item.m_FlightTimeInTicks;
|
||||
m_HasFlicker = a_Item.m_HasFlicker;
|
||||
m_HasTrail = a_Item.m_HasTrail;
|
||||
m_Type = a_Item.m_Type;
|
||||
m_Colours = a_Item.m_Colours;
|
||||
m_FadeColours = a_Item.m_FadeColours;
|
||||
}
|
||||
|
||||
inline void EmptyData(void)
|
||||
{
|
||||
m_FlightTimeInTicks = 0;
|
||||
m_HasFlicker = false;
|
||||
m_Type = 0;
|
||||
m_HasTrail = false;
|
||||
m_Colours.clear();
|
||||
m_FadeColours.clear();
|
||||
}
|
||||
|
||||
inline bool IsEqualTo(const cFireworkItem & a_Item) const
|
||||
{
|
||||
return
|
||||
(
|
||||
(m_FlightTimeInTicks == a_Item.m_FlightTimeInTicks) &&
|
||||
(m_HasFlicker == a_Item.m_HasFlicker) &&
|
||||
(m_HasTrail == a_Item.m_HasTrail) &&
|
||||
(m_Type == a_Item.m_Type) &&
|
||||
(m_Colours == a_Item.m_Colours) &&
|
||||
(m_FadeColours == a_Item.m_FadeColours)
|
||||
);
|
||||
}
|
||||
|
||||
/** Writes firework NBT data to a Writer object */
|
||||
static void WriteToNBTCompound(const cFireworkItem & a_FireworkItem, cFastNBTWriter & a_Writer, const ENUM_ITEM_ID a_Type);
|
||||
|
||||
/** Reads NBT data from a NBT object and populates a FireworkItem with it */
|
||||
static void ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNBT & a_NBT, int a_TagIdx, const ENUM_ITEM_ID a_Type);
|
||||
|
||||
/** Converts the firework's vector of colours into a string of values separated by a semicolon */
|
||||
static AString ColoursToString(const cFireworkItem & a_FireworkItem);
|
||||
|
||||
/** Parses a string containing encoded firework colours and populates a FireworkItem with it */
|
||||
static void ColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem);
|
||||
|
||||
/** Converts the firework's vector of fade colours into a string of values separated by a semicolon */
|
||||
static AString FadeColoursToString(const cFireworkItem & a_FireworkItem);
|
||||
|
||||
/** Parses a string containing encoded firework fade colours and populates a FireworkItem with it */
|
||||
static void FadeColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem);
|
||||
|
||||
/** Returns a colour code for fireworks used by the network code */
|
||||
static int GetVanillaColourCodeFromDye(short a_DyeMeta);
|
||||
|
||||
bool m_HasFlicker;
|
||||
bool m_HasTrail;
|
||||
NIBBLETYPE m_Type;
|
||||
short m_FlightTimeInTicks;
|
||||
std::vector<int> m_Colours;
|
||||
std::vector<int> m_FadeColours;
|
||||
};
|
@ -28,6 +28,7 @@
|
||||
#include "../Entities/Minecart.h"
|
||||
#include "../Entities/Pickup.h"
|
||||
#include "../Entities/ProjectileEntity.h"
|
||||
#include "../Entities/TNTEntity.h"
|
||||
|
||||
#include "../Mobs/Monster.h"
|
||||
#include "../Mobs/Bat.h"
|
||||
@ -91,11 +92,19 @@ void cNBTChunkSerializer::AddItem(const cItem & a_Item, int a_Slot, const AStrin
|
||||
}
|
||||
|
||||
// Write the enchantments:
|
||||
if (!a_Item.m_Enchantments.IsEmpty())
|
||||
if (!a_Item.m_Enchantments.IsEmpty() || ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR)))
|
||||
{
|
||||
const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
|
||||
m_Writer.BeginCompound("tag");
|
||||
EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, m_Writer, TagName);
|
||||
if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR))
|
||||
{
|
||||
cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, m_Writer, (ENUM_ITEM_ID)a_Item.m_ItemType);
|
||||
}
|
||||
|
||||
if (!a_Item.m_Enchantments.IsEmpty())
|
||||
{
|
||||
const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
|
||||
EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, m_Writer, TagName);
|
||||
}
|
||||
m_Writer.EndCompound();
|
||||
}
|
||||
|
||||
@ -583,6 +592,18 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
|
||||
|
||||
|
||||
|
||||
void cNBTChunkSerializer::AddTNTEntity(cTNTEntity * a_TNT)
|
||||
{
|
||||
m_Writer.BeginCompound("");
|
||||
AddBasicEntity(a_TNT, "PrimedTnt");
|
||||
m_Writer.AddByte("Fuse", (unsigned char)a_TNT->GetFuseTicks());
|
||||
m_Writer.EndCompound();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Minecart)
|
||||
{
|
||||
m_Writer.BeginList("Items", TAG_Compound);
|
||||
@ -662,7 +683,7 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity)
|
||||
case cEntity::etMonster: AddMonsterEntity ((cMonster *) a_Entity); break;
|
||||
case cEntity::etPickup: AddPickupEntity ((cPickup *) a_Entity); break;
|
||||
case cEntity::etProjectile: AddProjectileEntity ((cProjectileEntity *)a_Entity); break;
|
||||
case cEntity::etTNT: /* TODO */ break;
|
||||
case cEntity::etTNT: AddTNTEntity ((cTNTEntity *) a_Entity); break;
|
||||
case cEntity::etExpOrb: /* TODO */ break;
|
||||
case cEntity::etItemFrame: /* TODO */ break;
|
||||
case cEntity::etPainting: /* TODO */ break;
|
||||
|
@ -41,6 +41,7 @@ class cMonster;
|
||||
class cPickup;
|
||||
class cItemGrid;
|
||||
class cProjectileEntity;
|
||||
class cTNTEntity;
|
||||
|
||||
|
||||
|
||||
@ -107,6 +108,7 @@ protected:
|
||||
void AddMonsterEntity (cMonster * a_Monster);
|
||||
void AddPickupEntity (cPickup * a_Pickup);
|
||||
void AddProjectileEntity (cProjectileEntity * a_Projectile);
|
||||
void AddTNTEntity (cTNTEntity * a_TNT);
|
||||
|
||||
void AddMinecartChestContents(cMinecartWithChest * a_Minecart);
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "../Entities/Minecart.h"
|
||||
#include "../Entities/Pickup.h"
|
||||
#include "../Entities/ProjectileEntity.h"
|
||||
#include "../Entities/TNTEntity.h"
|
||||
|
||||
|
||||
|
||||
@ -663,6 +664,12 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_
|
||||
{
|
||||
EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, a_NBT, EnchTag);
|
||||
}
|
||||
|
||||
int FireworksTag = a_NBT.FindChildByName(TagTag, ((a_Item.m_ItemType == E_ITEM_FIREWORK_STAR) ? "Fireworks" : "Explosion"));
|
||||
if (EnchTag > 0)
|
||||
{
|
||||
cFireworkItem::ParseFromNBT(a_Item.m_FireworkItem, a_NBT, FireworksTag, (ENUM_ITEM_ID)a_Item.m_ItemType);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1231,6 +1238,10 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
|
||||
{
|
||||
LoadPigZombieFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||
}
|
||||
else if (strncmp(a_IDTag, "PrimedTnt", a_IDTagLength) == 0)
|
||||
{
|
||||
LoadTNTFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||
}
|
||||
// TODO: other entities
|
||||
}
|
||||
|
||||
@ -2167,6 +2178,28 @@ void cWSSAnvil::LoadPigZombieFromNBT(cEntityList & a_Entities, const cParsedNBT
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
std::auto_ptr<cTNTEntity> TNT(new cTNTEntity(0.0, 0.0, 0.0, 0));
|
||||
if (!LoadEntityBaseFromNBT(*TNT.get(), a_NBT, a_TagIdx))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Load Fuse Ticks:
|
||||
int FuseTicks = a_NBT.FindChildByName(a_TagIdx, "Fuse");
|
||||
if (FuseTicks > 0)
|
||||
{
|
||||
TNT->SetFuseTicks((int) a_NBT.GetByte(FuseTicks));
|
||||
}
|
||||
|
||||
a_Entities.push_back(TNT.release());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
double Pos[3];
|
||||
|
@ -192,6 +192,7 @@ protected:
|
||||
void LoadWolfFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadPigZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadTNTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
|
||||
/// Loads entity common data from the NBT compound; returns true if successful
|
||||
bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
|
Loading…
Reference in New Issue
Block a user