1
0
Fork 0

Merge remote-tracking branch 'origin/master' into ChunkStay

This commit is contained in:
madmaxoft 2014-02-09 09:36:42 +01:00
commit a184d59209
36 changed files with 378 additions and 161 deletions

View File

@ -693,7 +693,6 @@ end
GetRawDamageAgainst = { Params = "ReceiverEntity", Return = "number", Notes = "Returns the raw damage that this entity's equipment would cause when attacking the ReceiverEntity. This includes this entity's weapon {{cEnchantments|enchantments}}, but excludes the receiver's armor or potion effects. See {{TakeDamageInfo}} for more information on attack damage." },
GetRoll = { Params = "", Return = "number", Notes = "Returns the roll (sideways rotation) of the entity. Currently unused." },
GetRot = { Params = "", Return = "{{Vector3f}}", Notes = "Returns the entire rotation vector (Yaw, Pitch, Roll)" },
GetRotation = { Params = "", Return = "number", Notes = "Returns the yaw (direction) of the entity. OBSOLETE, use GetYaw() instead." },
GetSpeed = { Params = "", Return = "{{Vector3d}}", Notes = "Returns the complete speed vector of the entity" },
GetSpeedX = { Params = "", Return = "number", Notes = "Returns the X-part of the speed vector" },
GetSpeedY = { Params = "", Return = "number", Notes = "Returns the Y-part of the speed vector" },
@ -720,8 +719,11 @@ end
IsRclking = { Params = "", Return = "bool", Notes = "Currently unimplemented" },
IsRiding = { Params = "", Return = "bool", Notes = "Returns true if the entity is attached to (riding) another entity." },
IsSprinting = { Params = "", Return = "bool", Notes = "Returns true if the entity is sprinting. Entities that cannot sprint return always false" },
IsSubmerged = { Params = "", Return = "bool", Notes = "Returns true if the mob or player is submerged in water (head is in a water block). Note, this function is only updated with mobs or players." },
IsSwimming = { Params = "", Return = "bool", Notes = "Returns true if the mob or player is swimming in water (feet are in a water block). Note, this function is only updated with mobs or players." },
IsTNT = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cTNTEntity|TNT entity}}" },
KilledBy = { Notes = "FIXME: Remove this from API" },
GetAirLevel = { Params = "", Return = "number", Notes = "Returns the air level (number of ticks of air left). Note, this function is only updated with mobs or players." },
SetGravity = { Params = "Gravity", Return = "", Notes = "Sets the number that is used as the gravity for physics simulation. 1G (9.78) by default." },
SetHeadYaw = { Params = "HeadPitch", Return = "", Notes = "Sets the head pitch (FIXME: Rename to SetHeadPitch() )." },
SetHealth = { Params = "Hitpoints", Return = "", Notes = "Sets the entity's health to the specified amount of hitpoints. Doesn't broadcast any hurt animation. Doesn't kill the entity if health drops below zero. Use the TakeDamage() function instead for taking damage." },
@ -740,8 +742,7 @@ end
SetPosZ = { Params = "number", Return = "", Notes = "Sets the Z-coord of the entity's pivot" },
SetRoll = { Params = "number", Return = "", Notes = "Sets the roll (sideways rotation) of the entity. Currently unused." },
SetRot = { Params = "{{Vector3f|Rotation}}", Return = "", Notes = "Sets the entire rotation vector (Yaw, Pitch, Roll)" },
SetRotation = { Params = "number", Return = "", Notes = "Sets the yaw (direction) of the entity. OBSOLETE, use SetYaw() instead." },
SetRotationFromSpeed = { Params = "", Return = "", Notes = "Sets the entity's yaw to match its current speed (entity looking forwards as it moves). (FIXME: Rename to SetYawFromSpeed)" },
SetYawFromSpeed = { Params = "", Return = "", Notes = "Sets the entity's yaw to match its current speed (entity looking forwards as it moves). (FIXME: Rename to SetYawFromSpeed)" },
SetSpeed =
{
{ Params = "SpeedX, SpeedY, SpeedZ", Return = "", Notes = "Sets the current speed of the entity" },
@ -1103,8 +1104,8 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
GetMaxStackSize = { Params = "", Return = "number", Notes = "Returns the maximum stack size for this item." },
IsDamageable = { Params = "", Return = "bool", Notes = "Returns true if this item does account for its damage" },
IsEmpty = { Params = "", Return = "bool", Notes = "Returns true if this object represents an empty item (zero count or invalid ID)" },
IsEqual = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is the same as the one stored in the object (type, damage, lore, name and enchantments)" },
IsEnchantable = { Params = "", Return = "bool", Notes = "Returns true if the item is enchantable" },
IsEqual = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is the same as the one stored in the object (type, damage and enchantments)" },
IsFullStack = { Params = "", Return = "bool", Notes = "Returns true if the item is stacked up to its maximum stacking" },
IsSameType = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is of the same ItemType as the one stored in the object. This is true even if the two items have different enchantments" },
IsStackableWith = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is stackable with the one stored in the object. Two items with different enchantments cannot be stacked" },
@ -1566,7 +1567,6 @@ a_Player:OpenWindow(Window);
]],
Functions =
{
constructor = { Params = "PosX, PosY, PosZ, {{cItem|Item}}, IsPlayerCreated, [SpeedX, SpeedY, SpeedZ]", Return = "cPickup", Notes = "Creates a new pickup at the specified coords. If IsPlayerCreated is true, the pickup has a longer initial collection interval." },
CollectedBy = { Params = "{{cPlayer}}", Return = "bool", Notes = "Tries to make the player collect the pickup. Returns true if the pickup was collected, at least partially." },
GetAge = { Params = "", Return = "number", Notes = "Returns the number of ticks that the pickup has existed." },
GetItem = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item represented by this pickup" },
@ -1596,7 +1596,6 @@ a_Player:OpenWindow(Window);
Feed = { Params = "AddFood, AddSaturation", Return = "bool", Notes = "Tries to add the specified amounts to food level and food saturation level (only positive amounts expected). Returns true if player was hungry and the food was consumed, false if too satiated." },
FoodPoison = { Params = "NumTicks", Return = "", Notes = "Starts the food poisoning for the specified amount of ticks; if already foodpoisoned, sets FoodPoisonedTicksRemaining to the larger of the two" },
ForceSetSpeed = { Params = "{{Vector3d|Direction}}", Notes = "Forces the player to move to the given direction." },
GetAirLevel = { Params = "", Return = "number", Notes = "Returns the air level (number of ticks of air left)." },
GetClientHandle = { Params = "", Return = "{{cClientHandle}}", Notes = "Returns the client handle representing the player's connection. May be nil (AI players)." },
GetColor = { Return = "string", Notes = "Returns the full color code to be used for this player (based on the first group). Prefix player messages with this code." },
GetCurrentXp = { Params = "", Return = "number", Notes = "Returns the current amount of XP" },
@ -1637,8 +1636,6 @@ a_Player:OpenWindow(Window);
IsInGroup = { Params = "GroupNameString", Return = "bool", Notes = "Returns true if the player is a member of the specified group." },
IsOnGround = { Params = "", Return = "bool", Notes = "Returns true if the player is on ground (not falling, not jumping, not flying)" },
IsSatiated = { Params = "", Return = "bool", Notes = "Returns true if the player is satiated (cannot eat)." },
IsSubmerged = { Params = "", Return = "bool", Notes = "Returns true if the player is submerged in water (the player's head is in a water block)" },
IsSwimming = { Params = "", Return = "bool", Notes = "Returns true if the player is swimming in water (the player's feet are in a water block)" },
IsVisible = { Params = "", Return = "bool", Notes = "Returns true if the player is visible to other players" },
LoadPermissionsFromDisk = { Params = "", Return = "", Notes = "Reloads the player's permissions from the disk. This loses any temporary changes made to the player's groups." },
MoveTo = { Params = "{{Vector3d|NewPosition}}", Return = "Tries to move the player into the specified position." },
@ -1646,7 +1643,13 @@ a_Player:OpenWindow(Window);
OpenWindow = { Params = "{{cWindow|Window}}", Return = "", Notes = "Opens the specified UI window for the player." },
RemoveFromGroup = { Params = "GroupName", Return = "", Notes = "Temporarily removes the player from the specified group. This change is lost when the player disconnects." },
Respawn = { Params = "", Return = "", Notes = "Restores the health, extinguishes fire, makes visible and sends the Respawn packet." },
SendMessage = { Params = "MessageString", Return = "", Notes = "Sends the specified message to the player." },
SendMessage = { Params = "Message", Return = "", Notes = "Sends the specified message to the player." },
SendMessageFailure = { Params = "Message", Return = "", Notes = "Prepends Rose [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For a command that failed to run because of insufficient permissions, etc." },
SendMessageFatal = { Params = "Message", Return = "", Notes = "Prepends Red [FATAL] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For something serious, such as a plugin crash, etc." },
SendMessageInfo = { Params = "Message", Return = "", Notes = "Prepends Yellow [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. Informational message, such as command usage, etc." },
SendMessagePrivateMsg = { Params = "Message, SenderName", Return = "", Notes = "Prepends Light Blue [MSG: *SenderName*] / prepends SenderName and colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For private messaging." },
SendMessageSuccess = { Params = "Message", Return = "", Notes = "Prepends Green [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. Success notification." },
SendMessageWarning = { Params = "Message, Sender", Return = "", Notes = "Prepends Rose [WARN] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. Denotes that something concerning, such as plugin reload, is about to happen." },
SetCanFly = { Params = "CanFly", Notes = "Sets if the player can fly or not." },
SetCrouch = { Params = "IsCrouched", Return = "", Notes = "Sets the crouch state, broadcasts the change to other players." },
SetCurrentExperience = { Params = "XPAmount", Return = "", Notes = "Sets the current amount of experience (and indirectly, the XP level)." },
@ -1668,9 +1671,7 @@ a_Player:OpenWindow(Window);
},
Constants =
{
DROWNING_TICKS = { Notes = "Number of ticks per heart of damage when drowning (zero AirLevel)" },
EATING_TICKS = { Notes = "Number of ticks required for consuming an item." },
MAX_AIR_LEVEL = { Notes = "The maximum air level value. AirLevel gets reset to this value when the player exits water." },
MAX_FOOD_LEVEL = { Notes = "The maximum food level value. When the food level is at this value, the player cannot eat." },
MAX_HEALTH = { Notes = "The maximum health value" },
},
@ -1826,7 +1827,12 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
Functions =
{
Get = { Params = "", Return = "Root object", Notes = "(STATIC)This function returns the cRoot object." },
BroadcastChat = { Params = "Message", Return = "", Notes = "Broadcasts a message to every player in the server." },
BroadcastChat = { Params = "Message", Return = "", Notes = "Broadcasts a message to every player in the server. No formatting is done by the server." },
BroadcastChatFailure = { Params = "Message", Return = "", Notes = "Prepends Rose [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For a command that failed to run because of insufficient permissions, etc." },
BroadcastChatFatal = { Params = "Message", Return = "", Notes = "Prepends Red [FATAL] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For a plugin that crashed, or similar." },
BroadcastChatInfo = { Params = "Message", Return = "", Notes = "Prepends Yellow [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For informational messages, such as command usage." },
BroadcastChatSuccess = { Params = "Message", Return = "", Notes = "Prepends Green [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For success messages." },
BroadcastChatWarning = { Params = "Message", Return = "", Notes = "Prepends Rose [WARN] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For concerning events, such as plugin reload etc." },
FindAndDoWithPlayer = { Params = "PlayerName, CallbackFunction", Return = "", Notes = "Calls the given callback function for the given player." },
ForEachPlayer = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each player. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|cPlayer}})</pre>" },
ForEachWorld = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each world. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cWorld|cWorld}})</pre>" },
@ -2017,8 +2023,14 @@ end
Functions =
{
AreCommandBlocksEnabled = { Params = "", Return = "bool", Notes = "Returns whether command blocks are enabled on the (entire) server" },
BroadcastBlockAction = { Params = "BlockX, BlockY, BlockZ, ActionByte1, ActionByte2, BlockType, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Broadcasts the BlockAction packet to all clients who have the appropriate chunk loaded (except ExcludeClient). The contents of the packet are specified by the parameters for the call, the blocktype needn't match the actual block that is present in the world data at the specified location." },
BroadcastChat = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Sends the Message to all players in this world, except the optional ExceptClient" },
BroadcastChat = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Sends the Message to all players in this world, except the optional ExcludeClient. No formatting is done by the server." },
BroadcastChatFailure = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Prepends Rose [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For a command that failed to run because of insufficient permissions, etc." },
BroadcastChatFatal = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Prepends Red [FATAL] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For a plugin that crashed, or similar." },
BroadcastChatInfo = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Prepends Yellow [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For informational messages, such as command usage." },
BroadcastChatSuccess = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Prepends Green [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For success messages." },
BroadcastChatWarning = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Prepends Rose [WARN] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For concerning events, such as plugin reload etc." },
BroadcastSoundEffect = { Params = "SoundName, X, Y, Z, Volume, Pitch, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Sends the specified sound effect to all players in this world, except the optional ExceptClient" },
BroadcastSoundParticleEffect = { Params = "EffectID, X, Y, Z, EffectData, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Sends the specified effect to all players in this world, except the optional ExceptClient" },
CastThunderbolt = { Params = "X, Y, Z", Return = "", Notes = "Creates a thunderbolt at the specified coords" },
@ -2114,6 +2126,10 @@ end
{ Params = "{{Vector3i|BlockCoords}}, BlockMeta", Return = "", Notes = "Sets the meta for the block at the specified coords." },
},
SetNextBlockTick = { Params = "BlockX, BlockY, BlockZ", Return = "", Notes = "Sets the blockticking to start at the specified block in the next tick." },
SetCommandBlockCommand = { Params = "BlockX, BlockY, BlockZ, Command", Return = "bool", Notes = "Sets the command to be executed in a command block at the specified coordinates. Returns if command was changed." },
SetCommandBlocksEnabled = { Params = "IsEnabled (bool)", Return = "", Notes = "Sets whether command blocks should be enabled on the (entire) server." },
SetShouldUseChatPrefixes = { Params = "", Return = "ShouldUse (bool)", Notes = "Sets whether coloured chat prefixes such as [INFO] is used with the SendMessageXXX() or BroadcastChatXXX(), or simply the entire message is coloured in the respective colour." },
ShouldUseChatPrefixes = { Params = "", Return = "bool", Notes = "Returns whether coloured chat prefixes are prepended to chat messages or the entire message is simply coloured." },
SetSignLines = { 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 UpdateSign()." },
SetTicksUntilWeatherChange = { Params = "NumTicks", Return = "", Notes = "Sets the number of ticks after which the weather will be changed." },
SetTimeOfDay = { Params = "TimeOfDayTicks", Return = "", Notes = "Sets the time of day, expressed as number of ticks past sunrise, in the range 0 .. 24000." },

View File

@ -5,13 +5,10 @@ return
CalledWhen = "A player has explicitly disconnected.",
DefaultFnName = "OnDisconnect", -- also used as pagename
Desc = [[
This hook is called when a client sends the disconnect packet and is about to be disconnected from
the server.</p>
<p>
Note that this callback is not called if the client drops the connection or is kicked by the
server.</p>
<p>
FIXME: There is no callback for "client destroying" that would be called in all circumstances.</p>
This hook is called when a client is about to be disconnected from the server, for whatever reason.
<p><b>Note that this hook will be removed after <1.7 protocol support is removed, as it was originally a hook for
the client sending the server a disconnect packet, which no longer happens.</b></p>
]],
Params =
{
@ -19,9 +16,8 @@ return
{ Name = "Reason", Type = "string", Notes = "The reason that the client has sent in the disconnect packet" },
},
Returns = [[
If the function returns false or no value, MCServer calls other plugins' callbacks for this event
and finally broadcasts a disconnect message to the player's world. If the function returns true, no
other plugins are called for this event and the disconnect message is not broadcast. In either case,
If the function returns false or no value, MCServer calls other plugins' callbacks for this event.
If the function returns true, no other plugins are called for this event. In either case,
the player is disconnected.
]],
}, -- HOOK_DISCONNECT

View File

@ -2,17 +2,21 @@ return
{
HOOK_PLAYER_DESTROYED =
{
CalledWhen = "A player is about to get destroyed.",
CalledWhen = "A player object is about to be destroyed.",
DefaultFnName = "OnPlayerDestroyed", -- also used as pagename
Desc = [[
This function is called when a {{cPlayer|player}} is about to get destroyed. But the player isn't already destroyed.
This function is called before a {{cPlayer|player}} is about to be destroyed.
The player has disconnected for whatever reason and is no longer in the server.
If a plugin returns true, a leave message is not broadcast, and vice versa.
However, whatever the return value, the player object is removed from memory.
]],
Params =
{
{ Name = "Player", Type = "{{cPlayer}}", Notes = "The destroyed player" },
},
Returns = [[
It's only for notification. Can't be returned.
If the function returns false or no value, other plugins' callbacks are called and a leave message is broadcast.
If the function returns true, no other callbacks are called for this event and no leave message appears. Either way the player is removed internally.
]],
}, -- HOOK_PLAYER_DESTROYED
}

View File

@ -9,16 +9,16 @@ return
enabled, this function is called after their name has been authenticated. It is called after
{{OnLogin|HOOK_LOGIN}} and before {{OnPlayerSpawned|HOOK_PLAYER_SPAWNED}}, right after the player's
entity is created, but not added to the world yet. The player is not yet visible to other players.
This is a notification-only event, plugins wishing to refuse player's entry should kick the player
using the {{cPlayer}}:Kick() function.
Returning true will block a join message from being broadcast, but otherwise, the player is still allowed to join.
Plugins wishing to refuse player's entry should kick the player using the {{cPlayer}}:Kick() function.
]],
Params =
{
{ Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has joined the game" },
},
Returns = [[
If the function returns false or no value, other plugins' callbacks are called. If the function
returns true, no other callbacks are called for this event. Either way the player is let in.
If the function returns false or no value, other plugins' callbacks are called and a join message is broadcast. If the function
returns true, no other callbacks are called for this event and a join message is not sent. Either way the player is let in.
]],
}, -- HOOK_PLAYER_JOINED
}

