1
0

Merge branch 'master' into ballisticmissiles

Conflicts:
	src/ClientHandle.cpp
This commit is contained in:
Tiger Wang 2014-03-09 12:53:50 +00:00
commit c2978a3457
134 changed files with 3964 additions and 1400 deletions

View File

@ -22,8 +22,10 @@ Code Stuff
- This helps prevent mistakes such as `if (a & 1 == 0)` - This helps prevent mistakes such as `if (a & 1 == 0)`
* White space is free, so use it freely * White space is free, so use it freely
- "freely" as in "plentifully", not "arbitrarily" - "freely" as in "plentifully", not "arbitrarily"
* All `case` statements inside a `switch` need an extra indent.
* Each and every control statement deserves its braces. This helps maintainability later on when the file is edited, lines added or removed - the control logic doesn't break so easily. * Each and every control statement deserves its braces. This helps maintainability later on when the file is edited, lines added or removed - the control logic doesn't break so easily.
- The only exception: a `switch` statement with all `case` statements being a single short statement is allowed to use the short brace-less form. - The only exception: a `switch` statement with all `case` statements being a single short statement is allowed to use the short brace-less form.
- These two rules really mean that indent is governed by braces
* Add an empty last line in all source files (GCC and GIT can complain otherwise) * Add an empty last line in all source files (GCC and GIT can complain otherwise)
* Use doxy-comments for functions in the header file, format as `/** Description */` * Use doxy-comments for functions in the header file, format as `/** Description */`
* Use spaces after the comment markers: `// Comment` instead of `//Comment` * Use spaces after the comment markers: `// Comment` instead of `//Comment`

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

@ -1,2 +1,3 @@
*.txt *.txt
*.md *.md
*/

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

@ -134,6 +134,7 @@ g_APIDesc =
HasBlockSkyLights = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include skylight" }, HasBlockSkyLights = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include skylight" },
HasBlockTypes = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include block types" }, HasBlockTypes = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include block types" },
LoadFromSchematicFile = { Params = "FileName", Return = "", Notes = "Clears current content and loads new content from the specified schematic file. Returns true if successful. Returns false and logs error if unsuccessful, old content is preserved in such a case." }, LoadFromSchematicFile = { Params = "FileName", Return = "", Notes = "Clears current content and loads new content from the specified schematic file. Returns true if successful. Returns false and logs error if unsuccessful, old content is preserved in such a case." },
LoadFromSchematicString = { Params = "SchematicData", Return = "", Notes = "Clears current content and loads new content from the specified string (assumed to contain .schematic data). Returns true if successful. Returns false and logs error if unsuccessful, old content is preserved in such a case." },
Merge = Merge =
{ {
{ Params = "BlockAreaSrc, {{Vector3i|RelMinCoords}}, Strategy", Return = "", Notes = "Merges BlockAreaSrc into this object at the specified relative coords, using the specified strategy" }, { Params = "BlockAreaSrc, {{Vector3i|RelMinCoords}}, Strategy", Return = "", Notes = "Merges BlockAreaSrc into this object at the specified relative coords, using the specified strategy" },
@ -161,6 +162,7 @@ g_APIDesc =
RotateCW = { Params = "", Return = "", Notes = "Rotates the block area around the Y axis, clockwise (north -> east). Modifies blocks' metas (if present) to match." }, RotateCW = { Params = "", Return = "", Notes = "Rotates the block area around the Y axis, clockwise (north -> east). Modifies blocks' metas (if present) to match." },
RotateCWNoMeta = { Params = "", Return = "", Notes = "Rotates the block area around the Y axis, clockwise (north -> east). Doesn't modify blocks' metas." }, RotateCWNoMeta = { Params = "", Return = "", Notes = "Rotates the block area around the Y axis, clockwise (north -> east). Doesn't modify blocks' metas." },
SaveToSchematicFile = { Params = "FileName", Return = "", Notes = "Saves the current contents to a schematic file. Returns true if successful." }, SaveToSchematicFile = { Params = "FileName", Return = "", Notes = "Saves the current contents to a schematic file. Returns true if successful." },
SaveToSchematicString = { Params = "", Return = "string", Notes = "Saves the current contents to a string (in a .schematic file format). Returns the data if successful, nil if failed." },
SetBlockLight = { Params = "BlockX, BlockY, BlockZ, BlockLight", Return = "", Notes = "Sets the blocklight at the specified absolute coords" }, SetBlockLight = { Params = "BlockX, BlockY, BlockZ, BlockLight", Return = "", Notes = "Sets the blocklight at the specified absolute coords" },
SetBlockMeta = { Params = "BlockX, BlockY, BlockZ, BlockMeta", Return = "", Notes = "Sets the block meta at the specified absolute coords" }, SetBlockMeta = { Params = "BlockX, BlockY, BlockZ, BlockMeta", Return = "", Notes = "Sets the block meta at the specified absolute coords" },
SetBlockSkyLight = { Params = "BlockX, BlockY, BlockZ, SkyLight", Return = "", Notes = "Sets the skylight at the specified absolute coords" }, SetBlockSkyLight = { Params = "BlockX, BlockY, BlockZ, SkyLight", Return = "", Notes = "Sets the skylight at the specified absolute coords" },
@ -290,6 +292,38 @@ g_APIDesc =
}, -- AdditionalInfo }, -- AdditionalInfo
}, -- cBlockArea }, -- cBlockArea
cBlockInfo =
{
Desc = [[
This class is used to query and register block properties.
]],
Functions =
{
FullyOccupiesVoxel = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block fully occupies its voxel." },
Get = { Params = "Type", Return = "{{cBlockInfo}}", Notes = "(STATIC) Returns the {{cBlockInfo}} structure for the specified type." },
GetLightValue = { Params = "Type", Return = "number", Notes = "(STATIC) Returns how much light the specified block emits on its own." },
GetSpreadLightFalloff = { Params = "Type", Return = "number", Notes = "(STATIC) Returns how much light the specified block consumes." },
IsOneHitDig = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block will be destroyed after a single hit." },
IsPistonBreakable = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether a piston can break the specified block." },
IsSnowable = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block can hold snow atop." },
IsSolid = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block is solid." },
IsTransparent = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block is transparent." },
RequiresSpecialTool = { Params = "Type", Return = "bool", Notes = "(STATIC) Returns whether the specified block requires a special tool to drop." },
},
Variables =
{
m_FullyOccupiesVoxel = { Type = "bool", Notes = "Does this block fully occupy its voxel - is it a 'full' block?" },
m_IsSnowable = { Type = "bool", Notes = "Can this block hold snow atop?" },
m_IsSolid = { Type = "bool", Notes = "Is this block solid (player cannot walk through)?" },
m_LightValue = { Type = "number", Notes = "How much light do the blocks emit on their own?" },
m_OneHitDig = { Type = "bool", Notes = "Is a block destroyed after a single hit?" },
m_PistonBreakable = { Type = "bool", Notes = "Can a piston break this block?" },
m_RequiresSpecialTool = { Type = "bool", Notes = "Does this block require a tool to drop?" },
m_SpreadLightFalloff = { Type = "number", Notes = "How much light do the blocks consume?" },
m_Transparent = { Type = "bool", Notes = "Is a block completely transparent? (light doesn't get decreased(?))" },
},
}, -- cBlockInfo
cChatColor = cChatColor =
{ {
Desc = [[ Desc = [[
@ -451,6 +485,58 @@ end
}, },
}, -- cClientHandle }, -- cClientHandle
cCompositeChat =
{
Desc = [[
Encapsulates a chat message that can contain various formatting, URLs, commands executed on click
and commands suggested on click. The chat message can be sent by the regular chat-sending functions,
{{cPlayer}}:SendMessage(), {{cWorld}}:BroadcastChat() and {{cRoot}}:BroadcastChat().</p>
<p>
Note that most of the functions in this class are so-called modifiers - they modify the object and
then return the object itself, so that they can be chained one after another.
]],
Functions =
{
constructor =
{
{ Params = "", Return = "", Notes = "Creates an empty chat message" },
{ Params = "Text", Return = "", Notes = "Creates a chat message containing the specified text, parsed by the ParseText() function. This allows easy migration from old chat messages." },
},
AddRunCommandPart = { Params = "Text, Command, [Style]", Return = "self", Notes = "Adds a text which, when clicked, runs the specified command. Chaining." },
AddSuggestCommandPart = { Params = "Text, Command, [Style]", Return = "self", Notes = "Adds a text which, when clicked, puts the specified command into the player's chat input area. Chaining." },
AddTextPart = { Params = "Text, [Style]", Return = "self", Notes = "Adds a regular text. Chaining." },
AddUrlPart = { Params = "Text, Url, [Style]", Return = "self", Notes = "Adds a text which, when clicked, opens up a browser at the specified URL. Chaining." },
Clear = { Params = "", Return = "", Notes = "Removes all parts from this object" },
GetMessageType = { Params = "", Return = "MessageType", Notes = "Returns the MessageType (mtXXX constant) that is associated with this message. When sent to a player, the message will be formatted according to this message type and the player's settings (adding \"[INFO]\" prefix etc.)" },
ParseText = { Params = "Text", Return = "self", Notes = "Adds text, while recognizing http and https URLs and old-style formatting codes (\"@2\"). Chaining." },
SetMessageType = { Params = "MessageType", Return = "self", Notes = "Sets the MessageType (mtXXX constant) that is associated with this message. When sent to a player, the message will be formatted according to this message type and the player's settings (adding \"[INFO]\" prefix etc.) Chaining." },
UnderlineUrls = { Params = "", Return = "self", Notes = "Makes all URL parts contained in the message underlined. Doesn't affect parts added in the future. Chaining." },
},
AdditionalInfo =
{
{
Header = "Chaining example",
Contents = [[
Sending a chat message that is composed of multiple different parts has been made easy thanks to
chaining. Consider the following example that shows how a message containing all kinds of parts
is sent (adapted from the Debuggers plugin):
<pre class="prettyprint lang-lua">
function OnPlayerJoined(a_Player)
-- Send an example composite chat message to the player:
a_Player:SendMessage(cCompositeChat()
:AddTextPart("Hello, ")
:AddUrlPart(a_Player:GetName(), "www.mc-server.org", "u@2") -- Colored underlined link
:AddSuggestCommandPart(", and welcome.", "/help", "u") -- Underlined suggest-command
:AddRunCommandPart(" SetDay", "/time set 0") -- Regular text that will execute command when clicked
:SetMessageType(mtJoin) -- It is a join-message
)
end</pre>
]],
},
}, -- AdditionalInfo
}, -- cCompositeChat
cCraftingGrid = cCraftingGrid =
{ {
Desc = [[ Desc = [[
@ -1115,6 +1201,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 +1895,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 +1944,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 +1994,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.",
@ -1973,7 +2152,9 @@ end
DoWithDropSpenserAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dropper or a dispenser at the specified coords, calls the CallbackFunction with the {{cDropSpenserEntity}} parameter representing the dropper or dispenser. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cDropSpenserEntity|DropSpenserEntity}}, [CallbackData])</pre> Note that this can be used to access both dispensers and droppers in a similar way. The function returns false if there is neither dispenser nor dropper, or if there is, it returns the bool value that the callback has returned." }, DoWithDropSpenserAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dropper or a dispenser at the specified coords, calls the CallbackFunction with the {{cDropSpenserEntity}} parameter representing the dropper or dispenser. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cDropSpenserEntity|DropSpenserEntity}}, [CallbackData])</pre> Note that this can be used to access both dispensers and droppers in a similar way. The function returns false if there is neither dispenser nor dropper, or if there is, it returns the bool value that the callback has returned." },
DoWithDropperAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dropper at the specified coords, calls the CallbackFunction with the {{cDropperEntity}} parameter representing the dropper. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cDropperEntity|DropperEntity}}, [CallbackData])</pre> The function returns false if there is no dropper, or if there is, it returns the bool value that the callback has returned." }, DoWithDropperAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dropper at the specified coords, calls the CallbackFunction with the {{cDropperEntity}} parameter representing the dropper. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cDropperEntity|DropperEntity}}, [CallbackData])</pre> The function returns false if there is no dropper, or if there is, it returns the bool value that the callback has returned." },
DoWithEntityByID = { Params = "EntityID, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If an entity with the specified ID exists, calls the callback with the {{cEntity}} parameter representing the entity. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}}, [CallbackData])</pre> The function returns false if the entity was not found, and it returns the same bool value that the callback has returned if the entity was found." }, DoWithEntityByID = { Params = "EntityID, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If an entity with the specified ID exists, calls the callback with the {{cEntity}} parameter representing the entity. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}}, [CallbackData])</pre> The function returns false if the entity was not found, and it returns the same bool value that the callback has returned if the entity was found." },
DoWithFlowerPotAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a flower pot at the specified coords, calls the CallbackFunction with the {{cFlowerPotEntity}} parameter representing the flower pot. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cFlowerPotEntity|FlowerPotEntity}}, [CallbackData])</pre> The function returns false if there is no flower pot, or if there is, it returns the bool value that the callback has returned." },
DoWithFurnaceAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a furnace at the specified coords, calls the CallbackFunction with the {{cFurnaceEntity}} parameter representing the furnace. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cFurnaceEntity|FurnaceEntity}}, [CallbackData])</pre> The function returns false if there is no furnace, or if there is, it returns the bool value that the callback has returned." }, DoWithFurnaceAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a furnace at the specified coords, calls the CallbackFunction with the {{cFurnaceEntity}} parameter representing the furnace. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cFurnaceEntity|FurnaceEntity}}, [CallbackData])</pre> The function returns false if there is no furnace, or if there is, it returns the bool value that the callback has returned." },
DoWithMobHeadAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a mob head at the specified coords, calls the CallbackFunction with the {{cMobHeadEntity}} parameter representing the furnace. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cMobHeadEntity|MobHeadEntity}}, [CallbackData])</pre> The function returns false if there is no mob head, or if there is, it returns the bool value that the callback has returned." },
DoWithNoteBlockAt = { Params = "BlockX, BlockY, BlockZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a note block at the specified coords, calls the CallbackFunction with the {{cNoteEntity}} parameter representing the note block. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cNoteEntity|NoteEntity}}, [CallbackData])</pre> The function returns false if there is no note block, or if there is, it returns the bool value that the callback has returned." }, DoWithNoteBlockAt = { Params = "BlockX, BlockY, BlockZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a note block at the specified coords, calls the CallbackFunction with the {{cNoteEntity}} parameter representing the note block. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cNoteEntity|NoteEntity}}, [CallbackData])</pre> The function returns false if there is no note block, or if there is, it returns the bool value that the callback has returned." },
DoWithPlayer = { Params = "PlayerName, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a player of the specified name (exact match), calls the CallbackFunction with the {{cPlayer}} parameter representing the player. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}}, [CallbackData])</pre> The function returns false if the player was not found, or whatever bool value the callback returned if the player was found." }, DoWithPlayer = { Params = "PlayerName, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a player of the specified name (exact match), calls the CallbackFunction with the {{cPlayer}} parameter representing the player. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}}, [CallbackData])</pre> The function returns false if the player was not found, or whatever bool value the callback returned if the player was found." },
FastSetBlock = FastSetBlock =
@ -2576,16 +2757,16 @@ end
IgnoreClasses = IgnoreClasses =
{ {
"coroutine", "^coroutine$",
"debug", "^debug$",
"io", "^io$",
"math", "^math$",
"package", "^package$",
"os", "^os$",
"string", "^string$",
"table", "^table$",
"g_Stats", "^g_Stats$",
"g_TrackedPages", "^g_TrackedPages$",
}, },
IgnoreFunctions = IgnoreFunctions =

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
@ -236,6 +238,20 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
}, },
Inherits = "cBlockEntity"; Inherits = "cBlockEntity";
}, -- cSignEntity }, -- cSignEntity
cFlowerPotEntity =
{
Desc = [[
This class represents a flower pot entity in the world.
]],
Functions =
{
IsItemInPot = { Params = "", Return = "bool", Notes = "Is a flower in the pot?" },
GetItem = { Params = "", Return = "{{cItem|Item}}", Notes = "Returns the item in the flower pot." },
SetItem = { Params = "{{cItem|Item}}", Return = "", Notes = "Set the item in the flower pot" },
},
Inherits = "cBlockEntity";
}, -- cFlowerPotEntity
} }

@ -1 +1 @@
Subproject commit 3b416b07a339b3abcbc127070d56eea05b05373d Subproject commit 013a32a7fb3c8a6cfe0aef892d4c7394d4e1be59

View File

@ -30,6 +30,7 @@ function Initialize(Plugin)
PM:AddHook(cPluginManager.HOOK_CHUNK_GENERATED, OnChunkGenerated); PM:AddHook(cPluginManager.HOOK_CHUNK_GENERATED, OnChunkGenerated);
PM:AddHook(cPluginManager.HOOK_PLUGINS_LOADED, OnPluginsLoaded); PM:AddHook(cPluginManager.HOOK_PLUGINS_LOADED, OnPluginsLoaded);
PM:AddHook(cPluginManager.HOOK_PLUGIN_MESSAGE, OnPluginMessage); PM:AddHook(cPluginManager.HOOK_PLUGIN_MESSAGE, OnPluginMessage);
PM:AddHook(cPluginManager.HOOK_PLAYER_JOINED, OnPlayerJoined)
PM:BindCommand("/le", "debuggers", HandleListEntitiesCmd, "- Shows a list of all the loaded entities"); PM:BindCommand("/le", "debuggers", HandleListEntitiesCmd, "- Shows a list of all the loaded entities");
PM:BindCommand("/ke", "debuggers", HandleKillEntitiesCmd, "- Kills all the loaded entities"); PM:BindCommand("/ke", "debuggers", HandleKillEntitiesCmd, "- Kills all the loaded entities");
@ -70,6 +71,8 @@ function Initialize(Plugin)
-- TestExpatBindings(); -- TestExpatBindings();
-- TestPluginCalls(); -- TestPluginCalls();
TestBlockAreasString()
return true return true
end; end;
@ -201,6 +204,42 @@ end
function TestBlockAreasString()
-- Write one area to string, then to file:
local BA1 = cBlockArea()
BA1:Create(5, 5, 5, cBlockArea.baTypes + cBlockArea.baMetas)
BA1:Fill(cBlockArea.baTypes, E_BLOCK_DIAMOND_BLOCK)
BA1:FillRelCuboid(1, 3, 1, 3, 1, 3, cBlockArea.baTypes, E_BLOCK_GOLD_BLOCK)
local Data = BA1:SaveToSchematicString()
if ((type(Data) ~= "string") or (Data == "")) then
LOG("Cannot save schematic to string")
return
end
cFile:CreateFolder("schematics")
local f = io.open("schematics/StringTest.schematic", "w")
f:write(Data)
f:close()
-- Load a second area from that file:
local BA2 = cBlockArea()
if not(BA2:LoadFromSchematicFile("schematics/StringTest.schematic")) then
LOG("Cannot read schematic from string test file")
return
end
BA2:Clear()
-- Load another area from a string in that file:
f = io.open("schematics/StringTest.schematic", "r")
Data = f:read("*all")
if not(BA2:LoadFromSchematicString(Data)) then
LOG("Cannot load schematic from string")
end
end
function TestSQLiteBindings() function TestSQLiteBindings()
LOG("Testing SQLite bindings..."); LOG("Testing SQLite bindings...");
@ -1258,3 +1297,17 @@ end
function OnPlayerJoined(a_Player)
-- Test composite chat chaining:
a_Player:SendMessage(cCompositeChat()
:AddTextPart("Hello, ")
:AddUrlPart(a_Player:GetName(), "www.mc-server.org", "u@2")
:AddSuggestCommandPart(", and welcome.", "/help", "u")
:AddRunCommandPart(" SetDay", "/time set 0")
)
end

View File

