1
0

Merge branch 'master' into MetaRotate

This commit is contained in:
Tycho 2014-03-01 09:48:44 -08:00
commit 0d26e81ab5
32 changed files with 604 additions and 181 deletions

View File

@ -665,9 +665,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories # directories like "/usr/src/myproject". Separate the files or directories
# with spaces. # with spaces.
INPUT = source \ INPUT = src
iniFile \
WebServer
# This tag can be used to specify the character encoding of the source files # This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is

View File

@ -0,0 +1,29 @@
-- @EnableMobDebug.lua
-- Enables the MobDebug debugger, used by ZeroBrane Studio, for a plugin
-- Needs to be named with a @ at the start so that it's loaded as the first file of the plugin
--[[
Usage:
Copy this file to your plugin's folder when you want to debug that plugin
You should neither check this file into the plugin's version control system,
nor distribute it in the final release.
--]]
-- Try to load the debugger, be silent about failures:
local IsSuccess, MobDebug = pcall(require, "mobdebug")
if (IsSuccess) then
MobDebug.start()
-- The debugger will automatically put a breakpoint on this line, use this opportunity to set more breakpoints in your code
LOG(cPluginManager:GetCurrentPlugin():GetName() .. ": MobDebug enabled")
end

View File

@ -1115,6 +1115,42 @@ local Item5 = cItem(E_ITEM_DIAMOND_CHESTPLATE, 1, 0, "thorns=1;unbreaking=3");
}, },
}, -- cItem }, -- cItem
cObjective =
{
Desc = [[
This class represents a single scoreboard objective.
]],
Functions =
{
AddScore = { Params = "string, number", Return = "Score", Notes = "Adds a value to the score of the specified player and returns the new value." },
GetDisplayName = { Params = "", Return = "string", Notes = "Returns the display name of the objective. This name will be shown to the connected players." },
GetName = { Params = "", Return = "string", Notes = "Returns the internal name of the objective." },
GetScore = { Params = "string", Return = "Score", Notes = "Returns the score of the specified player." },
GetType = { Params = "", Return = "eType", Notes = "Returns the type of the objective. (i.e what is being tracked)" },
Reset = { Params = "", Return = "", Notes = "Resets the scores of the tracked players." },
ResetScore = { Params = "string", Return = "", Notes = "Reset the score of the specified player." },
SetDisplayName = { Params = "string", Return = "", Notes = "Sets the display name of the objective." },
SetScore = { Params = "string, Score", Return = "", Notes = "Sets the score of the specified player." },
SubScore = { Params = "string, number", Return = "Score", Notes = "Subtracts a value from the score of the specified player and returns the new value." },
},
Constants =
{
otAchievement = { Notes = "" },
otDeathCount = { Notes = "" },
otDummy = { Notes = "" },
otHealth = { Notes = "" },
otPlayerKillCount = { Notes = "" },
otStat = { Notes = "" },
otStatBlockMine = { Notes = "" },
otStatEntityKill = { Notes = "" },
otStatEntityKilledBy = { Notes = "" },
otStatItemBreak = { Notes = "" },
otStatItemCraft = { Notes = "" },
otStatItemUse = { Notes = "" },
otTotalKillCount = { Notes = "" },
},
}, -- cObjective
cPainting = cPainting =
{ {
Desc = "This class represents a painting in the world. These paintings are special and different from Vanilla in that they can be critical-hit.", Desc = "This class represents a painting in the world. These paintings are special and different from Vanilla in that they can be critical-hit.",
@ -1773,6 +1809,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
BroadcastChatInfo = { Params = "Message", Return = "", Notes = "Prepends Yellow [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For informational messages, such as command usage." }, 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." }, 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." }, 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." },
CreateAndInitializeWorld = { Params = "WorldName", Return = "{{cWorld|cWorld}}", Notes = "Creates a new world and initializes it. If there is a world whith the same name it returns nil." },
FindAndDoWithPlayer = { Params = "PlayerName, CallbackFunction", Return = "", Notes = "Calls the given callback function for the given player." }, 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>" }, 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>" }, 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>" },
@ -1821,6 +1858,36 @@ end
}, },
}, -- cRoot }, -- cRoot
cScoreboard =
{
Desc = [[
This class manages the objectives and teams of a single world.
]],
Functions =
{
AddPlayerScore = { Params = "Name, Type, Value", Return = "", Notes = "Adds a value to all player scores of the specified objective type." },
ForEachObjective = { Params = "CallBackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each objective in the scoreboard. Returns true if all objectives have been processed (including when there are zero objectives), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cObjective|Objective}}, [CallbackData])</pre> The callback should return false or no value to continue with the next objective, or true to abort the enumeration." },
ForEachTeam = { Params = "CallBackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each team in the scoreboard. Returns true if all teams have been processed (including when there are zero teams), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cObjective|Objective}}, [CallbackData])</pre> The callback should return false or no value to continue with the next team, or true to abort the enumeration." },
GetNumObjectives = { Params = "", Return = "number", Notes = "Returns the nuber of registered objectives." },
GetNumTeams = { Params = "", Return = "number", Notes = "Returns the number of registered teams." },
GetObjective = { Params = "string", Return = "{{cObjective}}", Notes = "Returns the objective with the specified name." },
GetObjectiveIn = { Params = "DisplaySlot", Return = "{{cObjective}}", Notes = "Returns the objective in the specified display slot. Can be nil." },
GetTeam = { Params = "string", Return = "{{cTeam}}", Notes = "Returns the team with the specified name." },
RegisterObjective = { Params = "Name, DisplayName, Type", Return = "{{cObjective}}", Notes = "Registers a new scoreboard objective. Returns the {{cObjective}} instance, nil on error." },
RegisterTeam = { Params = "Name, DisplayName, Prefix, Suffix", Return = "{{cTeam}}", Notes = "Registers a new team. Returns the {{cTeam}} instance, nil on error." },
RemoveObjective = { Params = "string", Return = "bool", Notes = "Removes the objective with the specified name. Returns true if operation was successful." },
RemoveTeam = { Params = "string", Return = "bool", Notes = "Removes the team with the specified name. Returns true if operation was successful." },
SetDisplay = { Params = "Name, DisplaySlot", Return = "", Notes = "Updates the currently displayed objective." },
},
Constants =
{
dsCount = { Notes = "" },
dsList = { Notes = "" },
dsName = { Notes = "" },
dsSidebar = { Notes = "" },
},
}, -- cScoreboard
cServer = cServer =
{ {
Desc = [[ Desc = [[
@ -1841,6 +1908,32 @@ end
}, },
}, -- cServer }, -- cServer
cTeam =
{
Desc = [[
This class manages a single player team.
]],
Functions =
{
AddPlayer = { Params = "string", Returns = "bool", Notes = "Adds a player to this team. Returns true if the operation was successful." },
AllowsFriendlyFire = { Params = "", Return = "bool", Notes = "Returns whether team friendly fire is allowed." },
CanSeeFriendlyInvisible = { Params = "", Return = "bool", Notes = "Returns whether players can see invisible teammates." },
HasPlayer = { Params = "string", Returns = "bool", Notes = "Returns whether the specified player is a member of this team." },
GetDisplayName = { Params = "", Return = "string", Notes = "Returns the display name of the team." },
GetName = { Params = "", Return = "string", Notes = "Returns the internal name of the team." },
GetNumPlayers = { Params = "", Return = "number", Notes = "Returns the number of registered players." },
GetPrefix = { Params = "", Return = "string", Notes = "Returns the prefix prepended to the names of the members of this team." },
RemovePlayer = { Params = "string", Returns = "bool", Notes = "Removes the player with the specified name from this team. Returns true if the operation was successful." },
Reset = { Params = "", Returns = "", Notes = "Removes all players from this team." },
GetSuffix = { Params = "", Return = "string", Notes = "Returns the suffix appended to the names of the members of this team." },
SetCanSeeFriendlyInvisible = { Params = "bool", Return = "", Notes = "Set whether players can see invisible teammates." },
SetDisplayName = { Params = "string", Return = "", Notes = "Sets the display name of this team. (i.e. what will be shown to the players)" },
SetFriendlyFire = { Params = "bool", Return = "", Notes = "Sets whether team friendly fire is allowed." },
SetPrefix = { Params = "string", Return = "", Notes = "Sets the prefix prepended to the names of the members of this team." },
SetSuffix = { Params = "string", Return = "", Notes = "Sets the suffix appended to the names of the members of this team." },
},
}, -- cTeam
cTNTEntity = cTNTEntity =
{ {
Desc = "This class manages a TNT entity.", Desc = "This class manages a TNT entity.",

View File

@ -196,9 +196,11 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
Inherits = "cBlockEntity", Inherits = "cBlockEntity",
Functions = Functions =
{ {
EjectRecord = { Params = "", Return = "", Notes = "Ejects the current record as a {{cPickup|pickup}}. No action if there's no current record. To remove record without generating the pickup, use SetRecord(0)" }, EjectRecord = { Params = "", Return = "bool", Notes = "Ejects the current record as a {{cPickup|pickup}}. No action if there's no current record. To remove record without generating the pickup, use SetRecord(0). Returns true if pickup ejected." },
GetRecord = { Params = "", Return = "number", Notes = "Returns the record currently present. Zero for no record, E_ITEM_*_DISC for records." }, GetRecord = { Params = "", Return = "number", Notes = "Returns the record currently present. Zero for no record, E_ITEM_*_DISC for records." },
PlayRecord = { Params = "", Return = "", Notes = "Plays the currently present record. No action if there's no current record." }, IsPlayingRecord = { Params = "", Return = "bool", Notes = "Returns true if the jukebox is playing a record." },
IsRecordItem = { Params = "ItemType", Return = "bool", Notes = "Returns true if the specified item is a record that can be played." },
PlayRecord = { Params = "RecordItemType", Return = "bool", Notes = "Plays the specified Record. Return false if the parameter isn't a playable Record (E_ITEM_XXX_DISC). If there is a record already playing, ejects it first." },
SetRecord = { Params = "number", Return = "", Notes = "Sets the currently present record. Use zero for no record, or E_ITEM_*_DISC for records." }, SetRecord = { Params = "number", Return = "", Notes = "Sets the currently present record. Use zero for no record, or E_ITEM_*_DISC for records." },
}, },
}, -- cJukeboxEntity }, -- cJukeboxEntity

View File

@ -578,7 +578,10 @@ local function DumpPluginInfoForum(a_PluginFolder, a_PluginInfo)
DumpAdditionalInfoForum(a_PluginInfo, f); DumpAdditionalInfoForum(a_PluginInfo, f);
DumpCommandsForum(a_PluginInfo, f); DumpCommandsForum(a_PluginInfo, f);
DumpPermissionsForum(a_PluginInfo, f); DumpPermissionsForum(a_PluginInfo, f);
if (a_PluginInfo.SourceLocation ~= nil) then
f:write("[b][color=blue]Source:[/color] [url=", a_PluginInfo.SourceLocation, "]Link[/url][/b]");
end
f:close(); f:close();
end end

BIN
MCServer/lua5.1.dll Normal file

Binary file not shown.

View File

@ -47,8 +47,12 @@ if (WIN32)
) )
endif() endif()
set_target_properties(lua PROPERTIES OUTPUT_NAME "lua51")
# NOTE: The DLL for each configuration is stored at the same place, thus overwriting each other. # NOTE: The DLL for each configuration is stored at the same place, thus overwriting each other.
# This is known, however such behavior is needed for LuaRocks - they always load "lua.dll" # This is known, however such behavior is needed for LuaRocks - they always load "lua5.1.dll" or "lua51.dll"
# We make it work by compiling to "lua51.dll" and providing a proxy-DLL "lua5.1.dll"
# See http://lua-users.org/wiki/LuaProxyDllFour for details
else() else()
add_library(lua ${SOURCE}) add_library(lua ${SOURCE})
endif() endif()