@ -1 +1 @@
Subproject commit 5fe3662a8719f79cb2ca0a16150c716a3c5eb19c
Subproject commit 7f97e93ef25616673e8342b7919d9b5914e1327e

@ -1 +1 @@
Subproject commit c78c8422c25b9dc38f09eded3200d565375522e2
Subproject commit 2cb1a0c4009ecf368ecc74eb428394e10f9e6d00

View File

@ -248,7 +248,7 @@ bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message)
{
AStringVector Split(StringSplit(a_Message, " "));
ASSERT(!Split.empty()); // This should not happen - we know there's at least one char in the message so the split needs to be at least one item long
a_Player->SendMessage(Printf("%s[INFO] %sUnknown command: \"%s\"", cChatColor::Yellow.c_str(), cChatColor::White.c_str(), Split[0].c_str()));
a_Player->SendMessageInfo(Printf("Unknown command: \"%s\"", Split[0].c_str()));
LOGINFO("Player %s issued an unknown command: \"%s\"", a_Player->GetName().c_str(), a_Message.c_str());
return true; // Cancel sending
}
@ -1392,7 +1392,7 @@ bool cPluginManager::HandleCommand(cPlayer * a_Player, const AString & a_Command
!a_Player->HasPermission(cmd->second.m_Permission)
)
{
a_Player->SendMessage(Printf("%s[INFO] %sForbidden command; insufficient privileges: \"%s\"", cChatColor::Rose.c_str(), cChatColor::White.c_str(), Split[0].c_str()));
a_Player->SendMessageFailure(Printf("Forbidden command; insufficient privileges: \"%s\"", Split[0].c_str()));
LOGINFO("Player %s tried to execute forbidden command: \"%s\"", a_Player->GetName().c_str(), Split[0].c_str());
a_WasCommandForbidden = true;
return false;

View File

@ -78,7 +78,7 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
}
}
} else {
a_Player->SendMessage("You can only sleep at night");
a_Player->SendMessageFailure("You can only sleep at night");
}
}
}