@ -317,26 +317,19 @@ local function WriteCommandsCategoryGithub(a_Category, f)
if (CategoryName == "") then if (CategoryName == "") then
CategoryName = "General"; CategoryName = "General";
end end
f:write("\n## ", GithubizeString(a_Category.DisplayName or CategoryName), "\n"); f:write("\n### ", GithubizeString(a_Category.DisplayName or CategoryName), "\n");
-- Write description: -- Write description:
if (a_Category.Description ~= "") then if (a_Category.Description ~= "") then
f:write(GithubizeString(a_Category.Description), "\n"); f:write(GithubizeString(a_Category.Description), "\n\n");
end end
f:write("| Command | Permission | Description | \n")
f:write("| ------- | ---------- | ----------- | \n")
-- Write commands: -- Write commands:
f:write("\n");
for idx2, cmd in ipairs(a_Category.Commands) do for idx2, cmd in ipairs(a_Category.Commands) do
f:write("\n### ", cmd.CommandString, "\n", GithubizeString(cmd.Info.HelpString or "UNDOCUMENTED"), "\n\n"); f:write("|", cmd.CommandString, " | ", cmd.Info.Permission or "", " | ", GithubizeString(cmd.Info.HelpString or "UNDOCUMENTED"), "| \n")
if (cmd.Info.Permission ~= nil) then
f:write("Permission required: **", cmd.Info.Permission, "**\n\n");
end
if (cmd.Info.DetailedDescription ~= nil) then
f:write(GithubizeString(cmd.Info.DetailedDescription));
end
if (cmd.Info.ParameterCombinations ~= nil) then
WriteCommandParameterCombinationsGithub(cmd.CommandString, cmd.Info.ParameterCombinations, f);
end
end end
f:write("\n\n") f:write("\n\n")
end end
@ -537,12 +530,13 @@ local function DumpPermissionsGithub(a_PluginInfo, f)
-- Dump the permissions: -- Dump the permissions:
f:write("\n# Permissions\n"); f:write("\n# Permissions\n");
f:write("| Permissions | Description | Commands | Recommended groups |\n")
f:write("| ----------- | ----------- | -------- | ------------------ |\n")
for idx, perm in ipairs(Permissions) do for idx, perm in ipairs(Permissions) do
f:write("### ", perm.Name, "\n"); f:write(perm.Name, " | ");
f:write(GithubizeString(perm.Info.Description or "")); f:write(GithubizeString(perm.Info.Description or ""), " | ");
local CommandsAffected = perm.Info.CommandsAffected or {}; local CommandsAffected = perm.Info.CommandsAffected or {};
if (#CommandsAffected > 0) then if (#CommandsAffected > 0) then
f:write("\n\nCommands affected:\n - ");
local Affects = {}; local Affects = {};
for idx2, cmd in ipairs(CommandsAffected) do for idx2, cmd in ipairs(CommandsAffected) do
if (type(cmd) == "string") then if (type(cmd) == "string") then
@ -551,11 +545,10 @@ local function DumpPermissionsGithub(a_PluginInfo, f)
table.insert(Affects, GetCommandRefGithub(cmd.Name, cmd)); table.insert(Affects, GetCommandRefGithub(cmd.Name, cmd));
end end
end end
f:write(table.concat(Affects, "\n - ")); f:write(table.concat(Affects, ", "), " | ");
f:write("\n");
end end
if (perm.Info.RecommendedGroups ~= nil) then if (perm.Info.RecommendedGroups ~= nil) then
f:write("\n\nRecommended groups: ", perm.Info.RecommendedGroups, "\n"); f:write(perm.Info.RecommendedGroups, " |");
end end
f:write("\n"); f:write("\n");
end end
@ -578,7 +571,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

@ -1,5 +1,3 @@
macro (add_flags_lnk FLAGS) macro (add_flags_lnk FLAGS)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAGS}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${FLAGS}") set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${FLAGS}")
@ -62,6 +60,7 @@ macro(set_flags)
# We use a signed char (fixes #640 on RasPi) # We use a signed char (fixes #640 on RasPi)
add_flags_cxx("-fsigned-char") add_flags_cxx("-fsigned-char")
endif() endif()
@ -184,6 +183,14 @@ macro(set_exe_flags)
string(REPLACE "-w" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") string(REPLACE "-w" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
string(REPLACE "-w" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") string(REPLACE "-w" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
add_flags_cxx("-Wall -Wextra") add_flags_cxx("-Wall -Wextra")
# we support non-IEEE 754 fpus so can make no guarentees about error
add_flags_cxx("-ffast-math")
# clang does not provide the __extern_always_inline macro and a part of libm depends on this when using fast-math
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_flags_cxx("-D__extern_always_inline=inline")
endif()
endif() endif()
endmacro() endmacro()

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()

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

View File

@ -26,6 +26,7 @@ $cfile "WebPlugin.h"
$cfile "LuaWindow.h" $cfile "LuaWindow.h"
$cfile "../BlockID.h" $cfile "../BlockID.h"
$cfile "../BlockInfo.h"
$cfile "../StringUtils.h" $cfile "../StringUtils.h"
$cfile "../Defines.h" $cfile "../Defines.h"
$cfile "../ChatColor.h" $cfile "../ChatColor.h"
@ -57,6 +58,8 @@ $cfile "../BlockEntities/HopperEntity.h"
$cfile "../BlockEntities/JukeboxEntity.h" $cfile "../BlockEntities/JukeboxEntity.h"
$cfile "../BlockEntities/NoteEntity.h" $cfile "../BlockEntities/NoteEntity.h"
$cfile "../BlockEntities/SignEntity.h" $cfile "../BlockEntities/SignEntity.h"
$cfile "../BlockEntities/MobHeadEntity.h"
$cfile "../BlockEntities/FlowerPotEntity.h"
$cfile "../WebAdmin.h" $cfile "../WebAdmin.h"
$cfile "../Root.h" $cfile "../Root.h"
$cfile "../Vector3f.h" $cfile "../Vector3f.h"
@ -75,6 +78,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

@ -0,0 +1,506 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "DeprecatedBindings.h"
#include "tolua++/include/tolua++.h"
#include "Plugin.h"
#include "PluginLua.h"
#include "PluginManager.h"
#include "LuaWindow.h"
#include "LuaChunkStay.h"
#include "../BlockInfo.h"
/* get function: g_BlockLightValue */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockLightValue
static int tolua_get_AllToLua_g_BlockLightValue(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
tolua_pushnumber(tolua_S,(lua_Number)cBlockInfo::GetLightValue(tolua_index));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* set function: g_BlockLightValue */
#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockLightValue
static int tolua_set_AllToLua_g_BlockLightValue(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
cBlockInfo::Get(tolua_index).m_LightValue = ((unsigned char) tolua_tonumber(tolua_S,3,0));
return 0;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: g_BlockSpreadLightFalloff */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockSpreadLightFalloff
static int tolua_get_AllToLua_g_BlockSpreadLightFalloff(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
tolua_pushnumber(tolua_S,(lua_Number)cBlockInfo::GetSpreadLightFalloff(tolua_index));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* set function: g_BlockSpreadLightFalloff */
#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockSpreadLightFalloff
static int tolua_set_AllToLua_g_BlockSpreadLightFalloff(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
cBlockInfo::Get(tolua_index).m_SpreadLightFalloff = ((unsigned char) tolua_tonumber(tolua_S,3,0));
return 0;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: g_BlockTransparent */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockTransparent
static int tolua_get_AllToLua_g_BlockTransparent(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
tolua_pushboolean(tolua_S, cBlockInfo::IsTransparent(tolua_index));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* set function: g_BlockTransparent */
#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockTransparent
static int tolua_set_AllToLua_g_BlockTransparent(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
cBlockInfo::Get(tolua_index).m_Transparent = (tolua_toboolean(tolua_S,3,0) != 0);
return 0;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: g_BlockOneHitDig */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockOneHitDig
static int tolua_get_AllToLua_g_BlockOneHitDig(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
tolua_pushboolean(tolua_S,(bool)cBlockInfo::IsOneHitDig(tolua_index));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* set function: g_BlockOneHitDig */
#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockOneHitDig
static int tolua_set_AllToLua_g_BlockOneHitDig(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
cBlockInfo::Get(tolua_index).m_OneHitDig = (tolua_toboolean(tolua_S,3,0) != 0);
return 0;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: g_BlockPistonBreakable */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockPistonBreakable
static int tolua_get_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0 || tolua_index>=256)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
tolua_pushboolean(tolua_S,(bool)cBlockInfo::IsPistonBreakable(tolua_index));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* set function: g_BlockPistonBreakable */
#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockPistonBreakable
static int tolua_set_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0 || tolua_index>=256)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
cBlockInfo::Get(tolua_index).m_PistonBreakable = (tolua_toboolean(tolua_S,3,0) != 0);
return 0;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: g_BlockIsSnowable */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockIsSnowable
static int tolua_get_AllToLua_g_BlockIsSnowable(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0 || tolua_index>=256)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
tolua_pushboolean(tolua_S,(bool)cBlockInfo::IsSnowable(tolua_index));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* set function: g_BlockIsSnowable */
#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockIsSnowable
static int tolua_set_AllToLua_g_BlockIsSnowable(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0 || tolua_index>=256)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
cBlockInfo::Get(tolua_index).m_IsSnowable = (tolua_toboolean(tolua_S,3,0) != 0);
return 0;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: g_BlockRequiresSpecialTool */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockRequiresSpecialTool
static int tolua_get_AllToLua_g_BlockRequiresSpecialTool(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0 || tolua_index>=256)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
tolua_pushboolean(tolua_S,(bool)cBlockInfo::RequiresSpecialTool(tolua_index));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* set function: g_BlockRequiresSpecialTool */
#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockRequiresSpecialTool
static int tolua_set_AllToLua_g_BlockRequiresSpecialTool(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0 || tolua_index>=256)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
cBlockInfo::Get(tolua_index).m_RequiresSpecialTool = (tolua_toboolean(tolua_S,3,0) != 0);
return 0;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: g_BlockIsSolid */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockIsSolid
static int tolua_get_AllToLua_g_BlockIsSolid(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0 || tolua_index>=256)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
tolua_pushboolean(tolua_S,(bool)cBlockInfo::IsSolid(tolua_index));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* set function: g_BlockIsSolid */
#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockIsSolid
static int tolua_set_AllToLua_g_BlockIsSolid(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0 || tolua_index>=256)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
cBlockInfo::Get(tolua_index).m_IsSolid = (tolua_toboolean(tolua_S,3,0) != 0);
return 0;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: g_BlockFullyOccupiesVoxel */
#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockFullyOccupiesVoxel
static int tolua_get_AllToLua_g_BlockFullyOccupiesVoxel(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0 || tolua_index>=256)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
tolua_pushboolean(tolua_S,(bool)cBlockInfo::FullyOccupiesVoxel(tolua_index));
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* set function: g_BlockFullyOccupiesVoxel */
#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockFullyOccupiesVoxel
static int tolua_set_AllToLua_g_BlockFullyOccupiesVoxel(lua_State* tolua_S)
{
int tolua_index;
#ifndef TOLUA_RELEASE
{
tolua_Error tolua_err;
if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
}
#endif
tolua_index = (int)tolua_tonumber(tolua_S,2,0);
#ifndef TOLUA_RELEASE
if (tolua_index<0 || tolua_index>=256)
tolua_error(tolua_S,"array indexing out of range.",NULL);
#endif
cBlockInfo::Get(tolua_index).m_FullyOccupiesVoxel = (tolua_toboolean(tolua_S,3,0) != 0);
return 0;
}
#endif //#ifndef TOLUA_DISABLE
void DeprecatedBindings::Bind(lua_State * tolua_S)
{
tolua_beginmodule(tolua_S, NULL);
tolua_array(tolua_S, "g_BlockLightValue", tolua_get_AllToLua_g_BlockLightValue, tolua_set_AllToLua_g_BlockLightValue);
tolua_array(tolua_S, "g_BlockSpreadLightFalloff", tolua_get_AllToLua_g_BlockSpreadLightFalloff, tolua_set_AllToLua_g_BlockSpreadLightFalloff);
tolua_array(tolua_S, "g_BlockTransparent", tolua_get_AllToLua_g_BlockTransparent, tolua_set_AllToLua_g_BlockTransparent);
tolua_array(tolua_S, "g_BlockOneHitDig", tolua_get_AllToLua_g_BlockOneHitDig, tolua_set_AllToLua_g_BlockOneHitDig);
tolua_array(tolua_S, "g_BlockPistonBreakable", tolua_get_AllToLua_g_BlockPistonBreakable, tolua_set_AllToLua_g_BlockPistonBreakable);
tolua_array(tolua_S, "g_BlockIsSnowable", tolua_get_AllToLua_g_BlockIsSnowable, tolua_set_AllToLua_g_BlockIsSnowable);
tolua_array(tolua_S, "g_BlockRequiresSpecialTool", tolua_get_AllToLua_g_BlockRequiresSpecialTool, tolua_set_AllToLua_g_BlockRequiresSpecialTool);
tolua_array(tolua_S, "g_BlockIsSolid", tolua_get_AllToLua_g_BlockIsSolid, tolua_set_AllToLua_g_BlockIsSolid);
tolua_array(tolua_S, "g_BlockFullyOccupiesVoxel", tolua_get_AllToLua_g_BlockFullyOccupiesVoxel, tolua_set_AllToLua_g_BlockFullyOccupiesVoxel);
tolua_endmodule(tolua_S);
}

View File

@ -0,0 +1,8 @@
#pragma once
struct lua_State;
class DeprecatedBindings
{
public:
static void Bind( lua_State* tolua_S );
};

View File

@ -14,6 +14,7 @@ extern "C"
#include "tolua++/include/tolua++.h" #include "tolua++/include/tolua++.h"
#include "Bindings.h" #include "Bindings.h"
#include "ManualBindings.h" #include "ManualBindings.h"
#include "DeprecatedBindings.h"
// fwd: SQLite/lsqlite3.c // fwd: SQLite/lsqlite3.c
extern "C" extern "C"
@ -95,6 +96,7 @@ void cLuaState::Create(void)
luaL_openlibs(m_LuaState); luaL_openlibs(m_LuaState);
tolua_AllToLua_open(m_LuaState); tolua_AllToLua_open(m_LuaState);
ManualBindings::Bind(m_LuaState); ManualBindings::Bind(m_LuaState);
DeprecatedBindings::Bind(m_LuaState);
luaopen_lsqlite3(m_LuaState); luaopen_lsqlite3(m_LuaState);
luaopen_lxp(m_LuaState); luaopen_lxp(m_LuaState);
m_IsOwned = true; m_IsOwned = true;
@ -714,7 +716,7 @@ void cLuaState::Push(cBlockEntity * a_BlockEntity)
void cLuaState::GetReturn(int a_StackPos, bool & a_ReturnedVal) void cLuaState::GetStackValue(int a_StackPos, bool & a_ReturnedVal)
{ {
a_ReturnedVal = (tolua_toboolean(m_LuaState, a_StackPos, a_ReturnedVal ? 1 : 0) > 0); a_ReturnedVal = (tolua_toboolean(m_LuaState, a_StackPos, a_ReturnedVal ? 1 : 0) > 0);
} }
@ -723,11 +725,17 @@ void cLuaState::GetReturn(int a_StackPos, bool & a_ReturnedVal)
void cLuaState::GetReturn(int a_StackPos, AString & a_ReturnedVal) void cLuaState::GetStackValue(int a_StackPos, AString & a_Value)
{ {
if (lua_isstring(m_LuaState, a_StackPos)) size_t len = 0;
const char * data = lua_tolstring(m_LuaState, a_StackPos, &len);
if (data != NULL)
{ {
a_ReturnedVal = tolua_tocppstring(m_LuaState, a_StackPos, a_ReturnedVal.c_str()); a_Value.assign(data, len);
}
else
{
a_Value.clear();
} }
} }
@ -735,7 +743,7 @@ void cLuaState::GetReturn(int a_StackPos, AString & a_ReturnedVal)
void cLuaState::GetReturn(int a_StackPos, int & a_ReturnedVal) void cLuaState::GetStackValue(int a_StackPos, int & a_ReturnedVal)
{ {
if (lua_isnumber(m_LuaState, a_StackPos)) if (lua_isnumber(m_LuaState, a_StackPos))
{ {
@ -747,7 +755,7 @@ void cLuaState::GetReturn(int a_StackPos, int & a_ReturnedVal)
void cLuaState::GetReturn(int a_StackPos, double & a_ReturnedVal) void cLuaState::GetStackValue(int a_StackPos, double & a_ReturnedVal)
{ {
if (lua_isnumber(m_LuaState, a_StackPos)) if (lua_isnumber(m_LuaState, a_StackPos))
{ {

View File

@ -197,6 +197,19 @@ public:
void Push(void * a_Ptr); void Push(void * a_Ptr);
void Push(cHopperEntity * a_Hopper); void Push(cHopperEntity * a_Hopper);
void Push(cBlockEntity * a_BlockEntity); void Push(cBlockEntity * a_BlockEntity);
/** Retrieve value at a_StackPos, if it is a valid bool. If not, a_Value is unchanged */
void GetStackValue(int a_StackPos, bool & a_Value);
/** Retrieve value at a_StackPos, if it is a valid string. If not, a_Value is unchanged */
void GetStackValue(int a_StackPos, AString & a_Value);
/** Retrieve value at a_StackPos, if it is a valid number. If not, a_Value is unchanged */
void GetStackValue(int a_StackPos, int & a_Value);
/** Retrieve value at a_StackPos, if it is a valid number. If not, a_Value is unchanged */
void GetStackValue(int a_StackPos, double & a_Value);
/** Call any 0-param 0-return Lua function in a single line: */ /** Call any 0-param 0-return Lua function in a single line: */
template <typename FnT> template <typename FnT>
@ -270,7 +283,7 @@ public:
{ {
return false; return false;
} }
GetReturn(-1, a_Ret1); GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1); lua_pop(m_LuaState, 1);
return true; return true;
} }
@ -292,7 +305,7 @@ public:
{ {
return false; return false;
} }
GetReturn(-1, a_Ret1); GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1); lua_pop(m_LuaState, 1);
ASSERT(InitialTop == lua_gettop(m_LuaState)); ASSERT(InitialTop == lua_gettop(m_LuaState));
return true; return true;
@ -315,7 +328,7 @@ public:
{ {
return false; return false;
} }
GetReturn(-1, a_Ret1); GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1); lua_pop(m_LuaState, 1);
return true; return true;
} }
@ -338,7 +351,7 @@ public:
{ {
return false; return false;
} }
GetReturn(-1, a_Ret1); GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1); lua_pop(m_LuaState, 1);
return true; return true;
} }
@ -362,7 +375,7 @@ public:
{ {
return false; return false;
} }
GetReturn(-1, a_Ret1); GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1); lua_pop(m_LuaState, 1);
return true; return true;
} }
@ -387,7 +400,7 @@ public:
{ {
return false; return false;
} }
GetReturn(-1, a_Ret1); GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1); lua_pop(m_LuaState, 1);
return true; return true;
} }
@ -414,7 +427,7 @@ public:
{ {
return false; return false;
} }
GetReturn(-1, a_Ret1); GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1); lua_pop(m_LuaState, 1);
return true; return true;
} }
@ -442,7 +455,7 @@ public:
{ {
return false; return false;
} }
GetReturn(-1, a_Ret1); GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1); lua_pop(m_LuaState, 1);
return true; return true;
} }
@ -471,7 +484,7 @@ public:
{ {
return false; return false;
} }
GetReturn(-1, a_Ret1); GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1); lua_pop(m_LuaState, 1);
return true; return true;
} }
@ -501,7 +514,7 @@ public:
{ {
return false; return false;
} }
GetReturn(-1, a_Ret1); GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1); lua_pop(m_LuaState, 1);
return true; return true;
} }
@ -532,7 +545,7 @@ public:
{ {
return false; return false;
} }
GetReturn(-1, a_Ret1); GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1); lua_pop(m_LuaState, 1);
return true; return true;
} }
@ -553,8 +566,8 @@ public:
{ {
return false; return false;
} }
GetReturn(-2, a_Ret1); GetStackValue(-2, a_Ret1);
GetReturn(-1, a_Ret2); GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2); lua_pop(m_LuaState, 2);
return true; return true;
} }
@ -576,8 +589,8 @@ public:
{ {
return false; return false;
} }
GetReturn(-2, a_Ret1); GetStackValue(-2, a_Ret1);
GetReturn(-1, a_Ret2); GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2); lua_pop(m_LuaState, 2);
return true; return true;
} }
@ -601,8 +614,8 @@ public:
{ {
return false; return false;
} }
GetReturn(-2, a_Ret1); GetStackValue(-2, a_Ret1);
GetReturn(-1, a_Ret2); GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2); lua_pop(m_LuaState, 2);
return true; return true;
} }
@ -627,8 +640,8 @@ public:
{ {
return false; return false;
} }
GetReturn(-2, a_Ret1); GetStackValue(-2, a_Ret1);
GetReturn(-1, a_Ret2); GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2); lua_pop(m_LuaState, 2);
return true; return true;
} }
@ -654,8 +667,8 @@ public:
{ {
return false; return false;
} }
GetReturn(-2, a_Ret1); GetStackValue(-2, a_Ret1);
GetReturn(-1, a_Ret2); GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2); lua_pop(m_LuaState, 2);
return true; return true;
} }
@ -683,8 +696,8 @@ public:
{ {
return false; return false;
} }
GetReturn(-2, a_Ret1); GetStackValue(-2, a_Ret1);
GetReturn(-1, a_Ret2); GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2); lua_pop(m_LuaState, 2);
return true; return true;
} }
@ -713,8 +726,8 @@ public:
{ {
return false; return false;
} }
GetReturn(-2, a_Ret1); GetStackValue(-2, a_Ret1);
GetReturn(-1, a_Ret2); GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2); lua_pop(m_LuaState, 2);
return true; return true;
} }
@ -743,9 +756,9 @@ public:
{ {
return false; return false;
} }
GetReturn(-3, a_Ret1); GetStackValue(-3, a_Ret1);
GetReturn(-2, a_Ret2); GetStackValue(-2, a_Ret2);
GetReturn(-1, a_Ret3); GetStackValue(-1, a_Ret3);
lua_pop(m_LuaState, 3); lua_pop(m_LuaState, 3);
return true; return true;
} }
@ -775,9 +788,9 @@ public:
{ {
return false; return false;
} }
GetReturn(-3, a_Ret1); GetStackValue(-3, a_Ret1);
GetReturn(-2, a_Ret2); GetStackValue(-2, a_Ret2);
GetReturn(-1, a_Ret3); GetStackValue(-1, a_Ret3);
lua_pop(m_LuaState, 3); lua_pop(m_LuaState, 3);
return true; return true;
} }
@ -808,11 +821,11 @@ public:
{ {
return false; return false;
} }
GetReturn(-5, a_Ret1); GetStackValue(-5, a_Ret1);
GetReturn(-4, a_Ret2); GetStackValue(-4, a_Ret2);
GetReturn(-3, a_Ret3); GetStackValue(-3, a_Ret3);
GetReturn(-2, a_Ret4); GetStackValue(-2, a_Ret4);
GetReturn(-1, a_Ret5); GetStackValue(-1, a_Ret5);
lua_pop(m_LuaState, 5); lua_pop(m_LuaState, 5);
return true; return true;
} }
@ -918,18 +931,6 @@ protected:
/** Pushes a usertype of the specified class type onto the stack */ /** Pushes a usertype of the specified class type onto the stack */
void PushUserType(void * a_Object, const char * a_Type); void PushUserType(void * a_Object, const char * a_Type);
/** Retrieve value returned at a_StackPos, if it is a valid bool. If not, a_ReturnedVal is unchanged */
void GetReturn(int a_StackPos, bool & a_ReturnedVal);
/** Retrieve value returned at a_StackPos, if it is a valid string. If not, a_ReturnedVal is unchanged */
void GetReturn(int a_StackPos, AString & a_ReturnedVal);
/** Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged */
void GetReturn(int a_StackPos, int & a_ReturnedVal);
/** Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged */
void GetReturn(int a_StackPos, double & a_ReturnedVal);
/** /**
Calls the function that has been pushed onto the stack by PushFunction(), Calls the function that has been pushed onto the stack by PushFunction(),
with arguments pushed by PushXXX(). with arguments pushed by PushXXX().

View File

@ -23,9 +23,11 @@
#include "../BlockEntities/HopperEntity.h" #include "../BlockEntities/HopperEntity.h"
#include "../BlockEntities/NoteEntity.h" #include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/FlowerPotEntity.h"
#include "md5/md5.h" #include "md5/md5.h"
#include "../LineBlockTracer.h" #include "../LineBlockTracer.h"
#include "../WorldStorage/SchematicFileSerializer.h" #include "../WorldStorage/SchematicFileSerializer.h"
#include "../CompositeChat.h"
@ -2455,7 +2457,7 @@ static int tolua_cBlockArea_GetSize(lua_State * tolua_S)
static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S) static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S)
{ {
// function cBlockArea::LoadFromSchematicFile // function cBlockArea::LoadFromSchematicFile
// Exported manually because function has been moved to SchematicFileSerilizer.cpp // Exported manually because function has been moved to SchematicFileSerializer.cpp
cLuaState L(tolua_S); cLuaState L(tolua_S);
if ( if (
!L.CheckParamUserType(1, "cBlockArea") || !L.CheckParamUserType(1, "cBlockArea") ||
@ -2482,10 +2484,41 @@ static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S)
static int tolua_cBlockArea_LoadFromSchematicString(lua_State * tolua_S)
{
// function cBlockArea::LoadFromSchematicString
// Exported manually because function has been moved to SchematicFileSerializer.cpp
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cBlockArea") ||
!L.CheckParamString (2) ||
!L.CheckParamEnd (3)
)
{
return 0;
}
cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::LoadFromSchematicFile'", NULL);
return 0;
}
AString Data;
L.GetStackValue(2, Data);
bool res = cSchematicFileSerializer::LoadFromSchematicString(*self, Data);
tolua_pushboolean(tolua_S, res);
return 1;
}
static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S) static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S)
{ {
// function cBlockArea::SaveToSchematicFile // function cBlockArea::SaveToSchematicFile
// Exported manually because function has been moved to SchematicFileSerilizer.cpp // Exported manually because function has been moved to SchematicFileSerializer.cpp
cLuaState L(tolua_S); cLuaState L(tolua_S);
if ( if (
!L.CheckParamUserType(1, "cBlockArea") || !L.CheckParamUserType(1, "cBlockArea") ||
@ -2511,6 +2544,285 @@ static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S)
static int tolua_cBlockArea_SaveToSchematicString(lua_State * tolua_S)
{
// function cBlockArea::SaveToSchematicString
// Exported manually because function has been moved to SchematicFileSerializer.cpp
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cBlockArea") ||
!L.CheckParamEnd (2)
)
{
return 0;
}
cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::SaveToSchematicFile'", NULL);
return 0;
}
AString Data;
if (cSchematicFileSerializer::SaveToSchematicString(*self, Data))
{
L.Push(Data);
return 1;
}
return 0;
}
static int tolua_cCompositeChat_AddRunCommandPart(lua_State * tolua_S)
{
// function cCompositeChat:AddRunCommandPart(Message, Command, [Style])
// Exported manually to support call-chaining (return *this)
// Check params:
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cCompositeChat") ||
!L.CheckParamString(2, 3)
)
{
return 0;
}
cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddRunCommandPart'", NULL);
return 0;
}
// Add the part:
AString Text, Command, Style;
L.GetStackValue(2, Text);
L.GetStackValue(3, Command);
L.GetStackValue(4, Style);
self->AddRunCommandPart(Text, Command, Style);
// Cut away everything from the stack except for the cCompositeChat instance; return that:
lua_settop(L, 1);
return 1;
}
static int tolua_cCompositeChat_AddSuggestCommandPart(lua_State * tolua_S)
{
// function cCompositeChat:AddSuggestCommandPart(Message, Command, [Style])
// Exported manually to support call-chaining (return *this)
// Check params:
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cCompositeChat") ||
!L.CheckParamString(2, 3)
)
{
return 0;
}
cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddSuggestCommandPart'", NULL);
return 0;
}
// Add the part:
AString Text, Command, Style;
L.GetStackValue(2, Text);
L.GetStackValue(3, Command);
L.GetStackValue(4, Style);
self->AddSuggestCommandPart(Text, Command, Style);
// Cut away everything from the stack except for the cCompositeChat instance; return that:
lua_settop(L, 1);
return 1;
}
static int tolua_cCompositeChat_AddTextPart(lua_State * tolua_S)
{
// function cCompositeChat:AddTextPart(Message, [Style])
// Exported manually to support call-chaining (return *this)
// Check params:
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cCompositeChat") ||
!L.CheckParamString(2)
)
{
return 0;
}
cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddTextPart'", NULL);
return 0;
}
// Add the part:
AString Text, Style;
L.GetStackValue(2, Text);
L.GetStackValue(3, Style);
self->AddTextPart(Text, Style);
// Cut away everything from the stack except for the cCompositeChat instance; return that:
lua_settop(L, 1);
return 1;
}
static int tolua_cCompositeChat_AddUrlPart(lua_State * tolua_S)
{
// function cCompositeChat:AddTextPart(Message, Url, [Style])
// Exported manually to support call-chaining (return *this)
// Check params:
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cCompositeChat") ||
!L.CheckParamString(2, 3)
)
{
return 0;
}
cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddUrlPart'", NULL);
return 0;
}
// Add the part:
AString Text, Url, Style;
L.GetStackValue(2, Text);
L.GetStackValue(3, Url);
L.GetStackValue(4, Style);
self->AddUrlPart(Text, Url, Style);
// Cut away everything from the stack except for the cCompositeChat instance; return that:
lua_settop(L, 1);
return 1;
}
static int tolua_cCompositeChat_ParseText(lua_State * tolua_S)
{
// function cCompositeChat:ParseText(TextMessage)
// Exported manually to support call-chaining (return *this)
// Check params:
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cCompositeChat") ||
!L.CheckParamString(2)
)
{
return 0;
}
cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:ParseText'", NULL);
return 0;
}
// Parse the text:
AString Text;
L.GetStackValue(2, Text);
self->ParseText(Text);
// Cut away everything from the stack except for the cCompositeChat instance; return that:
lua_settop(L, 1);
return 1;
}
static int tolua_cCompositeChat_SetMessageType(lua_State * tolua_S)
{
// function cCompositeChat:SetMessageType(MessageType)
// Exported manually to support call-chaining (return *this)
// Check params:
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cCompositeChat") ||
!L.CheckParamNumber(2)
)
{
return 0;
}
cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:SetMessageType'", NULL);
return 0;
}
// Set the type:
int MessageType;
L.GetStackValue(1, MessageType);
self->SetMessageType((eMessageType)MessageType);
// Cut away everything from the stack except for the cCompositeChat instance; return that:
lua_settop(L, 1);
return 1;
}
static int tolua_cCompositeChat_UnderlineUrls(lua_State * tolua_S)
{
// function cCompositeChat:UnderlineUrls()
// Exported manually to support call-chaining (return *this)
// Check params:
cLuaState L(tolua_S);
if (!L.CheckParamUserType(1, "cCompositeChat"))
{
return 0;
}
cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
if (self == NULL)
{
tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:UnderlineUrls'", NULL);
return 0;
}
// Call the processing
self->UnderlineUrls();
// Cut away everything from the stack except for the cCompositeChat instance; return that:
lua_settop(L, 1);
return 1;
}
void ManualBindings::Bind(lua_State * tolua_S) void ManualBindings::Bind(lua_State * tolua_S)
{ {
tolua_beginmodule(tolua_S, NULL); tolua_beginmodule(tolua_S, NULL);
@ -2527,12 +2839,24 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_endmodule(tolua_S); tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cBlockArea"); tolua_beginmodule(tolua_S, "cBlockArea");
tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cBlockArea_GetBlockTypeMeta); tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cBlockArea_GetBlockTypeMeta);
tolua_function(tolua_S, "GetOrigin", tolua_cBlockArea_GetOrigin); tolua_function(tolua_S, "GetOrigin", tolua_cBlockArea_GetOrigin);
tolua_function(tolua_S, "GetRelBlockTypeMeta", tolua_cBlockArea_GetRelBlockTypeMeta); tolua_function(tolua_S, "GetRelBlockTypeMeta", tolua_cBlockArea_GetRelBlockTypeMeta);
tolua_function(tolua_S, "GetSize", tolua_cBlockArea_GetSize); tolua_function(tolua_S, "GetSize", tolua_cBlockArea_GetSize);
tolua_function(tolua_S, "LoadFromSchematicFile", tolua_cBlockArea_LoadFromSchematicFile); tolua_function(tolua_S, "LoadFromSchematicFile", tolua_cBlockArea_LoadFromSchematicFile);
tolua_function(tolua_S, "SaveToSchematicFile", tolua_cBlockArea_SaveToSchematicFile); tolua_function(tolua_S, "LoadFromSchematicString", tolua_cBlockArea_LoadFromSchematicString);
tolua_function(tolua_S, "SaveToSchematicFile", tolua_cBlockArea_SaveToSchematicFile);
tolua_function(tolua_S, "SaveToSchematicString", tolua_cBlockArea_SaveToSchematicString);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cCompositeChat");
tolua_function(tolua_S, "AddRunCommandPart", tolua_cCompositeChat_AddRunCommandPart);
tolua_function(tolua_S, "AddSuggestCommandPart", tolua_cCompositeChat_AddSuggestCommandPart);
tolua_function(tolua_S, "AddTextPart", tolua_cCompositeChat_AddTextPart);
tolua_function(tolua_S, "AddUrlPart", tolua_cCompositeChat_AddUrlPart);
tolua_function(tolua_S, "ParseText", tolua_cCompositeChat_ParseText);
tolua_function(tolua_S, "SetMessageType", tolua_cCompositeChat_SetMessageType);
tolua_function(tolua_S, "UnderlineUrls", tolua_cCompositeChat_UnderlineUrls);
tolua_endmodule(tolua_S); tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cHopperEntity"); tolua_beginmodule(tolua_S, "cHopperEntity");
@ -2561,7 +2885,8 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>); tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>);
tolua_function(tolua_S, "DoWithNoteBlockAt", tolua_DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>); tolua_function(tolua_S, "DoWithNoteBlockAt", tolua_DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>);
tolua_function(tolua_S, "DoWithCommandBlockAt", tolua_DoWithXYZ<cWorld, cCommandBlockEntity, &cWorld::DoWithCommandBlockAt>); tolua_function(tolua_S, "DoWithCommandBlockAt", tolua_DoWithXYZ<cWorld, cCommandBlockEntity, &cWorld::DoWithCommandBlockAt>);
tolua_function(tolua_S, "DoWithMobHeadBlockAt", tolua_DoWithXYZ<cWorld, cMobHeadEntity, &cWorld::DoWithMobHeadBlockAt>); tolua_function(tolua_S, "DoWithMobHeadAt", tolua_DoWithXYZ<cWorld, cMobHeadEntity, &cWorld::DoWithMobHeadAt>);
tolua_function(tolua_S, "DoWithFlowerPotAt", tolua_DoWithXYZ<cWorld, cFlowerPotEntity, &cWorld::DoWithFlowerPotAt>);
tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>); tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>);
tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>);
tolua_function(tolua_S, "ForEachBlockEntityInChunk", tolua_ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>); tolua_function(tolua_S, "ForEachBlockEntityInChunk", tolua_ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>);
@ -2583,6 +2908,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

@ -10,6 +10,7 @@
#include "DispenserEntity.h" #include "DispenserEntity.h"
#include "DropperEntity.h" #include "DropperEntity.h"
#include "EnderChestEntity.h" #include "EnderChestEntity.h"
#include "FlowerPotEntity.h"
#include "FurnaceEntity.h" #include "FurnaceEntity.h"
#include "HopperEntity.h" #include "HopperEntity.h"
#include "JukeboxEntity.h" #include "JukeboxEntity.h"
@ -30,6 +31,7 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_FLOWER_POT: return new cFlowerPotEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);

View File

@ -0,0 +1,134 @@
// FlowerPotEntity.cpp
// Implements the cFlowerPotEntity class representing a single sign in the world
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "json/json.h"
#include "FlowerPotEntity.h"
#include "../Entities/Player.h"
#include "../Item.h"
cFlowerPotEntity::cFlowerPotEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
super(E_BLOCK_FLOWER_POT, a_BlockX, a_BlockY, a_BlockZ, a_World)
{
}
// It don't do anything when 'used'
void cFlowerPotEntity::UsedBy(cPlayer * a_Player)
{
if (IsItemInPot())
{
return;
}
cItem SelectedItem = a_Player->GetInventory().GetEquippedItem();
if (IsFlower(SelectedItem.m_ItemType, SelectedItem.m_ItemDamage))
{
m_Item = SelectedItem.CopyOne();
if (!a_Player->IsGameModeCreative())
{
a_Player->GetInventory().RemoveOneEquippedItem();
}
m_World->BroadcastBlockEntity(m_PosX, m_PosY, m_PosZ, a_Player->GetClientHandle());
}
}
void cFlowerPotEntity::SendTo(cClientHandle & a_Client)
{
a_Client.SendUpdateBlockEntity(*this);
}
void cFlowerPotEntity::Destroy(void)
{
// Drop the contents as pickups:
if (!m_Item.IsEmpty())
{
ASSERT(m_World != NULL);
cItems Pickups;
Pickups.Add(m_Item);
m_World->SpawnItemPickups(Pickups, m_PosX + 0.5, m_PosY + 0.5, m_PosZ + 0.5);
m_Item.Empty();
}
}
bool cFlowerPotEntity::LoadFromJson(const Json::Value & a_Value)
{
m_PosX = a_Value.get("x", 0).asInt();
m_PosY = a_Value.get("y", 0).asInt();
m_PosZ = a_Value.get("z", 0).asInt();
m_Item = cItem();
m_Item.FromJson(a_Value.get("Item", 0));
return true;
}
void cFlowerPotEntity::SaveToJson(Json::Value & a_Value)
{
a_Value["x"] = m_PosX;
a_Value["y"] = m_PosY;
a_Value["z"] = m_PosZ;
Json::Value Item;
m_Item.GetJson(Item);
a_Value["Item"] = Item;
}
bool cFlowerPotEntity::IsFlower(short m_ItemType, short m_ItemData)
{
switch (m_ItemType)
{
case E_BLOCK_DANDELION:
case E_BLOCK_FLOWER:
case E_BLOCK_CACTUS:
case E_BLOCK_BROWN_MUSHROOM:
case E_BLOCK_RED_MUSHROOM:
case E_BLOCK_SAPLING:
case E_BLOCK_DEAD_BUSH:
{
return true;
}
case E_BLOCK_TALL_GRASS:
{
return (m_ItemData == (short) 2);
}
default:
{
return false;
}
}
}

View File

@ -0,0 +1,74 @@
// FlowerPotEntity.h
// Declares the cFlowerPotEntity class representing a single sign in the world
#pragma once
#include "BlockEntity.h"
class cItem;
namespace Json
{
class Value;
}
// tolua_begin
class cFlowerPotEntity :
public cBlockEntity
{
typedef cBlockEntity super;
public:
// tolua_end
/** Creates a new flowerpot entity at the specified block coords. a_World may be NULL */
cFlowerPotEntity(int a_BlocX, int a_BlockY, int a_BlockZ, cWorld * a_World);
bool LoadFromJson( const Json::Value& a_Value );
virtual void SaveToJson(Json::Value& a_Value ) override;
virtual void Destroy(void) override;
// tolua_begin
/** Is a flower in the pot? */
bool IsItemInPot(void) { return !m_Item.IsEmpty(); }
/** Get the item in the flower pot */
cItem GetItem(void) const { return m_Item; }
/** Set the item in the flower pot */
void SetItem(const cItem a_Item) { m_Item = a_Item; }
// tolua_end
virtual void UsedBy(cPlayer * a_Player) override;
virtual void SendTo(cClientHandle & a_Client) override;
static bool IsFlower(short m_ItemType, short m_ItemData);
static const char * GetClassStatic(void) { return "cFlowerPotEntity"; }
private:
cItem m_Item;
} ; // tolua_export

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