View File

@ -75,6 +75,7 @@ $cfile "../Mobs/Monster.h"
$cfile "../CompositeChat.h" $cfile "../CompositeChat.h"
$cfile "../Map.h" $cfile "../Map.h"
$cfile "../MapManager.h" $cfile "../MapManager.h"
$cfile "../Scoreboard.h"

View File

@ -2583,6 +2583,11 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_beginmodule(tolua_S, "cMapManager"); tolua_beginmodule(tolua_S, "cMapManager");
tolua_function(tolua_S, "DoWithMap", tolua_DoWithID<cMapManager, cMap, &cMapManager::DoWithMap>); tolua_function(tolua_S, "DoWithMap", tolua_DoWithID<cMapManager, cMap, &cMapManager::DoWithMap>);
tolua_endmodule(tolua_S); tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cScoreboard");
tolua_function(tolua_S, "ForEachObjective", tolua_ForEach<cScoreboard, cObjective, &cScoreboard::ForEachObjective>);
tolua_function(tolua_S, "ForEachTeam", tolua_ForEach<cScoreboard, cTeam, &cScoreboard::ForEachTeam>);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cPlugin"); tolua_beginmodule(tolua_S, "cPlugin");
tolua_function(tolua_S, "Call", tolua_cPlugin_Call); tolua_function(tolua_S, "Call", tolua_cPlugin_Call);

View File

@ -30,48 +30,70 @@ cJukeboxEntity::~cJukeboxEntity()
void cJukeboxEntity::UsedBy(cPlayer * a_Player) void cJukeboxEntity::UsedBy(cPlayer * a_Player)
{ {
if (m_Record == 0) if (IsPlayingRecord())
{
const cItem & HeldItem = a_Player->GetEquippedItem();
if (HeldItem.m_ItemType >= 2256 && HeldItem.m_ItemType <= 2267)
{
m_Record = HeldItem.m_ItemType;
a_Player->GetInventory().RemoveOneEquippedItem();
PlayRecord();
}
}
else
{ {
EjectRecord(); EjectRecord();
} }
else
{
const cItem & HeldItem = a_Player->GetEquippedItem();
if (PlayRecord(HeldItem.m_ItemType))
{
a_Player->GetInventory().RemoveOneEquippedItem();
}
}
} }
void cJukeboxEntity::PlayRecord(void) bool cJukeboxEntity::PlayRecord(int a_Record)
{ {
if (!IsRecordItem(a_Record))
{
// This isn't a Record Item
return false;
}
if (IsPlayingRecord())
{
// A Record is already in the Jukebox.
EjectRecord();
}
m_Record = a_Record;
m_World->BroadcastSoundParticleEffect(1005, m_PosX, m_PosY, m_PosZ, m_Record); m_World->BroadcastSoundParticleEffect(1005, m_PosX, m_PosY, m_PosZ, m_Record);
m_World->SetBlockMeta(m_PosX, m_PosY, m_PosZ, E_META_JUKEBOX_ON);
return true;
} }
void cJukeboxEntity::EjectRecord(void) bool cJukeboxEntity::EjectRecord(void)
{ {
if ((m_Record < E_ITEM_FIRST_DISC) || (m_Record > E_ITEM_LAST_DISC)) if (!IsPlayingRecord())
{ {
// There's no record here // There's no record here
return; return false;
} }
cItems Drops; cItems Drops;
Drops.push_back(cItem(m_Record, 1, 0)); Drops.push_back(cItem(m_Record, 1, 0));
m_Record = 0;
m_World->SpawnItemPickups(Drops, m_PosX + 0.5, m_PosY + 1, m_PosZ + 0.5, 8); m_World->SpawnItemPickups(Drops, m_PosX + 0.5, m_PosY + 1, m_PosZ + 0.5, 8);
m_World->BroadcastSoundParticleEffect(1005, m_PosX, m_PosY, m_PosZ, 0); m_World->BroadcastSoundParticleEffect(1005, m_PosX, m_PosY, m_PosZ, 0);
m_Record = 0; m_World->SetBlockMeta(m_PosX, m_PosY, m_PosZ, E_META_JUKEBOX_OFF);
return true;
}
bool cJukeboxEntity::IsPlayingRecord(void)
{
return (m_Record != 0);
} }