View File

@ -87,7 +87,7 @@ public:
if ((Meta < 7) && (Light > 8))
{
a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_CROPS, ++Meta);
a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, m_BlockType, ++Meta);
}
else if (Light < 9)
{

View File

@ -90,6 +90,8 @@ public:
switch (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ))
{
case E_BLOCK_CROPS:
case E_BLOCK_POTATOES:
case E_BLOCK_CARROTS:
case E_BLOCK_MELON_STEM:
case E_BLOCK_PUMPKIN_STEM:
{

View File

@ -68,7 +68,7 @@ public:
default:
{
ASSERT(!"Unhandled block face!");
return 0x0;
return 0;
}
}
}

View File

@ -1847,7 +1847,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
bbTNT.Expand(ExplosionSizeInt * 2, ExplosionSizeInt * 2, ExplosionSizeInt * 2);
cTNTDamageCallback TNTDamageCallback(bbTNT, Vector3d(a_BlockX, a_BlockY, a_BlockZ), a_ExplosionSize, ExplosionSizeSq);
cTNTDamageCallback TNTDamageCallback(bbTNT, Vector3d(a_BlockX, a_BlockY, a_BlockZ), ExplosionSizeInt, ExplosionSizeSq);
ForEachEntity(TNTDamageCallback);
// Wake up all simulators for the area, so that water and lava flows and sand falls into the blasted holes (FS #391):