@ -12,20 +12,6 @@
NIBBLETYPE g_BlockLightValue[256];
NIBBLETYPE g_BlockSpreadLightFalloff[256];
bool g_BlockTransparent[256];
bool g_BlockOneHitDig[256];
bool g_BlockPistonBreakable[256];
bool g_BlockIsSnowable[256];
bool g_BlockRequiresSpecialTool[256];
bool g_BlockIsSolid[256];
bool g_BlockFullyOccupiesVoxel[256];
class cBlockIDMap class cBlockIDMap
{ {
// Making the map case-insensitive: // Making the map case-insensitive:
@ -481,389 +467,4 @@ cItem GetIniItemSet(cIniFile & a_IniFile, const char * a_Section, const char * a
// This is actually just some code that needs to run at program startup, so it is wrapped into a global var's constructor:
class cBlockPropertiesInitializer
{
public:
cBlockPropertiesInitializer(void)
{
memset(g_BlockLightValue, 0x00, sizeof(g_BlockLightValue));
memset(g_BlockSpreadLightFalloff, 0x0f, sizeof(g_BlockSpreadLightFalloff)); // 0x0f means total falloff
memset(g_BlockTransparent, 0x00, sizeof(g_BlockTransparent));
memset(g_BlockOneHitDig, 0x00, sizeof(g_BlockOneHitDig));
memset(g_BlockPistonBreakable, 0x00, sizeof(g_BlockPistonBreakable));
memset(g_BlockFullyOccupiesVoxel, 0x00, sizeof(g_BlockFullyOccupiesVoxel));
// Setting bools to true must be done manually, see http://forum.mc-server.org/showthread.php?tid=629&pid=5415#pid5415
for (size_t i = 0; i < ARRAYCOUNT(g_BlockIsSnowable); i++)
{
g_BlockIsSnowable[i] = true;
}
memset(g_BlockRequiresSpecialTool, 0x00, sizeof(g_BlockRequiresSpecialTool)); // Set all blocks to false
// Setting bools to true must be done manually, see http://forum.mc-server.org/showthread.php?tid=629&pid=5415#pid5415
for (size_t i = 0; i < ARRAYCOUNT(g_BlockIsSolid); i++)
{
g_BlockIsSolid[i] = true;
}
// Emissive blocks
g_BlockLightValue[E_BLOCK_FIRE] = 15;
g_BlockLightValue[E_BLOCK_GLOWSTONE] = 15;
g_BlockLightValue[E_BLOCK_JACK_O_LANTERN] = 15;
g_BlockLightValue[E_BLOCK_LAVA] = 15;
g_BlockLightValue[E_BLOCK_STATIONARY_LAVA] = 15;
g_BlockLightValue[E_BLOCK_END_PORTAL] = 15;
g_BlockLightValue[E_BLOCK_REDSTONE_LAMP_ON] = 15;
g_BlockLightValue[E_BLOCK_TORCH] = 14;
g_BlockLightValue[E_BLOCK_BURNING_FURNACE] = 13;
g_BlockLightValue[E_BLOCK_NETHER_PORTAL] = 11;
g_BlockLightValue[E_BLOCK_REDSTONE_ORE_GLOWING] = 9;
g_BlockLightValue[E_BLOCK_REDSTONE_REPEATER_ON] = 9;
g_BlockLightValue[E_BLOCK_REDSTONE_TORCH_ON] = 7;
g_BlockLightValue[E_BLOCK_BREWING_STAND] = 1;
g_BlockLightValue[E_BLOCK_BROWN_MUSHROOM] = 1;
g_BlockLightValue[E_BLOCK_DRAGON_EGG] = 1;
// Spread blocks
g_BlockSpreadLightFalloff[E_BLOCK_AIR] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_CAKE] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_CHEST] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_COBWEB] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_CROPS] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_FENCE] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_FENCE_GATE] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_FIRE] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_GLASS] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_GLASS_PANE] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_GLOWSTONE] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_IRON_BARS] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_IRON_DOOR] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_LEAVES] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_SIGN_POST] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_TORCH] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_VINES] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_WALLSIGN] = 1;
g_BlockSpreadLightFalloff[E_BLOCK_WOODEN_DOOR] = 1;
// Light in water and lava dissapears faster:
g_BlockSpreadLightFalloff[E_BLOCK_LAVA] = 3;
g_BlockSpreadLightFalloff[E_BLOCK_STATIONARY_LAVA] = 3;
g_BlockSpreadLightFalloff[E_BLOCK_STATIONARY_WATER] = 3;
g_BlockSpreadLightFalloff[E_BLOCK_WATER] = 3;
// Transparent blocks
g_BlockTransparent[E_BLOCK_ACTIVATOR_RAIL] = true;
g_BlockTransparent[E_BLOCK_AIR] = true;
g_BlockTransparent[E_BLOCK_BIG_FLOWER] = true;
g_BlockTransparent[E_BLOCK_BROWN_MUSHROOM] = true;
g_BlockTransparent[E_BLOCK_CARROTS] = true;
g_BlockTransparent[E_BLOCK_CHEST] = true;
g_BlockTransparent[E_BLOCK_COBWEB] = true;
g_BlockTransparent[E_BLOCK_CROPS] = true;
g_BlockTransparent[E_BLOCK_DANDELION] = true;
g_BlockTransparent[E_BLOCK_DETECTOR_RAIL] = true;
g_BlockTransparent[E_BLOCK_ENDER_CHEST] = true;
g_BlockTransparent[E_BLOCK_FENCE] = true;
g_BlockTransparent[E_BLOCK_FENCE_GATE] = true;
g_BlockTransparent[E_BLOCK_FIRE] = true;
g_BlockTransparent[E_BLOCK_FLOWER] = true;
g_BlockTransparent[E_BLOCK_FLOWER_POT] = true;
g_BlockTransparent[E_BLOCK_GLASS] = true;
g_BlockTransparent[E_BLOCK_GLASS_PANE] = true;
g_BlockTransparent[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE] = true;
g_BlockTransparent[E_BLOCK_ICE] = true;
g_BlockTransparent[E_BLOCK_IRON_DOOR] = true;
g_BlockTransparent[E_BLOCK_LAVA] = true;
g_BlockTransparent[E_BLOCK_LEAVES] = true;
g_BlockTransparent[E_BLOCK_LEVER] = true;
g_BlockTransparent[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE] = true;
g_BlockTransparent[E_BLOCK_MELON_STEM] = true;
g_BlockTransparent[E_BLOCK_NETHER_BRICK_FENCE] = true;
g_BlockTransparent[E_BLOCK_NEW_LEAVES] = true;
g_BlockTransparent[E_BLOCK_POTATOES] = true;
g_BlockTransparent[E_BLOCK_POWERED_RAIL] = true;
g_BlockTransparent[E_BLOCK_PISTON_EXTENSION] = true;
g_BlockTransparent[E_BLOCK_PUMPKIN_STEM] = true;
g_BlockTransparent[E_BLOCK_RAIL] = true;
g_BlockTransparent[E_BLOCK_RED_MUSHROOM] = true;
g_BlockTransparent[E_BLOCK_SIGN_POST] = true;
g_BlockTransparent[E_BLOCK_SNOW] = true;
g_BlockTransparent[E_BLOCK_STAINED_GLASS] = true;
g_BlockTransparent[E_BLOCK_STAINED_GLASS_PANE] = true;
g_BlockTransparent[E_BLOCK_STATIONARY_LAVA] = true;
g_BlockTransparent[E_BLOCK_STATIONARY_WATER] = true;
g_BlockTransparent[E_BLOCK_STONE_BUTTON] = true;
g_BlockTransparent[E_BLOCK_STONE_PRESSURE_PLATE] = true;
g_BlockTransparent[E_BLOCK_TALL_GRASS] = true;
g_BlockTransparent[E_BLOCK_TORCH] = true;
g_BlockTransparent[E_BLOCK_VINES] = true;
g_BlockTransparent[E_BLOCK_WALLSIGN] = true;
g_BlockTransparent[E_BLOCK_WATER] = true;
g_BlockTransparent[E_BLOCK_WOODEN_BUTTON] = true;
g_BlockTransparent[E_BLOCK_WOODEN_DOOR] = true;
g_BlockTransparent[E_BLOCK_WOODEN_PRESSURE_PLATE] = true;
// TODO: Any other transparent blocks?
// One hit break blocks:
g_BlockOneHitDig[E_BLOCK_ACTIVE_COMPARATOR] = true;
g_BlockOneHitDig[E_BLOCK_BIG_FLOWER] = true;
g_BlockOneHitDig[E_BLOCK_BROWN_MUSHROOM] = true;
g_BlockOneHitDig[E_BLOCK_CARROTS] = true;
g_BlockOneHitDig[E_BLOCK_CROPS] = true;
g_BlockOneHitDig[E_BLOCK_DANDELION] = true;
g_BlockOneHitDig[E_BLOCK_FIRE] = true;
g_BlockOneHitDig[E_BLOCK_FLOWER] = true;
g_BlockOneHitDig[E_BLOCK_FLOWER_POT] = true;
g_BlockOneHitDig[E_BLOCK_INACTIVE_COMPARATOR] = true;
g_BlockOneHitDig[E_BLOCK_MELON_STEM] = true;
g_BlockOneHitDig[E_BLOCK_POTATOES] = true;
g_BlockOneHitDig[E_BLOCK_PUMPKIN_STEM] = true;
g_BlockOneHitDig[E_BLOCK_REDSTONE_REPEATER_OFF] = true;
g_BlockOneHitDig[E_BLOCK_REDSTONE_REPEATER_ON] = true;
g_BlockOneHitDig[E_BLOCK_REDSTONE_TORCH_OFF] = true;
g_BlockOneHitDig[E_BLOCK_REDSTONE_TORCH_ON] = true;
g_BlockOneHitDig[E_BLOCK_REDSTONE_WIRE] = true;
g_BlockOneHitDig[E_BLOCK_RED_MUSHROOM] = true;
g_BlockOneHitDig[E_BLOCK_REEDS] = true;
g_BlockOneHitDig[E_BLOCK_SAPLING] = true;
g_BlockOneHitDig[E_BLOCK_TNT] = true;
g_BlockOneHitDig[E_BLOCK_TALL_GRASS] = true;
g_BlockOneHitDig[E_BLOCK_TORCH] = true;
// Blocks that break when pushed by piston:
g_BlockPistonBreakable[E_BLOCK_ACTIVE_COMPARATOR] = true;
g_BlockPistonBreakable[E_BLOCK_AIR] = true;
g_BlockPistonBreakable[E_BLOCK_BED] = true;
g_BlockPistonBreakable[E_BLOCK_BIG_FLOWER] = true;
g_BlockPistonBreakable[E_BLOCK_BROWN_MUSHROOM] = true;
g_BlockPistonBreakable[E_BLOCK_COBWEB] = true;
g_BlockPistonBreakable[E_BLOCK_CROPS] = true;
g_BlockPistonBreakable[E_BLOCK_DANDELION] = true;
g_BlockPistonBreakable[E_BLOCK_DEAD_BUSH] = true;
g_BlockPistonBreakable[E_BLOCK_FIRE] = true;
g_BlockPistonBreakable[E_BLOCK_FLOWER] = true;
g_BlockPistonBreakable[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE] = true;
g_BlockPistonBreakable[E_BLOCK_INACTIVE_COMPARATOR] = true;
g_BlockPistonBreakable[E_BLOCK_IRON_DOOR] = true;
g_BlockPistonBreakable[E_BLOCK_JACK_O_LANTERN] = true;
g_BlockPistonBreakable[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE] = true;
g_BlockPistonBreakable[E_BLOCK_LADDER] = true;
g_BlockPistonBreakable[E_BLOCK_LAVA] = true;
g_BlockPistonBreakable[E_BLOCK_LEVER] = true;
g_BlockPistonBreakable[E_BLOCK_MELON] = true;
g_BlockPistonBreakable[E_BLOCK_MELON_STEM] = true;
g_BlockPistonBreakable[E_BLOCK_PUMPKIN] = true;
g_BlockPistonBreakable[E_BLOCK_PUMPKIN_STEM] = true;
g_BlockPistonBreakable[E_BLOCK_REDSTONE_REPEATER_OFF] = true;
g_BlockPistonBreakable[E_BLOCK_REDSTONE_REPEATER_ON] = true;
g_BlockPistonBreakable[E_BLOCK_REDSTONE_TORCH_OFF] = true;
g_BlockPistonBreakable[E_BLOCK_REDSTONE_TORCH_ON] = true;
g_BlockPistonBreakable[E_BLOCK_REDSTONE_WIRE] = true;
g_BlockPistonBreakable[E_BLOCK_RED_MUSHROOM] = true;
g_BlockPistonBreakable[E_BLOCK_REEDS] = true;
g_BlockPistonBreakable[E_BLOCK_SNOW] = true;
g_BlockPistonBreakable[E_BLOCK_STATIONARY_LAVA] = true;
g_BlockPistonBreakable[E_BLOCK_STATIONARY_WATER] = true;
g_BlockPistonBreakable[E_BLOCK_STONE_BUTTON] = true;
g_BlockPistonBreakable[E_BLOCK_STONE_PRESSURE_PLATE] = true;
g_BlockPistonBreakable[E_BLOCK_TALL_GRASS] = true;
g_BlockPistonBreakable[E_BLOCK_TORCH] = true;
g_BlockPistonBreakable[E_BLOCK_VINES] = true;
g_BlockPistonBreakable[E_BLOCK_WATER] = true;
g_BlockPistonBreakable[E_BLOCK_WOODEN_BUTTON] = true;
g_BlockPistonBreakable[E_BLOCK_WOODEN_DOOR] = true;
g_BlockPistonBreakable[E_BLOCK_WOODEN_PRESSURE_PLATE] = true;
// Blocks that cannot be snowed over:
g_BlockIsSnowable[E_BLOCK_ACTIVE_COMPARATOR] = false;
g_BlockIsSnowable[E_BLOCK_AIR] = false;
g_BlockIsSnowable[E_BLOCK_BIG_FLOWER] = false;
g_BlockIsSnowable[E_BLOCK_BROWN_MUSHROOM] = false;
g_BlockIsSnowable[E_BLOCK_CACTUS] = false;
g_BlockIsSnowable[E_BLOCK_CHEST] = false;
g_BlockIsSnowable[E_BLOCK_CROPS] = false;
g_BlockIsSnowable[E_BLOCK_DANDELION] = false;
g_BlockIsSnowable[E_BLOCK_FIRE] = false;
g_BlockIsSnowable[E_BLOCK_FLOWER] = false;
g_BlockIsSnowable[E_BLOCK_GLASS] = false;
g_BlockIsSnowable[E_BLOCK_ICE] = false;
g_BlockIsSnowable[E_BLOCK_INACTIVE_COMPARATOR] = false;
g_BlockIsSnowable[E_BLOCK_LAVA] = false;
g_BlockIsSnowable[E_BLOCK_LILY_PAD] = false;
g_BlockIsSnowable[E_BLOCK_REDSTONE_REPEATER_OFF] = false;
g_BlockIsSnowable[E_BLOCK_REDSTONE_REPEATER_ON] = false;
g_BlockIsSnowable[E_BLOCK_REDSTONE_TORCH_OFF] = false;
g_BlockIsSnowable[E_BLOCK_REDSTONE_TORCH_ON] = false;
g_BlockIsSnowable[E_BLOCK_REDSTONE_WIRE] = false;
g_BlockIsSnowable[E_BLOCK_RED_MUSHROOM] = false;
g_BlockIsSnowable[E_BLOCK_REEDS] = false;
g_BlockIsSnowable[E_BLOCK_SAPLING] = false;
g_BlockIsSnowable[E_BLOCK_SIGN_POST] = false;
g_BlockIsSnowable[E_BLOCK_SNOW] = false;
g_BlockIsSnowable[E_BLOCK_STAINED_GLASS] = false;
g_BlockIsSnowable[E_BLOCK_STAINED_GLASS_PANE] = false;
g_BlockIsSnowable[E_BLOCK_STATIONARY_LAVA] = false;
g_BlockIsSnowable[E_BLOCK_STATIONARY_WATER] = false;
g_BlockIsSnowable[E_BLOCK_TALL_GRASS] = false;
g_BlockIsSnowable[E_BLOCK_TNT] = false;
g_BlockIsSnowable[E_BLOCK_TORCH] = false;
g_BlockIsSnowable[E_BLOCK_VINES] = false;
g_BlockIsSnowable[E_BLOCK_WALLSIGN] = false;
g_BlockIsSnowable[E_BLOCK_WATER] = false;
// Blocks that don't drop without a special tool:
g_BlockRequiresSpecialTool[E_BLOCK_BRICK] = true;
g_BlockRequiresSpecialTool[E_BLOCK_CAULDRON] = true;
g_BlockRequiresSpecialTool[E_BLOCK_COAL_ORE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_COBBLESTONE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_COBBLESTONE_STAIRS] = true;
g_BlockRequiresSpecialTool[E_BLOCK_COBWEB] = true;
g_BlockRequiresSpecialTool[E_BLOCK_DIAMOND_BLOCK] = true;
g_BlockRequiresSpecialTool[E_BLOCK_DIAMOND_ORE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_DOUBLE_STONE_SLAB] = true;
g_BlockRequiresSpecialTool[E_BLOCK_EMERALD_ORE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_END_STONE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_GOLD_BLOCK] = true;
g_BlockRequiresSpecialTool[E_BLOCK_GOLD_ORE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_IRON_BLOCK] = true;
g_BlockRequiresSpecialTool[E_BLOCK_IRON_ORE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_LAPIS_BLOCK] = true;
g_BlockRequiresSpecialTool[E_BLOCK_LAPIS_ORE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_MOSSY_COBBLESTONE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_NETHERRACK] = true;
g_BlockRequiresSpecialTool[E_BLOCK_NETHER_BRICK] = true;
g_BlockRequiresSpecialTool[E_BLOCK_NETHER_BRICK_STAIRS] = true;
g_BlockRequiresSpecialTool[E_BLOCK_OBSIDIAN] = true;
g_BlockRequiresSpecialTool[E_BLOCK_REDSTONE_ORE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_REDSTONE_ORE_GLOWING] = true;
g_BlockRequiresSpecialTool[E_BLOCK_SANDSTONE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_SANDSTONE_STAIRS] = true;
g_BlockRequiresSpecialTool[E_BLOCK_SNOW] = true;
g_BlockRequiresSpecialTool[E_BLOCK_STONE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_STONE_BRICKS] = true;
g_BlockRequiresSpecialTool[E_BLOCK_STONE_BRICK_STAIRS] = true;
g_BlockRequiresSpecialTool[E_BLOCK_STONE_PRESSURE_PLATE] = true;
g_BlockRequiresSpecialTool[E_BLOCK_STONE_SLAB] = true;
g_BlockRequiresSpecialTool[E_BLOCK_VINES] = true;
// Nonsolid blocks:
g_BlockIsSolid[E_BLOCK_ACTIVATOR_RAIL] = false;
g_BlockIsSolid[E_BLOCK_AIR] = false;
g_BlockIsSolid[E_BLOCK_BIG_FLOWER] = false;
g_BlockIsSolid[E_BLOCK_BROWN_MUSHROOM] = false;
g_BlockIsSolid[E_BLOCK_CARROTS] = false;
g_BlockIsSolid[E_BLOCK_COBWEB] = false;
g_BlockIsSolid[E_BLOCK_CROPS] = false;
g_BlockIsSolid[E_BLOCK_DANDELION] = false;
g_BlockIsSolid[E_BLOCK_DETECTOR_RAIL] = false;
g_BlockIsSolid[E_BLOCK_END_PORTAL] = false;
g_BlockIsSolid[E_BLOCK_FIRE] = false;
g_BlockIsSolid[E_BLOCK_FLOWER] = false;
g_BlockIsSolid[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE] = false;
g_BlockIsSolid[E_BLOCK_LAVA] = false;
g_BlockIsSolid[E_BLOCK_LEVER] = false;
g_BlockIsSolid[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE] = false;
g_BlockIsSolid[E_BLOCK_MELON_STEM] = false;
g_BlockIsSolid[E_BLOCK_NETHER_PORTAL] = false;
g_BlockIsSolid[E_BLOCK_PISTON_EXTENSION] = false;
g_BlockIsSolid[E_BLOCK_POTATOES] = false;
g_BlockIsSolid[E_BLOCK_POWERED_RAIL] = false;
g_BlockIsSolid[E_BLOCK_RAIL] = false;
g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_OFF] = false;
g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_ON] = false;
g_BlockIsSolid[E_BLOCK_REDSTONE_WIRE] = false;
g_BlockIsSolid[E_BLOCK_RED_MUSHROOM] = false;
g_BlockIsSolid[E_BLOCK_REEDS] = false;
g_BlockIsSolid[E_BLOCK_SAPLING] = false;
g_BlockIsSolid[E_BLOCK_SIGN_POST] = false;
g_BlockIsSolid[E_BLOCK_SNOW] = false;
g_BlockIsSolid[E_BLOCK_STATIONARY_LAVA] = false;
g_BlockIsSolid[E_BLOCK_STATIONARY_WATER] = false;
g_BlockIsSolid[E_BLOCK_STONE_BUTTON] = false;
g_BlockIsSolid[E_BLOCK_STONE_PRESSURE_PLATE] = false;
g_BlockIsSolid[E_BLOCK_TALL_GRASS] = false;
g_BlockIsSolid[E_BLOCK_TORCH] = false;
g_BlockIsSolid[E_BLOCK_TRIPWIRE] = false;
g_BlockIsSolid[E_BLOCK_VINES] = false;
g_BlockIsSolid[E_BLOCK_WALLSIGN] = false;
g_BlockIsSolid[E_BLOCK_WATER] = false;
g_BlockIsSolid[E_BLOCK_WOODEN_BUTTON] = false;
g_BlockIsSolid[E_BLOCK_WOODEN_PRESSURE_PLATE] = false;
g_BlockIsSolid[E_BLOCK_WOODEN_SLAB] = false;
// Torch placeable blocks:
g_BlockFullyOccupiesVoxel[E_BLOCK_NEW_LOG] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_BEDROCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_BLOCK_OF_COAL] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_BLOCK_OF_REDSTONE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_BOOKCASE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_BRICK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_CLAY] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_COAL_ORE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_COBBLESTONE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_COMMAND_BLOCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_CRAFTING_TABLE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_DIAMOND_BLOCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_DIAMOND_ORE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_DIRT] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_DISPENSER] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_DOUBLE_STONE_SLAB] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_DOUBLE_WOODEN_SLAB] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_DROPPER] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_EMERALD_BLOCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_EMERALD_ORE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_END_STONE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_FURNACE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_GLOWSTONE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_GOLD_BLOCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_GOLD_ORE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_GRASS] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_GRAVEL] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_HARDENED_CLAY] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_HAY_BALE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_HUGE_BROWN_MUSHROOM] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_HUGE_RED_MUSHROOM] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_IRON_BLOCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_IRON_ORE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_JACK_O_LANTERN] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_JUKEBOX] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_LAPIS_BLOCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_LAPIS_ORE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_LOG] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_MELON] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_MOSSY_COBBLESTONE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_MYCELIUM] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_NETHERRACK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_NETHER_BRICK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_NETHER_QUARTZ_ORE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_NOTE_BLOCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_OBSIDIAN] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_PACKED_ICE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_PLANKS] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_PUMPKIN] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_QUARTZ_BLOCK] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_LAMP_OFF] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_LAMP_ON] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_ORE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_ORE_GLOWING] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_SANDSTONE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_SAND] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_SILVERFISH_EGG] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_SPONGE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_STAINED_CLAY] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_WOOL] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_STONE] = true;
g_BlockFullyOccupiesVoxel[E_BLOCK_STONE_BRICKS] = true;
}
} BlockPropertiesInitializer;

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
@ -905,17 +909,3 @@ extern cItem GetIniItemSet(cIniFile & a_IniFile, const char * a_Section, const c
// Block properties:
extern NIBBLETYPE g_BlockLightValue[256];
extern NIBBLETYPE g_BlockSpreadLightFalloff[256];
extern bool g_BlockTransparent[256];
extern bool g_BlockOneHitDig[256];
extern bool g_BlockPistonBreakable[256];
extern bool g_BlockIsSnowable[256];
extern bool g_BlockRequiresSpecialTool[256];
extern bool g_BlockIsSolid[256];
extern bool g_BlockFullyOccupiesVoxel[256];

451
src/BlockInfo.cpp Normal file
View File

@ -0,0 +1,451 @@
#include "Globals.h"
#include "BlockInfo.h"
#include "Blocks/BlockHandler.h"
cBlockInfo cBlockInfo::ms_Info[256];
cBlockInfo::cBlockInfo()
: m_LightValue(0x00)
, m_SpreadLightFalloff(0x0f)
, m_Transparent(false)
, m_OneHitDig(false)
, m_PistonBreakable(false)
, m_IsSnowable(true)
, m_RequiresSpecialTool(false)
, m_IsSolid(true)
, m_FullyOccupiesVoxel(false)
, m_Handler(NULL)
{}
cBlockInfo::~cBlockInfo()
{
delete m_Handler;
}
cBlockInfo & cBlockInfo::Get(BLOCKTYPE a_Type)
{
ASSERT(a_Type < 256);
return ms_Info[a_Type];
}
void cBlockInfo::Initialize(void)
{
for (unsigned int i = 0; i < 256; ++i)
{
if (ms_Info[i].m_Handler == NULL)
{
ms_Info[i].m_Handler = cBlockHandler::CreateBlockHandler((BLOCKTYPE) i);
}
}
// Emissive blocks
ms_Info[E_BLOCK_FIRE ].m_LightValue = 15;
ms_Info[E_BLOCK_GLOWSTONE ].m_LightValue = 15;
ms_Info[E_BLOCK_JACK_O_LANTERN ].m_LightValue = 15;
ms_Info[E_BLOCK_LAVA ].m_LightValue = 15;
ms_Info[E_BLOCK_STATIONARY_LAVA ].m_LightValue = 15;
ms_Info[E_BLOCK_END_PORTAL ].m_LightValue = 15;
ms_Info[E_BLOCK_REDSTONE_LAMP_ON ].m_LightValue = 15;
ms_Info[E_BLOCK_TORCH ].m_LightValue = 14;
ms_Info[E_BLOCK_BURNING_FURNACE ].m_LightValue = 13;
ms_Info[E_BLOCK_NETHER_PORTAL ].m_LightValue = 11;
ms_Info[E_BLOCK_REDSTONE_ORE_GLOWING].m_LightValue = 9;
ms_Info[E_BLOCK_REDSTONE_REPEATER_ON].m_LightValue = 9;
ms_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_LightValue = 7;
ms_Info[E_BLOCK_BREWING_STAND ].m_LightValue = 1;
ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_LightValue = 1;
ms_Info[E_BLOCK_DRAGON_EGG ].m_LightValue = 1;
// Spread blocks
ms_Info[E_BLOCK_AIR ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_CAKE ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_CHEST ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_COBWEB ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_CROPS ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_FENCE ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_FENCE_GATE ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_FIRE ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_GLASS ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_GLASS_PANE ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_GLOWSTONE ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_IRON_BARS ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_IRON_DOOR ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_LEAVES ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_SIGN_POST ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_TORCH ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_VINES ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_WALLSIGN ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_WOODEN_DOOR ].m_SpreadLightFalloff = 1;
// Light in water and lava dissapears faster:
ms_Info[E_BLOCK_LAVA ].m_SpreadLightFalloff = 3;
ms_Info[E_BLOCK_STATIONARY_LAVA ].m_SpreadLightFalloff = 3;
ms_Info[E_BLOCK_STATIONARY_WATER ].m_SpreadLightFalloff = 3;
ms_Info[E_BLOCK_WATER ].m_SpreadLightFalloff = 3;
// Transparent blocks
ms_Info[E_BLOCK_ACTIVATOR_RAIL ].m_Transparent = true;
ms_Info[E_BLOCK_AIR ].m_Transparent = true;
ms_Info[E_BLOCK_BIG_FLOWER ].m_Transparent = true;
ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_Transparent = true;
ms_Info[E_BLOCK_CARROTS ].m_Transparent = true;
ms_Info[E_BLOCK_CHEST ].m_Transparent = true;
ms_Info[E_BLOCK_COBWEB ].m_Transparent = true;
ms_Info[E_BLOCK_CROPS ].m_Transparent = true;
ms_Info[E_BLOCK_DANDELION ].m_Transparent = true;
ms_Info[E_BLOCK_DETECTOR_RAIL ].m_Transparent = true;
ms_Info[E_BLOCK_ENDER_CHEST ].m_Transparent = true;
ms_Info[E_BLOCK_FENCE ].m_Transparent = true;
ms_Info[E_BLOCK_FENCE_GATE ].m_Transparent = true;
ms_Info[E_BLOCK_FIRE ].m_Transparent = true;
ms_Info[E_BLOCK_FLOWER ].m_Transparent = true;
ms_Info[E_BLOCK_FLOWER_POT ].m_Transparent = true;
ms_Info[E_BLOCK_GLASS ].m_Transparent = true;
ms_Info[E_BLOCK_GLASS_PANE ].m_Transparent = true;
ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_Transparent = true;
ms_Info[E_BLOCK_ICE ].m_Transparent = true;
ms_Info[E_BLOCK_IRON_DOOR ].m_Transparent = true;
ms_Info[E_BLOCK_LAVA ].m_Transparent = true;
ms_Info[E_BLOCK_LEAVES ].m_Transparent = true;
ms_Info[E_BLOCK_LEVER ].m_Transparent = true;
ms_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_Transparent = true;
ms_Info[E_BLOCK_MELON_STEM ].m_Transparent = true;
ms_Info[E_BLOCK_NETHER_BRICK_FENCE ].m_Transparent = true;
ms_Info[E_BLOCK_NEW_LEAVES ].m_Transparent = true;
ms_Info[E_BLOCK_POTATOES ].m_Transparent = true;
ms_Info[E_BLOCK_POWERED_RAIL ].m_Transparent = true;
ms_Info[E_BLOCK_PISTON_EXTENSION ].m_Transparent = true;
ms_Info[E_BLOCK_PUMPKIN_STEM ].m_Transparent = true;
ms_Info[E_BLOCK_RAIL ].m_Transparent = true;
ms_Info[E_BLOCK_RED_MUSHROOM ].m_Transparent = true;
ms_Info[E_BLOCK_SIGN_POST ].m_Transparent = true;
ms_Info[E_BLOCK_SNOW ].m_Transparent = true;
ms_Info[E_BLOCK_STAINED_GLASS ].m_Transparent = true;
ms_Info[E_BLOCK_STAINED_GLASS_PANE ].m_Transparent = true;
ms_Info[E_BLOCK_STATIONARY_LAVA ].m_Transparent = true;
ms_Info[E_BLOCK_STATIONARY_WATER ].m_Transparent = true;
ms_Info[E_BLOCK_STONE_BUTTON ].m_Transparent = true;
ms_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_Transparent = true;
ms_Info[E_BLOCK_TALL_GRASS ].m_Transparent = true;
ms_Info[E_BLOCK_TORCH ].m_Transparent = true;
ms_Info[E_BLOCK_VINES ].m_Transparent = true;
ms_Info[E_BLOCK_WALLSIGN ].m_Transparent = true;
ms_Info[E_BLOCK_WATER ].m_Transparent = true;
ms_Info[E_BLOCK_WOODEN_BUTTON ].m_Transparent = true;
ms_Info[E_BLOCK_WOODEN_DOOR ].m_Transparent = true;
ms_Info[E_BLOCK_WOODEN_PRESSURE_PLATE].m_Transparent = true;
// TODO: Any other transparent blocks?
// One hit break blocks:
ms_Info[E_BLOCK_ACTIVE_COMPARATOR ].m_OneHitDig = true;
ms_Info[E_BLOCK_BIG_FLOWER ].m_OneHitDig = true;
ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_OneHitDig = true;
ms_Info[E_BLOCK_CARROTS ].m_OneHitDig = true;
ms_Info[E_BLOCK_CROPS ].m_OneHitDig = true;
ms_Info[E_BLOCK_DANDELION ].m_OneHitDig = true;
ms_Info[E_BLOCK_FIRE ].m_OneHitDig = true;
ms_Info[E_BLOCK_FLOWER ].m_OneHitDig = true;
ms_Info[E_BLOCK_FLOWER_POT ].m_OneHitDig = true;
ms_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_OneHitDig = true;
ms_Info[E_BLOCK_MELON_STEM ].m_OneHitDig = true;
ms_Info[E_BLOCK_POTATOES ].m_OneHitDig = true;
ms_Info[E_BLOCK_PUMPKIN_STEM ].m_OneHitDig = true;
ms_Info[E_BLOCK_REDSTONE_REPEATER_OFF].m_OneHitDig = true;
ms_Info[E_BLOCK_REDSTONE_REPEATER_ON].m_OneHitDig = true;
ms_Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_OneHitDig = true;
ms_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_OneHitDig = true;
ms_Info[E_BLOCK_REDSTONE_WIRE ].m_OneHitDig = true;
ms_Info[E_BLOCK_RED_MUSHROOM ].m_OneHitDig = true;
ms_Info[E_BLOCK_REEDS ].m_OneHitDig = true;
ms_Info[E_BLOCK_SAPLING ].m_OneHitDig = true;
ms_Info[E_BLOCK_TNT ].m_OneHitDig = true;
ms_Info[E_BLOCK_TALL_GRASS ].m_OneHitDig = true;
ms_Info[E_BLOCK_TORCH ].m_OneHitDig = true;
// Blocks that break when pushed by piston:
ms_Info[E_BLOCK_ACTIVE_COMPARATOR ].m_PistonBreakable = true;
ms_Info[E_BLOCK_AIR ].m_PistonBreakable = true;
ms_Info[E_BLOCK_BED ].m_PistonBreakable = true;
ms_Info[E_BLOCK_BIG_FLOWER ].m_PistonBreakable = true;
ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_PistonBreakable = true;
ms_Info[E_BLOCK_COBWEB ].m_PistonBreakable = true;
ms_Info[E_BLOCK_CROPS ].m_PistonBreakable = true;
ms_Info[E_BLOCK_DANDELION ].m_PistonBreakable = true;
ms_Info[E_BLOCK_DEAD_BUSH ].m_PistonBreakable = true;
ms_Info[E_BLOCK_FIRE ].m_PistonBreakable = true;
ms_Info[E_BLOCK_FLOWER ].m_PistonBreakable = true;
ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_PistonBreakable = true;
ms_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_PistonBreakable = true;
ms_Info[E_BLOCK_IRON_DOOR ].m_PistonBreakable = true;
ms_Info[E_BLOCK_JACK_O_LANTERN ].m_PistonBreakable = true;
ms_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_PistonBreakable = true;
ms_Info[E_BLOCK_LADDER ].m_PistonBreakable = true;
ms_Info[E_BLOCK_LAVA ].m_PistonBreakable = true;
ms_Info[E_BLOCK_LEVER ].m_PistonBreakable = true;
ms_Info[E_BLOCK_MELON ].m_PistonBreakable = true;
ms_Info[E_BLOCK_MELON_STEM ].m_PistonBreakable = true;
ms_Info[E_BLOCK_PUMPKIN ].m_PistonBreakable = true;
ms_Info[E_BLOCK_PUMPKIN_STEM ].m_PistonBreakable = true;
ms_Info[E_BLOCK_REDSTONE_REPEATER_OFF].m_PistonBreakable = true;
ms_Info[E_BLOCK_REDSTONE_REPEATER_ON].m_PistonBreakable = true;
ms_Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_PistonBreakable = true;
ms_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_PistonBreakable = true;
ms_Info[E_BLOCK_REDSTONE_WIRE ].m_PistonBreakable = true;
ms_Info[E_BLOCK_RED_MUSHROOM ].m_PistonBreakable = true;
ms_Info[E_BLOCK_REEDS ].m_PistonBreakable = true;
ms_Info[E_BLOCK_SNOW ].m_PistonBreakable = true;
ms_Info[E_BLOCK_STATIONARY_LAVA ].m_PistonBreakable = true;
ms_Info[E_BLOCK_STATIONARY_WATER ].m_PistonBreakable = true;
ms_Info[E_BLOCK_STONE_BUTTON ].m_PistonBreakable = true;
ms_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_PistonBreakable = true;
ms_Info[E_BLOCK_TALL_GRASS ].m_PistonBreakable = true;
ms_Info[E_BLOCK_TORCH ].m_PistonBreakable = true;
ms_Info[E_BLOCK_VINES ].m_PistonBreakable = true;
ms_Info[E_BLOCK_WATER ].m_PistonBreakable = true;
ms_Info[E_BLOCK_WOODEN_BUTTON ].m_PistonBreakable = true;
ms_Info[E_BLOCK_WOODEN_DOOR ].m_PistonBreakable = true;
ms_Info[E_BLOCK_WOODEN_PRESSURE_PLATE].m_PistonBreakable = true;
// Blocks that cannot be snowed over:
ms_Info[E_BLOCK_ACTIVE_COMPARATOR ].m_IsSnowable = false;
ms_Info[E_BLOCK_AIR ].m_IsSnowable = false;
ms_Info[E_BLOCK_BIG_FLOWER ].m_IsSnowable = false;
ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_IsSnowable = false;
ms_Info[E_BLOCK_CACTUS ].m_IsSnowable = false;
ms_Info[E_BLOCK_CHEST ].m_IsSnowable = false;
ms_Info[E_BLOCK_CROPS ].m_IsSnowable = false;
ms_Info[E_BLOCK_DANDELION ].m_IsSnowable = false;
ms_Info[E_BLOCK_FIRE ].m_IsSnowable = false;
ms_Info[E_BLOCK_FLOWER ].m_IsSnowable = false;
ms_Info[E_BLOCK_GLASS ].m_IsSnowable = false;
ms_Info[E_BLOCK_ICE ].m_IsSnowable = false;
ms_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_IsSnowable = false;
ms_Info[E_BLOCK_LAVA ].m_IsSnowable = false;
ms_Info[E_BLOCK_LILY_PAD ].m_IsSnowable = false;
ms_Info[E_BLOCK_REDSTONE_REPEATER_OFF].m_IsSnowable = false;
ms_Info[E_BLOCK_REDSTONE_REPEATER_ON].m_IsSnowable = false;
ms_Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_IsSnowable = false;
ms_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_IsSnowable = false;
ms_Info[E_BLOCK_REDSTONE_WIRE ].m_IsSnowable = false;
ms_Info[E_BLOCK_RED_MUSHROOM ].m_IsSnowable = false;
ms_Info[E_BLOCK_REEDS ].m_IsSnowable = false;
ms_Info[E_BLOCK_SAPLING ].m_IsSnowable = false;
ms_Info[E_BLOCK_SIGN_POST ].m_IsSnowable = false;
ms_Info[E_BLOCK_SNOW ].m_IsSnowable = false;
ms_Info[E_BLOCK_STAINED_GLASS ].m_IsSnowable = false;
ms_Info[E_BLOCK_STAINED_GLASS_PANE ].m_IsSnowable = false;
ms_Info[E_BLOCK_STATIONARY_LAVA ].m_IsSnowable = false;
ms_Info[E_BLOCK_STATIONARY_WATER ].m_IsSnowable = false;
ms_Info[E_BLOCK_TALL_GRASS ].m_IsSnowable = false;
ms_Info[E_BLOCK_TNT ].m_IsSnowable = false;
ms_Info[E_BLOCK_TORCH ].m_IsSnowable = false;
ms_Info[E_BLOCK_VINES ].m_IsSnowable = false;
ms_Info[E_BLOCK_WALLSIGN ].m_IsSnowable = false;
ms_Info[E_BLOCK_WATER ].m_IsSnowable = false;
ms_Info[E_BLOCK_RAIL ].m_IsSnowable = false;
ms_Info[E_BLOCK_ACTIVATOR_RAIL ].m_IsSnowable = false;
ms_Info[E_BLOCK_POWERED_RAIL ].m_IsSnowable = false;
ms_Info[E_BLOCK_DETECTOR_RAIL ].m_IsSnowable = false;
ms_Info[E_BLOCK_COBWEB ].m_IsSnowable = false;
// Blocks that don't drop without a special tool:
ms_Info[E_BLOCK_BRICK ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_CAULDRON ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_COAL_ORE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_COBBLESTONE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_COBBLESTONE_STAIRS ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_COBWEB ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_DIAMOND_BLOCK ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_DIAMOND_ORE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_DOUBLE_STONE_SLAB ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_EMERALD_ORE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_END_STONE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_GOLD_BLOCK ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_GOLD_ORE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_IRON_BLOCK ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_IRON_ORE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_LAPIS_BLOCK ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_LAPIS_ORE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_MOSSY_COBBLESTONE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_NETHERRACK ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_NETHER_BRICK ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_NETHER_BRICK_STAIRS ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_OBSIDIAN ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_REDSTONE_ORE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_REDSTONE_ORE_GLOWING].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_SANDSTONE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_SANDSTONE_STAIRS ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_SNOW ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_STONE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_STONE_BRICKS ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_STONE_BRICK_STAIRS ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_STONE_SLAB ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_VINES ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_FURNACE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_LIT_FURNACE ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_ANVIL ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_ENCHANTMENT_TABLE ].m_RequiresSpecialTool = true;
// Nonsolid blocks:
ms_Info[E_BLOCK_ACTIVATOR_RAIL ].m_IsSolid = false;
ms_Info[E_BLOCK_AIR ].m_IsSolid = false;
ms_Info[E_BLOCK_BIG_FLOWER ].m_IsSolid = false;
ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_IsSolid = false;
ms_Info[E_BLOCK_CARROTS ].m_IsSolid = false;
ms_Info[E_BLOCK_COBWEB ].m_IsSolid = false;
ms_Info[E_BLOCK_CROPS ].m_IsSolid = false;
ms_Info[E_BLOCK_DANDELION ].m_IsSolid = false;
ms_Info[E_BLOCK_DETECTOR_RAIL ].m_IsSolid = false;
ms_Info[E_BLOCK_END_PORTAL ].m_IsSolid = false;
ms_Info[E_BLOCK_FIRE ].m_IsSolid = false;
ms_Info[E_BLOCK_FLOWER ].m_IsSolid = false;
ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_IsSolid = false;
ms_Info[E_BLOCK_LAVA ].m_IsSolid = false;
ms_Info[E_BLOCK_LEVER ].m_IsSolid = false;
ms_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE].m_IsSolid = false;
ms_Info[E_BLOCK_MELON_STEM ].m_IsSolid = false;
ms_Info[E_BLOCK_NETHER_PORTAL ].m_IsSolid = false;
ms_Info[E_BLOCK_PISTON_EXTENSION ].m_IsSolid = false;
ms_Info[E_BLOCK_POTATOES ].m_IsSolid = false;
ms_Info[E_BLOCK_POWERED_RAIL ].m_IsSolid = false;
ms_Info[E_BLOCK_RAIL ].m_IsSolid = false;
ms_Info[E_BLOCK_REDSTONE_TORCH_OFF ].m_IsSolid = false;
ms_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_IsSolid = false;
ms_Info[E_BLOCK_REDSTONE_WIRE ].m_IsSolid = false;
ms_Info[E_BLOCK_RED_MUSHROOM ].m_IsSolid = false;
ms_Info[E_BLOCK_REEDS ].m_IsSolid = false;
ms_Info[E_BLOCK_SAPLING ].m_IsSolid = false;
ms_Info[E_BLOCK_SIGN_POST ].m_IsSolid = false;
ms_Info[E_BLOCK_SNOW ].m_IsSolid = false;
ms_Info[E_BLOCK_STATIONARY_LAVA ].m_IsSolid = false;
ms_Info[E_BLOCK_STATIONARY_WATER ].m_IsSolid = false;
ms_Info[E_BLOCK_STONE_BUTTON ].m_IsSolid = false;
ms_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_IsSolid = false;
ms_Info[E_BLOCK_TALL_GRASS ].m_IsSolid = false;
ms_Info[E_BLOCK_TORCH ].m_IsSolid = false;
ms_Info[E_BLOCK_TRIPWIRE ].m_IsSolid = false;
ms_Info[E_BLOCK_VINES ].m_IsSolid = false;
ms_Info[E_BLOCK_WALLSIGN ].m_IsSolid = false;
ms_Info[E_BLOCK_WATER ].m_IsSolid = false;
ms_Info[E_BLOCK_WOODEN_BUTTON ].m_IsSolid = false;
ms_Info[E_BLOCK_WOODEN_PRESSURE_PLATE].m_IsSolid = false;
ms_Info[E_BLOCK_WOODEN_SLAB ].m_IsSolid = false;
// Torch placeable blocks:
ms_Info[E_BLOCK_NEW_LOG ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_BEDROCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_BLOCK_OF_COAL ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_BLOCK_OF_REDSTONE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_BOOKCASE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_BRICK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_CLAY ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_COAL_ORE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_COBBLESTONE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_COMMAND_BLOCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_CRAFTING_TABLE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_DIAMOND_BLOCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_DIAMOND_ORE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_DIRT ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_DISPENSER ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_DOUBLE_STONE_SLAB ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_DOUBLE_WOODEN_SLAB ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_DROPPER ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_EMERALD_BLOCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_EMERALD_ORE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_END_STONE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_FURNACE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_GLOWSTONE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_GOLD_BLOCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_GOLD_ORE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_GRASS ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_GRAVEL ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_HARDENED_CLAY ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_HAY_BALE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_HUGE_BROWN_MUSHROOM ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_HUGE_RED_MUSHROOM ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_IRON_BLOCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_IRON_ORE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_JACK_O_LANTERN ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_JUKEBOX ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_LAPIS_BLOCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_LAPIS_ORE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_LOG ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_MELON ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_MOSSY_COBBLESTONE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_MYCELIUM ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_NETHERRACK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_NETHER_BRICK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_NETHER_QUARTZ_ORE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_NOTE_BLOCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_OBSIDIAN ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_PACKED_ICE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_PLANKS ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_PUMPKIN ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_QUARTZ_BLOCK ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_REDSTONE_LAMP_OFF ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_REDSTONE_LAMP_ON ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_REDSTONE_ORE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_REDSTONE_ORE_GLOWING].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_SANDSTONE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_SAND ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_SILVERFISH_EGG ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_SPONGE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_STAINED_CLAY ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_WOOL ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_STONE ].m_FullyOccupiesVoxel = true;
ms_Info[E_BLOCK_STONE_BRICKS ].m_FullyOccupiesVoxel = true;
}
// This is actually just some code that needs to run at program startup, so it is wrapped into a global var's constructor:
class cBlockInfoInitializer
{
public:
cBlockInfoInitializer(void)
{
cBlockInfo::Initialize();
}
} BlockInfoInitializer;