View File

@ -37,10 +37,21 @@ public:
int GetRecord(void); int GetRecord(void);
void SetRecord(int a_Record); void SetRecord(int a_Record);
void PlayRecord(void);
/// Ejects the currently held record as a pickup. Does nothing when no record inserted. /** Plays the specified Record. Return false if a_Record isn't a playable Record (E_ITEM_XXX_DISC).
void EjectRecord(void); If there is a record already playing, ejects it first. */
bool PlayRecord(int a_Record);
/** Ejects the currently held record as a pickup. Return false when no record had been inserted. */
bool EjectRecord(void);
/** Is in the Jukebox a Record? */
bool IsPlayingRecord(void);
static bool IsRecordItem(int a_Item)
{
return ((a_Item >= E_ITEM_FIRST_DISC) && (a_Item <= E_ITEM_LAST_DISC));
}
// tolua_end // tolua_end

View File

@ -466,6 +466,10 @@ enum
E_META_FLOWER_PINK_TULIP = 7, E_META_FLOWER_PINK_TULIP = 7,
E_META_FLOWER_OXEYE_DAISY = 8, E_META_FLOWER_OXEYE_DAISY = 8,
// E_BLOCK_JUKEBOX metas
E_META_JUKEBOX_OFF = 0,
E_META_JUKEBOX_ON = 1,
// E_BLOCK_HOPPER metas: // E_BLOCK_HOPPER metas:
E_META_HOPPER_FACING_YM = 0, E_META_HOPPER_FACING_YM = 0,
E_META_HOPPER_UNATTACHED = 1, // Hopper doesn't move items up, there's no YP E_META_HOPPER_UNATTACHED = 1, // Hopper doesn't move items up, there's no YP

View File

@ -5,31 +5,35 @@
#include "../ForEachChunkProvider.h" #include "../ForEachChunkProvider.h"
#include "WorldInterface.h" #include "WorldInterface.h"
class cBlockHandler;
class cChunkInterface : public cForEachChunkProvider
class cChunkInterface:
public cForEachChunkProvider
{ {
public: public:
cChunkInterface(cChunkMap * a_ChunkMap) : m_ChunkMap(a_ChunkMap) {} cChunkInterface(cChunkMap * a_ChunkMap) : m_ChunkMap(a_ChunkMap) {}
BLOCKTYPE GetBlock (int a_BlockX, int a_BlockY, int a_BlockZ) BLOCKTYPE GetBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
return m_ChunkMap->GetBlock(a_BlockX,a_BlockY,a_BlockZ); return m_ChunkMap->GetBlock(a_BlockX,a_BlockY,a_BlockZ);
} }
BLOCKTYPE GetBlock (const Vector3i & a_Pos ) BLOCKTYPE GetBlock(const Vector3i & a_Pos)
{ {
return GetBlock( a_Pos.x, a_Pos.y, a_Pos.z ); return GetBlock(a_Pos.x, a_Pos.y, a_Pos.z);
} }
NIBBLETYPE GetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ) NIBBLETYPE GetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
return m_ChunkMap->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); return m_ChunkMap->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
} }
bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) bool GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta)
{ {
return m_ChunkMap->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); return m_ChunkMap->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
} }
/** Sets the block at the specified coords to the specified value. /** Sets the block at the specified coords to the specified value.
Full processing, incl. updating neighbors, is performed. Full processing, incl. updating neighbors, is performed.
*/ */
@ -37,7 +41,8 @@ public:
{ {
m_ChunkMap->SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); m_ChunkMap->SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
} }
void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData)
void SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData)
{ {
m_ChunkMap->SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_MetaData); m_ChunkMap->SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_MetaData);
} }
@ -55,7 +60,11 @@ public:
{ {
m_ChunkMap->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); m_ChunkMap->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
} }
void FastSetBlock(const Vector3i & a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ) { FastSetBlock( a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta ); }
void FastSetBlock(const Vector3i & a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta )
{
FastSetBlock( a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta );
}
void UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) void UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
@ -77,3 +86,7 @@ public:
private: private:
cChunkMap * m_ChunkMap; cChunkMap * m_ChunkMap;
}; };

View File

@ -4,6 +4,7 @@
#include "Painting.h" #include "Painting.h"
#include "ClientHandle.h" #include "ClientHandle.h"
#include "Player.h" #include "Player.h"
#include "../Chunk.h"
@ -30,6 +31,16 @@ void cPainting::SpawnOn(cClientHandle & a_Client)
void cPainting::Tick(float a_Dt, cChunk & a_Chunk)
{
UNUSED(a_Dt);
UNUSED(a_Chunk);
}
void cPainting::GetDrops(cItems & a_Items, cEntity * a_Killer) void cPainting::GetDrops(cItems & a_Items, cEntity * a_Killer)
{ {
if ((a_Killer != NULL) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative()) if ((a_Killer != NULL) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative())

View File

@ -24,7 +24,7 @@ public:
private: private:
virtual void SpawnOn(cClientHandle & a_Client) override; virtual void SpawnOn(cClientHandle & a_Client) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override {}; virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override; virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override;
virtual void KilledBy(cEntity * a_Killer) override virtual void KilledBy(cEntity * a_Killer) override
{ {

View File

@ -858,6 +858,8 @@ void cPlayer::KilledBy(cEntity * a_Killer)
else if (a_Killer->IsPlayer()) else if (a_Killer->IsPlayer())
{ {
GetWorld()->BroadcastChatDeath(Printf("%s was killed by %s", 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()));
m_World->GetScoreBoard().AddPlayerScore(((cPlayer *)a_Killer)->GetName(), cObjective::otPlayerKillCount, 1);
} }
else else
{ {
@ -867,24 +869,7 @@ void cPlayer::KilledBy(cEntity * a_Killer)
GetWorld()->BroadcastChatDeath(Printf("%s was killed by a %s", GetName().c_str(), KillerClass.c_str())); GetWorld()->BroadcastChatDeath(Printf("%s was killed by a %s", GetName().c_str(), KillerClass.c_str()));
} }
class cIncrementCounterCB m_World->GetScoreBoard().AddPlayerScore(GetName(), cObjective::otDeathCount, 1);
: public cObjectiveCallback
{
AString m_Name;
public:
cIncrementCounterCB(const AString & a_Name) : m_Name(a_Name) {}
virtual bool Item(cObjective * a_Objective) override
{
a_Objective->AddScore(m_Name, 1);
return true;
}
} IncrementCounter (GetName());
cScoreboard & Scoreboard = m_World->GetScoreBoard();
// Update scoreboard objectives
Scoreboard.ForEachObjectiveWith(cObjective::E_TYPE_DEATH_COUNT, IncrementCounter);
} }
@ -1529,10 +1514,14 @@ void cPlayer::LoadPermissionsFromDisk()
std::string Groups = IniFile.GetValue(m_PlayerName, "Groups", ""); std::string Groups = IniFile.GetValue(m_PlayerName, "Groups", "");
if (!Groups.empty()) if (!Groups.empty())
{ {
AStringVector Split = StringSplit( Groups, "," ); AStringVector Split = StringSplitAndTrim(Groups, ",");
for( unsigned int i = 0; i < Split.size(); i++ ) for (AStringVector::const_iterator itr = Split.begin(), end = Split.end(); itr != end; ++itr)
{ {
AddToGroup( Split[i].c_str() ); if (!cRoot::Get()->GetGroupManager()->ExistsGroup(*itr))
{
LOGWARNING("The group %s for player %s was not found!", itr->c_str(), m_PlayerName.c_str());
}
AddToGroup(*itr);
} }
} }
else else
@ -1540,16 +1529,15 @@ void cPlayer::LoadPermissionsFromDisk()
AddToGroup("Default"); AddToGroup("Default");
} }
m_Color = IniFile.GetValue(m_PlayerName, "Color", "-")[0]; AString Color = IniFile.GetValue(m_PlayerName, "Color", "-");
if (!Color.empty())
{
m_Color = Color[0];
}
} }
else else
{ {
LOGWARN("Regenerating users.ini, player %s will be added to the \"Default\" group", m_PlayerName.c_str()); cGroupManager::GenerateDefaultUsersIni(IniFile);
IniFile.AddHeaderComment(" This is the file in which the group the player belongs to is stored");
IniFile.AddHeaderComment(" The format is: [PlayerName] | Groups=GroupName");
IniFile.SetValue(m_PlayerName, "Groups", "Default");
IniFile.WriteFile("users.ini");
AddToGroup("Default"); AddToGroup("Default");
} }
ResolvePermissions(); ResolvePermissions();