View File

@ -44,16 +44,13 @@
/// If the number of queued outgoing packets reaches this, the client will be kicked
/** If the number of queued outgoing packets reaches this, the client will be kicked */
#define MAX_OUTGOING_PACKETS 2000
/// How many explosions per single game tick are allowed
static const int MAX_EXPLOSIONS_PER_TICK = 100;
/** Maximum number of explosions to send this tick, server will start dropping if exceeded */
#define MAX_EXPLOSIONS_PER_TICK 20
/// How many explosions in the recent history are allowed
static const int MAX_RUNNING_SUM_EXPLOSIONS = cClientHandle::NUM_CHECK_EXPLOSIONS_TICKS * MAX_EXPLOSIONS_PER_TICK / 8;
/// How many ticks before the socket is closed after the client is destroyed (#31)
/** How many ticks before the socket is closed after the client is destroyed (#31) */
static const int TICKS_BEFORE_CLOSE = 20;
@ -95,8 +92,7 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) :
m_TicksSinceDestruction(0),
m_State(csConnected),
m_ShouldCheckDownloaded(false),
m_CurrentExplosionTick(0),
m_RunningSumExplosions(0),
m_NumExplosionsThisTick(0),
m_UniqueID(0),
m_HasSentPlayerChunk(false)
{
@ -227,7 +223,11 @@ void cClientHandle::Authenticate(void)
m_Player->SetIP (m_IPString);
cRoot::Get()->GetPluginManager()->CallHookPlayerJoined(*m_Player);
if (!cRoot::Get()->GetPluginManager()->CallHookPlayerJoined(*m_Player))
{
cRoot::Get()->BroadcastChatJoin(Printf("%s has joined the game", GetUsername().c_str()));
LOGINFO("Player %s has joined the game.", m_Username.c_str());
}
m_ConfirmPosition = m_Player->GetPosition();
@ -566,7 +566,7 @@ void cClientHandle::HandleCommandBlockMessage(const char* a_Data, unsigned int a
{
if (a_Length < 14)
{
SendChat(Printf("%s[INFO]%s Failure setting command block command; bad request", cChatColor::Red.c_str(), cChatColor::White.c_str()));
SendChat("Failure setting command block command; bad request", mtFailure);
LOGD("Malformed MC|AdvCdm packet.");
return;
}
@ -596,7 +596,7 @@ void cClientHandle::HandleCommandBlockMessage(const char* a_Data, unsigned int a
default:
{
SendChat(Printf("%s[INFO]%s Failure setting command block command; unhandled mode", cChatColor::Red.c_str(), cChatColor::White.c_str()));
SendChat("Failure setting command block command; unhandled mode", mtFailure);
LOGD("Unhandled MC|AdvCdm packet mode.");
return;
}
@ -607,12 +607,12 @@ void cClientHandle::HandleCommandBlockMessage(const char* a_Data, unsigned int a
if (World->AreCommandBlocksEnabled())
{
World->SetCommandBlockCommand(BlockX, BlockY, BlockZ, Command);
SendChat(Printf("%s[INFO]%s Successfully set command block command", cChatColor::Green.c_str(), cChatColor::White.c_str()));
SendChat("Successfully set command block command", mtSuccess);
}
else
{
SendChat(Printf("%s[INFO]%s Command blocks are not enabled on this server", cChatColor::Yellow.c_str(), cChatColor::White.c_str()));
SendChat("Command blocks are not enabled on this server", mtFailure);
}
}
@ -910,7 +910,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(Equipped.m_ItemType);
if (ItemHandler->IsPlaceable())
if (ItemHandler->IsPlaceable() && (a_BlockFace > -1))
{
HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler);
}
@ -1330,13 +1330,9 @@ void cClientHandle::HandleRespawn(void)
void cClientHandle::HandleDisconnect(const AString & a_Reason)
{
LOGD("Received d/c packet from %s with reason \"%s\"", m_Username.c_str(), a_Reason.c_str());
if (!cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, a_Reason))
{
AString DisconnectMessage;
Printf(DisconnectMessage, "%s[LEAVE] %s%s has left the game", cChatColor::Yellow.c_str(), cChatColor::White.c_str(), m_Username.c_str());
cRoot::Get()->BroadcastChat(DisconnectMessage);
LOGINFO("Player %s has left the game.", m_Username.c_str());
}
cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, a_Reason);
m_HasSentDC = true;
Destroy();
}
@ -1635,10 +1631,8 @@ void cClientHandle::Tick(float a_Dt)
}
}
// Update the explosion statistics:
m_CurrentExplosionTick = (m_CurrentExplosionTick + 1) % ARRAYCOUNT(m_NumExplosionsPerTick);
m_RunningSumExplosions -= m_NumExplosionsPerTick[m_CurrentExplosionTick];
m_NumExplosionsPerTick[m_CurrentExplosionTick] = 0;
// Reset explosion counter:
m_NumExplosionsThisTick = 0;
}
@ -1735,9 +1729,111 @@ void cClientHandle::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlock
void cClientHandle::SendChat(const AString & a_Message)
void cClientHandle::SendChat(const AString & a_Message, ChatPrefixCodes a_ChatPrefix, const AString & a_AdditionalData)
{
m_Protocol->SendChat(a_Message);
bool ShouldAppendChatPrefixes = true;
if (GetPlayer()->GetWorld() == NULL)
{
cWorld * World = cRoot::Get()->GetWorld(GetPlayer()->GetLoadedWorldName());
if (World == NULL)
{
World = cRoot::Get()->GetDefaultWorld();
}
if (!World->ShouldUseChatPrefixes())
{
ShouldAppendChatPrefixes = false;
}
}
else if (!GetPlayer()->GetWorld()->ShouldUseChatPrefixes())
{
ShouldAppendChatPrefixes = false;
}
AString Message;
switch (a_ChatPrefix)
{
case mtCustom: break;
case mtFailure:
{
if (ShouldAppendChatPrefixes)
Message = Printf("%s[INFO] %s", cChatColor::Rose.c_str(), cChatColor::White.c_str());
else
Message = Printf("%s", cChatColor::Rose.c_str());
break;
}
case mtInformation:
{
if (ShouldAppendChatPrefixes)
Message = Printf("%s[INFO] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str());
else
Message = Printf("%s", cChatColor::Yellow.c_str());
break;
}
case mtSuccess:
{
if (ShouldAppendChatPrefixes)
Message = Printf("%s[INFO] %s", cChatColor::Green.c_str(), cChatColor::White.c_str());
else
Message = Printf("%s", cChatColor::Green.c_str());
break;
}
case mtWarning:
{
if (ShouldAppendChatPrefixes)
Message = Printf("%s[WARN] %s", cChatColor::Rose.c_str(), cChatColor::White.c_str());
else
Message = Printf("%s", cChatColor::Rose.c_str());
break;
}
case mtFatal:
{
if (ShouldAppendChatPrefixes)
Message = Printf("%s[FATAL] %s", cChatColor::Red.c_str(), cChatColor::White.c_str());
else
Message = Printf("%s", cChatColor::Red.c_str());
break;
}
case mtDeath:
{
if (ShouldAppendChatPrefixes)
Message = Printf("%s[DEATH] %s", cChatColor::Gray.c_str(), cChatColor::White.c_str());
else
Message = Printf("%s", cChatColor::Gray.c_str());
break;
}
case mtPrivateMessage:
{
if (ShouldAppendChatPrefixes)
Message = Printf("%s[MSG: %s] %s%s", cChatColor::LightBlue.c_str(), a_AdditionalData.c_str(), cChatColor::White.c_str(), cChatColor::Italic.c_str());
else
Message = Printf("%s: %s", a_AdditionalData.c_str(), cChatColor::LightBlue.c_str());
break;
}
case mtJoin:
{
if (ShouldAppendChatPrefixes)
Message = Printf("%s[JOIN] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str());
else
Message = Printf("%s", cChatColor::Yellow.c_str());
break;
}
case mtLeave:
{
if (ShouldAppendChatPrefixes)
Message = Printf("%s[LEAVE] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str());
else
Message = Printf("%s", cChatColor::Yellow.c_str());
break;
}
default: ASSERT(!"Unhandled chat prefix type!"); return;
}
Message.append(a_Message);
m_Protocol->SendChat(Message);
}
@ -1918,18 +2014,14 @@ void cClientHandle::SendEntityVelocity(const cEntity & a_Entity)
void cClientHandle::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion)
{
if (
(m_NumExplosionsPerTick[m_CurrentExplosionTick] > MAX_EXPLOSIONS_PER_TICK) || // Too many explosions in this tick
(m_RunningSumExplosions > MAX_RUNNING_SUM_EXPLOSIONS) // Too many explosions in the recent history
)
if (m_NumExplosionsThisTick > MAX_EXPLOSIONS_PER_TICK)
{
LOGD("Dropped %u explosions", a_BlocksAffected.size());
LOGD("Dropped an explosion!");
return;
}
// Update the statistics:
m_NumExplosionsPerTick[m_CurrentExplosionTick] += a_BlocksAffected.size();
m_RunningSumExplosions += a_BlocksAffected.size();
m_NumExplosionsThisTick += 1;
m_Protocol->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, a_Radius, a_BlocksAffected, a_PlayerMotion);
}
@ -2459,13 +2551,7 @@ void cClientHandle::SocketClosed(void)
if (m_Username != "") // Ignore client pings
{
if (!cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, "Player disconnected"))
{
AString DisconnectMessage;
Printf(DisconnectMessage, "%s[LEAVE] %s%s has left the game", cChatColor::Yellow.c_str(), cChatColor::White.c_str(), m_Username.c_str());
cRoot::Get()->BroadcastChat(DisconnectMessage);
LOGINFO("Player %s has left the game.", m_Username.c_str());
}
cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, "Player disconnected");
}
Destroy();