103
src/BlockInfo.h Normal file
View File

@ -0,0 +1,103 @@
#pragma once
// fwd:
class cBlockHandler;
// tolua_begin
class cBlockInfo
{
public:
// tolua_end
cBlockInfo();
~cBlockInfo();
/** (Re-)Initializes the internal BlockInfo structures. */
static void Initialize(void);
// tolua_begin
/** Returns the associated BlockInfo structure. */
static cBlockInfo & Get(BLOCKTYPE a_Type);
/** How much light do the blocks emit on their own? */
NIBBLETYPE m_LightValue;
/** How much light do the blocks consume? */
NIBBLETYPE m_SpreadLightFalloff;
/** Is a block completely transparent? (light doesn't get decreased(?)) */
bool m_Transparent;
/** Is a block destroyed after a single hit? */
bool m_OneHitDig;
/** Can a piston break this block? */
bool m_PistonBreakable;
/** Can this block hold snow atop? */
bool m_IsSnowable;
/** Does this block require a tool to drop? */
bool m_RequiresSpecialTool;
/** Is this block solid (player cannot walk through)? */
bool m_IsSolid;
/** Does this block fully occupy its voxel - is it a 'full' block? */
bool m_FullyOccupiesVoxel;
// tolua_end
/** Associated block handler. */
cBlockHandler * m_Handler;
// tolua_begin
inline static NIBBLETYPE GetLightValue (BLOCKTYPE a_Type) { return Get(a_Type).m_LightValue; }
inline static NIBBLETYPE GetSpreadLightFalloff(BLOCKTYPE a_Type) { return Get(a_Type).m_SpreadLightFalloff; }
inline static bool IsTransparent (BLOCKTYPE a_Type) { return Get(a_Type).m_Transparent; }
inline static bool IsOneHitDig (BLOCKTYPE a_Type) { return Get(a_Type).m_OneHitDig; }
inline static bool IsPistonBreakable (BLOCKTYPE a_Type) { return Get(a_Type).m_PistonBreakable; }
inline static bool IsSnowable (BLOCKTYPE a_Type) { return Get(a_Type).m_IsSnowable; }
inline static bool RequiresSpecialTool (BLOCKTYPE a_Type) { return Get(a_Type).m_RequiresSpecialTool; }
inline static bool IsSolid (BLOCKTYPE a_Type) { return Get(a_Type).m_IsSolid; }
inline static bool FullyOccupiesVoxel (BLOCKTYPE a_Type) { return Get(a_Type).m_FullyOccupiesVoxel; }
// tolua_end
inline static cBlockHandler * GetHandler (BLOCKTYPE a_Type) { return Get(a_Type).m_Handler; }
protected:
// TODO xdot: Change to std::vector to support dynamic block IDs
static cBlockInfo ms_Info[256];
}; // tolua_export
// Shortcut to get the blockhandler for a specific block
inline cBlockHandler * BlockHandler(BLOCKTYPE a_BlockType)
{
return cBlockInfo::Get(a_BlockType).m_Handler;
}