View File

@ -46,6 +46,7 @@ cGroupManager::cGroupManager()
LOGD("-- Loading Groups --"); LOGD("-- Loading Groups --");
LoadGroups(); LoadGroups();
CheckUsers();
LOGD("-- Groups Successfully Loaded --"); LOGD("-- Groups Successfully Loaded --");
} }
@ -54,6 +55,53 @@ cGroupManager::cGroupManager()
void cGroupManager::GenerateDefaultUsersIni(cIniFile & a_IniFile)
{
LOGWARN("Regenerating users.ini, all users will be reset");
a_IniFile.AddHeaderComment(" This file stores the players' groups.");
a_IniFile.AddHeaderComment(" The format is:");
a_IniFile.AddHeaderComment(" [PlayerName]");
a_IniFile.AddHeaderComment(" Groups = GroupName1, GroupName2, ...");
a_IniFile.WriteFile("users.ini");
}
void cGroupManager::CheckUsers(void)
{
cIniFile IniFile;
if (!IniFile.ReadFile("users.ini"))
{
GenerateDefaultUsersIni(IniFile);
return;
}
unsigned int NumKeys = IniFile.GetNumKeys();
for (size_t i = 0; i < NumKeys; i++)
{
AString Player = IniFile.GetKeyName( i );
AString Groups = IniFile.GetValue(Player, "Groups", "");
if (!Groups.empty())
{
AStringVector Split = StringSplit( Groups, "," );
for( unsigned int i = 0; i < Split.size(); i++ )
{
if (!ExistsGroup(Split[i]))
{
LOGWARNING("The group %s for player %s was not found!", Split[i].c_str(), Player.c_str());
}
}
}
}
}
void cGroupManager::LoadGroups() void cGroupManager::LoadGroups()
{ {
cIniFile IniFile; cIniFile IniFile;
@ -137,6 +185,16 @@ void cGroupManager::LoadGroups()
bool cGroupManager::ExistsGroup( const AString & a_Name )
{
GroupMap::iterator itr = m_pState->Groups.find( a_Name );
return ( itr != m_pState->Groups.end() );
}
cGroup* cGroupManager::GetGroup( const AString & a_Name ) cGroup* cGroupManager::GetGroup( const AString & a_Name )
{ {
GroupMap::iterator itr = m_pState->Groups.find( a_Name ); GroupMap::iterator itr = m_pState->Groups.find( a_Name );

View File

@ -14,8 +14,13 @@ class cGroup;
class cGroupManager class cGroupManager
{ {
public: public:
bool ExistsGroup(const AString & a_Name);
cGroup * GetGroup(const AString & a_Name); cGroup * GetGroup(const AString & a_Name);
void LoadGroups(void); void LoadGroups(void);
void CheckUsers(void);
/** Writes the default header to the specified ini file, and saves it as "users.ini". */
static void GenerateDefaultUsersIni(cIniFile & a_IniFile);
private: private:
friend class cRoot; friend class cRoot;

View File

@ -29,6 +29,8 @@ class cDebugCallbacks :
{ {
virtual void OnRequestBegun(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) override virtual void OnRequestBegun(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) override
{ {
UNUSED(a_Connection);
if (cHTTPFormParser::HasFormData(a_Request)) if (cHTTPFormParser::HasFormData(a_Request))
{ {
a_Request.SetUserData(new cHTTPFormParser(a_Request, *this)); a_Request.SetUserData(new cHTTPFormParser(a_Request, *this));
@ -38,6 +40,8 @@ class cDebugCallbacks :
virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) override virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) override
{ {
UNUSED(a_Connection);
cHTTPFormParser * FormParser = (cHTTPFormParser *)(a_Request.GetUserData()); cHTTPFormParser * FormParser = (cHTTPFormParser *)(a_Request.GetUserData());
if (FormParser != NULL) if (FormParser != NULL)
{ {

View File

@ -248,6 +248,14 @@ cItemHandler::cItemHandler(int a_ItemType)
bool cItemHandler::OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) bool cItemHandler::OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir)
{ {
UNUSED(a_World);
UNUSED(a_Player);
UNUSED(a_Item);
UNUSED(a_BlockX);
UNUSED(a_BlockY);
UNUSED(a_BlockZ);
UNUSED(a_Dir);
return false; return false;
} }
@ -257,6 +265,14 @@ bool cItemHandler::OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem &
bool cItemHandler::OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) bool cItemHandler::OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir)
{ {
UNUSED(a_World);
UNUSED(a_Player);
UNUSED(a_Item);
UNUSED(a_BlockX);
UNUSED(a_BlockY);
UNUSED(a_BlockZ);
UNUSED(a_Dir);
return false; return false;
} }
@ -266,6 +282,8 @@ bool cItemHandler::OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cI
void cItemHandler::OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ) void cItemHandler::OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
UNUSED(a_Item);
BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
cBlockHandler * Handler = cBlockHandler::GetBlockHandler(Block); cBlockHandler * Handler = cBlockHandler::GetBlockHandler(Block);
@ -288,7 +306,9 @@ void cItemHandler::OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const
void cItemHandler::OnFoodEaten(cWorld * a_World, cPlayer * a_Player, cItem * a_Item) void cItemHandler::OnFoodEaten(cWorld * a_World, cPlayer * a_Player, cItem * a_Item)
{ {
UNUSED(a_World);
UNUSED(a_Player);
UNUSED(a_Item);
} }
@ -461,6 +481,8 @@ bool cItemHandler::IsPlaceable(void)
bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType) bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType)
{ {
UNUSED(a_BlockType);
return false; return false;
} }
@ -499,6 +521,8 @@ bool cItemHandler::GetPlacementBlockTypeMeta(
bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item) bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item)
{ {
UNUSED(a_Item);
FoodInfo Info = GetFoodInfo(); FoodInfo Info = GetFoodInfo();
if ((Info.FoodLevel > 0) || (Info.Saturation > 0.f)) if ((Info.FoodLevel > 0) || (Info.Saturation > 0.f))

View File

@ -42,7 +42,7 @@ cLog::~cLog()
cLog* cLog::GetInstance() cLog * cLog::GetInstance()
{ {
if (s_Log != NULL) if (s_Log != NULL)
{ {
@ -92,7 +92,7 @@ void cLog::ClearLog()
if( m_File ) if( m_File )
fclose (m_File); fclose (m_File);
#endif #endif
m_File = 0; m_File = NULL;
} }

View File

@ -67,6 +67,8 @@ void cMooshroom::OnRightClicked(cPlayer & a_Player)
cItems Drops; cItems Drops;
Drops.push_back(cItem(E_BLOCK_RED_MUSHROOM, 5, 0)); Drops.push_back(cItem(E_BLOCK_RED_MUSHROOM, 5, 0));
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10); m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10);
m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), cMonster::mtCow);
Destroy();
} break; } break;
} }
} }