View File

@ -53,9 +53,6 @@ public:
static const int MAX_VIEW_DISTANCE = 15;
static const int MIN_VIEW_DISTANCE = 3;
/// How many ticks should be checked for a running average of explosions, for limiting purposes
static const int NUM_CHECK_EXPLOSIONS_TICKS = 20;
cClientHandle(const cSocket * a_Socket, int a_ViewDistance);
virtual ~cClientHandle();
@ -92,7 +89,7 @@ public:
void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage);
void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); // tolua_export
void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes);
void SendChat (const AString & a_Message);
void SendChat (const AString & a_Message, ChatPrefixCodes a_ChatPrefix, const AString & a_AdditionalData = "");
void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer);
void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player);
void SendDestroyEntity (const cEntity & a_Entity);
@ -301,14 +298,8 @@ private:
/// If set to true during csDownloadingWorld, the tick thread calls CheckIfWorldDownloaded()
bool m_ShouldCheckDownloaded;
/// Stores the recent history of the number of explosions per tick
int m_NumExplosionsPerTick[NUM_CHECK_EXPLOSIONS_TICKS];
/// Points to the current tick in the m_NumExplosionsPerTick[] array
int m_CurrentExplosionTick;
/// Running sum of m_NumExplosionsPerTick[]
int m_RunningSumExplosions;
/** Number of explosions sent this tick */
int m_NumExplosionsThisTick;
static int s_ClientCount;
int m_UniqueID;

View File

@ -1,6 +1,8 @@
#pragma once
#include "ChatColor.h"
@ -439,9 +441,26 @@ inline float GetSpecialSignf( float a_Val )
enum ChatPrefixCodes
{
// http://forum.mc-server.org/showthread.php?tid=1212
// MessageType...
mtCustom, // Send raw data without any processing
mtFailure, // Something could not be done (i.e. command not executed due to insufficient privilege)
mtInformation, // Informational message (i.e. command usage)
mtSuccess, // Something executed successfully
mtWarning, // Something concerning (i.e. reload) is about to happen
mtFatal, // Something catastrophic occured (i.e. plugin crash)
mtDeath, // Denotes death of player
mtPrivateMessage, // Player to player messaging identifier
mtJoin, // A player has joined the server
mtLeave, // A player has left the server
};
// tolua_begin
/// Normalizes an angle in degrees to the [-180, +180) range:
/** Normalizes an angle in degrees to the [-180, +180) range: */
inline double NormalizeAngleDegrees(const double a_Degrees)
{
double Norm = fmod(a_Degrees + 180, 360);

View File

@ -89,8 +89,14 @@ void cBoat::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
BroadcastMovementUpdate();
SetSpeed(GetSpeed() * 0.97); // Slowly decrease the speed.
if (IsBlockWater(m_World->GetBlock((int) GetPosX(), (int) GetPosY(), (int) GetPosZ())))
SetSpeed(GetSpeed() * 0.97); // Slowly decrease the speed
if ((POSY_TOINT < 0) || (POSY_TOINT > cChunkDef::Height))
{
return;
}
if (IsBlockWater(m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT)))
{
SetSpeedY(1);
}

View File

@ -13,6 +13,7 @@ class cExpOrb :
typedef cExpOrb super;
public:
CLASS_PROTODEF(cExpOrb);
cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward);
cExpOrb(const Vector3d & a_Pos, int a_Reward);