View File

@ -4,6 +4,7 @@
#include "BlockHandler.h" #include "BlockHandler.h"
#include "ChunkInterface.h" #include "ChunkInterface.h"
#include "WorldInterface.h" #include "WorldInterface.h"
#include "MetaRotater.h"
#include "../Entities/Player.h" #include "../Entities/Player.h"
@ -11,11 +12,11 @@
class cBlockBedHandler : class cBlockBedHandler :
public cBlockHandler public cMetaRotater<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>
{ {
public: public:
cBlockBedHandler(BLOCKTYPE a_BlockType) cBlockBedHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType) : cMetaRotater<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01,true>(a_BlockType)
{ {
} }

View File

@ -2,16 +2,17 @@
#include "BlockHandler.h" #include "BlockHandler.h"
#include "Chunk.h" #include "Chunk.h"
#include "MetaRotater.h"
class cBlockButtonHandler : class cBlockButtonHandler :
public cBlockHandler public cMetaRotater<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>
{ {
public: public:
cBlockButtonHandler(BLOCKTYPE a_BlockType) cBlockButtonHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType) : cMetaRotater<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>(a_BlockType)
{ {
} }
@ -101,7 +102,7 @@ public:
AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true); AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true);
BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn); BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn);
return (a_RelY > 0) && (g_BlockIsSolid[BlockIsOn]); return (a_RelY > 0) && (cBlockInfo::IsSolid(BlockIsOn));
} }
} ; } ;

View File

@ -54,7 +54,7 @@ public:
NIBBLETYPE BlockMeta; NIBBLETYPE BlockMeta;
if ( if (
a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta) && a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta) &&
(g_BlockIsSolid[BlockType]) cBlockInfo::IsSolid(BlockType)
) )
{ {
return false; return false;

View File

@ -4,17 +4,18 @@
#include "BlockEntity.h" #include "BlockEntity.h"
#include "../BlockArea.h" #include "../BlockArea.h"
#include "../Entities/Player.h" #include "../Entities/Player.h"
#include "MetaRotater.h"
class cBlockChestHandler : class cBlockChestHandler :
public cBlockEntityHandler public cMetaRotater<cBlockEntityHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>
{ {
public: public:
cBlockChestHandler(BLOCKTYPE a_BlockType) cBlockChestHandler(BLOCKTYPE a_BlockType)
: cBlockEntityHandler(a_BlockType) : cMetaRotater<cBlockEntityHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>(a_BlockType)
{ {
} }

View File

@ -3,17 +3,18 @@
#include "BlockHandler.h" #include "BlockHandler.h"
#include "BlockRedstoneRepeater.h" #include "BlockRedstoneRepeater.h"
#include "MetaRotater.h"
class cBlockComparatorHandler : class cBlockComparatorHandler :
public cBlockHandler public cMetaRotater<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>
{ {
public: public:
cBlockComparatorHandler(BLOCKTYPE a_BlockType) cBlockComparatorHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType) : cMetaRotater<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>(a_BlockType)
{ {
} }
@ -26,6 +27,13 @@ public:
} }
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
{
UNUSED(a_ChunkInterface);
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{ {
// Reset meta to 0 // Reset meta to 0

View File

@ -36,7 +36,7 @@ public:
if (a_RelY < cChunkDef::Height - 1) if (a_RelY < cChunkDef::Height - 1)
{ {
BLOCKTYPE Above = a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ); BLOCKTYPE Above = a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ);
if ((!g_BlockTransparent[Above] && !g_BlockOneHitDig[Above]) || IsBlockWater(Above)) if ((!cBlockInfo::IsTransparent(Above) && !cBlockInfo::IsOneHitDig(Above)) || IsBlockWater(Above))
{ {
a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_DIRT, E_META_DIRT_NORMAL); a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_DIRT, E_META_DIRT_NORMAL);
return; return;
@ -77,7 +77,7 @@ public:
BLOCKTYPE AboveDest; BLOCKTYPE AboveDest;
NIBBLETYPE AboveMeta; NIBBLETYPE AboveMeta;
Chunk->GetBlockTypeMeta(BlockX, BlockY + 1, BlockZ, AboveDest, AboveMeta); Chunk->GetBlockTypeMeta(BlockX, BlockY + 1, BlockZ, AboveDest, AboveMeta);
if ((g_BlockOneHitDig[AboveDest] || g_BlockTransparent[AboveDest]) && !IsBlockWater(AboveDest)) if ((cBlockInfo::IsOneHitDig(AboveDest) || cBlockInfo::IsTransparent(AboveDest)) && !IsBlockWater(AboveDest))
{ {
Chunk->FastSetBlock(BlockX, BlockY, BlockZ, E_BLOCK_GRASS, 0); Chunk->FastSetBlock(BlockX, BlockY, BlockZ, E_BLOCK_GRASS, 0);
} }

View File

@ -9,7 +9,7 @@
cBlockDoorHandler::cBlockDoorHandler(BLOCKTYPE a_BlockType) cBlockDoorHandler::cBlockDoorHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType) : super(a_BlockType)
{ {
} }
@ -55,6 +55,29 @@ void cBlockDoorHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterfac
void cBlockDoorHandler::OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
{
UNUSED(a_ChunkInterface);
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
if (Meta & 8)
{
// Current block is top of the door
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY - 1, a_BlockZ, a_Player);
}
else
{
// Current block is bottom of the door
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, a_Player);
}
}
void cBlockDoorHandler::OnPlacedByPlayer( void cBlockDoorHandler::OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,

View File

@ -4,18 +4,21 @@
#include "BlockHandler.h" #include "BlockHandler.h"
#include "../Entities/Player.h" #include "../Entities/Player.h"
#include "Chunk.h" #include "Chunk.h"
#include "MetaRotater.h"
class cBlockDoorHandler : class cBlockDoorHandler :
public cBlockHandler public cMetaRotater<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true>
{ {
typedef cMetaRotater<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true> super;
public: public:
cBlockDoorHandler(BLOCKTYPE a_BlockType); cBlockDoorHandler(BLOCKTYPE a_BlockType);
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override; virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override;
virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override;
virtual const char * GetStepSound(void) override; virtual const char * GetStepSound(void) override;
@ -167,6 +170,60 @@ public:
} }
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
{
if (a_Meta & 0x08)
{
return a_Meta;
}
else
{
return super::MetaRotateCCW(a_Meta);
}
}
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
{
if (a_Meta & 0x08)
{
return a_Meta;
}
else
{
return super::MetaRotateCW(a_Meta);
}
}
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
{
if (a_Meta & 0x08)
{
return a_Meta;
}
else
{
return super::MetaMirrorXY(a_Meta);
}
}
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
{
if (a_Meta & 0x08)
{
return a_Meta;
}
else
{
return super::MetaMirrorYZ(a_Meta);
}
}
} ; } ;

View File

@ -6,17 +6,18 @@
#pragma once #pragma once
#include "../Piston.h" #include "../Piston.h"
#include "MetaRotater.h"
class cBlockDropSpenserHandler : class cBlockDropSpenserHandler :
public cBlockEntityHandler public cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{ {
public: public:
cBlockDropSpenserHandler(BLOCKTYPE a_BlockType) : cBlockDropSpenserHandler(BLOCKTYPE a_BlockType) :
cBlockEntityHandler(a_BlockType) cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{ {
} }
@ -34,6 +35,20 @@ public:
a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch()); a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
return true; return true;
} }
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
{
// Bit 0x08 is a flag. Lowest three bits are position. 0x08 == 1000
NIBBLETYPE OtherMeta = a_Meta & 0x08;
// Mirrors defined by by a table. (Source, mincraft.gamepedia.com) 0x07 == 0111
switch (a_Meta & 0x07)
{
case 0x00: return 0x01 + OtherMeta; // Down -> Up
case 0x01: return 0x00 + OtherMeta; // Up -> Down
}
// Not Facing Up or Down; No change.
return a_Meta;
}
} ; } ;

View File

@ -2,17 +2,17 @@
#pragma once #pragma once
#include "BlockEntity.h" #include "BlockEntity.h"
#include "MetaRotater.h"
class cBlockEnderchestHandler : class cBlockEnderchestHandler :
public cBlockEntityHandler public cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{ {
public: public:
cBlockEnderchestHandler(BLOCKTYPE a_BlockType) cBlockEnderchestHandler(BLOCKTYPE a_BlockType)
: cBlockEntityHandler(a_BlockType) : cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{ {
} }

View File

@ -2,17 +2,17 @@
#pragma once #pragma once
#include "BlockHandler.h" #include "BlockHandler.h"
#include "MetaRotater.h"
class cBlockFenceGateHandler : class cBlockFenceGateHandler :
public cBlockHandler public cMetaRotater<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>
{ {
public: public:
cBlockFenceGateHandler(BLOCKTYPE a_BlockType) : cBlockFenceGateHandler(BLOCKTYPE a_BlockType) :
cBlockHandler(a_BlockType) cMetaRotater<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType)
{ {
} }
@ -48,6 +48,12 @@ public:
} }
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
{
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
}
virtual bool IsUseable(void) override virtual bool IsUseable(void) override
{ {
return true; return true;

View File

@ -2,101 +2,24 @@
#pragma once #pragma once
#include "BlockHandler.h" #include "BlockHandler.h"
#include "BlockEntity.h"
class cBlockFlowerPotHandler : class cBlockFlowerPotHandler :
public cBlockHandler public cBlockEntityHandler
{ {
public: public:
cBlockFlowerPotHandler(BLOCKTYPE a_BlockType) : cBlockFlowerPotHandler(BLOCKTYPE a_BlockType) :
cBlockHandler(a_BlockType) cBlockEntityHandler(a_BlockType)
{ {
} }
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{ {
a_Pickups.push_back(cItem(E_ITEM_FLOWER_POT, 1, 0)); a_Pickups.push_back(cItem(E_ITEM_FLOWER_POT, 1, 0));
if (a_BlockMeta == 0)
{
return;
}
cItem Plant;
switch (a_BlockMeta)
{
case 1: Plant = cItem(E_BLOCK_RED_ROSE, 1, 0); break;
case 2: Plant = cItem(E_BLOCK_YELLOW_FLOWER, 1, 0); break;
case 3: Plant = cItem(E_BLOCK_SAPLING, 1, E_META_SAPLING_APPLE); break;
case 4: Plant = cItem(E_BLOCK_SAPLING, 1, E_META_SAPLING_CONIFER); break;
case 5: Plant = cItem(E_BLOCK_SAPLING, 1, E_META_SAPLING_BIRCH); break;
case 6: Plant = cItem(E_BLOCK_SAPLING, 1, E_META_SAPLING_JUNGLE); break;
case 7: Plant = cItem(E_BLOCK_RED_MUSHROOM, 1, 0); break;
case 8: Plant = cItem(E_BLOCK_BROWN_MUSHROOM, 1, 0); break;
case 9: Plant = cItem(E_BLOCK_CACTUS, 1, 0); break;
case 10: Plant = cItem(E_BLOCK_DEAD_BUSH, 1, 0); break;
case 11: Plant = cItem(E_BLOCK_TALL_GRASS, 1, E_META_TALL_GRASS_FERN); break;
default: return;
}
a_Pickups.push_back(Plant);
}
void OnUse(cWorld * a_World, cWorldInterface * a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
{
NIBBLETYPE Meta = a_World->GetBlockMeta( a_BlockX, a_BlockY, a_BlockZ );
if (Meta != 0)
{
// Already filled
return;
}
switch (a_Player->GetEquippedItem().m_ItemType)
{
case E_BLOCK_RED_ROSE: Meta = 1; break;
case E_BLOCK_YELLOW_FLOWER: Meta = 2; break;
case E_BLOCK_SAPLING:
{
switch (a_Player->GetEquippedItem().m_ItemDamage)
{
case E_META_SAPLING_APPLE: Meta = 3; break;
case E_META_SAPLING_CONIFER: Meta = 4; break;
case E_META_SAPLING_BIRCH: Meta = 5; break;
case E_META_SAPLING_JUNGLE: Meta = 6; break;
}
break;
}
case E_BLOCK_RED_MUSHROOM: Meta = 7; break;
case E_BLOCK_BROWN_MUSHROOM: Meta = 8; break;
case E_BLOCK_CACTUS: Meta = 9; break;
case E_BLOCK_DEAD_BUSH: Meta = 10; break;
case E_BLOCK_TALL_GRASS:
{
if (a_Player->GetEquippedItem().m_ItemDamage == E_META_TALL_GRASS_FERN)
{
Meta = 11;
}
else
{
return;
}
break;
}
}
if (a_Player->GetGameMode() != gmCreative)
{
a_Player->GetInventory().RemoveOneEquippedItem();
}
a_World->SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
}
virtual bool IsUseable(void) override
{
return true;
} }
} ; } ;

View File

@ -57,6 +57,7 @@
#include "BlockRedstoneLamp.h" #include "BlockRedstoneLamp.h"
#include "BlockRedstoneRepeater.h" #include "BlockRedstoneRepeater.h"
#include "BlockRedstoneTorch.h" #include "BlockRedstoneTorch.h"
#include "BlockTNT.h"
#include "BlockSand.h" #include "BlockSand.h"
#include "BlockSapling.h" #include "BlockSapling.h"
#include "BlockSideways.h" #include "BlockSideways.h"
@ -77,33 +78,6 @@
bool cBlockHandler::m_HandlerInitialized = false;
cBlockHandler * cBlockHandler::m_BlockHandler[256];
cBlockHandler * cBlockHandler::GetBlockHandler(BLOCKTYPE a_BlockType)
{
if (!m_HandlerInitialized)
{
// We have to initialize
memset(m_BlockHandler, 0, sizeof(m_BlockHandler));
m_HandlerInitialized = true;
}
if (m_BlockHandler[a_BlockType] != NULL)
{
return m_BlockHandler[a_BlockType];
}
return m_BlockHandler[a_BlockType] = CreateBlockHandler(a_BlockType);
}
cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
{ {
switch(a_BlockType) switch(a_BlockType)
@ -172,6 +146,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_NETHER_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_NETHER_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_NETHER_PORTAL: return new cBlockPortalHandler (a_BlockType); case E_BLOCK_NETHER_PORTAL: return new cBlockPortalHandler (a_BlockType);
case E_BLOCK_NETHER_WART: return new cBlockNetherWartHandler (a_BlockType); case E_BLOCK_NETHER_WART: return new cBlockNetherWartHandler (a_BlockType);
case E_BLOCK_NETHER_QUARTZ_ORE: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_NEW_LEAVES: return new cBlockNewLeavesHandler (a_BlockType); case E_BLOCK_NEW_LEAVES: return new cBlockNewLeavesHandler (a_BlockType);
case E_BLOCK_NEW_LOG: return new cBlockSidewaysHandler (a_BlockType); case E_BLOCK_NEW_LOG: return new cBlockSidewaysHandler (a_BlockType);
case E_BLOCK_NOTE_BLOCK: return new cBlockNoteHandler (a_BlockType); case E_BLOCK_NOTE_BLOCK: return new cBlockNoteHandler (a_BlockType);
@ -192,7 +167,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_REDSTONE_REPEATER_ON: return new cBlockRedstoneRepeaterHandler(a_BlockType); case E_BLOCK_REDSTONE_REPEATER_ON: return new cBlockRedstoneRepeaterHandler(a_BlockType);
case E_BLOCK_REDSTONE_TORCH_OFF: return new cBlockRedstoneTorchHandler (a_BlockType); case E_BLOCK_REDSTONE_TORCH_OFF: return new cBlockRedstoneTorchHandler (a_BlockType);
case E_BLOCK_REDSTONE_TORCH_ON: return new cBlockRedstoneTorchHandler (a_BlockType); case E_BLOCK_REDSTONE_TORCH_ON: return new cBlockRedstoneTorchHandler (a_BlockType);
case E_BLOCK_REDSTONE_WIRE: return new cBlockRedstoneHandler (a_BlockType); case E_BLOCK_REDSTONE_WIRE: return new cBlockRedstoneHandler (a_BlockType);
case E_BLOCK_RED_MUSHROOM: return new cBlockMushroomHandler (a_BlockType); case E_BLOCK_RED_MUSHROOM: return new cBlockMushroomHandler (a_BlockType);
case E_BLOCK_RED_ROSE: return new cBlockFlowerHandler (a_BlockType); case E_BLOCK_RED_ROSE: return new cBlockFlowerHandler (a_BlockType);
case E_BLOCK_SAND: return new cBlockSandHandler (a_BlockType); case E_BLOCK_SAND: return new cBlockSandHandler (a_BlockType);
@ -212,6 +187,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_TALL_GRASS: return new cBlockTallGrassHandler (a_BlockType); case E_BLOCK_TALL_GRASS: return new cBlockTallGrassHandler (a_BlockType);
case E_BLOCK_TORCH: return new cBlockTorchHandler (a_BlockType); case E_BLOCK_TORCH: return new cBlockTorchHandler (a_BlockType);
case E_BLOCK_TRAPDOOR: return new cBlockTrapdoorHandler (a_BlockType); case E_BLOCK_TRAPDOOR: return new cBlockTrapdoorHandler (a_BlockType);
case E_BLOCK_TNT: return new cBlockTNTHandler (a_BlockType);
case E_BLOCK_VINES: return new cBlockVineHandler (a_BlockType); case E_BLOCK_VINES: return new cBlockVineHandler (a_BlockType);
case E_BLOCK_WALLSIGN: return new cBlockSignHandler (a_BlockType); case E_BLOCK_WALLSIGN: return new cBlockSignHandler (a_BlockType);
case E_BLOCK_WATER: return new cBlockFluidHandler (a_BlockType); case E_BLOCK_WATER: return new cBlockFluidHandler (a_BlockType);
@ -231,20 +207,6 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
void cBlockHandler::Deinit()
{
for (int i = 0; i < 256; i++)
{
delete m_BlockHandler[i];
}
memset(m_BlockHandler, 0, sizeof(m_BlockHandler)); // Don't leave any dangling pointers around, just in case
m_HandlerInitialized = false;
}
cBlockHandler::cBlockHandler(BLOCKTYPE a_BlockType) cBlockHandler::cBlockHandler(BLOCKTYPE a_BlockType)
{ {
m_BlockType = a_BlockType; m_BlockType = a_BlockType;
@ -329,7 +291,7 @@ void cBlockHandler::NeighborChanged(cChunkInterface & a_ChunkInterface, int a_Bl
{ {
if ((a_BlockY >= 0) && (a_BlockY < cChunkDef::Height)) if ((a_BlockY >= 0) && (a_BlockY < cChunkDef::Height))
{ {
GetBlockHandler(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); cBlockInfo::GetHandler(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
} }
} }
@ -361,6 +323,14 @@ void cBlockHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface &
void cBlockHandler::OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer *a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
{
}
void cBlockHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) void cBlockHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta)
{ {
// Setting the meta to a_BlockMeta keeps most textures. The few other blocks have to override this. // Setting the meta to a_BlockMeta keeps most textures. The few other blocks have to override this.

View File

@ -69,6 +69,9 @@ public:
/// Called if the user right clicks the block and the block is useable /// Called if the user right clicks the block and the block is useable
virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ); virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ);
/** Called when a Right Click to this Block is cancelled */
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace);
/// <summary>Called when the item is mined to convert it into pickups. Pickups may specify multiple items. Appends items to a_Pickups, preserves its original contents</summary> /// <summary>Called when the item is mined to convert it into pickups. Pickups may specify multiple items. Appends items to a_Pickups, preserves its original contents</summary>
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta); virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta);
@ -136,31 +139,15 @@ public:
/// <returns>Block meta following mirroring</returns> /// <returns>Block meta following mirroring</returns>
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) { return a_Meta; } virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) { return a_Meta; }
/// <summary>Get the blockhandler for a specific block id</summary>
static cBlockHandler * GetBlockHandler(BLOCKTYPE a_BlockType);
/// <summary>Deletes all initialised block handlers</summary>
static void Deinit();
protected: protected:
BLOCKTYPE m_BlockType; BLOCKTYPE m_BlockType;
// Creates a new blockhandler for the given block type. For internal use only, use ::GetBlockHandler() instead. // Creates a new blockhandler for the given block type. For internal use only, use ::GetBlockHandler() instead.
static cBlockHandler *CreateBlockHandler(BLOCKTYPE a_BlockType); static cBlockHandler * CreateBlockHandler(BLOCKTYPE a_BlockType);
static cBlockHandler *m_BlockHandler[256];
static bool m_HandlerInitialized; //used to detect if the blockhandlers are initialized friend class cBlockInfo;
}; };
// Shortcut to get the blockhandler for a specific block
inline cBlockHandler * BlockHandler(BLOCKTYPE a_BlockType)
{
return cBlockHandler::GetBlockHandler(a_BlockType);
}

View File

@ -91,7 +91,7 @@ public:
AddFaceDirection( a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); AddFaceDirection( a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true);
return g_BlockIsSolid[a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ)]; return cBlockInfo::IsSolid(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ));
} }

View File

@ -102,7 +102,7 @@ public:
AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true); AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true);
BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn); BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn);
return (a_RelY > 0) && (g_BlockIsSolid[BlockIsOn]); return (a_RelY > 0) && cBlockInfo::IsSolid(BlockIsOn);
} }
} ; } ;

View File

@ -29,7 +29,7 @@ public:
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
) override ) override
{ {
class cCallback : public cMobHeadBlockCallback class cCallback : public cMobHeadCallback
{ {
cPlayer * m_Player; cPlayer * m_Player;
NIBBLETYPE m_OldBlockMeta; NIBBLETYPE m_OldBlockMeta;
@ -45,6 +45,7 @@ public:
a_MobHeadEntity->SetType(static_cast<eMobHeadType>(m_OldBlockMeta)); a_MobHeadEntity->SetType(static_cast<eMobHeadType>(m_OldBlockMeta));
a_MobHeadEntity->SetRotation(static_cast<eMobHeadRotation>(Rotation)); a_MobHeadEntity->SetRotation(static_cast<eMobHeadRotation>(Rotation));
a_MobHeadEntity->GetWorld()->BroadcastBlockEntity(a_MobHeadEntity->GetPosX(), a_MobHeadEntity->GetPosY(), a_MobHeadEntity->GetPosZ(), m_Player->GetClientHandle());
return false; return false;
} }
@ -59,7 +60,7 @@ public:
a_BlockMeta = a_BlockFace; a_BlockMeta = a_BlockFace;
cWorld * World = (cWorld *) &a_WorldInterface; cWorld * World = (cWorld *) &a_WorldInterface;
World->DoWithMobHeadBlockAt(a_BlockX, a_BlockY, a_BlockZ, Callback); World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta); a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta);
} }
} ; } ;

View File

@ -98,7 +98,7 @@ public:
{ {
return false; return false;
} }
if (!g_BlockIsSolid[a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)]) if (!cBlockInfo::IsSolid(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)))
{ {
return false; return false;
} }
@ -130,7 +130,7 @@ public:
// Too close to the edge, cannot simulate // Too close to the edge, cannot simulate
return true; return true;
} }
return g_BlockIsSolid[BlockType]; return cBlockInfo::IsSolid(BlockType);
} }
} }
return true; return true;

View File

@ -20,7 +20,7 @@ public:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{ {
return ((a_RelY > 0) && g_BlockFullyOccupiesVoxel[a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)]); return ((a_RelY > 0) && cBlockInfo::FullyOccupiesVoxel(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)));
} }

View File

