commit
9f321e29cf
@ -1 +1 @@
|
|||||||
Subproject commit 7cc99285ae5117418f657c3b295ca71f2b75b4f4
|
Subproject commit bd23915df763b182610c6163c5ff2d64a0756560
|
@ -13,6 +13,7 @@
|
|||||||
#include "../Root.h"
|
#include "../Root.h"
|
||||||
#include "../Server.h" // ExecuteConsoleCommand()
|
#include "../Server.h" // ExecuteConsoleCommand()
|
||||||
#include "../Chunk.h"
|
#include "../Chunk.h"
|
||||||
|
#include "../ChatColor.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -206,15 +207,28 @@ void cCommandBlockEntity::Execute()
|
|||||||
virtual void Out(const AString & a_Text)
|
virtual void Out(const AString & a_Text)
|
||||||
{
|
{
|
||||||
// Overwrite field
|
// Overwrite field
|
||||||
m_CmdBlock->SetLastOutput(a_Text);
|
m_CmdBlock->SetLastOutput(cClientHandle::FormatChatPrefix(m_CmdBlock->GetWorld()->ShouldUseChatPrefixes(), "SUCCESS", cChatColor::Green, cChatColor::White) + a_Text);
|
||||||
}
|
}
|
||||||
} CmdBlockOutCb(this);
|
} CmdBlockOutCb(this);
|
||||||
|
|
||||||
LOGD("cCommandBlockEntity: Executing command %s", m_Command.c_str());
|
// Administrator commands are not executable by command blocks:
|
||||||
|
if (
|
||||||
cServer * Server = cRoot::Get()->GetServer();
|
(m_Command != "stop") &&
|
||||||
|
(m_Command != "restart") &&
|
||||||
Server->ExecuteConsoleCommand(m_Command, CmdBlockOutCb);
|
(m_Command != "kick") &&
|
||||||
|
(m_Command != "ban") &&
|
||||||
|
(m_Command != "ipban")
|
||||||
|
)
|
||||||
|
{
|
||||||
|
cServer * Server = cRoot::Get()->GetServer();
|
||||||
|
LOGD("cCommandBlockEntity: Executing command %s", m_Command.c_str());
|
||||||
|
Server->ExecuteConsoleCommand(m_Command, CmdBlockOutCb);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetLastOutput(cClientHandle::FormatChatPrefix(GetWorld()->ShouldUseChatPrefixes(), "FAILURE", cChatColor::Rose, cChatColor::White) + "Adminstration commands can not be executed");
|
||||||
|
LOGD("cCommandBlockEntity: Prevented execution of administration command %s", m_Command.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
// TODO 2014-01-18 xdot: Update the signal strength.
|
// TODO 2014-01-18 xdot: Update the signal strength.
|
||||||
m_Result = 0;
|
m_Result = 0;
|
||||||
|
@ -1880,21 +1880,19 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
|
|||||||
}
|
}
|
||||||
else if ((m_World->GetTNTShrapnelLevel() > slNone) && (m_World->GetTickRandomNumber(100) < 20)) // 20% chance of flinging stuff around
|
else if ((m_World->GetTNTShrapnelLevel() > slNone) && (m_World->GetTickRandomNumber(100) < 20)) // 20% chance of flinging stuff around
|
||||||
{
|
{
|
||||||
if (!cBlockInfo::FullyOccupiesVoxel(Block))
|
// If the block is shrapnel-able, make a falling block entity out of it:
|
||||||
|
if (
|
||||||
|
((m_World->GetTNTShrapnelLevel() == slAll) && cBlockInfo::FullyOccupiesVoxel(Block)) ||
|
||||||
|
((m_World->GetTNTShrapnelLevel() == slGravityAffectedOnly) && ((Block == E_BLOCK_SAND) || (Block == E_BLOCK_GRAVEL)))
|
||||||
|
)
|
||||||
{
|
{
|
||||||
break;
|
m_World->SpawnFallingBlock(bx + x, by + y + 5, bz + z, Block, area.GetBlockMeta(bx + x, by + y, bz + z));
|
||||||
}
|
}
|
||||||
else if ((m_World->GetTNTShrapnelLevel() == slGravityAffectedOnly) && ((Block != E_BLOCK_SAND) && (Block != E_BLOCK_GRAVEL)))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
m_World->SpawnFallingBlock(bx + x, by + y + 5, bz + z, Block, area.GetBlockMeta(bx + x, by + y, bz + z));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
area.SetBlockTypeMeta(bx + x, by + y, bz + z, E_BLOCK_AIR, 0);
|
area.SetBlockTypeMeta(bx + x, by + y, bz + z, E_BLOCK_AIR, 0);
|
||||||
a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z));
|
a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
} // switch (BlockType)
|
} // switch (BlockType)
|
||||||
} // for z
|
} // for z
|
||||||
@ -1916,51 +1914,31 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
|
|||||||
|
|
||||||
virtual bool Item(cEntity * a_Entity) override
|
virtual bool Item(cEntity * a_Entity) override
|
||||||
{
|
{
|
||||||
if (a_Entity->IsPickup())
|
if (a_Entity->IsPickup() && (a_Entity->GetTicksAlive() < 20))
|
||||||
{
|
{
|
||||||
if (((cPickup *)a_Entity)->GetAge() < 20) // If pickup age is smaller than one second, it is invincible (so we don't kill pickups that were just spawned)
|
// If pickup age is smaller than one second, it is invincible (so we don't kill pickups that were just spawned)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3d DistanceFromExplosion = a_Entity->GetPosition() - m_ExplosionPos;
|
||||||
|
|
||||||
|
if (!a_Entity->IsTNT() && !a_Entity->IsFallingBlock()) // Don't apply damage to other TNT entities and falling blocks, they should be invincible
|
||||||
|
{
|
||||||
|
cBoundingBox bbEntity(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight());
|
||||||
|
|
||||||
|
if (!m_bbTNT.IsInside(bbEntity)) // If bbEntity is inside bbTNT, not vice versa!
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Vector3d EntityPos = a_Entity->GetPosition();
|
// Ensure that the damage dealt is inversely proportional to the distance to the TNT centre - the closer a player is, the harder they are hit
|
||||||
cBoundingBox bbEntity(EntityPos, a_Entity->GetWidth() / 2, a_Entity->GetHeight());
|
a_Entity->TakeDamage(dtExplosion, NULL, (int)((1 / DistanceFromExplosion.Length()) * 6 * m_ExplosionSize), 0);
|
||||||
|
|
||||||
if (!m_bbTNT.IsInside(bbEntity)) // IsInside actually acts like DoesSurround
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3d AbsoluteEntityPos(abs(EntityPos.x), abs(EntityPos.y), abs(EntityPos.z));
|
|
||||||
|
|
||||||
// Work out how far we are from the edge of the TNT's explosive effect
|
|
||||||
AbsoluteEntityPos -= m_ExplosionPos;
|
|
||||||
|
|
||||||
// All to positive
|
|
||||||
AbsoluteEntityPos.x = abs(AbsoluteEntityPos.x);
|
|
||||||
AbsoluteEntityPos.y = abs(AbsoluteEntityPos.y);
|
|
||||||
AbsoluteEntityPos.z = abs(AbsoluteEntityPos.z);
|
|
||||||
|
|
||||||
double FinalDamage = (((1 / AbsoluteEntityPos.x) + (1 / AbsoluteEntityPos.y) + (1 / AbsoluteEntityPos.z)) * 2) * m_ExplosionSize;
|
|
||||||
|
|
||||||
// Clip damage values
|
|
||||||
FinalDamage = Clamp(FinalDamage, 0.0, (double)a_Entity->GetMaxHealth());
|
|
||||||
|
|
||||||
if (!a_Entity->IsTNT() && !a_Entity->IsFallingBlock()) // Don't apply damage to other TNT entities and falling blocks, they should be invincible
|
|
||||||
{
|
|
||||||
a_Entity->TakeDamage(dtExplosion, NULL, (int)FinalDamage, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply force to entities around the explosion - code modified from World.cpp DoExplosionAt()
|
// Apply force to entities around the explosion - code modified from World.cpp DoExplosionAt()
|
||||||
Vector3d distance_explosion = a_Entity->GetPosition() - m_ExplosionPos;
|
DistanceFromExplosion.Normalize();
|
||||||
if (distance_explosion.SqrLength() < 4096.0)
|
DistanceFromExplosion *= m_ExplosionSize * m_ExplosionSize;
|
||||||
{
|
a_Entity->AddSpeed(DistanceFromExplosion);
|
||||||
distance_explosion.Normalize();
|
|
||||||
distance_explosion *= m_ExplosionSize * m_ExplosionSize;
|
|
||||||
|
|
||||||
a_Entity->AddSpeed(distance_explosion);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -367,7 +367,7 @@ void cCraftingRecipes::ClearRecipes(void)
|
|||||||
void cCraftingRecipes::AddRecipeLine(int a_LineNum, const AString & a_RecipeLine)
|
void cCraftingRecipes::AddRecipeLine(int a_LineNum, const AString & a_RecipeLine)
|
||||||
{
|
{
|
||||||
AString RecipeLine(a_RecipeLine);
|
AString RecipeLine(a_RecipeLine);
|
||||||
RecipeLine.erase(std::remove(RecipeLine.begin(), RecipeLine.end(), ' '), RecipeLine.end());
|
RecipeLine.erase(std::remove_if(RecipeLine.begin(), RecipeLine.end(), isspace), RecipeLine.end());
|
||||||
|
|
||||||
AStringVector Sides = StringSplit(RecipeLine, "=");
|
AStringVector Sides = StringSplit(RecipeLine, "=");
|
||||||
if (Sides.size() != 2)
|
if (Sides.size() != 2)
|
||||||
|
@ -55,7 +55,6 @@ void cItemFrame::KilledBy(TakeDamageInfo & a_TDI)
|
|||||||
{
|
{
|
||||||
if (m_Item.IsEmpty())
|
if (m_Item.IsEmpty())
|
||||||
{
|
{
|
||||||
SetHealth(0);
|
|
||||||
super::KilledBy(a_TDI);
|
super::KilledBy(a_TDI);
|
||||||
Destroy();
|
Destroy();
|
||||||
return;
|
return;
|
||||||
|
@ -75,7 +75,7 @@ public:
|
|||||||
int FoodLevel;
|
int FoodLevel;
|
||||||
double Saturation;
|
double Saturation;
|
||||||
|
|
||||||
FoodInfo(int a_FoodLevel, double a_Saturation, int a_PoisonChance = 0) :
|
FoodInfo(int a_FoodLevel, double a_Saturation) :
|
||||||
FoodLevel(a_FoodLevel),
|
FoodLevel(a_FoodLevel),
|
||||||
Saturation(a_Saturation)
|
Saturation(a_Saturation)
|
||||||
{
|
{
|
||||||
|
14
src/Root.cpp
14
src/Root.cpp
@ -468,16 +468,6 @@ void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCall
|
|||||||
|
|
||||||
void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd)
|
void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd)
|
||||||
{
|
{
|
||||||
// Some commands are built-in:
|
|
||||||
if (a_Cmd == "stop")
|
|
||||||
{
|
|
||||||
m_bStop = true;
|
|
||||||
}
|
|
||||||
else if (a_Cmd == "restart")
|
|
||||||
{
|
|
||||||
m_bRestart = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put the command into a queue (Alleviates FS #363):
|
// Put the command into a queue (Alleviates FS #363):
|
||||||
cCSLock Lock(m_CSPendingCommands);
|
cCSLock Lock(m_CSPendingCommands);
|
||||||
m_PendingCommands.push_back(cCommand(a_Cmd, new cLogCommandDeleteSelfOutputCallback));
|
m_PendingCommands.push_back(cCommand(a_Cmd, new cLogCommandDeleteSelfOutputCallback));
|
||||||
@ -489,14 +479,16 @@ void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd)
|
|||||||
|
|
||||||
void cRoot::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output)
|
void cRoot::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output)
|
||||||
{
|
{
|
||||||
// Some commands are built-in:
|
// cRoot handles stopping and restarting due to our access to controlling variables
|
||||||
if (a_Cmd == "stop")
|
if (a_Cmd == "stop")
|
||||||
{
|
{
|
||||||
m_bStop = true;
|
m_bStop = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else if (a_Cmd == "restart")
|
else if (a_Cmd == "restart")
|
||||||
{
|
{
|
||||||
m_bRestart = true;
|
m_bRestart = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("Executing console command: \"%s\"", a_Cmd.c_str());
|
LOG("Executing console command: \"%s\"", a_Cmd.c_str());
|
||||||
|
@ -458,56 +458,80 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special handling: "stop" and "restart" are built in
|
// "stop" and "restart" are handled in cRoot::ExecuteConsoleCommand, our caller, due to its access to controlling variables
|
||||||
if ((split[0].compare("stop") == 0) || (split[0].compare("restart") == 0))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// "help" and "reload" are to be handled by MCS, so that they work no matter what
|
// "help" and "reload" are to be handled by MCS, so that they work no matter what
|
||||||
if (split[0] == "help")
|
if (split[0] == "help")
|
||||||
{
|
{
|
||||||
PrintHelp(split, a_Output);
|
PrintHelp(split, a_Output);
|
||||||
|
a_Output.Finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (split[0] == "reload")
|
else if (split[0] == "reload")
|
||||||
{
|
{
|
||||||
cPluginManager::Get()->ReloadPlugins();
|
cPluginManager::Get()->ReloadPlugins();
|
||||||
|
a_Output.Finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (split[0] == "reloadplugins")
|
else if (split[0] == "reloadplugins")
|
||||||
{
|
{
|
||||||
cPluginManager::Get()->ReloadPlugins();
|
cPluginManager::Get()->ReloadPlugins();
|
||||||
|
a_Output.Out("Plugins reloaded");
|
||||||
|
a_Output.Finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (split[0] == "load")
|
else if (split[0] == "load")
|
||||||
{
|
{
|
||||||
if (split.size() > 1)
|
if (split.size() > 1)
|
||||||
{
|
{
|
||||||
cPluginManager::Get()->LoadPlugin(split[1]);
|
a_Output.Out(cPluginManager::Get()->LoadPlugin(split[1]) ? "Plugin loaded" : "Error occurred loading plugin");
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
a_Output.Out("No plugin given! Command: load <pluginname>");
|
a_Output.Out("Usage: load <pluginname>");
|
||||||
a_Output.Finished();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
a_Output.Finished();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else if (split[0] == "unload")
|
else if (split[0] == "unload")
|
||||||
{
|
{
|
||||||
if (split.size() > 1)
|
if (split.size() > 1)
|
||||||
{
|
{
|
||||||
cPluginManager::Get()->RemovePlugin(cPluginManager::Get()->GetPlugin(split[1]));
|
cPluginManager::Get()->RemovePlugin(cPluginManager::Get()->GetPlugin(split[1]));
|
||||||
return;
|
a_Output.Out("Plugin unloaded");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
a_Output.Out("No plugin given! Command: unload <pluginname>");
|
a_Output.Out("Usage: unload <pluginname>");
|
||||||
a_Output.Finished();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
a_Output.Finished();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (split[0] == "destroyentities")
|
||||||
|
{
|
||||||
|
class WorldCallback : public cWorldListCallback
|
||||||
|
{
|
||||||
|
virtual bool Item(cWorld * a_World) override
|
||||||
|
{
|
||||||
|
class EntityCallback : public cEntityCallback
|
||||||
|
{
|
||||||
|
virtual bool Item(cEntity * a_Entity) override
|
||||||
|
{
|
||||||
|
if (!a_Entity->IsPlayer())
|
||||||
|
{
|
||||||
|
a_Entity->Destroy();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} EC;
|
||||||
|
a_World->ForEachEntity(EC);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} WC;
|
||||||
|
cRoot::Get()->ForEachWorld(WC);
|
||||||
|
a_Output.Out("Destroyed all entities");
|
||||||
|
a_Output.Finished();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is currently no way a plugin can do these (and probably won't ever be):
|
// There is currently no way a plugin can do these (and probably won't ever be):
|
||||||
@ -602,6 +626,7 @@ void cServer::BindBuiltInConsoleCommands(void)
|
|||||||
PlgMgr->BindConsoleCommand("chunkstats", NULL, " - Displays detailed chunk memory statistics");
|
PlgMgr->BindConsoleCommand("chunkstats", NULL, " - Displays detailed chunk memory statistics");
|
||||||
PlgMgr->BindConsoleCommand("load <pluginname>", NULL, " - Adds and enables the specified plugin");
|
PlgMgr->BindConsoleCommand("load <pluginname>", NULL, " - Adds and enables the specified plugin");
|
||||||
PlgMgr->BindConsoleCommand("unload <pluginname>", NULL, " - Disables the specified plugin");
|
PlgMgr->BindConsoleCommand("unload <pluginname>", NULL, " - Disables the specified plugin");
|
||||||
|
PlgMgr->BindConsoleCommand("destroyentities", NULL, " - Destroys all entities in all worlds");
|
||||||
|
|
||||||
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
|
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
|
||||||
PlgMgr->BindConsoleCommand("dumpmem", NULL, " - Dumps all used memory blocks together with their callstacks into memdump.xml");
|
PlgMgr->BindConsoleCommand("dumpmem", NULL, " - Dumps all used memory blocks together with their callstacks into memdump.xml");
|
||||||
|
@ -1226,24 +1226,26 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add damage to entities and implement block hardiness
|
// TODO: Implement block hardiness
|
||||||
Vector3d explosion_pos = Vector3d(a_BlockX, a_BlockY, a_BlockZ);
|
Vector3d explosion_pos = Vector3d(a_BlockX, a_BlockY, a_BlockZ);
|
||||||
cVector3iArray BlocksAffected;
|
cVector3iArray BlocksAffected;
|
||||||
m_ChunkMap->DoExplosionAt(a_ExplosionSize, a_BlockX, a_BlockY, a_BlockZ, BlocksAffected);
|
m_ChunkMap->DoExplosionAt(a_ExplosionSize, a_BlockX, a_BlockY, a_BlockZ, BlocksAffected);
|
||||||
BroadcastSoundEffect("random.explode", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 0.6f);
|
BroadcastSoundEffect("random.explode", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 0.6f);
|
||||||
|
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSPlayers);
|
cCSLock Lock(m_CSPlayers);
|
||||||
for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
|
for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
|
||||||
{
|
{
|
||||||
cClientHandle * ch = (*itr)->GetClientHandle();
|
cClientHandle * ch = (*itr)->GetClientHandle();
|
||||||
if ((ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed())
|
if (ch == NULL)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3d distance_explosion = (*itr)->GetPosition() - explosion_pos;
|
Vector3d distance_explosion = (*itr)->GetPosition() - explosion_pos;
|
||||||
if (distance_explosion.SqrLength() < 4096.0)
|
if (distance_explosion.SqrLength() < 4096.0)
|
||||||
{
|
{
|
||||||
double real_distance = std::max(0.004, sqrt(distance_explosion.SqrLength()));
|
double real_distance = std::max(0.004, distance_explosion.Length());
|
||||||
double power = a_ExplosionSize / real_distance;
|
double power = a_ExplosionSize / real_distance;
|
||||||
if (power <= 1)
|
if (power <= 1)
|
||||||
{
|
{
|
||||||
@ -1255,6 +1257,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cPluginManager::Get()->CallHookExploded(*this, a_ExplosionSize, a_CanCauseFire, a_BlockX, a_BlockY, a_BlockZ, a_Source, a_SourceData);
|
cPluginManager::Get()->CallHookExploded(*this, a_ExplosionSize, a_CanCauseFire, a_BlockX, a_BlockY, a_BlockZ, a_Source, a_SourceData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,7 +615,6 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
|
|||||||
{
|
{
|
||||||
m_Writer.BeginCompound("");
|
m_Writer.BeginCompound("");
|
||||||
AddBasicEntity(a_Projectile, a_Projectile->GetMCAClassName());
|
AddBasicEntity(a_Projectile, a_Projectile->GetMCAClassName());
|
||||||
Vector3d Pos = a_Projectile->GetPosition();
|
|
||||||
m_Writer.AddByte("inGround", a_Projectile->IsInGround() ? 1 : 0);
|
m_Writer.AddByte("inGround", a_Projectile->IsInGround() ? 1 : 0);
|
||||||
|
|
||||||
switch (a_Projectile->GetProjectileKind())
|
switch (a_Projectile->GetProjectileKind())
|
||||||
|
Loading…
Reference in New Issue
Block a user