View File

@ -14,8 +14,10 @@ class cFloater :
typedef cFloater super;
public:
//tolua_end
CLASS_PROTODEF(cFloater);
cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID, int a_CountDownTime);
virtual void SpawnOn(cClientHandle & a_Client) override;

View File

@ -18,15 +18,16 @@ class cPlayer;
class cPickup :
public cEntity
{
// tolua_end
typedef cEntity super;
public:
// tolua_end
CLASS_PROTODEF(cPickup);
cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, bool IsPlayerCreated, float a_SpeedX = 0.f, float a_SpeedY = 0.f, float a_SpeedZ = 0.f); // tolua_export
cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, bool IsPlayerCreated, float a_SpeedX = 0.f, float a_SpeedY = 0.f, float a_SpeedZ = 0.f);
cItem & GetItem(void) {return m_Item; } // tolua_export
cItem & GetItem(void) {return m_Item; } // tolua_export
const cItem & GetItem(void) const {return m_Item; }
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;

View File

@ -3,7 +3,6 @@
#include "Player.h"
#include "../Server.h"
#include "../ClientHandle.h"
#include "../UI/Window.h"
#include "../UI/WindowOwner.h"
#include "../World.h"
@ -130,9 +129,13 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
cPlayer::~cPlayer(void)
{
cRoot::Get()->GetPluginManager()->CallHookPlayerDestroyed(*this);
if (!cRoot::Get()->GetPluginManager()->CallHookPlayerDestroyed(*this))
{
cRoot::Get()->BroadcastChatLeave(Printf("%s has left the game", GetName().c_str()));
LOGINFO("Player %s has left the game.", GetName().c_str());
}
LOGD("Deleting cPlayer \"%s\" at %p, ID %d", m_PlayerName.c_str(), this, GetUniqueID());
LOGD("Deleting cPlayer \"%s\" at %p, ID %d", GetName().c_str(), this, GetUniqueID());
// Notify the server that the player is being destroyed
cRoot::Get()->GetServer()->PlayerDestroying(this);
@ -841,18 +844,18 @@ void cPlayer::KilledBy(cEntity * a_Killer)
if (a_Killer == NULL)
{
GetWorld()->BroadcastChat(Printf("%s[DEATH] %s%s was killed by environmental damage", cChatColor::Red.c_str(), cChatColor::White.c_str(), GetName().c_str()));
GetWorld()->BroadcastChatDeath(Printf("%s was killed by environmental damage", GetName().c_str()));
}
else if (a_Killer->IsPlayer())
{
GetWorld()->BroadcastChat(Printf("%s[DEATH] %s%s was killed by %s", cChatColor::Red.c_str(), cChatColor::White.c_str(), GetName().c_str(), ((cPlayer *)a_Killer)->GetName().c_str()));
GetWorld()->BroadcastChatDeath(Printf("%s was killed by %s", GetName().c_str(), ((cPlayer *)a_Killer)->GetName().c_str()));
}
else
{
AString KillerClass = a_Killer->GetClass();
KillerClass.erase(KillerClass.begin()); // Erase the 'c' of the class (e.g. "cWitch" -> "Witch")
GetWorld()->BroadcastChat(Printf("%s[DEATH] %s%s was killed by a %s", cChatColor::Red.c_str(), cChatColor::White.c_str(), GetName().c_str(), KillerClass.c_str()));
GetWorld()->BroadcastChatDeath(Printf("%s was killed by a %s", GetName().c_str(), KillerClass.c_str()));
}
class cIncrementCounterCB
@ -1117,15 +1120,6 @@ void cPlayer::SetIP(const AString & a_IP)
void cPlayer::SendMessage(const AString & a_Message)
{
m_ClientHandle->SendChat(a_Message);
}
void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
{
SetPosition( a_PosX, a_PosY, a_PosZ );
@ -1741,6 +1735,23 @@ void cPlayer::UseEquippedItem(void)
void cPlayer::TickBurning(cChunk & a_Chunk)
{
// Don't burn in creative and stop burning in creative if necessary
if (!IsGameModeCreative())
{
super::TickBurning(a_Chunk);
}
else if (IsOnFire())
{
m_TicksLeftBurning = 0;
OnFinishedBurning();
}
}
void cPlayer::HandleFood(void)
{

View File

@ -5,6 +5,7 @@
#include "../Inventory.h"
#include "../Defines.h"
#include "../World.h"
#include "../ClientHandle.h"
@ -195,7 +196,13 @@ public:
cClientHandle * GetClientHandle(void) const { return m_ClientHandle; }
void SendMessage(const AString & a_Message);
void SendMessage (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtCustom); }
void SendMessageInfo (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtInformation); }
void SendMessageFailure (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtFailure); }
void SendMessageSuccess (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtSuccess); }
void SendMessageWarning (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtWarning); }
void SendMessageFatal (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtFailure); }
void SendMessagePrivateMsg(const AString & a_Message, const AString & a_Sender) { m_ClientHandle->SendChat(a_Message, mtPrivateMessage, a_Sender); }
const AString & GetName(void) const { return m_PlayerName; }
void SetName(const AString & a_Name) { m_PlayerName = a_Name; }
@ -467,6 +474,9 @@ protected:
/// Filters out damage for creative mode/friendly fire
virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
/** Stops players from burning in creative mode */
virtual void TickBurning(cChunk & a_Chunk) override;
/// Called in each tick to handle food-related processing
void HandleFood(void);

View File

@ -60,15 +60,6 @@ template <typename T> T Clamp(T a_Value, T a_Min, T a_Max)
static bool SortTreeBlocks(const sSetBlock & a_First, const sSetBlock & a_Second)
{
return (a_First.BlockType == E_BLOCK_LOG) && (a_Second.BlockType != E_BLOCK_LOG);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenTrees:

View File

@ -31,7 +31,7 @@ public:
// Please keep alpha-sorted.
case E_ITEM_BAKED_POTATO: return FoodInfo(6, 7.2);
case E_ITEM_BREAD: return FoodInfo(5, 6);
case E_ITEM_CARROT: return FoodInfo(4, 4.8);
// Carrots handled in ItemSeeds
case E_ITEM_COOKED_CHICKEN: return FoodInfo(6, 7.2);
case E_ITEM_COOKED_FISH: return FoodInfo(5, 6);
case E_ITEM_COOKED_PORKCHOP: return FoodInfo(8, 12.8);
@ -39,8 +39,9 @@ public:
case E_ITEM_GOLDEN_APPLE: return FoodInfo(4, 9.6);
case E_ITEM_GOLDEN_CARROT: return FoodInfo(6, 14.4);
case E_ITEM_MELON_SLICE: return FoodInfo(2, 1.2);
case E_ITEM_MUSHROOM_SOUP: return FoodInfo(6, 7.2);
case E_ITEM_POISONOUS_POTATO: return FoodInfo(2, 1.2, 60);
case E_ITEM_POTATO: return FoodInfo(1, 0.6);
// Potatoes handled in ItemSeeds
case E_ITEM_PUMPKIN_PIE: return FoodInfo(8, 4.8);
case E_ITEM_RAW_BEEF: return FoodInfo(3, 1.8);
case E_ITEM_RAW_CHICKEN: return FoodInfo(2, 1.2, 30);
@ -50,7 +51,6 @@ public:
case E_ITEM_ROTTEN_FLESH: return FoodInfo(4, 0.8, 80);
case E_ITEM_SPIDER_EYE: return FoodInfo(2, 3.2, 100);
case E_ITEM_STEAK: return FoodInfo(8, 12.8);
case E_ITEM_MUSHROOM_SOUP: return FoodInfo(6, 7.2);
}
LOGWARNING("%s: Unknown food item (%d), returning zero nutrition", __FUNCTION__, m_ItemType);
return FoodInfo(0, 0.f);