@ -29,7 +29,7 @@ public:
a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetYaw()); a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetYaw());
return true; return true;
} }
virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
{ {
@ -37,6 +37,13 @@ public:
} }
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
{
UNUSED(a_ChunkInterface);
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{ {
// Reset meta to 0 // Reset meta to 0

View File

@ -28,7 +28,7 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{ {
a_Pickups.push_back(cItem(m_BlockType, 1, a_BlockMeta)); a_Pickups.push_back(cItem(m_BlockType, 1, a_BlockMeta & 0x7));
} }
@ -41,7 +41,7 @@ public:
{ {
a_BlockType = m_BlockType; a_BlockType = m_BlockType;
BLOCKTYPE Type = (BLOCKTYPE) (a_Player->GetEquippedItem().m_ItemType); BLOCKTYPE Type = (BLOCKTYPE) (a_Player->GetEquippedItem().m_ItemType);
NIBBLETYPE Meta = (NIBBLETYPE)(a_Player->GetEquippedItem().m_ItemDamage & 0x07); NIBBLETYPE Meta = (NIBBLETYPE) a_Player->GetEquippedItem().m_ItemDamage;
// HandlePlaceBlock wants a cItemHandler pointer thing, so let's give it one // HandlePlaceBlock wants a cItemHandler pointer thing, so let's give it one
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(GetDoubleSlabType(Type)); cItemHandler * ItemHandler = cItemHandler::GetItemHandler(GetDoubleSlabType(Type));
@ -159,21 +159,30 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{ {
if (m_BlockType == E_BLOCK_DOUBLE_STONE_SLAB) BLOCKTYPE Block = GetSingleSlabType(m_BlockType);
{ a_Pickups.push_back(cItem(Block, 2, a_BlockMeta & 0x7));
m_BlockType = E_BLOCK_STONE_SLAB; }
}
else inline static BLOCKTYPE GetSingleSlabType(BLOCKTYPE a_BlockType)
{ {
m_BlockType = E_BLOCK_WOODEN_SLAB; switch (a_BlockType)
} {
a_Pickups.push_back(cItem(m_BlockType, 2, a_BlockMeta)); case E_BLOCK_DOUBLE_STONE_SLAB: return E_BLOCK_STONE_SLAB;
case E_BLOCK_DOUBLE_WOODEN_SLAB: return E_BLOCK_WOODEN_SLAB;
}
ASSERT(!"Unhandled double slab type!");
return a_BlockType;
} }
virtual const char * GetStepSound(void) override virtual const char * GetStepSound(void) override
{ {
return ((m_BlockType == E_BLOCK_DOUBLE_WOODEN_SLAB) || (m_BlockType == E_BLOCK_DOUBLE_WOODEN_SLAB)) ? "step.wood" : "step.stone"; switch (m_BlockType)
{
case E_BLOCK_DOUBLE_STONE_SLAB: return "step.stone";
case E_BLOCK_DOUBLE_WOODEN_SLAB: return "step.wood";
}
ASSERT(!"Unhandled double slab type!");
return "";
} }
} ; } ;

View File

@ -72,7 +72,7 @@ public:
BLOCKTYPE BlockBelow = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ); BLOCKTYPE BlockBelow = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ);
NIBBLETYPE MetaBelow = a_Chunk.GetMeta(a_RelX, a_RelY - 1, a_RelZ); NIBBLETYPE MetaBelow = a_Chunk.GetMeta(a_RelX, a_RelY - 1, a_RelZ);
if (g_BlockIsSnowable[BlockBelow] || ((BlockBelow == E_BLOCK_SNOW) && (MetaBelow == 7))) if (cBlockInfo::IsSnowable(BlockBelow) || ((BlockBelow == E_BLOCK_SNOW) && (MetaBelow == 7)))
{ {
// If block below is snowable, or it is a thin slow block and has a meta of 7 (full thin snow block), say yay // If block below is snowable, or it is a thin slow block and has a meta of 7 (full thin snow block), say yay
return true; return true;

View File

@ -2,17 +2,17 @@
#pragma once #pragma once
#include "BlockHandler.h" #include "BlockHandler.h"
#include "MetaRotater.h"
class cBlockStairsHandler : class cBlockStairsHandler :
public cBlockHandler public cMetaRotater<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>
{ {
public: public:
cBlockStairsHandler(BLOCKTYPE a_BlockType) : cBlockStairsHandler(BLOCKTYPE a_BlockType) :
cBlockHandler(a_BlockType) cMetaRotater<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>(a_BlockType)
{ {
} }
@ -96,54 +96,6 @@ public:
} }
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
{
// Bits 3 and 4 stay, the rest is swapped around according to a table:
NIBBLETYPE TopBits = (a_Meta & 0x0c);
switch (a_Meta & 0x03)
{
case 0x00: return TopBits | 0x03; // East -> North
case 0x01: return TopBits | 0x02; // West -> South
case 0x02: return TopBits | 0x00; // South -> East
case 0x03: return TopBits | 0x01; // North -> West
}
// Not reachable, but to avoid a compiler warning:
return 0;
}
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
{
// Bits 3 and 4 stay, the rest is swapped around according to a table:
NIBBLETYPE TopBits = (a_Meta & 0x0c);
switch (a_Meta & 0x03)
{
case 0x00: return TopBits | 0x02; // East -> South
case 0x01: return TopBits | 0x03; // West -> North
case 0x02: return TopBits | 0x01; // South -> West
case 0x03: return TopBits | 0x00; // North -> East
}
// Not reachable, but to avoid a compiler warning:
return 0;
}
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
{
// Bits 3 and 4 stay, the rest is swapped around according to a table:
NIBBLETYPE TopBits = (a_Meta & 0x0c);
switch (a_Meta & 0x03)
{
case 0x00: return TopBits | 0x00; // East -> East
case 0x01: return TopBits | 0x01; // West -> West
case 0x02: return TopBits | 0x03; // South -> North
case 0x03: return TopBits | 0x02; // North -> South
}
// Not reachable, but to avoid a compiler warning:
return 0;
}
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
{ {
// Toggle bit 3: // Toggle bit 3:
@ -151,20 +103,6 @@ public:
} }
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
{
// Bits 3 and 4 stay, the rest is swapped around according to a table:
NIBBLETYPE TopBits = (a_Meta & 0x0c);
switch (a_Meta & 0x03)
{
case 0x00: return TopBits | 0x01; // East -> West
case 0x01: return TopBits | 0x00; // West -> East
case 0x02: return TopBits | 0x02; // South -> South
case 0x03: return TopBits | 0x03; // North -> North
}
// Not reachable, but to avoid a compiler warning:
return 0;
}
} ; } ;

32
src/Blocks/BlockTNT.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
#include "BlockHandler.h"
class cBlockTNTHandler :
public cBlockHandler
{
public:
cBlockTNTHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
{
}
virtual const char * GetStepSound(void) override
{
return "step.grass";
}
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
{
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
}
};

View File

@ -2,17 +2,17 @@
#include "BlockHandler.h" #include "BlockHandler.h"
#include "../Chunk.h" #include "../Chunk.h"
#include "MetaRotater.h"
class cBlockTorchHandler : class cBlockTorchHandler :
public cBlockHandler public cMetaRotater<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>
{ {
public: public:
cBlockTorchHandler(BLOCKTYPE a_BlockType) cBlockTorchHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType) : cMetaRotater<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>(a_BlockType)
{ {
} }
@ -99,7 +99,7 @@ public:
static bool CanBePlacedOn(BLOCKTYPE a_BlockType, eBlockFace a_BlockFace) static bool CanBePlacedOn(BLOCKTYPE a_BlockType, eBlockFace a_BlockFace)
{ {
if ( !g_BlockFullyOccupiesVoxel[a_BlockType] ) if ( !cBlockInfo::FullyOccupiesVoxel(a_BlockType) )
{ {
return (a_BlockFace == BLOCK_FACE_TOP); // Allow placement only when torch upright (for glass, etc.); exceptions won't even be sent by client, no need to handle return (a_BlockFace == BLOCK_FACE_TOP); // Allow placement only when torch upright (for glass, etc.); exceptions won't even be sent by client, no need to handle
} }
@ -129,7 +129,7 @@ public:
{ {
return Face; return Face;
} }
else if ((g_BlockFullyOccupiesVoxel[BlockInQuestion]) && (i != BLOCK_FACE_BOTTOM)) else if (cBlockInfo::FullyOccupiesVoxel(BlockInQuestion) && (i != BLOCK_FACE_BOTTOM))
{ {
// Otherwise, if block in that direction is torch placeable and we haven't gotten to it via the bottom face, return that face // Otherwise, if block in that direction is torch placeable and we haven't gotten to it via the bottom face, return that face
return Face; return Face;
@ -163,7 +163,7 @@ public:
// No need to check for upright orientation, it was done when the torch was placed // No need to check for upright orientation, it was done when the torch was placed
return true; return true;
} }
else if ( !g_BlockFullyOccupiesVoxel[BlockInQuestion] ) else if ( !cBlockInfo::FullyOccupiesVoxel(BlockInQuestion) )
{ {
return false; return false;
} }
@ -185,67 +185,6 @@ public:
{ {
return "step.wood"; return "step.wood";
} }
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
{
// Bit 4 stays, the rest is swapped around according to a table:
NIBBLETYPE TopBits = (a_Meta & 0x08);
switch (a_Meta & 0x07)
{
case 0x01: return TopBits | 0x04; // East -> North
case 0x02: return TopBits | 0x03; // West -> South
case 0x03: return TopBits | 0x01; // South -> East
case 0x04: return TopBits | 0x02; // North -> West
default: return a_Meta; // Floor -> Floor
}
}
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
{
// Bit 4 stays, the rest is swapped around according to a table:
NIBBLETYPE TopBits = (a_Meta & 0x08);
switch (a_Meta & 0x07)
{
case 0x01: return TopBits | 0x03; // East -> South
case 0x02: return TopBits | 0x04; // West -> North
case 0x03: return TopBits | 0x02; // South -> West
case 0x04: return TopBits | 0x01; // North -> East
default: return a_Meta; // Floor -> Floor
}
}
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
{
// Bit 4 stays, the rest is swapped around according to a table:
NIBBLETYPE TopBits = (a_Meta & 0x08);
switch (a_Meta & 0x07)
{
case 0x03: return TopBits | 0x04; // South -> North
case 0x04: return TopBits | 0x03; // North -> South
default: return a_Meta; // Keep the rest
}
}
// Mirroring around the XZ plane doesn't make sense for floor torches,
// the others stay the same, so let's keep all the metas the same.
// The base class does tht for us, no need to override MetaMirrorXZ()
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
{
// Bit 4 stays, the rest is swapped around according to a table:
NIBBLETYPE TopBits = (a_Meta & 0x08);
switch (a_Meta & 0x07)
{
case 0x01: return TopBits | 0x02; // East -> West
case 0x02: return TopBits | 0x01; // West -> East
default: return a_Meta; // Keep the rest
}
}
} ; } ;

View File

@ -36,8 +36,16 @@ public:
{ {
// Flip the ON bit on/off using the XOR bitwise operation // Flip the ON bit on/off using the XOR bitwise operation
NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x04); NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x04);
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta); a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
cWorld * World = (cWorld *) &a_WorldInterface;
World->BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0, a_Player->GetClientHandle());
}
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
{
UNUSED(a_ChunkInterface);
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
} }
virtual bool GetPlacementBlockTypeMeta( virtual bool GetPlacementBlockTypeMeta(
@ -97,7 +105,7 @@ public:
AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true); AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true);
BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn); BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn);
return (a_RelY > 0) && (g_BlockIsSolid[BlockIsOn]); return (a_RelY > 0) && cBlockInfo::IsSolid(BlockIsOn);
} }
}; };

View File

@ -1,8 +1,7 @@
#pragma once #pragma once
#include "BlockHandler.h" #include "BlockHandler.h"
#include "MetaRotater.h"
@ -70,7 +69,7 @@ public:
/// Returns true if the specified block type is good for vines to attach to /// Returns true if the specified block type is good for vines to attach to
static bool IsBlockAttachable(BLOCKTYPE a_BlockType) static bool IsBlockAttachable(BLOCKTYPE a_BlockType)
{ {
return (a_BlockType == E_BLOCK_LEAVES) || g_BlockIsSolid[a_BlockType]; return (a_BlockType == E_BLOCK_LEAVES) || cBlockInfo::IsSolid(a_BlockType);
} }
@ -180,8 +179,8 @@ public:
{ {
return ((a_Meta << 1) | (a_Meta >> 3)) & 0x0f; // Rotate bits to the left return ((a_Meta << 1) | (a_Meta >> 3)) & 0x0f; // Rotate bits to the left
} }
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
{ {
// Bits 2 and 4 stay, bits 1 and 3 swap // Bits 2 and 4 stay, bits 1 and 3 swap
@ -194,6 +193,7 @@ public:
// Bits 1 and 3 stay, bits 2 and 4 swap // Bits 1 and 3 stay, bits 2 and 4 swap
return ((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2)); return ((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2));
} }
} ; } ;

View File

@ -6,7 +6,7 @@
bool cChunkInterface::DigBlock(cWorldInterface & a_WorldInterface, int a_X, int a_Y, int a_Z) bool cChunkInterface::DigBlock(cWorldInterface & a_WorldInterface, int a_X, int a_Y, int a_Z)
{ {
cBlockHandler *Handler = cBlockHandler::GetBlockHandler(GetBlock(a_X, a_Y, a_Z)); cBlockHandler * Handler = cBlockInfo::GetHandler(GetBlock(a_X, a_Y, a_Z));
Handler->OnDestroyed(*this, a_WorldInterface, a_X, a_Y, a_Z); Handler->OnDestroyed(*this, a_WorldInterface, a_X, a_Y, a_Z);
return m_ChunkMap->DigBlock(a_X, a_Y, a_Z); return m_ChunkMap->DigBlock(a_X, a_Y, a_Z);
} }

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;
}; };

99
src/Blocks/MetaRotater.h Normal file
View File

@ -0,0 +1,99 @@
// MetaRotater.h
// Provides a mixin for rotations and reflections
#pragma once
/*
Provides a mixin for rotations and reflections following the standard pattern of apply mask then use case.
Usage:
Inherit from this class providing your base class as Base, the BitMask for the direction bits in bitmask and the masked value for the directions in North, East, South, West. There is also an aptional parameter AssertIfNotMatched. Set this if it is invalid for a block to exist in any other state.
*/
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched = false>
class cMetaRotater : public Base
{
public:
cMetaRotater(BLOCKTYPE a_BlockType) :
Base(a_BlockType)
{}
virtual ~cMetaRotater() {}
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override;
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override;
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override;
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override;
};
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCW(NIBBLETYPE a_Meta)
{
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
switch (a_Meta & BitMask)
{
case South: return West | OtherMeta;
case West: return North | OtherMeta;
case North: return East | OtherMeta;
case East: return South | OtherMeta;
}
if (AssertIfNotMatched)
{
ASSERT(!"Invalid Meta value");
}
return a_Meta;
}
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCCW(NIBBLETYPE a_Meta)
{
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
switch (a_Meta & BitMask)
{
case South: return East | OtherMeta;
case East: return North | OtherMeta;
case North: return West | OtherMeta;
case West: return South | OtherMeta;
}
if (AssertIfNotMatched)
{
ASSERT(!"Invalid Meta value");
}
return a_Meta;
}
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorXY(NIBBLETYPE a_Meta)
{
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
switch (a_Meta & BitMask)
{
case South: return North | OtherMeta;
case North: return South | OtherMeta;
}
// Not Facing North or South; No change.
return a_Meta;
}
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorYZ(NIBBLETYPE a_Meta)
{
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
switch (a_Meta & BitMask)
{
case West: return East | OtherMeta;
case East: return West | OtherMeta;
}
// Not Facing East or West; No change.
return a_Meta;
}

View File

@ -27,4 +27,7 @@ public:
/** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */ /** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */
virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType) = 0; virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType) = 0;
/** Sends the block on those coords to the player */
virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer * a_Player) = 0;
}; };

View File

@ -40,6 +40,7 @@ if (NOT MSVC)
BlockEntities/NoteEntity.h BlockEntities/NoteEntity.h
BlockEntities/SignEntity.h BlockEntities/SignEntity.h
BlockEntities/MobHeadEntity.h BlockEntities/MobHeadEntity.h
BlockEntities/FlowerPotEntity.h
BlockID.h BlockID.h
BoundingBox.h BoundingBox.h
ChatColor.h ChatColor.h
@ -95,6 +96,7 @@ if (NOT MSVC)
#add cpp files here #add cpp files here
add_library(Bindings add_library(Bindings
Bindings/Bindings Bindings/Bindings
Bindings/DeprecatedBindings
Bindings/LuaChunkStay Bindings/LuaChunkStay
Bindings/LuaState Bindings/LuaState
Bindings/LuaWindow Bindings/LuaWindow

View File

@ -20,6 +20,7 @@
#include "BlockEntities/NoteEntity.h" #include "BlockEntities/NoteEntity.h"
#include "BlockEntities/SignEntity.h" #include "BlockEntities/SignEntity.h"
#include "BlockEntities/MobHeadEntity.h" #include "BlockEntities/MobHeadEntity.h"
#include "BlockEntities/FlowerPotEntity.h"
#include "Entities/Pickup.h" #include "Entities/Pickup.h"
#include "Item.h" #include "Item.h"
#include "Noise.h" #include "Noise.h"
@ -883,7 +884,7 @@ void cChunk::ApplyWeatherToTop()
FastSetBlock(X, Height, Z, E_BLOCK_SNOW, TopMeta - 1); FastSetBlock(X, Height, Z, E_BLOCK_SNOW, TopMeta - 1);
} }
} }
else if (g_BlockIsSnowable[TopBlock]) else if (cBlockInfo::IsSnowable(TopBlock))
{ {
SetBlock(X, Height + 1, Z, E_BLOCK_SNOW, 0); SetBlock(X, Height + 1, Z, E_BLOCK_SNOW, 0);
} }
@ -1311,6 +1312,7 @@ void cChunk::CreateBlockEntities(void)
case E_BLOCK_HEAD: case E_BLOCK_HEAD:
case E_BLOCK_NOTE_BLOCK: case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_JUKEBOX: case E_BLOCK_JUKEBOX:
case E_BLOCK_FLOWER_POT:
{ {
if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width)) if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width))
{ {
@ -1440,6 +1442,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
case E_BLOCK_HEAD: case E_BLOCK_HEAD:
case E_BLOCK_NOTE_BLOCK: case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_JUKEBOX: case E_BLOCK_JUKEBOX:
case E_BLOCK_FLOWER_POT:
{ {
AddBlockEntity(cBlockEntity::CreateByBlockType(a_BlockType, a_BlockMeta, WorldPos.x, WorldPos.y, WorldPos.z, m_World)); AddBlockEntity(cBlockEntity::CreateByBlockType(a_BlockType, a_BlockMeta, WorldPos.x, WorldPos.y, WorldPos.z, m_World));
break; break;
@ -1540,10 +1543,10 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
SetNibble(m_BlockMeta, index, a_BlockMeta); SetNibble(m_BlockMeta, index, a_BlockMeta);
// ONLY recalculate lighting if it's necessary! // ONLY recalculate lighting if it's necessary!
if( if (
(g_BlockLightValue[OldBlockType ] != g_BlockLightValue[a_BlockType]) || (cBlockInfo::GetLightValue (OldBlockType) != cBlockInfo::GetLightValue (a_BlockType)) ||
(g_BlockSpreadLightFalloff[OldBlockType] != g_BlockSpreadLightFalloff[a_BlockType]) || (cBlockInfo::GetSpreadLightFalloff(OldBlockType) != cBlockInfo::GetSpreadLightFalloff(a_BlockType)) ||
(g_BlockTransparent[OldBlockType] != g_BlockTransparent[a_BlockType]) (cBlockInfo::IsTransparent (OldBlockType) != cBlockInfo::IsTransparent (a_BlockType))
) )
{ {
m_IsLightValid = false; m_IsLightValid = false;
@ -2337,7 +2340,7 @@ bool cChunk::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCom
bool cChunk::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback) bool cChunk::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback)
{ {
// The blockentity list is locked by the parent chunkmap's CS // The blockentity list is locked by the parent chunkmap's CS
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2) for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2)
@ -2369,6 +2372,38 @@ bool cChunk::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMob
bool cChunk::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback)
{
// The blockentity list is locked by the parent chunkmap's CS
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2)
{
++itr2;
if (((*itr)->GetPosX() != a_BlockX) || ((*itr)->GetPosY() != a_BlockY) || ((*itr)->GetPosZ() != a_BlockZ))
{
continue;
}
if ((*itr)->GetBlockType() != E_BLOCK_FLOWER_POT)
{
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false;
}
// The correct block entity is here,
if (a_Callback.Item((cFlowerPotEntity *)*itr))
{
return false;
}
return true;
} // for itr - m_BlockEntitites[]
// Not found:
return false;
}
bool cChunk::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4) bool cChunk::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4)
{ {
// The blockentity list is locked by the parent chunkmap's CS // The blockentity list is locked by the parent chunkmap's CS

View File

@ -32,6 +32,7 @@ class cDispenserEntity;
class cFurnaceEntity; class cFurnaceEntity;
class cNoteEntity; class cNoteEntity;
class cMobHeadEntity; class cMobHeadEntity;
class cFlowerPotEntity;
class cBlockArea; class cBlockArea;
class cPawn; class cPawn;
class cPickup; class cPickup;
@ -48,7 +49,8 @@ typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback; typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback; typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
typedef cItemCallback<cMobHeadEntity> cMobHeadBlockCallback; typedef cItemCallback<cMobHeadEntity> cMobHeadCallback;
typedef cItemCallback<cFlowerPotEntity> cFlowerPotCallback;
@ -253,8 +255,11 @@ public:
/** Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found */ /** Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found */
bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback);
/** Calls the callback for the mob head block at the specified coords; returns false if there's no mob header block at those coords or callback returns true, returns true if found */ /** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */
bool DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback); bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback);
/** Calls the callback for the flower pot at the specified coords; returns false if there's no flower pot at those coords or callback returns true, returns true if found */
bool DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback);
/** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */ /** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible

View File

@ -2182,7 +2182,7 @@ bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, c
bool cChunkMap::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback) bool cChunkMap::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback)
{ {
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
@ -2193,7 +2193,25 @@ bool cChunkMap::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, c
{ {
return false; return false;
} }
return Chunk->DoWithMobHeadBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); return Chunk->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
}
bool cChunkMap::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback)
{
int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
{
return false;
}
return Chunk->DoWithFlowerPotAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
} }

View File

@ -26,6 +26,7 @@ class cFurnaceEntity;
class cNoteEntity; class cNoteEntity;
class cCommandBlockEntity; class cCommandBlockEntity;
class cMobHeadEntity; class cMobHeadEntity;
class cFlowerPotEntity;
class cPawn; class cPawn;
class cPickup; class cPickup;
class cChunkDataSerializer; class cChunkDataSerializer;
@ -41,10 +42,11 @@ typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback; typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cDropperEntity> cDropperCallback; typedef cItemCallback<cDropperEntity> cDropperCallback;
typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback; typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback;
typedef cItemCallback<cFlowerPotEntity> cFlowerPotCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback; typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback; typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
typedef cItemCallback<cMobHeadEntity> cMobHeadBlockCallback; typedef cItemCallback<cMobHeadEntity> cMobHeadCallback;
typedef cItemCallback<cChunk> cChunkCallback; typedef cItemCallback<cChunk> cChunkCallback;
@ -257,7 +259,10 @@ public:
bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Lua-accessible bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Lua-accessible
/** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */ /** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */
bool DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback); // Lua-accessible bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback); // Lua-accessible
/** Calls the callback for the flower pot at the specified coords; returns false if there's no flower pot at those coords or callback returns true, returns true if found */
bool DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback); // Lua-accessible
/** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */ /** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible

View File

@ -558,12 +558,25 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString
} }
else if (a_Channel == "REGISTER") else if (a_Channel == "REGISTER")
{ {
if (HasPluginChannel(a_Channel))
{
SendPluginMessage("UNREGISTER", a_Channel);
return; // Can't register again if already taken - kinda defeats the point of plugin messaging!
}
RegisterPluginChannels(BreakApartPluginChannels(a_Message)); RegisterPluginChannels(BreakApartPluginChannels(a_Message));
} }
else if (a_Channel == "UNREGISTER") else if (a_Channel == "UNREGISTER")
{ {
UnregisterPluginChannels(BreakApartPluginChannels(a_Message)); UnregisterPluginChannels(BreakApartPluginChannels(a_Message));
} }
else if (!HasPluginChannel(a_Channel))
{
// Ignore if client sent something but didn't register the channel first
LOGD("Player %s sent a plugin message on channel \"%s\", but didn't REGISTER it first", GetUsername().c_str(), a_Channel.c_str());
SendPluginMessage("UNREGISTER", a_Channel);
return;
}
cPluginManager::Get()->CallHookPluginMessage(*this, a_Channel, a_Message); cPluginManager::Get()->CallHookPluginMessage(*this, a_Channel, a_Message);
} }
@ -824,7 +837,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
if ( if (
(m_Player->IsGameModeCreative()) || // In creative mode, digging is done immediately (m_Player->IsGameModeCreative()) || // In creative mode, digging is done immediately
g_BlockOneHitDig[a_OldBlock] // One-hit blocks get destroyed immediately, too cBlockInfo::IsOneHitDig(a_OldBlock) // One-hit blocks get destroyed immediately, too
) )
{ {
HandleBlockDigFinished(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta); HandleBlockDigFinished(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta);
@ -843,7 +856,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
cWorld * World = m_Player->GetWorld(); cWorld * World = m_Player->GetWorld();
cChunkInterface ChunkInterface(World->GetChunkMap()); cChunkInterface ChunkInterface(World->GetChunkMap());
cBlockHandler * Handler = cBlockHandler::GetBlockHandler(a_OldBlock); cBlockHandler * Handler = cBlockInfo::GetHandler(a_OldBlock);
Handler->OnDigging(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ); Handler->OnDigging(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ);
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem()); cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
@ -857,7 +870,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
int pZ = a_BlockZ; int pZ = a_BlockZ;
AddFaceDirection(pX, pY, pZ, a_BlockFace); // Get the block in front of the clicked coordinates (m_bInverse defaulted to false) AddFaceDirection(pX, pY, pZ, a_BlockFace); // Get the block in front of the clicked coordinates (m_bInverse defaulted to false)
Handler = cBlockHandler::GetBlockHandler(World->GetBlock(pX, pY, pZ)); Handler = cBlockInfo::GetHandler(World->GetBlock(pX, pY, pZ));
if (Handler->IsClickedThrough()) if (Handler->IsClickedThrough())
{ {
@ -925,14 +938,22 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, ItemToFullString(a_HeldItem).c_str() a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, ItemToFullString(a_HeldItem).c_str()
); );
cWorld * World = m_Player->GetWorld();
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager(); cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
if (PlgMgr->CallHookPlayerRightClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ)) if (PlgMgr->CallHookPlayerRightClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
{ {
// A plugin doesn't agree with the action, replace the block on the client and quit: // A plugin doesn't agree with the action, replace the block on the client and quit:
cChunkInterface ChunkInterface(World->GetChunkMap());
BLOCKTYPE BlockType = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
BlockHandler->OnCancelRightClick(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
if (a_BlockFace > BLOCK_FACE_NONE) if (a_BlockFace > BLOCK_FACE_NONE)
{ {
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); //2 block high things
} }
return; return;
} }
@ -958,17 +979,15 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
if (a_BlockFace > -1) if (a_BlockFace > -1)
{ {
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
} }
return; return;
} }
cWorld * World = m_Player->GetWorld();
BLOCKTYPE BlockType; BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta; NIBBLETYPE BlockMeta;
World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta); World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
cBlockHandler * BlockHandler = cBlockHandler::GetBlockHandler(BlockType); cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
if (BlockHandler->IsUseable() && !m_Player->IsCrouched()) if (BlockHandler->IsUseable() && !m_Player->IsCrouched())
{ {
@ -1048,7 +1067,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
if ( if (
cBlockSlabHandler::IsAnySlabType(ClickedBlock) && // Is there a slab already? cBlockSlabHandler::IsAnySlabType(ClickedBlock) && // Is there a slab already?
cBlockSlabHandler::IsAnySlabType(EquippedBlock) && // Is the player placing another slab? cBlockSlabHandler::IsAnySlabType(EquippedBlock) && // Is the player placing another slab?
((ClickedBlockMeta & 0x07) == (EquippedBlockDamage & 0x07)) && // Is it the same slab type? ((ClickedBlockMeta & 0x07) == EquippedBlockDamage) && // Is it the same slab type?
( (
(a_BlockFace == BLOCK_FACE_TOP) || // Clicking the top of a bottom slab (a_BlockFace == BLOCK_FACE_TOP) || // Clicking the top of a bottom slab
(a_BlockFace == BLOCK_FACE_BOTTOM) // Clicking the bottom of a top slab (a_BlockFace == BLOCK_FACE_BOTTOM) // Clicking the bottom of a top slab

View File

@ -124,14 +124,15 @@ public:
/** Removes all parts from the object. */ /** Removes all parts from the object. */
void Clear(void); void Clear(void);
// tolua_end
// The following are exported in ManualBindings in order to support chaining - they return *this in Lua (#755)
/** Adds a plain text part, with optional style. /** Adds a plain text part, with optional style.
The default style is plain white text. */ The default style is plain white text. */
void AddTextPart(const AString & a_Message, const AString & a_Style = ""); void AddTextPart(const AString & a_Message, const AString & a_Style = "");
// tolua_end /** Adds a part that is translated client-side, with the formatting parameters and optional style. */
/** Adds a part that is translated client-side, with the formatting parameters and optional style.
Exported in ManualBindings due to AStringVector usage - Lua uses an array-table of strings. */
void AddClientTranslatedPart(const AString & a_TranslationID, const AStringVector & a_Parameters, const AString & a_Style = ""); void AddClientTranslatedPart(const AString & a_TranslationID, const AStringVector & a_Parameters, const AString & a_Style = "");
// tolua_begin // tolua_begin
@ -155,12 +156,14 @@ public:
/** Sets the message type, which is indicated by prefixes added to the message when serializing. */ /** Sets the message type, which is indicated by prefixes added to the message when serializing. */
void SetMessageType(eMessageType a_MessageType); void SetMessageType(eMessageType a_MessageType);
/** Returns the message type set previously by SetMessageType(). */
eMessageType GetMessageType(void) const { return m_MessageType; }
/** Adds the "underline" style to each part that is an URL. */ /** Adds the "underline" style to each part that is an URL. */
void UnderlineUrls(void); void UnderlineUrls(void);
// tolua_begin
/** Returns the message type set previously by SetMessageType(). */
eMessageType GetMessageType(void) const { return m_MessageType; }
// tolua_end // tolua_end
const cParts & GetParts(void) const { return m_Parts; } const cParts & GetParts(void) const { return m_Parts; }

View File