View File

@ -89,6 +89,8 @@ bool cBlockingTCPLink::Connect(const char * iAddress, unsigned int iPort)
int cBlockingTCPLink::Send(char * a_Data, unsigned int a_Size, int a_Flags /* = 0 */ ) int cBlockingTCPLink::Send(char * a_Data, unsigned int a_Size, int a_Flags /* = 0 */ )
{ {
UNUSED(a_Flags);
ASSERT(m_Socket.IsValid()); ASSERT(m_Socket.IsValid());
if (!m_Socket.IsValid()) if (!m_Socket.IsValid())
{ {
@ -104,6 +106,8 @@ int cBlockingTCPLink::Send(char * a_Data, unsigned int a_Size, int a_Flags /* =
int cBlockingTCPLink::SendMessage( const char* a_Message, int a_Flags /* = 0 */ ) int cBlockingTCPLink::SendMessage( const char* a_Message, int a_Flags /* = 0 */ )
{ {
UNUSED(a_Flags);
ASSERT(m_Socket.IsValid()); ASSERT(m_Socket.IsValid());
if (!m_Socket.IsValid()) if (!m_Socket.IsValid())
{ {

View File

@ -194,7 +194,7 @@ void cRoot::Start(void)
#if !defined(ANDROID_NDK) #if !defined(ANDROID_NDK)
LOGD("Starting InputThread..."); LOGD("Starting InputThread...");
m_InputThread = new cThread( InputThread, this, "cRoot::InputThread" ); m_InputThread = new cThread( InputThread, this, "cRoot::InputThread" );
m_InputThread->Start( false ); // We should NOT wait? Otherwise we can´t stop the server from other threads than the input thread m_InputThread->Start( false ); // We should NOT wait? Otherwise we can't stop the server from other threads than the input thread
#endif #endif
long long finishmseconds = Time.GetNowTime(); long long finishmseconds = Time.GetNowTime();
@ -536,7 +536,9 @@ void cRoot::SaveAllChunks(void)
void cRoot::ReloadGroups(void) void cRoot::ReloadGroups(void)
{ {
LOG("Reload groups ...");
m_GroupManager->LoadGroups(); m_GroupManager->LoadGroups();
m_GroupManager->CheckUsers();
} }

View File

@ -17,19 +17,19 @@ AString cObjective::TypeToString(eType a_Type)
{ {
switch (a_Type) switch (a_Type)
{ {
case E_TYPE_DUMMY: return "dummy"; case otDummy: return "dummy";
case E_TYPE_DEATH_COUNT: return "deathCount"; case otDeathCount: return "deathCount";
case E_TYPE_PLAYER_KILL_COUNT: return "playerKillCount"; case otPlayerKillCount: return "playerKillCount";
case E_TYPE_TOTAL_KILL_COUNT: return "totalKillCount"; case otTotalKillCount: return "totalKillCount";
case E_TYPE_HEALTH: return "health"; case otHealth: return "health";
case E_TYPE_ACHIEVEMENT: return "achievement"; case otAchievement: return "achievement";
case E_TYPE_STAT: return "stat"; case otStat: return "stat";
case E_TYPE_STAT_ITEM_CRAFT: return "stat.craftItem"; case otStatItemCraft: return "stat.craftItem";
case E_TYPE_STAT_ITEM_USE: return "stat.useItem"; case otStatItemUse: return "stat.useItem";
case E_TYPE_STAT_ITEM_BREAK: return "stat.breakItem"; case otStatItemBreak: return "stat.breakItem";
case E_TYPE_STAT_BLOCK_MINE: return "stat.mineBlock"; case otStatBlockMine: return "stat.mineBlock";
case E_TYPE_STAT_ENTITY_KILL: return "stat.killEntity"; case otStatEntityKill: return "stat.killEntity";
case E_TYPE_STAT_ENTITY_KILLED_BY: return "stat.entityKilledBy"; case otStatEntityKilledBy: return "stat.entityKilledBy";
default: return ""; default: return "";
} }
@ -46,19 +46,19 @@ cObjective::eType cObjective::StringToType(const AString & a_Name)
const char * m_String; const char * m_String;
} TypeMap [] = } TypeMap [] =
{ {
{E_TYPE_DUMMY, "dummy"}, {otDummy, "dummy" },
{E_TYPE_DEATH_COUNT, "deathCount"}, {otDeathCount, "deathCount" },
{E_TYPE_PLAYER_KILL_COUNT, "playerKillCount"}, {otPlayerKillCount, "playerKillCount" },
{E_TYPE_TOTAL_KILL_COUNT, "totalKillCount"}, {otTotalKillCount, "totalKillCount" },
{E_TYPE_HEALTH, "health"}, {otHealth, "health" },
{E_TYPE_ACHIEVEMENT, "achievement"}, {otAchievement, "achievement" },
{E_TYPE_STAT, "stat"}, {otStat, "stat" },
{E_TYPE_STAT_ITEM_CRAFT, "stat.craftItem"}, {otStatItemCraft, "stat.craftItem" },
{E_TYPE_STAT_ITEM_USE, "stat.useItem"}, {otStatItemUse, "stat.useItem" },
{E_TYPE_STAT_ITEM_BREAK, "stat.breakItem"}, {otStatItemBreak, "stat.breakItem" },
{E_TYPE_STAT_BLOCK_MINE, "stat.mineBlock"}, {otStatBlockMine, "stat.mineBlock" },
{E_TYPE_STAT_ENTITY_KILL, "stat.killEntity"}, {otStatEntityKill, "stat.killEntity" },
{E_TYPE_STAT_ENTITY_KILLED_BY, "stat.entityKilledBy"} {otStatEntityKilledBy, "stat.entityKilledBy"}
}; };
for (size_t i = 0; i < ARRAYCOUNT(TypeMap); i++) for (size_t i = 0; i < ARRAYCOUNT(TypeMap); i++)
{ {
@ -67,7 +67,7 @@ cObjective::eType cObjective::StringToType(const AString & a_Name)
return TypeMap[i].m_Type; return TypeMap[i].m_Type;
} }
} // for i - TypeMap[] } // for i - TypeMap[]
return E_TYPE_DUMMY; return otDummy;
} }
@ -246,6 +246,17 @@ void cTeam::Reset(void)
void cTeam::SetDisplayName(const AString & a_Name)
{
m_DisplayName = a_Name;
// TODO 2014-03-01 xdot: Update clients
}
unsigned int cTeam::GetNumPlayers(void) const unsigned int cTeam::GetNumPlayers(void) const
{ {
return m_Players.size(); return m_Players.size();
@ -257,7 +268,7 @@ unsigned int cTeam::GetNumPlayers(void) const
cScoreboard::cScoreboard(cWorld * a_World) : m_World(a_World) cScoreboard::cScoreboard(cWorld * a_World) : m_World(a_World)
{ {
for (int i = 0; i < (int) E_DISPLAY_SLOT_COUNT; ++i) for (int i = 0; i < (int) dsCount; ++i)
{ {
m_Display[i] = NULL; m_Display[i] = NULL;
} }
@ -306,6 +317,8 @@ bool cScoreboard::RemoveObjective(const AString & a_Name)
ASSERT(m_World != NULL); ASSERT(m_World != NULL);
m_World->BroadcastScoreboardObjective(it->second.GetName(), it->second.GetDisplayName(), 1); m_World->BroadcastScoreboardObjective(it->second.GetName(), it->second.GetDisplayName(), 1);
// TODO 2014-03-01 xdot: Remove objective from display slot
return true; return true;
} }
@ -410,7 +423,7 @@ cTeam * cScoreboard::QueryPlayerTeam(const AString & a_Name)
void cScoreboard::SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot) void cScoreboard::SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot)
{ {
ASSERT(a_Slot < E_DISPLAY_SLOT_COUNT); ASSERT(a_Slot < dsCount);
cObjective * Objective = GetObjective(a_Objective); cObjective * Objective = GetObjective(a_Objective);
@ -435,7 +448,7 @@ void cScoreboard::SetDisplay(cObjective * a_Objective, eDisplaySlot a_Slot)
cObjective * cScoreboard::GetObjectiveIn(eDisplaySlot a_Slot) cObjective * cScoreboard::GetObjectiveIn(eDisplaySlot a_Slot)
{ {
ASSERT(a_Slot < E_DISPLAY_SLOT_COUNT); ASSERT(a_Slot < dsCount);
return m_Display[a_Slot]; return m_Display[a_Slot];
} }
@ -444,7 +457,7 @@ cObjective * cScoreboard::GetObjectiveIn(eDisplaySlot a_Slot)
void cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback& a_Callback) bool cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback& a_Callback)
{ {
cCSLock Lock(m_CSObjectives); cCSLock Lock(m_CSObjectives);
@ -455,10 +468,66 @@ void cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallb
// Call callback // Call callback
if (a_Callback.Item(&it->second)) if (a_Callback.Item(&it->second))
{ {
return; return false;
} }
} }
} }
return true;
}
bool cScoreboard::ForEachObjective(cObjectiveCallback& a_Callback)
{
cCSLock Lock(m_CSObjectives);
for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
{
// Call callback
if (a_Callback.Item(&it->second))
{
return false;
}
}
return true;
}
bool cScoreboard::ForEachTeam(cTeamCallback& a_Callback)
{
cCSLock Lock(m_CSObjectives);
for (cTeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it)
{
// Call callback
if (a_Callback.Item(&it->second))
{
return false;
}
}
return true;
}
void cScoreboard::AddPlayerScore(const AString & a_Name, cObjective::eType a_Type, cObjective::Score a_Value)
{
cCSLock Lock(m_CSObjectives);
for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
{
if (it->second.GetType() == a_Type)
{
it->second.AddScore(a_Name, a_Value);
}
}
} }
@ -474,7 +543,7 @@ void cScoreboard::SendTo(cClientHandle & a_Client)
it->second.SendTo(a_Client); it->second.SendTo(a_Client);
} }
for (int i = 0; i < (int) E_DISPLAY_SLOT_COUNT; ++i) for (int i = 0; i < (int) dsCount; ++i)
{ {
// Avoid race conditions // Avoid race conditions
cObjective * Objective = m_Display[i]; cObjective * Objective = m_Display[i];

View File

@ -14,9 +14,11 @@
class cObjective; class cObjective;
class cTeam;
class cWorld; class cWorld;
typedef cItemCallback<cObjective> cObjectiveCallback; typedef cItemCallback<cObjective> cObjectiveCallback;
typedef cItemCallback<cTeam> cTeamCallback;
@ -31,23 +33,23 @@ public:
enum eType enum eType
{ {
E_TYPE_DUMMY, otDummy,
E_TYPE_DEATH_COUNT, otDeathCount,
E_TYPE_PLAYER_KILL_COUNT, otPlayerKillCount,
E_TYPE_TOTAL_KILL_COUNT, otTotalKillCount,
E_TYPE_HEALTH, otHealth,
E_TYPE_ACHIEVEMENT, otAchievement,
E_TYPE_STAT, otStat,
E_TYPE_STAT_ITEM_CRAFT, otStatItemCraft,
E_TYPE_STAT_ITEM_USE, otStatItemUse,
E_TYPE_STAT_ITEM_BREAK, otStatItemBreak,
E_TYPE_STAT_BLOCK_MINE, otStatBlockMine,
E_TYPE_STAT_ENTITY_KILL, otStatEntityKill,
E_TYPE_STAT_ENTITY_KILLED_BY otStatEntityKilledBy
}; };
// tolua_end // tolua_end
@ -67,31 +69,37 @@ public:
const AString & GetName(void) const { return m_Name; } const AString & GetName(void) const { return m_Name; }
const AString & GetDisplayName(void) const { return m_DisplayName; } const AString & GetDisplayName(void) const { return m_DisplayName; }
/// Resets the objective /** Resets the objective */
void Reset(void); void Reset(void);
/// Returns the score of the specified player /** Returns the score of the specified player */
Score GetScore(const AString & a_Name) const; Score GetScore(const AString & a_Name) const;
/// Sets the score of the specified player /** Sets the score of the specified player */
void SetScore(const AString & a_Name, Score a_Score); void SetScore(const AString & a_Name, Score a_Score);
/// Resets the score of the specified player /** Resets the score of the specified player */
void ResetScore(const AString & a_Name); void ResetScore(const AString & a_Name);
/// Adds a_Delta and returns the new score /** Adds a_Delta and returns the new score */
Score AddScore(const AString & a_Name, Score a_Delta); Score AddScore(const AString & a_Name, Score a_Delta);
/// Subtracts a_Delta and returns the new score /** Subtracts a_Delta and returns the new score */
Score SubScore(const AString & a_Name, Score a_Delta); Score SubScore(const AString & a_Name, Score a_Delta);
void SetDisplayName(const AString & a_Name); void SetDisplayName(const AString & a_Name);
// tolua_end // tolua_end
/// Send this objective to the specified client /** Send this objective to the specified client */
void SendTo(cClientHandle & a_Client); void SendTo(cClientHandle & a_Client);
static const char * GetClassStatic(void) // Needed for ManualBindings's ForEach templates
{
return "cObjective";
}
private: private:
typedef std::pair<AString, Score> cTrackedPlayer; typedef std::pair<AString, Score> cTrackedPlayer;
@ -109,7 +117,8 @@ private:
friend class cScoreboardSerializer; friend class cScoreboardSerializer;
};
}; // tolua_export
@ -127,21 +136,21 @@ public:
const AString & a_Prefix, const AString & a_Suffix const AString & a_Prefix, const AString & a_Suffix
); );
/// Adds a new player to the team
bool AddPlayer(const AString & a_Name);
/// Removes a player from the team
bool RemovePlayer(const AString & a_Name);
/// Returns whether the specified player is in this team
bool HasPlayer(const AString & a_Name) const;
/// Removes all registered players
void Reset(void);
// tolua_begin // tolua_begin
/// Returns the number of registered players /** Adds a new player to the team */
bool AddPlayer(const AString & a_Name);
/** Removes a player from the team */
bool RemovePlayer(const AString & a_Name);
/** Returns whether the specified player is in this team */
bool HasPlayer(const AString & a_Name) const;
/** Removes all registered players */
void Reset(void);
/** Returns the number of registered players */
unsigned int GetNumPlayers(void) const; unsigned int GetNumPlayers(void) const;
bool AllowsFriendlyFire(void) const { return m_AllowsFriendlyFire; } bool AllowsFriendlyFire(void) const { return m_AllowsFriendlyFire; }
@ -163,6 +172,11 @@ public:
// tolua_end // tolua_end
static const char * GetClassStatic(void) // Needed for ManualBindings's ForEach templates
{
return "cTeam";
}
private: private:
typedef std::set<AString> cPlayerNameSet; typedef std::set<AString> cPlayerNameSet;
@ -180,7 +194,8 @@ private:
friend class cScoreboardSerializer; friend class cScoreboardSerializer;
};
}; // tolua_export
@ -193,11 +208,11 @@ public:
enum eDisplaySlot enum eDisplaySlot
{ {
E_DISPLAY_SLOT_LIST = 0, dsList = 0,
E_DISPLAY_SLOT_SIDEBAR, dsSidebar,
E_DISPLAY_SLOT_NAME, dsName,
E_DISPLAY_SLOT_COUNT dsCount
}; };
// tolua_end // tolua_end
@ -209,44 +224,61 @@ public:
// tolua_begin // tolua_begin
/// Registers a new scoreboard objective, returns the cObjective instance, NULL on name collision /** Registers a new scoreboard objective, returns the cObjective instance, NULL on name collision */
cObjective * RegisterObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type); cObjective * RegisterObjective(const AString & a_Name, const AString & a_DisplayName, cObjective::eType a_Type);
/// Removes a registered objective, returns true if operation was successful /** Removes a registered objective, returns true if operation was successful */
bool RemoveObjective(const AString & a_Name); bool RemoveObjective(const AString & a_Name);
/// Retrieves the objective with the specified name, NULL if not found /** Retrieves the objective with the specified name, NULL if not found */
cObjective * GetObjective(const AString & a_Name); cObjective * GetObjective(const AString & a_Name);
/// Registers a new team, returns the cTeam instance, NULL on name collision /** Registers a new team, returns the cTeam instance, NULL on name collision */
cTeam * RegisterTeam(const AString & a_Name, const AString & a_DisplayName, const AString & a_Prefix, const AString & a_Suffix); cTeam * RegisterTeam(const AString & a_Name, const AString & a_DisplayName, const AString & a_Prefix, const AString & a_Suffix);
/// Removes a registered team, returns true if operation was successful /** Removes a registered team, returns true if operation was successful */
bool RemoveTeam(const AString & a_Name); bool RemoveTeam(const AString & a_Name);
/// Retrieves the team with the specified name, NULL if not found /** Retrieves the team with the specified name, NULL if not found */
cTeam * GetTeam(const AString & a_Name); cTeam * GetTeam(const AString & a_Name);
cTeam * QueryPlayerTeam(const AString & a_Name); // WARNING: O(n logn)
void SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot); void SetDisplay(const AString & a_Objective, eDisplaySlot a_Slot);
void SetDisplay(cObjective * a_Objective, eDisplaySlot a_Slot);
cObjective * GetObjectiveIn(eDisplaySlot a_Slot); cObjective * GetObjectiveIn(eDisplaySlot a_Slot);
/// Execute callback for each objective with the specified type
void ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback& a_Callback);
unsigned int GetNumObjectives(void) const; unsigned int GetNumObjectives(void) const;
unsigned int GetNumTeams(void) const; unsigned int GetNumTeams(void) const;
void AddPlayerScore(const AString & a_Name, cObjective::eType a_Type, cObjective::Score a_Value = 1);
// tolua_end // tolua_end
/// Send this scoreboard to the specified client /** Send this scoreboard to the specified client */
void SendTo(cClientHandle & a_Client); void SendTo(cClientHandle & a_Client);
cTeam * QueryPlayerTeam(const AString & a_Name); // WARNING: O(n logn)
/** Execute callback for each objective with the specified type
*
* Returns true if all objectives processed, false if the callback aborted by returning true.
*/
bool ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback& a_Callback);
/** Execute callback for each objective.
*
* Returns true if all objectives have been processed, false if the callback aborted by returning true.
*/
bool ForEachObjective(cObjectiveCallback& a_Callback); // Exported in ManualBindings.cpp
/** Execute callback for each team.
*
* Returns true if all teams have been processed, false if the callback aborted by returning true.
*/
bool ForEachTeam(cTeamCallback& a_Callback); // Exported in ManualBindings.cpp
void SetDisplay(cObjective * a_Objective, eDisplaySlot a_Slot);
private: private:
@ -265,11 +297,12 @@ private:
cWorld * m_World; cWorld * m_World;
cObjective* m_Display[E_DISPLAY_SLOT_COUNT]; cObjective * m_Display[dsCount];
friend class cScoreboardSerializer; friend class cScoreboardSerializer;
} ;
}; // tolua_export