View File

@ -181,23 +181,28 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
return new cItemMinecartHandler(a_ItemType);
}
// Food:
// Food (please keep alpha-sorted):
// (carrots and potatoes handled in SeedHandler as both seed and food
case E_ITEM_BAKED_POTATO:
case E_ITEM_BREAD:
case E_ITEM_COOKIE:
case E_ITEM_MELON_SLICE:
case E_ITEM_RAW_CHICKEN:
case E_ITEM_COOKED_CHICKEN:
case E_ITEM_RAW_BEEF:
case E_ITEM_RAW_PORKCHOP:
case E_ITEM_STEAK:
case E_ITEM_COOKED_PORKCHOP:
case E_ITEM_RAW_FISH:
case E_ITEM_COOKED_FISH:
case E_ITEM_RED_APPLE:
case E_ITEM_COOKED_PORKCHOP:
case E_ITEM_COOKIE:
case E_ITEM_GOLDEN_APPLE:
case E_ITEM_ROTTEN_FLESH:
case E_ITEM_GOLDEN_CARROT:
case E_ITEM_MELON_SLICE:
case E_ITEM_MUSHROOM_SOUP:
case E_ITEM_POISONOUS_POTATO:
case E_ITEM_PUMPKIN_PIE:
case E_ITEM_RAW_BEEF:
case E_ITEM_RAW_CHICKEN:
case E_ITEM_RAW_FISH:
case E_ITEM_RAW_PORKCHOP:
case E_ITEM_RED_APPLE:
case E_ITEM_ROTTEN_FLESH:
case E_ITEM_SPIDER_EYE:
case E_ITEM_STEAK:
{
return new cItemFoodHandler(a_ItemType);
}
@ -511,7 +516,7 @@ bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item)
cItemHandler::FoodInfo cItemHandler::GetFoodInfo()
{
return FoodInfo(0, 0.f);
return FoodInfo(0, 0);
}

View File

@ -22,6 +22,26 @@ public:
{
return true;
}
virtual bool IsFood(void) override
{
switch (m_ItemType) // Special cases, both a seed and food
{
case E_ITEM_CARROT:
case E_ITEM_POTATO: return true;
default: return false;
}
}
virtual FoodInfo GetFoodInfo(void) override
{
switch (m_ItemType)
{
case E_ITEM_CARROT: return FoodInfo(4, 4.8);
case E_ITEM_POTATO: return FoodInfo(1, 0.6);
default: return FoodInfo(0, 0);
}
}
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,

View File

@ -126,7 +126,7 @@ cMonster::eType cMobSpawner::ChooseMobType(EMCSBiome a_Biome)
bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, cMonster::eType a_MobType, EMCSBiome a_Biome)
{
BLOCKTYPE TargetBlock;
BLOCKTYPE TargetBlock = E_BLOCK_AIR;
if (m_AllowedTypes.find(a_MobType) != m_AllowedTypes.end() && a_Chunk->UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, TargetBlock))
{
NIBBLETYPE BlockLight = a_Chunk->GetBlockLight(a_RelX, a_RelY, a_RelZ);

View File

@ -276,7 +276,7 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
{
m_Destination.y = FindFirstNonAirBlockPosition(m_Destination.x, m_Destination.z);
if (DoesPosYRequireJump(m_Destination.y))
if (DoesPosYRequireJump((int)floor(m_Destination.y)))
{
m_bOnGround = false;
AddPosY(1.5); // Jump!!

View File

@ -73,14 +73,26 @@ bool cFile::Open(const AString & iFileName, eMode iMode)
return false;
}
}
m_File = fopen( (FILE_IO_PREFIX + iFileName).c_str(), Mode);
#ifdef _WIN32
fopen_s(&m_File, (FILE_IO_PREFIX + iFileName).c_str(), Mode);
#else
m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), Mode);
#endif // _WIN32
if ((m_File == NULL) && (iMode == fmReadWrite))
{
// Fix for MS not following C spec, opening "a" mode files for writing at the end only
// The file open operation has been tried with "read update", fails if file not found
// So now we know either the file doesn't exist or we don't have rights, no need to worry about file contents.
// Simply re-open for read-writing, erasing existing contents:
m_File = fopen( (FILE_IO_PREFIX + iFileName).c_str(), "wb+");
#ifdef _WIN32
fopen_s(&m_File, (FILE_IO_PREFIX + iFileName).c_str(), "wb+");
#else
m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), "wb+");
#endif // _WIN32
}
return (m_File != NULL);
}

View File

@ -2435,7 +2435,8 @@ void cProtocol172::cPacketizer::WriteEntityProperties(const cEntity & a_Entity)
WriteInt(0);
return;
}
const cMonster & Mob = (const cMonster &)a_Entity;
//const cMonster & Mob = (const cMonster &)a_Entity;
// TODO: Send properties and modifiers based on the mob type

View File

@ -543,11 +543,11 @@ void cRoot::ReloadGroups(void)
void cRoot::BroadcastChat(const AString & a_Message)
void cRoot::LoopWorldsAndBroadcastChat(const AString & a_Message, ChatPrefixCodes a_ChatPrefix)
{
for (WorldMap::iterator itr = m_WorldsByName.begin(), end = m_WorldsByName.end(); itr != end; ++itr)
{
itr->second->BroadcastChat(a_Message);
itr->second->LoopPlayersAndBroadcastChat(a_Message, a_ChatPrefix);
} // for itr - m_WorldsByName[]
}

View File

@ -3,6 +3,7 @@
#include "Authenticator.h"
#include "HTTPServer/HTTPServer.h"
#include "Defines.h"
@ -100,18 +101,28 @@ public:
/// Reloads all the groups
void ReloadGroups(void); // tolua_export
/// Sends a chat message to all connected clients (in all worlds)
void BroadcastChat(const AString & a_Message); // tolua_export
/// Calls the callback for each player in all worlds
bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
/// Finds a player from a partial or complete player name and calls the callback - case-insensitive
bool FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
void LoopWorldsAndBroadcastChat(const AString & a_Message, ChatPrefixCodes a_ChatPrefix);
void BroadcastChatJoin (const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtJoin); }
void BroadcastChatLeave (const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtLeave); }
void BroadcastChatDeath (const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtDeath); }
// tolua_begin
/// Sends a chat message to all connected clients (in all worlds)
void BroadcastChat (const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtCustom); }
void BroadcastChatInfo (const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtInformation); }
void BroadcastChatFailure(const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtFailure); }
void BroadcastChatSuccess(const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtSuccess); }
void BroadcastChatWarning(const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtWarning); }
void BroadcastChatFatal (const AString & a_Message) { LoopWorldsAndBroadcastChat(a_Message, mtFailure); }
/// Returns the textual description of the protocol version: 49 -> "1.4.4". Provided specifically for Lua API
static AString GetProtocolVersionTextFromInt(int a_ProtocolVersionNum);