@ -17,33 +17,6 @@ typedef std::vector<int> cSlotNums;
// tolua_begin // tolua_begin
/// How much light do the blocks emit on their own?
extern unsigned char g_BlockLightValue[];
/// How much light do the block consume?
extern unsigned char g_BlockSpreadLightFalloff[];
/// Is a block completely transparent? (light doesn't get decreased(?))
extern bool g_BlockTransparent[];
/// Is a block destroyed after a single hit?
extern bool g_BlockOneHitDig[];
/// Can a piston break this block?
extern bool g_BlockPistonBreakable[256];
/// Can this block hold snow atop?
extern bool g_BlockIsSnowable[256];
/// Does this block require a tool to drop?
extern bool g_BlockRequiresSpecialTool[256];
/// Is this block solid (player cannot walk through)?
extern bool g_BlockIsSolid[256];
/// Does this block fully occupy it's voxel - is it a 'full' block?
extern bool g_BlockFullyOccupiesVoxel[256];
/// Experience Orb setup /// Experience Orb setup
enum enum
{ {
@ -253,6 +226,56 @@ inline const char * ClickActionToString(eClickAction a_ClickAction)
/** Returns a blockface mirrored around the Y axis (doesn't change up/down). */
inline eBlockFace MirrorBlockFaceY(eBlockFace a_BlockFace)
{
switch (a_BlockFace)
{
case BLOCK_FACE_XM: return BLOCK_FACE_XP;
case BLOCK_FACE_XP: return BLOCK_FACE_XM;
case BLOCK_FACE_ZM: return BLOCK_FACE_ZP;
case BLOCK_FACE_ZP: return BLOCK_FACE_ZM;
default: return a_BlockFace;
}
}
/** Returns a blockface rotated around the Y axis counter-clockwise. */
inline eBlockFace RotateBlockFaceCCW(eBlockFace a_BlockFace)
{
switch (a_BlockFace)
{
case BLOCK_FACE_XM: return BLOCK_FACE_ZP;
case BLOCK_FACE_XP: return BLOCK_FACE_ZM;
case BLOCK_FACE_ZM: return BLOCK_FACE_XM;
case BLOCK_FACE_ZP: return BLOCK_FACE_XP;
default: return a_BlockFace;
}
}
inline eBlockFace RotateBlockFaceCW(eBlockFace a_BlockFace)
{
switch (a_BlockFace)
{
case BLOCK_FACE_XM: return BLOCK_FACE_ZM;
case BLOCK_FACE_XP: return BLOCK_FACE_ZP;
case BLOCK_FACE_ZM: return BLOCK_FACE_XP;
case BLOCK_FACE_ZP: return BLOCK_FACE_XM;
default: return a_BlockFace;
}
}
inline bool IsValidBlock(int a_BlockType) inline bool IsValidBlock(int a_BlockType)
{ {
if ( if (
@ -654,7 +677,7 @@ namespace ItemCategory
inline bool BlockRequiresSpecialTool(BLOCKTYPE a_BlockType) inline bool BlockRequiresSpecialTool(BLOCKTYPE a_BlockType)
{ {
if(!IsValidBlock(a_BlockType)) return false; if(!IsValidBlock(a_BlockType)) return false;
return g_BlockRequiresSpecialTool[a_BlockType]; return cBlockInfo::RequiresSpecialTool(a_BlockType);
} }

View File

@ -582,11 +582,11 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width); int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width);
BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ ); BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ );
BLOCKTYPE BlockBelow = (BlockY > 0) ? NextChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR; BLOCKTYPE BlockBelow = (BlockY > 0) ? NextChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
if (!g_BlockIsSolid[BlockIn]) // Making sure we are not inside a solid block if (!cBlockInfo::IsSolid(BlockIn)) // Making sure we are not inside a solid block
{ {
if (m_bOnGround) // check if it's still on the ground if (m_bOnGround) // check if it's still on the ground
{ {
if (!g_BlockIsSolid[BlockBelow]) // Check if block below is air or water. if (!cBlockInfo::IsSolid(BlockBelow)) // Check if block below is air or water.
{ {
m_bOnGround = false; m_bOnGround = false;
} }
@ -616,7 +616,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
// The pickup is too close to an unloaded chunk, bail out of any physics handling // The pickup is too close to an unloaded chunk, bail out of any physics handling
return; return;
} }
if (!g_BlockIsSolid[GotBlock]) if (!cBlockInfo::IsSolid(GotBlock))
{ {
NextPos.x += gCrossCoords[i].x; NextPos.x += gCrossCoords[i].x;
NextPos.z += gCrossCoords[i].z; NextPos.z += gCrossCoords[i].z;

View File

@ -720,7 +720,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
if (GetSpeedZ() > 0) if (GetSpeedZ() > 0)
{ {
BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ())); BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ()));
if (!IsBlockRail(Block) && g_BlockIsSolid[Block]) if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
{ {
// We could try to detect a block in front based purely on coordinates, but xoft made a bounding box system - why not use? :P // We could try to detect a block in front based purely on coordinates, but xoft made a bounding box system - why not use? :P
cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ())), 0.5, 1); cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ())), 0.5, 1);
@ -737,7 +737,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
else if (GetSpeedZ() < 0) else if (GetSpeedZ() < 0)
{ {
BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1); BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1);
if (!IsBlockRail(Block) && g_BlockIsSolid[Block]) if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
{ {
cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1), 0.5, 1); cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1), 0.5, 1);
cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ() - 1), GetWidth() / 2, GetHeight()); cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ() - 1), GetWidth() / 2, GetHeight());
@ -757,7 +757,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
if (GetSpeedX() > 0) if (GetSpeedX() > 0)
{ {
BLOCKTYPE Block = m_World->GetBlock((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())); BLOCKTYPE Block = m_World->GetBlock((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()));
if (!IsBlockRail(Block) && g_BlockIsSolid[Block]) if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
{ {
cBoundingBox bbBlock(Vector3d((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1); cBoundingBox bbBlock(Vector3d((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1);
cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight()); cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
@ -773,7 +773,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
else if (GetSpeedX() < 0) else if (GetSpeedX() < 0)
{ {
BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ())); BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ()));
if (!IsBlockRail(Block) && g_BlockIsSolid[Block]) if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
{ {
cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1); cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1);
cBoundingBox bbMinecart(Vector3d(GetPosX() - 1, floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight()); cBoundingBox bbMinecart(Vector3d(GetPosX() - 1, floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
@ -798,10 +798,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
BLOCKTYPE BlockZM = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1); BLOCKTYPE BlockZM = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1);
BLOCKTYPE BlockZP = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1); BLOCKTYPE BlockZP = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1);
if ( if (
(!IsBlockRail(BlockXM) && g_BlockIsSolid[BlockXM]) || (!IsBlockRail(BlockXM) && cBlockInfo::IsSolid(BlockXM)) ||
(!IsBlockRail(BlockXP) && g_BlockIsSolid[BlockXP]) || (!IsBlockRail(BlockXP) && cBlockInfo::IsSolid(BlockXP)) ||
(!IsBlockRail(BlockZM) && g_BlockIsSolid[BlockZM]) || (!IsBlockRail(BlockZM) && cBlockInfo::IsSolid(BlockZM)) ||
(!IsBlockRail(BlockZP) && g_BlockIsSolid[BlockZP]) (!IsBlockRail(BlockZP) && cBlockInfo::IsSolid(BlockZP))
) )
{ {
SetSpeed(0, 0, 0); SetSpeed(0, 0, 0);

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

@ -847,6 +847,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
{ {
@ -856,24 +858,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);
} }
@ -1497,10 +1482,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
@ -1508,16 +1497,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();
@ -1884,7 +1872,7 @@ void cPlayer::Detach()
{ {
for (int z = PosZ - 2; z <= (PosZ + 2); ++z) for (int z = PosZ - 2; z <= (PosZ + 2); ++z)
{ {
if (!g_BlockIsSolid[m_World->GetBlock(x, y, z)] && g_BlockIsSolid[m_World->GetBlock(x, y - 1, z)]) if (!cBlockInfo::IsSolid(m_World->GetBlock(x, y, z)) && cBlockInfo::IsSolid(m_World->GetBlock(x, y - 1, z)))
{ {
TeleportToCoords(x, y, z); TeleportToCoords(x, y, z);
return; return;

View File

@ -50,12 +50,12 @@ protected:
LOGD("Hit block %d:%d at {%d, %d, %d} face %d, %s (%s)", LOGD("Hit block %d:%d at {%d, %d, %d} face %d, %s (%s)",
a_BlockType, a_BlockMeta, a_BlockType, a_BlockMeta,
a_BlockX, a_BlockY, a_BlockZ, a_EntryFace, a_BlockX, a_BlockY, a_BlockZ, a_EntryFace,
g_BlockIsSolid[a_BlockType] ? "solid" : "non-solid", cBlockInfo::IsSolid(a_BlockType) ? "solid" : "non-solid",
ItemToString(cItem(a_BlockType, 1, a_BlockMeta)).c_str() ItemToString(cItem(a_BlockType, 1, a_BlockMeta)).c_str()
); );
*/ */
if (g_BlockIsSolid[a_BlockType]) if (cBlockInfo::IsSolid(a_BlockType))
{ {
// The projectile hit a solid block // The projectile hit a solid block
// Calculate the exact hit coords: // Calculate the exact hit coords:

View File

@ -762,7 +762,7 @@ void cStructGenWormNestCaves::ClearCache(void)
void cStructGenWormNestCaves::GenStructures(cChunkDesc & a_ChunkDesc) void cStructGenWormNestCaves::GenFinish(cChunkDesc & a_ChunkDesc)
{ {
int ChunkX = a_ChunkDesc.GetChunkX(); int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ(); int ChunkZ = a_ChunkDesc.GetChunkZ();
@ -902,7 +902,7 @@ static float GetMarbleNoise( float x, float y, float z, cNoise & a_Noise )
void cStructGenMarbleCaves::GenStructures(cChunkDesc & a_ChunkDesc) void cStructGenMarbleCaves::GenFinish(cChunkDesc & a_ChunkDesc)
{ {
cNoise Noise(m_Seed); cNoise Noise(m_Seed);
for (int z = 0; z < cChunkDef::Width; z++) for (int z = 0; z < cChunkDef::Width; z++)
@ -938,7 +938,7 @@ void cStructGenMarbleCaves::GenStructures(cChunkDesc & a_ChunkDesc)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenDualRidgeCaves: // cStructGenDualRidgeCaves:
void cStructGenDualRidgeCaves::GenStructures(cChunkDesc & a_ChunkDesc) void cStructGenDualRidgeCaves::GenFinish(cChunkDesc & a_ChunkDesc)
{ {
for (int z = 0; z < cChunkDef::Width; z++) for (int z = 0; z < cChunkDef::Width; z++)
{ {

View File

@ -20,7 +20,7 @@
class cStructGenMarbleCaves : class cStructGenMarbleCaves :
public cStructureGen public cFinishGen
{ {
public: public:
cStructGenMarbleCaves(int a_Seed) : m_Seed(a_Seed) {} cStructGenMarbleCaves(int a_Seed) : m_Seed(a_Seed) {}
@ -29,8 +29,8 @@ protected:
int m_Seed; int m_Seed;
// cStructureGen override: // cFinishGen override:
virtual void GenStructures(cChunkDesc & a_ChunkDesc) override; virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ; } ;
@ -38,7 +38,7 @@ protected:
class cStructGenDualRidgeCaves : class cStructGenDualRidgeCaves :
public cStructureGen public cFinishGen
{ {
public: public:
cStructGenDualRidgeCaves(int a_Seed, float a_Threshold) : cStructGenDualRidgeCaves(int a_Seed, float a_Threshold) :
@ -55,8 +55,8 @@ protected:
int m_Seed; int m_Seed;
float m_Threshold; float m_Threshold;
// cStructureGen override: // cFinishGen override:
virtual void GenStructures(cChunkDesc & a_ChunkDesc) override; virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ; } ;
@ -64,7 +64,7 @@ protected:
class cStructGenWormNestCaves : class cStructGenWormNestCaves :
public cStructureGen public cFinishGen
{ {
public: public:
cStructGenWormNestCaves(int a_Seed, int a_Size = 64, int a_Grid = 96, int a_MaxOffset = 128) : cStructGenWormNestCaves(int a_Seed, int a_Size = 64, int a_Grid = 96, int a_MaxOffset = 128) :
@ -94,7 +94,7 @@ protected:
void GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cCaveSystems & a_Caves); void GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cCaveSystems & a_Caves);
// cStructGen override: // cStructGen override:
virtual void GenStructures(cChunkDesc & a_ChunkDesc) override; virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ; } ;

View File

@ -209,6 +209,7 @@ bool cChunkDesc::IsUsingDefaultComposition(void) const
void cChunkDesc::SetUseDefaultStructures(bool a_bUseDefaultStructures) void cChunkDesc::SetUseDefaultStructures(bool a_bUseDefaultStructures)
{ {
LOGWARNING("%s: Structures are no longer accounted for, use Finishers instead", __FUNCTION__);
m_bUseDefaultStructures = a_bUseDefaultStructures; m_bUseDefaultStructures = a_bUseDefaultStructures;
} }
@ -218,6 +219,7 @@ void cChunkDesc::SetUseDefaultStructures(bool a_bUseDefaultStructures)
bool cChunkDesc::IsUsingDefaultStructures(void) const bool cChunkDesc::IsUsingDefaultStructures(void) const
{ {
LOGWARNING("%s: Structures are no longer accounted for, use Finishers instead", __FUNCTION__);
return m_bUseDefaultStructures; return m_bUseDefaultStructures;
} }

View File

@ -133,11 +133,6 @@ cComposableGenerator::~cComposableGenerator()
delete *itr; delete *itr;
} }
m_FinishGens.clear(); m_FinishGens.clear();
for (cStructureGenList::const_iterator itr = m_StructureGens.begin(); itr != m_StructureGens.end(); ++itr)
{
delete *itr;
}
m_StructureGens.clear();
delete m_CompositionGen; delete m_CompositionGen;
m_CompositionGen = NULL; m_CompositionGen = NULL;
@ -164,7 +159,6 @@ void cComposableGenerator::Initialize(cIniFile & a_IniFile)
InitBiomeGen(a_IniFile); InitBiomeGen(a_IniFile);
InitHeightGen(a_IniFile); InitHeightGen(a_IniFile);
InitCompositionGen(a_IniFile); InitCompositionGen(a_IniFile);
InitStructureGens(a_IniFile);
InitFinishGens(a_IniFile); InitFinishGens(a_IniFile);
} }
@ -201,14 +195,6 @@ void cComposableGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a
m_CompositionGen->ComposeTerrain(a_ChunkDesc); m_CompositionGen->ComposeTerrain(a_ChunkDesc);
} }
if (a_ChunkDesc.IsUsingDefaultStructures())
{
for (cStructureGenList::iterator itr = m_StructureGens.begin(); itr != m_StructureGens.end(); ++itr)
{
(*itr)->GenStructures(a_ChunkDesc);
} // for itr - m_StructureGens[]
}
if (a_ChunkDesc.IsUsingDefaultFinish()) if (a_ChunkDesc.IsUsingDefaultFinish())
{ {
for (cFinishGenList::iterator itr = m_FinishGens.begin(); itr != m_FinishGens.end(); ++itr) for (cFinishGenList::iterator itr = m_FinishGens.begin(); itr != m_FinishGens.end(); ++itr)
@ -290,86 +276,26 @@ void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile)
void cComposableGenerator::InitStructureGens(cIniFile & a_IniFile)
{
AString Structures = a_IniFile.GetValueSet("Generator", "Structures", "Ravines, WormNestCaves, WaterLakes, LavaLakes, OreNests, Trees");
int Seed = m_ChunkGenerator.GetSeed();
AStringVector Str = StringSplitAndTrim(Structures, ",");
for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
{
if (NoCaseCompare(*itr, "DualRidgeCaves") == 0)
{
float Threshold = (float)a_IniFile.GetValueSetF("Generator", "DualRidgeCavesThreshold", 0.3);
m_StructureGens.push_back(new cStructGenDualRidgeCaves(Seed, Threshold));
}
else if (NoCaseCompare(*itr, "DirectOverhangs") == 0)
{
m_StructureGens.push_back(new cStructGenDirectOverhangs(Seed));
}
else if (NoCaseCompare(*itr, "DistortedMembraneOverhangs") == 0)
{
m_StructureGens.push_back(new cStructGenDistortedMembraneOverhangs(Seed));
}
else if (NoCaseCompare(*itr, "LavaLakes") == 0)
{
int Probability = a_IniFile.GetValueSetI("Generator", "LavaLakesProbability", 10);
m_StructureGens.push_back(new cStructGenLakes(Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, *m_HeightGen, Probability));
}
else if (NoCaseCompare(*itr, "MarbleCaves") == 0)
{
m_StructureGens.push_back(new cStructGenMarbleCaves(Seed));
}
else if (NoCaseCompare(*itr, "MineShafts") == 0)
{
int GridSize = a_IniFile.GetValueSetI("Generator", "MineShaftsGridSize", 512);
int MaxSystemSize = a_IniFile.GetValueSetI("Generator", "MineShaftsMaxSystemSize", 160);
int ChanceCorridor = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCorridor", 600);
int ChanceCrossing = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCrossing", 200);
int ChanceStaircase = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceStaircase", 200);
m_StructureGens.push_back(new cStructGenMineShafts(
Seed, GridSize, MaxSystemSize,
ChanceCorridor, ChanceCrossing, ChanceStaircase
));
}
else if (NoCaseCompare(*itr, "OreNests") == 0)
{
m_StructureGens.push_back(new cStructGenOreNests(Seed));
}
else if (NoCaseCompare(*itr, "Ravines") == 0)
{
m_StructureGens.push_back(new cStructGenRavines(Seed, 128));
}
else if (NoCaseCompare(*itr, "Trees") == 0)
{
m_StructureGens.push_back(new cStructGenTrees(Seed, m_BiomeGen, m_HeightGen, m_CompositionGen));
}
else if (NoCaseCompare(*itr, "WaterLakes") == 0)
{
int Probability = a_IniFile.GetValueSetI("Generator", "WaterLakesProbability", 25);
m_StructureGens.push_back(new cStructGenLakes(Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, *m_HeightGen, Probability));
}
else if (NoCaseCompare(*itr, "WormNestCaves") == 0)
{
m_StructureGens.push_back(new cStructGenWormNestCaves(Seed));
}
else
{
LOGWARNING("Unknown structure generator: \"%s\". Ignoring.", itr->c_str());
}
} // for itr - Str[]
}
void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{ {
int Seed = m_ChunkGenerator.GetSeed(); int Seed = m_ChunkGenerator.GetSeed();
eDimension Dimension = StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld")); eDimension Dimension = StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld"));
AString Finishers = a_IniFile.GetValueSet("Generator", "Finishers", "SprinkleFoliage,Ice,Snow,Lilypads,BottomLava,DeadBushes,PreSimulator"); // Older configuration used "Structures" in addition to "Finishers"; we don't distinguish between the two anymore (#398)
// Therefore, we load Structures from the ini file for compatibility, but move its contents over to Finishers:
AString Structures = a_IniFile.GetValue("Generator", "Structures", "");
AString Finishers = a_IniFile.GetValueSet("Generator", "Finishers", "Ravines, WormNestCaves, WaterLakes, LavaLakes, OreNests, Trees, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator");
if (!Structures.empty())
{
LOGINFO("[Generator].Structures is deprecated, moving the contents to [Generator].Finishers.");
// Structures used to generate before Finishers, so place them first:
Structures.append(", ");
Finishers = Structures + Finishers;
a_IniFile.SetValue("Generator", "Finishers", Finishers);
}
a_IniFile.DeleteValue("Generator", "Structures");
// Create all requested finishers:
AStringVector Str = StringSplitAndTrim(Finishers, ","); AStringVector Str = StringSplitAndTrim(Finishers, ",");
for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr) for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
{ {
@ -384,14 +310,48 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{ {
m_FinishGens.push_back(new cFinishGenSingleBiomeSingleTopBlock(Seed, E_BLOCK_DEAD_BUSH, biDesert, 2, E_BLOCK_SAND, E_BLOCK_SAND)); m_FinishGens.push_back(new cFinishGenSingleBiomeSingleTopBlock(Seed, E_BLOCK_DEAD_BUSH, biDesert, 2, E_BLOCK_SAND, E_BLOCK_SAND));
} }
else if (NoCaseCompare(*itr, "DirectOverhangs") == 0)
{
m_FinishGens.push_back(new cStructGenDirectOverhangs(Seed));
}
else if (NoCaseCompare(*itr, "DistortedMembraneOverhangs") == 0)
{
m_FinishGens.push_back(new cStructGenDistortedMembraneOverhangs(Seed));
}
else if (NoCaseCompare(*itr, "DualRidgeCaves") == 0)
{
float Threshold = (float)a_IniFile.GetValueSetF("Generator", "DualRidgeCavesThreshold", 0.3);
m_FinishGens.push_back(new cStructGenDualRidgeCaves(Seed, Threshold));
}
else if (NoCaseCompare(*itr, "Ice") == 0) else if (NoCaseCompare(*itr, "Ice") == 0)
{ {
m_FinishGens.push_back(new cFinishGenIce); m_FinishGens.push_back(new cFinishGenIce);
} }
else if (NoCaseCompare(*itr, "LavaLakes") == 0)
{
int Probability = a_IniFile.GetValueSetI("Generator", "LavaLakesProbability", 10);
m_FinishGens.push_back(new cStructGenLakes(Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, *m_HeightGen, Probability));
}
else if (NoCaseCompare(*itr, "LavaSprings") == 0) else if (NoCaseCompare(*itr, "LavaSprings") == 0)
{ {
m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, Dimension)); m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, Dimension));
} }
else if (NoCaseCompare(*itr, "MarbleCaves") == 0)
{
m_FinishGens.push_back(new cStructGenMarbleCaves(Seed));
}
else if (NoCaseCompare(*itr, "MineShafts") == 0)
{
int GridSize = a_IniFile.GetValueSetI("Generator", "MineShaftsGridSize", 512);
int MaxSystemSize = a_IniFile.GetValueSetI("Generator", "MineShaftsMaxSystemSize", 160);
int ChanceCorridor = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCorridor", 600);
int ChanceCrossing = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCrossing", 200);
int ChanceStaircase = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceStaircase", 200);
m_FinishGens.push_back(new cStructGenMineShafts(
Seed, GridSize, MaxSystemSize,
ChanceCorridor, ChanceCrossing, ChanceStaircase
));
}
else if (NoCaseCompare(*itr, "Lilypads") == 0) else if (NoCaseCompare(*itr, "Lilypads") == 0)
{ {
m_FinishGens.push_back(new cFinishGenSingleBiomeSingleTopBlock(Seed, E_BLOCK_LILY_PAD, biSwampland, 4, E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER)); m_FinishGens.push_back(new cFinishGenSingleBiomeSingleTopBlock(Seed, E_BLOCK_LILY_PAD, biSwampland, 4, E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER));
@ -400,10 +360,18 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{ {
m_FinishGens.push_back(new cFinishGenNetherClumpFoliage(Seed)); m_FinishGens.push_back(new cFinishGenNetherClumpFoliage(Seed));
} }
else if (NoCaseCompare(*itr, "OreNests") == 0)
{
m_FinishGens.push_back(new cStructGenOreNests(Seed));
}
else if (NoCaseCompare(*itr, "PreSimulator") == 0) else if (NoCaseCompare(*itr, "PreSimulator") == 0)
{ {
m_FinishGens.push_back(new cFinishGenPreSimulator); m_FinishGens.push_back(new cFinishGenPreSimulator);
} }
else if (NoCaseCompare(*itr, "Ravines") == 0)
{
m_FinishGens.push_back(new cStructGenRavines(Seed, 128));
}
else if (NoCaseCompare(*itr, "Snow") == 0) else if (NoCaseCompare(*itr, "Snow") == 0)
{ {
m_FinishGens.push_back(new cFinishGenSnow); m_FinishGens.push_back(new cFinishGenSnow);
@ -412,10 +380,27 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{ {
m_FinishGens.push_back(new cFinishGenSprinkleFoliage(Seed)); m_FinishGens.push_back(new cFinishGenSprinkleFoliage(Seed));
} }
else if (NoCaseCompare(*itr, "Trees") == 0)
{
m_FinishGens.push_back(new cStructGenTrees(Seed, m_BiomeGen, m_HeightGen, m_CompositionGen));
}
else if (NoCaseCompare(*itr, "WaterLakes") == 0)
{
int Probability = a_IniFile.GetValueSetI("Generator", "WaterLakesProbability", 25);
m_FinishGens.push_back(new cStructGenLakes(Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, *m_HeightGen, Probability));
}
else if (NoCaseCompare(*itr, "WaterSprings") == 0) else if (NoCaseCompare(*itr, "WaterSprings") == 0)
{ {
m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, Dimension)); m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, Dimension));
} }
else if (NoCaseCompare(*itr, "WormNestCaves") == 0)
{
m_FinishGens.push_back(new cStructGenWormNestCaves(Seed));
}
else
{
LOGWARNING("Unknown Finisher in the [Generator] section: \"%s\". Ignoring.", itr->c_str());
}
} // for itr - Str[] } // for itr - Str[]
} }

View File

@ -43,16 +43,16 @@ class cBiomeGen
public: public:
virtual ~cBiomeGen() {} // Force a virtual destructor in descendants virtual ~cBiomeGen() {} // Force a virtual destructor in descendants
/// Generates biomes for the given chunk /** Generates biomes for the given chunk */
virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) = 0; virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) = 0;
/// Reads parameters from the ini file, prepares generator for use. /** Reads parameters from the ini file, prepares generator for use. */
virtual void InitializeBiomeGen(cIniFile & a_IniFile) {} virtual void InitializeBiomeGen(cIniFile & a_IniFile) {}
/// Creates the correct BiomeGen descendant based on the ini file settings and the seed provided. /** Creates the correct BiomeGen descendant based on the ini file settings and the seed provided.
/// a_CacheOffByDefault gets set to whether the cache should be disabled by default a_CacheOffByDefault gets set to whether the cache should be disabled by default.
/// Used in BiomeVisualiser, too. Used in BiomeVisualiser, too.
/// Implemented in BioGen.cpp! Implemented in BioGen.cpp! */
static cBiomeGen * CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault); static cBiomeGen * CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault);
} ; } ;
@ -72,10 +72,10 @@ class cTerrainHeightGen
public: public:
virtual ~cTerrainHeightGen() {} // Force a virtual destructor in descendants virtual ~cTerrainHeightGen() {} // Force a virtual destructor in descendants
/// Generates heightmap for the given chunk /** Generates heightmap for the given chunk */
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) = 0; virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) = 0;
/// Reads parameters from the ini file, prepares generator for use. /** Reads parameters from the ini file, prepares generator for use. */
virtual void InitializeHeightGen(cIniFile & a_IniFile) {} virtual void InitializeHeightGen(cIniFile & a_IniFile) {}
/** Creates the correct TerrainHeightGen descendant based on the ini file settings and the seed provided. /** Creates the correct TerrainHeightGen descendant based on the ini file settings and the seed provided.
@ -102,7 +102,7 @@ public:
virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) = 0; virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) = 0;
/// Reads parameters from the ini file, prepares generator for use. /** Reads parameters from the ini file, prepares generator for use. */
virtual void InitializeCompoGen(cIniFile & a_IniFile) {} virtual void InitializeCompoGen(cIniFile & a_IniFile) {}
/** Creates the correct TerrainCompositionGen descendant based on the ini file settings and the seed provided. /** Creates the correct TerrainCompositionGen descendant based on the ini file settings and the seed provided.
@ -116,28 +116,12 @@ public:
/** The interface that a structure generator must implement
Structures are generated after the terrain composition took place. It should modify the blocktype data to account
for whatever structures the generator is generating.
Note that ores are considered structures too, at least from the interface point of view.
Also note that a worldgenerator may contain multiple structure generators, one for each type of structure
*/
class cStructureGen
{
public:
virtual ~cStructureGen() {} // Force a virtual destructor in descendants
virtual void GenStructures(cChunkDesc & a_ChunkDesc) = 0;
} ;
typedef std::list<cStructureGen *> cStructureGenList;
/** The interface that a finisher must implement /** The interface that a finisher must implement
Finisher implements small additions after all structures have been generated. Finisher implements changes to the chunk after the rough terrain has been generated.
Examples of finishers are trees, snow, ore, lilypads and others.
Note that a worldgenerator may contain multiple finishers.
Also note that previously we used to distinguish between a structuregen and a finisher; this distinction is
no longer relevant, all structure generators are considered finishers now (#398)
*/ */
class cFinishGen class cFinishGen
{ {
@ -171,7 +155,6 @@ protected:
cBiomeGen * m_BiomeGen; cBiomeGen * m_BiomeGen;
cTerrainHeightGen * m_HeightGen; cTerrainHeightGen * m_HeightGen;
cTerrainCompositionGen * m_CompositionGen; cTerrainCompositionGen * m_CompositionGen;
cStructureGenList m_StructureGens;
cFinishGenList m_FinishGens; cFinishGenList m_FinishGens;
// Generators underlying the caches: // Generators underlying the caches:
@ -180,19 +163,16 @@ protected:
cTerrainCompositionGen * m_UnderlyingCompositionGen; cTerrainCompositionGen * m_UnderlyingCompositionGen;
/// Reads the biome gen settings from the ini and initializes m_BiomeGen accordingly /** Reads the biome gen settings from the ini and initializes m_BiomeGen accordingly */
void InitBiomeGen(cIniFile & a_IniFile); void InitBiomeGen(cIniFile & a_IniFile);
/// Reads the HeightGen settings from the ini and initializes m_HeightGen accordingly /** Reads the HeightGen settings from the ini and initializes m_HeightGen accordingly */
void InitHeightGen(cIniFile & a_IniFile); void InitHeightGen(cIniFile & a_IniFile);
/// Reads the CompositionGen settings from the ini and initializes m_CompositionGen accordingly /** Reads the CompositionGen settings from the ini and initializes m_CompositionGen accordingly */
void InitCompositionGen(cIniFile & a_IniFile); void InitCompositionGen(cIniFile & a_IniFile);
/// Reads the structures to generate from the ini and initializes m_StructureGens accordingly /** Reads the finishers from the ini and initializes m_FinishGens accordingly */
void InitStructureGens(cIniFile & a_IniFile);
/// Reads the finishers from the ini and initializes m_FinishGens accordingly
void InitFinishGens(cIniFile & a_IniFile); void InitFinishGens(cIniFile & a_IniFile);
} ; } ;

View File

@ -88,7 +88,7 @@ void cFinishGenNetherClumpFoliage::GenFinish(cChunkDesc & a_ChunkDesc)
{ {
continue; continue;
} }
if (!g_BlockIsSolid[a_ChunkDesc.GetBlockType(PosX, y - 1, PosZ)]) // Only place on solid blocks if (!cBlockInfo::IsSolid(a_ChunkDesc.GetBlockType(PosX, y - 1, PosZ))) // Only place on solid blocks
{ {
continue; continue;
} }
@ -131,7 +131,7 @@ void cFinishGenNetherClumpFoliage::TryPlaceClump(cChunkDesc & a_ChunkDesc, int a
} }
BLOCKTYPE BlockBelow = a_ChunkDesc.GetBlockType(x, y - 1, z); BLOCKTYPE BlockBelow = a_ChunkDesc.GetBlockType(x, y - 1, z);
if (!g_BlockIsSolid[BlockBelow]) // Only place on solid blocks if (!cBlockInfo::IsSolid(BlockBelow)) // Only place on solid blocks
{ {
continue; continue;
} }
@ -329,7 +329,7 @@ void cFinishGenSnow::GenFinish(cChunkDesc & a_ChunkDesc)
case biFrozenOcean: case biFrozenOcean:
{ {
int Height = a_ChunkDesc.GetHeight(x, z); int Height = a_ChunkDesc.GetHeight(x, z);
if (g_BlockIsSnowable[a_ChunkDesc.GetBlockType(x, Height, z)]) if (cBlockInfo::IsSnowable(a_ChunkDesc.GetBlockType(x, Height, z)))
{ {
a_ChunkDesc.SetBlockType(x, Height + 1, z, E_BLOCK_SNOW); a_ChunkDesc.SetBlockType(x, Height + 1, z, E_BLOCK_SNOW);
a_ChunkDesc.SetHeight(x, z, Height + 1); a_ChunkDesc.SetHeight(x, z, Height + 1);

View File

@ -1407,7 +1407,7 @@ void cStructGenMineShafts::GetMineShaftSystemsForChunk(
void cStructGenMineShafts::GenStructures(cChunkDesc & a_ChunkDesc) void cStructGenMineShafts::GenFinish(cChunkDesc & a_ChunkDesc)
{ {
int ChunkX = a_ChunkDesc.GetChunkX(); int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ(); int ChunkZ = a_ChunkDesc.GetChunkZ();

View File

@ -17,7 +17,7 @@
class cStructGenMineShafts : class cStructGenMineShafts :
public cStructureGen public cFinishGen
{ {
public: public:
cStructGenMineShafts( cStructGenMineShafts(
@ -52,8 +52,8 @@ protected:
*/ */
void GetMineShaftSystemsForChunk(int a_ChunkX, int a_ChunkZ, cMineShaftSystems & a_MineShaftSystems); void GetMineShaftSystemsForChunk(int a_ChunkX, int a_ChunkZ, cMineShaftSystems & a_MineShaftSystems);
// cStructureGen overrides: // cFinishGen overrides:
virtual void GenStructures(cChunkDesc & a_ChunkDesc) override; virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ; } ;

View File

@ -117,7 +117,7 @@ void cStructGenRavines::ClearCache(void)
void cStructGenRavines::GenStructures(cChunkDesc & a_ChunkDesc) void cStructGenRavines::GenFinish(cChunkDesc & a_ChunkDesc)
{ {
int ChunkX = a_ChunkDesc.GetChunkX(); int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ(); int ChunkZ = a_ChunkDesc.GetChunkZ();

View File

@ -17,7 +17,7 @@
class cStructGenRavines : class cStructGenRavines :
public cStructureGen public cFinishGen
{ {
public: public:
cStructGenRavines(int a_Seed, int a_Size); cStructGenRavines(int a_Seed, int a_Size);
@ -37,8 +37,8 @@ protected:
/// Returns all ravines that *may* intersect the given chunk. All the ravines are valid until the next call to this function. /// Returns all ravines that *may* intersect the given chunk. All the ravines are valid until the next call to this function.
void GetRavinesForChunk(int a_ChunkX, int a_ChunkZ, cRavines & a_Ravines); void GetRavinesForChunk(int a_ChunkX, int a_ChunkZ, cRavines & a_Ravines);
// cStructureGen override: // cFinishGen override:
virtual void GenStructures(cChunkDesc & a_ChunkDesc) override; virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ; } ;

View File

@ -54,7 +54,7 @@ const int NEST_SIZE_GRAVEL = 32;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenTrees: // cStructGenTrees:
void cStructGenTrees::GenStructures(cChunkDesc & a_ChunkDesc) void cStructGenTrees::GenFinish(cChunkDesc & a_ChunkDesc)
{ {
int ChunkX = a_ChunkDesc.GetChunkX(); int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ(); int ChunkZ = a_ChunkDesc.GetChunkZ();
@ -306,7 +306,7 @@ int cStructGenTrees::GetNumTrees(
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenOreNests: // cStructGenOreNests:
void cStructGenOreNests::GenStructures(cChunkDesc & a_ChunkDesc) void cStructGenOreNests::GenFinish(cChunkDesc & a_ChunkDesc)
{ {
int ChunkX = a_ChunkDesc.GetChunkX(); int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ(); int ChunkZ = a_ChunkDesc.GetChunkZ();
@ -413,7 +413,7 @@ void cStructGenOreNests::GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_Ore
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenLakes: // cStructGenLakes:
void cStructGenLakes::GenStructures(cChunkDesc & a_ChunkDesc) void cStructGenLakes::GenFinish(cChunkDesc & a_ChunkDesc)
{ {
int ChunkX = a_ChunkDesc.GetChunkX(); int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ(); int ChunkZ = a_ChunkDesc.GetChunkZ();
@ -545,7 +545,7 @@ cStructGenDirectOverhangs::cStructGenDirectOverhangs(int a_Seed) :
void cStructGenDirectOverhangs::GenStructures(cChunkDesc & a_ChunkDesc) void cStructGenDirectOverhangs::GenFinish(cChunkDesc & a_ChunkDesc)
{ {
// If there is no column of the wanted biome, bail out: // If there is no column of the wanted biome, bail out:
if (!HasWantedBiome(a_ChunkDesc)) if (!HasWantedBiome(a_ChunkDesc))
@ -665,7 +665,7 @@ cStructGenDistortedMembraneOverhangs::cStructGenDistortedMembraneOverhangs(int a
void cStructGenDistortedMembraneOverhangs::GenStructures(cChunkDesc & a_ChunkDesc) void cStructGenDistortedMembraneOverhangs::GenFinish(cChunkDesc & a_ChunkDesc)
{ {
const NOISE_DATATYPE Frequency = (NOISE_DATATYPE)16; const NOISE_DATATYPE Frequency = (NOISE_DATATYPE)16;
const NOISE_DATATYPE Amount = (NOISE_DATATYPE)1; const NOISE_DATATYPE Amount = (NOISE_DATATYPE)1;

View File

@ -21,7 +21,7 @@
class cStructGenTrees : class cStructGenTrees :
public cStructureGen public cFinishGen
{ {
public: public:
cStructGenTrees(int a_Seed, cBiomeGen * a_BiomeGen, cTerrainHeightGen * a_HeightGen, cTerrainCompositionGen * a_CompositionGen) : cStructGenTrees(int a_Seed, cBiomeGen * a_BiomeGen, cTerrainHeightGen * a_HeightGen, cTerrainCompositionGen * a_CompositionGen) :
@ -64,8 +64,8 @@ protected:
const cChunkDef::BiomeMap & a_Biomes const cChunkDef::BiomeMap & a_Biomes
); );
// cStructureGen override: // cFinishGen override:
virtual void GenStructures(cChunkDesc & a_ChunkDesc) override; virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ; } ;
@ -73,7 +73,7 @@ protected:
class cStructGenOreNests : class cStructGenOreNests :
public cStructureGen public cFinishGen
{ {
public: public:
cStructGenOreNests(int a_Seed) : m_Noise(a_Seed), m_Seed(a_Seed) {} cStructGenOreNests(int a_Seed) : m_Noise(a_Seed), m_Seed(a_Seed) {}
@ -82,8 +82,8 @@ protected:
cNoise m_Noise; cNoise m_Noise;
int m_Seed; int m_Seed;
// cStructureGen override: // cFinishGen override:
virtual void GenStructures(cChunkDesc & a_ChunkDesc) override; virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
void GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_OreType, int a_MaxHeight, int a_NumNests, int a_NestSize, cChunkDef::BlockTypes & a_BlockTypes, int a_Seq); void GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_OreType, int a_MaxHeight, int a_NumNests, int a_NestSize, cChunkDef::BlockTypes & a_BlockTypes, int a_Seq);
} ; } ;
@ -93,7 +93,7 @@ protected:
class cStructGenLakes : class cStructGenLakes :
public cStructureGen public cFinishGen
{ {
public: public:
cStructGenLakes(int a_Seed, BLOCKTYPE a_Fluid, cTerrainHeightGen & a_HeiGen, int a_Probability) : cStructGenLakes(int a_Seed, BLOCKTYPE a_Fluid, cTerrainHeightGen & a_HeiGen, int a_Probability) :
@ -112,8 +112,8 @@ protected:
cTerrainHeightGen & m_HeiGen; cTerrainHeightGen & m_HeiGen;
int m_Probability; ///< Chance, 0 .. 100, of a chunk having the lake int m_Probability; ///< Chance, 0 .. 100, of a chunk having the lake
// cStructureGen override: // cFinishGen override:
virtual void GenStructures(cChunkDesc & a_ChunkDesc) override; virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
/// Creates a lake image for the specified chunk into a_Lake /// Creates a lake image for the specified chunk into a_Lake
void CreateLakeImage(int a_ChunkX, int a_ChunkZ, cBlockArea & a_Lake); void CreateLakeImage(int a_ChunkX, int a_ChunkZ, cBlockArea & a_Lake);
@ -125,7 +125,7 @@ protected:
class cStructGenDirectOverhangs : class cStructGenDirectOverhangs :
public cStructureGen public cFinishGen
{ {
public: public:
cStructGenDirectOverhangs(int a_Seed); cStructGenDirectOverhangs(int a_Seed);
@ -134,8 +134,8 @@ protected:
cNoise m_Noise1; cNoise m_Noise1;
cNoise m_Noise2; cNoise m_Noise2;
// cStructureGen override: // cFinishGen override:
virtual void GenStructures(cChunkDesc & a_ChunkDesc) override; virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
bool HasWantedBiome(cChunkDesc & a_ChunkDesc) const; bool HasWantedBiome(cChunkDesc & a_ChunkDesc) const;
} ; } ;
@ -145,7 +145,7 @@ protected:
class cStructGenDistortedMembraneOverhangs : class cStructGenDistortedMembraneOverhangs :
public cStructureGen public cFinishGen
{ {
public: public:
cStructGenDistortedMembraneOverhangs(int a_Seed); cStructGenDistortedMembraneOverhangs(int a_Seed);
@ -156,8 +156,8 @@ protected:
cNoise m_NoiseZ; cNoise m_NoiseZ;
cNoise m_NoiseH; cNoise m_NoiseH;
// cStructureGen override: // cFinishGen override:
virtual void GenStructures(cChunkDesc & a_ChunkDesc) override; virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ; } ;

View File

@ -250,6 +250,7 @@ T Clamp(T a_Value, T a_Min, T a_Max)
#include "ChunkDef.h" #include "ChunkDef.h"
#include "BiomeDef.h" #include "BiomeDef.h"
#include "BlockID.h" #include "BlockID.h"
#include "BlockInfo.h"
#include "Entities/Effects.h" #include "Entities/Effects.h"

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

@ -204,6 +204,12 @@ void cInventory::SetSlot(int a_SlotNum, const cItem & a_Item)
return; return;
} }
Grid->SetSlot(GridSlotNum, a_Item); Grid->SetSlot(GridSlotNum, a_Item);
// Broadcast the Equipped Item, if the Slot is changed.
if ((Grid == &m_HotbarSlots) && (m_EquippedSlotNum == (a_SlotNum - invHotbarOffset)))
{
m_Owner.GetWorld()->BroadcastEntityEquipment(m_Owner, 0, a_Item, m_Owner.GetClientHandle());
}
} }

View File

@ -36,10 +36,10 @@ public:
// The map center is fixed at the central point of the 8x8 block of chunks you are standing in when you right-click it. // The map center is fixed at the central point of the 8x8 block of chunks you are standing in when you right-click it.
const int RegionWidth = cChunkDef::Width * 8 * pow(2.0, (double) DEFAULT_SCALE); const int RegionWidth = cChunkDef::Width * 8;
int CenterX = floor(a_Player->GetPosX() / (float) RegionWidth) * RegionWidth; int CenterX = (int)(floor(a_Player->GetPosX() / (float) RegionWidth) * RegionWidth);
int CenterZ = floor(a_Player->GetPosZ() / (float) RegionWidth) * RegionWidth; int CenterZ = (int)(floor(a_Player->GetPosZ() / (float) RegionWidth) * RegionWidth);
cMap * NewMap = a_World->GetMapManager().CreateMap(CenterX, CenterZ, DEFAULT_SCALE); cMap * NewMap = a_World->GetMapManager().CreateMap(CenterX, CenterZ, DEFAULT_SCALE);

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,8 +282,10 @@ 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 = cBlockInfo::GetHandler(Block);
if (a_Player->IsGameModeSurvival()) if (a_Player->IsGameModeSurvival())
{ {
@ -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

@ -19,17 +19,13 @@ public:
{ {
switch(m_ItemType) switch(m_ItemType)
{ {
case E_ITEM_WOODEN_PICKAXE: case E_ITEM_WOODEN_PICKAXE: return 1;
case E_ITEM_GOLD_PICKAXE: case E_ITEM_GOLD_PICKAXE: return 1;
return 1; case E_ITEM_STONE_PICKAXE: return 2;
case E_ITEM_STONE_PICKAXE: case E_ITEM_IRON_PICKAXE: return 3;
return 2; case E_ITEM_DIAMOND_PICKAXE: return 4;
case E_ITEM_IRON_PICKAXE:
return 3; default: return 0;
case E_ITEM_DIAMOND_PICKAXE:
return 4;
default:
return 0;
} }
} }
@ -61,6 +57,10 @@ public:
return PickaxeLevel() >= 2; return PickaxeLevel() >= 2;
} }
case E_BLOCK_ANVIL:
case E_BLOCK_ENCHANTMENT_TABLE:
case E_BLOCK_FURNACE:
case E_BLOCK_LIT_FURNACE:
case E_BLOCK_COAL_ORE: case E_BLOCK_COAL_ORE:
case E_BLOCK_STONE: case E_BLOCK_STONE:
case E_BLOCK_COBBLESTONE: case E_BLOCK_COBBLESTONE:

View File

@ -27,7 +27,7 @@ public:
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override ) override
{ {
if (!g_BlockFullyOccupiesVoxel[a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)]) // Some solid blocks, such as cocoa beans, are not suitable for dust if (!cBlockInfo::FullyOccupiesVoxel(a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ))) // Some solid blocks, such as cocoa beans, are not suitable for dust
{ {
return false; return false;
} }

View File

@ -391,7 +391,7 @@ void cLightingThread::PrepareBlockLight(void)
int idx = BaseZ + x; int idx = BaseZ + x;
for (int y = m_HeightMap[idx], Index = idx + y * BlocksPerYLayer; y >= 0; y--, Index -= BlocksPerYLayer) for (int y = m_HeightMap[idx], Index = idx + y * BlocksPerYLayer; y >= 0; y--, Index -= BlocksPerYLayer)
{ {
if (g_BlockLightValue[m_BlockTypes[Index]] == 0) if (cBlockInfo::GetLightValue(m_BlockTypes[Index]) == 0)
{ {
continue; continue;
} }
@ -401,7 +401,7 @@ void cLightingThread::PrepareBlockLight(void)
m_SeedIdx1[m_NumSeeds++] = Index; m_SeedIdx1[m_NumSeeds++] = Index;
// Light it up: // Light it up:
m_BlockLight[Index] = g_BlockLightValue[m_BlockTypes[Index]]; m_BlockLight[Index] = cBlockInfo::GetLightValue(m_BlockTypes[Index]);
} }
} }
} }

View File

@ -169,13 +169,13 @@ protected:
ASSERT(a_DstIdx >= 0); ASSERT(a_DstIdx >= 0);
ASSERT(a_DstIdx < (int)ARRAYCOUNT(m_BlockTypes)); ASSERT(a_DstIdx < (int)ARRAYCOUNT(m_BlockTypes));
if (a_Light[a_SrcIdx] <= a_Light[a_DstIdx] + g_BlockSpreadLightFalloff[m_BlockTypes[a_DstIdx]]) if (a_Light[a_SrcIdx] <= a_Light[a_DstIdx] + cBlockInfo::GetSpreadLightFalloff(m_BlockTypes[a_DstIdx]))
{ {
// We're not offering more light than the dest block already has // We're not offering more light than the dest block already has
return; return;
} }
a_Light[a_DstIdx] = a_Light[a_SrcIdx] - g_BlockSpreadLightFalloff[m_BlockTypes[a_DstIdx]]; a_Light[a_DstIdx] = a_Light[a_SrcIdx] - cBlockInfo::GetSpreadLightFalloff(m_BlockTypes[a_DstIdx]);
if (!a_IsSeedOut[a_DstIdx]) if (!a_IsSeedOut[a_DstIdx])
{ {
a_IsSeedOut[a_DstIdx] = true; a_IsSeedOut[a_DstIdx] = true;

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

@ -357,6 +357,8 @@ void cMap::AddPlayer(cPlayer * a_Player, Int64 a_WorldAge)
MapClient.m_LastUpdate = a_WorldAge; MapClient.m_LastUpdate = a_WorldAge;
MapClient.m_SendInfo = true; MapClient.m_SendInfo = true;
MapClient.m_Handle = Handle; MapClient.m_Handle = Handle;
MapClient.m_DataUpdate = 0;
MapClient.m_NextDecoratorUpdate = 0;
m_Clients.push_back(MapClient); m_Clients.push_back(MapClient);

View File

@ -145,7 +145,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
case cMonster::mtBat: case cMonster::mtBat:
{ {
return (a_RelY <= 63) && (BlockLight <= 4) && (SkyLight <= 4) && (TargetBlock == E_BLOCK_AIR) && (!g_BlockTransparent[BlockAbove]); return (a_RelY <= 63) && (BlockLight <= 4) && (SkyLight <= 4) && (TargetBlock == E_BLOCK_AIR) && !cBlockInfo::IsTransparent(BlockAbove);
} }
case cMonster::mtChicken: case cMonster::mtChicken:
@ -157,7 +157,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
return ( return (
(TargetBlock == E_BLOCK_AIR) && (TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) &&
(!g_BlockTransparent[BlockBelow]) && (!cBlockInfo::IsTransparent(BlockBelow)) &&
(BlockBelow == E_BLOCK_GRASS) && (BlockBelow == E_BLOCK_GRASS) &&
(SkyLight >= 9) (SkyLight >= 9)
); );
@ -188,7 +188,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
(TargetBlock == E_BLOCK_AIR) && (TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) &&
(BlockTop == E_BLOCK_AIR) && (BlockTop == E_BLOCK_AIR) &&
(!g_BlockTransparent[BlockBelow]) && (!cBlockInfo::IsTransparent(BlockBelow)) &&
(SkyLight <= 7) && (SkyLight <= 7) &&
(BlockLight <= 7) (BlockLight <= 7)
); );
@ -215,7 +215,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
HaveFloor || HaveFloor ||
( (
a_Chunk->UnboundedRelGetBlockType(a_RelX + x, a_RelY - 1, a_RelZ + z, TargetBlock) && a_Chunk->UnboundedRelGetBlockType(a_RelX + x, a_RelY - 1, a_RelZ + z, TargetBlock) &&
!g_BlockTransparent[TargetBlock] !cBlockInfo::IsTransparent(TargetBlock)
) )
); );
} }
@ -230,7 +230,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
return ( return (
(TargetBlock == E_BLOCK_AIR) && (TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) &&
(!g_BlockTransparent[BlockBelow]) && (!cBlockInfo::IsTransparent(BlockBelow)) &&
(SkyLight <= 7) && (SkyLight <= 7) &&
(BlockLight <= 7) && (BlockLight <= 7) &&
(m_Random.NextInt(2, a_Biome) == 0) (m_Random.NextInt(2, a_Biome) == 0)
@ -242,7 +242,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
return ( return (
(TargetBlock == E_BLOCK_AIR) && (TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) &&
(!g_BlockTransparent[BlockBelow]) && (!cBlockInfo::IsTransparent(BlockBelow)) &&
( (
(a_RelY <= 40) || (a_Biome == biSwampland) (a_RelY <= 40) || (a_Biome == biSwampland)
) )
@ -255,7 +255,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
return ( return (
(TargetBlock == E_BLOCK_AIR) && (TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) &&
(!g_BlockTransparent[BlockBelow]) && (!cBlockInfo::IsTransparent(BlockBelow)) &&
(m_Random.NextInt(20, a_Biome) == 0) (m_Random.NextInt(20, a_Biome) == 0)
); );
} }

View File

@ -4,6 +4,7 @@
#include "Creeper.h" #include "Creeper.h"
#include "../World.h" #include "../World.h"
#include "../Entities/ProjectileEntity.h" #include "../Entities/ProjectileEntity.h"
#include "../Entities/Player.h"
@ -13,6 +14,7 @@ cCreeper::cCreeper(void) :
super("Creeper", mtCreeper, "mob.creeper.say", "mob.creeper.say", 0.6, 1.8), super("Creeper", mtCreeper, "mob.creeper.say", "mob.creeper.say", 0.6, 1.8),
m_bIsBlowing(false), m_bIsBlowing(false),
m_bIsCharged(false), m_bIsCharged(false),
m_BurnedWithFlintAndSteel(false),
m_ExplodingTimer(0) m_ExplodingTimer(0)
{ {
} }
@ -25,12 +27,25 @@ void cCreeper::Tick(float a_Dt, cChunk & a_Chunk)
{ {
super::Tick(a_Dt, a_Chunk); super::Tick(a_Dt, a_Chunk);
if (!ReachedFinalDestination()) if (!ReachedFinalDestination() && !m_BurnedWithFlintAndSteel)
{ {
m_ExplodingTimer = 0; m_ExplodingTimer = 0;
m_bIsBlowing = false; m_bIsBlowing = false;
m_World->BroadcastEntityMetadata(*this); m_World->BroadcastEntityMetadata(*this);
} }
else
{
if (m_bIsBlowing)
{
m_ExplodingTimer += 1;
}
if (m_ExplodingTimer == 30)
{
m_World->DoExplosionAt((m_bIsCharged ? 5 : 3), GetPosX(), GetPosY(), GetPosZ(), false, esMonster, this);
Destroy();
}
}
} }
@ -80,22 +95,30 @@ void cCreeper::Attack(float a_Dt)
{ {
UNUSED(a_Dt); UNUSED(a_Dt);
m_ExplodingTimer += 1;
if (!m_bIsBlowing) if (!m_bIsBlowing)
{ {
m_World->BroadcastSoundEffect("game.tnt.primed", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); m_World->BroadcastSoundEffect("game.tnt.primed", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
m_bIsBlowing = true; m_bIsBlowing = true;
m_World->BroadcastEntityMetadata(*this); m_World->BroadcastEntityMetadata(*this);
} }
if (m_ExplodingTimer == 20)
{
m_World->DoExplosionAt((m_bIsCharged ? 5 : 3), GetPosX(), GetPosY(), GetPosZ(), false, esMonster, this);
Destroy();
}
} }
void cCreeper::OnRightClicked(cPlayer & a_Player)
{
if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_FLINT_AND_STEEL))
{
if (!a_Player.IsGameModeCreative())
{
a_Player.UseEquippedItem();
}
m_World->BroadcastSoundEffect("game.tnt.primed", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
m_bIsBlowing = true;
m_World->BroadcastEntityMetadata(*this);
m_BurnedWithFlintAndSteel = true;
}
}

Some files were not shown because too many files have changed in this diff Show More