Merge branch 'master' into BlockEntitys
This commit is contained in:
commit
8316ae330e
@ -3,7 +3,13 @@ compiler:
|
||||
- gcc
|
||||
- clang
|
||||
# Build MCServer
|
||||
script: cmake . -DCMAKE_BUILD_TYPE=RELEASE -DBUILD_TOOLS=1 -DSELF_TEST=1 && make -j 2 && cd MCServer/ && (echo stop | ./MCServer)
|
||||
script: cmake . -DBUILD_TOOLS=1 -DSELF_TEST=1 && make -j 2 && cd MCServer/ && (echo stop | $MCSERVER_PATH)
|
||||
|
||||
env:
|
||||
- TRAVIS_MCSERVER_BUILD_TYPE=RELEASE MCSERVER_PATH=./MCServer
|
||||
- TRAVIS_MCSERVER_BUILD_TYPE=DEBUG MCSERVER_PATH=./MCServer_debug
|
||||
- TRAVIS_MCSERVER_BUILD_TYPE=RELEASE TRAVIS_MCSERVER_FORCE32=1 MCSERVER_PATH=./MCServer
|
||||
- TRAVIS_MCSERVER_BUILD_TYPE=DEBUG TRAVIS_MCSERVER_FORCE32=1 MCSERVER_PATH=./MCServer_debug
|
||||
|
||||
# Notification Settings
|
||||
notifications:
|
||||
|
@ -3,6 +3,17 @@ cmake_minimum_required (VERSION 2.6)
|
||||
# Without this, the MSVC variable isn't defined for MSVC builds ( http://www.cmake.org/pipermail/cmake/2011-November/047130.html )
|
||||
enable_language(CXX C)
|
||||
|
||||
# These env variables are used for configuring Travis CI builds.
|
||||
# See https://github.com/mc-server/MCServer/pull/767
|
||||
if(DEFINED ENV{TRAVIS_MCSERVER_BUILD_TYPE})
|
||||
message("Setting build type to $ENV{TRAVIS_MCSERVER_BUILD_TYPE}")
|
||||
set(CMAKE_BUILD_TYPE $ENV{TRAVIS_MCSERVER_BUILD_TYPE})
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{TRAVIS_MCSERVER_FORCE32})
|
||||
set(FORCE32 $ENV{TRAVIS_MCSERVER_FORCE32})
|
||||
endif()
|
||||
|
||||
# This has to be done before any flags have been set up.
|
||||
if(${BUILD_TOOLS})
|
||||
add_subdirectory(Tools/MCADefrag/)
|
||||
|
@ -1,7 +1,7 @@
|
||||
Code Stuff
|
||||
----------
|
||||
|
||||
* We use C++03
|
||||
* We use C++03 with some C++11 extensions (ask if you think that something would be useful)
|
||||
* Use the provided wrappers for OS stuff:
|
||||
- Threading is done by inheriting from `cIsThread`, thread synchronization through `cCriticalSection`, `cSemaphore` and `cEvent`, file access and filesystem operations through the `cFile` class, high-precision timers through `cTimer`, high-precision sleep through `cSleep`
|
||||
* No magic numbers, use named constants:
|
||||
@ -22,8 +22,10 @@ Code Stuff
|
||||
- This helps prevent mistakes such as `if (a & 1 == 0)`
|
||||
* White space is free, so use it freely
|
||||
- "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.
|
||||
- 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)
|
||||
* Use doxy-comments for functions in the header file, format as `/** Description */`
|
||||
* Use spaces after the comment markers: `// Comment` instead of `//Comment`
|
||||
|
6
MCServer/.gitignore
vendored
6
MCServer/.gitignore
vendored
@ -19,10 +19,8 @@ schematics
|
||||
*.pdb
|
||||
memdump*
|
||||
*.grab
|
||||
Galleries.cfg
|
||||
Galleries.example.cfg
|
||||
Galleries.sqlite
|
||||
ProtectionAreas.sqlite
|
||||
*.cfg
|
||||
*.sqlite
|
||||
helgrind.log
|
||||
valgrind.log
|
||||
motd.txt
|
||||
|
@ -114,7 +114,7 @@ g_APIDesc =
|
||||
GetBlockSkyLight = { Params = "BlockX, BlockY, BlockZ", Return = "NIBBLETYPE", Notes = "Returns the skylight at the specified absolute coords" },
|
||||
GetBlockType = { Params = "BlockX, BlockY, BlockZ", Return = "BLOCKTYPE", Notes = "Returns the block type at the specified absolute coords" },
|
||||
GetBlockTypeMeta = { Params = "BlockX, BlockY, BlockZ", Return = "BLOCKTYPE, NIBBLETYPE", Notes = "Returns the block type and meta at the specified absolute coords" },
|
||||
GetDataTypes = { Params = "", Return = "number", Notes = "Returns the mask of datatypes that the objectis currently holding" },
|
||||
GetDataTypes = { Params = "", Return = "number", Notes = "Returns the mask of datatypes that the object is currently holding" },
|
||||
GetOrigin = { Params = "", Return = "OriginX, OriginY, OriginZ", Notes = "Returns the origin coords of where the area was read from." },
|
||||
GetOriginX = { Params = "", Return = "number", Notes = "Returns the origin x-coord" },
|
||||
GetOriginY = { Params = "", Return = "number", Notes = "Returns the origin y-coord" },
|
||||
@ -129,6 +129,7 @@ g_APIDesc =
|
||||
GetSizeY = { Params = "", Return = "number", Notes = "Returns the size of the held data in the y-axis" },
|
||||
GetSizeZ = { Params = "", Return = "number", Notes = "Returns the size of the held data in the z-axis" },
|
||||
GetVolume = { Params = "", Return = "number", Notes = "Returns the volume of the area - the total number of blocks stored within." },
|
||||
GetWEOffset = { Params = "", Return = "{{Vector3i}}", Notes = "Returns the WE offset, a data value sometimes stored in the schematic files. MCServer doesn't use this value, but provides access to it using this method. The default is {0, 0, 0}."},
|
||||
HasBlockLights = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include blocklight" },
|
||||
HasBlockMetas = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include block metas" },
|
||||
HasBlockSkyLights = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include skylight" },
|
||||
@ -178,6 +179,11 @@ g_APIDesc =
|
||||
SetRelBlockSkyLight = { Params = "RelBlockX, RelBlockY, RelBlockZ, SkyLight", Return = "", Notes = "Sets the skylight at the specified relative coords" },
|
||||
SetRelBlockType = { Params = "RelBlockX, RelBlockY, RelBlockZ, BlockType", Return = "", Notes = "Sets the block type at the specified relative coords" },
|
||||
SetRelBlockTypeMeta = { Params = "RelBlockX, RelBlockY, RelBlockZ, BlockType, BlockMeta", Return = "", Notes = "Sets the block type and meta at the specified relative coords" },
|
||||
SetWEOffset =
|
||||
{
|
||||
{ Params = "{{Vector3i|Offset}}", Return = "", Notes = "Sets the WE offset, a data value sometimes stored in the schematic files. Mostly used for WorldEdit. MCServer doesn't use this value, but provides access to it using this method." },
|
||||
{ Params = "OffsetX, OffsetY, OffsetZ", Return = "", Notes = "Sets the WE offset, a data value sometimes stored in the schematic files. Mostly used for WorldEdit. MCServer doesn't use this value, but provides access to it using this method." },
|
||||
},
|
||||
Write =
|
||||
{
|
||||
{ Params = "World, {{Vector3i|MinPoint}}, DataTypes", Return = "bool", Notes = "Writes the area into World at the specified coords, returns true if successful" },
|
||||
@ -417,6 +423,7 @@ g_APIDesc =
|
||||
SetUseDefaultFinish = { Params = "bool", Return = "", Notes = "Sets the chunk to use default finishers or not" },
|
||||
SetUseDefaultHeight = { Params = "bool", Return = "", Notes = "Sets the chunk to use default height generator or not" },
|
||||
SetUseDefaultStructures = { Params = "bool", Return = "", Notes = "Sets the chunk to use default structures or not" },
|
||||
UpdateHeightmap = { Params = "", Return = "", Notes = "Updates the heightmap to match current contents. The plugins should do that if they modify the contents and don't modify the heightmap accordingly; MCServer expects (and checks in Debug mode) that the heightmap matches the contents when the cChunkDesc is returned from a plugin." },
|
||||
WriteBlockArea = { Params = "{{cBlockArea|BlockArea}}, MinRelX, MinRelY, MinRelZ", Return = "", Notes = "Writes data from the block area into the chunk" },
|
||||
},
|
||||
AdditionalInfo =
|
||||
@ -466,6 +473,7 @@ end
|
||||
|
||||
Functions =
|
||||
{
|
||||
GetLocale = { Params = "", Return = "Locale", Notes = "Returns the locale string that the client sends as part of the protocol handshake. Can be used to provide localized strings." },
|
||||
GetPing = { Params = "", Return = "number", Notes = "Returns the ping time, in ms" },
|
||||
GetPlayer = { Params = "", Return = "{{cPlayer|cPlayer}}", Notes = "Returns the player object connected to this client. Note that this may be nil, for example if the player object is not yet spawned." },
|
||||
GetUniqueID = { Params = "", Return = "number", Notes = "Returns the UniqueID of the client used to identify the client in the server" },
|
||||
@ -474,6 +482,7 @@ end
|
||||
HasPluginChannel = { Params = "ChannelName", Return = "bool", Notes = "Returns true if the client has registered to receive messages on the specified plugin channel." },
|
||||
Kick = { Params = "Reason", Return = "", Notes = "Kicks the user with the specified reason" },
|
||||
SendPluginMessage = { Params = "Channel, Message", Return = "", Notes = "Sends the plugin message on the specified channel." },
|
||||
SetLocale = { Params = "Locale", Return = "", Notes = "Sets the locale that MCServer keeps on record. Initially the locale is initialized in protocol handshake, this function allows plugins to override the stored value (but only server-side and only until the user disconnects)." },
|
||||
SetUsername = { Params = "Name", Return = "", Notes = "Sets the username" },
|
||||
SetViewDistance = { Params = "ViewDistance", Return = "", Notes = "Sets the viewdistance (number of chunks loaded for the player in each direction)" },
|
||||
SendBlockChange = { Params = "BlockX, BlockY, BlockZ, BlockType, BlockMeta", Return = "", Notes = "Sends a BlockChange packet to the client. This can be used to create fake blocks only for that player." },
|
||||
@ -877,7 +886,6 @@ cFile:Delete("/usr/bin/virus.exe");
|
||||
SetColor = { Return = "" },
|
||||
GetColor = { Return = "string" },
|
||||
AddCommand = { Return = "" },
|
||||
HasCommand = { Return = "bool" },
|
||||
AddPermission = { Return = "" },
|
||||
InheritFrom = { Return = "" },
|
||||
},
|
||||
@ -1144,7 +1152,6 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
|
||||
IsEnchantable = { Params = "", Return = "bool", Notes = "Returns true if the item is enchantable" },
|
||||
IsFullStack = { Params = "", Return = "bool", Notes = "Returns true if the item is stacked up to its maximum stacking" },
|
||||
IsSameType = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is of the same ItemType as the one stored in the object. This is true even if the two items have different enchantments" },
|
||||
IsStackableWith = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is stackable with the one stored in the object. Two items with different enchantments cannot be stacked" },
|
||||
IsBothNameAndLoreEmpty = { Params = "", Return = "bool", Notes = "Returns if both the custom name and lore are not set." },
|
||||
IsCustomNameEmpty = { Params = "", Return = "bool", Notes = "Returns if the custom name of the cItem is empty." },
|
||||
IsLoreEmpty = { Params = "", Return = "", Notes = "Returns if the lore of the cItem is empty." },
|
||||
@ -1650,7 +1657,6 @@ a_Player:OpenWindow(Window);
|
||||
AddToGroup = { Params = "GroupName", Return = "", Notes = "Temporarily adds the player to the specified group. The assignment is lost when the player disconnects." },
|
||||
CalcLevelFromXp = { Params = "XPAmount", Return = "number", Notes = "(STATIC) Returns the level which is reached with the specified amount of XP. Inverse of XpForLevel()." },
|
||||
CanFly = { Return = "bool", Notes = "Returns if the player is able to fly." },
|
||||
CanUseCommand = { Params = "Command", Return = "bool", Notes = "Returns true if the player is allowed to use the specified command." },
|
||||
CloseWindow = { Params = "[CanRefuse]", Return = "", Notes = "Closes the currently open UI window. If CanRefuse is true (default), the window may refuse the closing." },
|
||||
CloseWindowIfID = { Params = "WindowID, [CanRefuse]", Return = "", Notes = "Closes the currently open UI window if its ID matches the given ID. If CanRefuse is true (default), the window may refuse the closing." },
|
||||
DeltaExperience = { Params = "DeltaXP", Return = "", Notes = "Adds or removes XP from the current XP amount. Won't allow XP to go negative. Returns the new experience, -1 on error (XP overflow)." },
|
||||
@ -1727,7 +1733,6 @@ a_Player:OpenWindow(Window);
|
||||
SetSprint = { Params = "IsSprinting", Return = "", Notes = "Sets whether the player is sprinting or not." },
|
||||
SetSprintingMaxSpeed = { Params = "SprintingMaxSpeed", Return = "", Notes = "Sets the sprinting maximum speed (as reported by the 1.6.1+ protocols)" },
|
||||
SetVisible = { Params = "IsVisible", Return = "", Notes = "Sets the player visibility to other players" },
|
||||
TossItem = { Params = "DraggedItem, [Amount], [CreateType], [CreateDamage]", Return = "", Notes = "FIXME: This function will be rewritten, avoid it. It tosses an item, either from the inventory, dragged in hand (while in UI window) or a newly created one." },
|
||||
XpForLevel = { Params = "XPLevel", Return = "number", Notes = "(STATIC) Returns the total amount of XP needed for the specified XP level. Inverse of CalcLevelFromXp()." },
|
||||
},
|
||||
Constants =
|
||||
@ -1789,13 +1794,13 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
|
||||
},
|
||||
BindCommand =
|
||||
{
|
||||
{ Params = "Command, Permission, Callback, HelpString", Return = "", Notes = "(STATIC) Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display." },
|
||||
{ Params = "Command, Permission, Callback, HelpString", Return = "", Notes = "Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display." },
|
||||
{ Params = "Command, Permission, Callback, HelpString", Return = "[bool]", Notes = "(STATIC) Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display. Returns true if successful, logs to console and returns no value on error." },
|
||||
{ Params = "Command, Permission, Callback, HelpString", Return = "[bool]", Notes = "Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display. Returns true if successful, logs to console and returns no value on error." },
|
||||
},
|
||||
BindConsoleCommand =
|
||||
{
|
||||
{ Params = "Command, Callback, HelpString", Return = "", Notes = "(STATIC) Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command." },
|
||||
{ Params = "Command, Callback, HelpString", Return = "", Notes = "Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command." },
|
||||
{ Params = "Command, Callback, HelpString", Return = "[bool]", Notes = "(STATIC) Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command. Returns true if successful, logs to console and returns no value on error." },
|
||||
{ Params = "Command, Callback, HelpString", Return = "[bool]", Notes = "Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command. Returns true if successful, logs to console and returns no value on error." },
|
||||
},
|
||||
CallPlugin = { Params = "PluginName, FunctionName, [FunctionArgs...]", Return = "[FunctionRets]", Notes = "(STATIC) Calls the specified function in the specified plugin, passing all the given arguments to it. If it succeeds, it returns all the values returned by that function. If it fails, returns no value at all. Note that only strings, numbers, bools, nils and classes can be used for parameters and return values; tables and functions cannot be copied across plugins." },
|
||||
DisablePlugin = { Params = "PluginName", Return = "bool", Notes = "Disables a plugin specified by its name. Returns true if the plugin was disabled, false if it wasn't found or wasn't active." },
|
||||
@ -2624,7 +2629,8 @@ end
|
||||
]],
|
||||
Functions =
|
||||
{
|
||||
AddFaceDirection = {Params = "BlockX, BlockY, BlockZ, BlockFace, [IsInverse]", Return = "BlockX, BlockY, BlockZ", Notes = "Returns the coords of a block adjacent to the specified block through the specified {{Globals#BlockFace|face}}"},
|
||||
AddFaceDirection = {Params = "BlockX, BlockY, BlockZ, BlockFace, [IsInverse]", Return = "BlockX, BlockY, BlockZ", Notes = "Returns the coords of a block adjacent to the specified block through the specified {{Globals#BlockFaces|face}}"},
|
||||
BlockFaceToString = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "string", Notes = "Returns the string representation of the {{Globals#BlockFaces|eBlockFace}} constant. Uses the axis-direction-based names, such as BLOCK_FACE_XP." },
|
||||
BlockStringToType = {Params = "BlockTypeString", Return = "BLOCKTYPE", Notes = "Returns the block type parsed from the given string"},
|
||||
ClickActionToString = {Params = "{{Globals#ClickAction|ClickAction}}", Return = "string", Notes = "Returns a string description of the ClickAction enumerated value"},
|
||||
DamageTypeToString = {Params = "{{Globals#DamageType|DamageType}}", Return = "string", Notes = "Converts the {{Globals#DamageType|DamageType}} enumerated value to a string representation "},
|
||||
@ -2643,9 +2649,12 @@ end
|
||||
LOGINFO = {Params = "string", Notes = "Logs a text into the server console using 'info' severity (yellow text)"},
|
||||
LOGWARN = {Params = "string", Notes = "Logs a text into the server console using 'warning' severity (red text); OBSOLETE, use LOGWARNING() instead"},
|
||||
LOGWARNING = {Params = "string", Notes = "Logs a text into the server console using 'warning' severity (red text)"},
|
||||
MirrorBlockFaceY = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "{{Globals#BlockFaces|eBlockFace}}", Notes = "Returns the {{Globals#BlockFaces|eBlockFace}} that corresponds to the given {{Globals#BlockFaces|eBlockFace}} after mirroring it around the Y axis (or rotating 180 degrees around it)." },
|
||||
NoCaseCompare = {Params = "string, string", Return = "number", Notes = "Case-insensitive string comparison; returns 0 if the strings are the same"},
|
||||
NormalizeAngleDegrees = { Params = "AngleDegrees", Return = "AngleDegrees", Notes = "Returns the angle, wrapped into the [-180, +180) range." },
|
||||
ReplaceString = {Params = "full-string, to-be-replaced-string, to-replace-string", Notes = "Replaces *each* occurence of to-be-replaced-string in full-string with to-replace-string"},
|
||||
RotateBlockFaceCCW = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "{{Globals#BlockFaces|eBlockFace}}", Notes = "Returns the {{Globals#BlockFaces|eBlockFace}} that corresponds to the given {{Globals#BlockFaces|eBlockFace}} after rotating it around the Y axis 90 degrees counter-clockwise." },
|
||||
RotateBlockFaceCW = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "{{Globals#BlockFaces|eBlockFace}}", Notes = "Returns the {{Globals#BlockFaces|eBlockFace}} that corresponds to the given {{Globals#BlockFaces|eBlockFace}} after rotating it around the Y axis 90 degrees clockwise." },
|
||||
StringSplit = {Params = "string, SeperatorsString", Return = "array table of strings", Notes = "Seperates string into multiple by splitting every time any of the characters in SeperatorsString is encountered."},
|
||||
StringSplitAndTrim = {Params = "string, SeperatorsString", Return = "array table of strings", Notes = "Seperates string into multiple by splitting every time any of the characters in SeperatorsString is encountered. Each of the separate strings is trimmed (whitespace removed from the beginning and end of the string)"},
|
||||
StringToBiome = {Params = "string", Return = "{{Globals#BiomeTypes|BiomeType}}", Notes = "Converts a string representation to a {{Globals#BiomeTypes|BiomeType}} enumerated value"},
|
||||
@ -2692,7 +2701,13 @@ end
|
||||
Include = "^BLOCK_FACE_.*",
|
||||
TextBefore = [[
|
||||
These constants are used to describe individual faces of the block. They are used when the
|
||||
client is interacting with a block, or when the {{cLineBlockTracer}} hits a block, etc.
|
||||
client is interacting with a block in the {{OnPlayerBreakingBlock|HOOK_PLAYER_BREAKING_BLOCK}},
|
||||
{{OnPlayerBrokenBlock|HOOK_PLAYER_BROKEN_BLOCK}}, {{OnPlayerLeftClick|HOOK_PLAYER_LEFT_CLICK}},
|
||||
{{OnPlayerPlacedBlock|HOOK_PLAYER_PLACED_BLOCK}}, {{OnPlayerPlacingBlock|HOOK_PLAYER_PLACING_BLOCK}},
|
||||
{{OnPlayerRightClick|HOOK_PLAYER_RIGHT_CLICK}}, {{OnPlayerUsedBlock|HOOK_PLAYER_USED_BLOCK}},
|
||||
{{OnPlayerUsedItem|HOOK_PLAYER_USED_ITEM}}, {{OnPlayerUsingBlock|HOOK_PLAYER_USING_BLOCK}},
|
||||
and {{OnPlayerUsingItem|HOOK_PLAYER_USING_ITEM}} hooks, or when the {{cLineBlockTracer}} hits a
|
||||
block, etc.
|
||||
]],
|
||||
},
|
||||
ClickAction =
|
||||
|
@ -76,6 +76,7 @@ return
|
||||
DifY = { Params = "", Return = "number", Notes = "Returns the difference between the two Y coords (Y-size minus 1). Assumes sorted." },
|
||||
DifZ = { Params = "", Return = "number", Notes = "Returns the difference between the two Z coords (Z-size minus 1). Assumes sorted." },
|
||||
DoesIntersect = { Params = "OtherCuboid", Return = "bool", Notes = "Returns true if this cuboid has at least one voxel in common with OtherCuboid. Note that edges are considered inclusive. Assumes both sorted." },
|
||||
Engulf = { Params = "{{Vector3i|Point}}", Return = "", Notes = "If needed, expands the cuboid to include the specified point. Doesn't shrink. Assumes sorted. " },
|
||||
Expand = { Params = "SubMinX, AddMaxX, SubMinY, AddMaxY, SubMinZ, AddMaxZ", Return = "", Notes = "Expands the cuboid by the specified amount in each direction. Works on unsorted cuboids as well. NOTE: this function doesn't check for underflows." },
|
||||
GetVolume = { Params = "", Return = "number", Notes = "Returns the volume of the cuboid, in blocks. Note that the volume considers both coords inclusive. Works on unsorted cuboids, too." },
|
||||
IsCompletelyInside = { Params = "OuterCuboid", Return = "bool", Notes = "Returns true if this cuboid is completely inside (in all directions) in OuterCuboid. Assumes both sorted." },
|
||||
@ -308,6 +309,7 @@ end
|
||||
},
|
||||
Equals = { Params = "Vector3i", Return = "bool", Notes = "Returns true if this vector is exactly the same as the specified vector." },
|
||||
Length = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector." },
|
||||
Move = { Params = "X, Y, Z", Return = "", Notes = "Moves the vector by the specified amount in each axis direction." },
|
||||
Set = { Params = "x, y, z", Return = "", Notes = "Sets all the coords of the vector at once" },
|
||||
SqrLength = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector, squared. This operation is slightly less computationally expensive than Length(), while it conserves some properties of Length(), such as comparison." },
|
||||
},
|
||||
|
@ -9,22 +9,6 @@
|
||||
-- Global variables:
|
||||
g_Plugin = nil;
|
||||
g_PluginFolder = "";
|
||||
g_TrackedPages = {}; -- List of tracked pages, to be checked later whether they exist. Each item is an array of referring pagenames.
|
||||
g_Stats = -- Statistics about the documentation
|
||||
{
|
||||
NumTotalClasses = 0,
|
||||
NumUndocumentedClasses = 0,
|
||||
NumTotalFunctions = 0,
|
||||
NumUndocumentedFunctions = 0,
|
||||
NumTotalConstants = 0,
|
||||
NumUndocumentedConstants = 0,
|
||||
NumTotalVariables = 0,
|
||||
NumUndocumentedVariables = 0,
|
||||
NumTotalHooks = 0,
|
||||
NumUndocumentedHooks = 0,
|
||||
NumTrackedLinks = 0,
|
||||
NumInvalidLinks = 0,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -33,15 +17,34 @@ g_Stats = -- Statistics about the documentation
|
||||
|
||||
function Initialize(Plugin)
|
||||
g_Plugin = Plugin;
|
||||
|
||||
Plugin:SetName("APIDump");
|
||||
Plugin:SetVersion(1);
|
||||
g_PluginFolder = Plugin:GetLocalFolder();
|
||||
|
||||
LOG("Initialising " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
|
||||
|
||||
g_PluginFolder = Plugin:GetLocalFolder();
|
||||
cPluginManager:BindConsoleCommand("api", HandleCmdApi, "Dumps the Lua API docs into the API/ subfolder")
|
||||
g_Plugin:AddWebTab("APIDump", HandleWebAdminDump)
|
||||
-- TODO: Add a WebAdmin tab that has a Dump button
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function HandleCmdApi(a_Split)
|
||||
DumpApi()
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function DumpApi()
|
||||
LOG("Dumping the API...")
|
||||
|
||||
-- Load the API descriptions from the Classes and Hooks subfolders:
|
||||
-- This needs to be done each time the command is invoked because the export modifies the tables' contents
|
||||
dofile(g_PluginFolder .. "/APIDesc.lua")
|
||||
if (g_APIDesc.Classes == nil) then
|
||||
g_APIDesc.Classes = {};
|
||||
end
|
||||
@ -51,6 +54,24 @@ function Initialize(Plugin)
|
||||
LoadAPIFiles("/Classes/", g_APIDesc.Classes);
|
||||
LoadAPIFiles("/Hooks/", g_APIDesc.Hooks);
|
||||
|
||||
-- Reset the stats:
|
||||
g_TrackedPages = {}; -- List of tracked pages, to be checked later whether they exist. Each item is an array of referring pagenames.
|
||||
g_Stats = -- Statistics about the documentation
|
||||
{
|
||||
NumTotalClasses = 0,
|
||||
NumUndocumentedClasses = 0,
|
||||
NumTotalFunctions = 0,
|
||||
NumUndocumentedFunctions = 0,
|
||||
NumTotalConstants = 0,
|
||||
NumUndocumentedConstants = 0,
|
||||
NumTotalVariables = 0,
|
||||
NumUndocumentedVariables = 0,
|
||||
NumTotalHooks = 0,
|
||||
NumUndocumentedHooks = 0,
|
||||
NumTrackedLinks = 0,
|
||||
NumInvalidLinks = 0,
|
||||
}
|
||||
|
||||
-- dump all available API functions and objects:
|
||||
-- DumpAPITxt();
|
||||
|
||||
@ -58,7 +79,6 @@ function Initialize(Plugin)
|
||||
DumpAPIHtml();
|
||||
|
||||
LOG("APIDump finished");
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
@ -67,6 +87,9 @@ end
|
||||
|
||||
|
||||
function LoadAPIFiles(a_Folder, a_DstTable)
|
||||
assert(type(a_Folder) == "string")
|
||||
assert(type(a_DstTable) == "table")
|
||||
|
||||
local Folder = g_PluginFolder .. a_Folder;
|
||||
for idx, fnam in ipairs(cFile:GetFolderContents(Folder)) do
|
||||
local FileName = Folder .. fnam;
|
||||
@ -317,6 +340,11 @@ end
|
||||
function DumpAPIHtml()
|
||||
LOG("Dumping all available functions and constants to API subfolder...");
|
||||
|
||||
-- Create the output folder
|
||||
if not(cFile:IsFolder("API")) then
|
||||
cFile:CreateFolder("API");
|
||||
end
|
||||
|
||||
LOG("Copying static files..");
|
||||
cFile:CreateFolder("API/Static");
|
||||
local localFolder = g_Plugin:GetLocalFolder();
|
||||
@ -366,11 +394,6 @@ function DumpAPIHtml()
|
||||
ReadDescriptions(API);
|
||||
ReadHooks(Hooks);
|
||||
|
||||
-- Create the output folder
|
||||
if not(cFile:IsFolder("API")) then
|
||||
cFile:CreateFolder("API");
|
||||
end
|
||||
|
||||
-- Create a "class index" file, write each class as a link to that file,
|
||||
-- then dump class contents into class-specific file
|
||||
LOG("Writing HTML files...");
|
||||
@ -1428,3 +1451,18 @@ end
|
||||
|
||||
|
||||
|
||||
|
||||
function HandleWebAdminDump(a_Request)
|
||||
if (a_Request.PostParams["Dump"] ~= nil) then
|
||||
DumpApi()
|
||||
end
|
||||
return
|
||||
[[
|
||||
<p>Pressing the button will generate the API dump on the server. Note that this can take some time.</p>
|
||||
<form method="POST"><input type="submit" name="Dump" value="Dump the API"/></form>
|
||||
]]
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 3b416b07a339b3abcbc127070d56eea05b05373d
|
||||
Subproject commit 013a32a7fb3c8a6cfe0aef892d4c7394d4e1be59
|
@ -39,6 +39,7 @@
|
||||
#
|
||||
|
||||
# Need to list each of the four log types, otherwise all logs would get converted into apple planks (^0)
|
||||
|
||||
ApplePlanks, 4 = AppleLog, *
|
||||
ConiferPlanks, 4 = ConiferLog, *
|
||||
BirchPlanks, 4 = BirchLog, *
|
||||
@ -434,6 +435,55 @@ GoldNugget, 9 = GoldIngot, *
|
||||
EnchantmentTable = Obsidian, 1:3, 2:3, 3:3, 2:2 | Diamond, 1:2, 3:2 | Book, 2:1
|
||||
|
||||
|
||||
#******************************************************#
|
||||
# Fireworks & Co.
|
||||
# (Best not to add non-vanilla items to this as it will cause internal firework data handling code to log warnings)
|
||||
|
||||
# Ballistic firework rockets - plain and with firework star, all with 1 - 3 gunpowder
|
||||
FireworkRocket = Paper, * | Gunpowder, *
|
||||
FireworkRocket = Paper, * | Gunpowder, * | Gunpowder, *
|
||||
FireworkRocket = Paper, * | Gunpowder, * | Gunpowder, * | Gunpowder, *
|
||||
FireworkRocket = FireworkStar, * | Paper, * | Gunpowder, *
|
||||
FireworkRocket = FireworkStar, * | Paper, * | Gunpowder, * | Gunpowder, *
|
||||
FireworkRocket = FireworkStar, * | Paper, * | Gunpowder, * | Gunpowder, * | Gunpowder, *
|
||||
|
||||
# Radioactive firework stars
|
||||
# Plain powder and dye
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, *
|
||||
|
||||
# Powder and effect, with effect combining
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Diamond, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Glowdust, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Glowdust, * | Diamond, *
|
||||
|
||||
# Powder and shape (no shape combining possible)
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Firecharge, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Goldnugget, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Feather, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | SkeletonHead ^-1, *
|
||||
|
||||
# Power and shape (no shape combining possible), combined with effect
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Firecharge, * | Diamond, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Firecharge, * | Glowdust, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Goldnugget, * | Diamond, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Goldnugget, * | Glowdust, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Feather, * | Diamond, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Feather, * | Glowdust, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | SkeletonHead ^-1, * | Diamond, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | SkeletonHead ^-1, * | Glowdust, *
|
||||
|
||||
# Power and shape (no shape combining possible), combined with effect (with effect combining)
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Firecharge, * | Glowdust, * | Diamond, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Goldnugget, * | Glowdust, * | Diamond, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | Feather, * | Glowdust, * | Diamond, *
|
||||
FireworkStar = Gunpowder, * | Dye ^-1, * | SkeletonHead ^-1, * | Glowdust, * | Diamond, *
|
||||
|
||||
# Star fade colour-change
|
||||
FireworkStar = FireworkStar, * | Dye ^-1, *
|
||||
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, *
|
||||
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
|
||||
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
|
||||
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
|
||||
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
|
||||
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
|
||||
FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
|
||||
|
@ -182,14 +182,23 @@ macro(set_exe_flags)
|
||||
string(REPLACE "-w" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
|
||||
string(REPLACE "-w" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
string(REPLACE "-w" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
|
||||
add_flags_cxx("-Wall -Wextra")
|
||||
add_flags_cxx("-Wall -Wextra -Wno-unused-parameter -Wno-error=switch")
|
||||
|
||||
# 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")
|
||||
# clang does not provide the __extern_always_inline macro and a part of libm depends on this when using fast-math
|
||||
add_flags_cxx("-D__extern_always_inline=inline")
|
||||
add_flags_cxx("-Werror -Weverything -Wno-c++98-compat-pedantic -Wno-string-conversion")
|
||||
add_flags_cxx("-Wno-extra-semi -Wno-error=switch-enum -Wno-documentation")
|
||||
add_flags_cxx("-Wno-error=sign-conversion -Wno-error=conversion -Wno-padded")
|
||||
add_flags_cxx("-Wno-error=deprecated -Wno-error=weak-vtables -Wno-error=float-equal")
|
||||
add_flags_cxx("-Wno-error=missing-prototypes -Wno-error=non-virtual-dtor")
|
||||
add_flags_cxx("-Wno-error=covered-switch-default -Wno-error=shadow")
|
||||
add_flags_cxx("-Wno-error=exit-time-destructors -Wno-error=missing-variable-declarations")
|
||||
add_flags_cxx("-Wno-error=global-constructors -Wno-implicit-fallthrough")
|
||||
add_flags_cxx("-Wno-error=unreachable-code")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -37,7 +37,8 @@
|
||||
|
||||
// Some portability macros :)
|
||||
#define stricmp strcasecmp
|
||||
|
||||
|
||||
#define FORMATSTRING(formatIndex,va_argsIndex)
|
||||
#else
|
||||
|
||||
#error "You are using an unsupported compiler, you might need to #define some stuff here for your compiler"
|
||||
@ -58,6 +59,8 @@
|
||||
#define ALIGN_8
|
||||
#define ALIGN_16
|
||||
*/
|
||||
|
||||
#define FORMATSTRING(formatIndex,va_argsIndex) __attribute__((format (printf, formatIndex, va_argsIndex)))
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -131,8 +131,6 @@
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define MAX_ENC_LEN 1024
|
||||
|
||||
|
||||
|
||||
@ -473,14 +471,14 @@ bool cConnection::SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a
|
||||
|
||||
|
||||
|
||||
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, int a_Size, const char * a_Peer)
|
||||
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer)
|
||||
{
|
||||
DataLog(a_Data, a_Size, "Encrypting %d bytes to %s", a_Size, a_Peer);
|
||||
const Byte * Data = (const Byte *)a_Data;
|
||||
while (a_Size > 0)
|
||||
{
|
||||
Byte Buffer[64 KiB];
|
||||
int NumBytes = (a_Size > sizeof(Buffer)) ? sizeof(Buffer) : a_Size;
|
||||
size_t NumBytes = (a_Size > sizeof(Buffer)) ? sizeof(Buffer) : a_Size;
|
||||
a_Encryptor.ProcessData(Buffer, Data, NumBytes);
|
||||
bool res = SendData(a_Socket, (const char *)Buffer, NumBytes, a_Peer);
|
||||
if (!res)
|
||||
@ -2263,7 +2261,9 @@ bool cConnection::HandleServerSpawnObjectVehicle(void)
|
||||
HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, DataIndicator);
|
||||
AString ExtraData;
|
||||
short VelocityX, VelocityY, VelocityZ;
|
||||
short VelocityX = 0;
|
||||
short VelocityY = 0;
|
||||
short VelocityZ = 0;
|
||||
if (DataIndicator != 0)
|
||||
{
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, SpeedX);
|
||||
@ -2697,7 +2697,7 @@ bool cConnection::ParseMetadata(cByteBuffer & a_Buffer, AString & a_Metadata)
|
||||
a_Metadata.push_back(x);
|
||||
while (x != 0x7f)
|
||||
{
|
||||
int Index = ((unsigned)((unsigned char)x)) & 0x1f; // Lower 5 bits = index
|
||||
// int Index = ((unsigned)((unsigned char)x)) & 0x1f; // Lower 5 bits = index
|
||||
int Type = ((unsigned)((unsigned char)x)) >> 5; // Upper 3 bits = type
|
||||
int Length = 0;
|
||||
switch (Type)
|
||||
@ -2772,7 +2772,7 @@ void cConnection::LogMetadata(const AString & a_Metadata, size_t a_IndentCount)
|
||||
{
|
||||
int Index = ((unsigned)((unsigned char)a_Metadata[pos])) & 0x1f; // Lower 5 bits = index
|
||||
int Type = ((unsigned)((unsigned char)a_Metadata[pos])) >> 5; // Upper 3 bits = type
|
||||
int Length = 0;
|
||||
// int Length = 0;
|
||||
switch (Type)
|
||||
{
|
||||
case 0:
|
||||
@ -2827,7 +2827,7 @@ void cConnection::LogMetadata(const AString & a_Metadata, size_t a_IndentCount)
|
||||
ASSERT(!"Cannot parse item description from metadata");
|
||||
return;
|
||||
}
|
||||
int After = bb.GetReadableSpace();
|
||||
// int After = bb.GetReadableSpace();
|
||||
int BytesConsumed = BytesLeft - bb.GetReadableSpace();
|
||||
|
||||
Log("%sslot[%d] = %s (%d bytes)", Indent.c_str(), Index, ItemDesc.c_str(), BytesConsumed);
|
||||
|
@ -109,7 +109,7 @@ protected:
|
||||
bool SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a_Peer);
|
||||
|
||||
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
|
||||
bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, int a_Size, const char * a_Peer);
|
||||
bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer);
|
||||
|
||||
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
|
||||
bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer);
|
||||
|
@ -37,6 +37,8 @@
|
||||
|
||||
// Some portability macros :)
|
||||
#define stricmp strcasecmp
|
||||
|
||||
#define FORMATSTRING(formatIndex,va_argsIndex)
|
||||
|
||||
#else
|
||||
|
||||
@ -59,6 +61,9 @@
|
||||
#define ALIGN_16
|
||||
*/
|
||||
|
||||
#define FORMATSTRING(formatIndex,va_argsIndex) __attribute__((format (printf, formatIndex, va_argsIndex)))
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -233,4 +238,4 @@ public:
|
||||
|
||||
#define LOGERROR printf
|
||||
#define LOGINFO printf
|
||||
#define LOGWARNING printf
|
||||
#define LOGWARNING printf
|
||||
|
@ -11,6 +11,7 @@ typedef unsigned int UInt32;
|
||||
typedef unsigned short UInt16;
|
||||
|
||||
|
||||
$cfile "../Vector3.h"
|
||||
$cfile "../ChunkDef.h"
|
||||
$cfile "../BiomeDef.h"
|
||||
|
||||
@ -62,10 +63,6 @@ $cfile "../BlockEntities/MobHeadEntity.h"
|
||||
$cfile "../BlockEntities/FlowerPotEntity.h"
|
||||
$cfile "../WebAdmin.h"
|
||||
$cfile "../Root.h"
|
||||
$cfile "../Vector3f.h"
|
||||
$cfile "../Vector3d.h"
|
||||
$cfile "../Vector3i.h"
|
||||
$cfile "../Matrix4f.h"
|
||||
$cfile "../Cuboid.h"
|
||||
$cfile "../BoundingBox.h"
|
||||
$cfile "../Tracer.h"
|
||||
@ -97,4 +94,10 @@ typedef unsigned char Byte;
|
||||
|
||||
|
||||
|
||||
// Aliases
|
||||
$renaming Vector3<double> @ Vector3d
|
||||
$renaming Vector3<float> @ Vector3f
|
||||
$renaming Vector3<int> @ Vector3i
|
||||
|
||||
|
||||
|
||||
|
@ -94,12 +94,20 @@ void cLuaState::Create(void)
|
||||
}
|
||||
m_LuaState = lua_open();
|
||||
luaL_openlibs(m_LuaState);
|
||||
m_IsOwned = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cLuaState::RegisterAPILibs(void)
|
||||
{
|
||||
tolua_AllToLua_open(m_LuaState);
|
||||
ManualBindings::Bind(m_LuaState);
|
||||
DeprecatedBindings::Bind(m_LuaState);
|
||||
luaopen_lsqlite3(m_LuaState);
|
||||
luaopen_lxp(m_LuaState);
|
||||
m_IsOwned = true;
|
||||
}
|
||||
|
||||
|
||||
@ -677,6 +685,7 @@ void cLuaState::Push(Vector3i * a_Vector)
|
||||
|
||||
void cLuaState::Push(void * a_Ptr)
|
||||
{
|
||||
UNUSED(a_Ptr);
|
||||
ASSERT(IsValid());
|
||||
|
||||
// Investigate the cause of this - what is the callstack?
|
||||
@ -733,10 +742,6 @@ void cLuaState::GetStackValue(int a_StackPos, AString & a_Value)
|
||||
{
|
||||
a_Value.assign(data, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
a_Value.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1280,7 +1285,9 @@ void cLuaState::LogStack(lua_State * a_LuaState, const char * a_Header)
|
||||
{
|
||||
UNUSED(a_Header); // The param seems unused when compiling for release, so the compiler warns
|
||||
|
||||
LOGD((a_Header != NULL) ? a_Header : "Lua C API Stack contents:");
|
||||
|
||||
// Format string consisting only of %s is used to appease the compiler
|
||||
LOGD("%s",(a_Header != NULL) ? a_Header : "Lua C API Stack contents:");
|
||||
for (int i = lua_gettop(a_LuaState); i > 0; i--)
|
||||
{
|
||||
AString Value;
|
||||
|
@ -29,6 +29,8 @@ extern "C"
|
||||
#include "lua/src/lauxlib.h"
|
||||
}
|
||||
|
||||
#include "../Vector3.h"
|
||||
|
||||
|
||||
|
||||
|
||||
@ -52,7 +54,6 @@ class cWebAdmin;
|
||||
struct HTTPTemplateRequest;
|
||||
class cTNTEntity;
|
||||
class cCreeper;
|
||||
class Vector3i;
|
||||
class cHopperEntity;
|
||||
class cBlockEntity;
|
||||
|
||||
@ -139,9 +140,14 @@ public:
|
||||
/** Allows this object to be used in the same way as a lua_State *, for example in the LuaLib functions */
|
||||
operator lua_State * (void) { return m_LuaState; }
|
||||
|
||||
/** Creates the m_LuaState, if not closed already. This state will be automatically closed in the destructor */
|
||||
/** Creates the m_LuaState, if not closed already. This state will be automatically closed in the destructor.
|
||||
The regular Lua libs are registered, but the MCS API is not registered (so that Lua can be used as
|
||||
lite-config as well), use RegisterAPILibs() to do that. */
|
||||
void Create(void);
|
||||
|
||||
/** Registers all the API libraries that MCS provides into m_LuaState. */
|
||||
void RegisterAPILibs(void);
|
||||
|
||||
/** Closes the m_LuaState, if not closed already */
|
||||
void Close(void);
|
||||
|
||||
@ -194,7 +200,7 @@ public:
|
||||
void Push(const HTTPTemplateRequest * a_Request);
|
||||
void Push(cTNTEntity * a_TNTEntity);
|
||||
void Push(Vector3i * a_Vector);
|
||||
void Push(void * a_Ptr);
|
||||
NORETURNDEBUG void Push(void * a_Ptr);
|
||||
void Push(cHopperEntity * a_Hopper);
|
||||
void Push(cBlockEntity * a_BlockEntity);
|
||||
|
||||
|
@ -1497,7 +1497,8 @@ static int tolua_cPluginManager_BindCommand(lua_State * L)
|
||||
}
|
||||
|
||||
Plugin->BindCommand(Command, FnRef);
|
||||
return 0;
|
||||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@ -1521,7 +1522,10 @@ static int tolua_cPluginManager_BindConsoleCommand(lua_State * L)
|
||||
// Read the arguments to this API call:
|
||||
tolua_Error tolua_err;
|
||||
int idx = 1;
|
||||
if (tolua_isusertype(L, 1, "cPluginManager", 0, &tolua_err))
|
||||
if (
|
||||
tolua_isusertype(L, 1, "cPluginManager", 0, &tolua_err) ||
|
||||
tolua_isusertable(L, 1, "cPluginManager", 0, &tolua_err)
|
||||
)
|
||||
{
|
||||
idx++;
|
||||
}
|
||||
@ -1561,7 +1565,8 @@ static int tolua_cPluginManager_BindConsoleCommand(lua_State * L)
|
||||
}
|
||||
|
||||
Plugin->BindConsoleCommand(Command, FnRef);
|
||||
return 0;
|
||||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -75,6 +75,7 @@ bool cPluginLua::Initialize(void)
|
||||
if (!m_LuaState.IsValid())
|
||||
{
|
||||
m_LuaState.Create();
|
||||
m_LuaState.RegisterAPILibs();
|
||||
|
||||
// Inject the identification global variables into the state:
|
||||
lua_pushlightuserdata(m_LuaState, this);
|
||||
|
@ -168,6 +168,7 @@ cBlockArea::cBlockArea(void) :
|
||||
m_SizeX(0),
|
||||
m_SizeY(0),
|
||||
m_SizeZ(0),
|
||||
m_WEOffset(0, 0, 0),
|
||||
m_BlockTypes(NULL),
|
||||
m_BlockMetas(NULL),
|
||||
m_BlockLight(NULL),
|
||||
@ -254,6 +255,24 @@ void cBlockArea::Create(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes)
|
||||
|
||||
|
||||
|
||||
void cBlockArea::SetWEOffset(int a_OffsetX, int a_OffsetY, int a_OffsetZ)
|
||||
{
|
||||
m_WEOffset.Set(a_OffsetX, a_OffsetY, a_OffsetZ);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cBlockArea::SetWEOffset(const Vector3i & a_Offset)
|
||||
{
|
||||
m_WEOffset.Set(a_Offset.x, a_Offset.y, a_Offset.z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cBlockArea::SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ)
|
||||
{
|
||||
m_OriginX = a_OriginX;
|
||||
|
@ -13,13 +13,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "ForEachChunkProvider.h"
|
||||
#include "Vector3.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// fwd:
|
||||
class cCuboid;
|
||||
class Vector3i;
|
||||
|
||||
|
||||
|
||||
@ -209,6 +209,8 @@ public:
|
||||
void SetBlockLight (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockLight);
|
||||
void SetRelBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockSkyLight);
|
||||
void SetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockSkyLight);
|
||||
void SetWEOffset (int a_OffsetX, int a_OffsetY, int a_OffsetZ);
|
||||
void SetWEOffset (const Vector3i & a_Offset);
|
||||
|
||||
// Getters:
|
||||
BLOCKTYPE GetRelBlockType (int a_RelX, int a_RelY, int a_RelZ) const;
|
||||
@ -219,6 +221,7 @@ public:
|
||||
NIBBLETYPE GetBlockLight (int a_BlockX, int a_BlockY, int a_BlockZ) const;
|
||||
NIBBLETYPE GetRelBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ) const;
|
||||
NIBBLETYPE GetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ) const;
|
||||
const Vector3i & GetWEOffset (void) const {return m_WEOffset;}
|
||||
|
||||
void SetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
||||
void SetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
||||
@ -299,6 +302,10 @@ protected:
|
||||
int m_SizeY;
|
||||
int m_SizeZ;
|
||||
|
||||
/** An extra data value sometimes stored in the .schematic file. Used mainly by the WorldEdit plugin.
|
||||
cBlockArea doesn't use this value in any way. */
|
||||
Vector3i m_WEOffset;
|
||||
|
||||
BLOCKTYPE * m_BlockTypes;
|
||||
NIBBLETYPE * m_BlockMetas; // Each meta is stored as a separate byte for faster access
|
||||
NIBBLETYPE * m_BlockLight; // Each light value is stored as a separate byte for faster access
|
||||
|
@ -42,8 +42,6 @@ cBlockInfo::~cBlockInfo()
|
||||
|
||||
cBlockInfo & cBlockInfo::Get(BLOCKTYPE a_Type)
|
||||
{
|
||||
ASSERT(a_Type < 256);
|
||||
|
||||
return ms_Info[a_Type];
|
||||
}
|
||||
|
||||
@ -271,6 +269,11 @@ void cBlockInfo::Initialize(void)
|
||||
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:
|
||||
@ -309,6 +312,10 @@ void cBlockInfo::Initialize(void)
|
||||
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:
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "BlockHandler.h"
|
||||
#include "ChunkInterface.h"
|
||||
#include "WorldInterface.h"
|
||||
#include "MetaRotater.h"
|
||||
#include "../Entities/Player.h"
|
||||
|
||||
|
||||
@ -11,11 +12,11 @@
|
||||
|
||||
|
||||
class cBlockBedHandler :
|
||||
public cBlockHandler
|
||||
public cMetaRotater<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>
|
||||
{
|
||||
public:
|
||||
cBlockBedHandler(BLOCKTYPE a_BlockType)
|
||||
: cBlockHandler(a_BlockType)
|
||||
: cMetaRotater<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01,true>(a_BlockType)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -2,16 +2,17 @@
|
||||
|
||||
#include "BlockHandler.h"
|
||||
#include "Chunk.h"
|
||||
#include "MetaRotater.h"
|
||||
|
||||
|
||||
|
||||
|
||||
class cBlockButtonHandler :
|
||||
public cBlockHandler
|
||||
public cMetaRotater<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>
|
||||
{
|
||||
public:
|
||||
cBlockButtonHandler(BLOCKTYPE a_BlockType)
|
||||
: cBlockHandler(a_BlockType)
|
||||
: cMetaRotater<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>(a_BlockType)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -4,17 +4,18 @@
|
||||
#include "BlockEntity.h"
|
||||
#include "../BlockArea.h"
|
||||
#include "../Entities/Player.h"
|
||||
#include "MetaRotater.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cBlockChestHandler :
|
||||
public cBlockEntityHandler
|
||||
public cMetaRotater<cBlockEntityHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>
|
||||
{
|
||||
public:
|
||||
cBlockChestHandler(BLOCKTYPE a_BlockType)
|
||||
: cBlockEntityHandler(a_BlockType)
|
||||
: cMetaRotater<cBlockEntityHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>(a_BlockType)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -3,17 +3,18 @@
|
||||
|
||||
#include "BlockHandler.h"
|
||||
#include "BlockRedstoneRepeater.h"
|
||||
#include "MetaRotater.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cBlockComparatorHandler :
|
||||
public cBlockHandler
|
||||
public cMetaRotater<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>
|
||||
{
|
||||
public:
|
||||
cBlockComparatorHandler(BLOCKTYPE a_BlockType)
|
||||
: cBlockHandler(a_BlockType)
|
||||
: cMetaRotater<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>(a_BlockType)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
|
||||
cBlockDoorHandler::cBlockDoorHandler(BLOCKTYPE a_BlockType)
|
||||
: cBlockHandler(a_BlockType)
|
||||
: super(a_BlockType)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -4,13 +4,15 @@
|
||||
#include "BlockHandler.h"
|
||||
#include "../Entities/Player.h"
|
||||
#include "Chunk.h"
|
||||
#include "MetaRotater.h"
|
||||
|
||||
|
||||
|
||||
|
||||
class cBlockDoorHandler :
|
||||
public cBlockHandler
|
||||
public cMetaRotater<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true>
|
||||
{
|
||||
typedef cMetaRotater<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true> super;
|
||||
public:
|
||||
cBlockDoorHandler(BLOCKTYPE a_BlockType);
|
||||
|
||||
@ -168,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);
|
||||
}
|
||||
}
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -6,17 +6,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Piston.h"
|
||||
#include "MetaRotater.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cBlockDropSpenserHandler :
|
||||
public cBlockEntityHandler
|
||||
public cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
|
||||
{
|
||||
public:
|
||||
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());
|
||||
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;
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -2,17 +2,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "BlockEntity.h"
|
||||
|
||||
#include "MetaRotater.h"
|
||||
|
||||
|
||||
|
||||
|
||||
class cBlockEnderchestHandler :
|
||||
public cBlockEntityHandler
|
||||
public cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
|
||||
{
|
||||
public:
|
||||
cBlockEnderchestHandler(BLOCKTYPE a_BlockType)
|
||||
: cBlockEntityHandler(a_BlockType)
|
||||
: cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -2,17 +2,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "BlockHandler.h"
|
||||
|
||||
#include "MetaRotater.h"
|
||||
|
||||
|
||||
|
||||
|
||||
class cBlockFenceGateHandler :
|
||||
public cBlockHandler
|
||||
public cMetaRotater<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>
|
||||
{
|
||||
public:
|
||||
cBlockFenceGateHandler(BLOCKTYPE a_BlockType) :
|
||||
cBlockHandler(a_BlockType)
|
||||
cMetaRotater<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -146,6 +146,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE 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_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_LOG: return new cBlockSidewaysHandler (a_BlockType);
|
||||
case E_BLOCK_NOTE_BLOCK: return new cBlockNoteHandler (a_BlockType);
|
||||
|
@ -23,6 +23,8 @@ class cBlockHandler
|
||||
{
|
||||
public:
|
||||
cBlockHandler(BLOCKTYPE a_BlockType);
|
||||
|
||||
virtual ~cBlockHandler() {}
|
||||
|
||||
/// Called when the block gets ticked either by a random tick or by a queued tick.
|
||||
/// Note that the coords are chunk-relative!
|
||||
|
@ -2,17 +2,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "BlockHandler.h"
|
||||
|
||||
#include "MetaRotater.h"
|
||||
|
||||
|
||||
|
||||
|
||||
class cBlockStairsHandler :
|
||||
public cBlockHandler
|
||||
public cMetaRotater<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>
|
||||
{
|
||||
public:
|
||||
cBlockStairsHandler(BLOCKTYPE a_BlockType) :
|
||||
cBlockHandler(a_BlockType)
|
||||
cMetaRotater<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>(a_BlockType)
|
||||
{
|
||||
|
||||
}
|
||||
@ -25,6 +25,14 @@ public:
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
UNUSED(a_ChunkInterface);
|
||||
UNUSED(a_BlockX);
|
||||
UNUSED(a_BlockY);
|
||||
UNUSED(a_BlockZ);
|
||||
UNUSED(a_CursorX);
|
||||
UNUSED(a_CursorY);
|
||||
UNUSED(a_CursorZ);
|
||||
UNUSED(a_BlockMeta);
|
||||
a_BlockType = m_BlockType;
|
||||
a_BlockMeta = RotationToMetaData(a_Player->GetYaw());
|
||||
switch (a_BlockFace)
|
||||
@ -96,54 +104,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
|
||||
{
|
||||
// Toggle bit 3:
|
||||
@ -151,20 +111,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;
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -2,17 +2,17 @@
|
||||
|
||||
#include "BlockHandler.h"
|
||||
#include "../Chunk.h"
|
||||
|
||||
#include "MetaRotater.h"
|
||||
|
||||
|
||||
|
||||
|
||||
class cBlockTorchHandler :
|
||||
public cBlockHandler
|
||||
public cMetaRotater<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>
|
||||
{
|
||||
public:
|
||||
cBlockTorchHandler(BLOCKTYPE a_BlockType)
|
||||
: cBlockHandler(a_BlockType)
|
||||
: cMetaRotater<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>(a_BlockType)
|
||||
{
|
||||
}
|
||||
|
||||
@ -185,67 +185,6 @@ public:
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BlockHandler.h"
|
||||
|
||||
#include "MetaRotater.h"
|
||||
|
||||
|
||||
|
||||
@ -24,6 +23,10 @@ public:
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
UNUSED(a_Player);
|
||||
UNUSED(a_CursorX);
|
||||
UNUSED(a_CursorY);
|
||||
UNUSED(a_CursorZ);
|
||||
// TODO: Disallow placement where the vine doesn't attach to something properly
|
||||
BLOCKTYPE BlockType = 0;
|
||||
NIBBLETYPE BlockMeta;
|
||||
@ -162,11 +165,17 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void OnUpdate(cWorld * a_World, int X, int Y, int Z)
|
||||
virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
|
||||
{
|
||||
if (a_World->GetBlock(X, Y - 1, Z) == E_BLOCK_AIR)
|
||||
UNUSED(a_ChunkInterface);
|
||||
UNUSED(a_WorldInterface);
|
||||
UNUSED(a_BlockPluginInterface);
|
||||
|
||||
BLOCKTYPE Block;
|
||||
a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY - 1, a_RelZ, Block);
|
||||
if (Block == E_BLOCK_AIR)
|
||||
{
|
||||
a_World->SetBlock(X, Y - 1, Z, E_BLOCK_VINES, a_World->GetBlockMeta(X, Y, Z));
|
||||
a_Chunk.UnboundedRelSetBlock(a_RelX, a_RelY - 1, a_RelZ, E_BLOCK_VINES, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,8 +189,8 @@ public:
|
||||
{
|
||||
return ((a_Meta << 1) | (a_Meta >> 3)) & 0x0f; // Rotate bits to the left
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
// Bits 2 and 4 stay, bits 1 and 3 swap
|
||||
@ -194,6 +203,7 @@ public:
|
||||
// Bits 1 and 3 stay, bits 2 and 4 swap
|
||||
return ((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2));
|
||||
}
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
120
src/Blocks/MetaRotater.h
Normal file
120
src/Blocks/MetaRotater.h
Normal file
@ -0,0 +1,120 @@
|
||||
// MetaRotater.h
|
||||
|
||||
// Provides a mixin for rotations and reflections
|
||||
|
||||
#pragma once
|
||||
|
||||
// MSVC generates warnings for the templated AssertIfNotMatched parameter conditions, so disable it:
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4127) // Conditional expression is constant
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
|
||||
|
||||
#if SELF_TEST
|
||||
#ifdef SELF_TEST
|
||||
|
||||
/** A simple self-test that is executed on program start, used to verify bbox functionality */
|
||||
static class SelfTest_BoundingBox
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Vector3d.h"
|
||||
#include "Vector3.h"
|
||||
#include "Defines.h"
|
||||
|
||||
|
||||
|
@ -44,10 +44,10 @@
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
#ifdef SELF_TEST
|
||||
|
||||
/// Self-test of the VarInt-reading and writing code
|
||||
class cByteBufferSelfTest
|
||||
static class cByteBufferSelfTest
|
||||
{
|
||||
public:
|
||||
cByteBufferSelfTest(void)
|
||||
@ -62,11 +62,11 @@ public:
|
||||
cByteBuffer buf(50);
|
||||
buf.Write("\x05\xac\x02\x00", 4);
|
||||
UInt32 v1;
|
||||
assert(buf.ReadVarInt(v1) && (v1 == 5));
|
||||
assert_test(buf.ReadVarInt(v1) && (v1 == 5));
|
||||
UInt32 v2;
|
||||
assert(buf.ReadVarInt(v2) && (v2 == 300));
|
||||
assert_test(buf.ReadVarInt(v2) && (v2 == 300));
|
||||
UInt32 v3;
|
||||
assert(buf.ReadVarInt(v3) && (v3 == 0));
|
||||
assert_test(buf.ReadVarInt(v3) && (v3 == 0));
|
||||
}
|
||||
|
||||
void TestWrite(void)
|
||||
@ -77,8 +77,8 @@ public:
|
||||
buf.WriteVarInt(0);
|
||||
AString All;
|
||||
buf.ReadAll(All);
|
||||
assert(All.size() == 4);
|
||||
assert(memcmp(All.data(), "\x05\xac\x02\x00", All.size()) == 0);
|
||||
assert_test(All.size() == 4);
|
||||
assert_test(memcmp(All.data(), "\x05\xac\x02\x00", All.size()) == 0);
|
||||
}
|
||||
|
||||
void TestWrap(void)
|
||||
@ -86,18 +86,18 @@ public:
|
||||
cByteBuffer buf(3);
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
int FreeSpace = buf.GetFreeSpace();
|
||||
assert(buf.GetReadableSpace() == 0);
|
||||
assert(FreeSpace > 0);
|
||||
assert(buf.Write("a", 1));
|
||||
assert(buf.CanReadBytes(1));
|
||||
assert(buf.GetReadableSpace() == 1);
|
||||
size_t FreeSpace = buf.GetFreeSpace();
|
||||
assert_test(buf.GetReadableSpace() == 0);
|
||||
assert_test(FreeSpace > 0);
|
||||
assert_test(buf.Write("a", 1));
|
||||
assert_test(buf.CanReadBytes(1));
|
||||
assert_test(buf.GetReadableSpace() == 1);
|
||||
unsigned char v = 0;
|
||||
assert(buf.ReadByte(v));
|
||||
assert(v == 'a');
|
||||
assert(buf.GetReadableSpace() == 0);
|
||||
assert_test(buf.ReadByte(v));
|
||||
assert_test(v == 'a');
|
||||
assert_test(buf.GetReadableSpace() == 0);
|
||||
buf.CommitRead();
|
||||
assert(buf.GetFreeSpace() == FreeSpace); // We're back to normal
|
||||
assert_test(buf.GetFreeSpace() == FreeSpace); // We're back to normal
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,21 +171,22 @@ cByteBuffer::~cByteBuffer()
|
||||
|
||||
|
||||
|
||||
bool cByteBuffer::Write(const char * a_Bytes, int a_Count)
|
||||
bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
|
||||
{
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
|
||||
// Store the current free space for a check after writing:
|
||||
int CurFreeSpace = GetFreeSpace();
|
||||
int CurReadableSpace = GetReadableSpace();
|
||||
int WrittenBytes = 0;
|
||||
size_t CurFreeSpace = GetFreeSpace();
|
||||
size_t CurReadableSpace = GetReadableSpace();
|
||||
size_t WrittenBytes = 0;
|
||||
|
||||
if (CurFreeSpace < a_Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int TillEnd = m_BufferSize - m_WritePos;
|
||||
ASSERT(m_BufferSize >= m_WritePos);
|
||||
size_t TillEnd = m_BufferSize - m_WritePos;
|
||||
if (TillEnd <= a_Count)
|
||||
{
|
||||
// Need to wrap around the ringbuffer end
|
||||
@ -216,16 +217,20 @@ bool cByteBuffer::Write(const char * a_Bytes, int a_Count)
|
||||
|
||||
|
||||
|
||||
int cByteBuffer::GetFreeSpace(void) const
|
||||
size_t cByteBuffer::GetFreeSpace(void) const
|
||||
{
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
if (m_WritePos >= m_DataStart)
|
||||
{
|
||||
// Wrap around the buffer end:
|
||||
ASSERT(m_BufferSize >= m_WritePos);
|
||||
ASSERT((m_BufferSize - m_WritePos + m_DataStart) >= 1);
|
||||
return m_BufferSize - m_WritePos + m_DataStart - 1;
|
||||
}
|
||||
// Single free space partition:
|
||||
ASSERT(m_BufferSize >= m_WritePos);
|
||||
ASSERT(m_BufferSize - m_WritePos >= 1);
|
||||
return m_DataStart - m_WritePos - 1;
|
||||
}
|
||||
|
||||
@ -234,10 +239,12 @@ int cByteBuffer::GetFreeSpace(void) const
|
||||
|
||||
|
||||
/// Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes()
|
||||
int cByteBuffer::GetUsedSpace(void) const
|
||||
size_t cByteBuffer::GetUsedSpace(void) const
|
||||
{
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
ASSERT(m_BufferSize >= GetFreeSpace());
|
||||
ASSERT((m_BufferSize - GetFreeSpace()) >= 1);
|
||||
return m_BufferSize - GetFreeSpace() - 1;
|
||||
}
|
||||
|
||||
@ -246,16 +253,18 @@ int cByteBuffer::GetUsedSpace(void) const
|
||||
|
||||
|
||||
/// Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already)
|
||||
int cByteBuffer::GetReadableSpace(void) const
|
||||
size_t cByteBuffer::GetReadableSpace(void) const
|
||||
{
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
if (m_ReadPos > m_WritePos)
|
||||
{
|
||||
// Wrap around the buffer end:
|
||||
ASSERT(m_BufferSize >= m_ReadPos);
|
||||
return m_BufferSize - m_ReadPos + m_WritePos;
|
||||
}
|
||||
// Single readable space partition:
|
||||
ASSERT(m_WritePos >= m_ReadPos);
|
||||
return m_WritePos - m_ReadPos ;
|
||||
}
|
||||
|
||||
@ -263,7 +272,7 @@ int cByteBuffer::GetReadableSpace(void) const
|
||||
|
||||
|
||||
|
||||
bool cByteBuffer::CanReadBytes(int a_Count) const
|
||||
bool cByteBuffer::CanReadBytes(size_t a_Count) const
|
||||
{
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
@ -274,7 +283,7 @@ bool cByteBuffer::CanReadBytes(int a_Count) const
|
||||
|
||||
|
||||
|
||||
bool cByteBuffer::CanWriteBytes(int a_Count) const
|
||||
bool cByteBuffer::CanWriteBytes(size_t a_Count) const
|
||||
{
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
@ -450,7 +459,7 @@ bool cByteBuffer::ReadVarUTF8String(AString & a_Value)
|
||||
}
|
||||
if (Size > MAX_STRING_SIZE)
|
||||
{
|
||||
LOGWARNING("%s: String too large: %llu (%llu KiB)", __FUNCTION__, Size, Size / 1024);
|
||||
LOGWARNING("%s: String too large: %u (%u KiB)", __FUNCTION__, Size, Size / 1024);
|
||||
}
|
||||
return ReadString(a_Value, (int)Size);
|
||||
}
|
||||
@ -650,15 +659,14 @@ bool cByteBuffer::WriteLEInt(int a_Value)
|
||||
|
||||
|
||||
|
||||
bool cByteBuffer::ReadBuf(void * a_Buffer, int a_Count)
|
||||
bool cByteBuffer::ReadBuf(void * a_Buffer, size_t a_Count)
|
||||
{
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
ASSERT(a_Count >= 0);
|
||||
NEEDBYTES(a_Count);
|
||||
char * Dst = (char *)a_Buffer; // So that we can do byte math
|
||||
int BytesToEndOfBuffer = m_BufferSize - m_ReadPos;
|
||||
ASSERT(BytesToEndOfBuffer >= 0); // Sanity check
|
||||
ASSERT(m_BufferSize >= m_ReadPos);
|
||||
size_t BytesToEndOfBuffer = m_BufferSize - m_ReadPos;
|
||||
if (BytesToEndOfBuffer <= a_Count)
|
||||
{
|
||||
// Reading across the ringbuffer end, read the first part and adjust parameters:
|
||||
@ -684,14 +692,14 @@ bool cByteBuffer::ReadBuf(void * a_Buffer, int a_Count)
|
||||
|
||||
|
||||
|
||||
bool cByteBuffer::WriteBuf(const void * a_Buffer, int a_Count)
|
||||
bool cByteBuffer::WriteBuf(const void * a_Buffer, size_t a_Count)
|
||||
{
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
ASSERT(a_Count >= 0);
|
||||
PUTBYTES(a_Count);
|
||||
char * Src = (char *)a_Buffer; // So that we can do byte math
|
||||
int BytesToEndOfBuffer = m_BufferSize - m_WritePos;
|
||||
ASSERT(m_BufferSize >= m_ReadPos);
|
||||
size_t BytesToEndOfBuffer = m_BufferSize - m_WritePos;
|
||||
if (BytesToEndOfBuffer <= a_Count)
|
||||
{
|
||||
// Reading across the ringbuffer end, read the first part and adjust parameters:
|
||||
@ -714,22 +722,22 @@ bool cByteBuffer::WriteBuf(const void * a_Buffer, int a_Count)
|
||||
|
||||
|
||||
|
||||
bool cByteBuffer::ReadString(AString & a_String, int a_Count)
|
||||
bool cByteBuffer::ReadString(AString & a_String, size_t a_Count)
|
||||
{
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
ASSERT(a_Count >= 0);
|
||||
NEEDBYTES(a_Count);
|
||||
a_String.clear();
|
||||
a_String.reserve(a_Count);
|
||||
int BytesToEndOfBuffer = m_BufferSize - m_ReadPos;
|
||||
ASSERT(BytesToEndOfBuffer >= 0); // Sanity check
|
||||
ASSERT(m_BufferSize >= m_ReadPos);
|
||||
size_t BytesToEndOfBuffer = m_BufferSize - m_ReadPos;
|
||||
if (BytesToEndOfBuffer <= a_Count)
|
||||
{
|
||||
// Reading across the ringbuffer end, read the first part and adjust parameters:
|
||||
if (BytesToEndOfBuffer > 0)
|
||||
{
|
||||
a_String.assign(m_Buffer + m_ReadPos, BytesToEndOfBuffer);
|
||||
ASSERT(a_Count >= BytesToEndOfBuffer);
|
||||
a_Count -= BytesToEndOfBuffer;
|
||||
}
|
||||
m_ReadPos = 0;
|
||||
@ -759,7 +767,7 @@ bool cByteBuffer::ReadUTF16String(AString & a_String, int a_NumChars)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
RawBEToUTF8((short *)(RawData.data()), a_NumChars, a_String);
|
||||
RawBEToUTF8(RawData.data(), a_NumChars, a_String);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -767,11 +775,10 @@ bool cByteBuffer::ReadUTF16String(AString & a_String, int a_NumChars)
|
||||
|
||||
|
||||
|
||||
bool cByteBuffer::SkipRead(int a_Count)
|
||||
bool cByteBuffer::SkipRead(size_t a_Count)
|
||||
{
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
ASSERT(a_Count >= 0);
|
||||
if (!CanReadBytes(a_Count))
|
||||
{
|
||||
return false;
|
||||
@ -809,6 +816,7 @@ bool cByteBuffer::ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes)
|
||||
size_t num = (a_NumBytes > sizeof(buf)) ? sizeof(buf) : a_NumBytes;
|
||||
VERIFY(ReadBuf(buf, num));
|
||||
VERIFY(a_Dst.Write(buf, num));
|
||||
ASSERT(a_NumBytes >= num);
|
||||
a_NumBytes -= num;
|
||||
}
|
||||
return true;
|
||||
@ -846,13 +854,15 @@ void cByteBuffer::ReadAgain(AString & a_Out)
|
||||
// Used by ProtoProxy to repeat communication twice, once for parsing and the other time for the remote party
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
int DataStart = m_DataStart;
|
||||
size_t DataStart = m_DataStart;
|
||||
if (m_ReadPos < m_DataStart)
|
||||
{
|
||||
// Across the ringbuffer end, read the first part and adjust next part's start:
|
||||
ASSERT(m_BufferSize >= m_DataStart);
|
||||
a_Out.append(m_Buffer + m_DataStart, m_BufferSize - m_DataStart);
|
||||
DataStart = 0;
|
||||
}
|
||||
ASSERT(m_ReadPos >= DataStart);
|
||||
a_Out.append(m_Buffer + DataStart, m_ReadPos - DataStart);
|
||||
}
|
||||
|
||||
@ -860,7 +870,7 @@ void cByteBuffer::ReadAgain(AString & a_Out)
|
||||
|
||||
|
||||
|
||||
void cByteBuffer::AdvanceReadPos(int a_Count)
|
||||
void cByteBuffer::AdvanceReadPos(size_t a_Count)
|
||||
{
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
|
@ -31,25 +31,25 @@ public:
|
||||
~cByteBuffer();
|
||||
|
||||
/// Writes the bytes specified to the ringbuffer. Returns true if successful, false if not
|
||||
bool Write(const char * a_Bytes, int a_Count);
|
||||
bool Write(const char * a_Bytes, size_t a_Count);
|
||||
|
||||
/// Returns the number of bytes that can be successfully written to the ringbuffer
|
||||
int GetFreeSpace(void) const;
|
||||
size_t GetFreeSpace(void) const;
|
||||
|
||||
/// Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes()
|
||||
int GetUsedSpace(void) const;
|
||||
size_t GetUsedSpace(void) const;
|
||||
|
||||
/// Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already)
|
||||
int GetReadableSpace(void) const;
|
||||
size_t GetReadableSpace(void) const;
|
||||
|
||||
/// Returns the current data start index. For debugging purposes.
|
||||
int GetDataStart(void) const { return m_DataStart; }
|
||||
size_t GetDataStart(void) const { return m_DataStart; }
|
||||
|
||||
/// Returns true if the specified amount of bytes are available for reading
|
||||
bool CanReadBytes(int a_Count) const;
|
||||
bool CanReadBytes(size_t a_Count) const;
|
||||
|
||||
/// Returns true if the specified amount of bytes are available for writing
|
||||
bool CanWriteBytes(int a_Count) const;
|
||||
bool CanWriteBytes(size_t a_Count) const;
|
||||
|
||||
// Read the specified datatype and advance the read pointer; return true if successfully read:
|
||||
bool ReadChar (char & a_Value);
|
||||
@ -92,19 +92,19 @@ public:
|
||||
bool WriteLEInt (int a_Value);
|
||||
|
||||
/// Reads a_Count bytes into a_Buffer; returns true if successful
|
||||
bool ReadBuf(void * a_Buffer, int a_Count);
|
||||
bool ReadBuf(void * a_Buffer, size_t a_Count);
|
||||
|
||||
/// Writes a_Count bytes into a_Buffer; returns true if successful
|
||||
bool WriteBuf(const void * a_Buffer, int a_Count);
|
||||
bool WriteBuf(const void * a_Buffer, size_t a_Count);
|
||||
|
||||
/// Reads a_Count bytes into a_String; returns true if successful
|
||||
bool ReadString(AString & a_String, int a_Count);
|
||||
bool ReadString(AString & a_String, size_t a_Count);
|
||||
|
||||
/// Reads 2 * a_NumChars bytes and interprets it as a UTF16-BE string, converting it into UTF8 string a_String
|
||||
bool ReadUTF16String(AString & a_String, int a_NumChars);
|
||||
|
||||
/// Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer
|
||||
bool SkipRead(int a_Count);
|
||||
bool SkipRead(size_t a_Count);
|
||||
|
||||
/// Reads all available data into a_Data
|
||||
void ReadAll(AString & a_Data);
|
||||
@ -126,18 +126,18 @@ public:
|
||||
|
||||
protected:
|
||||
char * m_Buffer;
|
||||
int m_BufferSize; // Total size of the ringbuffer
|
||||
size_t m_BufferSize; // Total size of the ringbuffer
|
||||
|
||||
#ifdef _DEBUG
|
||||
volatile unsigned long m_ThreadID; // Thread that is currently accessing the object, checked via cSingleThreadAccessChecker
|
||||
#endif // _DEBUG
|
||||
|
||||
int m_DataStart; // Where the data starts in the ringbuffer
|
||||
int m_WritePos; // Where the data ends in the ringbuffer
|
||||
int m_ReadPos; // Where the next read will start in the ringbuffer
|
||||
size_t m_DataStart; // Where the data starts in the ringbuffer
|
||||
size_t m_WritePos; // Where the data ends in the ringbuffer
|
||||
size_t m_ReadPos; // Where the next read will start in the ringbuffer
|
||||
|
||||
/// Advances the m_ReadPos by a_Count bytes
|
||||
void AdvanceReadPos(int a_Count);
|
||||
void AdvanceReadPos(size_t a_Count);
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
cmake_minimum_required (VERSION 2.8.2)
|
||||
project (MCServer)
|
||||
|
||||
@ -10,7 +9,6 @@ set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating)
|
||||
set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities)
|
||||
|
||||
|
||||
|
||||
if (NOT MSVC)
|
||||
|
||||
#Bindings needs to reference other folders so are done here
|
||||
@ -67,7 +65,6 @@ if (NOT MSVC)
|
||||
Inventory.h
|
||||
Item.h
|
||||
ItemGrid.h
|
||||
Matrix4f.h
|
||||
Mobs/Monster.h
|
||||
OSSupport/File.h
|
||||
Root.h
|
||||
@ -75,9 +72,7 @@ if (NOT MSVC)
|
||||
StringUtils.h
|
||||
Tracer.h
|
||||
UI/Window.h
|
||||
Vector3d.h
|
||||
Vector3f.h
|
||||
Vector3i.h
|
||||
Vector3.h
|
||||
WebAdmin.h
|
||||
World.h
|
||||
)
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Vector3i.h"
|
||||
#include "Vector3.h"
|
||||
#include "BiomeDef.h"
|
||||
|
||||
|
||||
@ -62,16 +62,12 @@ typedef unsigned char HEIGHTTYPE;
|
||||
class cChunkDef
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
// Chunk dimensions:
|
||||
Width = 16,
|
||||
Height = 256,
|
||||
NumBlocks = Width * Height * Width,
|
||||
|
||||
/// If the data is collected into a single buffer, how large it needs to be:
|
||||
BlockDataSize = cChunkDef::NumBlocks * 2 + (cChunkDef::NumBlocks / 2), // 2.5 * numblocks
|
||||
} ;
|
||||
// Chunk dimensions:
|
||||
static const int Width = 16;
|
||||
static const int Height = 256;
|
||||
static const int NumBlocks = Width * Height * Width;
|
||||
/// If the data is collected into a single buffer, how large it needs to be:
|
||||
static const int BlockDataSize = cChunkDef::NumBlocks * 2 + (cChunkDef::NumBlocks / 2); // 2.5 * numblocks
|
||||
|
||||
/// The type used for any heightmap operations and storage; idx = x + Width * z; Height points to the highest non-air block in the column
|
||||
typedef HEIGHTTYPE HeightMap[Width * Width];
|
||||
@ -116,7 +112,7 @@ public:
|
||||
}
|
||||
|
||||
|
||||
inline static unsigned int MakeIndex(int x, int y, int z )
|
||||
inline static int MakeIndex(int x, int y, int z )
|
||||
{
|
||||
if (
|
||||
(x < Width) && (x > -1) &&
|
||||
@ -132,7 +128,7 @@ public:
|
||||
}
|
||||
|
||||
|
||||
inline static unsigned int MakeIndexNoCheck(int x, int y, int z)
|
||||
inline static int MakeIndexNoCheck(int x, int y, int z)
|
||||
{
|
||||
#if AXIS_ORDER == AXIS_ORDER_XZY
|
||||
// For some reason, NOT using the Horner schema is faster. Weird.
|
||||
@ -255,7 +251,7 @@ public:
|
||||
ASSERT(!"cChunkDef::SetNibble(): index out of range!");
|
||||
return;
|
||||
}
|
||||
a_Buffer[a_BlockIdx / 2] = (
|
||||
a_Buffer[a_BlockIdx / 2] = static_cast<NIBBLETYPE>(
|
||||
(a_Buffer[a_BlockIdx / 2] & (0xf0 >> ((a_BlockIdx & 1) * 4))) | // The untouched nibble
|
||||
((a_Nibble & 0x0f) << ((a_BlockIdx & 1) * 4)) // The nibble being set
|
||||
);
|
||||
@ -275,20 +271,20 @@ public:
|
||||
}
|
||||
|
||||
int Index = MakeIndexNoCheck(x, y, z);
|
||||
a_Buffer[Index / 2] = (
|
||||
a_Buffer[Index / 2] = static_cast<NIBBLETYPE>(
|
||||
(a_Buffer[Index / 2] & (0xf0 >> ((Index & 1) * 4))) | // The untouched nibble
|
||||
((a_Nibble & 0x0f) << ((Index & 1) * 4)) // The nibble being set
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
inline static char GetNibble(const NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos )
|
||||
inline static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos )
|
||||
{
|
||||
return GetNibble(a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z );
|
||||
}
|
||||
|
||||
|
||||
inline static void SetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos, char a_Value )
|
||||
inline static void SetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos, NIBBLETYPE a_Value )
|
||||
{
|
||||
SetNibble( a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Value );
|
||||
}
|
||||
@ -306,6 +302,9 @@ The virtual methods are called in the same order as they're declared here.
|
||||
class cChunkDataCallback abstract
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~cChunkDataCallback() {}
|
||||
|
||||
/** Called before any other callbacks to inform of the current coords
|
||||
(only in processes where multiple chunks can be processed, such as cWorld::ForEachChunkInRect()).
|
||||
If false is returned, the chunk is skipped.
|
||||
@ -432,6 +431,9 @@ Used primarily for entity moving while both chunks are locked.
|
||||
class cClientDiffCallback
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~cClientDiffCallback() {}
|
||||
|
||||
/// Called for clients that are in Chunk1 and not in Chunk2,
|
||||
virtual void Removed(cClientHandle * a_Client) = 0;
|
||||
|
||||
@ -492,6 +494,9 @@ typedef std::vector<cChunkCoords> cChunkCoordsVector;
|
||||
class cChunkCoordCallback
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~cChunkCoordCallback() {}
|
||||
|
||||
virtual void Call(int a_ChunkX, int a_ChunkZ) = 0;
|
||||
} ;
|
||||
|
||||
|
@ -22,9 +22,6 @@
|
||||
#include "Blocks/BlockSlab.h"
|
||||
#include "Blocks/ChunkInterface.h"
|
||||
|
||||
#include "Vector3f.h"
|
||||
#include "Vector3d.h"
|
||||
|
||||
#include "Root.h"
|
||||
|
||||
#include "Authenticator.h"
|
||||
@ -36,22 +33,12 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define AddPistonDir(x, y, z, dir, amount) switch (dir) { case 0: (y)-=(amount); break; case 1: (y)+=(amount); break;\
|
||||
case 2: (z)-=(amount); break; case 3: (z)+=(amount); break;\
|
||||
case 4: (x)-=(amount); break; case 5: (x)+=(amount); break; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** If the number of queued outgoing packets reaches this, the client will be kicked */
|
||||
#define MAX_OUTGOING_PACKETS 2000
|
||||
|
||||
/** Maximum number of explosions to send this tick, server will start dropping if exceeded */
|
||||
#define MAX_EXPLOSIONS_PER_TICK 20
|
||||
|
||||
/** Maximum number of block change interactions a player can perform per tick - exceeding this causes a kick */
|
||||
#define MAX_BLOCK_CHANGE_INTERACTIONS 20
|
||||
|
||||
/** How many ticks before the socket is closed after the client is destroyed (#31) */
|
||||
static const int TICKS_BEFORE_CLOSE = 20;
|
||||
|
||||
@ -96,8 +83,8 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) :
|
||||
m_ShouldCheckDownloaded(false),
|
||||
m_NumExplosionsThisTick(0),
|
||||
m_UniqueID(0),
|
||||
m_Locale("en_GB"),
|
||||
m_HasSentPlayerChunk(false)
|
||||
m_HasSentPlayerChunk(false),
|
||||
m_Locale("en_GB")
|
||||
{
|
||||
m_Protocol = new cProtocolRecognizer(this);
|
||||
|
||||
@ -555,12 +542,25 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString
|
||||
}
|
||||
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));
|
||||
}
|
||||
else if (a_Channel == "UNREGISTER")
|
||||
{
|
||||
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);
|
||||
}
|
||||
@ -687,6 +687,14 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
|
||||
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status
|
||||
);
|
||||
|
||||
m_NumBlockChangeInteractionsThisTick++;
|
||||
|
||||
if (!CheckBlockInteractionsRate())
|
||||
{
|
||||
Kick("Too many blocks were destroyed per unit time - hacked client?");
|
||||
return;
|
||||
}
|
||||
|
||||
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
|
||||
if (PlgMgr->CallHookPlayerLeftClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status))
|
||||
{
|
||||
@ -694,12 +702,6 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
|
||||
m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CheckBlockInteractionsRate())
|
||||
{
|
||||
// Too many interactions per second, simply ignore. Probably a hacked client, so don't even send bak the block
|
||||
return;
|
||||
}
|
||||
|
||||
switch (a_Status)
|
||||
{
|
||||
@ -877,7 +879,7 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo
|
||||
LOGD("Prevented a dig/aim bug in the client (finish {%d, %d, %d} vs start {%d, %d, %d}, HSD: %s)",
|
||||
a_BlockX, a_BlockY, a_BlockZ,
|
||||
m_LastDigBlockX, m_LastDigBlockY, m_LastDigBlockZ,
|
||||
m_HasStartedDigging
|
||||
(m_HasStartedDigging ? "True" : "False")
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -931,7 +933,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||
cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
|
||||
BlockHandler->OnCancelRightClick(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||
|
||||
if (a_BlockFace > -1)
|
||||
if (a_BlockFace != BLOCK_FACE_NONE)
|
||||
{
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
||||
@ -942,7 +944,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||
|
||||
if (!CheckBlockInteractionsRate())
|
||||
{
|
||||
LOGD("Too many block interactions, aborting placement");
|
||||
Kick("Too many blocks were placed/interacted with per unit time - hacked client?");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1453,7 +1455,7 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
|
||||
|
||||
|
||||
|
||||
void cClientHandle::HandleEntityAction(int a_EntityID, char a_ActionID)
|
||||
void cClientHandle::HandleEntityCrouch(int a_EntityID, bool a_IsCrouching)
|
||||
{
|
||||
if (a_EntityID != m_Player->GetUniqueID())
|
||||
{
|
||||
@ -1461,35 +1463,37 @@ void cClientHandle::HandleEntityAction(int a_EntityID, char a_ActionID)
|
||||
return;
|
||||
}
|
||||
|
||||
switch (a_ActionID)
|
||||
m_Player->SetCrouch(a_IsCrouching);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cClientHandle::HandleEntityLeaveBed(int a_EntityID)
|
||||
{
|
||||
if (a_EntityID != m_Player->GetUniqueID())
|
||||
{
|
||||
case 1: // Crouch
|
||||
{
|
||||
m_Player->SetCrouch(true);
|
||||
break;
|
||||
}
|
||||
case 2: // Uncrouch
|
||||
{
|
||||
m_Player->SetCrouch(false);
|
||||
break;
|
||||
}
|
||||
case 3: // Leave bed
|
||||
{
|
||||
m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, 2);
|
||||
break;
|
||||
}
|
||||
case 4: // Start sprinting
|
||||
{
|
||||
m_Player->SetSprint(true);
|
||||
break;
|
||||
}
|
||||
case 5: // Stop sprinting
|
||||
{
|
||||
m_Player->SetSprint(false);
|
||||
SendPlayerMaxSpeed();
|
||||
break;
|
||||
}
|
||||
// We should only receive entity actions from the entity that is performing the action
|
||||
return;
|
||||
}
|
||||
|
||||
m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cClientHandle::HandleEntitySprinting(int a_EntityID, bool a_IsSprinting)
|
||||
{
|
||||
if (a_EntityID != m_Player->GetUniqueID())
|
||||
{
|
||||
// We should only receive entity actions from the entity that is performing the action
|
||||
return;
|
||||
}
|
||||
|
||||
m_Player->SetSprint(a_IsSprinting);
|
||||
}
|
||||
|
||||
|
||||
@ -1619,28 +1623,12 @@ bool cClientHandle::CheckBlockInteractionsRate(void)
|
||||
{
|
||||
ASSERT(m_Player != NULL);
|
||||
ASSERT(m_Player->GetWorld() != NULL);
|
||||
/*
|
||||
// TODO: _X 2012_11_01: This needs a total re-thinking and rewriting
|
||||
int LastActionCnt = m_Player->GetLastBlockActionCnt();
|
||||
if ((m_Player->GetWorld()->GetTime() - m_Player->GetLastBlockActionTime()) < 0.1)
|
||||
|
||||
if (m_NumBlockChangeInteractionsThisTick > MAX_BLOCK_CHANGE_INTERACTIONS)
|
||||
{
|
||||
// Limit the number of block interactions per tick
|
||||
m_Player->SetLastBlockActionTime(); //Player tried to interact with a block. Reset last block interation time.
|
||||
m_Player->SetLastBlockActionCnt(LastActionCnt + 1);
|
||||
if (m_Player->GetLastBlockActionCnt() > MAXBLOCKCHANGEINTERACTIONS)
|
||||
{
|
||||
// Kick if more than MAXBLOCKCHANGEINTERACTIONS per tick
|
||||
LOGWARN("Player %s tried to interact with a block too quickly! (could indicate bot) Was Kicked.", m_Username.c_str());
|
||||
Kick("You're a baaaaaad boy!");
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Player->SetLastBlockActionCnt(0); // Reset count
|
||||
m_Player->SetLastBlockActionTime(); // Player tried to interact with a block. Reset last block interation time.
|
||||
}
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1713,8 +1701,9 @@ void cClientHandle::Tick(float a_Dt)
|
||||
}
|
||||
}
|
||||
|
||||
// Reset explosion counter:
|
||||
// Reset explosion & block change counters:
|
||||
m_NumExplosionsThisTick = 0;
|
||||
m_NumBlockChangeInteractionsThisTick = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
#define CCLIENTHANDLE_H_INCLUDED
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Vector3d.h"
|
||||
#include "Vector3.h"
|
||||
#include "OSSupport/SocketThreads.h"
|
||||
#include "ChunkDef.h"
|
||||
#include "ByteBuffer.h"
|
||||
@ -46,7 +46,6 @@ class cClientHandle : // tolua_export
|
||||
public cSocketThreads::cCallback
|
||||
{ // tolua_export
|
||||
public:
|
||||
static const int MAXBLOCKCHANGEINTERACTIONS = 20; // 5 didn't help, 10 still doesn't work in Creative, 20 seems to have done the trick
|
||||
|
||||
#if defined(ANDROID_NDK)
|
||||
static const int DEFAULT_VIEW_DISTANCE = 4; // The default ViewDistance (used when no value is set in Settings.ini)
|
||||
@ -188,7 +187,9 @@ public:
|
||||
void HandleChat (const AString & a_Message);
|
||||
void HandleCreativeInventory(short a_SlotNum, const cItem & a_HeldItem);
|
||||
void HandleDisconnect (const AString & a_Reason);
|
||||
void HandleEntityAction (int a_EntityID, char a_ActionID);
|
||||
void HandleEntityCrouch (int a_EntityID, bool a_IsCrouching);
|
||||
void HandleEntityLeaveBed (int a_EntityID);
|
||||
void HandleEntitySprinting (int a_EntityID, bool a_IsSprinting);
|
||||
|
||||
/** Called when the protocol handshake has been received (for protocol versions that support it;
|
||||
otherwise the first instant when a username is received).
|
||||
@ -319,6 +320,9 @@ private:
|
||||
|
||||
/** Number of explosions sent this tick */
|
||||
int m_NumExplosionsThisTick;
|
||||
|
||||
/** Number of place or break interactions this tick */
|
||||
int m_NumBlockChangeInteractionsThisTick;
|
||||
|
||||
static int s_ClientCount;
|
||||
int m_UniqueID;
|
||||
|
@ -51,7 +51,7 @@ void cLogCommandOutputCallback::Finished(void)
|
||||
{
|
||||
case '\n':
|
||||
{
|
||||
LOG(m_Buffer.substr(last, i - last).c_str());
|
||||
LOG("%s", m_Buffer.substr(last, i - last).c_str());
|
||||
last = i + 1;
|
||||
break;
|
||||
}
|
||||
@ -59,7 +59,7 @@ void cLogCommandOutputCallback::Finished(void)
|
||||
} // for i - m_Buffer[]
|
||||
if (last < len)
|
||||
{
|
||||
LOG(m_Buffer.substr(last).c_str());
|
||||
LOG("%s", m_Buffer.substr(last).c_str());
|
||||
}
|
||||
|
||||
// Clear the buffer for the next command output:
|
||||
|
@ -17,7 +17,7 @@ public:
|
||||
virtual ~cCommandOutputCallback() {}; // Force a virtual destructor in subclasses
|
||||
|
||||
/// Syntax sugar function, calls Out() with Printf()-ed parameters; appends a "\n"
|
||||
void Out(const char * a_Fmt, ...);
|
||||
void Out(const char * a_Fmt, ...) FORMATSTRING(2, 3);
|
||||
|
||||
/// Called when the command wants to output anything; may be called multiple times
|
||||
virtual void Out(const AString & a_Text) = 0;
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
|
||||
|
||||
#if SELF_TEST
|
||||
#ifdef SELF_TEST
|
||||
|
||||
/** A simple self-test that verifies that the composite chat parser is working properly. */
|
||||
class SelfTest_CompositeChat
|
||||
@ -32,15 +32,15 @@ public:
|
||||
cCompositeChat Msg;
|
||||
Msg.ParseText("Testing @2color codes and http://links parser");
|
||||
const cCompositeChat::cParts & Parts = Msg.GetParts();
|
||||
assert(Parts.size() == 4);
|
||||
assert(Parts[0]->m_PartType == cCompositeChat::ptText);
|
||||
assert(Parts[1]->m_PartType == cCompositeChat::ptText);
|
||||
assert(Parts[2]->m_PartType == cCompositeChat::ptUrl);
|
||||
assert(Parts[3]->m_PartType == cCompositeChat::ptText);
|
||||
assert(Parts[0]->m_Style == "");
|
||||
assert(Parts[1]->m_Style == "@2");
|
||||
assert(Parts[2]->m_Style == "@2");
|
||||
assert(Parts[3]->m_Style == "@2");
|
||||
assert_test(Parts.size() == 4);
|
||||
assert_test(Parts[0]->m_PartType == cCompositeChat::ptText);
|
||||
assert_test(Parts[1]->m_PartType == cCompositeChat::ptText);
|
||||
assert_test(Parts[2]->m_PartType == cCompositeChat::ptUrl);
|
||||
assert_test(Parts[3]->m_PartType == cCompositeChat::ptText);
|
||||
assert_test(Parts[0]->m_Style == "");
|
||||
assert_test(Parts[1]->m_Style == "@2");
|
||||
assert_test(Parts[2]->m_Style == "@2");
|
||||
assert_test(Parts[3]->m_Style == "@2");
|
||||
}
|
||||
|
||||
void TestParser2(void)
|
||||
@ -48,15 +48,15 @@ public:
|
||||
cCompositeChat Msg;
|
||||
Msg.ParseText("@3Advanced stuff: @5overriding color codes and http://links.with/@4color-in-them handling");
|
||||
const cCompositeChat::cParts & Parts = Msg.GetParts();
|
||||
assert(Parts.size() == 4);
|
||||
assert(Parts[0]->m_PartType == cCompositeChat::ptText);
|
||||
assert(Parts[1]->m_PartType == cCompositeChat::ptText);
|
||||
assert(Parts[2]->m_PartType == cCompositeChat::ptUrl);
|
||||
assert(Parts[3]->m_PartType == cCompositeChat::ptText);
|
||||
assert(Parts[0]->m_Style == "@3");
|
||||
assert(Parts[1]->m_Style == "@5");
|
||||
assert(Parts[2]->m_Style == "@5");
|
||||
assert(Parts[3]->m_Style == "@5");
|
||||
assert_test(Parts.size() == 4);
|
||||
assert_test(Parts[0]->m_PartType == cCompositeChat::ptText);
|
||||
assert_test(Parts[1]->m_PartType == cCompositeChat::ptText);
|
||||
assert_test(Parts[2]->m_PartType == cCompositeChat::ptUrl);
|
||||
assert_test(Parts[3]->m_PartType == cCompositeChat::ptText);
|
||||
assert_test(Parts[0]->m_Style == "@3");
|
||||
assert_test(Parts[1]->m_Style == "@5");
|
||||
assert_test(Parts[2]->m_Style == "@5");
|
||||
assert_test(Parts[3]->m_Style == "@5");
|
||||
}
|
||||
|
||||
void TestParser3(void)
|
||||
@ -64,11 +64,11 @@ public:
|
||||
cCompositeChat Msg;
|
||||
Msg.ParseText("http://links.starting the text");
|
||||
const cCompositeChat::cParts & Parts = Msg.GetParts();
|
||||
assert(Parts.size() == 2);
|
||||
assert(Parts[0]->m_PartType == cCompositeChat::ptUrl);
|
||||
assert(Parts[1]->m_PartType == cCompositeChat::ptText);
|
||||
assert(Parts[0]->m_Style == "");
|
||||
assert(Parts[1]->m_Style == "");
|
||||
assert_test(Parts.size() == 2);
|
||||
assert_test(Parts[0]->m_PartType == cCompositeChat::ptUrl);
|
||||
assert_test(Parts[1]->m_PartType == cCompositeChat::ptText);
|
||||
assert_test(Parts[0]->m_Style == "");
|
||||
assert_test(Parts[1]->m_Style == "");
|
||||
}
|
||||
|
||||
void TestParser4(void)
|
||||
@ -76,11 +76,11 @@ public:
|
||||
cCompositeChat Msg;
|
||||
Msg.ParseText("links finishing the text: http://some.server");
|
||||
const cCompositeChat::cParts & Parts = Msg.GetParts();
|
||||
assert(Parts.size() == 2);
|
||||
assert(Parts[0]->m_PartType == cCompositeChat::ptText);
|
||||
assert(Parts[1]->m_PartType == cCompositeChat::ptUrl);
|
||||
assert(Parts[0]->m_Style == "");
|
||||
assert(Parts[1]->m_Style == "");
|
||||
assert_test(Parts.size() == 2);
|
||||
assert_test(Parts[0]->m_PartType == cCompositeChat::ptText);
|
||||
assert_test(Parts[1]->m_PartType == cCompositeChat::ptUrl);
|
||||
assert_test(Parts[0]->m_Style == "");
|
||||
assert_test(Parts[1]->m_Style == "");
|
||||
}
|
||||
|
||||
void TestParser5(void)
|
||||
@ -88,9 +88,9 @@ public:
|
||||
cCompositeChat Msg;
|
||||
Msg.ParseText("http://only.links");
|
||||
const cCompositeChat::cParts & Parts = Msg.GetParts();
|
||||
assert(Parts.size() == 1);
|
||||
assert(Parts[0]->m_PartType == cCompositeChat::ptUrl);
|
||||
assert(Parts[0]->m_Style == "");
|
||||
assert_test(Parts.size() == 1);
|
||||
assert_test(Parts[0]->m_PartType == cCompositeChat::ptUrl);
|
||||
assert_test(Parts[0]->m_Style == "");
|
||||
}
|
||||
|
||||
} gTest;
|
||||
|
@ -1,4 +1,4 @@
|
||||
|
||||
|
||||
// CraftingRecipes.cpp
|
||||
|
||||
// Interfaces to the cCraftingRecipes class representing the storage of crafting recipes
|
||||
@ -192,7 +192,9 @@ void cCraftingGrid::Dump(void)
|
||||
{
|
||||
for (int y = 0; y < m_Height; y++) for (int x = 0; x < m_Width; x++)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
int idx = x + m_Width * y;
|
||||
#endif
|
||||
LOGD("Slot (%d, %d): Type %d, health %d, count %d",
|
||||
x, y, m_Items[idx].m_ItemType, m_Items[idx].m_ItemDamage, m_Items[idx].m_ItemCount
|
||||
);
|
||||
@ -338,7 +340,7 @@ void cCraftingRecipes::LoadRecipes(void)
|
||||
}
|
||||
AddRecipeLine(LineNum, Recipe);
|
||||
} // for itr - Split[]
|
||||
LOG("Loaded %d crafting recipes", m_Recipes.size());
|
||||
LOG("Loaded " SIZE_T_FMT " crafting recipes", m_Recipes.size());
|
||||
}
|
||||
|
||||
|
||||
@ -762,9 +764,94 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::MatchRecipe(const cItem * a_Crafti
|
||||
Recipe->m_Ingredients.push_back(*itrS);
|
||||
}
|
||||
Recipe->m_Ingredients.insert(Recipe->m_Ingredients.end(), MatchedSlots.begin(), MatchedSlots.end());
|
||||
|
||||
// We use Recipe instead of a_Recipe because we want the wildcard ingredients' slot numbers as well, which was just added previously
|
||||
HandleFireworks(a_CraftingGrid, Recipe.get(), a_GridStride, a_OffsetX, a_OffsetY);
|
||||
|
||||
return Recipe.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cCraftingRecipes::HandleFireworks(const cItem * a_CraftingGrid, cCraftingRecipes::cRecipe * a_Recipe, int a_GridStride, int a_OffsetX, int a_OffsetY)
|
||||
{
|
||||
// TODO: add support for more than one dye in the recipe
|
||||
// A manual and temporary solution (listing everything) is in crafting.txt for fade colours, but a programmatic solutions needs to be done for everything else
|
||||
|
||||
if (a_Recipe->m_Result.m_ItemType == E_ITEM_FIREWORK_ROCKET)
|
||||
{
|
||||
for (cRecipeSlots::const_iterator itr = a_Recipe->m_Ingredients.begin(); itr != a_Recipe->m_Ingredients.end(); ++itr)
|
||||
{
|
||||
switch (itr->m_Item.m_ItemType)
|
||||
{
|
||||
case E_ITEM_FIREWORK_STAR:
|
||||
{
|
||||
// Result was a rocket, found a star - copy star data to rocket data
|
||||
int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
|
||||
a_Recipe->m_Result.m_FireworkItem.CopyFrom(a_CraftingGrid[GridID].m_FireworkItem);
|
||||
break;
|
||||
}
|
||||
case E_ITEM_GUNPOWDER:
|
||||
{
|
||||
// Gunpowder - increase flight time
|
||||
a_Recipe->m_Result.m_FireworkItem.m_FlightTimeInTicks += 20;
|
||||
break;
|
||||
}
|
||||
case E_ITEM_PAPER: break;
|
||||
default: LOG("Unexpected item in firework rocket a_Recipe, was the crafting file fireworks section changed?"); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (a_Recipe->m_Result.m_ItemType == E_ITEM_FIREWORK_STAR)
|
||||
{
|
||||
std::vector<int> DyeColours;
|
||||
bool FoundStar = false;
|
||||
|
||||
for (cRecipeSlots::const_iterator itr = a_Recipe->m_Ingredients.begin(); itr != a_Recipe->m_Ingredients.end(); ++itr)
|
||||
{
|
||||
switch (itr->m_Item.m_ItemType)
|
||||
{
|
||||
case E_ITEM_FIREWORK_STAR:
|
||||
{
|
||||
// Result was star, found another star - probably adding fade colours, but copy data over anyhow
|
||||
FoundStar = true;
|
||||
int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
|
||||
a_Recipe->m_Result.m_FireworkItem.CopyFrom(a_CraftingGrid[GridID].m_FireworkItem);
|
||||
break;
|
||||
}
|
||||
case E_ITEM_DYE:
|
||||
{
|
||||
int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
|
||||
DyeColours.push_back(cFireworkItem::GetVanillaColourCodeFromDye(a_CraftingGrid[GridID].m_ItemDamage));
|
||||
break;
|
||||
}
|
||||
case E_ITEM_GUNPOWDER: break;
|
||||
case E_ITEM_DIAMOND: a_Recipe->m_Result.m_FireworkItem.m_HasTrail = true; break;
|
||||
case E_ITEM_GLOWSTONE_DUST: a_Recipe->m_Result.m_FireworkItem.m_HasFlicker = true; break;
|
||||
|
||||
case E_ITEM_FIRE_CHARGE: a_Recipe->m_Result.m_FireworkItem.m_Type = 1; break;
|
||||
case E_ITEM_GOLD_NUGGET: a_Recipe->m_Result.m_FireworkItem.m_Type = 2; break;
|
||||
case E_ITEM_FEATHER: a_Recipe->m_Result.m_FireworkItem.m_Type = 4; break;
|
||||
case E_ITEM_HEAD: a_Recipe->m_Result.m_FireworkItem.m_Type = 3; break;
|
||||
default: LOG("Unexpected item in firework star a_Recipe, was the crafting file fireworks section changed?"); break; // ermahgerd BARD ardmins
|
||||
}
|
||||
}
|
||||
|
||||
if (FoundStar && (!DyeColours.empty()))
|
||||
{
|
||||
// Found a star and a dye? Fade colours.
|
||||
a_Recipe->m_Result.m_FireworkItem.m_FadeColours = DyeColours;
|
||||
}
|
||||
else if (!DyeColours.empty())
|
||||
{
|
||||
// Only dye? Normal colours.
|
||||
a_Recipe->m_Result.m_FireworkItem.m_Colours = DyeColours;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -165,6 +165,9 @@ protected:
|
||||
|
||||
/// Checks if the grid matches the specified recipe, offset by the specified offsets. Returns a matched cRecipe * if so, or NULL if not matching. Caller must delete the return value!
|
||||
cRecipe * MatchRecipe(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight, int a_GridStride, const cRecipe * a_Recipe, int a_OffsetX, int a_OffsetY);
|
||||
|
||||
/** Searches for anything firework related, and does the data setting if appropriate */
|
||||
void HandleFireworks(const cItem * a_CraftingGrid, cCraftingRecipes::cRecipe * a_Recipe, int a_GridStride, int a_OffsetX, int a_OffsetY);
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -72,6 +72,9 @@ int cCuboid::GetVolume(void) const
|
||||
|
||||
bool cCuboid::DoesIntersect(const cCuboid & a_Other) const
|
||||
{
|
||||
ASSERT(IsSorted());
|
||||
ASSERT(a_Other.IsSorted());
|
||||
|
||||
// In order for cuboids to intersect, each of their coord intervals need to intersect
|
||||
return (
|
||||
DoIntervalsIntersect(p1.x, p2.x, a_Other.p1.x, a_Other.p2.x) &&
|
||||
@ -86,6 +89,9 @@ bool cCuboid::DoesIntersect(const cCuboid & a_Other) const
|
||||
|
||||
bool cCuboid::IsCompletelyInside(const cCuboid & a_Outer) const
|
||||
{
|
||||
ASSERT(IsSorted());
|
||||
ASSERT(a_Outer.IsSorted());
|
||||
|
||||
return (
|
||||
(p1.x >= a_Outer.p1.x) &&
|
||||
(p2.x <= a_Outer.p2.x) &&
|
||||
@ -197,3 +203,37 @@ bool cCuboid::IsSorted(void) const
|
||||
|
||||
|
||||
|
||||
|
||||
void cCuboid::Engulf(const Vector3i & a_Point)
|
||||
{
|
||||
if (a_Point.x < p1.x)
|
||||
{
|
||||
p1.x = a_Point.x;
|
||||
}
|
||||
else if (a_Point.x > p2.x)
|
||||
{
|
||||
p2.x = a_Point.x;
|
||||
}
|
||||
|
||||
if (a_Point.y < p1.y)
|
||||
{
|
||||
p1.y = a_Point.y;
|
||||
}
|
||||
else if (a_Point.y > p2.y)
|
||||
{
|
||||
p2.y = a_Point.y;
|
||||
}
|
||||
|
||||
if (a_Point.z < p1.z)
|
||||
{
|
||||
p1.z = a_Point.z;
|
||||
}
|
||||
else if (a_Point.z > p2.z)
|
||||
{
|
||||
p2.z = a_Point.z;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
14
src/Cuboid.h
14
src/Cuboid.h
@ -1,8 +1,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Vector3i.h"
|
||||
#include "Vector3d.h"
|
||||
#include "Vector3.h"
|
||||
|
||||
|
||||
|
||||
@ -34,7 +33,8 @@ public:
|
||||
Works on unsorted cuboids, too. */
|
||||
int GetVolume(void) const;
|
||||
|
||||
/** Returns true if the cuboids have at least one voxel in common. Both coords are considered inclusive. */
|
||||
/** Returns true if the cuboids have at least one voxel in common. Both coords are considered inclusive.
|
||||
Assumes both cuboids are sorted. */
|
||||
bool DoesIntersect(const cCuboid & a_Other) const;
|
||||
|
||||
bool IsInside(const Vector3i & v) const
|
||||
@ -64,7 +64,8 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
/** Returns true if this cuboid is completely inside the specifie cuboid (in all 6 coords) */
|
||||
/** Returns true if this cuboid is completely inside the specifie cuboid (in all 6 coords).
|
||||
Assumes both cuboids are sorted. */
|
||||
bool IsCompletelyInside(const cCuboid & a_Outer) const;
|
||||
|
||||
/** Moves the cuboid by the specified offsets in each direction */
|
||||
@ -72,7 +73,7 @@ public:
|
||||
|
||||
/** Expands the cuboid by the specified amount in each direction.
|
||||
Works on unsorted cuboids as well.
|
||||
Note that this function doesn't check for underflows. */
|
||||
Note that this function doesn't check for underflows when using negative amounts. */
|
||||
void Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ);
|
||||
|
||||
/** Clamps both X coords to the specified range. Works on unsorted cuboids, too. */
|
||||
@ -86,6 +87,9 @@ public:
|
||||
|
||||
/** Returns true if the coords are properly sorted (lesser in p1, greater in p2) */
|
||||
bool IsSorted(void) const;
|
||||
|
||||
/** If needed, expands the cuboid so that it contains the specified point. Assumes sorted. Doesn't contract. */
|
||||
void Engulf(const Vector3i & a_Point);
|
||||
} ;
|
||||
// tolua_end
|
||||
|
||||
|
@ -60,7 +60,7 @@ protected:
|
||||
void CheckWorldAge(const AString & a_WorldName, Int64 a_Age);
|
||||
|
||||
/// Called when a deadlock is detected. Aborts the server.
|
||||
void DeadlockDetected(void);
|
||||
NORETURN void DeadlockDetected(void);
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "ChatColor.h"
|
||||
#include <limits>
|
||||
|
||||
|
||||
|
||||
@ -276,6 +277,26 @@ inline eBlockFace RotateBlockFaceCW(eBlockFace a_BlockFace)
|
||||
|
||||
|
||||
|
||||
/** Returns the textual representation of the BlockFace constant. */
|
||||
inline AString BlockFaceToString(eBlockFace a_BlockFace)
|
||||
{
|
||||
switch (a_BlockFace)
|
||||
{
|
||||
case BLOCK_FACE_XM: return "BLOCK_FACE_XM";
|
||||
case BLOCK_FACE_XP: return "BLOCK_FACE_XP";
|
||||
case BLOCK_FACE_YM: return "BLOCK_FACE_YM";
|
||||
case BLOCK_FACE_YP: return "BLOCK_FACE_YP";
|
||||
case BLOCK_FACE_ZM: return "BLOCK_FACE_ZM";
|
||||
case BLOCK_FACE_ZP: return "BLOCK_FACE_ZP";
|
||||
case BLOCK_FACE_NONE: return "BLOCK_FACE_NONE";
|
||||
}
|
||||
return Printf("Unknown BLOCK_FACE: %d", a_BlockFace);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline bool IsValidBlock(int a_BlockType)
|
||||
{
|
||||
if (
|
||||
@ -469,7 +490,7 @@ inline void EulerToVector(double a_Pan, double a_Pitch, double & a_X, double & a
|
||||
|
||||
inline void VectorToEuler(double a_X, double a_Y, double a_Z, double & a_Pan, double & a_Pitch)
|
||||
{
|
||||
if (a_X != 0)
|
||||
if (fabs(a_X) < std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
a_Pan = atan2(a_Z, a_X) * 180 / PI - 90;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "../World.h"
|
||||
#include "../Server.h"
|
||||
#include "../Root.h"
|
||||
#include "../Matrix4f.h"
|
||||
#include "../Matrix4.h"
|
||||
#include "../ClientHandle.h"
|
||||
#include "../Chunk.h"
|
||||
#include "../Simulator/FluidSimulator.h"
|
||||
|
@ -2,9 +2,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Item.h"
|
||||
#include "../Vector3d.h"
|
||||
#include "../Vector3f.h"
|
||||
#include "../Vector3i.h"
|
||||
#include "../Vector3.h"
|
||||
|
||||
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
class cFloater :
|
||||
public cEntity
|
||||
{
|
||||
typedef cFloater super;
|
||||
typedef cEntity super;
|
||||
|
||||
public:
|
||||
//tolua_end
|
||||
|
@ -1031,9 +1031,9 @@ cMinecartWithChest::cMinecartWithChest(double a_X, double a_Y, double a_Z) :
|
||||
|
||||
|
||||
|
||||
void cMinecartWithChest::SetSlot(int a_Idx, const cItem & a_Item)
|
||||
void cMinecartWithChest::SetSlot(size_t a_Idx, const cItem & a_Item)
|
||||
{
|
||||
ASSERT((a_Idx >= 0) && (a_Idx < ARRAYCOUNT(m_Items)));
|
||||
ASSERT(a_Idx < ARRAYCOUNT(m_Items));
|
||||
|
||||
m_Items[a_Idx] = a_Item;
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ public:
|
||||
const cItem & GetSlot(int a_Idx) const { return m_Items[a_Idx]; }
|
||||
cItem & GetSlot(int a_Idx) { return m_Items[a_Idx]; }
|
||||
|
||||
void SetSlot(int a_Idx, const cItem & a_Item);
|
||||
void SetSlot(size_t a_Idx, const cItem & a_Item);
|
||||
|
||||
protected:
|
||||
|
||||
@ -193,4 +193,4 @@ public:
|
||||
CLASS_PROTODEF(cMinecartWithHopper);
|
||||
|
||||
cMinecartWithHopper(double a_X, double a_Y, double a_Z);
|
||||
} ;
|
||||
} ;
|
||||
|
@ -10,17 +10,11 @@
|
||||
#include "../BlockEntities/BlockEntity.h"
|
||||
#include "../GroupManager.h"
|
||||
#include "../Group.h"
|
||||
#include "../ChatColor.h"
|
||||
#include "../Item.h"
|
||||
#include "../Tracer.h"
|
||||
#include "../Root.h"
|
||||
#include "../OSSupport/Timer.h"
|
||||
#include "../MersenneTwister.h"
|
||||
#include "../Chunk.h"
|
||||
#include "../Items/ItemHandler.h"
|
||||
|
||||
#include "../Vector3d.h"
|
||||
#include "../Vector3f.h"
|
||||
#include "../Vector3.h"
|
||||
|
||||
#include "inifile/iniFile.h"
|
||||
#include "json/json.h"
|
||||
@ -45,10 +39,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
|
||||
, m_Inventory(*this)
|
||||
, m_CurrentWindow(NULL)
|
||||
, m_InventoryWindow(NULL)
|
||||
, m_TimeLastPickupCheck(0.f)
|
||||
, m_Color('-')
|
||||
, m_LastBlockActionTime(0)
|
||||
, m_LastBlockActionCnt(0)
|
||||
, m_GameMode(eGameMode_NotSet)
|
||||
, m_IP("")
|
||||
, m_ClientHandle(a_Client)
|
||||
@ -86,7 +77,6 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
|
||||
m_LastPlayerListTime = t1.GetNowTime();
|
||||
|
||||
m_TimeLastTeleportPacket = 0;
|
||||
m_TimeLastPickupCheck = 0;
|
||||
|
||||
m_PlayerName = a_PlayerName;
|
||||
m_bDirtyPosition = true; // So chunks are streamed to player at spawn
|
||||
@ -1047,27 +1037,6 @@ void cPlayer::CloseWindowIfID(char a_WindowID, bool a_CanRefuse)
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetLastBlockActionTime()
|
||||
{
|
||||
if (m_World != NULL)
|
||||
{
|
||||
m_LastBlockActionTime = m_World->GetWorldAge() / 20.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetLastBlockActionCnt( int a_LastBlockActionCnt )
|
||||
{
|
||||
m_LastBlockActionCnt = a_LastBlockActionCnt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetGameMode(eGameMode a_GameMode)
|
||||
{
|
||||
if ((a_GameMode < gmMin) || (a_GameMode >= gmMax))
|
||||
|
@ -50,7 +50,7 @@ public:
|
||||
/// Returns the curently equipped weapon; empty item if none
|
||||
virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); }
|
||||
|
||||
/// Returns the currently equipped helmet; empty item if nonte
|
||||
/// Returns the currently equipped helmet; empty item if none
|
||||
virtual cItem GetEquippedHelmet(void) const override { return m_Inventory.GetEquippedHelmet(); }
|
||||
|
||||
/// Returns the currently equipped chestplate; empty item if none
|
||||
@ -165,11 +165,6 @@ public:
|
||||
// tolua_end
|
||||
|
||||
void SetIP(const AString & a_IP);
|
||||
|
||||
float GetLastBlockActionTime() { return m_LastBlockActionTime; }
|
||||
int GetLastBlockActionCnt() { return m_LastBlockActionCnt; }
|
||||
void SetLastBlockActionCnt( int );
|
||||
void SetLastBlockActionTime();
|
||||
|
||||
// Sets the current gamemode, doesn't check validity, doesn't send update packets to client
|
||||
void LoginSetGameMode(eGameMode a_GameMode);
|
||||
@ -416,12 +411,8 @@ protected:
|
||||
cWindow * m_CurrentWindow;
|
||||
cWindow * m_InventoryWindow;
|
||||
|
||||
float m_TimeLastPickupCheck;
|
||||
|
||||
char m_Color;
|
||||
|
||||
float m_LastBlockActionTime;
|
||||
int m_LastBlockActionCnt;
|
||||
eGameMode m_GameMode;
|
||||
AString m_IP;
|
||||
|
||||
|
@ -214,7 +214,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve
|
||||
|
||||
|
||||
|
||||
cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed)
|
||||
cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item, const Vector3d * a_Speed)
|
||||
{
|
||||
Vector3d Speed;
|
||||
if (a_Speed != NULL)
|
||||
@ -231,8 +231,15 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator,
|
||||
case pkGhastFireball: return new cGhastFireballEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkFireCharge: return new cFireChargeEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkExpBottle: return new cExpBottleEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkFirework: return new cFireworkEntity (a_Creator, a_X, a_Y, a_Z );
|
||||
// TODO: the rest
|
||||
case pkFirework:
|
||||
{
|
||||
if (a_Item.m_FireworkItem.m_Colours.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new cFireworkEntity(a_Creator, a_X, a_Y, a_Z, a_Item);
|
||||
}
|
||||
}
|
||||
|
||||
LOGWARNING("%s: Unknown projectile kind: %d", __FUNCTION__, a_Kind);
|
||||
@ -276,6 +283,7 @@ AString cProjectileEntity::GetMCAClassName(void) const
|
||||
case pkExpBottle: return "ThrownExpBottle";
|
||||
case pkSplashPotion: return "ThrownPotion";
|
||||
case pkWitherSkull: return "WitherSkull";
|
||||
case pkFirework: return "Firework";
|
||||
case pkFishingFloat: return ""; // Unknown, perhaps MC doesn't save this?
|
||||
}
|
||||
ASSERT(!"Unhandled projectile entity kind!");
|
||||
@ -655,8 +663,6 @@ cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, do
|
||||
|
||||
void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
// TODO: Apply damage to certain mobs (blaze etc.) and anger all mobs
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
@ -664,6 +670,30 @@ void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFac
|
||||
|
||||
|
||||
|
||||
void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
int TotalDamage = 0;
|
||||
if (a_EntityHit.IsMob())
|
||||
{
|
||||
cMonster::eType MobType = ((cMonster &) a_EntityHit).GetMobType();
|
||||
if (MobType == cMonster::mtBlaze)
|
||||
{
|
||||
TotalDamage = 3;
|
||||
}
|
||||
else if (MobType == cMonster::mtEnderDragon)
|
||||
{
|
||||
TotalDamage = 1;
|
||||
}
|
||||
}
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
||||
|
||||
Destroy(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cBottleOEnchantingEntity :
|
||||
|
||||
@ -693,8 +723,10 @@ void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_H
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cFireworkEntity :
|
||||
|
||||
cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z) :
|
||||
super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||
cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) :
|
||||
super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
|
||||
m_ExplodeTimer(0),
|
||||
m_FireworkItem(a_Item)
|
||||
{
|
||||
}
|
||||
|
||||
@ -702,30 +734,20 @@ super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||
|
||||
|
||||
|
||||
void cFireworkEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||
{
|
||||
if ((a_HitFace != BLOCK_FACE_BOTTOM) && (a_HitFace != BLOCK_FACE_NONE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetSpeed(0, 0, 0);
|
||||
SetPosition(GetPosX(), GetPosY() - 0.5, GetPosZ());
|
||||
|
||||
m_IsInGround = true;
|
||||
|
||||
BroadcastMovementUpdate();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
|
||||
int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
|
||||
int PosY = POSY_TOINT;
|
||||
|
||||
if ((PosY < 0) || (PosY >= cChunkDef::Height))
|
||||
{
|
||||
goto setspeed;
|
||||
}
|
||||
|
||||
if (m_IsInGround)
|
||||
{
|
||||
if (a_Chunk.GetBlock((int)GetPosX(), (int)GetPosY() + 1, (int)GetPosZ()) == E_BLOCK_AIR)
|
||||
if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR)
|
||||
{
|
||||
m_IsInGround = false;
|
||||
}
|
||||
@ -734,28 +756,35 @@ void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Vector3d PerTickSpeed = GetSpeed() / 20;
|
||||
Vector3d Pos = GetPosition();
|
||||
|
||||
// Trace the tick's worth of movement as a line:
|
||||
Vector3d NextPos = Pos + PerTickSpeed;
|
||||
cProjectileTracerCallback TracerCallback(this);
|
||||
if (!cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos))
|
||||
else
|
||||
{
|
||||
// Something has been hit, abort all other processing
|
||||
return;
|
||||
if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR)
|
||||
{
|
||||
OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff
|
||||
|
||||
// Update the position:
|
||||
SetPosition(NextPos);
|
||||
setspeed:
|
||||
AddSpeedY(1);
|
||||
AddPosition(GetSpeed() * (a_Dt / 1000));
|
||||
}
|
||||
|
||||
// Add slowdown and gravity effect to the speed:
|
||||
Vector3d NewSpeed(GetSpeed());
|
||||
NewSpeed.y += 2;
|
||||
NewSpeed *= TracerCallback.GetSlowdownCoeff();
|
||||
SetSpeed(NewSpeed);
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
super::Tick(a_Dt, a_Chunk);
|
||||
|
||||
if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks)
|
||||
{
|
||||
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_FIREWORK_EXPLODE);
|
||||
Destroy();
|
||||
}
|
||||
|
||||
m_ExplodeTimer++;
|
||||
}
|
||||
|
||||
|
||||
|
@ -46,7 +46,7 @@ public:
|
||||
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
|
||||
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height);
|
||||
|
||||
static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed = NULL);
|
||||
static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item, const Vector3d * a_Speed = NULL);
|
||||
|
||||
/// Called by the physics blocktracer when the entity hits a solid block, the hit position and the face hit (BLOCK_FACE_) is given
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace);
|
||||
@ -259,6 +259,7 @@ protected:
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
|
||||
// tolua_begin
|
||||
|
||||
@ -305,13 +306,19 @@ public:
|
||||
|
||||
CLASS_PROTODEF(cFireworkEntity);
|
||||
|
||||
cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z);
|
||||
cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item);
|
||||
const cItem & GetItem(void) const { return m_FireworkItem; }
|
||||
|
||||
protected:
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
private:
|
||||
|
||||
int m_ExplodeTimer;
|
||||
cItem m_FireworkItem;
|
||||
|
||||
// tolua_begin
|
||||
|
||||
|
@ -175,7 +175,7 @@ void cFurnaceRecipe::ReloadRecipes(void)
|
||||
{
|
||||
LOGERROR("ERROR: FurnaceRecipe, syntax error" );
|
||||
}
|
||||
LOG("Loaded %u furnace recipes and %u fuels", m_pState->Recipes.size(), m_pState->Fuel.size());
|
||||
LOG("Loaded " SIZE_T_FMT " furnace recipes and " SIZE_T_FMT " fuels", m_pState->Recipes.size(), m_pState->Fuel.size());
|
||||
}
|
||||
|
||||
|
||||
|
@ -116,7 +116,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_Chunk
|
||||
// Add to queue, issue a warning if too many:
|
||||
if (m_Queue.size() >= QUEUE_WARNING_LIMIT)
|
||||
{
|
||||
LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (%i)", a_ChunkX, a_ChunkZ, m_Queue.size());
|
||||
LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (" SIZE_T_FMT ")", a_ChunkX, a_ChunkZ, m_Queue.size());
|
||||
}
|
||||
m_Queue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
|
||||
}
|
||||
@ -180,7 +180,7 @@ BLOCKTYPE cChunkGenerator::GetIniBlock(cIniFile & a_IniFile, const AString & a_S
|
||||
BLOCKTYPE Block = BlockStringToType(BlockType);
|
||||
if (Block < 0)
|
||||
{
|
||||
LOGWARN("[&s].%s Could not parse block value \"%s\". Using default: \"%s\".", a_SectionName.c_str(), a_ValueName.c_str(), BlockType.c_str(),a_Default.c_str());
|
||||
LOGWARN("[%s].%s Could not parse block value \"%s\". Using default: \"%s\".", a_SectionName.c_str(), a_ValueName.c_str(), BlockType.c_str(),a_Default.c_str());
|
||||
return BlockStringToType(a_Default);
|
||||
}
|
||||
return Block;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "EndGen.h"
|
||||
#include "MineShafts.h"
|
||||
#include "Noise3DGenerator.h"
|
||||
#include "POCPieceGenerator.h"
|
||||
#include "Ravines.h"
|
||||
|
||||
|
||||
@ -364,6 +365,10 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
|
||||
{
|
||||
m_FinishGens.push_back(new cStructGenOreNests(Seed));
|
||||
}
|
||||
else if (NoCaseCompare(*itr, "POCPieces") == 0)
|
||||
{
|
||||
m_FinishGens.push_back(new cPOCPieceGenerator(Seed));
|
||||
}
|
||||
else if (NoCaseCompare(*itr, "PreSimulator") == 0)
|
||||
{
|
||||
m_FinishGens.push_back(new cFinishGenPreSimulator);
|
||||
|
@ -69,6 +69,8 @@ public:
|
||||
m_BoundingBox(a_BoundingBox)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~cMineShaft() {}
|
||||
|
||||
/// Returns true if this mineshaft intersects the specified cuboid
|
||||
bool DoesIntersect(const cCuboid & a_Other)
|
||||
|
270
src/Generating/POCPieceGenerator.cpp
Normal file
270
src/Generating/POCPieceGenerator.cpp
Normal file
@ -0,0 +1,270 @@
|
||||
|
||||
// POCPieceGenerator.cpp
|
||||
|
||||
// Implements the cPOCPieceGenerator class representing a Proof-Of_Concept structure generator using the cPieceGenerator technique
|
||||
// The generator generates a maze of rooms at {0, 50, 0}
|
||||
|
||||
#include "Globals.h"
|
||||
#include "POCPieceGenerator.h"
|
||||
#include "ChunkDesc.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** POC pieces are simple boxes that have connectors in the middle of their walls.
|
||||
Each wall has one connector, there are 3 connector types that get assigned semi-randomly.
|
||||
The piece also knows how to imprint itself in a cChunkDesc, each piece has a different color glass
|
||||
and each connector is uses a different color wool frame. */
|
||||
class cPOCPiece :
|
||||
public cPiece
|
||||
{
|
||||
public:
|
||||
cPOCPiece(int a_SizeXZ, int a_Height) :
|
||||
m_SizeXZ(a_SizeXZ),
|
||||
m_Height(a_Height)
|
||||
{
|
||||
m_Connectors.push_back(cConnector(m_SizeXZ / 2, a_Height / 2, 0, 0, BLOCK_FACE_ZM));
|
||||
m_Connectors.push_back(cConnector(m_SizeXZ / 2, a_Height / 2, m_SizeXZ - 1, 1, BLOCK_FACE_ZP));
|
||||
m_Connectors.push_back(cConnector(0, a_Height / 2, m_SizeXZ / 2, 2, BLOCK_FACE_XM));
|
||||
m_Connectors.push_back(cConnector(m_SizeXZ - 1, a_Height - 1, m_SizeXZ / 2, m_SizeXZ % 3, BLOCK_FACE_XP));
|
||||
}
|
||||
|
||||
|
||||
/** Imprints the piece in the specified chunk. Assumes they intersect. */
|
||||
void ImprintInChunk(cChunkDesc & a_ChunkDesc, const Vector3i & a_Pos, int a_NumCCWRotations)
|
||||
{
|
||||
int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
|
||||
int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
|
||||
Vector3i Min = a_Pos;
|
||||
Min.Move(-BlockX, 0, -BlockZ);
|
||||
Vector3i Max = Min;
|
||||
Max.Move(m_SizeXZ - 1, m_Height - 1, m_SizeXZ - 1);
|
||||
ASSERT(Min.x < cChunkDef::Width);
|
||||
ASSERT(Min.z < cChunkDef::Width);
|
||||
ASSERT(Max.x >= 0);
|
||||
ASSERT(Max.z >= 0);
|
||||
if (Min.x >= 0)
|
||||
{
|
||||
// Draw the XM wall:
|
||||
a_ChunkDesc.FillRelCuboid(Min.x, Min.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16);
|
||||
}
|
||||
if (Min.z >= 0)
|
||||
{
|
||||
// Draw the ZM wall:
|
||||
a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Min.z, Min.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16);
|
||||
}
|
||||
if (Max.x < cChunkDef::Width)
|
||||
{
|
||||
// Draw the XP wall:
|
||||
a_ChunkDesc.FillRelCuboid(Max.x, Max.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16);
|
||||
}
|
||||
if (Max.z < cChunkDef::Width)
|
||||
{
|
||||
// Draw the ZP wall:
|
||||
a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Max.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16);
|
||||
}
|
||||
|
||||
// Draw all the connectors:
|
||||
for (cConnectors::const_iterator itr = m_Connectors.begin(), end = m_Connectors.end(); itr != end; ++itr)
|
||||
{
|
||||
cConnector Conn = cPiece::RotateMoveConnector(*itr, a_NumCCWRotations, a_Pos.x, a_Pos.y, a_Pos.z);
|
||||
Conn.m_Pos.Move(-BlockX, 0, -BlockZ);
|
||||
if (
|
||||
(Conn.m_Pos.x >= 0) && (Conn.m_Pos.x < cChunkDef::Width) &&
|
||||
(Conn.m_Pos.z >= 0) && (Conn.m_Pos.z < cChunkDef::Width)
|
||||
)
|
||||
{
|
||||
a_ChunkDesc.SetBlockTypeMeta(Conn.m_Pos.x, Conn.m_Pos.y, Conn.m_Pos.z, E_BLOCK_WOOL, itr->m_Type % 16);
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO: Frame the connectors
|
||||
switch (itr->m_Direction)
|
||||
{
|
||||
case BLOCK_FACE_XM:
|
||||
case BLOCK_FACE_XP:
|
||||
{
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
|
||||
case BLOCK_FACE_ZM:
|
||||
case BLOCK_FACE_ZP:
|
||||
{
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
} // for itr - m_Connectors[]
|
||||
}
|
||||
|
||||
protected:
|
||||
int m_SizeXZ;
|
||||
int m_Height;
|
||||
cConnectors m_Connectors;
|
||||
|
||||
// cPiece overrides:
|
||||
virtual cConnectors GetConnectors(void) const override
|
||||
{
|
||||
return m_Connectors;
|
||||
}
|
||||
|
||||
virtual Vector3i GetSize(void) const override
|
||||
{
|
||||
return Vector3i(m_SizeXZ, m_Height, m_SizeXZ);
|
||||
}
|
||||
|
||||
virtual cCuboid GetHitBox(void) const override
|
||||
{
|
||||
return cCuboid(0, 0, 0, m_SizeXZ - 1, m_Height - 1, m_SizeXZ - 1);
|
||||
}
|
||||
|
||||
virtual bool CanRotateCCW(int a_NumRotations) const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
static void DebugPieces(const cPlacedPieces & a_Pieces)
|
||||
{
|
||||
size_t idx = 0;
|
||||
for (cPlacedPieces::const_iterator itr = a_Pieces.begin(), end = a_Pieces.end(); itr != end; ++itr, ++idx)
|
||||
{
|
||||
const cCuboid & HitBox = (*itr)->GetHitBox();
|
||||
printf(" %u: %d rotations, {%d - %d, %d - %d}\n",
|
||||
idx, (*itr)->GetNumCCWRotations(),
|
||||
HitBox.p1.x, HitBox.p2.x, HitBox.p1.z, HitBox.p2.z
|
||||
);
|
||||
} // for itr - a_Pieces[]
|
||||
}
|
||||
//*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cPOCPieceGenerator:
|
||||
|
||||
cPOCPieceGenerator::cPOCPieceGenerator(int a_Seed) :
|
||||
m_Seed(a_Seed)
|
||||
{
|
||||
// Prepare a vector of available pieces:
|
||||
m_AvailPieces.push_back(new cPOCPiece(5, 3));
|
||||
m_AvailPieces.push_back(new cPOCPiece(7, 5));
|
||||
m_AvailPieces.push_back(new cPOCPiece(9, 5));
|
||||
m_AvailPieces.push_back(new cPOCPiece(5, 7));
|
||||
|
||||
// Generate the structure:
|
||||
cBFSPieceGenerator Gen(*this, a_Seed);
|
||||
Gen.PlacePieces(0, 50, 0, 6, m_Pieces);
|
||||
|
||||
// DebugPieces(m_Pieces);
|
||||
|
||||
// Get the smallest cuboid encompassing the entire generated structure:
|
||||
cCuboid Bounds(0, 50, 0, 0, 50, 0);
|
||||
for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
|
||||
{
|
||||
Vector3i MinCoords = (*itr)->GetCoords();
|
||||
Bounds.Engulf(MinCoords);
|
||||
Bounds.Engulf(MinCoords + (*itr)->GetPiece().GetSize());
|
||||
} // for itr - m_Pieces[]
|
||||
m_Bounds = Bounds;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cPOCPieceGenerator::~cPOCPieceGenerator()
|
||||
{
|
||||
cPieceGenerator::FreePieces(m_Pieces);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPOCPieceGenerator::GenFinish(cChunkDesc & a_ChunkDesc)
|
||||
{
|
||||
int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
|
||||
int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
|
||||
if (
|
||||
(BlockX + 16 < m_Bounds.p1.x) || (BlockX > m_Bounds.p2.x) || // X coords out of bounds of the generated structure
|
||||
(BlockZ + 16 < m_Bounds.p1.z) || (BlockZ > m_Bounds.p2.z) // Z coords out of bounds of the generated structure
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Imprint each piece in the chunk:
|
||||
for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
|
||||
{
|
||||
const Vector3i & Pos = (*itr)->GetCoords();
|
||||
Vector3i Size = (*itr)->GetPiece().GetSize();
|
||||
if (((*itr)->GetNumCCWRotations() % 2) == 1)
|
||||
{
|
||||
std::swap(Size.x, Size.z);
|
||||
}
|
||||
if (
|
||||
(Pos.x >= BlockX + 16) || (Pos.x + Size.x - 1 < BlockX) ||
|
||||
(Pos.z >= BlockZ + 16) || (Pos.z + Size.z - 1 < BlockZ)
|
||||
)
|
||||
{
|
||||
// This piece doesn't intersect the chunk
|
||||
continue;
|
||||
}
|
||||
|
||||
((cPOCPiece &)(*itr)->GetPiece()).ImprintInChunk(a_ChunkDesc, Pos, (*itr)->GetNumCCWRotations());
|
||||
} // for itr - m_Pieces[]
|
||||
a_ChunkDesc.UpdateHeightmap();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cPieces cPOCPieceGenerator::GetPiecesWithConnector(int a_ConnectorType)
|
||||
{
|
||||
// Each piece has each connector
|
||||
return m_AvailPieces;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cPieces cPOCPieceGenerator::GetStartingPieces(void)
|
||||
{
|
||||
// Any piece can be a starting piece
|
||||
return m_AvailPieces;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPOCPieceGenerator::PiecePlaced(const cPiece & a_Piece)
|
||||
{
|
||||
UNUSED(a_Piece);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPOCPieceGenerator::Reset(void)
|
||||
{
|
||||
// Nothing needed
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
54
src/Generating/POCPieceGenerator.h
Normal file
54
src/Generating/POCPieceGenerator.h
Normal file
@ -0,0 +1,54 @@
|
||||
|
||||
// POCPieceGenerator.h
|
||||
|
||||
// Declares the cPOCPieceGenerator class representing a Proof-Of_Concept structure generator using the cPieceGenerator technique
|
||||
// The generator generates a maze of rooms at {0, 100, 0}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PieceGenerator.h"
|
||||
#include "ComposableGenerator.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cPOCPieceGenerator :
|
||||
public cFinishGen,
|
||||
protected cPiecePool
|
||||
{
|
||||
public:
|
||||
cPOCPieceGenerator(int a_Seed);
|
||||
~cPOCPieceGenerator();
|
||||
|
||||
protected:
|
||||
int m_Seed;
|
||||
|
||||
/** The pieces from which the generated structure is built. */
|
||||
cPieces m_AvailPieces;
|
||||
|
||||
/** The placed pieces of the generated structure. */
|
||||
cPlacedPieces m_Pieces;
|
||||
|
||||
/** Bounds of the complete structure, to save on processing outside chunks. */
|
||||
cCuboid m_Bounds;
|
||||
|
||||
|
||||
// cFinishGen overrides:
|
||||
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
|
||||
|
||||
// cPiecePool overrides:
|
||||
virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override;
|
||||
virtual cPieces GetStartingPieces(void) override;
|
||||
virtual void PiecePlaced(const cPiece & a_Piece) override;
|
||||
virtual void Reset(void) override;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
625
src/Generating/PieceGenerator.cpp
Normal file
625
src/Generating/PieceGenerator.cpp
Normal file
@ -0,0 +1,625 @@
|
||||
|
||||
// PieceGenerator.cpp
|
||||
|
||||
// Implements the cBFSPieceGenerator class and cDFSPieceGenerator class
|
||||
// representing base classes for generating structures composed of individual "pieces"
|
||||
|
||||
#include "Globals.h"
|
||||
#include "PieceGenerator.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef SELF_TEST
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Self-test:
|
||||
|
||||
static class cPieceGeneratorSelfTest :
|
||||
public cPiecePool
|
||||
{
|
||||
public:
|
||||
cPieceGeneratorSelfTest(void)
|
||||
{
|
||||
// Prepare the internal state:
|
||||
InitializePieces();
|
||||
|
||||
// Generate:
|
||||
cBFSPieceGenerator Gen(*this, 0);
|
||||
cPlacedPieces OutPieces;
|
||||
Gen.PlacePieces(500, 50, 500, 3, OutPieces);
|
||||
|
||||
// Print out the pieces:
|
||||
printf("OutPieces.size() = " SIZE_T_FMT "\n", OutPieces.size());
|
||||
size_t idx = 0;
|
||||
for (cPlacedPieces::const_iterator itr = OutPieces.begin(), end = OutPieces.end(); itr != end; ++itr, ++idx)
|
||||
{
|
||||
const Vector3i & Coords = (*itr)->GetCoords();
|
||||
cCuboid Hitbox = (*itr)->GetHitBox();
|
||||
Hitbox.Sort();
|
||||
printf(SIZE_T_FMT ": {%d, %d, %d}, rot %d, hitbox {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n", idx,
|
||||
Coords.x, Coords.y, Coords.z,
|
||||
(*itr)->GetNumCCWRotations(),
|
||||
Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
|
||||
Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z,
|
||||
Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
|
||||
);
|
||||
} // itr - OutPieces[]
|
||||
printf("Done.\n");
|
||||
|
||||
// Free the placed pieces properly:
|
||||
Gen.FreePieces(OutPieces);
|
||||
}
|
||||
|
||||
~cPieceGeneratorSelfTest()
|
||||
{
|
||||
// Dealloc all the pieces:
|
||||
for (cPieces::iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
|
||||
{
|
||||
delete *itr;
|
||||
}
|
||||
m_Pieces.clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
class cTestPiece :
|
||||
public cPiece
|
||||
{
|
||||
int m_Size;
|
||||
public:
|
||||
cTestPiece(int a_Size) :
|
||||
m_Size(a_Size)
|
||||
{
|
||||
}
|
||||
|
||||
virtual cConnectors GetConnectors(void) const override
|
||||
{
|
||||
// Each piece has 4 connectors, one of each type, plus one extra, at the center of its walls:
|
||||
cConnectors res;
|
||||
res.push_back(cConnector(m_Size / 2, 1, 0, 0, BLOCK_FACE_ZM));
|
||||
res.push_back(cConnector(m_Size / 2, 1, m_Size - 1, 1, BLOCK_FACE_ZP));
|
||||
res.push_back(cConnector(0, 1, m_Size / 2, 2, BLOCK_FACE_XM));
|
||||
res.push_back(cConnector(m_Size - 1, 1, m_Size / 2, m_Size % 3, BLOCK_FACE_XP));
|
||||
return res;
|
||||
}
|
||||
|
||||
virtual Vector3i GetSize(void) const override
|
||||
{
|
||||
return Vector3i(m_Size, 5, m_Size);
|
||||
}
|
||||
|
||||
virtual cCuboid GetHitBox(void) const override
|
||||
{
|
||||
return cCuboid(0, 0, 0, m_Size - 1, 4, m_Size - 1);
|
||||
}
|
||||
|
||||
virtual bool CanRotateCCW(int a_NumCCWRotations) const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
cPieces m_Pieces;
|
||||
|
||||
virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override
|
||||
{
|
||||
// Each piece contains each connector
|
||||
return m_Pieces;
|
||||
}
|
||||
|
||||
|
||||
virtual cPieces GetStartingPieces(void) override
|
||||
{
|
||||
return m_Pieces;
|
||||
}
|
||||
|
||||
|
||||
virtual void PiecePlaced(const cPiece & a_Piece) override
|
||||
{
|
||||
UNUSED(a_Piece);
|
||||
}
|
||||
|
||||
|
||||
virtual void Reset(void) override
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void InitializePieces(void)
|
||||
{
|
||||
m_Pieces.push_back(new cTestPiece(5));
|
||||
m_Pieces.push_back(new cTestPiece(7));
|
||||
m_Pieces.push_back(new cTestPiece(9));
|
||||
}
|
||||
} g_Test;
|
||||
|
||||
#endif // SELF_TEST
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cPiece:
|
||||
|
||||
|
||||
Vector3i cPiece::RotatePos(const Vector3i & a_Pos, int a_NumCCWRotations) const
|
||||
{
|
||||
Vector3i Size = GetSize();
|
||||
switch (a_NumCCWRotations)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// No rotation needed
|
||||
return a_Pos;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
// 1 CCW rotation:
|
||||
return Vector3i(a_Pos.z, a_Pos.y, Size.x - a_Pos.x - 1);
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
// 2 rotations ( = axis flip):
|
||||
return Vector3i(Size.x - a_Pos.x - 1, a_Pos.y, Size.z - a_Pos.z - 1);
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
// 1 CW rotation:
|
||||
return Vector3i(Size.z - a_Pos.z - 1, a_Pos.y, a_Pos.x);
|
||||
}
|
||||
}
|
||||
ASSERT(!"Unhandled rotation");
|
||||
return a_Pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cPiece::cConnector cPiece::RotateMoveConnector(const cConnector & a_Connector, int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const
|
||||
{
|
||||
cPiece::cConnector res(a_Connector);
|
||||
|
||||
// Rotate the res connector:
|
||||
switch (a_NumCCWRotations)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// No rotation needed
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
// 1 CCW rotation:
|
||||
res.m_Direction = RotateBlockFaceCCW(res.m_Direction);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
// 2 rotations ( = axis flip):
|
||||
res.m_Direction = MirrorBlockFaceY(res.m_Direction);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
// 1 CW rotation:
|
||||
res.m_Direction = RotateBlockFaceCW(res.m_Direction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
res.m_Pos = RotatePos(a_Connector.m_Pos, a_NumCCWRotations);
|
||||
|
||||
// Move the res connector:
|
||||
res.m_Pos.x += a_MoveX;
|
||||
res.m_Pos.y += a_MoveY;
|
||||
res.m_Pos.z += a_MoveZ;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cCuboid cPiece::RotateHitBoxToConnector(
|
||||
const cPiece::cConnector & a_MyConnector,
|
||||
const Vector3i & a_ToConnectorPos,
|
||||
int a_NumCCWRotations
|
||||
) const
|
||||
{
|
||||
ASSERT(a_NumCCWRotations == (a_NumCCWRotations % 4));
|
||||
Vector3i ConnPos = RotatePos(a_MyConnector.m_Pos, a_NumCCWRotations);
|
||||
ConnPos = a_ToConnectorPos - ConnPos;
|
||||
return RotateMoveHitBox(a_NumCCWRotations, ConnPos.x, ConnPos.y, ConnPos.z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cCuboid cPiece::RotateMoveHitBox(int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const
|
||||
{
|
||||
ASSERT(a_NumCCWRotations == (a_NumCCWRotations % 4));
|
||||
cCuboid res = GetHitBox();
|
||||
res.p1 = RotatePos(res.p1, a_NumCCWRotations);
|
||||
res.p2 = RotatePos(res.p2, a_NumCCWRotations);
|
||||
res.p1.Move(a_MoveX, a_MoveY, a_MoveZ);
|
||||
res.p2.Move(a_MoveX, a_MoveY, a_MoveZ);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cPiece::cConnector:
|
||||
|
||||
cPiece::cConnector::cConnector(int a_X, int a_Y, int a_Z, int a_Type, eBlockFace a_Direction) :
|
||||
m_Pos(a_X, a_Y, a_Z),
|
||||
m_Type(a_Type),
|
||||
m_Direction(a_Direction)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cPiece::cConnector::cConnector(const Vector3i & a_Pos, int a_Type, eBlockFace a_Direction) :
|
||||
m_Pos(a_Pos),
|
||||
m_Type(a_Type),
|
||||
m_Direction(a_Direction)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cPlacedPiece:
|
||||
|
||||
cPlacedPiece::cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece, const Vector3i & a_Coords, int a_NumCCWRotations) :
|
||||
m_Parent(a_Parent),
|
||||
m_Piece(&a_Piece),
|
||||
m_Coords(a_Coords),
|
||||
m_NumCCWRotations(a_NumCCWRotations)
|
||||
{
|
||||
m_Depth = (m_Parent == NULL) ? 0 : (m_Parent->GetDepth() + 1);
|
||||
m_HitBox = a_Piece.RotateMoveHitBox(a_NumCCWRotations, a_Coords.x, a_Coords.y, a_Coords.z);
|
||||
m_HitBox.Sort();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cPieceGenerator:
|
||||
|
||||
cPieceGenerator::cPieceGenerator(cPiecePool & a_PiecePool, int a_Seed) :
|
||||
m_PiecePool(a_PiecePool),
|
||||
m_Noise(a_Seed),
|
||||
m_Seed(a_Seed)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPieceGenerator::FreePieces(cPlacedPieces & a_PlacedPieces)
|
||||
{
|
||||
for (cPlacedPieces::iterator itr = a_PlacedPieces.begin(), end = a_PlacedPieces.end(); itr != end; ++itr)
|
||||
{
|
||||
delete *itr;
|
||||
} // for itr - a_PlacedPieces[]
|
||||
a_PlacedPieces.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cPlacedPiece * cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, int a_BlockZ, cFreeConnectors & a_OutConnectors)
|
||||
{
|
||||
m_PiecePool.Reset();
|
||||
int rnd = m_Noise.IntNoise3DInt(a_BlockX, a_BlockY, a_BlockZ) / 7;
|
||||
|
||||
// Choose a random one of the starting pieces:
|
||||
cPieces StartingPieces = m_PiecePool.GetStartingPieces();
|
||||
cPiece * StartingPiece = StartingPieces[rnd % StartingPieces.size()];
|
||||
rnd = rnd >> 16;
|
||||
|
||||
// Choose a random supported rotation:
|
||||
int Rotations[4] = {0};
|
||||
int NumRotations = 1;
|
||||
for (size_t i = 1; i < ARRAYCOUNT(Rotations); i++)
|
||||
{
|
||||
if (StartingPiece->CanRotateCCW(i))
|
||||
{
|
||||
Rotations[NumRotations] = i;
|
||||
NumRotations += 1;
|
||||
}
|
||||
}
|
||||
int Rotation = Rotations[rnd % NumRotations];
|
||||
|
||||
cPlacedPiece * res = new cPlacedPiece(NULL, *StartingPiece, Vector3i(a_BlockX, a_BlockY, a_BlockZ), Rotation);
|
||||
|
||||
// Place the piece's connectors into a_OutConnectors:
|
||||
const cPiece::cConnectors & Conn = StartingPiece->GetConnectors();
|
||||
for (cPiece::cConnectors::const_iterator itr = Conn.begin(), end = Conn.end(); itr != end; ++itr)
|
||||
{
|
||||
a_OutConnectors.push_back(
|
||||
cFreeConnector(res, StartingPiece->RotateMoveConnector(*itr, Rotation, a_BlockX, a_BlockY, a_BlockZ))
|
||||
);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cPieceGenerator::TryPlacePieceAtConnector(
|
||||
const cPlacedPiece & a_ParentPiece,
|
||||
const cPiece::cConnector & a_Connector,
|
||||
cPlacedPieces & a_OutPieces,
|
||||
cPieceGenerator::cFreeConnectors & a_OutConnectors
|
||||
)
|
||||
{
|
||||
// Translation of direction - direction -> number of CCW rotations needed:
|
||||
// You need DirectionRotationTable[rot1][rot2] CCW turns to connect rot1 to rot2 (they are opposite)
|
||||
static const int DirectionRotationTable[6][6] =
|
||||
{
|
||||
/* YM, YP, ZM, ZP, XM, XP */
|
||||
/* YM */ { 0, 0, 0, 0, 0, 0},
|
||||
/* YP */ { 0, 0, 0, 0, 0, 0},
|
||||
/* ZM */ { 0, 0, 2, 0, 1, 3},
|
||||
/* ZP */ { 0, 0, 0, 2, 3, 1},
|
||||
/* XM */ { 0, 0, 3, 1, 2, 0},
|
||||
/* XP */ { 0, 0, 1, 3, 0, 2},
|
||||
};
|
||||
|
||||
// Get a list of available connections:
|
||||
const int * RotTable = DirectionRotationTable[a_Connector.m_Direction];
|
||||
cConnections Connections;
|
||||
cPieces AvailablePieces = m_PiecePool.GetPiecesWithConnector(a_Connector.m_Type);
|
||||
Connections.reserve(AvailablePieces.size());
|
||||
Vector3i ConnPos = a_Connector.m_Pos; // The position at which the new connector should be placed - 1 block away from the connector
|
||||
AddFaceDirection(ConnPos.x, ConnPos.y, ConnPos.z, a_Connector.m_Direction);
|
||||
|
||||
/*
|
||||
// DEBUG:
|
||||
printf("Placing piece at connector pos {%d, %d, %d}, direction %s\n", ConnPos.x, ConnPos.y, ConnPos.z, BlockFaceToString(a_Connector.m_Direction).c_str());
|
||||
//*/
|
||||
|
||||
for (cPieces::iterator itrP = AvailablePieces.begin(), endP = AvailablePieces.end(); itrP != endP; ++itrP)
|
||||
{
|
||||
cPiece::cConnectors Connectors = (*itrP)->GetConnectors();
|
||||
for (cPiece::cConnectors::iterator itrC = Connectors.begin(), endC = Connectors.end(); itrC != endC; ++itrC)
|
||||
{
|
||||
if (itrC->m_Type != a_Connector.m_Type)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// This is a same-type connector, find out how to rotate to it:
|
||||
int NumCCWRotations = RotTable[itrC->m_Direction];
|
||||
if (!(*itrP)->CanRotateCCW(NumCCWRotations))
|
||||
{
|
||||
// Doesn't support this rotation
|
||||
continue;
|
||||
}
|
||||
if (!CheckConnection(a_Connector, ConnPos, **itrP, *itrC, NumCCWRotations, a_OutPieces))
|
||||
{
|
||||
// Doesn't fit in this rotation
|
||||
continue;
|
||||
}
|
||||
Connections.push_back(cConnection(**itrP, *itrC, NumCCWRotations));
|
||||
} // for itrC - Connectors[]
|
||||
} // for itrP - AvailablePieces[]
|
||||
if (Connections.empty())
|
||||
{
|
||||
// No available connections, bail out
|
||||
return false;
|
||||
}
|
||||
|
||||
// Choose a random connection from the list:
|
||||
int rnd = m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7;
|
||||
cConnection & Conn = Connections[rnd % Connections.size()];
|
||||
|
||||
// Place the piece:
|
||||
/*
|
||||
// DEBUG
|
||||
printf("Chosen connector at {%d, %d, %d}, direction %s, needs %d rotations\n",
|
||||
Conn.m_Connector.m_Pos.x, Conn.m_Connector.m_Pos.y, Conn.m_Connector.m_Pos.z,
|
||||
BlockFaceToString(Conn.m_Connector.m_Direction).c_str(),
|
||||
Conn.m_NumCCWRotations
|
||||
);
|
||||
//*/
|
||||
|
||||
Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations);
|
||||
ConnPos -= NewPos;
|
||||
cPlacedPiece * PlacedPiece = new cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations);
|
||||
a_OutPieces.push_back(PlacedPiece);
|
||||
|
||||
// Add the new piece's connectors to the list of free connectors:
|
||||
cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors();
|
||||
|
||||
/*
|
||||
// DEBUG:
|
||||
printf("Adding %u connectors to the pool\n", Connectors.size() - 1);
|
||||
//*/
|
||||
|
||||
for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr)
|
||||
{
|
||||
if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos))
|
||||
{
|
||||
// This is the connector through which we have been connected to the parent, don't add
|
||||
continue;
|
||||
}
|
||||
a_OutConnectors.push_back(cFreeConnector(PlacedPiece, Conn.m_Piece->RotateMoveConnector(*itr, Conn.m_NumCCWRotations, ConnPos.x, ConnPos.y, ConnPos.z)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cPieceGenerator::CheckConnection(
|
||||
const cPiece::cConnector & a_ExistingConnector,
|
||||
const Vector3i & a_ToPos,
|
||||
const cPiece & a_Piece,
|
||||
const cPiece::cConnector & a_NewConnector,
|
||||
int a_NumCCWRotations,
|
||||
const cPlacedPieces & a_OutPieces
|
||||
)
|
||||
{
|
||||
// For each placed piece, test the hitbox against the new piece:
|
||||
cCuboid RotatedHitBox = a_Piece.RotateHitBoxToConnector(a_NewConnector, a_ToPos, a_NumCCWRotations);
|
||||
RotatedHitBox.Sort();
|
||||
for (cPlacedPieces::const_iterator itr = a_OutPieces.begin(), end = a_OutPieces.end(); itr != end; ++itr)
|
||||
{
|
||||
if ((*itr)->GetHitBox().DoesIntersect(RotatedHitBox))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//*
|
||||
// DEBUG:
|
||||
void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors & a_ConnectorPool, size_t a_NumProcessed)
|
||||
{
|
||||
printf(" Connector pool: " SIZE_T_FMT " items\n", a_ConnectorPool.size() - a_NumProcessed);
|
||||
size_t idx = 0;
|
||||
for (cPieceGenerator::cFreeConnectors::const_iterator itr = a_ConnectorPool.begin() + a_NumProcessed, end = a_ConnectorPool.end(); itr != end; ++itr, ++idx)
|
||||
{
|
||||
printf(" " SIZE_T_FMT ": {%d, %d, %d}, type %d, direction %s, depth %d\n",
|
||||
idx,
|
||||
itr->m_Connector.m_Pos.x, itr->m_Connector.m_Pos.y, itr->m_Connector.m_Pos.z,
|
||||
itr->m_Connector.m_Type,
|
||||
BlockFaceToString(itr->m_Connector.m_Direction).c_str(),
|
||||
itr->m_Piece->GetDepth()
|
||||
);
|
||||
} // for itr - a_ConnectorPool[]
|
||||
}
|
||||
//*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cPieceGenerator::cConnection:
|
||||
|
||||
cPieceGenerator::cConnection::cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations) :
|
||||
m_Piece(&a_Piece),
|
||||
m_Connector(a_Connector),
|
||||
m_NumCCWRotations(a_NumCCWRotations)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cPieceGenerator::cFreeConnector:
|
||||
|
||||
cPieceGenerator::cFreeConnector::cFreeConnector(cPlacedPiece * a_Piece, const cPiece::cConnector & a_Connector) :
|
||||
m_Piece(a_Piece),
|
||||
m_Connector(a_Connector)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cBFSPieceGenerator:
|
||||
|
||||
cBFSPieceGenerator::cBFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed) :
|
||||
super(a_PiecePool, a_Seed)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MaxDepth, cPlacedPieces & a_OutPieces)
|
||||
{
|
||||
a_OutPieces.clear();
|
||||
cFreeConnectors ConnectorPool;
|
||||
|
||||
// Place the starting piece:
|
||||
a_OutPieces.push_back(PlaceStartingPiece(a_BlockX, a_BlockY, a_BlockZ, ConnectorPool));
|
||||
|
||||
/*
|
||||
// DEBUG:
|
||||
printf("Placed the starting piece at {%d, %d, %d}\n", a_BlockX, a_BlockY, a_BlockZ);
|
||||
cCuboid Hitbox = a_OutPieces[0]->GetHitBox();
|
||||
Hitbox.Sort();
|
||||
printf(" Hitbox: {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n",
|
||||
Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
|
||||
Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z,
|
||||
Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
|
||||
);
|
||||
DebugConnectorPool(ConnectorPool, 0);
|
||||
//*/
|
||||
|
||||
// Place pieces at the available connectors:
|
||||
/*
|
||||
Instead of removing them one by one from the pool, we process them sequentially and take note of the last
|
||||
processed one. To save on memory, once the number of processed connectors reaches a big number, a chunk
|
||||
of the connectors is removed.
|
||||
*/
|
||||
size_t NumProcessed = 0;
|
||||
while (ConnectorPool.size() > NumProcessed)
|
||||
{
|
||||
cFreeConnector & Conn = ConnectorPool[NumProcessed];
|
||||
if (Conn.m_Piece->GetDepth() < a_MaxDepth)
|
||||
{
|
||||
if (TryPlacePieceAtConnector(*Conn.m_Piece, Conn.m_Connector, a_OutPieces, ConnectorPool))
|
||||
{
|
||||
/*
|
||||
// DEBUG:
|
||||
const cPlacedPiece * NewPiece = a_OutPieces.back();
|
||||
const Vector3i & Coords = NewPiece->GetCoords();
|
||||
printf("Placed a new piece at {%d, %d, %d}, rotation %d\n", Coords.x, Coords.y, Coords.z, NewPiece->GetNumCCWRotations());
|
||||
cCuboid Hitbox = NewPiece->GetHitBox();
|
||||
Hitbox.Sort();
|
||||
printf(" Hitbox: {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n",
|
||||
Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
|
||||
Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z,
|
||||
Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
|
||||
);
|
||||
DebugConnectorPool(ConnectorPool, NumProcessed + 1);
|
||||
//*/
|
||||
}
|
||||
}
|
||||
NumProcessed++;
|
||||
if (NumProcessed > 1000)
|
||||
{
|
||||
ConnectorPool.erase(ConnectorPool.begin(), ConnectorPool.begin() + NumProcessed);
|
||||
NumProcessed = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
247
src/Generating/PieceGenerator.h
Normal file
247
src/Generating/PieceGenerator.h
Normal file
@ -0,0 +1,247 @@
|
||||
|
||||
// PieceGenerator.h
|
||||
|
||||
// Declares the cBFSPieceGenerator class and cDFSPieceGenerator class
|
||||
// representing base classes for generating structures composed of individual "pieces"
|
||||
|
||||
/*
|
||||
Each uses a slightly different approach to generating:
|
||||
- DFS extends pieces one by one until it hits the configured depth (or can't connect another piece anymore),
|
||||
then starts looking at adjacent connectors (like depth-first search).
|
||||
- BFS keeps a pool of currently-open connectors, chooses one at random and tries to place a piece on it,
|
||||
thus possibly extending the pool of open connectors (like breadth-first search).
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Defines.h"
|
||||
#include "../Cuboid.h"
|
||||
#include "../Noise.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Represents a single piece. Can have multiple connectors of different types where other pieces can connect. */
|
||||
class cPiece
|
||||
{
|
||||
public:
|
||||
// Force a virtual destructor in all descendants
|
||||
virtual ~cPiece() {}
|
||||
|
||||
struct cConnector
|
||||
{
|
||||
/** Position relative to the piece */
|
||||
Vector3i m_Pos;
|
||||
|
||||
/** Type of the connector. Any arbitrary number; the generator connects only connectors of the same type. */
|
||||
int m_Type;
|
||||
|
||||
/** Direction in which the connector is facing.
|
||||
Will be matched by the opposite direction for the connecting connector. */
|
||||
eBlockFace m_Direction;
|
||||
|
||||
cConnector(int a_X, int a_Y, int a_Z, int a_Type, eBlockFace a_Direction);
|
||||
cConnector(const Vector3i & a_Pos, int a_Type, eBlockFace a_Direction);
|
||||
};
|
||||
|
||||
typedef std::vector<cConnector> cConnectors;
|
||||
|
||||
/** Returns all of the available connectors that the piece has.
|
||||
Each connector has a (relative) position in the piece, and a type associated with it. */
|
||||
virtual cConnectors GetConnectors(void) const = 0;
|
||||
|
||||
/** Returns the dimensions of this piece.
|
||||
The dimensions cover the entire piece, there is no block that the piece generates outside of this size. */
|
||||
virtual Vector3i GetSize(void) const = 0;
|
||||
|
||||
/** Returns the "hitbox" of this piece.
|
||||
A hitbox is what is compared and must not intersect other pieces' hitboxes when generating. */
|
||||
virtual cCuboid GetHitBox(void) const = 0;
|
||||
|
||||
/** Returns true if the piece can be rotated CCW the specific number of 90-degree turns. */
|
||||
virtual bool CanRotateCCW(int a_NumRotations) const = 0;
|
||||
|
||||
/** Returns a copy of the a_Pos after rotating the piece the specified number of CCW rotations. */
|
||||
Vector3i RotatePos(const Vector3i & a_Pos, int a_NumCCWRotations) const;
|
||||
|
||||
/** Returns a copy of the connector that is rotated and then moved by the specified amounts. */
|
||||
cConnector RotateMoveConnector(const cConnector & a_Connector, int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const;
|
||||
|
||||
/** Returns the hitbox after the specified number of rotations and moved so that a_MyConnector is placed at a_ToConnectorPos. */
|
||||
cCuboid RotateHitBoxToConnector(const cConnector & a_MyConnector, const Vector3i & a_ToConnectorPos, int a_NumCCWRotations) const;
|
||||
|
||||
/** Returns the hitbox after the specified number of CCW rotations and moved by the specified amounts. */
|
||||
cCuboid RotateMoveHitBox(int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const;
|
||||
};
|
||||
|
||||
typedef std::vector<cPiece *> cPieces;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** This class is an interface that provides pieces for the generator. It can keep track of what pieces were
|
||||
placed and adjust the returned piece vectors. */
|
||||
class cPiecePool
|
||||
{
|
||||
public:
|
||||
// Force a virtual destructor in all descendants:
|
||||
virtual ~cPiecePool() {}
|
||||
|
||||
/** Returns a list of pieces that contain the specified connector type.
|
||||
The cPiece pointers returned are managed by the pool and the caller doesn't free them. */
|
||||
virtual cPieces GetPiecesWithConnector(int a_ConnectorType) = 0;
|
||||
|
||||
/** Returns the pieces that should be used as the starting point.
|
||||
Multiple starting points are supported, one of the returned piece will be chosen. */
|
||||
virtual cPieces GetStartingPieces(void) = 0;
|
||||
|
||||
/** Called after a piece is placed, to notify the pool that it has been used.
|
||||
The pool may adjust the pieces it will return the next time. */
|
||||
virtual void PiecePlaced(const cPiece & a_Piece) = 0;
|
||||
|
||||
/** Called when the pool has finished the current structure and should reset any piece-counters it has
|
||||
for a new structure. */
|
||||
virtual void Reset(void) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Represents a single piece that has been placed to specific coords in the world. */
|
||||
class cPlacedPiece
|
||||
{
|
||||
public:
|
||||
cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece, const Vector3i & a_Coords, int a_NumCCWRotations);
|
||||
|
||||
const cPiece & GetPiece (void) const { return *m_Piece; }
|
||||
const Vector3i & GetCoords (void) const { return m_Coords; }
|
||||
int GetNumCCWRotations(void) const { return m_NumCCWRotations; }
|
||||
const cCuboid & GetHitBox (void) const { return m_HitBox; }
|
||||
int GetDepth (void) const { return m_Depth; }
|
||||
|
||||
protected:
|
||||
const cPlacedPiece * m_Parent;
|
||||
const cPiece * m_Piece;
|
||||
Vector3i m_Coords;
|
||||
int m_NumCCWRotations;
|
||||
cCuboid m_HitBox;
|
||||
int m_Depth;
|
||||
};
|
||||
|
||||
typedef std::vector<cPlacedPiece *> cPlacedPieces;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cPieceGenerator
|
||||
{
|
||||
public:
|
||||
cPieceGenerator(cPiecePool & a_PiecePool, int a_Seed);
|
||||
|
||||
/** Cleans up all the memory used by the placed pieces.
|
||||
Call this utility function instead of freeing the items on your own. */
|
||||
static void FreePieces(cPlacedPieces & a_PlacedPieces);
|
||||
|
||||
protected:
|
||||
/** The type used for storing a connection from one piece to another, while building the piece tree. */
|
||||
struct cConnection
|
||||
{
|
||||
cPiece * m_Piece; // The piece being connected
|
||||
cPiece::cConnector m_Connector; // The piece's connector being used (relative non-rotated coords)
|
||||
int m_NumCCWRotations; // Number of rotations necessary to match the two connectors
|
||||
|
||||
cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations);
|
||||
};
|
||||
typedef std::vector<cConnection> cConnections;
|
||||
|
||||
/** The type used for storing a pool of connectors that will be attempted to expand by another piece. */
|
||||
struct cFreeConnector
|
||||
{
|
||||
cPlacedPiece * m_Piece;
|
||||
cPiece::cConnector m_Connector;
|
||||
|
||||
cFreeConnector(cPlacedPiece * a_Piece, const cPiece::cConnector & a_Connector);
|
||||
};
|
||||
typedef std::vector<cFreeConnector> cFreeConnectors;
|
||||
|
||||
|
||||
cPiecePool & m_PiecePool;
|
||||
cNoise m_Noise;
|
||||
int m_Seed;
|
||||
|
||||
|
||||
/** Selects a starting piece and places it, including the rotations.
|
||||
Also puts the piece's connectors in a_OutConnectors. */
|
||||
cPlacedPiece * PlaceStartingPiece(int a_BlockX, int a_BlockY, int a_BlockZ, cFreeConnectors & a_OutConnectors);
|
||||
|
||||
/** Tries to place a new piece at the specified (placed) connector. Returns true if successful. */
|
||||
bool TryPlacePieceAtConnector(
|
||||
const cPlacedPiece & a_ParentPiece, // The existing piece to a new piece should be placed
|
||||
const cPiece::cConnector & a_Connector, // The existing connector (world-coords) to which a new piece should be placed
|
||||
cPlacedPieces & a_OutPieces, // Already placed pieces, to be checked for intersections
|
||||
cFreeConnectors & a_OutConnectors // List of free connectors to which the new connectors will be placed
|
||||
);
|
||||
|
||||
/** Checks if the specified piece would fit with the already-placed pieces, using the specified connector
|
||||
and number of CCW rotations.
|
||||
a_ExistingConnector is in world-coords and is already rotated properly
|
||||
a_ToPos is the world-coords position on which the new connector should be placed (1 block away from a_ExistingConnector, in its Direction)
|
||||
a_NewConnector is in the original (non-rotated) coords.
|
||||
Returns true if the piece fits, false if not. */
|
||||
bool CheckConnection(
|
||||
const cPiece::cConnector & a_ExistingConnector, // The existing connector
|
||||
const Vector3i & a_ToPos, // The position on which the new connector should be placed
|
||||
const cPiece & a_Piece, // The new piece
|
||||
const cPiece::cConnector & a_NewConnector, // The connector of the new piece
|
||||
int a_NumCCWRotations, // Number of rotations for the new piece to align the connector
|
||||
const cPlacedPieces & a_OutPieces // All the already-placed pieces to check
|
||||
);
|
||||
|
||||
/** DEBUG: Outputs all the connectors in the pool into stdout.
|
||||
a_NumProcessed signals the number of connectors from the pool that should be considered processed (not listed). */
|
||||
void DebugConnectorPool(const cPieceGenerator::cFreeConnectors & a_ConnectorPool, size_t a_NumProcessed);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cBFSPieceGenerator :
|
||||
public cPieceGenerator
|
||||
{
|
||||
typedef cPieceGenerator super;
|
||||
|
||||
public:
|
||||
cBFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed);
|
||||
|
||||
/** Generates a placement for pieces at the specified coords.
|
||||
Caller must free each individual cPlacedPiece in a_OutPieces. */
|
||||
void PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MaxDepth, cPlacedPieces & a_OutPieces);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cDFSPieceGenerator :
|
||||
public cPieceGenerator
|
||||
{
|
||||
public:
|
||||
cDFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed);
|
||||
|
||||
/** Generates a placement for pieces at the specified coords.
|
||||
Caller must free each individual cPlacedPiece in a_OutPieces. */
|
||||
void PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, cPlacedPieces & a_OutPieces);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -595,7 +595,7 @@ void GetPineTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise
|
||||
{
|
||||
break;
|
||||
}
|
||||
ASSERT(LayerSize < ARRAYCOUNT(BigOs));
|
||||
ASSERT((size_t)LayerSize < ARRAYCOUNT(BigOs));
|
||||
PushCoordBlocks(a_BlockX, h, a_BlockZ, a_OtherBlocks, BigOs[LayerSize].Coords, BigOs[LayerSize].Count, E_BLOCK_LEAVES, E_META_LEAVES_CONIFER);
|
||||
h--;
|
||||
}
|
||||
|
@ -38,6 +38,15 @@
|
||||
// No alignment needed in MSVC
|
||||
#define ALIGN_8
|
||||
#define ALIGN_16
|
||||
|
||||
#define FORMATSTRING(formatIndex, va_argsIndex)
|
||||
|
||||
// MSVC has its own custom version of zu format
|
||||
#define SIZE_T_FMT "%Iu"
|
||||
#define SIZE_T_FMT_PRECISION(x) "%" #x "Iu"
|
||||
#define SIZE_T_FMT_HEX "%Ix"
|
||||
|
||||
#define NORETURN __declspec(noreturn)
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
@ -56,6 +65,14 @@
|
||||
|
||||
// Some portability macros :)
|
||||
#define stricmp strcasecmp
|
||||
|
||||
#define FORMATSTRING(formatIndex, va_argsIndex) __attribute__((format (printf, formatIndex, va_argsIndex)))
|
||||
|
||||
#define SIZE_T_FMT "%zu"
|
||||
#define SIZE_T_FMT_PRECISION(x) "%" #x "zu"
|
||||
#define SIZE_T_FMT_HEX "%zx"
|
||||
|
||||
#define NORETURN __attribute((__noreturn__))
|
||||
|
||||
#else
|
||||
|
||||
@ -81,8 +98,15 @@
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define NORETURNDEBUG NORETURN
|
||||
#else
|
||||
#define NORETURNDEBUG
|
||||
#endif
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
// Integral types with predefined sizes:
|
||||
typedef long long Int64;
|
||||
@ -96,8 +120,23 @@ typedef unsigned short UInt16;
|
||||
typedef unsigned char Byte;
|
||||
|
||||
|
||||
// If you get an error about specialization check the size of integral types
|
||||
template <typename T, size_t Size, bool x = sizeof(T) == Size>
|
||||
class SizeChecker;
|
||||
|
||||
template <typename T, size_t Size>
|
||||
class SizeChecker<T, Size, true>
|
||||
{
|
||||
T v;
|
||||
};
|
||||
|
||||
template class SizeChecker<Int64, 8>;
|
||||
template class SizeChecker<Int32, 4>;
|
||||
template class SizeChecker<Int16, 2>;
|
||||
|
||||
template class SizeChecker<UInt64, 8>;
|
||||
template class SizeChecker<UInt32, 4>;
|
||||
template class SizeChecker<UInt16, 2>;
|
||||
|
||||
// A macro to disallow the copy constructor and operator= functions
|
||||
// This should be used in the private: declarations for any class that shouldn't allow copying itself
|
||||
@ -179,7 +218,7 @@ typedef unsigned char Byte;
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <queue>
|
||||
|
||||
#include <limits>
|
||||
|
||||
|
||||
|
||||
@ -220,9 +259,10 @@ typedef unsigned char Byte;
|
||||
// Pretty much the same as ASSERT() but stays in Release builds
|
||||
#define VERIFY( x ) ( !!(x) || ( LOGERROR("Verification failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), exit(1), 0 ) )
|
||||
|
||||
|
||||
|
||||
|
||||
// Same as assert but in all Self test builds
|
||||
#ifdef SELF_TEST
|
||||
#define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
|
||||
#endif
|
||||
|
||||
/// A generic interface used mainly in ForEach() functions
|
||||
template <typename Type> class cItemCallback
|
||||
@ -246,6 +286,14 @@ T Clamp(T a_Value, T a_Min, T a_Max)
|
||||
|
||||
|
||||
|
||||
#ifndef TOLUA_TEMPLATE_BIND
|
||||
#define TOLUA_TEMPLATE_BIND(x)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Common headers (part 2, with macros):
|
||||
#include "ChunkDef.h"
|
||||
#include "BiomeDef.h"
|
||||
@ -254,5 +302,3 @@ T Clamp(T a_Value, T a_Min, T a_Max)
|
||||
#include "Entities/Effects.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
30
src/Item.cpp
30
src/Item.cpp
@ -1,4 +1,4 @@
|
||||
|
||||
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "Item.h"
|
||||
@ -139,6 +139,16 @@ void cItem::GetJson(Json::Value & a_OutValue) const
|
||||
{
|
||||
a_OutValue["Lore"] = m_Lore;
|
||||
}
|
||||
|
||||
if ((m_ItemType == E_ITEM_FIREWORK_ROCKET) || (m_ItemType == E_ITEM_FIREWORK_STAR))
|
||||
{
|
||||
a_OutValue["Flicker"] = m_FireworkItem.m_HasFlicker;
|
||||
a_OutValue["Trail"] = m_FireworkItem.m_HasTrail;
|
||||
a_OutValue["Type"] = m_FireworkItem.m_Type;
|
||||
a_OutValue["FlightTimeInTicks"] = m_FireworkItem.m_FlightTimeInTicks;
|
||||
a_OutValue["Colours"] = m_FireworkItem.ColoursToString(m_FireworkItem);
|
||||
a_OutValue["FadeColours"] = m_FireworkItem.FadeColoursToString(m_FireworkItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,6 +167,16 @@ void cItem::FromJson(const Json::Value & a_Value)
|
||||
m_Enchantments.AddFromString(a_Value.get("ench", "").asString());
|
||||
m_CustomName = a_Value.get("Name", "").asString();
|
||||
m_Lore = a_Value.get("Lore", "").asString();
|
||||
|
||||
if ((m_ItemType == E_ITEM_FIREWORK_ROCKET) || (m_ItemType == E_ITEM_FIREWORK_STAR))
|
||||
{
|
||||
m_FireworkItem.m_HasFlicker = a_Value.get("Flicker", false).asBool();
|
||||
m_FireworkItem.m_HasTrail = a_Value.get("Trail", false).asBool();
|
||||
m_FireworkItem.m_Type = (NIBBLETYPE)a_Value.get("Type", 0).asInt();
|
||||
m_FireworkItem.m_FlightTimeInTicks = (short)a_Value.get("FlightTimeInTicks", 0).asInt();
|
||||
m_FireworkItem.ColoursFromString(a_Value.get("Colours", "").asString(), m_FireworkItem);
|
||||
m_FireworkItem.FadeColoursFromString(a_Value.get("FadeColours", "").asString(), m_FireworkItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,7 +216,7 @@ cItem * cItems::Get(int a_Idx)
|
||||
{
|
||||
if ((a_Idx < 0) || (a_Idx >= (int)size()))
|
||||
{
|
||||
LOGWARNING("cItems: Attempt to get an out-of-bounds item at index %d; there are currently %d items. Returning a nil.", a_Idx, size());
|
||||
LOGWARNING("cItems: Attempt to get an out-of-bounds item at index %d; there are currently " SIZE_T_FMT " items. Returning a nil.", a_Idx, size());
|
||||
return NULL;
|
||||
}
|
||||
return &at(a_Idx);
|
||||
@ -210,7 +230,7 @@ void cItems::Set(int a_Idx, const cItem & a_Item)
|
||||
{
|
||||
if ((a_Idx < 0) || (a_Idx >= (int)size()))
|
||||
{
|
||||
LOGWARNING("cItems: Attempt to set an item at an out-of-bounds index %d; there are currently %d items. Not setting.", a_Idx, size());
|
||||
LOGWARNING("cItems: Attempt to set an item at an out-of-bounds index %d; there are currently " SIZE_T_FMT " items. Not setting.", a_Idx, size());
|
||||
return;
|
||||
}
|
||||
at(a_Idx) = a_Item;
|
||||
@ -224,7 +244,7 @@ void cItems::Delete(int a_Idx)
|
||||
{
|
||||
if ((a_Idx < 0) || (a_Idx >= (int)size()))
|
||||
{
|
||||
LOGWARNING("cItems: Attempt to delete an item at an out-of-bounds index %d; there are currently %d items. Ignoring.", a_Idx, size());
|
||||
LOGWARNING("cItems: Attempt to delete an item at an out-of-bounds index %d; there are currently " SIZE_T_FMT " items. Ignoring.", a_Idx, size());
|
||||
return;
|
||||
}
|
||||
erase(begin() + a_Idx);
|
||||
@ -238,7 +258,7 @@ void cItems::Set(int a_Idx, short a_ItemType, char a_ItemCount, short a_ItemDama
|
||||
{
|
||||
if ((a_Idx < 0) || (a_Idx >= (int)size()))
|
||||
{
|
||||
LOGWARNING("cItems: Attempt to set an item at an out-of-bounds index %d; there are currently %d items. Not setting.", a_Idx, size());
|
||||
LOGWARNING("cItems: Attempt to set an item at an out-of-bounds index %d; there are currently " SIZE_T_FMT " items. Not setting.", a_Idx, size());
|
||||
return;
|
||||
}
|
||||
at(a_Idx) = cItem(a_ItemType, a_ItemCount, a_ItemDamage);
|
||||
|
16
src/Item.h
16
src/Item.h
@ -11,6 +11,7 @@
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Enchantments.h"
|
||||
#include "WorldStorage/FireworksSerializer.h"
|
||||
|
||||
|
||||
|
||||
@ -38,7 +39,8 @@ public:
|
||||
m_ItemCount(0),
|
||||
m_ItemDamage(0),
|
||||
m_CustomName(""),
|
||||
m_Lore("")
|
||||
m_Lore(""),
|
||||
m_FireworkItem()
|
||||
{
|
||||
}
|
||||
|
||||
@ -57,7 +59,8 @@ public:
|
||||
m_ItemDamage (a_ItemDamage),
|
||||
m_Enchantments(a_Enchantments),
|
||||
m_CustomName (a_CustomName),
|
||||
m_Lore (a_Lore)
|
||||
m_Lore (a_Lore),
|
||||
m_FireworkItem()
|
||||
{
|
||||
if (!IsValidItem(m_ItemType))
|
||||
{
|
||||
@ -77,7 +80,8 @@ public:
|
||||
m_ItemDamage (a_CopyFrom.m_ItemDamage),
|
||||
m_Enchantments(a_CopyFrom.m_Enchantments),
|
||||
m_CustomName (a_CopyFrom.m_CustomName),
|
||||
m_Lore (a_CopyFrom.m_Lore)
|
||||
m_Lore (a_CopyFrom.m_Lore),
|
||||
m_FireworkItem(a_CopyFrom.m_FireworkItem)
|
||||
{
|
||||
}
|
||||
|
||||
@ -90,6 +94,7 @@ public:
|
||||
m_Enchantments.Clear();
|
||||
m_CustomName = "";
|
||||
m_Lore = "";
|
||||
m_FireworkItem.EmptyData();
|
||||
}
|
||||
|
||||
|
||||
@ -115,7 +120,8 @@ public:
|
||||
(m_ItemDamage == a_Item.m_ItemDamage) &&
|
||||
(m_Enchantments == a_Item.m_Enchantments) &&
|
||||
(m_CustomName == a_Item.m_CustomName) &&
|
||||
(m_Lore == a_Item.m_Lore)
|
||||
(m_Lore == a_Item.m_Lore) &&
|
||||
m_FireworkItem.IsEqualTo(a_Item.m_FireworkItem)
|
||||
);
|
||||
}
|
||||
|
||||
@ -177,6 +183,8 @@ public:
|
||||
cEnchantments m_Enchantments;
|
||||
AString m_CustomName;
|
||||
AString m_Lore;
|
||||
|
||||
cFireworkItem m_FireworkItem;
|
||||
};
|
||||
// tolua_end
|
||||
|
||||
|
@ -21,6 +21,9 @@ class cItemHandler
|
||||
public:
|
||||
cItemHandler(int a_ItemType);
|
||||
|
||||
// Force virtual destructor
|
||||
virtual ~cItemHandler() {}
|
||||
|
||||
/// Called when the player tries to use the item (right mouse button). Return false to make the item unusable. DEFAULT: False
|
||||
virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir);
|
||||
|
||||
|
@ -19,17 +19,13 @@ public:
|
||||
{
|
||||
switch(m_ItemType)
|
||||
{
|
||||
case E_ITEM_WOODEN_PICKAXE:
|
||||
case E_ITEM_GOLD_PICKAXE:
|
||||
return 1;
|
||||
case E_ITEM_STONE_PICKAXE:
|
||||
return 2;
|
||||
case E_ITEM_IRON_PICKAXE:
|
||||
return 3;
|
||||
case E_ITEM_DIAMOND_PICKAXE:
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
case E_ITEM_WOODEN_PICKAXE: return 1;
|
||||
case E_ITEM_GOLD_PICKAXE: return 1;
|
||||
case E_ITEM_STONE_PICKAXE: return 2;
|
||||
case E_ITEM_IRON_PICKAXE: return 3;
|
||||
case E_ITEM_DIAMOND_PICKAXE: return 4;
|
||||
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,6 +57,10 @@ public:
|
||||
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_STONE:
|
||||
case E_BLOCK_COBBLESTONE:
|
||||
|
@ -35,7 +35,7 @@ public:
|
||||
|
||||
Vector3d Pos = a_Player->GetThrowStartPos();
|
||||
Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff;
|
||||
a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &Speed);
|
||||
a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, a_Player->GetEquippedItem(), &Speed);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -127,13 +127,13 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, a_Player->GetEquippedItem());
|
||||
|
||||
if (!a_Player->IsGameModeCreative())
|
||||
{
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
}
|
||||
|
||||
a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -13,12 +13,6 @@
|
||||
|
||||
|
||||
|
||||
/// If more than this many chunks are in the queue, a warning is printed to the log
|
||||
#define WARN_ON_QUEUE_SIZE 800
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Chunk data callback that takes the chunk data and puts them into cLightingThread's m_BlockTypes[] / m_HeightMap[]:
|
||||
class cReader :
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include "Globals.h"
|
||||
#include "LineBlockTracer.h"
|
||||
#include "Vector3d.h"
|
||||
#include "Vector3.h"
|
||||
#include "World.h"
|
||||
#include "Chunk.h"
|
||||
|
||||
|
@ -118,7 +118,7 @@ void cLog::Log(const char * a_Format, va_list argList)
|
||||
|
||||
AString Line;
|
||||
#ifdef _DEBUG
|
||||
Printf(Line, "[%04x|%02d:%02d:%02d] %s", cIsThread::GetCurrentID(), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, Message.c_str());
|
||||
Printf(Line, "[%04lx|%02d:%02d:%02d] %s", cIsThread::GetCurrentID(), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, Message.c_str());
|
||||
#else
|
||||
Printf(Line, "[%02d:%02d:%02d] %s", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, Message.c_str());
|
||||
#endif
|
||||
|
@ -14,8 +14,8 @@ private:
|
||||
public:
|
||||
cLog(const AString & a_FileName);
|
||||
~cLog();
|
||||
void Log(const char * a_Format, va_list argList);
|
||||
void Log(const char * a_Format, ...);
|
||||
void Log(const char * a_Format, va_list argList) FORMATSTRING(2, 0);
|
||||
void Log(const char * a_Format, ...) FORMATSTRING(2, 3);
|
||||
// tolua_begin
|
||||
void SimpleLog(const char * a_String);
|
||||
void OpenLog(const char * a_FileName);
|
||||
|
@ -21,10 +21,10 @@ public: // tolua_export
|
||||
|
||||
~cMCLogger(); // tolua_export
|
||||
|
||||
void Log(const char* a_Format, va_list a_ArgList);
|
||||
void Info(const char* a_Format, va_list a_ArgList);
|
||||
void Warn(const char* a_Format, va_list a_ArgList);
|
||||
void Error(const char* a_Format, va_list a_ArgList);
|
||||
void Log(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
|
||||
void Info(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
|
||||
void Warn(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
|
||||
void Error(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
|
||||
|
||||
void LogSimple(const char* a_Text, int a_LogType = 0 ); // tolua_export
|
||||
|
||||
@ -57,10 +57,10 @@ private:
|
||||
|
||||
|
||||
|
||||
extern void LOG(const char* a_Format, ...);
|
||||
extern void LOGINFO(const char* a_Format, ...);
|
||||
extern void LOGWARN(const char* a_Format, ...);
|
||||
extern void LOGERROR(const char* a_Format, ...);
|
||||
extern void LOG(const char* a_Format, ...) FORMATSTRING(1, 2);
|
||||
extern void LOGINFO(const char* a_Format, ...) FORMATSTRING(1, 2);
|
||||
extern void LOGWARN(const char* a_Format, ...) FORMATSTRING(1, 2);
|
||||
extern void LOGERROR(const char* a_Format, ...) FORMATSTRING(1, 2);
|
||||
|
||||
|
||||
|
||||
|
@ -64,7 +64,7 @@ public:
|
||||
unsigned int GetPixelX(void) const { return m_PixelX; }
|
||||
unsigned int GetPixelZ(void) const { return m_PixelZ; }
|
||||
|
||||
int GetRot(void) const { return m_Rot; }
|
||||
unsigned int GetRot(void) const { return m_Rot; }
|
||||
|
||||
eType GetType(void) const { return m_Type; }
|
||||
|
||||
|
224
src/Matrix4.h
Normal file
224
src/Matrix4.h
Normal file
@ -0,0 +1,224 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#define _USE_MATH_DEFINES // Enable non-standard math defines (MSVC)
|
||||
#include <math.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
// tolua_begin
|
||||
class Matrix4
|
||||
{
|
||||
|
||||
TOLUA_TEMPLATE_BIND((T, float, double))
|
||||
|
||||
// tolua_end
|
||||
|
||||
public:
|
||||
|
||||
T cell[16];
|
||||
|
||||
// tolua_begin
|
||||
|
||||
inline Matrix4(void)
|
||||
{
|
||||
Identity();
|
||||
}
|
||||
|
||||
inline Matrix4(const Matrix4 & a_Rhs)
|
||||
{
|
||||
*this = a_Rhs;
|
||||
}
|
||||
|
||||
inline Matrix4 & operator = (const Matrix4 & a_Rhs)
|
||||
{
|
||||
for (unsigned int i = 0; i < 16; ++i)
|
||||
{
|
||||
cell[i] = a_Rhs.cell[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline T & operator [] (int a_N)
|
||||
{
|
||||
ASSERT(a_N < 16);
|
||||
return cell[a_N];
|
||||
}
|
||||
|
||||
inline void Identity()
|
||||
{
|
||||
cell[1] = cell[2] = cell[3] = cell[4] = 0;
|
||||
cell[6] = cell[7] = cell[8] = cell[9] = 0;
|
||||
cell[11] = cell[12] = cell[13] = cell[14] = 0;
|
||||
|
||||
cell[0] = cell[5] = cell[10] = cell[15] = 1;
|
||||
}
|
||||
|
||||
inline void Init(const Vector3<T> & a_Pos, T a_RX, T a_RY, T a_RZ)
|
||||
{
|
||||
Matrix4<T> t;
|
||||
t.RotateX(a_RZ);
|
||||
RotateY(a_RY);
|
||||
Concatenate(t);
|
||||
t.RotateZ(a_RX);
|
||||
Concatenate(t);
|
||||
Translate(a_Pos);
|
||||
}
|
||||
|
||||
inline void RotateX(T a_RX)
|
||||
{
|
||||
T sx = (T) sin(a_RX * M_PI / 180);
|
||||
T cx = (T) cos(a_RX * M_PI / 180);
|
||||
|
||||
Identity();
|
||||
|
||||
cell[5] = cx; cell[6] = sx;
|
||||
cell[9] = -sx; cell[10] = cx;
|
||||
}
|
||||
|
||||
inline void RotateY(T a_RY)
|
||||
{
|
||||
T sy = (T) sin(a_RY * M_PI / 180);
|
||||
T cy = (T) cos(a_RY * M_PI / 180);
|
||||
|
||||
Identity();
|
||||
|
||||
cell[0] = cy; cell[2] = -sy;
|
||||
cell[8] = sy; cell[10] = cy;
|
||||
}
|
||||
|
||||
inline void RotateZ(T a_RZ)
|
||||
{
|
||||
T sz = (T) sin(a_RZ * M_PI / 180);
|
||||
T cz = (T) cos(a_RZ * M_PI / 180);
|
||||
|
||||
Identity();
|
||||
|
||||
cell[0] = cz; cell[1] = sz;
|
||||
cell[4] = -sz; cell[5] = cz;
|
||||
}
|
||||
|
||||
inline void Translate(const Vector3<T> & a_Pos)
|
||||
{
|
||||
cell[3] += a_Pos.x;
|
||||
cell[7] += a_Pos.y;
|
||||
cell[11] += a_Pos.z;
|
||||
}
|
||||
|
||||
inline void SetTranslation(const Vector3<T> & a_Pos)
|
||||
{
|
||||
cell[3] = a_Pos.x;
|
||||
cell[7] = a_Pos.y;
|
||||
cell[11] = a_Pos.z;
|
||||
}
|
||||
|
||||
inline void Concatenate(const Matrix4 & m2)
|
||||
{
|
||||
Matrix4 res;
|
||||
|
||||
for (unsigned int c = 0; c < 4; ++c)
|
||||
{
|
||||
for (unsigned int r = 0; r < 4; ++r)
|
||||
{
|
||||
res.cell[r * 4 + c] = (
|
||||
cell[r * 4 + 0] * m2.cell[c + 0] +
|
||||
cell[r * 4 + 1] * m2.cell[c + 4] +
|
||||
cell[r * 4 + 2] * m2.cell[c + 8] +
|
||||
cell[r * 4 + 3] * m2.cell[c + 12]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
*this = res;
|
||||
}
|
||||
|
||||
inline Vector3<T> Transform(const Vector3<T> & v) const
|
||||
{
|
||||
T x = cell[0] * v.x + cell[1] * v.y + cell[2] * v.z + cell[3];
|
||||
T y = cell[4] * v.x + cell[5] * v.y + cell[6] * v.z + cell[7];
|
||||
T z = cell[8] * v.x + cell[9] * v.y + cell[10] * v.z + cell[11];
|
||||
|
||||
return Vector3<T>(x, y, z);
|
||||
}
|
||||
|
||||
inline void Invert(void)
|
||||
{
|
||||
Matrix4 t;
|
||||
|
||||
T tx = -cell[3];
|
||||
T ty = -cell[7];
|
||||
T tz = -cell[11];
|
||||
|
||||
for (unsigned int h = 0; h < 3; ++h)
|
||||
{
|
||||
for (unsigned int v = 0; v < 3; ++v)
|
||||
{
|
||||
t.cell[h + v * 4] = cell[v + h * 4];
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < 11; ++i)
|
||||
{
|
||||
cell[i] = t.cell[i];
|
||||
}
|
||||
|
||||
cell[3] = tx * cell[0] + ty * cell[1] + tz * cell[2];
|
||||
cell[7] = tx * cell[4] + ty * cell[5] + tz * cell[6];
|
||||
cell[11] = tx * cell[8] + ty * cell[9] + tz * cell[10];
|
||||
}
|
||||
|
||||
inline Vector3<T> GetXColumn(void) const
|
||||
{
|
||||
return Vector3<T>(cell[0], cell[1], cell[2]);
|
||||
}
|
||||
|
||||
inline Vector3<T> GetYColumn(void) const
|
||||
{
|
||||
return Vector3<T>(cell[4], cell[5], cell[6]);
|
||||
}
|
||||
|
||||
inline Vector3<T> GetZColumn(void) const
|
||||
{
|
||||
return Vector3<T>(cell[8], cell[9], cell[10]);
|
||||
}
|
||||
|
||||
inline void SetXColumn(const Vector3<T> & a_X)
|
||||
{
|
||||
cell[0] = a_X.x;
|
||||
cell[1] = a_X.y;
|
||||
cell[2] = a_X.z;
|
||||
}
|
||||
|
||||
inline void SetYColumn(const Vector3<T> & a_Y)
|
||||
{
|
||||
cell[4] = a_Y.x;
|
||||
cell[5] = a_Y.y;
|
||||
cell[6] = a_Y.z;
|
||||
}
|
||||
|
||||
inline void SetZColumn(const Vector3<T> & a_Z)
|
||||
{
|
||||
cell[8] = a_Z.x;
|
||||
cell[9] = a_Z.y;
|
||||
cell[10] = a_Z.z;
|
||||
}
|
||||
};
|
||||
// tolua_end
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
typedef Matrix4<double> Matrix4d;
|
||||
typedef Matrix4<float> Matrix4f;
|
||||
// tolua_end
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
// _X: empty file??
|
225
src/Matrix4f.h
225
src/Matrix4f.h
@ -1,225 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include "Vector3f.h"
|
||||
|
||||
class Matrix4f
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
TX=3,
|
||||
TY=7,
|
||||
TZ=11,
|
||||
D0=0, D1=5, D2=10, D3=15,
|
||||
SX=D0, SY=D1, SZ=D2,
|
||||
W=D3
|
||||
};
|
||||
Matrix4f() { Identity(); }
|
||||
float& operator [] ( int a_N ) { return cell[a_N]; }
|
||||
void Identity()
|
||||
{
|
||||
cell[1] = cell[2] = cell[TX] = cell[4] = cell[6] = cell[TY] =
|
||||
cell[8] = cell[9] = cell[TZ] = cell[12] = cell[13] = cell[14] = 0;
|
||||
cell[D0] = cell[D1] = cell[D2] = cell[W] = 1;
|
||||
}
|
||||
void Init( Vector3f a_Pos, float a_RX, float a_RY, float a_RZ )
|
||||
{
|
||||
Matrix4f t;
|
||||
t.RotateX( a_RZ );
|
||||
RotateY( a_RY );
|
||||
Concatenate( t );
|
||||
t.RotateZ( a_RX );
|
||||
Concatenate( t );
|
||||
Translate( a_Pos );
|
||||
}
|
||||
void RotateX( float a_RX )
|
||||
{
|
||||
float sx = (float)sin( a_RX * M_PI / 180 );
|
||||
float cx = (float)cos( a_RX * M_PI / 180 );
|
||||
Identity();
|
||||
cell[5] = cx, cell[6] = sx, cell[9] = -sx, cell[10] = cx;
|
||||
}
|
||||
void RotateY( float a_RY )
|
||||
{
|
||||
float sy = (float)sin( a_RY * M_PI / 180 );
|
||||
float cy = (float)cos( a_RY * M_PI / 180 );
|
||||
Identity ();
|
||||
cell[0] = cy, cell[2] = -sy, cell[8] = sy, cell[10] = cy;
|
||||
}
|
||||
void RotateZ( float a_RZ )
|
||||
{
|
||||
float sz = (float)sin( a_RZ * M_PI / 180 );
|
||||
float cz = (float)cos( a_RZ * M_PI / 180 );
|
||||
Identity ();
|
||||
cell[0] = cz, cell[1] = sz, cell[4] = -sz, cell[5] = cz;
|
||||
}
|
||||
void Translate( Vector3f a_Pos ) { cell[TX] += a_Pos.x; cell[TY] += a_Pos.y; cell[TZ] += a_Pos.z; }
|
||||
void SetTranslation( Vector3f a_Pos ) { cell[TX] = a_Pos.x; cell[TY] = a_Pos.y; cell[TZ] = a_Pos.z; }
|
||||
void Concatenate( const Matrix4f& m2 )
|
||||
{
|
||||
Matrix4f res;
|
||||
int c;
|
||||
for ( c = 0; c < 4; c++ ) for ( int r = 0; r < 4; r++ )
|
||||
res.cell[r * 4 + c] = cell[r * 4] * m2.cell[c] +
|
||||
cell[r * 4 + 1] * m2.cell[c + 4] +
|
||||
cell[r * 4 + 2] * m2.cell[c + 8] +
|
||||
cell[r * 4 + 3] * m2.cell[c + 12];
|
||||
for ( c = 0; c < 16; c++ ) cell[c] = res.cell[c];
|
||||
}
|
||||
Vector3f Transform( const Vector3f& v ) const
|
||||
{
|
||||
float x = cell[0] * v.x + cell[1] * v.y + cell[2] * v.z + cell[3];
|
||||
float y = cell[4] * v.x + cell[5] * v.y + cell[6] * v.z + cell[7];
|
||||
float z = cell[8] * v.x + cell[9] * v.y + cell[10] * v.z + cell[11];
|
||||
return Vector3f( x, y, z );
|
||||
}
|
||||
void Invert()
|
||||
{
|
||||
Matrix4f t;
|
||||
int h, i;
|
||||
float tx = -cell[3], ty = -cell[7], tz = -cell[11];
|
||||
for ( h = 0; h < 3; h++ ) for ( int v = 0; v < 3; v++ ) t.cell[h + v * 4] = cell[v + h * 4];
|
||||
for ( i = 0; i < 11; i++ ) cell[i] = t.cell[i];
|
||||
cell[3] = tx * cell[0] + ty * cell[1] + tz * cell[2];
|
||||
cell[7] = tx * cell[4] + ty * cell[5] + tz * cell[6];
|
||||
cell[11] = tx * cell[8] + ty * cell[9] + tz * cell[10];
|
||||
}
|
||||
Vector3f GetXColumn() { return Vector3f( cell[0], cell[1], cell[2] ); }
|
||||
Vector3f GetYColumn() { return Vector3f( cell[4], cell[5], cell[6] ); }
|
||||
Vector3f GetZColumn() { return Vector3f( cell[8], cell[9], cell[10] ); }
|
||||
void SetXColumn( const Vector3f & a_X )
|
||||
{
|
||||
cell[0] = a_X.x;
|
||||
cell[1] = a_X.y;
|
||||
cell[2] = a_X.z;
|
||||
}
|
||||
void SetYColumn( const Vector3f & a_Y )
|
||||
{
|
||||
cell[4] = a_Y.x;
|
||||
cell[5] = a_Y.y;
|
||||
cell[6] = a_Y.z;
|
||||
}
|
||||
void SetZColumn( const Vector3f & a_Z )
|
||||
{
|
||||
cell[8] = a_Z.x;
|
||||
cell[9] = a_Z.y;
|
||||
cell[10] = a_Z.z;
|
||||
}
|
||||
float cell[16];
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Matrix4d
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
TX=3,
|
||||
TY=7,
|
||||
TZ=11,
|
||||
D0=0, D1=5, D2=10, D3=15,
|
||||
SX=D0, SY=D1, SZ=D2,
|
||||
W=D3
|
||||
};
|
||||
Matrix4d() { Identity(); }
|
||||
double& operator [] ( int a_N ) { return cell[a_N]; }
|
||||
void Identity()
|
||||
{
|
||||
cell[1] = cell[2] = cell[TX] = cell[4] = cell[6] = cell[TY] =
|
||||
cell[8] = cell[9] = cell[TZ] = cell[12] = cell[13] = cell[14] = 0;
|
||||
cell[D0] = cell[D1] = cell[D2] = cell[W] = 1;
|
||||
}
|
||||
void Init( Vector3f a_Pos, double a_RX, double a_RY, double a_RZ )
|
||||
{
|
||||
Matrix4d t;
|
||||
t.RotateX( a_RZ );
|
||||
RotateY( a_RY );
|
||||
Concatenate( t );
|
||||
t.RotateZ( a_RX );
|
||||
Concatenate( t );
|
||||
Translate( a_Pos );
|
||||
}
|
||||
void RotateX( double a_RX )
|
||||
{
|
||||
double sx = (double)sin( a_RX * M_PI / 180 );
|
||||
double cx = (double)cos( a_RX * M_PI / 180 );
|
||||
Identity();
|
||||
cell[5] = cx, cell[6] = sx, cell[9] = -sx, cell[10] = cx;
|
||||
}
|
||||
void RotateY( double a_RY )
|
||||
{
|
||||
double sy = (double)sin( a_RY * M_PI / 180 );
|
||||
double cy = (double)cos( a_RY * M_PI / 180 );
|
||||
Identity ();
|
||||
cell[0] = cy, cell[2] = -sy, cell[8] = sy, cell[10] = cy;
|
||||
}
|
||||
void RotateZ( double a_RZ )
|
||||
{
|
||||
double sz = (double)sin( a_RZ * M_PI / 180 );
|
||||
double cz = (double)cos( a_RZ * M_PI / 180 );
|
||||
Identity ();
|
||||
cell[0] = cz, cell[1] = sz, cell[4] = -sz, cell[5] = cz;
|
||||
}
|
||||
void Translate( Vector3d a_Pos ) { cell[TX] += a_Pos.x; cell[TY] += a_Pos.y; cell[TZ] += a_Pos.z; }
|
||||
void SetTranslation( Vector3d a_Pos ) { cell[TX] = a_Pos.x; cell[TY] = a_Pos.y; cell[TZ] = a_Pos.z; }
|
||||
void Concatenate( const Matrix4d & m2 )
|
||||
{
|
||||
Matrix4d res;
|
||||
int c;
|
||||
for ( c = 0; c < 4; c++ ) for ( int r = 0; r < 4; r++ )
|
||||
res.cell[r * 4 + c] = cell[r * 4] * m2.cell[c] +
|
||||
cell[r * 4 + 1] * m2.cell[c + 4] +
|
||||
cell[r * 4 + 2] * m2.cell[c + 8] +
|
||||
cell[r * 4 + 3] * m2.cell[c + 12];
|
||||
for ( c = 0; c < 16; c++ ) cell[c] = res.cell[c];
|
||||
}
|
||||
Vector3d Transform( const Vector3d & v ) const
|
||||
{
|
||||
double x = cell[0] * v.x + cell[1] * v.y + cell[2] * v.z + cell[3];
|
||||
double y = cell[4] * v.x + cell[5] * v.y + cell[6] * v.z + cell[7];
|
||||
double z = cell[8] * v.x + cell[9] * v.y + cell[10] * v.z + cell[11];
|
||||
return Vector3d( x, y, z );
|
||||
}
|
||||
void Invert()
|
||||
{
|
||||
Matrix4d t;
|
||||
int h, i;
|
||||
double tx = -cell[3], ty = -cell[7], tz = -cell[11];
|
||||
for ( h = 0; h < 3; h++ ) for ( int v = 0; v < 3; v++ ) t.cell[h + v * 4] = cell[v + h * 4];
|
||||
for ( i = 0; i < 11; i++ ) cell[i] = t.cell[i];
|
||||
cell[3] = tx * cell[0] + ty * cell[1] + tz * cell[2];
|
||||
cell[7] = tx * cell[4] + ty * cell[5] + tz * cell[6];
|
||||
cell[11] = tx * cell[8] + ty * cell[9] + tz * cell[10];
|
||||
}
|
||||
Vector3d GetXColumn() { return Vector3d( cell[0], cell[1], cell[2] ); }
|
||||
Vector3d GetYColumn() { return Vector3d( cell[4], cell[5], cell[6] ); }
|
||||
Vector3d GetZColumn() { return Vector3d( cell[8], cell[9], cell[10] ); }
|
||||
void SetXColumn( const Vector3d & a_X )
|
||||
{
|
||||
cell[0] = a_X.x;
|
||||
cell[1] = a_X.y;
|
||||
cell[2] = a_X.z;
|
||||
}
|
||||
void SetYColumn( const Vector3d & a_Y )
|
||||
{
|
||||
cell[4] = a_Y.x;
|
||||
cell[5] = a_Y.y;
|
||||
cell[6] = a_Y.z;
|
||||
}
|
||||
void SetZColumn( const Vector3d & a_Z )
|
||||
{
|
||||
cell[8] = a_Z.x;
|
||||
cell[9] = a_Z.y;
|
||||
cell[10] = a_Z.z;
|
||||
}
|
||||
double cell[16];
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
@ -62,7 +62,7 @@
|
||||
class MTRand {
|
||||
// Data
|
||||
public:
|
||||
typedef long uint32; // unsigned integer type, at least 32 bits
|
||||
typedef UInt32 uint32; // unsigned integer type, at least 32 bits
|
||||
|
||||
enum { N = 624 }; // length of state vector
|
||||
enum { SAVE = N + 1 }; // length of array for save()
|
||||
@ -72,7 +72,7 @@ protected:
|
||||
|
||||
uint32 state[N]; // internal state
|
||||
uint32 *pNext; // next value to get from state
|
||||
int left; // number of values left before reload needed
|
||||
uint32 left; // number of values left before reload needed
|
||||
|
||||
// Methods
|
||||
public:
|
||||
@ -164,7 +164,7 @@ inline void MTRand::initialize( const uint32 seed )
|
||||
// only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto.
|
||||
uint32 *s = state;
|
||||
uint32 *r = state;
|
||||
int i = 1;
|
||||
uint32 i = 1;
|
||||
*s++ = seed & 0xffffffffUL;
|
||||
for( ; i < N; ++i )
|
||||
{
|
||||
@ -205,9 +205,9 @@ inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength )
|
||||
// in each element are discarded.
|
||||
// Just call seed() if you want to get array from /dev/urandom
|
||||
initialize(19650218UL);
|
||||
int i = 1;
|
||||
uint32 i = 1;
|
||||
uint32 j = 0;
|
||||
int k = ( (uint32)N > seedLength ? (uint32)N : seedLength );
|
||||
uint32 k = ( (uint32)N > seedLength ? (uint32)N : seedLength );
|
||||
for( ; k; --k )
|
||||
{
|
||||
state[i] =
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "Bat.h"
|
||||
#include "../Vector3d.h"
|
||||
#include "../Vector3.h"
|
||||
#include "../Chunk.h"
|
||||
|
||||
|
||||
|
@ -68,17 +68,28 @@ void cSheep::OnRightClicked(cPlayer & a_Player)
|
||||
|
||||
void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
// The sheep should not move when he's eating so only handle the physics.
|
||||
super::Tick(a_Dt, a_Chunk);
|
||||
int PosX = POSX_TOINT;
|
||||
int PosY = POSY_TOINT - 1;
|
||||
int PosZ = POSZ_TOINT;
|
||||
|
||||
if ((PosY <= 0) || (PosY > cChunkDef::Height))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_TimeToStopEating > 0)
|
||||
{
|
||||
HandlePhysics(a_Dt, a_Chunk);
|
||||
m_bMovingToDestination = false; // The sheep should not move when he's eating
|
||||
m_TimeToStopEating--;
|
||||
|
||||
if (m_TimeToStopEating == 0)
|
||||
{
|
||||
if (m_World->GetBlock((int) GetPosX(), (int) GetPosY() - 1, (int) GetPosZ()) == E_BLOCK_GRASS)
|
||||
if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS) // Make sure grass hasn't been destroyed in the meantime
|
||||
{
|
||||
// The sheep ate the grass so we change it to dirt.
|
||||
m_World->SetBlock((int) GetPosX(), (int) GetPosY() - 1, (int) GetPosZ(), E_BLOCK_DIRT, 0);
|
||||
// The sheep ate the grass so we change it to dirt
|
||||
m_World->SetBlock(PosX, PosY, PosZ, E_BLOCK_DIRT, 0);
|
||||
GetWorld()->BroadcastSoundParticleEffect(2001, PosX, PosY, PosX, E_BLOCK_GRASS);
|
||||
m_IsSheared = false;
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
}
|
||||
@ -86,12 +97,11 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
}
|
||||
else
|
||||
{
|
||||
super::Tick(a_Dt, a_Chunk);
|
||||
if (m_World->GetTickRandomNumber(600) == 1)
|
||||
{
|
||||
if (m_World->GetBlock((int) GetPosX(), (int) GetPosY() - 1, (int) GetPosZ()) == E_BLOCK_GRASS)
|
||||
if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS)
|
||||
{
|
||||
m_World->BroadcastEntityStatus(*this, 10);
|
||||
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_SHEEP_EATING);
|
||||
m_TimeToStopEating = 40;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "Squid.h"
|
||||
#include "../Vector3d.h"
|
||||
#include "../Vector3.h"
|
||||
#include "../Chunk.h"
|
||||
|
||||
|
||||
|
@ -3,14 +3,6 @@
|
||||
|
||||
#include "Noise.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if NOISE_USE_SSE
|
||||
#include <smmintrin.h> //_mm_mul_epi32
|
||||
#endif
|
||||
|
||||
#define FAST_FLOOR(x) (((x) < 0) ? (((int)x) - 1) : ((int)x))
|
||||
|
||||
|
||||
|
@ -70,7 +70,7 @@ bool cBlockingTCPLink::Connect(const char * iAddress, unsigned int iPort)
|
||||
}
|
||||
}
|
||||
|
||||
server.sin_addr.s_addr = *((unsigned long *)hp->h_addr);
|
||||
memcpy(&server.sin_addr.s_addr,hp->h_addr, hp->h_length);
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_port = htons( (unsigned short)iPort);
|
||||
if (connect(m_Socket, (struct sockaddr *)&server, sizeof(server)))
|
||||
|
@ -131,7 +131,7 @@ public:
|
||||
/** Returns the list of all items in the specified folder (files, folders, nix pipes, whatever's there). */
|
||||
static AStringVector GetFolderContents(const AString & a_Folder); // Exported in ManualBindings.cpp
|
||||
|
||||
int Printf(const char * a_Fmt, ...);
|
||||
int Printf(const char * a_Fmt, ...) FORMATSTRING(2, 3);
|
||||
|
||||
/** Flushes all the bufferef output into the file (only when writing) */
|
||||
void Flush(void);
|
||||
|
@ -34,7 +34,7 @@ protected:
|
||||
|
||||
public:
|
||||
cIsThread(const AString & iThreadName);
|
||||
~cIsThread();
|
||||
virtual ~cIsThread();
|
||||
|
||||
/// Starts the thread; returns without waiting for the actual start
|
||||
bool Start(void);
|
||||
|
@ -307,7 +307,8 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por
|
||||
CloseSocket();
|
||||
return false;
|
||||
}
|
||||
addr = *((unsigned long*)hp->h_addr);
|
||||
// Should be optimised to a single word copy
|
||||
memcpy(&addr, hp->h_addr, hp->h_length);
|
||||
}
|
||||
|
||||
sockaddr_in server;
|
||||
|
@ -54,7 +54,7 @@ bool cSocketThreads::AddClient(const cSocket & a_Socket, cCallback * a_Client)
|
||||
}
|
||||
|
||||
// No thread has free space, create a new one:
|
||||
LOGD("Creating a new cSocketThread (currently have %d)", m_Threads.size());
|
||||
LOGD("Creating a new cSocketThread (currently have " SIZE_T_FMT ")", m_Threads.size());
|
||||
cSocketThread * Thread = new cSocketThread(this);
|
||||
if (!Thread->Start())
|
||||
{
|
||||
|
@ -103,7 +103,7 @@ private:
|
||||
public:
|
||||
|
||||
cSocketThread(cSocketThreads * a_Parent);
|
||||
~cSocketThread();
|
||||
virtual ~cSocketThread();
|
||||
|
||||
// All these methods assume parent's m_CS is locked
|
||||
bool HasEmptySlot(void) const {return m_NumSlots < MAX_SLOTS; }
|
||||
|
@ -52,7 +52,7 @@ public:
|
||||
virtual ~cProtocol() {}
|
||||
|
||||
/// Called when client sends some data
|
||||
virtual void DataReceived(const char * a_Data, int a_Size) = 0;
|
||||
virtual void DataReceived(const char * a_Data, size_t a_Size) = 0;
|
||||
|
||||
// Sending stuff to clients (alphabetically sorted):
|
||||
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) = 0;
|
||||
|
@ -1186,7 +1186,7 @@ void cProtocol125::SendData(const char * a_Data, int a_Size)
|
||||
|
||||
|
||||
|
||||
void cProtocol125::DataReceived(const char * a_Data, int a_Size)
|
||||
void cProtocol125::DataReceived(const char * a_Data, size_t a_Size)
|
||||
{
|
||||
if (!m_ReceivedData.Write(a_Data, a_Size))
|
||||
{
|
||||
@ -1269,19 +1269,6 @@ int cProtocol125::ParsePacket(unsigned char a_PacketType)
|
||||
|
||||
|
||||
|
||||
#define HANDLE_PACKET_PARSE(Packet) \
|
||||
{ \
|
||||
int res = Packet.Parse(m_ReceivedData); \
|
||||
if (res < 0) \
|
||||
{ \
|
||||
return res; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cProtocol125::ParseArmAnim(void)
|
||||
{
|
||||
HANDLE_PACKET_READ(ReadBEInt, int, EntityID);
|
||||
@ -1375,7 +1362,16 @@ int cProtocol125::ParseEntityAction(void)
|
||||
{
|
||||
HANDLE_PACKET_READ(ReadBEInt, int, EntityID);
|
||||
HANDLE_PACKET_READ(ReadChar, char, ActionID);
|
||||
m_Client->HandleEntityAction(EntityID, ActionID);
|
||||
|
||||
switch (ActionID)
|
||||
{
|
||||
case 1: m_Client->HandleEntityCrouch(EntityID, true); break; // Crouch
|
||||
case 2: m_Client->HandleEntityCrouch(EntityID, false); break; // Uncrouch
|
||||
case 3: m_Client->HandleEntityLeaveBed(EntityID); break; // Leave Bed
|
||||
case 4: m_Client->HandleEntitySprinting(EntityID, true); break; // Start sprinting
|
||||
case 5: m_Client->HandleEntitySprinting(EntityID, false); break; // Stop sprinting
|
||||
}
|
||||
|
||||
return PARSE_OK;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user