View File

@ -459,6 +459,17 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac
if (split[0] == "reload")
{
cPluginManager::Get()->ReloadPlugins();
cRoot::Get()->ReloadGroups();
return;
}
if (split[0] == "reloadplugins")
{
cPluginManager::Get()->ReloadPlugins();
return;
}
if (split[0] == "reloadgroups")
{
cRoot::Get()->ReloadGroups();
return;
}

View File

@ -250,7 +250,9 @@ cWorld::cWorld(const AString & a_WorldName) :
m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :)
m_Scoreboard(this),
m_GeneratorCallbacks(*this),
m_TickThread(*this)
m_TickThread(*this),
m_bCommandBlocksEnabled(false),
m_bUseChatPrefixes(true)
{
LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str());
@ -543,13 +545,14 @@ void cWorld::Start(void)
m_IsPumpkinBonemealable = IniFile.GetValueSetB("Plants", "IsPumpkinBonemealable", false);
m_IsSaplingBonemealable = IniFile.GetValueSetB("Plants", "IsSaplingBonemealable", true);
m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false);
m_bEnabledPVP = IniFile.GetValueSetB("PVP", "Enabled", true);
m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", false);
m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true);
m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true);
m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false);
m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true);
m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true);
m_VillagersShouldHarvestCrops = IniFile.GetValueSetB("Monsters", "VillagersShouldHarvestCrops", true);
m_GameMode = (eGameMode)IniFile.GetValueSetI("GameMode", "GameMode", m_GameMode);
m_GameMode = (eGameMode)IniFile.GetValueSetI("General", "Gamemode", m_GameMode);
// Load allowed mobs:
const char * DefaultMonsters = "";
@ -1744,7 +1747,7 @@ void cWorld::BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cons
void cWorld::BroadcastChat(const AString & a_Message, const cClientHandle * a_Exclude)
void cWorld::LoopPlayersAndBroadcastChat(const AString & a_Message, ChatPrefixCodes a_ChatPrefix, const cClientHandle * a_Exclude)
{
cCSLock Lock(m_CSPlayers);
for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
@ -1754,7 +1757,7 @@ void cWorld::BroadcastChat(const AString & a_Message, const cClientHandle * a_Ex
{
continue;
}
ch->SendChat(a_Message);
ch->SendChat(a_Message, a_ChatPrefix);
}
}

View File

@ -157,7 +157,19 @@ public:
void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL); // tolua_export
void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = NULL);
void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); ///< If there is a block entity at the specified coods, sends it to all clients except a_Exclude
void BroadcastChat (const AString & a_Message, const cClientHandle * a_Exclude = NULL); // tolua_export
void LoopPlayersAndBroadcastChat(const AString & a_Message, ChatPrefixCodes a_ChatPrefix, const cClientHandle * a_Exclude = NULL);
void BroadcastChatDeath (const AString & a_Message, const cClientHandle * a_Exclude = NULL) { LoopPlayersAndBroadcastChat(a_Message, mtDeath, a_Exclude); }
// tolua_begin
void BroadcastChat (const AString & a_Message, const cClientHandle * a_Exclude = NULL) { LoopPlayersAndBroadcastChat(a_Message, mtCustom, a_Exclude); }
void BroadcastChatInfo (const AString & a_Message, const cClientHandle * a_Exclude = NULL) { LoopPlayersAndBroadcastChat(a_Message, mtInformation, a_Exclude); }
void BroadcastChatFailure(const AString & a_Message, const cClientHandle * a_Exclude = NULL) { LoopPlayersAndBroadcastChat(a_Message, mtFailure, a_Exclude); }
void BroadcastChatSuccess(const AString & a_Message, const cClientHandle * a_Exclude = NULL) { LoopPlayersAndBroadcastChat(a_Message, mtSuccess, a_Exclude); }
void BroadcastChatWarning(const AString & a_Message, const cClientHandle * a_Exclude = NULL) { LoopPlayersAndBroadcastChat(a_Message, mtWarning, a_Exclude); }
void BroadcastChatFatal (const AString & a_Message, const cClientHandle * a_Exclude = NULL) { LoopPlayersAndBroadcastChat(a_Message, mtFailure, a_Exclude); }
// tolua_end
void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL);
void BroadcastCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL);
void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
@ -531,12 +543,14 @@ public:
/** Returns the name of the world.ini file used by this world */
const AString & GetIniFileName(void) const {return m_IniFileName; }
/// Returns the associated scoreboard instance
/** Returns the associated scoreboard instance */
cScoreboard & GetScoreBoard(void) { return m_Scoreboard; }
bool AreCommandBlocksEnabled(void) const { return m_bCommandBlocksEnabled; }
void SetCommandBlocksEnabled(bool a_Flag) { m_bCommandBlocksEnabled = a_Flag; }
bool ShouldUseChatPrefixes(void) const { return m_bUseChatPrefixes; }
void SetShouldUseChatPrefixes(bool a_Flag) { m_bUseChatPrefixes = a_Flag; }
// tolua_end
@ -787,7 +801,10 @@ private:
bool m_IsSaplingBonemealable;
bool m_IsSugarcaneBonemealable;
/** Whether command blocks are enabled or not */
bool m_bCommandBlocksEnabled;
/** Whether prefixes such as [INFO] are prepended to SendMessageXXX() / BroadcastChatXXX() functions */
bool m_bUseChatPrefixes;
cChunkGenerator m_Generator;

View File

@ -625,6 +625,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::etExpOrb: /* TODO */ break;
case cEntity::etPlayer: return; // Players aren't saved into the world
default:

View File

@ -242,7 +242,7 @@ bool cScoreboardSerializer::LoadScoreboardFromNBT(const cParsedNBT & a_NBT)
{
AString Name, ObjectiveName;
cObjective::Score Score;
cObjective::Score Score = 0;
int CurrLine = a_NBT.FindChildByName(Child, "Score");
if (CurrLine >= 0)
@ -280,7 +280,7 @@ bool cScoreboardSerializer::LoadScoreboardFromNBT(const cParsedNBT & a_NBT)
{
AString Name, DisplayName, Prefix, Suffix;
bool AllowsFriendlyFire, CanSeeFriendlyInvisible;
bool AllowsFriendlyFire = false, CanSeeFriendlyInvisible = false;
int CurrLine = a_NBT.FindChildByName(Child, "Name");
if (CurrLine >= 0)