View File

@ -472,6 +472,8 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac
if (split[0] == "reloadgroups") if (split[0] == "reloadgroups")
{ {
cRoot::Get()->ReloadGroups(); cRoot::Get()->ReloadGroups();
a_Output.Out("Groups reloaded!");
a_Output.Finished();
return; return;
} }

View File

@ -224,6 +224,24 @@ void cSlotArea::DblClicked(cPlayer & a_Player, int a_SlotNum)
void cSlotArea::OnPlayerAdded(cPlayer & a_Player)
{
UNUSED(a_Player);
}
void cSlotArea::OnPlayerRemoved(cPlayer & a_Player)
{
UNUSED(a_Player);
}
void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots) void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots)
{ {
for (int i = 0; i < m_NumSlots; i++) for (int i = 0; i < m_NumSlots; i++)
@ -447,6 +465,18 @@ void cSlotAreaCrafting::OnPlayerRemoved(cPlayer & a_Player)
void cSlotAreaCrafting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots)
{
UNUSED(a_ItemStack);
UNUSED(a_Player);
UNUSED(a_ShouldApply);
UNUSED(a_KeepEmptySlots);
}
void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player) void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player)
{ {
cItem & DraggingItem = a_Player.GetDraggingItem(); cItem & DraggingItem = a_Player.GetDraggingItem();

View File

@ -48,10 +48,10 @@ public:
virtual void DblClicked(cPlayer & a_Player, int a_SlotNum); virtual void DblClicked(cPlayer & a_Player, int a_SlotNum);
/// Called when a new player opens the same parent window. The window already tracks the player. CS-locked. /// Called when a new player opens the same parent window. The window already tracks the player. CS-locked.
virtual void OnPlayerAdded(cPlayer & a_Player) {} ; virtual void OnPlayerAdded(cPlayer & a_Player);
/// Called when one of the players closes the parent window. The window already doesn't track the player. CS-locked. /// Called when one of the players closes the parent window. The window already doesn't track the player. CS-locked.
virtual void OnPlayerRemoved(cPlayer & a_Player) {} ; virtual void OnPlayerRemoved(cPlayer & a_Player);
/** Called to store as much of a_ItemStack in the area as possible. a_ItemStack is modified to reflect the change. /** Called to store as much of a_ItemStack in the area as possible. a_ItemStack is modified to reflect the change.
The default implementation searches each slot for available space and distributes the stack there. The default implementation searches each slot for available space and distributes the stack there.
@ -226,7 +226,7 @@ public:
virtual void OnPlayerRemoved(cPlayer & a_Player) override; virtual void OnPlayerRemoved(cPlayer & a_Player) override;
// Distributing items into this area is completely disabled // Distributing items into this area is completely disabled
virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override {} virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override;
protected: protected:
/// Maps player's EntityID -> current recipe; not a std::map because cCraftingGrid needs proper constructor params /// Maps player's EntityID -> current recipe; not a std::map because cCraftingGrid needs proper constructor params

View File

@ -173,13 +173,14 @@ public:
{ {
ASSERT(m_Tags[a_Tag].m_Type == TAG_Float); ASSERT(m_Tags[a_Tag].m_Type == TAG_Float);
// Cause a compile-time error if sizeof(int) != sizeof(float) // Cause a compile-time error if sizeof(float) != 4
char Check1[sizeof(int) - sizeof(float) + 1]; // sizeof(int) >= sizeof(float) // If your platform produces a compiler error here, you'll need to add code that manually decodes 32-bit floats
char Check2[sizeof(float) - sizeof(int) + 1]; // sizeof(float) >= sizeof(int) char Check1[5 - sizeof(float)]; // Fails if sizeof(float) > 4
char Check2[sizeof(float) - 3]; // Fails if sizeof(float) < 4
UNUSED(Check1); UNUSED(Check1);
UNUSED(Check2); UNUSED(Check2);
int i = GetBEInt(m_Data + m_Tags[a_Tag].m_DataStart); Int32 i = GetBEInt(m_Data + m_Tags[a_Tag].m_DataStart);
float f; float f;
memcpy(&f, &i, sizeof(f)); memcpy(&f, &i, sizeof(f));
return f; return f;

View File

@ -173,13 +173,13 @@ void cScoreboardSerializer::SaveScoreboardToNBT(cFastNBTWriter & a_Writer)
a_Writer.BeginCompound("DisplaySlots"); a_Writer.BeginCompound("DisplaySlots");
cObjective * Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::E_DISPLAY_SLOT_LIST); cObjective * Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::dsList);
a_Writer.AddString("slot_0", (Objective == NULL) ? "" : Objective->GetName()); a_Writer.AddString("slot_0", (Objective == NULL) ? "" : Objective->GetName());
Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::E_DISPLAY_SLOT_SIDEBAR); Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::dsSidebar);
a_Writer.AddString("slot_1", (Objective == NULL) ? "" : Objective->GetName()); a_Writer.AddString("slot_1", (Objective == NULL) ? "" : Objective->GetName());
Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::E_DISPLAY_SLOT_NAME); Objective = m_ScoreBoard->GetObjectiveIn(cScoreboard::dsName);
a_Writer.AddString("slot_2", (Objective == NULL) ? "" : Objective->GetName()); a_Writer.AddString("slot_2", (Objective == NULL) ? "" : Objective->GetName());
a_Writer.EndCompound(); // DisplaySlots a_Writer.EndCompound(); // DisplaySlots
@ -280,7 +280,7 @@ bool cScoreboardSerializer::LoadScoreboardFromNBT(const cParsedNBT & a_NBT)
{ {
AString Name, DisplayName, Prefix, Suffix; AString Name, DisplayName, Prefix, Suffix;
bool AllowsFriendlyFire = false, CanSeeFriendlyInvisible = false; bool AllowsFriendlyFire = true, CanSeeFriendlyInvisible = false;
int CurrLine = a_NBT.FindChildByName(Child, "Name"); int CurrLine = a_NBT.FindChildByName(Child, "Name");
if (CurrLine >= 0) if (CurrLine >= 0)
@ -346,7 +346,7 @@ bool cScoreboardSerializer::LoadScoreboardFromNBT(const cParsedNBT & a_NBT)
{ {
AString Name = a_NBT.GetString(CurrLine); AString Name = a_NBT.GetString(CurrLine);
m_ScoreBoard->SetDisplay(Name, cScoreboard::E_DISPLAY_SLOT_LIST); m_ScoreBoard->SetDisplay(Name, cScoreboard::dsList);
} }
CurrLine = a_NBT.FindChildByName(DisplaySlots, "slot_1"); CurrLine = a_NBT.FindChildByName(DisplaySlots, "slot_1");
@ -354,7 +354,7 @@ bool cScoreboardSerializer::LoadScoreboardFromNBT(const cParsedNBT & a_NBT)
{ {
AString Name = a_NBT.GetString(CurrLine); AString Name = a_NBT.GetString(CurrLine);
m_ScoreBoard->SetDisplay(Name, cScoreboard::E_DISPLAY_SLOT_SIDEBAR); m_ScoreBoard->SetDisplay(Name, cScoreboard::dsSidebar);
} }
CurrLine = a_NBT.FindChildByName(DisplaySlots, "slot_2"); CurrLine = a_NBT.FindChildByName(DisplaySlots, "slot_2");
@ -362,7 +362,7 @@ bool cScoreboardSerializer::LoadScoreboardFromNBT(const cParsedNBT & a_NBT)
{ {
AString Name = a_NBT.GetString(CurrLine); AString Name = a_NBT.GetString(CurrLine);
m_ScoreBoard->SetDisplay(Name, cScoreboard::E_DISPLAY_SLOT_NAME); m_ScoreBoard->SetDisplay(Name, cScoreboard::dsName);
} }
return true; return true;

View File

@ -243,31 +243,36 @@ int main( int argc, char **argv )
// Check if comm logging is to be enabled: // Check if comm logging is to be enabled:
for (int i = 0; i < argc; i++) for (int i = 0; i < argc; i++)
{ {
AString Arg(argv[i]);
if ( if (
(NoCaseCompare(argv[i], "/commlog") == 0) || (NoCaseCompare(Arg, "/commlog") == 0) ||
(NoCaseCompare(argv[i], "/logcomm") == 0) (NoCaseCompare(Arg, "/logcomm") == 0)
) )
{ {
g_ShouldLogCommIn = true; g_ShouldLogCommIn = true;
g_ShouldLogCommOut = true; g_ShouldLogCommOut = true;
} }
if ( else if (
(NoCaseCompare(argv[i], "/commlogin") == 0) || (NoCaseCompare(Arg, "/commlogin") == 0) ||
(NoCaseCompare(argv[i], "/comminlog") == 0) || (NoCaseCompare(Arg, "/comminlog") == 0) ||
(NoCaseCompare(argv[i], "/logcommin") == 0) (NoCaseCompare(Arg, "/logcommin") == 0)
) )
{ {
g_ShouldLogCommIn = true; g_ShouldLogCommIn = true;
} }
if ( else if (
(NoCaseCompare(argv[i], "/commlogout") == 0) || (NoCaseCompare(Arg, "/commlogout") == 0) ||
(NoCaseCompare(argv[i], "/commoutlog") == 0) || (NoCaseCompare(Arg, "/commoutlog") == 0) ||
(NoCaseCompare(argv[i], "/logcommout") == 0) (NoCaseCompare(Arg, "/logcommout") == 0)
) )
{ {
g_ShouldLogCommOut = true; g_ShouldLogCommOut = true;
} }
} else if (NoCaseCompare(Arg, "nooutbuf") == 0)
{
setvbuf(stdout, NULL, _IONBF, 0);
}
} // for i - argv[]
#if !defined(ANDROID_NDK) #if !defined(ANDROID_NDK)
try try