1
0

Merge branch 'master' into issue850

Conflicts:
	src/BlockID.h
This commit is contained in:
Alexander Harkness 2014-10-11 18:32:21 +01:00
commit 93833069a8
472 changed files with 26998 additions and 18854 deletions

3
.gitignore vendored
View File

@ -56,6 +56,7 @@ Makefile
*.a
*.d
*.so
BuildInfo.h
CMakeCache.txt
CMakeFiles
Makefile
@ -64,7 +65,7 @@ install_mainfest.txt
src/MCServer
lib/tolua++/tolua
src/Bindings/Bindings.*
src/Bindings/BindingDependecies.txt
src/Bindings/BindingDependencies.txt
MCServer.dir/
src/AllFiles.lst

17
.gitmodules vendored
View File

@ -7,6 +7,21 @@
[submodule "MCServer/Plugins/TransAPI"]
path = MCServer/Plugins/TransAPI
url = https://github.com/bearbin/transapi.git
[submodule "MCServer/Plugins/ChunkWorx"]
path = MCServer/Plugins/ChunkWorx
url = https://github.com/mc-server/ChunkWorx.git
[submodule "MCServer/Plugins/ChatLog"]
path = MCServer/Plugins/ChatLog
url = https://github.com/mc-server/ChatLog.git
[submodule "MCServer/Plugins/Handy"]
path = MCServer/Plugins/Handy
url = https://github.com/mc-server/Handy.git
[submodule "MCServer/Plugins/MagicCarpet"]
path = MCServer/Plugins/MagicCarpet
url = https://github.com/mc-server/MagicCarpet.git
[submodule "lib/polarssl"]
path = lib/polarssl
url = https://github.com/mc-server/polarssl
url = https://github.com/mc-server/polarssl.git
[submodule "lib/SQLiteCpp"]
path = lib/SQLiteCpp
url = https://github.com/mc-server/SQLiteCpp.git

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, MCServerActivity!</string>
<string name="app_name">MCServer</string>
<string name="start">Start</string>
<string name="stop">Stop</string>
<string name="mcserver_is_running">MCServer jest włączony</string>
<string name="mcserver_is_not_running">MCServer jest wyłączony</string>
<string name="your_ip">Twoje IP …</string>
<string name="configure">Ustawienia</string>
</resources>

View File

@ -2,6 +2,10 @@
set -e
export MCSERVER_BUILD_SERIES_NAME="Travis $CC $TRAVIS_MCSERVER_BUILD_TYPE"
export MCSERVER_BUILD_ID=$TRAVIS_JOB_NUMBER
export MCSERVER_BUILD_DATETIME=`date`
cmake . -DBUILD_TOOLS=1 -DSELF_TEST=1;
make -j 2;
make -j 2 test;

View File

@ -1,4 +1,4 @@
cmake_minimum_required (VERSION 2.8.2)
cmake_minimum_required (VERSION 2.8.7)
# 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)
@ -18,6 +18,25 @@ if(DEFINED ENV{TRAVIS_BUILD_WITH_COVERAGE})
set(BUILD_WITH_COVERAGE $ENV{TRAVIS_BUILD_WITH_COVERAGE})
endif()
if(DEFINED ENV{MCSERVER_BUILD_ID})
set(BUILD_ID $ENV{MCSERVER_BUILD_ID})
set(BUILD_SERIES_NAME $ENV{MCSERVER_BUILD_SERIES_NAME})
set(BUILD_DATETIME $ENV{MCSERVER_BUILD_DATETIME})
if(DEFINED ENV{MCSERVER_BUILD_COMMIT_ID})
set(BUILD_COMMIT_ID $ENV{MCSERVER_BUILD_COMMIT_ID})
else()
message("Commit id not set, attempting to determine id from git")
execute_process(
COMMAND git rev-parse HEAD
RESULT_VARIABLE GIT_EXECUTED
OUTPUT_VARIABLE BUILD_COMMIT_ID)
string(STRIP ${BUILD_COMMIT_ID} BUILD_COMMIT_ID)
if (NOT (GIT_EXECUTED EQUAL 0))
message(FATAL_ERROR "Could not identifiy git commit id")
endif()
endif()
endif()
# This has to be done before any flags have been set up.
if(${BUILD_TOOLS})
add_subdirectory(Tools/MCADefrag/)
@ -53,6 +72,14 @@ endif()
project (MCServer)
# Set options for SQLiteCpp, disable all their tests and lints:
set(SQLITECPP_RUN_CPPLINT OFF CACHE BOOL "Run cpplint.py tool for Google C++ StyleGuide." FORCE)
set(SQLITECPP_RUN_CPPCHECK OFF CACHE BOOL "Run cppcheck C++ static analysis tool." FORCE)
set(SQLITECPP_RUN_DOXYGEN OFF CACHE BOOL "Run Doxygen C++ documentation tool." FORCE)
set(SQLITECPP_BUILD_EXAMPLES OFF CACHE BOOL "Build examples." FORCE)
set(SQLITECPP_BUILD_TESTS OFF CACHE BOOL "Build and run tests." FORCE)
set(SQLITECPP_INTERNAL_SQLITE OFF CACHE BOOL "Add the internal SQLite3 source to the project." FORCE)
# Include all the libraries:
add_subdirectory(lib/inifile/)
add_subdirectory(lib/jsoncpp/)
@ -60,9 +87,16 @@ add_subdirectory(lib/zlib/)
add_subdirectory(lib/lua/)
add_subdirectory(lib/tolua++/)
add_subdirectory(lib/sqlite/)
add_subdirectory(lib/SQLiteCpp/)
add_subdirectory(lib/expat/)
add_subdirectory(lib/luaexpat/)
# Add proper include directories so that SQLiteCpp can find SQLite3:
get_property(SQLITECPP_INCLUDES DIRECTORY "lib/SQLiteCpp/" PROPERTY INCLUDE_DIRECTORIES)
set(SQLITECPP_INCLUDES "${SQLITECPP_INCLUDES}" "${CMAKE_CURRENT_SOURCE_DIR}/lib/sqlite/")
set_property(DIRECTORY lib/SQLiteCpp/ PROPERTY INCLUDE_DIRECTORIES "${SQLITECPP_INCLUDES}")
set_property(TARGET SQLiteCpp PROPERTY INCLUDE_DIRECTORIES "${SQLITECPP_INCLUDES}")
if (WIN32)
add_subdirectory(lib/luaproxy/)
endif()

View File

@ -29,5 +29,7 @@ worktycho
xoft
Yeeeeezus (Donated AlchemistVillage prefabs)
Howaner
Masy98
WebFreak001
Please add yourself to this list if you contribute to MCServer.

View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2012-2014 Sebastien Rombauts (sebastien.rombauts@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -6,9 +6,7 @@
..\MCServer\furnace.txt
..\MCServer\items.ini
..\MCServer\monsters.ini
..\MCServer\buildinfo.txt
MCServer*debug.cmd
*.example.ini
Lua-LICENSE.txt
LuaExpat-license.html
LuaSQLite3-LICENSE.txt
MersenneTwister-LICENSE.txt
ThirdPartyLicenses

View File

@ -1,2 +1,3 @@
MCServer\*.pdb
MCServer\buildinfo.txt
src\Bindings\Bindings.*

View File

@ -523,22 +523,29 @@ end
Functions =
{
GenerateOfflineUUID = { Params = "Username", Return = "string", Notes = "(STATIC) Generates an UUID based on the player name provided. This is used for the offline (non-auth) mode, when there's no UUID source. Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. Returns a 36-char UUID (with dashes)." },
GenerateOfflineUUID = { Params = "Username", Return = "string", Notes = "(STATIC) Generates an UUID based on the player name provided. This is used for the offline (non-auth) mode, when there's no UUID source. Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. Returns a 32-char UUID (no dashes)." },
GetClientBrand = { Params = "", Return = "string", Notes = "Returns the brand that the client has sent in their MC|Brand plugin message." },
GetIPString = { Params = "", Return = "string", Notes = "Returns the IP address of the connection, as a string. Only the address part is returned, without the port number." },
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." },
GetProtocolVersion = { Params = "", Return = "number", Notes = "Returns the protocol version number of the protocol that the client is talking. Returns zero if the protocol version is not (yet) known." },
GetUniqueID = { Params = "", Return = "number", Notes = "Returns the UniqueID of the client used to identify the client in the server" },
GetUUID = { Params = "", Return = "string", Notes = "Returns the authentication-based UUID of the client. This UUID should be used to identify the player when persisting any player-related data." },
GetUUID = { Params = "", Return = "string", Notes = "Returns the authentication-based UUID of the client. This UUID should be used to identify the player when persisting any player-related data. Returns a 32-char UUID (no dashes)" },
GetUsername = { Params = "", Return = "string", Notes = "Returns the username that the client has provided" },
GetViewDistance = { Params = "", Return = "number", Notes = "Returns the viewdistance (number of chunks loaded for the player in each direction)" },
HasPluginChannel = { Params = "ChannelName", Return = "bool", Notes = "Returns true if the client has registered to receive messages on the specified plugin channel." },
IsUUIDOnline = { Params = "UUID", Return = "bool", Notes = "(STATIC) Returns true if the UUID is generated by online auth, false if it is an offline-generated UUID. We use Version-3 UUIDs for offline UUIDs, online UUIDs are Version-4, thus we can tell them apart. Accepts both 32-char and 36-char UUIDs (with and without dashes). If the string given is not a valid UUID, returns false."},
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." },
SetClientBrand = { Params = "ClientBrand", Return = "", Notes = "Sets the value of the client's brand. Normally this value is received from the client by a MC|Brand plugin message, this function lets plugins overwrite the value." },
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." },
SendEntityAnimation = { Params = "{{cEntity|Entity}}, AnimationNumber", Return = "", Notes = "Sends the specified animation of the specified entity to the client. The AnimationNumber is protocol-specific." },
SendSoundEffect = { Params = "SoundName, X, Y, Z, Volume, Pitch", Return = "", Notes = "Sends a sound effect request to the client. The sound is played at the specified coords, with the specified volume (a float, 1.0 is full volume, can be more) and pitch (0-255, 63 is 100%)" },
SendTimeUpdate = { Params = "WorldAge, TimeOfDay, DoDaylightCycle", Return = "", Notes = "Sends the specified time update to the client. WorldAge is the total age of the world, in ticks. TimeOfDay is the current day's time, in ticks (0 - 24000). DoDaylightCycle is a bool that specifies whether the client should automatically move the sun (true) or keep it in the same place (false)." },
},
Constants =
{
@ -554,9 +561,9 @@ end
and commands suggested on click. The chat message can be sent by the regular chat-sending functions,
{{cPlayer}}:SendMessage(), {{cWorld}}:BroadcastChat() and {{cRoot}}:BroadcastChat().</p>
<p>
Note that most of the functions in this class are so-called modifiers - they modify the object and
then return the object itself, so that they can be chained one after another. See the Chaining
example below for details.</p>
Note that most of the functions in this class are so-called chaining modifiers - they modify the
object and then return the object itself, so that they can be chained one after another. See the
Chaining example below for details.</p>
<p>
Each part of the composite chat message takes a "Style" parameter, this is a string that describes
the formatting. It uses the following strings, concatenated together:
@ -580,14 +587,17 @@ end
{ Params = "Text", Return = "", Notes = "Creates a chat message containing the specified text, parsed by the ParseText() function. This allows easy migration from old chat messages." },
},
AddRunCommandPart = { Params = "Text, Command, [Style]", Return = "self", Notes = "Adds a text which, when clicked, runs the specified command. Chaining." },
AddShowAchievementPart = { Params = "PlayerName, AchievementName, [Style]", Return = "", Notes = "Adds a text that represents the 'Achievement get' message." },
AddSuggestCommandPart = { Params = "Text, Command, [Style]", Return = "self", Notes = "Adds a text which, when clicked, puts the specified command into the player's chat input area. Chaining." },
AddTextPart = { Params = "Text, [Style]", Return = "self", Notes = "Adds a regular text. Chaining." },
AddUrlPart = { Params = "Text, Url, [Style]", Return = "self", Notes = "Adds a text which, when clicked, opens up a browser at the specified URL. Chaining." },
Clear = { Params = "", Return = "", Notes = "Removes all parts from this object" },
CreateJsonString = { Params = "[AddPrefixes]", Return = "string", Notes = "Returns the entire object serialized into JSON, as it would be sent to a client. AddPrefixes specifies whether the chat prefixes should be prepended to the message, true by default." },
ExtractText = { Params = "", Return = "string", Notes = "Returns the text from the parts that comprises the human-readable data. Used for older protocols that don't support composite chat and for console-logging." },
GetAdditionalMessageTypeData = { Params = "", Return = "string", Notes = "Returns the AdditionalData associated with the message, such as the sender's name for mtPrivateMessage" },
GetMessageType = { Params = "", Return = "MessageType", Notes = "Returns the MessageType (mtXXX constant) that is associated with this message. When sent to a player, the message will be formatted according to this message type and the player's settings (adding \"[INFO]\" prefix etc.)" },
ParseText = { Params = "Text", Return = "self", Notes = "Adds text, while recognizing http and https URLs and old-style formatting codes (\"@2\"). Chaining." },
SetMessageType = { Params = "MessageType", Return = "self", Notes = "Sets the MessageType (mtXXX constant) that is associated with this message. When sent to a player, the message will be formatted according to this message type and the player's settings (adding \"[INFO]\" prefix etc.) Chaining." },
SetMessageType = { Params = "MessageType, AdditionalData", Return = "self", Notes = "Sets the MessageType (mtXXX constant) that is associated with this message. Also sets the additional data (string) associated with the message, which is specific for the message type - such as the sender's name for mtPrivateMessage. When sent to a player, the message will be formatted according to this message type and the player's settings (adding \"[INFO]\" prefix etc.). Chaining." },
UnderlineUrls = { Params = "", Return = "self", Notes = "Makes all URL parts contained in the message underlined. Doesn't affect parts added in the future. Chaining." },
},
@ -776,7 +786,9 @@ end</pre>
AddSpeedX = { Params = "AddX", Return = "", Notes = "Adds the specified amount of speed in the X axis direction." },
AddSpeedY = { Params = "AddY", Return = "", Notes = "Adds the specified amount of speed in the Y axis direction." },
AddSpeedZ = { Params = "AddZ", Return = "", Notes = "Adds the specified amount of speed in the Z axis direction." },
ArmorCoversAgainst = { Params = "{{cEntity|AttackerEntity}}, DamageType, RawDamage", Return = "number", Notes = "Returns the points out of a_RawDamage that the currently equipped armor would cover." },
Destroy = { Params = "", Return = "", Notes = "Schedules the entity to be destroyed" },
GetAirLevel = { Params = "", Return = "number", Notes = "Returns the air level (number of ticks of air left). Note, this function is only updated with mobs or players." },
GetArmorCoverAgainst = { Params = "AttackerEntity, DamageType, RawDamage", Return = "number", Notes = "Returns the number of hitpoints out of RawDamage that the currently equipped armor would cover. See {{TakeDamageInfo}} for more information on attack damage." },
GetChunkX = { Params = "", Return = "number", Notes = "Returns the X-coord of the chunk in which the entity is placed" },
GetChunkZ = { Params = "", Return = "number", Notes = "Returns the Z-coord of the chunk in which the entity is placed" },
@ -792,6 +804,7 @@ end</pre>
GetHeadYaw = { Params = "", Return = "number", Notes = "Returns the pitch of the entity's head (FIXME: Rename to GetHeadPitch() )." },
GetHealth = { Params = "", Return = "number", Notes = "Returns the current health of the entity." },
GetHeight = { Params = "", Return = "number", Notes = "Returns the height (Y size) of the entity" },
GetInvulnerableTicks = { Params = "", Return = "number", Notes = "Returns the number of ticks that this entity will be invulnerable for. This is used for after-hit recovery - the entities are invulnerable for half a second after being hit." },
GetKnockbackAmountAgainst = { Params = "ReceiverEntity", Return = "number", Notes = "Returns the amount of knockback that the currently equipped items would cause when attacking the ReceiverEntity." },
GetLookVector = { Params = "", Return = "{{Vector3f}}", Notes = "Returns the vector that defines the direction in which the entity is looking" },
GetMass = { Params = "", Return = "number", Notes = "Returns the mass of the entity. Currently unused." },
@ -809,23 +822,29 @@ end</pre>
GetSpeedX = { Params = "", Return = "number", Notes = "Returns the X-part of the speed vector" },
GetSpeedY = { Params = "", Return = "number", Notes = "Returns the Y-part of the speed vector" },
GetSpeedZ = { Params = "", Return = "number", Notes = "Returns the Z-part of the speed vector" },
GetTicksAlive = { Params = "", Return = "number", Notes = "Returns the number of ticks that this entity has been alive for." },
GetUniqueID = { Params = "", Return = "number", Notes = "Returns the ID that uniquely identifies the entity within the running server. Note that this ID is not persisted to the data files." },
GetWidth = { Params = "", Return = "number", Notes = "Returns the width (X and Z size) of the entity." },
GetWorld = { Params = "", Return = "{{cWorld}}", Notes = "Returns the world where the entity resides" },
GetYaw = { Params = "", Return = "number", Notes = "Returns the yaw (direction) of the entity. Measured in degrees, values range from -180 to +180. 0 means ZP, 90 means XM, -180 means ZM, -90 means XP." },
HandleSpeedFromAttachee = { Params = "ForwardAmount, SidewaysAmount", Return = "", Notes = "Updates the entity's speed based on the attachee exerting the specified force forward and sideways. Used for entities being driven by other entities attached to them - usually players driving minecarts and boats." },
Heal = { Params = "Hitpoints", Return = "", Notes = "Heals the specified number of hitpoints. Hitpoints is expected to be a positive number." },
IsA = { Params = "ClassName", Return = "bool", Notes = "Returns true if the entity class is a descendant of the specified class name, or the specified class itself" },
IsBoat = { Params = "", Return = "bool", Notes = "Returns true if the entity is a {{cBoat|boat}}." },
IsCrouched = { Params = "", Return = "bool", Notes = "Returns true if the entity is crouched. Always false for entities that don't support crouching." },
IsDestroyed = { Params = "", Return = "bool", Notes = "Returns true if the entity has been destroyed and is awaiting removal from the internal structures." },
IsEnderCrystal = { Params = "", Return = "bool", Notes = "Returns true if the entity is an ender crystal." },
IsExpOrb = { Params = "", Return = "bool", Notes = "Returns true if the entity represents an experience orb" },
IsFallingBlock = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cFallingBlock}} entity." },
IsFireproof = { Params = "", Return = "bool", Notes = "Returns true if the entity takes no damage from being on fire." },
IsFloater = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a fishing rod floater" },
IsInvisible = { Params = "", Return = "bool", Notes = "Returns true if the entity is invisible" },
IsItemFrame = { Params = "", Return = "bool", Notes = "Returns true if the entity is an item frame." },
IsMinecart = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cMinecart|minecart}}" },
IsMob = { Params = "", Return = "bool", Notes = "Returns true if the entity represents any {{cMonster|mob}}." },
IsOnFire = { Params = "", Return = "bool", Notes = "Returns true if the entity is on fire" },
IsPainting = { Params = "", Return = "bool", Notes = "Returns if this entity is a painting." },
IsPawn = { Params = "", Return = "bool", Notes = "Returns true if the entity is a {{cPawn}} descendant." },
IsPickup = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cPickup|pickup}}." },
IsPlayer = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cPlayer|player}}" },
IsProjectile = { Params = "", Return = "bool", Notes = "Returns true if the entity is a {{cProjectileEntity}} descendant." },
@ -835,12 +854,19 @@ end</pre>
IsSubmerged = { Params = "", Return = "bool", Notes = "Returns true if the mob or player is submerged in water (head is in a water block). Note, this function is only updated with mobs or players." },
IsSwimming = { Params = "", Return = "bool", Notes = "Returns true if the mob or player is swimming in water (feet are in a water block). Note, this function is only updated with mobs or players." },
IsTNT = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cTNTEntity|TNT entity}}" },
Killed = { Params = "{{cEntity|Victim}}", Return = "", Notes = "This entity has killed another entity (the Victim). For players, adds the scoreboard statistics about the kill." },
KilledBy = { Notes = "FIXME: Remove this from API" },
GetAirLevel = { Params = "", Return = "number", Notes = "Returns the air level (number of ticks of air left). Note, this function is only updated with mobs or players." },
MoveToWorld =
{
{ Params = "{{cWorld|World}}, [ShouldSendRespawn]", Return = "bool", Notes = "Removes the entity from this world and starts moving it to the specified world. Note that to avoid deadlocks, the move is asynchronous - the entity is moved into a queue and will be moved from that queue into the destination world at some (unpredictable) time in the future. ShouldSendRespawn is used only for players, it specifies whether the player should be sent a Repawn packet upon leaving the world (The client handles respawns only between different dimensions)." },
{ Params = "WorldName, [ShouldSendRespawn]", Return = "bool", Notes = "Removes the entity from this world and starts moving it to the specified world. Note that to avoid deadlocks, the move is asynchronous - the entity is moved into a queue and will be moved from that queue into the destination world at some (unpredictable) time in the future. ShouldSendRespawn is used only for players, it specifies whether the player should be sent a Repawn packet upon leaving the world (The client handles respawns only between different dimensions)." },
},
SetGravity = { Params = "Gravity", Return = "", Notes = "Sets the number that is used as the gravity for physics simulation. 1G (9.78) by default." },
SetHeadYaw = { Params = "HeadPitch", Return = "", Notes = "Sets the head pitch (FIXME: Rename to SetHeadPitch() )." },
SetHealth = { Params = "Hitpoints", Return = "", Notes = "Sets the entity's health to the specified amount of hitpoints. Doesn't broadcast any hurt animation. Doesn't kill the entity if health drops below zero. Use the TakeDamage() function instead for taking damage." },
SetHeight = { Params = "", Return = "", Notes = "FIXME: Remove this from API" },
SetInvulnerableTicks = { Params = "NumTicks", Return = "", Notes = "Sets the amount of ticks for which the entity will not receive any damage from other entities." },
SetIsFireproof = { Params = "IsFireproof", Return = "", Notes = "Sets whether the entity receives damage from being on fire." },
SetMass = { Params = "Mass", Return = "", Notes = "Sets the mass of the entity. Currently unused." },
SetMaxHealth = { Params = "MaxHitpoints", Return = "", Notes = "Sets the maximum hitpoints of the entity. If current health is above MaxHitpoints, it is capped to MaxHitpoints." },
SetPitch = { Params = "number", Return = "", Notes = "Sets the pitch (nose-down rotation) of the entity" },
@ -855,7 +881,7 @@ end</pre>
SetPosZ = { Params = "number", Return = "", Notes = "Sets the Z-coord of the entity's pivot" },
SetRoll = { Params = "number", Return = "", Notes = "Sets the roll (sideways rotation) of the entity. Currently unused." },
SetRot = { Params = "{{Vector3f|Rotation}}", Return = "", Notes = "Sets the entire rotation vector (Yaw, Pitch, Roll)" },
SetYawFromSpeed = { Params = "", Return = "", Notes = "Sets the entity's yaw to match its current speed (entity looking forwards as it moves). (FIXME: Rename to SetYawFromSpeed)" },
SetYawFromSpeed = { Params = "", Return = "", Notes = "Sets the entity's yaw to match its current speed (entity looking forwards as it moves)." },
SetSpeed =
{
{ Params = "SpeedX, SpeedY, SpeedZ", Return = "", Notes = "Sets the current speed of the entity" },
@ -881,18 +907,20 @@ end</pre>
Constants =
{
etBoat = { Notes = "The entity is a {{cBoat}}" },
etEnderCrystal = { Notes = "" },
etEntity = { Notes = "No further specialization available" },
etExpOrb = { Notes = "The entity is a {{cExpOrb}}" },
etFallingBlock = { Notes = "The entity is a {{cFallingBlock}}" },
etFloater = { Notes = "The entity is a fishing rod floater" },
etItemFrame = { Notes = "" },
etMinecart = { Notes = "The entity is a {{cMinecart}} descendant" },
etMob = { Notes = "The entity is a {{cMonster}} descendant" },
etMonster = { Notes = "The entity is a {{cMonster}} descendant" },
etMinecart = { Notes = "The entity is a {{cMinecart}} descendant" },
etPlayer = { Notes = "The entity is a {{cPlayer}}" },
etPainting = { Notes = "The entity is a {{cPainting}}" },
etPickup = { Notes = "The entity is a {{cPickup}}" },
etPlayer = { Notes = "The entity is a {{cPlayer}}" },
etProjectile = { Notes = "The entity is a {{cProjectileEntity}} descendant" },
etTNT = { Notes = "The entity is a {{cTNTEntity}}" },
etPainting = { Notes = "The entity is a {{cPainting}}" },
},
ConstantGroups =
{
@ -942,24 +970,6 @@ cFile:Delete("/usr/bin/virus.exe");
Inherits = "cEntity",
},
cGroup =
{
Desc = [[
This class represents a group {{cPlayer|players}} can be in. Groups define the permissions players
have, and optionally the color of their name in the chat.
]],
Functions =
{
SetName = { Return = "" },
GetName = { Return = "string" },
SetColor = { Return = "" },
GetColor = { Return = "string" },
AddCommand = { Return = "" },
AddPermission = { Return = "" },
InheritFrom = { Return = "" },
},
}, -- cGroup
cIniFile =
{
Desc = [[
@ -1060,6 +1070,7 @@ ValueName0=SomeOtherValue
GetValueSetB = { Params = "KeyName, ValueName, Default", Return = "bool", Notes = "Returns the value of the specified name under the specified key, as a bool. If the value doesn't exist, creates it with the specified default." },
GetValueSetF = { Params = "KeyName, ValueName, Default", Return = "number", Notes = "Returns the value of the specified name under the specified key, as a floating-point number. If the value doesn't exist, creates it with the specified default." },
GetValueSetI = { Params = "KeyName, ValueName, Default", Return = "number", Notes = "Returns the value of the specified name under the specified key, as an integer. If the value doesn't exist, creates it with the specified default." },
HasValue = { Params = "KeyName, ValueName", Return = "bool", Notes = "Returns true if the specified value is present." },
ReadFile = { Params = "FileName, [AllowExampleFallback]", Return = "bool", Notes = "Reads the values from the specified file. Previous in-memory contents are lost. If the file cannot be opened, and AllowExample is true, another file, \"filename.example.ini\", is loaded and then saved as \"filename.ini\". Returns true if successful, false if not." },
SetValue =
{
@ -1206,7 +1217,7 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
constructor =
{
{ Params = "", Return = "cItem", Notes = "Creates a new empty cItem object" },
{ Params = "ItemType, Count, Damage, EnchantmentString", Return = "cItem", Notes = "Creates a new cItem object of the specified type, count (1 by default), damage (0 by default) and enchantments (non-enchanted by default)" },
{ Params = "ItemType, Count, Damage, EnchantmentString, CustomName, Lore", Return = "cItem", Notes = "Creates a new cItem object of the specified type, count (1 by default), damage (0 by default), enchantments (non-enchanted by default), CustomName (empty by default) and Lore (string, empty by default)" },
{ Params = "cItem", Return = "cItem", Notes = "Creates an exact copy of the cItem object in the parameter" },
} ,
AddCount = { Params = "AmountToAdd", Return = "cItem", Notes = "Adds the specified amount to the item count. Returns self (useful for chaining)." },
@ -1219,12 +1230,14 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
IsDamageable = { Params = "", Return = "bool", Notes = "Returns true if this item does account for its damage" },
IsEmpty = { Params = "", Return = "bool", Notes = "Returns true if this object represents an empty item (zero count or invalid ID)" },
IsEqual = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is the same as the one stored in the object (type, damage, lore, name and enchantments)" },
IsEnchantable = { Params = "", Return = "bool", Notes = "Returns true if the item is enchantable" },
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" },
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." },
GetEnchantability = { Params = "", Return = "number", Notes = "Returns the enchantability of the item. When the item hasn't a enchantability, it will returns 0" },
EnchantByXPLevels = { Params = "NumXPLevels", Return = "bool", Notes = "Enchants the item using the specified number of XP levels. Returns true if item enchanted, false if not." },
IsEnchantable = { Params = "ItemType, WithBook", Return = "bool", Notes = "(STATIC) Returns true if the specified item type is enchantable. If WithBook is true, the function is used in the anvil inventory with book enchantments. So it checks the \"only book enchantments\" too. Example: You can only enchant a hoe with a book." },
},
Variables =
{
@ -1234,6 +1247,8 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
m_ItemType = { Type = "number", Notes = "The item type. One of E_ITEM_ or E_BLOCK_ constants" },
m_CustomName = { Type = "string", Notes = "The custom name for an item." },
m_Lore = { Type = "string", Notes = "The lore for an item. Line breaks are represented by the ` character." },
m_RepairCost = { Type = "number", Notes = "The repair cost of the item. The anvil need this value" },
m_Enchantments = { Type = "{{cEnchantments|cEnchantments}}}", Notes = "The enchantments of the item." },
},
AdditionalInfo =
{
@ -1606,6 +1621,38 @@ a_Player:OpenWindow(Window);
}, -- cMapManager
cMojangAPI =
{
Desc = [[
Provides interface to various API functions that Mojang provides through their servers. Note that
some of these calls will wait for a response from the network, and so shouldn't be used while the
server is fully running (or at least when there are players connected) to avoid percepted lag.</p>
<p>
All the functions are static, call them using the <code>cMojangAPI:Function()</code> convention.</p>
<p>
Mojang uses two formats for UUIDs, short and dashed. MCServer works with short UUIDs internally, but
will convert to dashed UUIDs where needed - in the protocol login for example. The MakeUUIDShort()
and MakeUUIDDashed() functions are provided for plugins to use for conversion between the two
formats.</p>
<p>
This class will cache values returned by the API service. The cache will hold the values for 7 days
by default, after that, they will no longer be available. This is in order to not let the server get
banned from using the API service, since they are rate-limited to 600 queries per 10 minutes. The
cache contents also gets updated whenever a player successfully joins, since that makes the server
contact the API service, too, and retrieve the relevant data.</p>
]],
Functions =
{
AddPlayerNameToUUIDMapping = { Params = "PlayerName, UUID", Return = "", Notes = "(STATIC) Adds the specified PlayerName-to-UUID mapping into the cache, with current timestamp. Accepts both short or dashed UUIDs. " },
GetPlayerNameFromUUID = { Params = "UUID, [UseOnlyCached]", Return = "PlayerName", Notes = "(STATIC) Returns the playername that corresponds to the given UUID, or an empty string on error. If UseOnlyCached is false (the default), queries the Mojang servers if the UUID is not in the cache. The UUID can be either short or dashed. <br /><b>WARNING</b>: Do NOT use this function with UseOnlyCached set to false while the server is running. Only use it when the server is starting up (inside the Initialize() method), otherwise you will lag the server severely." },
GetUUIDFromPlayerName = { Params = "PlayerName, [UseOnlyCached]", Return = "UUID", Notes = "(STATIC) Returns the (short) UUID that corresponds to the given playername, or an empty string on error. If UseOnlyCached is false (the default), queries the Mojang servers if the playername is not in the cache. <br /><b>WARNING</b>: Do NOT use this function with UseOnlyCached set to false while the server is running. Only use it when the server is starting up (inside the Initialize() method), otherwise you will lag the server severely." },
GetUUIDsFromPlayerNames = { Params = "PlayerNames, [UseOnlyCached]", Return = "table", Notes = "(STATIC) Returns a table that contains the map, 'PlayerName' -> '(short) UUID', for all valid playernames in the input array-table. PlayerNames not recognized will not be set in the returned map. If UseOnlyCached is false (the default), queries the Mojang servers for the results that are not in the cache. <br /><b>WARNING</b>: Do NOT use this function with UseOnlyCached set to false while the server is running. Only use it when the server is starting up (inside the Initialize() method), otherwise you will lag the server severely." },
MakeUUIDDashed = { Params = "UUID", Return = "DashedUUID", Notes = "(STATIC) Converts the UUID to a dashed format (\"01234567-8901-2345-6789-012345678901\"). Accepts both dashed or short UUIDs. Logs a warning and returns an empty string if UUID format not recognized." },
MakeUUIDShort = { Params = "UUID", Return = "ShortUUID", Notes = "(STATIC) Converts the UUID to a short format (without dashes, \"01234567890123456789012345678901\"). Accepts both dashed or short UUIDs. Logs a warning and returns an empty string if UUID format not recognized." },
},
},
cMonster =
{
Desc = [[
@ -1615,6 +1662,11 @@ a_Player:OpenWindow(Window);
]],
Functions =
{
HasCustomName = { Params = "", Return = "bool", Notes = "Returns true if the monster has a custom name." },
GetCustomName = { Params = "", Return = "string", Notes = "Gets the custom name of the monster. If no custom name is set, the function returns an empty string." },
SetCustomName = { Params = "string", Return = "", Notes = "Sets the custom name of the monster. You see the name over the monster. If you want to disable the custom name, simply set an empty string." },
IsCustomNameAlwaysVisible = { Params = "", Return = "bool", Notes = "Is the custom name of this monster always visible? If not, you only see the name when you sight the mob." },
SetCustomNameAlwaysVisible = { Params = "bool", Return = "", Notes = "Sets the custom name visiblity of this monster. If it's false, you only see the name when you sight the mob. If it's true, you always see the custom name." },
FamilyFromType = { Params = "{{cMonster#MobType|MobType}}", Return = "{{cMonster#MobFamily|MobFamily}}", Notes = "(STATIC) Returns the mob family ({{cMonster#MobFamily|mfXXX}} constants) based on the mob type ({{cMonster#MobType|mtXXX}} constants)" },
GetMobFamily = { Params = "", Return = "{{cMonster#MobFamily|MobFamily}}", Notes = "Returns this mob's family ({{cMonster#MobFamily|mfXXX}} constant)" },
GetMobType = { Params = "", Return = "{{cMonster#MobType|MobType}}", Notes = "Returns the type of this mob ({{cMonster#MobType|mtXXX}} constant)" },
@ -1622,6 +1674,8 @@ a_Player:OpenWindow(Window);
MobTypeToString = { Params = "{{cMonster#MobType|MobType}}", Return = "string", Notes = "(STATIC) Returns the string representing the given mob type ({{cMonster#MobType|mtXXX}} constant), or empty string if unknown type." },
MoveToPosition = { Params = "Position", Return = "", Notes = "Moves mob to the specified position" },
StringToMobType = { Params = "string", Return = "{{cMonster#MobType|MobType}}", Notes = "(STATIC) Returns the mob type ({{cMonster#MobType|mtXXX}} constant) parsed from the string type (\"creeper\"), or mtInvalidType if unrecognized." },
GetRelativeWalkSpeed = { Params = "", Return = "number", Notes = "Returns the relative walk speed of this mob. Standard is 1.0" },
SetRelativeWalkSpeed = { Params = "number", Return = "", Notes = "Sets the relative walk speed of this mob. Standard is 1.0" },
},
Constants =
{
@ -1714,6 +1768,7 @@ a_Player:OpenWindow(Window);
GetItem = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item represented by this pickup" },
IsCollected = { Params = "", Return = "bool", Notes = "Returns true if this pickup has already been collected (is waiting to be destroyed)" },
IsPlayerCreated = { Params = "", Return = "bool", Notes = "Returns true if the pickup was created by a player" },
SetAge = { Params = "AgeTicks", Return = "", Notes = "Sets the pickup's age, in ticks." },
},
Inherits = "cEntity",
}, -- cPickup
@ -1728,7 +1783,6 @@ a_Player:OpenWindow(Window);
Functions =
{
AddFoodExhaustion = { Params = "Exhaustion", Return = "", Notes = "Adds the specified number to the food exhaustion. Only positive numbers expected." },
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." },
CloseWindow = { Params = "[CanRefuse]", Return = "", Notes = "Closes the currently open UI window. If CanRefuse is true (default), the window may refuse the closing." },
@ -1738,8 +1792,9 @@ a_Player:OpenWindow(Window);
FoodPoison = { Params = "NumTicks", Return = "", Notes = "Starts the food poisoning for the specified amount of ticks; if already foodpoisoned, sets FoodPoisonedTicksRemaining to the larger of the two" },
ForceSetSpeed = { Params = "{{Vector3d|Direction}}", Notes = "Forces the player to move to the given direction." },
GetClientHandle = { Params = "", Return = "{{cClientHandle}}", Notes = "Returns the client handle representing the player's connection. May be nil (AI players)." },
GetColor = { Return = "string", Notes = "Returns the full color code to be used for this player (based on the first group). Prefix player messages with this code." },
GetColor = { Return = "string", Notes = "Returns the full color code to be used for this player's messages (based on their rank). Prefix player messages with this code." },
GetCurrentXp = { Params = "", Return = "number", Notes = "Returns the current amount of XP" },
GetCustomName = { Params = "", Return = "string", Notes = "Returns the custom name of this player. If the player hasn't a custom name, it will return an empty string." },
GetEffectiveGameMode = { Params = "", Return = "{{Globals#GameMode|GameMode}}", Notes = "(OBSOLETE) Returns the current resolved game mode of the player. If the player is set to inherit the world's gamemode, returns that instead. See also GetGameMode() and IsGameModeXXX() functions. Note that this function is the same as GetGameMode(), use that function instead." },
GetEquippedItem = { Params = "", Return = "{{cItem}}", Notes = "Returns the item that the player is currently holding; empty item if holding nothing." },
GetEyeHeight = { Return = "number", Notes = "Returns the height of the player's eyes, in absolute coords" },
@ -1752,21 +1807,26 @@ a_Player:OpenWindow(Window);
GetFoodSaturationLevel = { Params = "", Return = "number", Notes = "Returns the food saturation (overcharge of the food level, is depleted before food level)" },
GetFoodTickTimer = { Params = "", Return = "", Notes = "Returns the number of ticks past the last food-based heal or damage action; when this timer reaches 80, a new heal / damage is applied." },
GetGameMode = { Return = "{{Globals#GameMode|GameMode}}", Notes = "Returns the player's gamemode. The player may have their gamemode unassigned, in which case they inherit the gamemode from the current {{cWorld|world}}.<br /> <b>NOTE:</b> Instead of comparing the value returned by this function to the gmXXX constants, use the IsGameModeXXX() functions. These functions handle the gamemode inheritance automatically."},
GetGroups = { Return = "array-table of {{cGroup}}", Notes = "Returns all the groups that this player is member of, as a table. The groups are stored in the array part of the table, beginning with index 1."},
GetIP = { Return = "string", Notes = "Returns the IP address of the player, if available. Returns an empty string if there's no IP to report."},
GetInventory = { Return = "{{cInventory|Inventory}}", Notes = "Returns the player's inventory"},
GetLastBedPos = { Params = "", Return = "{{Vector3i}}", Notes = "Returns the position of the last bed the player has slept in, or the world's spawn if no such position was recorded." },
GetMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's current maximum speed, relative to the game default speed. Takes into account the sprinting / flying status." },
GetName = { Return = "string", Notes = "Returns the player's name" },
GetNormalMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's maximum walking speed, relative to the game default speed. Defaults to 1, but plugins may modify it for faster or slower walking." },
GetPermissions = { Params = "", Return = "array-table of strings", Notes = "Returns the list of all permissions that the player has assigned to them through their rank." },
GetPlayerListName = { Return = "string", Notes = "Returns the name that is used in the playerlist." },
GetResolvedPermissions = { Return = "array-table of string", Notes = "Returns all the player's permissions, as a table. The permissions are stored in the array part of the table, beginning with index 1." },
GetSprintingMaxSpeed = { Params = "", Return = "number", Notes = "Returns the player's maximum sprinting speed, relative to the game default speed. Defaults to 1.3, but plugins may modify it for faster or slower sprinting." },
GetStance = { Return = "number", Notes = "Returns the player's stance (Y-pos of player's eyes)" },
GetTeam = { Params = "", Return = "{{cTeam}}", Notes = "Returns the team that the player belongs to, or nil if none." },
GetThrowSpeed = { Params = "SpeedCoeff", Return = "{{Vector3d}}", Notes = "Returns the speed vector for an object thrown with the specified speed coeff. Basically returns the normalized look vector multiplied by the coeff, with a slight random variation." },
GetThrowStartPos = { Params = "", Return = "{{Vector3d}}", Notes = "Returns the position where the projectiles should start when thrown by this player." },
GetUUID = { Params = "", Return = "string", Notes = "Returns the (short) UUID that the player is using. Could be empty string for players that don't have a Mojang account assigned to them (in the future, bots for example)." },
GetWindow = { Params = "", Return = "{{cWindow}}", Notes = "Returns the currently open UI window. If the player doesn't have any UI window open, returns the inventory window." },
GetXpLevel = { Params = "", Return = "number", Notes = "Returns the current XP level (based on current XP amount)." },
GetXpLifetimeTotal = { Params = "", Return = "number", Notes = "Returns the amount of XP that has been accumulated throughout the player's lifetime." },
GetXpPercentage = { Params = "", Return = "number", Notes = "Returns the percentage of the experience bar - the amount of XP towards the next XP level. Between 0 and 1." },
HasCustomName = { Params = "", Return = "bool", Notes = "Returns true if the player has a custom name." },
HasPermission = { Params = "PermissionString", Return = "bool", Notes = "Returns true if the player has the specified permission" },
Heal = { Params = "HitPoints", Return = "", Notes = "Heals the player by the specified amount of HPs. Only positive amounts are expected. Sends a health update to the client." },
IsEating = { Params = "", Return = "bool", Notes = "Returns true if the player is currently eating the item in their hand." },
@ -1774,16 +1834,17 @@ a_Player:OpenWindow(Window);
IsFlying = { Return = "bool", Notes = "Returns true if the player is flying." },
IsGameModeAdventure = { Params = "", Return = "bool", Notes = "Returns true if the player is in the gmAdventure gamemode, or has their gamemode unset and the world is a gmAdventure world." },
IsGameModeCreative = { Params = "", Return = "bool", Notes = "Returns true if the player is in the gmCreative gamemode, or has their gamemode unset and the world is a gmCreative world." },
IsGameModeSpectator = { Params = "", Return = "bool", Notes = "Returns true if the player is in the gmSpectator gamemode, or has their gamemode unset and the world is a gmSpectator world." },
IsGameModeSurvival = { Params = "", Return = "bool", Notes = "Returns true if the player is in the gmSurvival gamemode, or has their gamemode unset and the world is a gmSurvival world." },
IsInGroup = { Params = "GroupNameString", Return = "bool", Notes = "Returns true if the player is a member of the specified group." },
IsInBed = { Params = "", Return = "bool", Notes = "Returns true if the player is currently lying in a bed." },
IsOnGround = { Params = "", Return = "bool", Notes = "Returns true if the player is on ground (not falling, not jumping, not flying)" },
IsSatiated = { Params = "", Return = "bool", Notes = "Returns true if the player is satiated (cannot eat)." },
IsVisible = { Params = "", Return = "bool", Notes = "Returns true if the player is visible to other players" },
LoadPermissionsFromDisk = { Params = "", Return = "", Notes = "Reloads the player's permissions from the disk. This loses any temporary changes made to the player's groups." },
LoadRank = { Params = "", Return = "", Notes = "Reloads the player's rank, message visuals and permissions from the {{cRankManager}}, based on the player's current rank." },
MoveTo = { Params = "{{Vector3d|NewPosition}}", Return = "Tries to move the player into the specified position." },
MoveToWorld = { Params = "WorldName", Return = "bool", Return = "Moves the player to the specified world. Returns true if successful." },
OpenWindow = { Params = "{{cWindow|Window}}", Return = "", Notes = "Opens the specified UI window for the player." },
RemoveFromGroup = { Params = "GroupName", Return = "", Notes = "Temporarily removes the player from the specified group. This change is lost when the player disconnects." },
PermissionMatches = { Params = "Permission, Template", Return = "bool", Notes = "(STATIC) Returns true if the specified permission matches the specified template. The template may contain wildcards." },
Respawn = { Params = "", Return = "", Notes = "Restores the health, extinguishes fire, makes visible and sends the Respawn packet." },
SendMessage = { Params = "Message", Return = "", Notes = "Sends the specified message to the player." },
SendMessageFailure = { Params = "Message", Return = "", Notes = "Prepends Rose [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For a command that failed to run because of insufficient permissions, etc." },
@ -1792,9 +1853,12 @@ a_Player:OpenWindow(Window);
SendMessagePrivateMsg = { Params = "Message, SenderName", Return = "", Notes = "Prepends Light Blue [MSG: *SenderName*] / prepends SenderName and colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For private messaging." },
SendMessageSuccess = { Params = "Message", Return = "", Notes = "Prepends Green [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. Success notification." },
SendMessageWarning = { Params = "Message, Sender", Return = "", Notes = "Prepends Rose [WARN] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. Denotes that something concerning, such as plugin reload, is about to happen." },
SendRotation = { Params = "YawDegrees, PitchDegrees", Return = "", Notes = "Sends the specified rotation to the player, forcing them to look that way" },
SetBedPos = { Params = "{{Vector3i|Position}}", Return = "", Notes = "Sets the internal representation of the last bed position the player has slept in. The player will respawn at this position if they die." },
SetCanFly = { Params = "CanFly", Notes = "Sets if the player can fly or not." },
SetCrouch = { Params = "IsCrouched", Return = "", Notes = "Sets the crouch state, broadcasts the change to other players." },
SetCurrentExperience = { Params = "XPAmount", Return = "", Notes = "Sets the current amount of experience (and indirectly, the XP level)." },
SetCustomName = { Params = "string", Return = "", Notes = "Sets the custom name of this player. If you want to disable the custom name, simply set an empty string. The custom name will be used in the tab-list, in the player nametag and in the tab-completion." },
SetFlying = { Params = "IsFlying", Notes = "Sets if the player is flying or not." },
SetFlyingMaxSpeed = { Params = "FlyingMaxSpeed", Return = "", Notes = "Sets the flying maximum speed, relative to the game default speed. The default value is 1. Sends the updated speed to the client." },
SetFoodExhaustionLevel = { Params = "ExhaustionLevel", Return = "", Notes = "Sets the food exhaustion to the specified level." },
@ -1808,7 +1872,11 @@ a_Player:OpenWindow(Window);
SetNormalMaxSpeed = { Params = "NormalMaxSpeed", Return = "", Notes = "Sets the normal (walking) maximum speed, relative to the game default speed. The default value is 1. Sends the updated speed to the client, if appropriate." },
SetSprint = { Params = "IsSprinting", Return = "", Notes = "Sets whether the player is sprinting or not." },
SetSprintingMaxSpeed = { Params = "SprintingMaxSpeed", Return = "", Notes = "Sets the sprinting maximum speed, relative to the game default speed. The default value is 1.3. Sends the updated speed to the client, if appropriate." },
SetTeam = { Params = "{{cTeam|Team}}", Return = "", Notes = "Moves the player to the specified team." },
SetVisible = { Params = "IsVisible", Return = "", Notes = "Sets the player visibility to other players" },
TossEquippedItem = { Params = "[Amount]", Return = "", Notes = "Tosses the item that the player has selected in their hotbar. Amount defaults to 1." },
TossHeldItem = { Params = "[Amount]", Return = "", Notes = "Tosses the item held by the cursor, then the player is in a UI window. Amount defaults to 1." },
TossPickup = { Params = "{{cItem|Item}}", Return = "", Notes = "Tosses a pickup newly created from the specified item." },
XpForLevel = { Params = "XPLevel", Return = "number", Notes = "(STATIC) Returns the total amount of XP needed for the specified XP level. Inverse of CalcLevelFromXp()." },
},
Constants =
@ -1870,13 +1938,13 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
},
BindCommand =
{
{ 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." },
{ 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. The callback uses the following signature: <pre class=\"prettyprint lang-lua\">function(Split, {{cPlayer|Player}})</pre> The Split parameter contains an array-table of the words that the player has sent, Player is the {{cPlayer}} object representing the player who sent the command. If the callback returns true, the command is assumed to have executed successfully; in all other cases the server sends a warning to the player that the command is unknown (this is so that subcommands can be implemented)." },
{ 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. The callback uses the following signature: <pre class=\"prettyprint lang-lua\">function(Split, {{cPlayer|Player}})</pre> The Split parameter contains an array-table of the words that the player has sent, Player is the {{cPlayer}} object representing the player who sent the command. If the callback returns true, the command is assumed to have executed successfully; in all other cases the server sends a warning to the player that the command is unknown (this is so that subcommands can be implemented)." },
},
BindConsoleCommand =
{
{ 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." },
{ 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. The callback uses the following signature: <pre class=\"prettyprint lang-lua\">function(Split)</pre> The Split parameter contains an array-table of the words that the admin has typed. If the callback returns true, the command is assumed to have executed successfully; in all other cases the server issues a warning to the console that the command is unknown (this is so that subcommands can be implemented)." },
{ 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. The callback uses the following signature: <pre class=\"prettyprint lang-lua\">function(Split)</pre> The Split parameter contains an array-table of the words that the admin has typed. If the callback returns true, the command is assumed to have executed successfully; in all other cases the server issues a warning to the console that the command is unknown (this is so that subcommands can be implemented)." },
},
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." },
@ -1958,6 +2026,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
HOOK_PLAYER_USING_ITEM = { Notes = "Called when the player is about to right-click with a usable item in their hand." },
HOOK_POST_CRAFTING = { Notes = "Called after a valid recipe has been chosen for the current contents of the crafting grid. Plugins may modify the recipe." },
HOOK_PRE_CRAFTING = { Notes = "Called before a recipe is searched for the current contents of the crafting grid. Plugins may provide a recipe and cancel the built-in search." },
HOOK_SERVER_PING = { Notes = "Called when a client pings the server from the server list. Plugins may change the favicon, server description, players online and maximum players values." },
HOOK_SPAWNED_ENTITY = { Notes = "Called after an entity is spawned in a {{cWorld|world}}. The entity is already part of the world." },
HOOK_SPAWNED_MONSTER = { Notes = "Called after a mob is spawned in a {{cWorld|world}}. The mob is already part of the world." },
HOOK_SPAWNING_ENTITY = { Notes = "Called just before an entity is spawned in a {{cWorld|world}}." },
@ -1972,6 +2041,74 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
},
}, -- cPluginManager
cRankManager =
{
Desc = [[
Manages the players' permissions. The players are assigned a single rank, which contains groups of
permissions. The functions in this class query or modify these.</p>
<p>
All the functions are static, call them using the <code>cRankManager:Function()</code> convention.</p>
<p>
The players are identified by their UUID, to support player renaming.</p>
<p>
The rank also contains specific "mesage visuals" - bits that are used for formatting messages from the
players. There's a message prefix, which is put in front of every message the player sends, and the
message suffix that is appended to each message. There's also a PlayerNameColorCode, which holds the
color that is used for the player's name in the messages.</p>
<p>
Each rank can contain any number of permission groups. These groups allow for an easier setup of the
permissions - you can share groups among ranks, so the usual approach is to group similar permissions
together and add that group to any rank that should use those permissions.</p>
<p>
Permissions are added to individual groups. Each group can support unlimited permissions. Note that
adding a permission to a group will make the permission available to all the ranks that contain that
permission group.</p>
<p>
One rank is reserved as the Default rank. All players that don't have an explicit rank assigned to them
will behave as if assigned to this rank. The default rank can be changed to any other rank at any time.
Note that the default rank cannot be removed from the RankManager - RemoveRank() will change the default
rank to the replacement rank, if specified, and fail if no replacement rank is specified. Renaming the
default rank using RenameRank() will change the default rank to the new name.
]],
Functions =
{
AddGroup = { Params = "GroupName", Return = "", Notes = "Adds the group of the specified name. Logs a warning and does nothing if the group already exists." },
AddGroupToRank = { Params = "GroupName, RankName", Return = "bool", Notes = "Adds the specified group to the specified rank. Returns true on success, false on failure - if the group name or the rank name is not found." },
AddPermissionToGroup = { Params = "Permission, GroupName", Return = "bool", Notes = "Adds the specified permission to the specified group. Returns true on success, false on failure - if the group name is not found." },
AddRank = { Params = "RankName, MsgPrefix, MsgSuffix, MsgNameColorCode", Return = "", Notes = "Adds a new rank of the specified name and with the specified message visuals. Logs an info message and does nothing if the rank already exists." },
ClearPlayerRanks = { Params = "", Return = "", Notes = "Removes all player ranks from the database. Note that this doesn't change the cPlayer instances for the already connected players, you need to update all the instances manually." },
GetAllGroups = { Params = "", Return = "array-table of groups' names", Notes = "Returns an array-table containing the names of all the groups that are known to the manager." },
GetAllPermissions = { Params = "", Return = "array-table of permissions", Notes = "Returns an array-table containing all the permissions that are known to the manager." },
GetAllPlayerUUIDs = { Params = "", Return = "array-table of uuids", Notes = "Returns the short uuids of all players stored in the rank DB, sorted by the players' names (case insensitive)." },
GetAllRanks = { Params = "", Return = "array-table of ranks' names", Notes = "Returns an array-table containing the names of all the ranks that are known to the manager." },
GetDefaultRank = { Params = "", Return = "string", Notes = "Returns the name of the default rank. " },
GetGroupPermissions = { Params = "GroupName", Return = "array-table of permissions", Notes = "Returns an array-table containing the permissions that the specified group contains." },
GetPlayerGroups = { Params = "PlayerUUID", Return = "array-table of groups' names", Notes = "Returns an array-table of the names of the groups that are assigned to the specified player through their rank. Returns an empty table if the player is not known or has no rank or groups assigned to them." },
GetPlayerMsgVisuals = { Params = "PlayerUUID", Return = "MsgPrefix, MsgSuffix, MsgNameColorCode", Notes = "Returns the message visuals assigned to the player. If the player is not explicitly assigned a rank, the default rank's visuals are returned. If there is an error, no value is returned at all." },
GetPlayerPermissions = { Params = "PlayerUUID", Return = "array-table of permissions", Notes = "Returns the permissions that the specified player is assigned through their rank. Returns the default rank's permissions if the player has no explicit rank assigned to them. Returns an empty array on error." },
GetPlayerRankName = { Params = "PlayerUUID", Return = "RankName", Notes = "Returns the name of the rank that is assigned to the specified player. An empty string (NOT the default rank) is returned if the player has no rank assigned to them." },
GetPlayerName = { Params = "PlayerUUID", Return = "PlayerName", Notes = "Returns the last name that the specified player has, for a player in the ranks database. An empty string is returned if the player isn't in the database." },
GetRankGroups = { Params = "RankName", Return = "array-table of groups' names", Notes = "Returns an array-table of the names of all the groups that are assigned to the specified rank. Returns an empty table if there is no such rank." },
GetRankPermissions = { Params = "RankName", Return = "array-table of permissions", Notes = "Returns an array-table of all the permissions that are assigned to the specified rank through its groups. Returns an empty table if there is no such rank." },
GetRankVisuals = { Params = "RankName", Return = "MsgPrefix, MsgSuffix, MsgNameColorCode", Notes = "Returns the message visuals for the specified rank. Returns no value if the specified rank does not exist." },
GroupExists = { Params = "GroupName", Return = "bool", Notes = "Returns true iff the specified group exists." },
IsGroupInRank = { Params = "GroupName, RankName", Return = "bool", Notes = "Returns true iff the specified group is assigned to the specified rank." },
IsPermissionInGroup = { Params = "Permission, GroupName", Return = "bool", Notes = "Returns true iff the specified permission is assigned to the specified group." },
IsPlayerRankSet = { Params = "PlayerUUID", Return = "bool", Notes = "Returns true iff the specified player has a rank assigned to them." },
RankExists = { Params = "RankName", Return = "bool", Notes = "Returns true iff the specified rank exists." },
RemoveGroup = { Params = "GroupName", Return = "", Notes = "Removes the specified group completely. The group will be removed from all the ranks using it and then erased from the manager. Logs an info message and does nothing if the group doesn't exist." },
RemoveGroupFromRank = { Params = "GroupName, RankName", Return = "", Notes = "Removes the specified group from the specified rank. The group will still exist, even if it isn't assigned to any rank. Logs an info message and does nothing if the group or rank doesn't exist." },
RemovePermissionFromGroup = { Params = "Permission, GroupName", Return = "", Notes = "Removes the specified permission from the specified group. Logs an info message and does nothing if the group doesn't exist." },
RemovePlayerRank = { Params = "PlayerUUID", Return = "", Notes = "Removes the player's rank; the player's left without a rank. Note that this doesn't change the {{cPlayer}} instances for the already connected players, you need to update all the instances manually. No action if the player has no rank assigned to them already." },
RemoveRank = { Params = "RankName, [ReplacementRankName]", Return = "", Notes = "Removes the specified rank. If ReplacementRankName is given, the players that have RankName will get their rank set to ReplacementRankName. If it isn't given, or is an invalid rank, the players will be removed from the manager, their ranks will be unset completely. Logs an info message and does nothing if the rank is not found." },
RenameGroup = { Params = "OldName, NewName", Return = "", Notes = "Renames the specified group. Logs an info message and does nothing if the group is not found or the new name is already used." },
RenameRank = { Params = "OldName, NewName", Return = "", Notes = "Renames the specified rank. Logs an info message and does nothing if the rank is not found or the new name is already used." },
SetDefaultRank = { Params = "RankName", Return = "bool", Notes = "Sets the specified rank as the default rank. Returns true on success, false on failure (rank doesn't exist)." },
SetPlayerRank = { Params = "PlayerUUID, PlayerName, RankName", Return = "", Notes = "Updates the rank for the specified player. The player name is provided for reference, the UUID is used for identification. Logs a warning and does nothing if the rank is not found." },
SetRankVisuals = { Params = "RankName, MsgPrefix, MsgSuffix, MsgNameColorCode", Return = "", Notes = "Updates the rank's message visuals. Logs an info message and does nothing if rank not found." },
},
}, -- cRankManager
cRoot =
{
Desc = [[
@ -1985,22 +2122,28 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
]],
Functions =
{
Get = { Params = "", Return = "Root object", Notes = "(STATIC)This function returns the cRoot object." },
BroadcastChat = { Params = "Message", Return = "", Notes = "Broadcasts a message to every player in the server. No formatting is done by the server." },
BroadcastChatFailure = { Params = "Message", Return = "", Notes = "Prepends Rose [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For a command that failed to run because of insufficient permissions, etc." },
BroadcastChatFatal = { Params = "Message", Return = "", Notes = "Prepends Red [FATAL] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For a plugin that crashed, or similar." },
BroadcastChatInfo = { Params = "Message", Return = "", Notes = "Prepends Yellow [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For informational messages, such as command usage." },
BroadcastChatSuccess = { Params = "Message", Return = "", Notes = "Prepends Green [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For success messages." },
BroadcastChatWarning = { Params = "Message", Return = "", Notes = "Prepends Rose [WARN] / colours entire text (depending on ShouldUseChatPrefixes()) and broadcasts message. For concerning events, such as plugin reload etc." },
CreateAndInitializeWorld = { Params = "WorldName", Return = "{{cWorld|cWorld}}", Notes = "Creates a new world and initializes it. If there is a world whith the same name it returns nil." },
BroadcastChat =
{
{ Params = "MessageText, MessageType", Return = "", Notes = "Broadcasts a message to all players, with its message type set to MessageType (default: mtCustom)." },
{ Params = "{{cCompositeChat|CompositeChat}}", Return = "", Notes = "Broadcasts a {{cCompositeChat|composite chat message} to all players." },
},
BroadcastChatDeath = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtDeath. Use for when a player has died." },
BroadcastChatFailure = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtFailure. Use for a command that failed to run because of insufficient permissions, etc." },
BroadcastChatFatal = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtFatal. Use for a plugin that crashed, or similar." },
BroadcastChatInfo = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtInfo. Use for informational messages, such as command usage." },
BroadcastChatJoin = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtJoin. Use for players joining the server." },
BroadcastChatLeave = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtLeave. Use for players leaving the server." },
BroadcastChatSuccess = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtSuccess. Use for success messages." },
BroadcastChatWarning = { Params = "MessageText", Return = "", Notes = "Broadcasts the specified message to all players, with its message type set to mtWarning. Use for concerning events, such as plugin reload etc." },
CreateAndInitializeWorld = { Params = "WorldName", Return = "{{cWorld|cWorld}}", Notes = "Creates a new world and initializes it. If there is a world whith the same name it returns nil.<br/><br/><b>NOTE</b>This function is currently unsafe, do not use!" },
FindAndDoWithPlayer = { Params = "PlayerName, CallbackFunction", Return = "", Notes = "Calls the given callback function for all players with names partially (or fully) matching the name string provided." },
ForEachPlayer = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each player. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|cPlayer}})</pre>" },
ForEachWorld = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each world. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cWorld|cWorld}})</pre>" },
Get = { Params = "", Return = "Root object", Notes = "(STATIC)This function returns the cRoot object." },
GetCraftingRecipes = { Params = "", Return = "{{cCraftingRecipe|cCraftingRecipe}}", Notes = "Returns the CraftingRecipes object" },
GetDefaultWorld = { Params = "", Return = "{{cWorld|cWorld}}", Notes = "Returns the world object from the default world." },
GetFurnaceFuelBurnTime = { Params = "{{cItem|Fuel}}", Return = "number", Notes = "(STATIC) Returns the number of ticks for how long the item would fuel a furnace. Returns zero if not a fuel." },
GetFurnaceRecipe = { Params = "{{cItem|InItem}}", Return = "{{cItem|OutItem}}, NumTicks, {{cItem|InItem}}", Notes = "(STATIC) Returns the furnace recipe for smelting the specified input. If a recipe is found, returns the smelted result, the number of ticks required for the smelting operation, and the input consumed (note that MCServer supports smelting M items into N items and different smelting rates). If no recipe is found, returns no value." },
GetGroupManager = { Params = "", Return = "{{cGroupManager|cGroupManager}}", Notes = "Returns the cGroupManager object." },
GetPhysicalRAMUsage = { Params = "", Return = "number", Notes = "Returns the amount of physical RAM that the entire MCServer process is using, in KiB. Negative if the OS doesn't support this query." },
GetPluginManager = { Params = "", Return = "{{cPluginManager|cPluginManager}}", Notes = "Returns the cPluginManager object." },
GetPrimaryServerVersion = { Params = "", Return = "number", Notes = "Returns the servers primary server version." },
@ -2084,10 +2227,11 @@ end
{
GetDescription = { Return = "string", Notes = "Returns the server description set in the settings.ini." },
GetMaxPlayers = { Return = "number", Notes = "Returns the max amount of players who can join the server." },
SetMaxPlayers = { Params = "number", Notes = "Sets the max amount of players who can join." },
GetNumPlayers = { Return = "number", Notes = "Returns the amount of players online." },
GetServerID = { Return = "string", Notes = "Returns the ID of the server?" },
IsHardcore = { Params = "", Return = "bool", Notes = "Returns true if the server is hardcore (players get banned on death)." },
SetMaxPlayers = { Params = "number", Notes = "Sets the max amount of players who can join." },
ShouldAuthenticate = { Params = "", Return = "bool", Notes = "Returns true iff the server is set to authenticate players (\"online mode\")." },
},
}, -- cServer
@ -2244,6 +2388,7 @@ end
DigBlock = { Params = "X, Y, Z", Return = "", Notes = "Replaces the specified block with air, without dropping the usual pickups for the block. Wakes up the simulators for the block and its neighbors." },
DoExplosionAt = { Params = "Force, X, Y, Z, CanCauseFire, Source, SourceData", Return = "", Notes = "Creates an explosion of the specified relative force in the specified position. If CanCauseFire is set, the explosion will set blocks on fire, too. The Source parameter specifies the source of the explosion, one of the esXXX constants. The SourceData parameter is specific to each source type, usually it provides more info about the source." },
DoWithBlockEntityAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a block entity at the specified coords, calls the CallbackFunction with the {{cBlockEntity}} parameter representing the block entity. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cBlockEntity|BlockEntity}}, [CallbackData])</pre> The function returns false if there is no block entity, or if there is, it returns the bool value that the callback has returned. Use {{tolua}}.cast() to cast the Callback's BlockEntity parameter to the correct {{cBlockEntity}} descendant." },
DoWithBeaconAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a beacon at the specified coords, calls the CallbackFunction with the {{cBeaconEntity}} parameter representing the beacon. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cBeaconEntity|BeaconEntity}}, [CallbackData])</pre> The function returns false if there is no beacon, or if there is, it returns the bool value that the callback has returned." },
DoWithChestAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a chest at the specified coords, calls the CallbackFunction with the {{cChestEntity}} parameter representing the chest. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cChestEntity|ChestEntity}}, [CallbackData])</pre> The function returns false if there is no chest, or if there is, it returns the bool value that the callback has returned." },
DoWithCommandBlockAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a command block at the specified coords, calls the CallbackFunction with the {{cCommandBlockEntity}} parameter representing the command block. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cCommandBlockEntity|CommandBlockEntity}}, [CallbackData])</pre> The function returns false if there is no command block, or if there is, it returns the bool value that the callback has returned." },
DoWithDispenserAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dispenser at the specified coords, calls the CallbackFunction with the {{cDispenserEntity}} parameter representing the dispenser. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cDispenserEntity|DispenserEntity}}, [CallbackData])</pre> The function returns false if there is no dispenser, or if there is, it returns the bool value that the callback has returned." },
@ -2264,6 +2409,7 @@ end
ForEachBlockEntityInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each block entity in the chunk. Returns true if all block entities in the chunk have been processed (including when there are zero block entities), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cBlockEntity|BlockEntity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next block entity, or true to abort the enumeration. Use {{tolua}}.cast() to cast the Callback's BlockEntity parameter to the correct {{cBlockEntity}} descendant." },
ForEachChestInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each chest in the chunk. Returns true if all chests in the chunk have been processed (including when there are zero chests), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cChestEntity|ChestEntity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next chest, or true to abort the enumeration." },
ForEachEntity = { Params = "CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each entity in the loaded world. Returns true if all the entities have been processed (including when there are zero entities), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next entity, or true to abort the enumeration." },
ForEachEntityInBox = { Params = "{{cBoundingBox|Box}}, CallbackFunction", Return = "bool", Notes = "Calls the specified callback for each entity in the specified bounding box. Returns true if all the entities have been processed (including when there are zero entities), or false if the callback function has aborted the enumeration by returning true. If any chunk within the bounding box is not valid, it is silently skipped without any notification. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}})</pre> The callback should return false or no value to continue with the next entity, or true to abort the enumeration." },
ForEachEntityInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each entity in the specified chunk. Returns true if all the entities have been processed (including when there are zero entities), or false if the chunk is not loaded or the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next entity, or true to abort the enumeration." },
ForEachFurnaceInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each furnace in the chunk. Returns true if all furnaces in the chunk have been processed (including when there are zero furnaces), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cFurnaceEntity|FurnaceEntity}}, [CallbackData])</pre> The callback should return false or no value to continue with the next furnace, or true to abort the enumeration." },
ForEachPlayer = { Params = "CallbackFunction, [CallbackData]", Return = "bool", Notes = "Calls the specified callback for each player in the loaded world. Returns true if all the players have been processed (including when there are zero players), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}}, [CallbackData])</pre> The callback should return false or no value to continue with the next player, or true to abort the enumeration." },
@ -2494,8 +2640,8 @@ World:ForEachEntity(
The following code snippet checks if the player holds a shovel.
<pre class="prettyprint lang-lua">
-- a_Player is a {{cPlayer}} object, possibly received as a hook param
local HeldItem = a_Player:GetEquippedItem();
if (cItemCategory:IsShovel(HeldItem.m_ItemType)) then
local HeldItem = a_Player:GetEquippedItem()
if (ItemCategory.IsShovel(HeldItem.m_ItemType)) then
-- It's a shovel
end
</pre>
@ -2721,7 +2867,7 @@ end
Globals =
{
Desc = [[
These functions are available directly, without a class instance. Any plugin cal call them at any
These functions are available directly, without a class instance. Any plugin can call them at any
time.
]],
Functions =
@ -2729,6 +2875,7 @@ end
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"},
Clamp = {Params = "Number, Min, Max", Return = "number", Notes = "Clamp the number to the specified range."},
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 "},
EscapeString = {Params = "string", Return = "string", Notes = "Returns a copy of the string with all quotes and backslashes escaped by a backslash"},
@ -2769,7 +2916,7 @@ end
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"},
ReplaceString = {Params = "full-string, to-be-replaced-string, to-replace-string", Return = "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."},

View File

@ -50,6 +50,32 @@ return
},
},
cBeaconEntity =
{
Desc = [[
A beacon entity is a {{cBlockEntityWithItems|cBlockEntityWithItems}} descendant that represents a beacon
in the world.
]],
Inherits = "cBlockEntityWithItems",
Functions =
{
IsActive = { Params = "", Return = "bool", Notes = "Is the beacon active?" },
GetBeaconLevel = { Params = "", Return = "number", Notes = "Returns the beacon level. (0 - 4)" },
GetPrimaryEffect = { Params = "", Return = "EffectType", Notes = "Returns the primary effect." },
GetSecondaryEffect = { Params = "", Return = "EffectType", Notes = "Returns the secondary effect." },
SetPrimaryEffect = { Params = "EffectType", Return = "bool", Notes = "Select the primary effect. Returns false when the effect is invalid." },
SetSecondaryEffect = { Params = "EffectType", Return = "bool", Notes = "Select the secondary effect. Returns false when the effect is invalid." },
CalculatePyramidLevel = { Params = "", Return = "number", Notes = "Calculate the amount of layers the pyramid below the beacon has." },
IsBeaconBlocked = { Params = "", Return = "bool", Notes = "Is the beacon blocked by non-transparent blocks that are higher than the beacon?" },
UpdateBeacon = { Params = "", Return = "", Notes = "Update the beacon." },
GiveEffects = { Params = "", Return = "", Notes = "Give the near-players the effects." },
IsMineralBlock = { Params = "BLOCKTYPE", Return = "bool", Notes = "Returns true if the block is a diamond block, a golden block, an iron block or an emerald block." },
IsValidEffect = { Params = "EffectType", Return = "bool", Notes = "Returns true if the effect can be used." },
},
},
cChestEntity =
{
Desc = [[

View File

@ -11,9 +11,11 @@ return
Params =
{
{ Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has moved. The object already has the new position stored in it." },
{ Name = "OldPosition", Type = "{{Vector3d}}", Notes = "The old position." },
{ Name = "NewPosition", Type = "{{Vector3d}}", Notes = "The new position." },
},
Returns = [[
If the function returns true, movement is prohibited. FIXME: The player's client is not informed.</p>
If the function returns true, movement is prohibited.</p>
<p>
If the function returns false or no value, other plugins' callbacks are called and finally the new
position is permanently stored in the cPlayer object.</p>

View File

@ -0,0 +1,50 @@
return
{
HOOK_SERVER_PING =
{
CalledWhen = "Client pings the server from the server list.",
DefaultFnName = "OnServerPing", -- also used as pagename
Desc = [[
A plugin may implement an OnServerPing() function and register it as a Hook to process pings from
clients in the server server list. It can change the logged in players and player capacity, as well
as the server description and the favicon, that are displayed to the client in the server list.
]],
Params = {
{ Name = "ClientHandle", Type = "{{cClientHandle}}", Notes = "The client handle that pinged the server" },
{ Name = "ServerDescription", Type = "string", Notes = "The server description" },
{ Name = "OnlinePlayersCount", Type = "number", Notes = "The number of players currently on the server" },
{ Name = "MaxPlayersCount", Type = "number", Notes = "The current player cap for the server" },
{ Name = "Favicon", Type = "string", Notes = "The base64 encoded favicon to be displayed in the server list for compatible clients" },
},
Returns = [[
The plugin can return whether to continue processing of the hook with other plugins, the server description to
be displayed to the client, the currently online players, the player cap and the base64/png favicon data, in that order.
]],
CodeExamples = {
{
Title = "Change information returned to the player",
Desc = "Tells the client that the server description is 'test', there are one more players online than there actually are, and that the player cap is zero. It also changes the favicon data.",
Code = [[
function OnServerPing(ClientHandle, ServerDescription, OnlinePlayers, MaxPlayers, Favicon)
-- Change Server Description
ServerDescription = "Test"
-- Change online / max players
OnlinePlayers = OnlinePlayers + 1
MaxPlayers = 0
-- Change favicon
if cFile:IsFile("my-favicon.png") then
local FaviconData = cFile:ReadWholeFile("my-favicon.png")
if (FaviconData ~= "") and (FaviconData ~= nil) then
Favicon = Base64Encode(FaviconData)
end
end
return false, ServerDescription, OnlinePlayers, MaxPlayers, Favicon
end
]],
},
},
}, -- HOOK_SERVER_PING
}

View File

@ -6,8 +6,9 @@ return
DefaultFnName = "OnSpawningEntity", -- also used as pagename
Desc = [[
This hook is called before the server spawns an {{cEntity|entity}}. The plugin can either modify the
entity before it is spawned, or disable the spawning altogether. If the entity spawning is a
monster, the {{OnSpawningMonster|HOOK_SPAWNING_MONSTER}} hook is called before this hook.</p>
entity before it is spawned, or disable the spawning altogether. You can't disable the spawning if the
entity is a player. If the entity spawning is a monster, the {{OnSpawningMonster|HOOK_SPAWNING_MONSTER}}
hook is called before this hook.</p>
<p>
See also the {{OnSpawnedEntity|HOOK_SPAWNED_ENTITY}} hook for a similar hook called after the
entity is spawned.

View File

@ -202,7 +202,7 @@ function Explode(Split, Player)
if (#Split ~= 2) then
-- There was more or less than one argument (excluding the "/explode" bit)
-- Send the proper usage to the player and exit
SendMessage(Player, "Usage: /explode [playername]")
Player:SendMessage("Usage: /explode [playername]")
return true
end
@ -213,7 +213,7 @@ function Explode(Split, Player)
if (Explodee:GetName() == Split[2]) then
-- Create an explosion at the same position as they are; see <a href="cWorld.html">API docs</a> for further details of this function
Player:GetWorld():DoExplosionAt(Explodee:GetPosX(), Explodee:GetPosY(), Explodee:GetPosZ(), false, esPlugin)
SendMessageSuccess(Player, Split[2] .. " was successfully exploded")
Player:SendMessageSuccess(Split[2] .. " was successfully exploded")
HasExploded = true;
return true -- Signalize to MCS that we do not need to call this callback for any more players
end
@ -224,7 +224,7 @@ function Explode(Split, Player)
if not(HasExploded) then
-- We have not broken out so far, therefore, the player must not exist, send failure
SendMessageFailure(Player, Split[2] .. " was not found")
Player:SendMessageFailure(Split[2] .. " was not found")
end
return true

@ -0,0 +1 @@
Subproject commit 983d23ca37baa89f7e4dc11d71502d9c059f6376

View File

@ -1,31 +0,0 @@
-- plugin.lua
-- Implements the main entrypoint for the plugin, as well as all the handling needed
-- ChatLog plugin logs all chat messages into the server log
function Initialize(Plugin)
Plugin:SetName("ChatLog")
Plugin:SetVersion(3)
cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChat)
LOG("Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
return true
end
function OnChat(Player, Message)
-- Lets get loggin'
LOGINFO("[" .. Player:GetName() .. "]: " .. StripColorCodes(Message));
return false
end

@ -0,0 +1 @@
Subproject commit 894c7e32049e9d2a1e736f7d721aaacd1ae29e53

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<project>
<file>
<filename>chunkworx_main.lua</filename>
</file>
<file>
<filename>chunkworx_web.lua</filename>
</file>
</project>

View File

@ -1,128 +0,0 @@
-- Global variables
PLUGIN = {} -- Reference to own plugin object
GENERATION_STATE = 0
OPERATION_CODE = 0 -- 0 = generation
CX = 0
CZ = 0
CURRENT = 0
TOTAL = 0
-- AREA Variables
AreaStartX = -10
AreaStartZ = -10
AreaEndX = 10
AreaEndZ = 10
-- RADIAL Variables
RadialX = 0
RadialZ = 0
Radius = 10
-- WORLD
WORK_WORLD = cRoot:Get():GetDefaultWorld():GetName()
WW_instance = cRoot:Get():GetDefaultWorld()
WORLDS = {}
function Initialize(Plugin)
PLUGIN = Plugin
PLUGIN:SetName("ChunkWorx")
PLUGIN:SetVersion(6)
cPluginManager.AddHook(cPluginManager.HOOK_TICK, OnTick)
Plugin:AddWebTab("(Re)Generation", HandleRequest_Generation)
GENERATION_STATE = 0
WW_instance = cRoot:Get():GetWorld(WORK_WORLD)
if (WW_instance == nil) then
LOG("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. ": NO WORLD found :(")
end
-- Read the stored values:
local SettingsIni = cIniFile();
SettingsIni:ReadFile("ChunkWorx.ini"); -- ignore any read errors
AreaStartX = SettingsIni:GetValueSetI("Area data", "StartX", AreaStartX)
AreaStartZ = SettingsIni:GetValueSetI("Area data", "StartZ", AreaStartZ)
AreaEndX = SettingsIni:GetValueSetI("Area data", "EndX", AreaEndX)
AreaEndZ = SettingsIni:GetValueSetI("Area data", "EndZ", AreaEndZ)
RadialX = SettingsIni:GetValueSetI("Radial data", "RadialX", RadialX)
RadialZ = SettingsIni:GetValueSetI("Radial data", "RadialZ", RadialZ)
Radius = SettingsIni:GetValueSetI("Radial data", "Radius", Radius)
SettingsIni:WriteFile("ChunkWorx.ini");
LOG("Initialized " .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion())
return true
end
function OnTick( DeltaTime )
if (GENERATION_STATE == 1 or GENERATION_STATE == 3) then
LOGINFO("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. ": works STARTED!")
LOGINFO("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. ": At world: " .. WORK_WORLD)
WW_instance = cRoot:Get():GetWorld(WORK_WORLD)
if (GENERATION_STATE == 1) then GENERATION_STATE = 2 end
if (GENERATION_STATE == 3) then GENERATION_STATE = 4 end
-- Changing in case coordinates are flipped
local shifter = AreaEndX
if (AreaStartX > AreaEndX) then
AreaEndX = AreaStartX
AreaStartX = shifter
end
shifter = AreaEndZ
if (AreaStartZ > AreaEndZ) then
AreaEndZ = AreaStartZ
AreaStartZ = shifter
end
CX = AreaStartX
CZ = AreaStartZ
CURRENT = 0
if (WW_instance == nil) then
LOGERROR("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. ": works ABORTED")
LOGERROR("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. ": NO WORLD found :(")
GENERATION_STATE = 0
end
end
if (GENERATION_STATE == 2 or GENERATION_STATE == 4) then
if (WW_instance:GetGeneratorQueueLength() < 200
and WW_instance:GetLightingQueueLength() < 200
and (WW_instance:GetStorageSaveQueueLength() + WW_instance:GetStorageLoadQueueLength()) < 80) then
local chunk_sum = (1+ AreaEndX - AreaStartX) * (1+ AreaEndZ - AreaStartZ)
TOTAL = chunk_sum
LOG("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. ": PROCESSING 100 chunks, (" .. CURRENT .. "/" .. chunk_sum .. ")")
for C = 1, 100 do
if (GENERATION_STATE == 2) then WW_instance:GenerateChunk(CX, CZ) end
if (GENERATION_STATE == 4) then WW_instance:RegenerateChunk(CX, CZ) end
CX = CX + 1
CURRENT = CURRENT + 1
if (CX > AreaEndX) then
CX = AreaStartX
CZ = CZ + 1
if (CZ > AreaEndZ) then
if (GENERATION_STATE == 2) then LOGINFO("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. " - generation ENDED!") end
if (GENERATION_STATE == 4) then LOGINFO("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. " - REgeneration ENDED!") end
GENERATION_STATE = 0
break
end
end
end
WW_instance:QueueSaveAllChunks()
WW_instance:QueueUnloadUnusedChunks()
end
end
end

View File

@ -1,274 +0,0 @@
-- chunkworx_web.lua
-- WebAdmin-related functions
local function Buttons_Player( Name )
return "<form method='POST'><input type='hidden' name='PlayerName' value='"..Name.."'><input type='submit' name='PlayerExact' value='Exact'><input type='submit' name='Player3x3' value='3x3'></form>"
end
local function Button_World( Name )
return "<form method='POST'><input type='hidden' name='WorldName' value='"..Name.."'><input type='submit' name='SelectWorld' value='Select'></form>"
end
local function SaveSettings()
local SettingsIni = cIniFile()
SettingsIni:SetValueI("Area data", "StartX", AreaStartX)
SettingsIni:SetValueI("Area data", "StartZ", AreaStartZ)
SettingsIni:SetValueI("Area data", "EndX", AreaEndX)
SettingsIni:SetValueI("Area data", "EndZ", AreaEndZ)
SettingsIni:SetValueI("Radial data", "RadialX", RadialX)
SettingsIni:SetValueI("Radial data", "RadialZ", RadialZ)
SettingsIni:SetValueI("Radial data", "Radius", Radius)
SettingsIni:WriteFile("ChunkWorx.ini")
end
function HandleRequest_Generation( Request )
local Content = ""
if (Request.PostParams["AGHRRRR"] ~= nil) then
GENERATION_STATE = 0
WW_instance:QueueSaveAllChunks()
WW_instance:QueueUnloadUnusedChunks()
LOGERROR("" .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. ": works ABORTED by admin")
end
--Content = Content .. "<head><meta http-equiv=\"refresh\" content=\"2;\"></head>"
-- PROCESSING
--------------------------------------------------------------------------------------------------
local function ProcessingContent()
local _small_content = ""
_small_content = _small_content .. "<head><meta http-equiv=\"refresh\" content=\"2;\"></head>"
_small_content = _small_content .. "<h4>World for operations:</h4>"..WORK_WORLD
if (OPERATION_CODE == 0) then
_small_content = _small_content .. "<h4>Operation:</h4>Generation"
elseif (OPERATION_CODE == 1) then
_small_content = _small_content .. "<h4>Operation:</h4>Regeneration"
end
_small_content = _small_content .. "<h4>Area: </h4>["..AreaStartX..":"..AreaStartZ.."] ["..AreaEndX..":"..AreaEndZ.."]"
_small_content = _small_content .. "<h4>Progress:</h4>"..CURRENT.."/"..TOTAL
_small_content = _small_content .. "<br>"
_small_content = _small_content .. "<form method='POST'>"
_small_content = _small_content .. "<input type='submit' name='AGHRRRR' value='Stop'>"
_small_content = _small_content .. "</form>"
return _small_content
end
if (GENERATION_STATE == 2 or GENERATION_STATE == 4) then
Content = ProcessingContent()
return Content
end
-- SELECTING
--------------------------------------------------------------------------------------------------
if ( Request.PostParams["FormSetWorld"] ) then
WORK_WORLD = Request.PostParams["FormWorldName"]
WW_instance = cRoot:Get():GetWorld(WORK_WORLD)
end
if( Request.PostParams["SelectWorld"] ~= nil
and Request.PostParams["WorldName"] ~= nil ) then -- World is selected!
WORK_WORLD = Request.PostParams["WorldName"]
WW_instance = cRoot:Get():GetWorld(WORK_WORLD)
end
if(Request.PostParams["OperationGenerate"] ~= nil) then
OPERATION_CODE = 0
end
if(Request.PostParams["OperationReGenerate"] ~= nil) then
OPERATION_CODE = 1
end
if (GENERATION_STATE == 0) then
if( Request.PostParams["FormAreaStartX"] ~= nil
and Request.PostParams["FormAreaStartZ"] ~= nil
and Request.PostParams["FormAreaEndX"] ~= nil
and Request.PostParams["FormAreaEndZ"] ~= nil ) then --(Re)Generation valid!
-- COMMON (Re)gen
if( Request.PostParams["StartArea"]) then
AreaStartX = tonumber(Request.PostParams["FormAreaStartX"])
AreaStartZ = tonumber(Request.PostParams["FormAreaStartZ"])
AreaEndX = tonumber(Request.PostParams["FormAreaEndX"])
AreaEndZ = tonumber(Request.PostParams["FormAreaEndZ"])
SaveSettings();
if (OPERATION_CODE == 0) then
GENERATION_STATE = 1
elseif (OPERATION_CODE == 1) then
GENERATION_STATE = 3
end
Content = ProcessingContent()
return Content
end
end
if( Request.PostParams["FormRadialX"] ~= nil
and Request.PostParams["FormRadialZ"] ~= nil
and Request.PostParams["FormRadius"] ~= nil ) then --(Re)Generation valid!
-- COMMON (Re)gen
if( Request.PostParams["StartRadial"]) then
RadialX = tonumber(Request.PostParams["FormRadialX"]) or 0
RadialZ = tonumber(Request.PostParams["FormRadialZ"]) or 0
Radius = tonumber(Request.PostParams["FormRadius"]) or 10
AreaStartX = RadialX - Radius
AreaStartZ = RadialZ - Radius
AreaEndX = RadialX + Radius
AreaEndZ = RadialZ + Radius
SaveSettings()
if (OPERATION_CODE == 0) then
GENERATION_STATE = 1
elseif (OPERATION_CODE == 1) then
GENERATION_STATE = 3
end
Content = ProcessingContent()
return Content
end
end
-- POINT REGEN!
if( Request.PostParams["FormPointX"] ~= nil
and Request.PostParams["FormPointZ"] ~= nil ) then --ReGeneration valid!
-- EXACT
if ( Request.PostParams["PointExact"] ~= nil) then
AreaStartX = tonumber(Request.PostParams["FormPointX"])
AreaStartZ = tonumber(Request.PostParams["FormPointZ"])
AreaEndX = AreaStartX
AreaEndZ = AreaStartZ
GENERATION_STATE = 3
Content = ProcessingContent()
return Content
end
-- 3x3
if ( Request.PostParams["Point3x3"] ~= nil) then
AreaStartX = tonumber(Request.PostParams["FormPointX"]) - 1
AreaStartZ = tonumber(Request.PostParams["FormPointZ"]) - 1
AreaEndX = AreaStartX + 2
AreaEndZ = AreaStartZ + 2
GENERATION_STATE = 3
Content = ProcessingContent()
return Content
end
end
local GetAreaByPlayer = function(Player)
-- Player is valid only within this function, it cannot be stord and used later!
AreaStartX = Player:GetChunkX()
AreaStartZ = Player:GetChunkZ()
end
-- PLAYERS REGEN!
if( Request.PostParams["PlayerExact"] ~= nil
and Request.PostParams["PlayerName"] ~= nil ) then -- Making BOOM! I meant, regenereate...
cRoot:Get():GetWorld(WORK_WORLD):DoWithPlayer(Request.PostParams["PlayerName"],GetAreaByPlayer)
AreaEndX = AreaStartX
AreaEndZ = AreaStartZ
GENERATION_STATE = 3
Content = ProcessingContent()
return Content
end
if( Request.PostParams["Player3x3"] ~= nil
and Request.PostParams["PlayerName"] ~= nil ) then -- Making BOOM! I meant, regenereate...
cRoot:Get():GetWorld(WORK_WORLD):DoWithPlayer(Request.PostParams["PlayerName"],GetAreaByPlayer)
AreaStartX = AreaStartX - 1
AreaStartZ = AreaStartZ - 1
AreaEndX = AreaStartX + 2
AreaEndZ = AreaStartZ + 2
GENERATION_STATE = 3
Content = ProcessingContent()
return Content
end
end
--Content = Content .. "<h4>World for operations: " .. WORK_WORLD .. "</h4>"
--Content = Content .. "<form method='POST'>"
--Content = Content .. "<input type='text' name='FormWorldName' value='Input world name here'><input type='submit' name='FormSetWorld' value='Set world'>"
--Content = Content .. "</form>"
-- SELECTING WORK_WORLD
Content = Content .. "<h4>World for operations: " .. WORK_WORLD .. "</h4>"
Content = Content .. "<table>"
local WorldNum = 0
local AddWorldToTable = function(World)
WorldNum = WorldNum + 1
Content = Content .. "<tr>"
Content = Content .. "<td style='width: 10px;'>" .. WorldNum .. ".</td>"
Content = Content .. "<td>" .. World:GetName() .. "</td>"
Content = Content .. "<td>" .. Button_World(World:GetName()) .. "</td>"
Content = Content .. "</tr>"
end
cRoot:Get():ForEachWorld(AddWorldToTable)
if( WorldNum == 0 ) then
Content = Content .. "<tr><td>No worlds! O_O</td></tr>"
end
Content = Content .. "</table>"
Content = Content .. "<br>"
-- SELECTING OPERATION
if (OPERATION_CODE == 0) then
Content = Content .. "<h4>Operation: Generation</h4>"
elseif (OPERATION_CODE == 1) then
Content = Content .. "<h4>Operation: Regeneration</h4>"
end
Content = Content .. "<form method='POST'>"
Content = Content .. "<input type='submit' name='OperationGenerate' value='Generation'>"
Content = Content .. "<input type='submit' name='OperationReGenerate' value='Regeneration'>"
Content = Content .. "</form>"
-- SELECTING AREA
Content = Content .. "<h4>Area: </h4>Start X, Start Z; End X, End Z"
Content = Content .. "<form method='POST'>"
Content = Content .. "<input type='text' name='FormAreaStartX' value='" .. AreaStartX .. "'><input type='text' name='FormAreaStartZ' value='" .. AreaStartZ .. "'>"
Content = Content .. "<input type='text' name='FormAreaEndX' value='" .. AreaEndX .. "'><input type='text' name='FormAreaEndZ' value='" .. AreaEndZ .. "'>"
Content = Content .. "<input type='submit' name='StartArea' value='Start'>"
Content = Content .. "</form>"
-- SELECTING RADIAL
Content = Content .. "<h4>Radial: </h4>Center X, Center Z, Radius"
Content = Content .. "<form method='POST'>"
Content = Content .. "<input type='text' name='FormRadialX' value='" .. RadialX .. "'><input type='text' name='FormRadialZ' value='" .. RadialZ .. "'><input type='text' name='FormRadius' value='" .. Radius .. "'>"
Content = Content .. "<input type='submit' name='StartRadial' value='Start'>"
Content = Content .. "</form>"
Content = Content .. "<br>"
Content = Content .. "<br>"
Content = Content .. "<br>"
-- SELECTING POINT
Content = Content .. "<h4>Point regeneration:</h4> X, Z"
Content = Content .. "<form method='POST'>"
Content = Content .. "<input type='text' name='FormPointX' value='0'><input type='text' name='FormPointZ' value='0'>"
Content = Content .. "<input type='submit' name='PointExact' value='Exact'>"
Content = Content .. "<input type='submit' name='Point3x3' value='3x3'>"
Content = Content .. "</form>"
-- SELECTING PLAYERS
Content = Content .. "<h4>Player-based regeneration:</h4>"
Content = Content .. "<table>"
local PlayerNum = 0
local AddPlayerToTable = function( Player )
PlayerNum = PlayerNum + 1
Content = Content .. "<tr>"
Content = Content .. "<td style='width: 10px;'>" .. PlayerNum .. ".</td>"
Content = Content .. "<td>" .. Player:GetName() .. "</td>"
Content = Content .. "<td>" .. Buttons_Player(Player:GetName()) .. "</td>"
Content = Content .. "</tr>"
end
if (cRoot:Get():GetWorld(WORK_WORLD) == nil) then
Content = Content .. "<tr><td>Incorrect world selection</td></tr>"
else
cRoot:Get():GetWorld(WORK_WORLD):ForEachPlayer( AddPlayerToTable )
if( PlayerNum == 0 ) then
Content = Content .. "<tr><td>No connected players</td></tr>"
end
end
Content = Content .. "</table>"
Content = Content .. "<br>"
return Content
end

View File

@ -33,10 +33,12 @@ function Initialize(Plugin)
PM:AddHook(cPluginManager.HOOK_PROJECTILE_HIT_BLOCK, OnProjectileHitBlock);
PM:AddHook(cPluginManager.HOOK_CHUNK_UNLOADING, OnChunkUnloading);
PM:AddHook(cPluginManager.HOOK_WORLD_STARTED, OnWorldStarted);
PM:AddHook(cPluginManager.HOOK_PROJECTILE_HIT_BLOCK, OnProjectileHitBlock);
-- _X: Disabled so that the normal operation doesn't interfere with anything
-- PM:AddHook(cPluginManager.HOOK_CHUNK_GENERATED, OnChunkGenerated);
PM:BindCommand("/nick", "debuggers", HandleNickCmd, "- Gives you a custom name");
PM:BindCommand("/le", "debuggers", HandleListEntitiesCmd, "- Shows a list of all the loaded entities");
PM:BindCommand("/ke", "debuggers", HandleKillEntitiesCmd, "- Kills all the loaded entities");
PM:BindCommand("/wool", "debuggers", HandleWoolCmd, "- Sets all your armor to blue wool");
@ -64,6 +66,8 @@ function Initialize(Plugin)
PM:BindCommand("/sb", "debuggers", HandleSetBiome, "- Sets the biome around you to the specified one");
PM:BindCommand("/wesel", "debuggers", HandleWESel, "- Expands the current WE selection by 1 block in X/Z");
PM:BindCommand("/rmitem", "debuggers", HandleRMItem, "- Remove the specified item from the inventory.");
PM:BindCommand("/pickups", "debuggers", HandlePickups, "- Spawns random pickups around you");
PM:BindCommand("/poof", "debuggers", HandlePoof, "- Nudges pickups close to you away from you");
Plugin:AddWebTab("Debuggers", HandleRequest_Debuggers)
Plugin:AddWebTab("StressTest", HandleRequest_StressTest)
@ -80,6 +84,8 @@ function Initialize(Plugin)
TestBlockAreasString()
TestStringBase64()
-- TestUUIDFromName()
-- TestRankMgr()
--[[
-- Test cCompositeChat usage in console-logging:
@ -275,6 +281,94 @@ end
function TestUUIDFromName()
LOG("Testing UUID-from-Name resolution...")
-- Test by querying a few existing names, along with a non-existent one:
local PlayerNames =
{
"xoft",
"aloe_vera",
"nonexistent_player",
}
-- WARNING: Blocking operation! DO NOT USE IN TICK THREAD!
local UUIDs = cMojangAPI:GetUUIDsFromPlayerNames(PlayerNames)
-- Log the results:
for _, name in ipairs(PlayerNames) do
local UUID = UUIDs[name]
if (UUID == nil) then
LOG(" UUID(" .. name .. ") not found.")
else
LOG(" UUID(" .. name .. ") = \"" .. UUID .. "\"")
end
end
-- Test once more with the same players, valid-only. This should go directly from cache, so fast.
LOG("Testing again with the same valid players...")
local ValidPlayerNames =
{
"xoft",
"aloe_vera",
}
UUIDs = cMojangAPI:GetUUIDsFromPlayerNames(ValidPlayerNames);
-- Log the results:
for _, name in ipairs(ValidPlayerNames) do
local UUID = UUIDs[name]
if (UUID == nil) then
LOG(" UUID(" .. name .. ") not found.")
else
LOG(" UUID(" .. name .. ") = \"" .. UUID .. "\"")
end
end
-- Test yet again, cache-only:
LOG("Testing once more, cache only...")
local PlayerNames3 =
{
"xoft",
"aloe_vera",
"notch", -- Valid player name, but not cached (most likely :)
}
UUIDs = cMojangAPI:GetUUIDsFromPlayerNames(PlayerNames3, true)
-- Log the results:
for _, name in ipairs(PlayerNames3) do
local UUID = UUIDs[name]
if (UUID == nil) then
LOG(" UUID(" .. name .. ") not found.")
else
LOG(" UUID(" .. name .. ") = \"" .. UUID .. "\"")
end
end
LOG("UUID-from-Name resolution tests finished.")
LOG("Performing a Name-from-UUID test...")
-- local NameToTest = "aloe_vera"
local NameToTest = "xoft"
local Name = cMojangAPI:GetPlayerNameFromUUID(UUIDs[NameToTest])
LOG("Name(" .. UUIDs[NameToTest] .. ") = '" .. Name .. "', expected '" .. NameToTest .. "'.")
LOG("Name-from-UUID test finished.")
end
function TestRankMgr()
LOG("Testing the rank manager")
cRankManager:AddRank("LuaRank")
cRankManager:AddGroup("LuaTestGroup")
cRankManager:AddGroupToRank("LuaTestGroup", "LuaRank")
cRankManager:AddPermissionToGroup("luaperm", "LuaTestGroup")
end
function TestSQLiteBindings()
LOG("Testing SQLite bindings...");
@ -677,6 +771,21 @@ end
function HandleNickCmd(Split, Player)
if (Split[2] == nil) then
Player:SendMessage("Usage: /nick [CustomName]");
return true;
end
Player:SetCustomName(Split[2]);
Player:SendMessageSuccess("Custom name setted to " .. Player:GetCustomName() .. "!")
return true
end
function HandleListEntitiesCmd(Split, Player)
local NumEntities = 0;
@ -1409,7 +1518,7 @@ function OnPlayerJoined(a_Player)
-- Test composite chat chaining:
a_Player:SendMessage(cCompositeChat()
:AddTextPart("Hello, ")
:AddUrlPart(a_Player:GetName(), "www.mc-server.org", "u@2")
:AddUrlPart(a_Player:GetName(), "http://www.mc-server.org", "u@2")
:AddSuggestCommandPart(", and welcome.", "/help", "u")
:AddRunCommandPart(" SetDay", "/time set 0")
)
@ -1455,3 +1564,69 @@ end
function OnProjectileHitBlock(a_ProjectileEntity, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockHitPos)
-- This simple test is for testing issue #1326 - simply declaring this hook would crash the server upon call
LOG("Projectile hit block")
LOG(" Projectile EntityID: " .. a_ProjectileEntity:GetUniqueID())
LOG(" Block: {" .. a_BlockX .. ", " .. a_BlockY .. ", " .. a_BlockZ .. "}, face " .. a_BlockFace)
LOG(" HitPos: {" .. a_BlockHitPos.x .. ", " .. a_BlockHitPos.y .. ", " .. a_BlockHitPos.z .. "}")
end
local PossibleItems =
{
cItem(E_ITEM_DIAMOND),
cItem(E_ITEM_GOLD),
cItem(E_ITEM_IRON),
cItem(E_ITEM_DYE, 1, E_META_DYE_BLUE), -- Lapis lazuli
cItem(E_ITEM_COAL),
}
function HandlePickups(a_Split, a_Player)
local PlayerX = a_Player:GetPosX()
local PlayerY = a_Player:GetPosY()
local PlayerZ = a_Player:GetPosZ()
local World = a_Player:GetWorld()
local Range = 12
for x = 0, Range do for z = 0, Range do
local px = PlayerX + x - Range / 2
local pz = PlayerZ + z - Range / 2
local Items = cItems()
Items:Add(PossibleItems[math.random(#PossibleItems)])
World:SpawnItemPickups(Items, px, PlayerY, pz, 0)
end end -- for z, for x
return true
end
function HandlePoof(a_Split, a_Player)
local PlayerPos = Vector3d(a_Player:GetPosition()) -- Create a copy of the position
PlayerPos.y = PlayerPos.y - 1
local Box = cBoundingBox(PlayerPos, 4, 2)
local NumEntities = 0
a_Player:GetWorld():ForEachEntityInBox(Box,
function (a_Entity)
if not(a_Entity:IsPlayer()) then
local AddSpeed = a_Entity:GetPosition() - PlayerPos -- Speed away from the player
a_Entity:AddSpeed(AddSpeed * 32 / (AddSpeed:SqrLength() + 1)) -- The further away, the less speed to add
NumEntities = NumEntities + 1
end
end
)
a_Player:SendMessage("Poof! (" .. NumEntities .. " entities)")
return true
end

@ -0,0 +1 @@
Subproject commit e64a04be39ac7790abcb09de3d4c7d8fc2a2a1e2

View File

@ -1,28 +0,0 @@
-- Global variables
PLUGIN = {} -- Reference to own plugin object
CHEST_WIDTH = 9
HANDY_VERSION = 2
--[[
Handy is a plugin for other plugins. It contain no commands, no hooks, but functions to ease plugins developers' life.
API:
TODO:
1. GetChestSlot wrapper, so it will detect double chest neighbour chest and will be able to access it.
]]
function Initialize(Plugin)
PLUGIN = Plugin
PLUGIN:SetName("Handy")
PLUGIN:SetVersion(HANDY_VERSION)
PluginManager = cRoot:Get():GetPluginManager()
LOG("Initialized " .. PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion())
return true
end
function OnDisable()
LOG(PLUGIN:GetName() .. " v" .. PLUGIN:GetVersion() .. " is shutting down...")
end

View File

@ -1,216 +0,0 @@
--[[
General stuff
]]
-- Returns Handy plugin version number
function GetHandyVersion()
return HANDY_VERSION
end
-- Checks if handy is in proper version
function CheckForRequiredVersion( inVersion )
if( inVersion > HANDY_VERSION ) then return false end
return true
end
--[[
MCS-specific _functions and nasty hacks :D
]]
function GetChestHeightCheat( inChest )
local chestGrid = inChest:GetContents()
LOGINFO( "This function serves no purpose now! You should consider chest:GetContents():GetHeight() now!" )
LOGINFO( "Also, you might find Handy's new 'IsChestDouble()' useful for your case" )
return chestGrid:GetHeight()
end
function IsChestDouble( inChest )
local chestHeight = inChest:GetContents():GetHeight()
if( chestHeight == 3 ) then
return false
end
return true
end
-- Those two checks how many items of given inItemID chest and player have, and how much they could fit inside them
function ReadChestForItem( inChest, inItemID )
return ReadGridForItems( inChest:GetContents(), inItemID )
end
function ReadPlayerForItem( inPlayer, inItemID )
local inventoryFound, inventoryFree = ReadGridForItems( inPlayer:GetInventory():GetInventoryGrid(), inItemID )
local hotbarFound, hotbarFree = ReadGridForItems( inPlayer:GetInventory():GetHotbarGrid(), inItemID )
local itemsFound = inventoryFound + hotbarFound
local freeSpace = inventoryFree + hotbarFree
return itemsFound, freeSpace
end
-- Following functions are for chest-related operations
-- BEWARE! Those assume you did checked if chest has items/space in it!
function ReadGridForItems( inGrid, inItemID )
local itemsFound = 0
local freeSpace = 0
local slotsCount = inGrid:GetNumSlots()
local testerItem = cItem( inItemID )
local maxStackSize = testerItem:GetMaxStackSize()
for index = 0, (slotsCount - 1) do
slotItem = inGrid:GetSlot( index )
if( slotItem:IsEmpty() ) then
freeSpace = freeSpace + maxStackSize
else
if( slotItem:IsStackableWith( testerItem ) ) then
itemsFound = itemsFound + slotItem.m_ItemCount
freeSpace = maxStackSize - slotItem.m_ItemCount
end
end
end
return itemsFound, freeSpace
end
function TakeItemsFromGrid( inGrid, inItem )
local slotsCount = inGrid:GetNumSlots()
local removedItem = cItem( inItem )
for index = 0, (slotsCount - 1) do
slotItem = inGrid:GetSlot( index )
if( slotItem:IsSameType( removedItem ) ) then
if( slotItem.m_ItemCount <= removedItem.m_ItemCount ) then
removedItem.m_ItemCount = removedItem.m_ItemCount - slotItem.m_ItemCount
inGrid:EmptySlot( index )
else
removedItem.m_ItemCount = slotItem.m_ItemCount - removedItem.m_ItemCount
inGrid:SetSlot( index, removedItem )
removedItem.m_ItemCount = 0
end
if( removedItem.m_ItemCount <= 0 ) then break end
end
end
return removedItem.m_ItemCount
end
--------------
function TakeItemsFromChest( inChest, inItemID, inAmount ) -- MIGHT BE UNSAFE! CHECK FOR ITEMS FIRST!!
local chestGrid = inChest:GetContents()
local removedItem = cItem( inItemID, inAmount )
TakeItemsFromGrid( chestGrid, removedItem )
end
function PutItemsToChest( inChest, inItemID, inAmount )
local chestGrid = inChest:GetContents()
local addedItem = cItem( inItemID, inAmount )
chestGrid:AddItem( addedItem )
end
-- Similar to chest-related.
function TakeItemsFromPlayer( inPlayer, inItemID, inAmount ) -- MIGHT BE UNSAFE! CHECK FIRST!
local removedItem = cItem( inItemID, inAmount )
local inventoryGrid = inPlayer:GetInventory():GetInventoryGrid()
local hotbarGrid = inPlayer:GetInventory():GetHotbarGrid()
local itemsLeft = TakeItemsFromGrid( inventoryGrid, removedItem )
if( itemsLeft > 0 ) then
removedItem = cItem( inItemID, itemsLeft )
TakeItemsFromGrid( hotbarGrid, removedItem )
end
end
function GiveItemsToPlayer( inPlayer, inItemID, inAmount )
local addedItem = cItem( inItemID, inAmount )
local inventoryGrid = inPlayer:GetInventory():GetInventoryGrid()
local hotbarGrid = inPlayer:GetInventory():GetHotbarGrid()
local itemsAdded = inventoryGrid:AddItem( addedItem )
if( itemsAdded < inAmount ) then
addedItem.m_ItemCount = addedItem.m_ItemCount - itemsAdded
hotbarGrid:AddItem( addedItem )
end
end
-- This function returns item max stack for a given itemID. It uses vanilla max stack size, and uses several non-common items notations;
-- Those are:
-- oneonerecord( because aparently 11record wasn't the best idea in lua scripting application )
-- carrotonastick( because it wasn't added to items.txt yet )
-- waitrecord( for same reason )
-- Feel free to ignore the difference, or to add those to items.txt
function GetItemMaxStack( inItemID )
local testerItem = cItem( inItemID )
LOGINFO( "This function serves no real purpose now, maybe consider using cItem:GetMaxStackSize()?" )
return testerItem:GetMaxStackSize()
end
function ItemIsArmor( inItemID, inCheckForHorseArmor )
inCheckForHorseArmor = inCheckForHorseArmor or false
if( inItemID == E_ITEM_LEATHER_CAP ) then return true end
if( inItemID == E_ITEM_LEATHER_TUNIC ) then return true end
if( inItemID == E_ITEM_LEATHER_PANTS ) then return true end
if( inItemID == E_ITEM_LEATHER_BOOTS ) then return true end
if( inItemID == E_ITEM_CHAIN_HELMET ) then return true end
if( inItemID == E_ITEM_CHAIN_CHESTPLATE ) then return true end
if( inItemID == E_ITEM_CHAIN_LEGGINGS ) then return true end
if( inItemID == E_ITEM_CHAIN_BOOTS ) then return true end
if( inItemID == E_ITEM_IRON_HELMET ) then return true end
if( inItemID == E_ITEM_IRON_CHESTPLATE ) then return true end
if( inItemID == E_ITEM_IRON_LEGGINGS ) then return true end
if( inItemID == E_ITEM_IRON_BOOTS ) then return true end
if( inItemID == E_ITEM_DIAMOND_HELMET ) then return true end
if( inItemID == E_ITEM_DIAMOND_CHESTPLATE ) then return true end
if( inItemID == E_ITEM_DIAMOND_LEGGINGS ) then return true end
if( inItemID == E_ITEM_DIAMOND_BOOTS ) then return true end
if( inItemID == E_ITEM_GOLD_HELMET ) then return true end
if( inItemID == E_ITEM_GOLD_CHESTPLATE ) then return true end
if( inItemID == E_ITEM_GOLD_LEGGINGS ) then return true end
if( inItemID == E_ITEM_GOLD_BOOTS ) then return true end
if( inCheckForHorseArmor ) then
if( inItemID == E_ITEM_IRON_HORSE_ARMOR ) then return true end
if( inItemID == E_ITEM_GOLD_HORSE_ARMOR ) then return true end
if( inItemID == E_ITEM_DIAMOND_HORSE_ARMOR ) then return true end
end
return false
end
-- Returns full-length playername for a short name( usefull for parsing commands )
function GetExactPlayername( inPlayerName )
local _result = inPlayerName
local function SetProcessingPlayername( inPlayer )
_result = inPlayer:GetName()
end
cRoot:Get():FindAndDoWithPlayer( inPlayerName, SetProcessingPlayername )
return _result
end
function GetPlayerByName( inPlayerName )
local _player
local PlayerSetter = function( Player )
_player = Player
end
cRoot:Get():FindAndDoWithPlayer( inPlayerName, PlayerSetter )
return _player
end
--[[
Not-so-usual math _functions
]]
-- Rounds floating point number. Because lua guys think this function doesn't deserve to be presented in lua's math
function round( inX )
if( inX%2 ~= 0.5 ) then
return math.floor( inX + 0.5 )
end
return inX - 0.5
end
--[[
Functions I use for filework and stringswork
]]
function PluralString( inValue, inSingularString, inPluralString )
local _value_string = tostring( inValue )
if( _value_string[#_value_string] == "1" ) then
return inSingularString
end
return inPluralString
end
function PluralItemName( inItemID, inAmount ) -- BEWARE! TEMPORAL SOLUTION THERE! :D
local _value_string = tostring( inValue )
local _name = ""
if( _value_string[#_value_string] == "1" ) then
-- singular names
_name = ItemTypeToString( inItemID )
else
-- plural names
_name = ItemTypeToString( inItemID ).."s"
end
return _name
end
-- for filewriting purposes. 0 = false, 1 = true
function StringToBool( inValue )
if( inValue == "1" ) then return true end
return false
end
-- same, but reversal
function BoolToString( inValue )
if( inValue == true ) then return 1 end
return 0
end

@ -0,0 +1 @@
Subproject commit 493f2dfa6d39f134e37c4c614cf8d6ffd10c825f

View File

@ -1,97 +0,0 @@
-- Location object
cLocation = {}
function cLocation:new( x, y, z )
local object = { x = x, y = y, z = z }
setmetatable(object, { __index = cLocation })
return object
end
-- Offsets
cFibers = { }
function cFibers:new()
local object = {
cLocation:new( 2, -1, 2 ),
cLocation:new( 2, -1, 1 ),
cLocation:new( 2, -1, 0 ),
cLocation:new( 2, -1, -1 ),
cLocation:new( 2, -1, -2 ),
cLocation:new( 1, -1, 2 ),
cLocation:new( 1, -1, 1 ),
cLocation:new( 1, -1, 0 ),
cLocation:new( 1, -1, -1 ),
cLocation:new( 1, -1, -2 ),
cLocation:new( 0, -1, 2 ),
cLocation:new( 0, -1, 1 ),
cLocation:new( 0, -1, 0 ),
cLocation:new( 0, -1, -1 ),
cLocation:new( 0, -1, -2 ),
cLocation:new( -1, -1, 2 ),
cLocation:new( -1, -1, 1 ),
cLocation:new( -1, -1, 0 ),
cLocation:new( -1, -1, -1 ),
cLocation:new( -1, -1, -2 ),
cLocation:new( -2, -1, 2 ),
cLocation:new( -2, -1, 1 ),
cLocation:new( -2, -1, 0 ),
cLocation:new( -2, -1, -1 ),
cLocation:new( -2, -1, -2 ),
imadeit = false,
}
setmetatable(object, { __index = cFibers })
return object;
end
-- Carpet object
cCarpet = {}
function cCarpet:new()
local object = { Location = cLocation:new(0,0,0),
Fibers = cFibers:new(),
}
setmetatable(object, { __index = cCarpet })
return object
end
function cCarpet:remove()
local World = cRoot:Get():GetDefaultWorld()
for i, fib in ipairs( self.Fibers ) do
local x = self.Location.x + fib.x
local y = self.Location.y + fib.y
local z = self.Location.z + fib.z
local BlockID = World:GetBlock( x, y, z )
if( fib.imadeit == true and BlockID == E_BLOCK_GLASS ) then
World:SetBlock( x, y, z, 0, 0 )
fib.imadeit = false
end
end
end
function cCarpet:draw()
local World = cRoot:Get():GetDefaultWorld()
for i, fib in ipairs( self.Fibers ) do
local x = self.Location.x + fib.x
local y = self.Location.y + fib.y
local z = self.Location.z + fib.z
local BlockID = World:GetBlock( x, y, z )
if( BlockID == 0 ) then
fib.imadeit = true
World:SetBlock( x, y, z, E_BLOCK_GLASS, 0 )
else
fib.imadeit = false
end
end
end
function cCarpet:moveTo( NewPos )
local x = math.floor( NewPos.x )
local y = math.floor( NewPos.y )
local z = math.floor( NewPos.z )
if( self.Location.x ~= x or self.Location.y ~= y or self.Location.z ~= z ) then
self:remove()
self.Location = cLocation:new( x, y, z )
self:draw()
end
end
function cCarpet:getY()
return self.Location.y
end

View File

@ -1,81 +0,0 @@
local Carpets = {}
local PLUGIN
function Initialize( Plugin )
Plugin:SetName( "MagicCarpet" )
Plugin:SetVersion( 2 )
cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving)
cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_DESTROYED, OnDisconnect)
local PluginManager = cPluginManager:Get()
PluginManager:BindCommand("/mc", "magiccarpet", HandleCarpetCommand, " - Spawns a magical carpet");
PLUGIN = Plugin
LOG( "Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion() )
return true
end
function OnDisable()
LOG( PLUGIN:GetName() .. " v." .. PLUGIN:GetVersion() .. " is shutting down..." )
for i, Carpet in pairs( Carpets ) do
Carpet:remove()
end
end
function HandleCarpetCommand( Split, Player )
Carpet = Carpets[ Player ]
if( Carpet == nil ) then
Carpets[ Player ] = cCarpet:new()
Player:SendMessageSuccess("You're on a magic carpet!")
Player:SendMessageInfo("Look straight down to descend. Jump to ascend.")
else
Carpet:remove()
Carpets[ Player ] = nil
Player:SendMessageSuccess("The carpet vanished!")
end
return true
end
function OnDisconnect( Reason, Player )
local Carpet = Carpets[ Player ]
if( Carpet ~= nil ) then
Carpet:remove()
end
Carpets[ Player ] = nil
end
function OnPlayerMoving(Player)
local Carpet = Carpets[ Player ]
if( Carpet == nil ) then
return
end
if( Player:GetPitch() == 90 ) then
Carpet:moveTo( cLocation:new( Player:GetPosX(), Player:GetPosY() - 1, Player:GetPosZ() ) )
else
if( Player:GetPosY() < Carpet:getY() ) then
Player:TeleportToCoords(Player:GetPosX(), Carpet:getY() + 0.2, Player:GetPosZ())
end
Carpet:moveTo( cLocation:new( Player:GetPosX(), Player:GetPosY(), Player:GetPosZ() ) )
end
end

@ -1 +1 @@
Subproject commit 9edfee93048f214175cbed7eb2a3f77f7ac4abb2
Subproject commit 7765048fa740b8f119db72a4ccc546504f86b2ab

View File

@ -40,10 +40,12 @@
# 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, *
OakPlanks, 4 = OakLog, *
SprucePlanks, 4 = SpruceLog, *
BirchPlanks, 4 = BirchLog, *
JunglePlanks, 4 = JungleLog, *
AcaciaPlanks, 4 = AcaciaLog, *
DarkOakPlanks, 4 = DarkOakLog, *
Stick, 4 = Planks, 2:2, 2:3
Torch, 4 = Stick, 1:2 | Coal, 1:1
Workbench = Planks, 1:1, 1:2, 2:1, 2:2
@ -65,6 +67,7 @@ DiamondBlock = Diamond, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
LapisBlock = LapisLazuli, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
EmeraldBlock = Emerald, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
RedstoneBlock = RedstoneDust, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
CoalBlock = Coal, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
QuartzBlock = NetherQuartz, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
NetherBrick = netherbrickitem, 1:1, 1:2, 2:1, 2:2
Glowstone = GlowstoneDust, 1:1, 1:2, 2:1, 2:2
@ -74,21 +77,62 @@ PillarQuartzBlock = QuartzSlab, 1:1, 1:2
ChiseledQuartzBlock, 2 = QuartzBlock, 1:1, 1:2
CoalBlock = Coal, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
HayBale = Wheat, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
SnowBlock = SnowBall, 1:1, 1:2, 2:1, 2:2
ClayBlock = Clay, 1:1, 1:2, 2:1, 2:2
BrickBlock = Brick, 1:1, 1:2, 2:1, 2:2
StoneBrick, 4 = Stone, 1:1, 1:2, 2:1, 2:2
BookShelf = Planks, 1:1, 2:1, 3:1, 1:3, 2:3, 3:3 | Book, 1:2, 2:2, 3:2
Sandstone, 4 = Sand, 1:1, 1:2, 2:1, 2:2
SmoothSandstone, 4 = Sandstone, 1:1, 1:2, 2:1, 2:2
OrnamentSandstone = SandstoneSlab, 1:1, 1:2
JackOLantern = Pumpkin, 1:1 | Torch, 1:2
PolishedGranite, 4 = Granite, 1:1, 1:2, 2:1, 2:2
PolishedDiorite, 4 = Diorite, 1:1, 1:2, 2:1, 2:2
PolishedAndesite, 4 = Andesite, 1:1, 1:2, 2:1, 2:2
CoarsedDirt, 4 = Dirt, 1:1, 2:2 | Gravel, 1:2, 2:1
CoarsedDirt, 4 = Gravel, 1:1, 2:2 | Dirt, 1:2, 2:1
SlimeBlock = Slimeball, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
Prismarine = PrismarineShard, 1:1, 1:2, 2:1, 2:2
PrismarineBricks = PrismarineShard, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
DarkPrismarine = PrismarineShard, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Inksac, 2:2
SeaLantern = PrismarineShard, 1:1, 1:3, 3:1, 3:3 | PrismarineCrystals, 1:2, 2:1, 2:2, 2:3, 3:2
RedSandstone, 4 = RedSand, 1:1, 1:2, 2:1, 2:2
ChiseledRedSandstone, 4 = RedSandstoneSlab, 1:1, 1:2
SmoothRedSandstone, 4 = RedSand, 1:1, 1:2, 2:1, 2:2
MossyStoneBrick = Stonebrick, * | Vines, *
Leather = RabbitHide, 1:1, 1:2, 2:1, 2:2
# Slabs:
StoneSlab, 6 = Stone, 1:1, 2:1, 3:1
SandstoneSlab, 6 = Sandstone, 1:1, 2:1, 3:1
WoodSlab, 6 = Planks, 1:1, 2:1, 3:1
SpruceWoodSlab, 6 = SprucePlanks, 1:1, 2:1, 3:1
BirchWoodSlab, 6 = BirchPlanks, 1:1, 2:1, 3:1
JungleWoodSlab, 6 = JunglePlanks, 1:1, 2:1, 3:1
AcaciaWoodSlab, 6 = AcaciaPlanks, 1:1, 2:1, 3:1
DarkOakWoodSlab, 6 = DarkOakPlanks, 1:1, 2:1, 3:1
OakWoodSlab, 6 = OakPlanks, 1:1, 2:1, 3:1
CobblestoneSlab, 6 = Cobblestone, 1:1, 2:1, 3:1
BrickSlab, 6 = BrickBlock, 1:1, 2:1, 3:1
StonebrickSlab, 6 = StoneBrick, 1:1, 2:1, 3:1
NetherbrickSlab, 6 = NetherBrick, 1:1, 2:1, 3:1
Quartzslab, 6 = QuartzBlock, 1:1, 2:1, 3:1
snow, 6 = SnowBlock, 1:1, 2:1, 3:1
RedSandstoneSlab, 6 = RedSandstone, 1:1, 2:1, 3:1
# Stairs:
WoodStairs, 4 = Planks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
WoodStairs, 4 = Planks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
SpruceWoodStairs, 4 = SprucePlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
SpruceWoodStairs, 4 = SprucePlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
BirchWoodStairs, 4 = BirchPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
BirchWoodStairs, 4 = BirchPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
JungleWoodStairs, 4 = JunglePlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
JungleWoodStairs, 4 = JunglePlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
AcaciaWoodStairs, 4 = AcaciaPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
AcaciaWoodStairs, 4 = AcaciaPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
DarkOakWoodStairs, 4 = DarkOakPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
DarkOakWoodStairs, 4 = DarkOakPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
WoodStairs, 4 = OakPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
WoodStairs, 4 = OakPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
cobblestoneStairs, 4 = Cobblestone, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
cobblestoneStairs, 4 = Cobblestone, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
BrickStairs, 4 = BrickBlock, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
@ -101,18 +145,8 @@ quartzstairs, 4 = QuartzBlock, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
quartzstairs, 4 = QuartzBlock, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
StoneBrickStairs, 4 = StoneBrick, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
StoneBrickStairs, 4 = StoneBrick, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
SnowBlock = SnowBall, 1:1, 1:2, 2:1, 2:2
ClayBlock = Clay, 1:1, 1:2, 2:1, 2:2
BrickBlock = Brick, 1:1, 1:2, 2:1, 2:2
StoneBrick, 4 = Stone, 1:1, 1:2, 2:1, 2:2
BookShelf = Planks, 1:1, 2:1, 3:1, 1:3, 2:3, 3:3 | Book, 1:2, 2:2, 3:2
Sandstone, 4 = Sand, 1:1, 1:2, 2:1, 2:2
SmoothSandstone, 4 = Sandstone, 1:1, 1:2, 2:1, 2:2
OrnamentSandstone = SandstoneSlab, 1:1, 1:2
JackOLantern = Pumpkin, 1:1 | Torch, 1:2
# Other
Carpet = Wool, 1:3, 2:3
RedSandstoneStairs, 4 = RedSandstone, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
RedSandstoneStairs, 4 = RedSandstone, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
@ -244,11 +278,19 @@ ActivatorRail, 6 = IronIngot, 1:1, 1:2, 1:3, 3:1, 3:2, 3:3 | Stick, 2:1, 2:3 | R
#******************************************************#
# Mechanisms
#
WoodenDoor = Planks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
IronDoor = IronIngot, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
WoodenDoor, 3 = OakPlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
SpruceDoor, 3 = SprucePlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
BirchDoor, 3 = BirchPlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
JungleDoor, 3 = JunglePlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
AcaciaDoor, 3 = AcaciaPlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
DarkOakDoor, 3 = DarkOakPlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
IronDoor, 3 = IronIngot, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
TrapDoor, 2 = Planks, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
IronTrapDoor = IronIngot, 1:1, 1:2, 2:1, 2:2
WoodPlate = Planks, 1:1, 2:1
StonePlate = Stone, 1:1, 2:1
lightweightedpressureplate = IronIngot, 1:1, 2:1
heavyweightedpressureplate = GoldIngot, 1:1, 2:1
StoneButton = Stone, 1:1
WoodenButton = Planks, 1:1
RedstoneTorchOn = Stick, 1:2 | RedstoneDust, 1:1
@ -286,6 +328,8 @@ MelonSeeds = MelonSlice, *
PumpkinSeeds, 4 = Pumpkin, *
PumpkinPie = Pumpkin, * | Sugar, * | egg, *
Wheat, 9 = Haybale, *
RabbitStew = Cooked Rabbit, 2:1 | Carrot, 1:2 | BakedPotato, 2:2 | BrownMushroom, 3:2 | Bowl, 2:3
RabbitStew = Cooked Rabbit, 2:1 | Carrot, 1:2 | BakedPotato, 2:2 | RedMushroom, 3:2 | Bowl, 2:3
@ -304,27 +348,60 @@ Emerald, 9 = EmeraldBlock, *
RedstoneDust, 9 = RedstoneBlock, *
Coal, 9 = CoalBlock, *
Clay, 4 = ClayBlock, *
SlimeBall, 9 = SlimeBlock, *
Painting = Stick, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Wool, 2:2
ItemFrame = Stick, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Leather, 2:2
Sign = Planks, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2 | Stick, 2:3
Sign, 3 = Planks, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2 | Stick, 2:3
Ladder, 3 = Stick, 1:1, 3:1, 1:2, 2:2, 3:2, 1:3, 3:3
GlassPane, 16 = Glass, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
IronBars, 16 = IronIngot, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
Paper, 3 = Sugarcane, 1:1, 2:1, 3:1
Book = Paper, *, *, * | leather, *
Bookandquill = Book, * | feather, * | inksac, *
Fence, 2 = Stick, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
Fence, 3 = OakPlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
SpruceFence, 3 = SprucePlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
BirchFence, 3 = BirchPlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
JungleFence, 3 = JunglePlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
DarkOakFence, 3 = DarkOakPlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
AcaciaFence, 3 = AcaciaPlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
Cobblestonewall, 6 = cobblestone, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
mossycobblestonewall, 6 = mossycobblestone, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
NetherBrickFence, 6 = NetherBrick, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
FenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | Planks, 2:1, 2:2
FenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | OakPlanks, 2:1, 2:2
SpruceFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | SprucePlanks, 2:1, 2:2
BirchFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | BirchPlanks, 2:1, 2:2
JungleFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | JunglePlanks, 2:1, 2:2
DarkOakFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | DarkOakPlanks, 2:1, 2:2
AcaciaFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | AcaciaPlanks, 2:1, 2:2
Bed = Planks, 1:2, 2:2, 3:2 | Wool, 1:1, 2:1, 3:1
GoldIngot = GoldNugget, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
EyeOfEnder = EnderPearl, * | BlazePowder, *
Beacon = Glass, 1:1, 1:2, 2:1, 3:1, 3:2 | Obsidian, 1:3, 2:3, 3:3 | NetherStar, 2:2
Anvil = IronBlock, 1:1, 2:1, 3:1 | IronIngot, 2:2, 1:3, 2:3, 3:3
FlowerPot = Brick, 1:2, 2:3, 3:2
ArmorStand = Stick, 1:1, 1:3, 2:1, 2:2, 3:1, 3:3 | StoneSlab, 2:3
# These are just the basic ones, you can add various shapes and stuff to each of them
# ToDo: Add the various shapes (saved in NBT-Tags, not in meta)
# Banners:
WhiteBanner = Stick, 2:3 | WhiteWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
OrangeBanner = Stick, 2:3 | OrangeWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
MagentaBanner = Stick, 2:3 | MagentaWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
LightBlueBanner = Stick, 2:3 | LightBlueWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
YellowBanner = Stick, 2:3 | YellowWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
LimeBanner = Stick, 2:3 | LimeWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
PinkBanner = Stick, 2:3 | PinkWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
GrayBanner = Stick, 2:3 | GrayWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
LightGrayBanner = Stick, 2:3 | LightGrayWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
CyanBanner = Stick, 2:3 | CyanWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
PurpleBanner = Stick, 2:3 | PurpleWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
BlueBanner = Stick, 2:3 | BlueWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
BrownBanner = Stick, 2:3 | BrownWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
GreenBanner = Stick, 2:3 | GreenWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
RedBanner = Stick, 2:3 | RedWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
BlackBanner = Stick, 2:3 | BlackWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
@ -373,13 +450,30 @@ PinkWool = Wool, * | PinkDye, *
GrayWool = Wool, * | GrayDye, *
LightGrayWool = Wool, * | LightGrayDye, *
CyanWool = Wool, * | CyanDye, *
VioletWool = Wool, * | VioletDye, *
PurpleWool = Wool, * | PurpleDye, *
BlueWool = Wool, * | BlueDye, *
BrownWool = Wool, * | BrownDye, *
GreenWool = Wool, * | GreenDye, *
RedWool = Wool, * | RedDye, *
BlackWool = Wool, * | BlackDye, *
WhiteCarpet, 3 = WhiteWool, 1:1, 2:1
OrangeCarpet, 3 = OrangeWool, 1:1, 2:1
MagentaCarpet, 3 = MagentaWool, 1:1, 2:1
LightBlueCarpet, 3 = LightBlueWool, 1:1, 2:1
YellowCarpet, 3 = YellowWool, 1:1, 2:1
LimeCarpet, 3 = LimeWool, 1:1, 2:1
PinkCarpet, 3 = PinkWool, 1:1, 2:1
GrayCarpet, 3 = GrayWool, 1:1, 2:1
LightGrayCarpet, 3 = LightGrayWool, 1:1, 2:1
CyanCarpet, 3 = CyanWool, 1:1, 2:1
PurpleCarpet, 3 = PurpleWool, 1:1, 2:1
BlueCarpet, 3 = BlueWool, 1:1, 2:1
BrownCarpet, 3 = BrownWool, 1:1, 2:1
GreenCarpet, 3 = GreenWool, 1:1, 2:1
RedCarpet, 3 = RedWool, 1:1, 2:2
BlackCarpet, 3 = BlackWool, 1:1, 2:1
#******************************************************#
# Stained Glass:
#

View File

@ -10,25 +10,28 @@
# An Item is defined by an Item Type, an amount (and damage)
# The damage is optional, and if not specified it's assumed to be 0
#
# -Cactus Green:
# 351 : 1 ( : 2 )
# ItemType : Amount ( : Damage )
# Cactus Green example:
# 351 : 2 ( , 1 )
# ItemType : Damage ( , Amount )
# or simple use the item name (marked in items.ini):
# CactusGreen ( , 1 )
#
#
# **** Recipe and result ****
#
# 4:1@200=1:1 -> Produces 1 smooth stone from 1 cobblestone in 200 ticks (10 seconds)
# Cobble @ 200 = Stone -> Produces 1 smooth stone from 1 cobblestone in 200 ticks (10 seconds)
#
# 4 : 1 @ 200 = 1 : 1
# ItemType : Amount @ ticks = ItemID : Amount
# Write in full:
# Cobble : 0 , 1 @ 200 = 1 : 1 , 1
# ItemType : Damage , Amount @ ticks = ItemType : Damage , Amount
#
#
# **** Fuel ****
#
# !17:1 = 300 -> 1 Wood burns for 300 ticks (15 s)
#
# ! 17 : 1 = 300
# Fuel ItemType : Amount = ticks
# ! Wood , 1 = 300
# Fuel ItemType , Amount = ticks
#
#******************************************************#
@ -39,20 +42,24 @@
#--------------------------
# Smelting recipes
4:1 @ 200 = 1:1 # 1 Cobblestone -> 1 Rock
15:1 @ 200 = 265:1 # 1 Iron Ore -> 1 Iron Ingot
14:1 @ 200 = 266:1 # 1 Gold Ore -> 1 Gold Ingot
153:1 @ 200 = 406:1 # 1 Quartz Ore -> 1 Quartz
12:1 @ 200 = 20:1 # 1 Sand -> 1 Glass
319:1 @ 200 = 320:1 # 1 Raw Pork -> 1 Cooked Pork
363:1 @ 200 = 364:1 # 1 Raw Beef -> 1 Cooked Beef (steak)
365:1 @ 200 = 366:1 # 1 Raw Chicken -> 1 Cooked Chicken
337:1 @ 200 = 336:1 # 1 Clay -> 1 Clay Brick
82:1 @ 200 = 172:1 # 1 Clay Block -> 1 Hardened Clay
87:1 @ 200 = 405:1 # 1 NetherRack -> 1 NetherBrick
349:1 @ 200 = 350:1 # 1 Raw Fish -> 1 Cooked Fish
17:1 @ 200 = 263:1:1 # 1 Log -> 1 Charcoal
81:1 @ 200 = 351:1:2 # 1 Cactus -> 1 Green Dye
Cobble = Stone
IronOre = IronIngot
GoldOre = GoldIngot
NetherQuartzOre = NetherQuartz
Sand = Glass
Pork = CookedPork
RawBeef = Steak
RawChicken = CookedChicken
Clay = Brick
ClayBlock = HardenedClay
TallGrass = NetherBrickItem
RawFish = CookedFish
Log = CharCoal
Cactus = GreenDye
WetSponge = Sponge
Stonebrick = CrackedStonebrick
RawRabbit = CookedRabbit
RawMutton = CookedMutton
@ -61,31 +68,41 @@
#--------------------------
# Fuels
! 263:1 = 1600 # 1 Coal -> 80 sec
! 263:1:1 = 1600 # 1 Charcoal -> 80 sec
! 126:1 = 15 # 1 Halfslab -> 7.5 sec
! 5:1 = 300 # 1 Planks -> 15 sec
! 280:1 = 100 # 1 Stick -> 5 sec
! 85:1 = 300 # 1 Fence -> 15 sec
! 53:1 = 300 # 1 Wooden Stairs -> 15 sec
! 58:1 = 300 # 1 Crafting Table -> 15 sec
! 47:1 = 300 # 1 Bookshelf -> 15 sec
! 54:1 = 300 # 1 Chest -> 15 sec
! 84:1 = 300 # 1 Jukebox -> 15 sec
! 327:1 = 20000 # 1 Lava Bucket -> 1000 sec
! 17:1 = 300 # 1 Wood -> 15 sec
! 6:1 = 100 # 1 Sapling -> 5 sec
! 173:1 = 16000 # 1 Coal Block -> 800 sec
! 369:1 = 2400 # 1 Blaze Rod -> 120 sec
! 25:1 = 300 # 1 Note Block -> 15 sec
! 151:1 = 300 # 1 Daylight Sensor -> 15 sec
! 107:1 = 300 # 1 Fence Gate -> 15 sec
! 167:1 = 300 # 1 Trapdoor -> 15 sec
! 146:1 = 300 # 1 Trapped Chest -> 15 sec
! 72:1 = 300 # 1 Pressure Plate -> 15 sec
! 270:1 = 200 # 1 Wooden Pickaxe -> 10 sec
! 271:1 = 200 # 1 Wooden Axe -> 10 sec
! 269:1 = 200 # 1 Wooden Shovel -> 10 sec
! 290:1 = 200 # 1 Wooden Hoe -> 10 sec
! 268:1 = 200 # 1 Wooden Sword -> 10 sec
! CharCoal = 1600 # -> 80 sec
! Coal = 1600 # -> 80 sec
! WoodenSlab = 15 # -> 7.5 sec
! Planks = 300 # -> 15 sec
! Stick = 100 # -> 5 sec
! Fence = 300 # -> 15 sec
! SpruceFence = 300 # -> 15 sec
! BirchFence = 300 # -> 15 sec
! JungleFence = 300 # -> 15 sec
! DarkOakFence = 300 # -> 15 sec
! AcaciaFence = 300 # -> 15 sec
! WoodStairs = 300 # -> 15 sec
! Workbench = 300 # -> 15 sec
! Bookshelf = 300 # -> 15 sec
! Chest = 300 # -> 15 sec
! Jukebox = 300 # -> 15 sec
! Lavabucket = 20000 # -> 1000 sec
! Log = 300 # -> 15 sec
! Sapling = 100 # -> 5 sec
! CoalBlock = 16000 # -> 800 sec
! BlazeRod = 2400 # -> 120 sec
! NoteBlock = 300 # -> 15 sec
! DaylightSensor = 300 # -> 15 sec
! FenceGate = 300 # -> 15 sec
! SpruceFenceGate = 300 # -> 15 sec
! BirchFenceGate = 300 # -> 15 sec
! JungleFenceGate = 300 # -> 15 sec
! DarkOakFenceGate = 300 # -> 15 sec
! Trapdoor = 300 # -> 15 sec
! TrappedChest = 300 # -> 15 sec
! WoodPlate = 300 # -> 15 sec
! WoodPickaxe = 200 # -> 10 sec
! WoodAxe = 200 # -> 10 sec
! WoodShovel = 200 # -> 10 sec
! WoodHoe = 200 # -> 10 sec
! WoodSword = 200 # -> 10 sec

View File

@ -1,77 +1,99 @@
[Items]
air=0
rock=1
stone=1
rock=1
granite=1:1
polishedgranite=1:2
diorite=1:3
polisheddiorite=1:4
andesite=1:5
polishedandesite=1:6
grass=2
dirt=3
coarseddirt=3:1
podzol=3:2
cobblestone=4
cobble=4
planks=5
appleplanks=5:0
oakplanks=5:0
appleplanks=5:0
spruceplanks=5:1
coniferplanks=5:1
pineplanks=5:1
spruceplanks=5:1
darkplanks=5:1
birchplanks=5:2
lightplanks=5:2
jungleplanks=5:3
redplanks=5:3
; Obsolete: do not use "wood", as its meaning is not clear - wiki uses log as wood, we use planks as wood.
wood=5
acaciaplanks=5:4
darkoakplanks=5:5
bigoakplanks=5:5
roofedoakplanks=5:5
sapling=6
applesapling=6:0
oaksapling=6:0
applesapling=6:0
sprucesapling=6:1
conifersapling=6:1
pinesapling=6:1
sprucesapling=6:1
darkplanks=6:1
birchsapling=6:2
whitesapling=6:2
junglesapling=6:3
adminium=7
redsapling=6:3
acaciasapling=6:4
darkoaksapling=6:5
bigoaksapling=6:5
roofedoaksapling=6:5
bedrock=7
adminium=7
water=8
flowingwater=8
stationarywater=9
stillwater=9
swater=9
stationarywater=9
lava=10
flowinglava=10
stationarylava=11
stilllava=11
slava=11
stationarylava=11
sand=12
redsand=12:1
gravel=13
goldore=14
ironore=15
coalore=16
tree=17
log=17
applelog=17:0
tree=17
oaklog=17:0
applelog=17:0
sprucelog=17:1
coniferlog=17:1
pinelog=17:1
sprucelog=17:1
darklog=17:1
birchlog=17:2
whitelog=17:2
junglelog=17:3
leaves=18
appleleaves=18:0
oakleaves=18:0
appleleaves=18:0
spruceleaves=18:1
coniferleaves=18:1
pineleaves=18:1
spruceleaves=18:1
darkleaves=18:1
birchleaves=18:2
whiteleaves=18:2
jungleleaves=18:3
sponge=19
wetsponge=19:1
glass=20
lapisore=21
lapisblock=22
dispenser=23
sandstone=24
normalsandstone=24:0
ornamentsandstone=24:1
chiseledsandstone=24:1
decorativesandstone=24:1
ornamentsandstone=24:1
smoothsandstone=24:2
noteblock=25
bedblock=26
@ -86,14 +108,16 @@ deadbush=32
piston=33
pistonextension=34
pistonhead=34
cloth=35
wool=35
cloth=35
whitewool=35:0
orangewool=35:1
magentawool=35:2
lightbluewool=35:3
ltbluewool=35:3
yellowwool=35:4
limewool=35:5
ltbluewool=35:3
lightgreenwool=35:5
ltgreenwool=35:5
pinkwool=35:6
@ -107,11 +131,13 @@ lightgraywool=35:8
lightgreywool=35:8
ltgraywool=35:8
ltgreywool=35:8
silverwool=35:8
cyanwool=35:9
purplewool=35:10
violetwool=35:10
bluewool=35:11
darkbluewool=35:11
dkbluewool=35:11
brownwool=35:12
greenwool=35:13
darkgreenwool=35:13
@ -119,14 +145,12 @@ dkgreenwool=35:13
redwool=35:14
blackwool=35:15
dandelion=37
; Renamed in 1.7, use "poppy" instead; kept for compatibility reasons, will be removed later on.
rose=38
flower=38
poppy=38
rose=38
flower=38
blueorchid=38:1
allium=38:2
azurebluet=38:3
redtulip=38:4
orangetulip=38:5
whitetulip=38:6
@ -134,11 +158,12 @@ pinktulip=38:7
oxeyedaisy=38:8
brownmushroom=39
redmushroom=40
gold=41
goldblock=41
iron=42
gold=41
ironblock=42
iron=42
doubleslab=43
doublestep=43
stonedoubleslab=43:0
sandstonedoubleslab=43:1
wooddoubleslab=43:2
@ -168,18 +193,19 @@ obsidian=49
torch=50
fire=51
mobspawner=52
oakwoodstairs=53
woodstairs=53
chest=54
redstonedust=55
redstonewire=55
redstonedust=55
diamondore=56
diamondblock=57
workbench=58
crop=59
crops=59
soil=60
farmland=60
tilleddirt=60
soil=60
furnace=61
litfurnace=62
signblock=63
@ -191,11 +217,11 @@ track=66
tracks=66
cobblestonestairs=67
stairs=67
signblocktop=68
wallsign=68
signblocktop=68
lever=69
rockplate=70
stoneplate=70
rockplate=70
irondoorblock=71
woodplate=72
redstoneore=73
@ -212,13 +238,13 @@ reedblock=83
jukebox=84
fence=85
pumpkin=86
netherstone=87
netherrack=87
hellrock=87
slowsand=88
netherstone=87
soulsand=88
lightstone=89
slowsand=88
glowstone=89
lightstone=89
portal=90
jackolantern=91
jacko=91
@ -227,22 +253,39 @@ whitestainedglass=95
orangestainedglass=95:1
magentastainedglass=95:2
lightbluestainedglass=95:3
ltbluestainedglass=95:3
yellowstainedglass=95:4
limestainedglass=95:5
lightgreenstainedglass=95:5
ltgreenstainedglass=95:5
pinkstainedglass=95:6
graystainedglass=95:7
greystainedglass=95:7
darkgraystainedglass=95:7
darkgreystainedglass=95:7
dkgraystainedglass=95:7
dkgreystainedglass=95:7
lightgraystainedglass=95:8
lightgreystainedglass=95:8
ltgraystainedglass=95:8
ltgreystainedglass=95:8
silverstainedglass=95:8
cyanstainedglass=95:9
purplestainedglass=95:10
violetstainedglass=95:10
bluestainedglass=95:11
darkbluestainedglass=95:11
dkbluestainedglass=95:11
brownstainedglass=95:12
greenstainedglass=95:13
darkgreenstainedglass=95:13
dkgreenstainedglass=95:13
redstainedglass=95:14
blackstainedglass=95:15
trapdoor=96
silverfishblock=97
stonebricks=98
stonebrick=98
stonebricks=98
mossystonebrick=98:1
crackedstonebrick=98:2
chiseledstonebrick=98:3
@ -272,15 +315,50 @@ endstone=121
dragonegg=122
redstonelamp=123
redstonelampoff=123
litredstonelamp=124
redstonelampon=124
woodendoubleslab=125
oakwooddoubleslab=125:0
appledoublewoodslab=125:0
sprucewooddoubleslab=125:1
coniferwooddoubleslab=125:1
pinewooddoubleslab=125:1
darkwooddoubleslab=125:1
birchwooddoubleslab=125:2
whitewooddoubleslab=125:2
junglewooddoubleslab=125:3
acaciawooddoubleslab=125:4
darkoakwooddoubleslab=125:5
bigoakwooddoubleslab=125:5
roofedwooddoubleslab=125:5
woodenslab=126
oakwoodslab=126:0
applewoodslab=126:0
sprucewoodslab=126:1
coniferwoodslab=126:1
pinewoodslab=126:1
darkwoodslab=126:1
birchwoodslab=126:2
whitewoodslab=126:2
junglewoodslab=126:3
acaciawoodslab=126:4
darkoakwoodslab=126:5
roofedwoodslab=126:5
bigoakwoodslab=126:5
cocoabeans=127
sandstonestairs=128
emeraldore=129
enderchest=130
tripwirehook=131
tripwire=132
emeraldblock=133
sprucewoodstairs=134
coniferwoodstairs=134
pinewoodstairs=134
darkwoodstairs=134
birchwoodstairs=135
whitewoodstairs=135
junglewoodstairs=136
commandblock=137
beacon=138
cobblestonewall=139
@ -292,6 +370,7 @@ woodenbutton=143
skeletonhead=144
witherhead=144:1
zombiehead=144:2
playerhead=144:3
humanhead=144:3
stevehead=144:3
creeperhead=144:4
@ -315,40 +394,162 @@ whitestainedclay=159
orangestainedclay=159:1
magentastainedclay=159:2
lightbluestainedclay=159:3
ltbluestainedclay=159:3
yellowstainedclay=159:4
limestainedclay=159:5
lightgreenstainedclay=159:5
ltgreenstainedclay=159:5
pinkstainedclay=159:6
graystainedclay=159:7
greystainedclay=159:7
darkgraystainedclay=159:7
darkgreystainedclay=159:7
dkgraystainedclay=159:7
dkgreystainedclay=159:7
lightgraystainedclay=159:8
lightgreystainedclay=159:8
ltgraystainedclay=159:8
ltgreystainedclay=159:8
silverstainedclay=159:8
cyanstainedclay=159:9
purplestainedclay=159:10
violetstainedclay=159:10
bluestainedclay=159:11
darkbluestainedclay=159:11
dkbluestainedclay=159:11
brownstainedclay=159:12
greenstainedclay=159:13
darkgreenstainedclay=159:13
dkgreenstainedclay=159:13
redstainedclay=159:14
blackstainedclay=159:15
whitestainedglasspane=160
orangestainedglasspane=160:1
magentastainedglasspane=160:2
lightbluestainedglasspane=160:3
ltbluestainedglasspane=160:3
yellowstainedglasspane=160:4
limestainedglasspane=160:5
lightgreenstainedglasspane=160:5
ltgreenstainedglasspane=160:5
pinkstainedglasspane=160:6
graystainedglasspane=160:7
greystainedglasspane=160:7
darkgraystainedglasspane=160:7
darkgreystainedglasspane=160:7
dkgraystainedglasspane=160:7
dkgreystainedglasspane=160:7
lightgraystainedglasspane=160:8
lightgreystainedglasspane=160:8
ltgraystainedglasspane=160:8
ltgreystainedglasspane=160:8
silverstainedglasspane=160:8
cyanstainedglasspane=160:9
purplestainedglasspane=160:10
violetstainedglasspane=160:10
bluestainedglasspane=160:11
darkbluestainedglasspane=160:11
dkbluestainedglasspane=160:11
brownstainedglasspane=160:12
greenstainedglasspane=160:13
darkgreenstainedglasspane=160:13
dkgreenstainedglasspane=160:13
redstainedglasspane=160:14
blackstainedglasspane=160:15
acaciawood=162
darkoakwood=162:1
acaciawoodenstairs=163
darkoakwoodenstairs=164
newleaves=161
acacialeaves=161:0
darkoakleaves=161:1
bigoakleaves=161:1
roofedoakleaves=161:1
newlog=162
acacialog=162:0
darkoaklog=162:1
bigoaklog=162:1
roofedoaklog=162:1
acaciawoodstairs=163
darkoakwoodstairs=164
bigoakwoodstiars=164
roofedoakwoodstairs=164
slimeblock=165
barrier=166
irontrapdoor=167
prismarine=168
prismarinebricks=168:1
darkprismarine=168:2
sealantern=169
haybale=170
carpet=171
whitecarpet=171:0
orangecarpet=171:1
magentacarpet=171:2
lightbluecarpet=171:3
ltbluecarpet=171:3
yellowcarpet=171:4
limecarpet=171:5
lightgreencarpet=171:5
ltgreencarpet=171:5
pinkcarpet=171:6
graycarpet=171:7
greycarpet=171:7
darkgraycarpet=171:7
darkgreycarpet=171:7
dkgraycarpet=171:7
dkgreycarpet=171:7
lightgraycarpet=171:8
lightgreycarpet=171:8
ltgraycarpet=171:8
ltgreycarpet=171:8
silvercarpet=171:8
cyancarpet=171:9
purplecarpet=171:10
violetcarpet=171:10
bluecarpet=171:11
darkbluecarpet=171:11
dkbluecarpet=171:11
browncarpet=171:12
greencarpet=171:13
darkgreencarpet=171:13
dkgreencarpet=171:13
redcarpet=171:14
blackcarpet=171:15
hardenedclay=172
coalblock=173
packedice=174
doubleplant=175
sunflower=175:0
lilac=175:1
doubletallgrass=175:2
doubletallfern=175:3
rosebush=175:4
peony=175:5
redsandstone=179
chiseledredsandstone=179:1
smoothredsandstone=179:2
redsandstonestairs=180
newstoneslab=182
redsandstoneslab=182:0
sprucefencegate=183
coniferfencegate=183
pinefencegate=183
darkfencegate=183
birchfencegate=184
whitefencegate=184
junglefencegate=185
darkoakfencegate=186
bigoakfencegate=186
roofedoakfencegate=186
acaciafencegate=187
sprucefence=188
coniferfence=188
pinefence=188
darkfence=188
birchfence=189
whitefence=189
junglefence=190
darkoakfence=191
bigoakfence=191
roofedoakfence=191
acaciafence=192
ironshovel=256
ironspade=256
ironpickaxe=257
@ -361,7 +562,6 @@ redapple=260
bow=261
arrow=262
coal=263
coalblock=173
charcoal=263:1
diamond=264
ironingot=265
@ -374,9 +574,9 @@ ironsword=267
woodensword=268
woodsword=268
woodenshovel=269
woodspade=269
woodshovel=269
woodenspade=269
woodspade=269
woodenpickaxe=270
woodpickaxe=270
woodenpick=270
@ -404,8 +604,8 @@ soup=282
goldensword=283
goldsword=283
goldenshovel=284
goldshovel=284
goldenspade=284
goldshovel=284
goldspade=284
goldenpickaxe=285
goldpickaxe=285
@ -416,13 +616,13 @@ goldaxe=286
string=287
feather=288
gunpowder=289
woodhoe=290
woodenhoe=290
woodhoe=290
stonehoe=291
ironhoe=292
diamondhoe=293
goldhoe=294
goldenhoe=294
goldhoe=294
seeds=295
wheat=296
bread=297
@ -451,19 +651,24 @@ goldpants=316
goldenboots=317
goldboots=317
flint=318
porkchop=319
meat=319
pork=319
cookedporkchop=320
cookedmeat=320
cookedpork=320
painting=321
paintings=321
goldenapple=322
goldapple=322
notchapple=322:1
enchantedgoldenapple=322:1
enchantedgoldapple=322:1
sign=323
wooddoor=324
oakdoor=324
appledoor=324
woodendoor=324
wooddoor=324
bucket=325
waterbucket=326
lavabucket=327
@ -477,32 +682,38 @@ leather=334
milkbucket=335
brick=336
clay=337
reed=338
sugarcane=338
reed=338
paper=339
book=340
slimeorb=341
slimeball=341
slimeorb=341
storageminecart=342
poweredminecart=343
egg=344
compass=345
fishingrod=346
watch=347
glowstonedust=348
lightstonedust=348
lightdust=348
glowstonedust=348
glowdust=348
rawfish=349
fish=349
rawfish=349
rawsalmon=349:1
clownfish=349:2
pufferfish=349:3
cookedfish=350
cookedsalmon=350:1
dye=351
inksac=351:0
blackdye=351:0
reddye=351:1
rosered=351:1
greendye=351:2
reddye=351:1
cactusgreen=351:2
greendye=351:2
darkgreendye=351:2
dkgreendye=351:2
cocoabeans=351:3
browndye=351:3
lapislazuli=351:4
@ -512,12 +723,13 @@ dkbluedye=351:4
purpledye=351:5
violetdye=351:5
cyandye=351:6
lightgreydye=351:7
lightgraydye=351:7
ltgreydye=351:7
lightgreydye=351:7
ltgraydye=351:7
greydye=351:8
ltgreydye=351:7
silverdye=351:7
graydye=351:8
greydye=351:8
darkgreydye=351:8
darkgraydye=351:8
dkgreydye=351:8
@ -583,6 +795,7 @@ goldencarrot=396
skeletonhead=397
witherhead=397:1
zombiehead=397:2
playerhead=397:3
stevehead=397:3
creeperhead=397:4
carrotonastick=398
@ -596,13 +809,68 @@ netherbrickitem=405
netherquartz=406
tntminecart=407
hopperminecart=408
prismarineshard=409
prismarinecrystals=410
rawrabbit=411
cookedrabbit=412
rabbitstew=413
rabbitsoup=413
rabbitsfood=414
rabbithide=415
armorstand=416
ironhorsearmor=417
goldhorsearmor=418
diamondhorsearmor=419
lead=420
nametag=421
commandblockminecart=422
rawmutton=423
cookedmutton=424
banner=425
blackbanner=415:0
redbanner=415:1
greenbanner=415:2
darkgreenbanner=415:2
dkgreenbanner=415:2
brownbanner=415:3
bluebanner=415:4
darkbluebanner=415:4
dkbluebanner=415:4
purplebanner=415:5
violetbanner=415:5
cyanbanner=415:6
lightgraybanner=415:7
lightgreybanner=415:7
ltgraybanner=415:7
ltgreybanner=415:7
silverbanner=415:7
graybanner=415:8
greybanner=415:8
darkgraybanner=415:8
darkgreybanner=415:8
dkgraybanner=415:8
dkgreybanner=415:8
pinkbanner=415:9
limebanner=415:10
lightgreenbanner=415:10
ltgreenbanner=415:10
yellowbanner=415:11
lightbluebanner=415:12
ltbluebanner=415:12
magentabanner=415:13
orangebanner=415:14
whitebanner=415:15
sprucedoor=427
coniferdoor=427
pinedoor=427
darkdoor=427
birchdoor=428
whitedoor=428
jungledoor=429
acaciadoor=430
darkoakdoor=431
bigoakdoor=431
roofedoakdoor=431
goldrecord=2256
greenrecord=2257
blocksrecord=2258
@ -617,4 +885,3 @@ wardrecord=2265

603
MCServer/lang/items_de.ini Normal file
View File

@ -0,0 +1,603 @@
[Items]
luft=0
stein=1
granit=1:1
poliertergranit=1:2
diorit=1:3
polierterdiorit=1:4
andesit=1:5
polierterandesit=1:6
grasblock=2
erde=3
grobeerde=3:1
podsol=3:2
bruchstein=4
holzbretter=5
eichenholzbretter=5:0
fichtenholzbretter=5:1
birkenholzbretter=5:2
tropenholzbretter=5:3
akazienholzbretter=5:4
schwarzeichenholzbretter=5:5
setzling=6
eichensetzling=6:0
fichtensetzling=6:1
birkensetzling=6:2
tropensetzling=6:3
akaziensetzling=6:4
schwarzeichensetzling=6:5
grundgestein=7
wasser=8
fliessendeswasser=8
stehendeswasser=9
stilleswasser=9
swasser=9
lava=10
fliessendelava=10
stehendelava=11
stillelava=11
slava=11
sand=12
rotersand=12:1
kies=13
golderz=14
eisenerz=15
kohleerz=16
stamm=17
eichenholz=17:0
fichtenholz=17:1
birkenholz=17:2
tropenholz=17:3
laub=18
eichenlaub=18:0
fichtenlaub=18:1
birkenlaub=18:2
tropenlaub=18:3
schwamm=19
nasserschwamm=19:1
glas=20
lapislazulierz=21
lapislazuliblock=22
werfer=23
sandstein=24
normalersandstein=24:0
gemeisseltersandstein=24:1
glattersandstein=24:2
notenblock=25
bettblock=26
antriebsschiene=27
sensorschiene=28
klebrigerkolben=29
spinnenweben=30
gras=31
gras=31:1
farn=31:2
toterbusch=32
kolben=33
kolbenkopf=34
wolle=35
weissewolle=35:0
orangenewolle=35:1
magentawolle=35:2
hellblauewolle=35:3
gelbewolle=35:4
hellgruene=35:5
rosawolle=35:6
grauwool=35:7
greywool=35:7
grauewolle=35:7
hellgrauewolle=35:8
tuerkisewolle=35:9
violettewolle=35:10
blauewolle=35:11
braunewolle=35:12
gruenewolle=35:13
rotewolle=35:14
schwarzewolle=35:15
loewenzahn=37
blume=38
mohn=38:0
blaueorchidee=38:1
sternlauch=38:2
porzellansternchen=38:3
rotetulpe=38:4
orangenetulpe=38:5
weissetulpe=38:6
rosatulpe=38:7
margerite=38:8
braunerpilz=39
roterpilz=40
goldblock=41
eisenblock=42
doppelstufe=43
doppelsteinstufe=43:0
doppelsandsteinstufe=43:1
doppelholzstufe=43:2
doppelbruchsteinstufe=43:3
doppelziegelstufe=43:4
doppelsteinziegelstufe=43:5
doppelnetherziegelstufe=43:6
doppelquarzstufe=43:7
stufe=44
steinstufe=44:0
sandsteinstufe=44:1
holzstufe=44:2
bruchsteinstufe=44:3
ziegelstufe=44:4
steinziegelstufe=44:5
netherziegelstufe=44:6
quarzstufe=44:7
ziegelsteine=45
tnt=46
buecherregal=47
bemoosterbruchstein=48
obsidian=49
fackel=50
feuer=51
monsterspawner=52
eichenholztreppe=53
kiste=54
rotstonekabel=55
diamanterz=56
diamantblock=57
werkbank=58
ernte=59
farmland=60
ofen=61
brennenderofen=62
schildblock=63
holztuerblock=64
leiter=65
schiene=66
bruchsteintreppe=67
wandschild=68
schalter=69
steindruckplatte=70
eisentuerblock=71
holzdruckplatte=72
rotstoneerz=73
leuchtendesrotstoneerz=74
erloschenerotstonefackel=75
rotstonefackel=76
setinknopf=77
schnee=78
eis=79
schneeblock=80
kaktus=81
ton=82
zuckerrohrblock=83
plattenspieler=84
eichenholzzaun=85
kuerbis=86
netherstein=87
selensand=88
leuchtstein=89
portal=90
kürbislaterne=91
kuchenlock=92
weissesglas=95
orangenesglas=95:1
magentaglas=95:2
hellblauesglas=95:3
gelbesglas=95:4
hellgruenesglas=95:5
rosagerfaerbtglas=95:6
grauesglas=95:7
hellgrauesglas=95:8
tuerkisesglas=95:9
violettesglas=95:10
blauesglas=95:11
braunesglas=95:12
gruenesglas=95:13
rotesglas=95:14
schwarzesglas=95:15
falltuer=96
silberfischblock=97
steinziegel=98
bemoostesteinziegel=98:1
rissigesteinziegel=98:2
gemeisseltesteinziegel=98:3
braunerpilzblock=99
roterpilzblock=100
eisengitter=101
glasscheibe=102
melone=103
kuerbispflanze=104
melonenpflanze=105
ranken=106
eichenholzzauntor=107
ziegeltreppe=108
steinziegeltreppe=109
myzel=110
seerosenblatt=111
netherziegel=112
netherziegelzaun=113
netherziegeltreppe=114
netherwarzenblock=115
zaubertisch=116
braustandblock=117
kesselblock=118
endportal=119
endportalrahmen=120
endstein=121
drachenei=122
redstonelampe=123
erlosscheneredstonelampe=124
doppelholzstufe=125
doppeleichenholzstufe=125:0
doppelfichtenholzstufe=125:1
doppelbirkenholzstufe=125:2
doppeltropenholzstufe=125:3
doppelakazienholzstufe=125:4
doppelschwarzeichenstufe=125:5
holzstufe=126
eichenholzstufe=126:0
fichtenholzstufe=126:1
birkenholzstufe=126:2
tropenholzstufe=126:3
akazienholzstufe=126:4
schwarzeichenholzstufe=126:5
kakaobohnen=127
sandsteintreppe=128
smaragderz=129
endertruhe=130
haken=131
stolperdraht=132
smaragdblock=133
fichtenholztreppe=134
birkenholztreppe=135
tropenholztreppe=136
kommandoblock=137
leuchtfeuer=138
bruchsteinmauer=139
bemoostebruchsteinmauer=139:1
blumentopfblock=140
karottenpflanze=141
kartoffelpflanze=142
knopf=143
skelettschaedel=144
witherskelettschaedel=144:1
zombieschaedel=144:2
schaedel=144:3
creeperschaedel=144:4
amboss=145
redstonetruhe=146
waegeplatteniedrigegewichte=147 # WTF, that names are so stupid...
waegeplattehohegewichte=148
inaktiverkomparator=149
aktiverkomparator=150
tageslichtsensor=151
redstoneblock=152
netherquarzerz=153
trichter=154
quarzblock=155
gemeisselterquarzblock=155:1
quarzsaeule=155:2
quarztreppe=156
aktivierungsschiene=157
spender=158
weissgerfaerbterton=159
orangegerfaerbterton=159:1
magentagerfaerbterton=159:2
hellblaugerfaerbterton=159:3
gelbgerfaerbterton=159:4
hellgruengerfaerbterton=159:5
rosagerfaerbterton=159:6
graugerfaerbterton=159:7
hellgraugefaerbterton=159:8
tuerkisgerfaerbterton=159:9
purplegerfaerbterton=159:10
violettegerfaerbterton=159:10
blaugerfaerbterton=159:11
braungerfaerbterton=159:12
gruengerfaerbterton=159:13
rotgerfaerbterton=159:14
schwarzgerfaerbterton=159:15
weisseglasscheibe=160
orangeneglasscheibe=160:1
magentaglasscheibe=160:2
hellblaueglasscheibe=160:3
gelbeglasscheibe=160:4
hellgrueneglasscheibe=160:5
rosaglasscheibe=160:6
graueglasscheibe=160:7
hellgraueglasscheibe=160:8
tuerkiseglasscheibe=160:9
violetteglasscheibe=160:10
blaueglasscheibe=160:11
brauneglasscheibe=160:12
grueneglasscheibe=160:13
roteglasscheibe=160:14
schwarzeglasscheibe=160:15
neueslaub=161
akazienlaub=161:0
schwarzeichenlaub=161:1
neuestaemme=162
akazienholz=162:0
schwarzeichenholz=162:1
akazientreppe=163
schwarzeichentreppe=164
schleimblock=165
bartriere=166
eisenfalltür=167
prismarin=168
prismarinziegel=168:1
dunklerprismarin=168:2
seelaterne=169
strohballen=170
teppich=171
weisserteppich=171:0
orangenerteppich=171:1
magentateppich=171:2
hellblauerteppich=171:3
gelberteppich=171:4
hellgruenerteppich=171:5
rosateppich=171:6
grauerteppich=171:7
hellgrauerteppich=171:8
tuerkiserteppich=171:9
violetterteppich=171:10
blauerteppich=171:11
braunerteppich=171:12
gruenerteppich=171:13
roterteppich=171:14
schwarzerteppich=171:15
gebrannterton=172
kohleblock=173
packeis=174
doppelpflanze=175
sonnenblume=175:0
Flieder=175:1
hohesgras=175:2
grosserfarn=175:3
rosenstrauch=175:4
pfingstrose=175:5
rotersandstein=179
gemeisselterrotersandstein=179:1
glatterrotersandstein=179:2
rotesandsteintreppe=180
neuesteinstufe=182
rotesandsteinstufe=182:0
fichtenzauntor=183
birkenzauntor=184
tropenzauntor=185
schwarzeichenzauntor=186
akazienzauntor=187
fichtenzaun=188
birkenzaun=189
tropenzaun=190
schwarzeichenzaun=191
akazienzaun=192
eisenschaufel=256
eisenspitzhacke=257
eisenaxt=258
feuerzeug=259
apfel=260
bogen=261
pfeil=262
kohle=263
holzkohle=263:1
diamant=264
eisenbarren=265
goldbarren=266
eisenschwert=267
holzschwert=268
holzschaufel=269
holzspitzhacke=270
holzaxt=271
steinschwert=272
steinschaufel=273
steinspitzhacke=274
steinaxt=275
diamantschwert=276
diamantschaufel=277
diamantspitzhacke=278
diamantaxt=279
stock=280
schuessel=281
pilzsuppe=282
goldschwert=283
goldschaufel=284
goldspitzhacke=285
goldaxt=286
faden=287
feder=288
schwarzpulver=289
holzhacke=290
steinhacke=291
eisenhacke=292
diamanthacke=293
goldhacke=294
samen=295
weizen=296
brot=297
lederkappe=298
lederjacke=299
lederhose=300
lederstiefel=301
kettenhaube=302
kettenhemd=303
kettenhose=304
kettenstiefel=305
eisenhelm=306
eisenbrustplatte=307
eisenbeinschutz=308
eisenstiefel=309
diamanthelm=310
diamantbrustplatte=311
diamantbeinschutz=312
diamantstiefel=313
goldhelm=314
goldharnisch=315
goldbeinschutz=316
goldstiefel=317
goldboots=317
feuerstein=318
rohesschweinefleisch=319
gebratenesschweinefleisch=320
gemaelde=321
goldenerapfel=322
goldenerapfel=322:1
schild=323
eichenholztuer=324
eimer=325
wassereimer=326
lavaeimer=327
lore=328
sattel=329
eisentuer=330
redstone=331
schneeballl=332
boot=333
leder=334
milcht=335
ziegel=336
ton=337
zuckercane=338
papier=339
buch=340
schleimball=341
gueterlore=342
angetriebenelore=343
ei=344
kompass=345
angel=346
uhr=347
glowstonestaub=348
fisch=349
roherfisch=349
roherlachs=349:1
clownfisch=349:2
kugelfisch=349:3
gebratenerfisch=350
gebratenerlachs=350:1
farbe=351
tintenbeutel=351:0
rosenrot=351:1
kaktusgruen=351:2
kakaobohnen=351:3
lapislazuli=351:4
violetterfarbstoff=351:5
tuerkiserfarbstoff=351:6
hellgrauerfarbstoff=351:7
grauerfarbstoff=351:8
rosafarbstoff=351:9
hellgruenerfarbstoff=351:10
gelberfarbstoff=351:11
hellblauerfarbstoff=351:12
magentafarbstoff=351:13
orangenerfarbstoff=351:14
knochenmehl=351:15
knochen=352
zucker=353
kuchen=354
bett=355
redstoneverstaerker=356
keks=357
karte=358
schere=359
melone=360
kürbiskerne=361
melonenkerne=362
rohesrindfleisch=363
steak=364
roheshühnchen=365
gebrateneshühnchen=366
verrottetesfleisch=367
enderperle=368
lohenrute=369
ghasttraene=370
goldnugget=371
netherwarze=372
trank=373
glasflasche=374
spinnenauge=375
fermentiertesspinnenauge=376
lohenstaub=377
magmacreme=378
braustand=379
kessel=380
enderauge=381
glitzerndemelone=382
spawnei=383
erfahrungsfläschchen=384
feuerkugel=385
buchundfeder=386
beschriebenesbuch=387
smaragd=388
rahmen=389
blumentopf=390
karotte=391
kartoffel=392
ofenkartoffel=393
giftigekartoffel=394
leerekarte=395
goldenekarotte=396
skelettschaedel=397
witherschaedel=397:1
zombieschaedel=397:2
kopf=397:3
creeperschaedel=397:4
karottenrute=398
netherstern=399
kuerbiskuchen=400
feuerwerksrakete=401
feuerwerksstern=402
verzauberungsbuch=403
redstonekomparator=404
netherziegelitem=405
netherquarz=406
tntlore=407
trichterlore=408
prismarinscherbe=409
prismarinkristalle=410
roheskaninchen=411
gebrateneskaninchen=412
kaninchenragout=413
hasenpfote=414
kaninchenfell=415
ruestungsstaender=416
eisernepferderuestung=417
goldenepferderuestung=418
diamantenepferderuestung=419
leine=420
namensschild=421
kommandoblocklore=422
roheshammelfleisch=423
gebrateneshammelfleisch=424
banner=425
schwarzesbanner=415:0
rotesbanner=415:1
gruenesbanner=415:2
braunbanner=415:3
blauesbanner=415:4
violettesbanner=415:5
tuerkisesbanner=415:6
hellgrauesbanner=415:7
grauesbanner=415:8
rosabanner=415:9
hellgruenesbanner=415:10
gelbesbanner=415:11
hellblauesbanner=415:12
magentabanner=415:13
orangenesbanner=415:14
weissesbanner=415:15
fichtenholztuer=427
birkenholztuer=428
tropentuer=429
akazientuer=430
schwarzeichentuer=431
goldeneschallplatte=2256
grueneschallplatte=2257
blocksschallplatte=2258
chirpschallplatte=2259
farschallplatte=2260
mallschallplatte=2261
mellohischallplatte=2262
stalschallplatte=2263
stradschallplatte=2264
wardschallplatte=2265
11schallplatte=2266

View File

@ -44,7 +44,7 @@ MaxHealth=10
AttackRange=2.0
AttackRate=1
AttackDamage=4.0
SightDistance=25.0
SightDistance=64.0
MaxHealth=40
[ZombiePigman]
@ -185,4 +185,10 @@ AttackDamage=6.0
SightDistance=25.0
MaxHealth=100
[Bat]
AttackRange=2.0
AttackRate=1
AttackDamage=0.0
SightDistance=25.0
MaxHealth=6

View File

@ -12,7 +12,8 @@
:: It expects the MS Performance tools installed in C:\Program Files\Microsoft Visual Studio 9.0\Team Tools\Performance Tools
:: You can override this path by setting the pt environment variable prior to launching this script
::
:: By default it will launch the release version of MCServer; set the app environment variable to another executable to run that instead.
:: By default it will launch the 32-bit release version of MCServer; set the app environment variable to another executable to run that instead.
:: Set the IsExecutablex64 env variable to \x64 to profile a 64-bit executable instead (available as the profile_run_x64.cmd script)
:: Note that the app needs to be compiled with the "/PROFILE" flag in order for the profiling to work
@ -55,15 +56,15 @@ mkdir %outputdir%
:: Start the profiler
set outputname=profile.vsp
set output=%outputdir%\%outputname%
%pt%\vsperfcmd /start:sample /output:%output%
%pt%%IsExecutablex64%\vsperfcmd /start:sample /output:%output%
if errorlevel 1 goto haderror
:: Launch the application via the profiler
%pt%\vsperfcmd /launch:%app%
if errorlevel 1 goto haderror
%pt%%IsExecutablex64%\vsperfcmd /launch:%app%
if errorlevel 1 goto haderrorshutdown
:: Shut down the profiler (this command waits, until the application is terminated)
%pt%\vsperfcmd /shutdown
%pt%%IsExecutablex64%\vsperfcmd /shutdown
if errorlevel 1 goto haderror
@ -86,6 +87,10 @@ goto finished
:haderrorshutdown
echo An error was encountered, shutting down the profiler
%pt%%IsExecutablex64%\vsperfcmd /shutdown
:haderror
echo An error was encountered
pause

View File

@ -0,0 +1,5 @@
@echo off
:: This script uses the profile_run.cmd script to run profiling on a x64 release executable
set IsExecutablex64=\x64
call profile_run.cmd

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

View File

@ -0,0 +1,353 @@
body, html
{
font-family: "Open Sans", Tahoma, sans-serif;
padding: 0;
margin: 0;
font-weight: 400;
background-color: #fbe9e7;
color: rgba(0, 0, 0, 0.87);
}
.light { font-weight: 300; }
.bold { font-weight: 600; }
#wrapper
{
background-color: #ff5722;
margin: 40px auto;
width: 99%;
max-width: 1200px;
box-sizing: border-box;
-moz-box-sizing: border-box;
box-shadow: 0px 4px 5px rgba(0, 0, 0, 0.15);
color: rgba(0, 0, 0, 0.87);
}
.title
{
font-size: 30pt;
padding: 10px 40px;
text-decoration: none;
color: white;
text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3);
display: block;
}
#sidebar
{
float: left;
width: 20%;
}
.sideNav
{
list-style: none;
background-color: #fafafa;
margin: 20px 0;
padding: 5px 0;
width: 100%;
box-shadow: 1px 0px 10px rgba(0, 0, 0, 0.2);
}
.sideNav li
{
padding: 10px;
color: rgba(0, 0, 0, 0.54);
}
.sideNav li.link
{
padding-left: 30px;
}
.sideNav li.link a
{
text-decoration: none;
color: rgba(0, 0, 0, 0.87);
}
#container
{
margin: 0;
padding: 0;
overflow: hidden;
background-color: #f5f5f5;
}
#main
{
float: right;
width: 80%;
padding: 0 15px 20px 15px;
box-sizing: border-box;
-moz-box-sizing: border-box;
}
.clear
{
clear: both;
}
table
{
width: 100%;
border-collapse: collapse;
}
table td
{
padding: 5px;
}
table th
{
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
padding: 5px;
text-align: center;
}
table tr:nth-child(odd)
{
background-color: rgba(0, 0, 0, 0.015);
}
p
{
margin: 8px 0;
padding: 8px 3px;
}
a
{
text-decoration: none;
color: #0277bd;
-webkit-transition: color 0.1s linear;
-moz-transition: color 0.1s linear;
transition: color 0.1s linear;
}
a:hover
{
color: #01579b;
}
.welcome-msg
{
color: rgba(0, 0, 0, 0.54);
}
.username
{
text-transform: capitalize;
color: rgba(0, 0, 0, 0.87);
}
a:hover
{
color: black;
}
input, select
{
padding: 8px;
}
form
{
padding: 4px;
}
.info input[type="submit"], .info button, .info input[type="button"],
.warn input[type="submit"], .warn button, .warn input[type="button"],
.err input[type="submit"], .err button, .err input[type="button"]
{
float: right;
}
.err
{
color: white;
display: block;
background-color: #e51c23 !important;
padding: 15px;
line-height: 30px;
min-height: 30px;
}
.err:before
{
content: "ERROR: ";
}
.warn
{
color: white;
display: block;
background-color: #ff5722 !important;
padding: 15px;
line-height: 30px;
min-height: 30px;
}
.warn:before
{
content: "WARNING: ";
}
.info
{
color: white;
display: block;
background-color: #5677fc !important;
padding: 15px;
line-height: 30px;
min-height: 30px;
}
.info:before
{
content: "INFORMATION: ";
}
#footer .fleft
{
float: left;
}
#footer .fright
{
float: right;
text-align: right;
}
#footer
{
margin: 0;
padding: 10px;
font-size: 9pt;
color: rgba(255, 255, 255, 0.8);
box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.2) inset;
}
#footer a
{
text-transform: none;
color: white;
}
input[type="submit"], button, input[type="button"]
{
background-color: #ffc107;
padding: 8px 15px 8px 15px;
margin: 0 2px;
display: inline-block;
text-align: center;
color: black;
box-shadow: 0px 2px 3px rgba(0,0,0,0.2);
border: none;
outline: none;
cursor: pointer;
}
input[type="submit"]:hover, button:hover, input[type="button"]:hover
{
background-color: #ffca28;
}
input[type="submit"]:active, button:active, input[type="button"]:active
{
background-color: #ffd54f;
-webkit-transform: translateY(1px);
-moz-transform: translateY(1px);
transform: translateY(1px);
}
hr
{
border: none;
height: 1px;
background-color: rgba(0, 0, 0, 0.12);
}
h4
{
padding-bottom: 10px;
margin-bottom: 12px;
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
}
/**** PAGE SPECIFIC CSS ****/
/* remove the * for disabling: */
.page-core-server-settings table td
{
text-align: center;
width: 25%;
}
.page-core-server-settings.no-param table td:nth-child(1) a,
.page-core-server-settings.param-tab-general table td:nth-child(1) a
{
font-weight: 600;
color: rgba(0, 0, 0, 0.87);
}
.page-core-server-settings.param-tab-monsters table td:nth-child(2) a
{
font-weight: 600;
color: rgba(0, 0, 0, 0.87);
}
.page-core-server-settings.param-tab-worlds table td:nth-child(3) a
{
font-weight: 600;
color: rgba(0, 0, 0, 0.87);
}
.page-core-server-settings.param-tab-world table td:nth-child(4) a
{
font-weight: 600;
color: rgba(0, 0, 0, 0.87);
}
.page-core-permissions form table tr,
.page-core-permissions form table td,
.page-core-permissions form table th
{
border: none;
background-color: transparent;
}
.page-core-permissions form table tr:nth-child(1) th
{
width: 35%;
}
.page-core-permissions form table tr:nth-child(1) td
{
width: 65%;
}
.page-core-permissions form table td input
{
width: 100%;
box-sizing: border-box;
-moz-box-sizing: border-box;
margin: 0;
}
#ChatDiv
{
margin-bottom: 10px;
}
#ChatMessage
{
width: 100%;
box-sizing: border-box;
-moz-box-sizing: border-box;
}
/**/

View File

@ -0,0 +1,25 @@
<html>
<head>
<title>MCServer WebAdmin - Login</title>
<meta charset="UTF-8">
<link rel="icon" href="favicon.ico">
<style type="text/css">
header {
margin: 0 auto;
text-align: center;
vertical-align: middle;
}
</style>
</head>
<body>
<header>
<img src="mc-logo.png" alt="MCServer Logo" class="logo">
<h1>MCServer - WebAdmin</h1>
<form method="get" action="webadmin/">
<input type="submit" value="Log in">
</form>
</header>
</body>
</html>

View File

@ -71,17 +71,23 @@
border: 1px solid #ddd;
border-radius: 3px;
}
#main table tr.odd td {
background: #fbfbfb;
}
table tr:hover td { background: #fdfcf6; }
table tr:hover td {
background: #fdfcf6;
}
table .action {
text-align: right;
padding: 0 20px 0 10px;
}
table tr .action a { color: #9b9b9b; }
table tr .action a {
color: #9b9b9b;
}
#cssmenu{ height:10px; display:table; padding:0; margin: 0 auto; border:1px #707070 solid; border-radius:5px; }
#cssmenu > ul {list-style:inside none; padding:0; margin:0;}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,137 @@
-- Use a table for fast concatenation of strings
local SiteContent = {}
function Output(String)
table.insert(SiteContent, String)
end
function GetTableSize(Table)
local Size = 0
for key,value in pairs(Table) do
Size = Size + 1
end
return Size
end
function GetDefaultPage()
local PM = cRoot:Get():GetPluginManager()
local SubTitle = "Current Game"
local Content = ""
Content = Content .. "<h4>Server Name:</h4>"
Content = Content .. "<p>" .. cRoot:Get():GetServer():GetServerID() .. "</p>"
Content = Content .. "<h4>Plugins:</h4><ul>"
local AllPlugins = PM:GetAllPlugins()
for key,value in pairs(AllPlugins) do
if( value ~= nil and value ~= false ) then
Content = Content .. "<li>" .. key .. " V." .. value:GetVersion() .. "</li>"
end
end
Content = Content .. "</ul>"
Content = Content .. "<h4>Players:</h4><ul>"
local AddPlayerToTable = function( Player )
Content = Content .. "<li>" .. Player:GetName() .. "</li>"
end
cRoot:Get():ForEachPlayer( AddPlayerToTable )
Content = Content .. "</ul><br>";
return Content, SubTitle
end
function ShowPage(WebAdmin, TemplateRequest)
SiteContent = {}
local BaseURL = WebAdmin:GetBaseURL(TemplateRequest.Request.Path)
local Title = "MCServer WebAdmin"
local MemoryUsageKiB = cRoot:GetPhysicalRAMUsage()
local NumChunks = cRoot:Get():GetTotalChunkCount()
local PluginPage = WebAdmin:GetPage(TemplateRequest.Request)
local PageContent = PluginPage.Content
local SubTitle = PluginPage.PluginName
if (PluginPage.TabName ~= "") then
SubTitle = PluginPage.PluginName .. " - " .. PluginPage.TabName
end
if (PageContent == "") then
PageContent, SubTitle = GetDefaultPage()
end
Output([[
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="icon" href="/favicon.ico">
<title>]] .. Title .. [[</title>
<link rel="stylesheet" type="text/css" media="screen" href="/style.css">
</head>
<body>
<div id="wrapper">
<!-- h1 tag stays for the logo, you can use the a tag for linking the index page -->
<h1>
<a href="]] .. BaseURL .. [["><span>MCServer</span></a>
</h1>
<div id="containerHolder">
<div id="container">
<div id="sidebar">
<ul class="sideNav">
]])
local AllPlugins = WebAdmin:GetPlugins()
for key,value in pairs(AllPlugins) do
local PluginWebTitle = value:GetWebTitle()
local TabNames = value:GetTabNames()
if (GetTableSize(TabNames) > 0) then
Output("<li>"..PluginWebTitle.."</li>\n");
for webname,prettyname in pairs(TabNames) do
Output("<li><a href='" .. BaseURL .. PluginWebTitle .. "/" .. webname .. "'>" .. prettyname .. "</a></li>\n")
end
end
end
Output([[
</ul>
<!-- // .sideNav -->
</div>
<!-- // #sidebar -->
<!-- h2 stays for breadcrumbs -->
<h2>Welcome ]] .. TemplateRequest.Request.Username .. [[</h2>
<div id="main">
<h3>]] .. SubTitle .. [[</h3>
]] .. PageContent .. [[
</div>
<!-- // #main -->
<div class="clear"></div>
</div>
<!-- // #container -->
</div>
<!-- // #containerHolder -->
<p id="footer">MCServer is using: ]] .. MemoryUsageKiB / 1024 .. [[ MiB of memory; Current chunk count: ]] .. NumChunks .. [[ </p>
</div>
<!-- // #wrapper -->
</body>
</html>
]])
return table.concat(SiteContent)
end

View File

@ -1,209 +0,0 @@
@echo off
:: Nightbbuild2008.cmd
:: This script is run every night to produce a new version of MCServer, backup its PDB files and upload the packages to web.
:: When run without parameters, this script pauses at the end and waits for a keypress.
:: To run in an automated scheduler, add any parameter to disable waiting for a keystroke
::
:: The sript creates a symbol store (a database of PDB files) that can be used as a single entry in MSVC's symbol path,
:: then any executable / crashdump built by this script can be debugged and its symbols will be found automatically by MSVC,
:: without the users needing to specify the build version or anything.
:: In order to support pruning the symstore, a per-month store is created, so that old months can be removed when no longer needed.
::
:: This script expects a few tools on specific paths, you can pass the correct paths for your system as env vars "zip" and "vc"
:: This script assumes that "git", "symstore" and "touch" are available on PATH.
:: git comes from msysgit
:: symstore comes from Microsoft's Debugging Tools for Windows
:: touch comes from unxtools
:: This script is locale-dependent, because it parses the output of "time" and "date" shell commands
:: 7-zip executable (by default it should be on PATH):
if %zip%a == a set zip=7z
:: Visual C++ compiler executable name:
if %vc%a == a set vc="vcbuild.exe"
:: Check that the required environment vars are available:
if "a%ftppass%" == "a" (
echo You need to set FTP password in the ftppass environment variable to upload the files
goto haderror
)
if "a%ftpuser%" == "a" (
echo You need to set FTP username in the ftpuser environment variable to upload the files
goto haderror
)
if "a%ftpsite%" == "a" (
echo You need to set FTP server in the ftpsite environment variable to upload the files
goto haderror
)
:: Get the date and time into vars:
:: This is locale-dependent!
For /f "tokens=2-4 delims=/. " %%a in ('date /t') do (
set MYYEAR=%%c
set MYMONTH=%%b
set MYDAY=%%a
)
For /f "tokens=1-2 delims=/:" %%a in ('time /t') do (set MYTIME=%%a_%%b)
echo Performing nightbuild of MC-Server
set DONOTPAUSE=y
:: Update the sources to the latest revision:
git pull
if errorlevel 1 goto haderror
:: Update the external plugins to the latest revision:
git submodule update
if errorlevel 1 goto haderror
:: Get the Git commit ID into an environment var
For /f "tokens=1 delims=/. " %%a in ('git log -1 --oneline --no-abbrev-commit') do (set COMMITID=%%a)
if errorlevel 1 goto haderror
:: Test if the version is already present, using a "tagfile" that we create upon successful build
set TAGFOLDER=Install\%MYYEAR%_%MYMONTH%\
set TAGFILE=%TAGFOLDER%built_%COMMITID%.tag
echo Tag file: %TAGFILE%
if exist %TAGFILE% (
echo Latest version already present, bailing out
goto end
)
:: Configure the sources to use the MSVC2008 compiler:
cmake -G "Visual Studio 9 2008" .
if errorlevel 1 goto haderror
:: Update the Bindings:
echo Updating Lua bindings
del src\Bindings\Bindings.cpp
del src\Bindings\Bindings.h
set ALLTOLUA_WAIT=N
cd src\Bindings
call AllToLua.bat
cd ..\..
:: Compile using VC2008 Express. Do a full rebuild.
echo Setting up VS environment...
call "%VS90COMNTOOLS%\vsvars32.bat"
echo Compiling MCServer...
title MCS Nightbuild
start "vc" /b /wait /low /min %vc% /r MCServer.sln "Release|Win32"
if errorlevel 1 goto haderror
:: Generate the .example.ini files by running the server without any ini files:
cd MCServer
del groups.ini
del settings.ini
del webadmin.ini
echo stop | MCServer
cd ..
:: Copy all the example ini files into the Install folder for zipping:
copy MCServer\groups.ini Install\groups.example.ini
copy MCServer\settings.ini Install\settings.example.ini
copy MCServer\webadmin.ini Install\webadmin.example.ini
:: Use 7-zip to compress the resulting files into a single file:
set FILESUFFIX=%MYYEAR%_%MYMONTH%_%MYDAY%_%MYTIME%_%COMMITID%
echo FILESUFFIX=%FILESUFFIX%
copy MCServer\MCServer.exe Install\MCServer.exe
cd Install
%zip% a -mx9 -y MCServer_Win_%FILESUFFIX%.7z -scsWIN -i@Zip2008.list -xr!*.git*
if errorlevel 1 goto haderror
cd ..
:: Also pack PDBs into a separate archive:
%zip% a -mx9 -y Install\PDBs_%FILESUFFIX%.7z -scsWIN @Install\Zip2008_PDBs.list
if errorlevel 1 goto haderror
:: upload to the FTP:
:upload
ncftpput -p %ftppass% -u %ftpuser% -T temp_ %ftpsite% / Install\MCServer_Win_%FILESUFFIX%.7z
if errorlevel 1 goto haderror
ncftpput -p %ftppass% -u %ftpuser% -T temp_ %ftpsite% /PDBs Install\PDBs_%FILESUFFIX%.7z
if errorlevel 1 goto haderror
echo Upload finished.
:: Create the tagfile so that we know that this CommitID has been built already
mkdir %TAGFOLDER%
touch %TAGFILE%
:: Add the symbols to a global symbol cache
:: We want per-month symbol caches, so that the old ones can be easily deleted
set SYMBOLS=Symbols\%MYYEAR%_%MYMONTH%\
echo Storing symbols in %SYMBOLS%
symstore add /f MCServer\MCServer.* /s %SYMBOLS% /t MCServer
if errorlevel 1 goto haderror
goto end
:haderror
echo an error was encountered, check command output above
pause
goto finished
:end
if "a%1" == "a" pause
:finished

View File

@ -5,15 +5,15 @@ MCServer is a Minecraft server that is written in C++ and designed to be efficie
MCServer can run on PCs, Macs, and *nix. This includes android phones and tablets as well as Raspberry Pis.
We currently support the protocol from Minecraft 1.2 all the way up to Minecraft 1.7.10.
We currently support the protocol from Minecraft 1.2 all the way up to Minecraft 1.8.
Installation
------------
Normally, you will want to download a pre-compiled version of MCServer from one of the buildservers:
* [Linux and Raspberry Pi](http://ci.bearbin.net) (Bearbin's CI Server)
* [Windows](http://mc-server.xoft.cz) (xoft's nightly build service)
* [Windows and Linux](http://builds.cuberite.org)
* [Raspberry Pi](http://builds.cuberite.org)
You simply need to download and extract these files before you can use the server.
@ -33,7 +33,7 @@ For other stuff, including plugins and discussion, check the [forums](http://for
Earn bitcoins for commits or donate to reward the MCServer developers: [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74)
Support Us on Gittip: [![Support via Gittip](http://img.shields.io/gittip/mcs_team.svg)](https://www.gittip.com/mcs_team)
Support Us on Gratipay: [![Support via Gratipay](http://img.shields.io/gittip/cuberite_team.svg)](https://www.gratipay.com/cuberite_team)
Travis CI: [![Build Status](http://img.shields.io/travis/mc-server/MCServer.svg)](https://travis-ci.org/mc-server/MCServer)

View File

@ -1,3 +1,5 @@
macro (add_flags_lnk FLAGS)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${FLAGS}")
@ -57,12 +59,25 @@ macro(set_flags)
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG")
set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} /LTCG")
elseif(APPLE)
#on os x clang adds pthread for us but we need to add it for gcc
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND (NOT GCC_VERSION VERSION_GREATER 4.6))
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++0x")
set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -std=c++0x")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++0x")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -std=c++11")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
endif()
#on os x clang adds pthread for us but we need to add it for gcc
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_flags_cxx("-stdlib=libc++")
add_flags_lnk("-stdlib=libc++")
else()
@ -75,8 +90,17 @@ macro(set_flags)
add_flags_cxx("-pthread")
endif()
# Make CLang use C++11, otherwise MSVC2008-supported extensions don't work ("override" keyword etc.):
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND (NOT GCC_VERSION VERSION_GREATER 4.6))
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++0x")
set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -std=c++0x")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++0x")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -std=c++11")
@ -203,6 +227,15 @@ macro(enable_profile)
endif()
endmacro()
#this is a hack because we can't use cmake 2.8.10 because of travis
macro(get_clang_version)
execute_process(
COMMAND "${CMAKE_CXX_COMPILER}" "--version"
OUTPUT_VARIABLE CLANG_VERSION_OUTPUT)
string(REGEX MATCH "version ([0-9]\\.[0-9])" x ${CLANG_VERSION_OUTPUT})
set(CLANG_VERSION ${CMAKE_MATCH_1})
endmacro()
macro(set_exe_flags)
# Remove disabling the maximum warning level:
# clang does not like a command line that reads -Wall -Wextra -w -Wall -Wextra and does not output any warnings
@ -221,17 +254,28 @@ macro(set_exe_flags)
add_flags_cxx("-ffast-math")
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
get_clang_version()
if ("${CLANG_VERSION}" VERSION_LESS 3.0)
message(FATAL_ERROR "MCServer requires clang version 3.0 or higher, version is ${CLANG_VERSION}")
endif()
# 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-error=switch-enum -Wno-documentation -Wno-exit-time-destructors")
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 -Wno-error=old-style-cast")
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=extra-semi -Wno-weak-vtables -Wno-switch-enum")
add_flags_cxx("-Wno-exit-time-destructors -Wno-padded")
add_flags_cxx("-Wno-error=sign-conversion -Wno-error=conversion -Wno-error=deprecated")
add_flags_cxx("-Wno-error=missing-prototypes")
add_flags_cxx("-Wno-error=shadow -Wno-error=old-style-cast -Wno-error=global-constructors")
add_flags_cxx("-Wno-error=float-equal")
add_flags_cxx("-Wno-weak-vtables -Wno-switch-enum")
if ("${CLANG_VERSION}" VERSION_GREATER 3.0)
# flags that are not present in 3.0
add_flags_cxx("-Wno-error=covered-switch-default -Wno-error=missing-variable-declarations")
add_flags_cxx("-Wno-implicit-fallthrough -Wno-error=extra-semi")
endif()
if ("${CLANG_VERSION}" VERSION_GREATER 3.1)
# flags introduced in 3.2
add_flags_cxx("-Wno-documentation")
endif()
endif()
endif()

1
Tools/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
Debug/

View File

@ -1,3 +1,7 @@
*.vcproj
*.vcxproj
*.sln
*.user
.xls
Statistics.txt
*.bmp
@ -7,3 +11,4 @@ Profiling
*.png
world/
*.html
*.xls

View File

@ -1,55 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 2013 for Windows Desktop
VisualStudioVersion = 12.0.21005.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AnvilStats", "AnvilStats.vcxproj", "{CF996A5E-0A86-4004-9710-682B06B5AEBA}"
ProjectSection(ProjectDependencies) = postProject
{B61007AC-B557-4B67-A765-E468C0C3A821} = {B61007AC-B557-4B67-A765-E468C0C3A821}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\..\lib\zlib\zlib.vcxproj", "{B61007AC-B557-4B67-A765-E468C0C3A821}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
DebugProfile|Win32 = DebugProfile|Win32
MinSizeRel|Win32 = MinSizeRel|Win32
Release profiled|Win32 = Release profiled|Win32
Release|Win32 = Release|Win32
ReleaseProfile|Win32 = ReleaseProfile|Win32
RelWithDebInfo|Win32 = RelWithDebInfo|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CF996A5E-0A86-4004-9710-682B06B5AEBA}.Debug|Win32.ActiveCfg = Debug|Win32
{CF996A5E-0A86-4004-9710-682B06B5AEBA}.Debug|Win32.Build.0 = Debug|Win32
{CF996A5E-0A86-4004-9710-682B06B5AEBA}.DebugProfile|Win32.ActiveCfg = Debug|Win32
{CF996A5E-0A86-4004-9710-682B06B5AEBA}.DebugProfile|Win32.Build.0 = Debug|Win32
{CF996A5E-0A86-4004-9710-682B06B5AEBA}.MinSizeRel|Win32.ActiveCfg = Release|Win32
{CF996A5E-0A86-4004-9710-682B06B5AEBA}.MinSizeRel|Win32.Build.0 = Release|Win32
{CF996A5E-0A86-4004-9710-682B06B5AEBA}.Release profiled|Win32.ActiveCfg = Release profiled|Win32
{CF996A5E-0A86-4004-9710-682B06B5AEBA}.Release profiled|Win32.Build.0 = Release profiled|Win32
{CF996A5E-0A86-4004-9710-682B06B5AEBA}.Release|Win32.ActiveCfg = Release|Win32
{CF996A5E-0A86-4004-9710-682B06B5AEBA}.Release|Win32.Build.0 = Release|Win32
{CF996A5E-0A86-4004-9710-682B06B5AEBA}.ReleaseProfile|Win32.ActiveCfg = Release|Win32
{CF996A5E-0A86-4004-9710-682B06B5AEBA}.ReleaseProfile|Win32.Build.0 = Release|Win32
{CF996A5E-0A86-4004-9710-682B06B5AEBA}.RelWithDebInfo|Win32.ActiveCfg = Release|Win32
{CF996A5E-0A86-4004-9710-682B06B5AEBA}.RelWithDebInfo|Win32.Build.0 = Release|Win32
{B61007AC-B557-4B67-A765-E468C0C3A821}.Debug|Win32.ActiveCfg = Debug|Win32
{B61007AC-B557-4B67-A765-E468C0C3A821}.Debug|Win32.Build.0 = Debug|Win32
{B61007AC-B557-4B67-A765-E468C0C3A821}.DebugProfile|Win32.ActiveCfg = DebugProfile|Win32
{B61007AC-B557-4B67-A765-E468C0C3A821}.DebugProfile|Win32.Build.0 = DebugProfile|Win32
{B61007AC-B557-4B67-A765-E468C0C3A821}.MinSizeRel|Win32.ActiveCfg = MinSizeRel|Win32
{B61007AC-B557-4B67-A765-E468C0C3A821}.MinSizeRel|Win32.Build.0 = MinSizeRel|Win32
{B61007AC-B557-4B67-A765-E468C0C3A821}.Release profiled|Win32.ActiveCfg = Release|Win32
{B61007AC-B557-4B67-A765-E468C0C3A821}.Release profiled|Win32.Build.0 = Release|Win32
{B61007AC-B557-4B67-A765-E468C0C3A821}.Release|Win32.ActiveCfg = Release|Win32
{B61007AC-B557-4B67-A765-E468C0C3A821}.Release|Win32.Build.0 = Release|Win32
{B61007AC-B557-4B67-A765-E468C0C3A821}.ReleaseProfile|Win32.ActiveCfg = ReleaseProfile|Win32
{B61007AC-B557-4B67-A765-E468C0C3A821}.ReleaseProfile|Win32.Build.0 = ReleaseProfile|Win32
{B61007AC-B557-4B67-A765-E468C0C3A821}.RelWithDebInfo|Win32.ActiveCfg = RelWithDebInfo|Win32
{B61007AC-B557-4B67-A765-E468C0C3A821}.RelWithDebInfo|Win32.Build.0 = RelWithDebInfo|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -1,468 +0,0 @@
<?xml version="1.0" encoding="windows-1250"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="AnvilStats"
ProjectGUID="{CF996A5E-0A86-4004-9710-682B06B5AEBA}"
RootNamespace="AnvilStats"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;..\..\lib&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="Globals.h"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
StackReserveSize="16777216"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="&quot;..\..\lib&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="Globals.h"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
StackReserveSize="16777216"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release profiled|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="&quot;..\..\lib&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="Globals.h"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
StackReserveSize="16777216"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
Profile="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\AnvilStats.cpp"
>
</File>
<File
RelativePath=".\BiomeMap.cpp"
>
</File>
<File
RelativePath=".\BiomeMap.h"
>
</File>
<File
RelativePath=".\Callback.h"
>
</File>
<File
RelativePath=".\ChunkExtract.cpp"
>
</File>
<File
RelativePath=".\ChunkExtract.h"
>
</File>
<File
RelativePath=".\Globals.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release profiled|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Globals.h"
>
</File>
<File
RelativePath=".\HeightBiomeMap.cpp"
>
</File>
<File
RelativePath=".\HeightBiomeMap.h"
>
</File>
<File
RelativePath=".\HeightMap.cpp"
>
</File>
<File
RelativePath=".\HeightMap.h"
>
</File>
<File
RelativePath=".\ImageComposingCallback.cpp"
>
</File>
<File
RelativePath=".\ImageComposingCallback.h"
>
</File>
<File
RelativePath=".\Processor.cpp"
>
</File>
<File
RelativePath=".\Processor.h"
>
</File>
<File
RelativePath=".\SpringStats.cpp"
>
</File>
<File
RelativePath=".\SpringStats.h"
>
</File>
<File
RelativePath=".\Statistics.cpp"
>
</File>
<File
RelativePath=".\Statistics.h"
>
</File>
<File
RelativePath=".\Utils.cpp"
>
</File>
<File
RelativePath=".\Utils.h"
>
</File>
</Filter>
<Filter
Name="shared"
>
<File
RelativePath="..\..\src\OSSupport\CriticalSection.cpp"
>
</File>
<File
RelativePath="..\..\src\OSSupport\CriticalSection.h"
>
</File>
<File
RelativePath="..\..\src\Endianness.h"
>
</File>
<File
RelativePath="..\..\src\OSSupport\Event.cpp"
>
</File>
<File
RelativePath="..\..\src\OSSupport\Event.h"
>
</File>
<File
RelativePath="..\..\src\WorldStorage\FastNBT.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="NBT_RESERVE_SIZE=10000"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="NBT_RESERVE_SIZE=10000"
/>
</FileConfiguration>
<FileConfiguration
Name="Release profiled|Win32"
>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="NBT_RESERVE_SIZE=10000"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\src\WorldStorage\FastNBT.h"
>
</File>
<File
RelativePath="..\..\src\OSSupport\File.cpp"
>
</File>
<File
RelativePath="..\..\src\OSSupport\File.h"
>
</File>
<File
RelativePath="..\..\src\OSSupport\GZipFile.cpp"
>
</File>
<File
RelativePath="..\..\src\OSSupport\GZipFile.h"
>
</File>
<File
RelativePath="..\..\src\OSSupport\IsThread.cpp"
>
</File>
<File
RelativePath="..\..\src\OSSupport\IsThread.h"
>
</File>
<File
RelativePath="..\..\src\StringUtils.cpp"
>
</File>
<File
RelativePath="..\..\src\StringUtils.h"
>
</File>
</Filter>
<File
RelativePath=".\AnvilStats.txt"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,144 @@
cmake_minimum_required (VERSION 2.8.3)
project (AnvilStats)
include(../../SetFlags.cmake)
set_flags()
set_lib_flags()
# Set include paths to the used libraries:
include_directories("../../lib")
include_directories("../../src")
function(flatten_files arg1)
set(res "")
foreach(f ${${arg1}})
get_filename_component(f ${f} ABSOLUTE)
list(APPEND res ${f})
endforeach()
set(${arg1} "${res}" PARENT_SCOPE)
endfunction()
add_subdirectory(../../lib/zlib ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/lib/zlib)
set_exe_flags()
# Include the shared files:
set(SHARED_SRC
../../src/ByteBuffer.cpp
../../src/StringUtils.cpp
../../src/LoggerListeners.cpp
../../src/Logger.cpp
../../src/WorldStorage/FastNBT.cpp
../BiomeVisualiser/BiomeColors.cpp
)
set(SHARED_HDR
../../src/ByteBuffer.h
../../src/StringUtils.h
../../src/LoggerListeners.h
../../src/Logger.h
../../src/WorldStorage/FastNBT.h
../BiomeVisualiser/BiomeColors.h
)
set(SHARED_OSS_SRC
../../src/OSSupport/CriticalSection.cpp
../../src/OSSupport/Event.cpp
../../src/OSSupport/File.cpp
../../src/OSSupport/GZipFile.cpp
../../src/OSSupport/IsThread.cpp
../../src/OSSupport/Timer.cpp
)
set(SHARED_OSS_HDR
../../src/OSSupport/CriticalSection.h
../../src/OSSupport/Event.h
../../src/OSSupport/File.h
../../src/OSSupport/GZipFile.h
../../src/OSSupport/IsThread.h
../../src/OSSupport/Timer.h
)
flatten_files(SHARED_SRC)
flatten_files(SHARED_HDR)
flatten_files(SHARED_OSS_SRC)
flatten_files(SHARED_OSS_HDR)
source_group("Shared" FILES ${SHARED_SRC} ${SHARED_HDR})
source_group("Shared\\OSSupport" FILES ${SHARED_OSS_SRC} ${SHARED_OSS_HDR})
# Include the main source files:
set(SOURCES
AnvilStats.cpp
BiomeMap.cpp
ChunkExtract.cpp
Globals.cpp
HeightBiomeMap.cpp
HeightMap.cpp
ImageComposingCallback.cpp
Processor.cpp
SpringStats.cpp
Statistics.cpp
Utils.cpp
)
set(HEADERS
BiomeMap.h
Callback.h
ChunkExtract.h
Globals.h
HeightBiomeMap.h
HeightMap.h
ImageComposingCallback.h
Processor.h
SpringStats.h
Statistics.h
Utils.h
AnvilStats.txt
)
source_group("" FILES ${SOURCES} ${HEADERS})
add_definitions(-DNBT_RESERVE_SIZE=10000)
add_executable(AnvilStats
${SOURCES}
${HEADERS}
${SHARED_SRC}
${SHARED_HDR}
${SHARED_OSS_SRC}
${SHARED_OSS_HDR}
)
target_link_libraries(AnvilStats zlib)
# Under MSVC we need to enlarge the default stack size for the executable:
if (MSVC)
get_target_property(TEMP AnvilStats LINK_FLAGS)
if (TEMP STREQUAL "TEMP-NOTFOUND")
SET(TEMP "") # set to empty string
message("LINKER_FLAGS not found")
else ()
SET(TEMP "${TEMP} ") # a space to cleanly separate from existing content
message("LINKER_FLAGS: ${LINKER_FLAGS}")
endif ()
# append our values
SET(TEMP "${TEMP}/STACK:16777216")
set_target_properties(AnvilStats PROPERTIES LINK_FLAGS ${TEMP})
endif ()

View File

@ -241,6 +241,17 @@ public:
/** Clamp value to the specified range. */
template <typename T>
T Clamp(T a_Value, T a_Min, T a_Max)
{
return (a_Value < a_Min) ? a_Min : ((a_Value > a_Max) ? a_Max : a_Value);
}
// Common headers (part 2, with macros):
#include "../../src/ChunkDef.h"
#include "../../src/BlockID.h"

View File

@ -28,6 +28,7 @@ cProcessor::cThread::cThread(cCallback & a_Callback, cProcessor & a_ParentProces
m_Callback(a_Callback),
m_ParentProcessor(a_ParentProcessor)
{
LOG("Created a new thread: %p", this);
super::Start();
}
@ -35,11 +36,20 @@ cProcessor::cThread::cThread(cCallback & a_Callback, cProcessor & a_ParentProces
void cProcessor::cThread::WaitForStart(void)
{
m_HasStarted.Wait();
}
void cProcessor::cThread::Execute(void)
{
LOG("Started a new thread: %d", cIsThread::GetCurrentID());
LOG("Started a new thread: %p, ID %d", this, cIsThread::GetCurrentID());
m_ParentProcessor.m_ThreadsHaveStarted.Set();
m_HasStarted.Set();
for (;;)
{
@ -52,7 +62,7 @@ void cProcessor::cThread::Execute(void)
ProcessFile(FileName);
} // for-ever
LOG("Thread %d terminated", cIsThread::GetCurrentID());
LOG("Thread %p (ID %d) terminated", this, cIsThread::GetCurrentID());
}
@ -522,20 +532,18 @@ void cProcessor::ProcessWorld(const AString & a_WorldFolder, cCallbackFactory &
#endif // _DEBUG
//*/
// Start all the threads:
for (int i = 0; i < NumThreads; i++)
{
cCallback * Callback = a_CallbackFactory.GetNewCallback();
m_Threads.push_back(new cThread(*Callback, *this));
}
// Wait for the first thread to start processing:
m_ThreadsHaveStarted.Wait();
// Wait for all threads to finish
// simply by calling each thread's destructor sequentially
// Wait for all threads to finish:
LOG("Waiting for threads to finish");
for (cThreads::iterator itr = m_Threads.begin(), end = m_Threads.end(); itr != end; ++itr)
{
(*itr)->WaitForStart();
delete *itr;
} // for itr - m_Threads[]
LOG("Processor finished");

View File

@ -30,6 +30,7 @@ class cProcessor
cCallback & m_Callback;
cProcessor & m_ParentProcessor;
cEvent m_HasStarted;
// cIsThread override:
virtual void Execute(void) override;
@ -48,6 +49,9 @@ class cProcessor
public:
cThread(cCallback & a_Callback, cProcessor & a_ParentProcessor);
/** Waits until the thread starts processing the callback code. */
void WaitForStart(void);
} ;
typedef std::vector<cThread *> cThreads;
@ -65,10 +69,12 @@ protected:
AStringList m_FileQueue;
cThreads m_Threads;
cEvent m_ThreadsHaveStarted; // This is signalled by each thread to notify the parent thread that it can start waiting for those threads
/** Populates m_FileQueue with Anvil files from the specified folder. */
void PopulateFileQueue(const AString & a_WorldFolder);
/** Returns one filename from m_FileQueue, and removes the name from the queue. */
AString GetOneFileName(void);
} ;

View File

@ -28,6 +28,8 @@ cStatistics::cStats::cStats(void) :
{
memset(m_BiomeCounts, 0, sizeof(m_BiomeCounts));
memset(m_BlockCounts, 0, sizeof(m_BlockCounts));
memset(m_PerHeightBlockCounts, 0, sizeof(m_PerHeightBlockCounts));
memset(m_PerHeightSpawners, 0, sizeof(m_PerHeightSpawners));
memset(m_SpawnerEntity, 0, sizeof(m_SpawnerEntity));
}
@ -46,6 +48,11 @@ void cStatistics::cStats::Add(const cStatistics::cStats & a_Stats)
for (int j = 0; j <= 255; j++)
{
m_BlockCounts[i][j] += a_Stats.m_BlockCounts[i][j];
m_PerHeightBlockCounts[i][j] += a_Stats.m_PerHeightBlockCounts[i][j];
}
for (int j = 0; j < ARRAYCOUNT(m_PerHeightSpawners[0]); j++)
{
m_PerHeightSpawners[i][j] += a_Stats.m_PerHeightSpawners[i][j];
}
}
for (int i = 0; i < ARRAYCOUNT(m_SpawnerEntity); i++)
@ -149,6 +156,7 @@ bool cStatistics::OnSection
for (int y = 0; y < 16; y++)
{
int Height = (int)a_Y * 16 + y;
for (int z = 0; z < 16; z++)
{
for (int x = 0; x < 16; x++)
@ -156,6 +164,7 @@ bool cStatistics::OnSection
unsigned char Biome = m_BiomeData[x + 16 * z]; // Cannot use cChunkDef, different datatype
unsigned char BlockType = cChunkDef::GetBlock(a_BlockTypes, x, y, z);
m_Stats.m_BlockCounts[Biome][BlockType] += 1;
m_Stats.m_PerHeightBlockCounts[Height][BlockType] += 1;
}
}
}
@ -259,16 +268,27 @@ bool cStatistics::OnTileTick(
void cStatistics::OnSpawner(cParsedNBT & a_NBT, int a_TileEntityTag)
{
// Get the spawned entity type:
int EntityIDTag = a_NBT.FindChildByName(a_TileEntityTag, "EntityId");
if ((EntityIDTag < 0) || (a_NBT.GetType(EntityIDTag) != TAG_String))
{
return;
}
eEntityType Ent = GetEntityType(a_NBT.GetString(EntityIDTag));
if (Ent < ARRAYCOUNT(m_Stats.m_SpawnerEntity))
if (Ent >= ARRAYCOUNT(m_Stats.m_SpawnerEntity))
{
m_Stats.m_SpawnerEntity[Ent] += 1;
return;
}
m_Stats.m_SpawnerEntity[Ent] += 1;
// Get the spawner pos:
int PosYTag = a_NBT.FindChildByName(a_TileEntityTag, "y");
if ((PosYTag < 0) || (a_NBT.GetType(PosYTag) != TAG_Int))
{
return;
}
int BlockY = Clamp(a_NBT.GetInt(PosYTag), 0, 255);
m_Stats.m_PerHeightSpawners[BlockY][Ent] += 1;
}
@ -316,10 +336,14 @@ cStatisticsFactory::~cStatisticsFactory()
SaveBiomes();
LOG(" BlockTypes.xls");
SaveBlockTypes();
LOG(" PerHeightBlockTypes.xls");
SavePerHeightBlockTypes();
LOG(" BiomeBlockTypes.xls");
SaveBiomeBlockTypes();
LOG(" Spawners.xls");
SaveSpawners();
LOG(" PerHeightSpawners.xls");
SavePerHeightSpawners();
}
@ -395,6 +419,61 @@ void cStatisticsFactory::SaveBlockTypes(void)
void cStatisticsFactory::SavePerHeightBlockTypes(void)
{
// Export as two tables: biomes 0-127 and 128-255, because OpenOffice doesn't support more than 256 columns
cFile f;
if (!f.Open("PerHeightBlockTypes.xls", cFile::fmWrite))
{
LOG("Cannot write to file PerHeightBlockTypes.xls. Statistics not written.");
return;
}
// Write header:
f.Printf("Blocks 0 - 127:\nHeight");
for (int i = 0; i < 128; i++)
{
f.Printf("\t%s(%d)", GetBlockTypeString(i), i);
}
f.Printf("\n");
// Write first half:
for (int y = 0; y < 256; y++)
{
f.Printf("%d", y);
for (int BlockType = 0; BlockType < 128; BlockType++)
{
f.Printf("\t%llu", m_CombinedStats.m_PerHeightBlockCounts[y][BlockType]);
} // for BlockType
f.Printf("\n");
} // for y - height (0 - 127)
f.Printf("\n");
// Write second header:
f.Printf("Blocks 128 - 255:\nHeight");
for (int i = 128; i < 256; i++)
{
f.Printf("\t%s(%d)", GetBlockTypeString(i), i);
}
f.Printf("\n");
// Write second half:
for (int y = 0; y < 256; y++)
{
f.Printf("%d", y);
for (int BlockType = 128; BlockType < 256; BlockType++)
{
f.Printf("\t%llu", m_CombinedStats.m_PerHeightBlockCounts[y][BlockType]);
} // for BlockType
f.Printf("\n");
} // for y - height (0 - 127)
}
void cStatisticsFactory::SaveBiomeBlockTypes(void)
{
// Export as two tables: biomes 0-127 and 128-255, because OpenOffice doesn't support more than 256 columns
@ -521,3 +600,41 @@ void cStatisticsFactory::SaveSpawners(void)
void cStatisticsFactory::SavePerHeightSpawners(void)
{
cFile f;
if (!f.Open("PerHeightSpawners.xls", cFile::fmWrite))
{
LOG("Cannot write to file PerHeightSpawners.xls. Statistics not written.");
return;
}
// Write header:
f.Printf("Height\tTotal");
for (int i = 0; i < entMax; i++)
{
f.Printf("\t%s", GetEntityTypeString((eEntityType)i));
}
f.Printf("\n");
// Write individual lines:
for (int y = 0; y < 256; y++)
{
UInt64 Total = 0;
for (int i = 0; i < entMax; i++)
{
Total += m_CombinedStats.m_PerHeightSpawners[y][i];
}
f.Printf("%d\t%llu", y, Total);
for (int i = 0; i < entMax; i++)
{
f.Printf("\t%llu", m_CombinedStats.m_PerHeightSpawners[y][i]);
}
f.Printf("\n");
}
}

View File

@ -31,6 +31,8 @@ public:
UInt64 m_NumEntities;
UInt64 m_NumTileEntities;
UInt64 m_NumTileTicks;
UInt64 m_PerHeightBlockCounts[256][256]; // First dimension is the height, second dimension is BlockType
UInt64 m_PerHeightSpawners[256][entMax + 1]; // First dimension is the height, second dimension is spawned entity type
int m_MinChunkX, m_MaxChunkX; // X coords range
int m_MinChunkZ, m_MaxChunkZ; // Z coords range
@ -74,6 +76,8 @@ protected:
virtual bool OnEmptySection(unsigned char a_Y) override;
virtual bool OnSectionsFinished(void) override { return false; } // continue processing
virtual bool OnEntity(
const AString & a_EntityType,
double a_PosX, double a_PosY, double a_PosZ,
@ -128,9 +132,11 @@ protected:
void JoinResults(void);
void SaveBiomes(void);
void SaveBlockTypes(void);
void SavePerHeightBlockTypes(void);
void SaveBiomeBlockTypes(void);
void SaveStatistics(void);
void SaveSpawners(void);
void SavePerHeightSpawners(void);
} ;

View File

@ -272,7 +272,7 @@ extern const char * GetEntityTypeString(eEntityType a_EntityType)
int GetNumCores(void)
{
// Get number of cores by querying the system process affinity mask (Windows-specific)
DWORD Affinity, ProcAffinity;
DWORD_PTR Affinity, ProcAffinity;
GetProcessAffinityMask(GetCurrentProcess(), &ProcAffinity, &Affinity);
int NumCores = 0;
while (Affinity > 0)

View File

@ -1,4 +0,0 @@
Debug/
logs/
Release/
Release profiled/

View File

@ -1,338 +0,0 @@
// BiomeCache.cpp
// Implements the cBiomeCache class representing a biome source that caches data from the underlying biome source
#include "Globals.h"
#include "BiomeCache.h"
#include "Timer.h"
static int GetNumCores(void)
{
// Get number of cores by querying the system process affinity mask
DWORD Affinity, ProcAffinity;
GetProcessAffinityMask(GetCurrentProcess(), &ProcAffinity, &Affinity);
int NumCores = 0;
while (Affinity > 0)
{
if ((Affinity & 1) == 1)
{
NumCores++;
}
Affinity >>= 1;
} // while (Affinity > 0)
return NumCores;
}
cBiomeCache::cBiomeCache(void) :
m_Source(NULL),
m_BaseX(-100000),
m_BaseZ(-100000),
m_Available(NULL),
m_IsTerminatingThreads(false)
{
int NumThreads = GetNumCores();
NumThreads--; // One core should be left for the system to run on ;)
for (int i = NumThreads; i > 0; i--)
{
cThread * Thread = new cThread(*this);
m_Threads.push_back(Thread);
Thread->Start();
}
}
cBiomeCache::~cBiomeCache()
{
m_IsTerminatingThreads = true;
for (cThreads::iterator itr = m_Threads.begin(), end = m_Threads.end(); itr != end; ++itr)
{
m_evtQueued.Set();
}
for (cThreads::iterator itr = m_Threads.begin(), end = m_Threads.end(); itr != end; ++itr)
{
delete *itr;
}
m_Threads.clear();
SetSource(NULL);
}
cBiomeSource::eAvailability cBiomeCache::GetBiome(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_Biomes)
{
if (m_Source == NULL)
{
return baNever;
}
// Look up using the cache:
int x = a_ChunkX - m_BaseX;
int z = a_ChunkZ - m_BaseZ;
if ((x < 0) || (x >= m_Width) || (z < 0) || (z >= m_Height))
{
// Outside the cached region
return baNever;
}
cCSLock Lock(m_CS);
cItem * Item = m_Available[x + m_Width * z];
if (Item == NULL)
{
// Item hasn't been processed yet
return baLater;
}
if (Item->m_IsValid)
{
memcpy(a_Biomes, Item->m_Biomes, sizeof(a_Biomes));
return baNow;
}
// Item has been processed, but the underlying source refused to give the data to us
return baNever;
}
void cBiomeCache::HintViewArea(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ)
{
cTimer Timer("Cache: HintViewArea");
if (
(a_MinChunkX == m_BaseX) &&
(a_MaxChunkX == m_BaseX + m_Width - 1) &&
(a_MinChunkZ == m_BaseZ) &&
(a_MaxChunkZ == m_BaseZ + m_Height - 1)
)
{
// The same set of parameters, bail out
return;
}
if (m_Source != NULL)
{
m_Source->HintViewArea(a_MinChunkX, a_MaxChunkX, a_MinChunkZ, a_MaxChunkZ);
}
int NewWidth = a_MaxChunkX - a_MinChunkX + 1;
int NewHeight = a_MaxChunkZ - a_MinChunkZ + 1;
// Make a new empty cache table:
pItem * NewAvailable = new pItem[NewWidth * NewHeight];
for (int i = NewWidth * NewHeight - 1; i >= 0; --i)
{
NewAvailable[i] = NULL;
}
// Move the common contents of the old table into the new table:
cCSLock Lock(m_CS);
for (int z = 0; z < NewHeight; z++)
{
int OldZ = z + a_MinChunkZ - m_BaseZ;
if ((OldZ < 0) || (OldZ >= m_Height))
{
continue;
}
for (int x = 0; x < NewWidth; x++)
{
int OldX = x + a_MinChunkX - m_BaseX;
if ((OldX < 0) || (OldX >= m_Width))
{
continue;
}
NewAvailable[x + NewWidth * z] = m_Available[OldX + m_Width * OldZ];
m_Available[OldX + m_Width * OldZ] = NULL;
} // for x
} // for z
// All items that aren't common go into the pool:
for (int idx = 0, z = 0; z < m_Height; z++)
{
for (int x = 0; x < m_Width; ++x, ++idx)
{
if (m_Available[idx] != NULL)
{
m_Pool.push_back(m_Available[idx]);
m_Available[idx] = NULL;
}
}
}
// Replace the cache table:
delete m_Available;
m_Available = NewAvailable;
m_Width = NewWidth;
m_Height = NewHeight;
m_BaseX = a_MinChunkX;
m_BaseZ = a_MinChunkZ;
// Remove all items outside the coords:
FilterOutItems(m_Queue, a_MinChunkX, a_MaxChunkX, a_MinChunkZ, a_MaxChunkZ);
// Queue all items from inside the coords into m_Queue:
for (int z = 0; z < NewHeight; z++)
{
for (int x = 0; x < NewWidth; x++)
{
if (m_Available[x + m_Width * z] != NULL)
{
// Already calculated, skip
continue;
}
if (m_Pool.empty())
{
m_Pool.push_back(new cItem(x + a_MinChunkX, z + a_MinChunkZ));
}
ASSERT(!m_Pool.empty());
m_Pool.back()->m_ChunkX = x + a_MinChunkX;
m_Pool.back()->m_ChunkZ = z + a_MinChunkZ;
m_Queue.push_back(m_Pool.back());
m_Pool.pop_back();
m_evtQueued.Set();
} // for x
} // for z
}
void cBiomeCache::SetSource(cBiomeSource * a_Source)
{
// TODO: Stop all threads, so that they don't use the source anymore!
delete m_Source;
m_Source = a_Source;
// Invalidate cache contents:
cCSLock Lock(m_CS);
m_BaseX = -10000;
m_BaseZ = -10000;
m_Pool.splice(m_Pool.end(), m_Queue);
}
void cBiomeCache::FilterOutItems(cItems & a_Items, int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ)
{
for (cItems::iterator itr = a_Items.begin(); itr != a_Items.end();)
{
if (
((*itr)->m_ChunkX < a_MinChunkX) ||
((*itr)->m_ChunkX > a_MaxChunkX) ||
((*itr)->m_ChunkX < a_MinChunkX) ||
((*itr)->m_ChunkX > a_MaxChunkX)
)
{
m_Pool.push_back(*itr);
itr = a_Items.erase(itr);
}
else
{
++itr;
}
}
}
void cBiomeCache::thrProcessQueueItem(void)
{
if (m_Source == NULL)
{
return;
}
cItem * Item = NULL;
{
cCSLock Lock(m_CS);
if (m_Queue.empty())
{
cCSUnlock Unlock(Lock);
m_evtQueued.Wait();
}
if (m_IsTerminatingThreads || m_Queue.empty())
{
// We've been woken up only to die / spurious wakeup
return;
}
Item = m_Queue.back();
m_Queue.pop_back();
}
// Process the item:
Item->m_IsValid = (m_Source->GetBiome(Item->m_ChunkX, Item->m_ChunkZ, Item->m_Biomes) == baNow);
// Store result:
cCSLock Lock(m_CS);
int x = Item->m_ChunkX - m_BaseX;
int z = Item->m_ChunkZ - m_BaseZ;
if ((x < 0) || (x >= m_Width) || (z < 0) || (z >= m_Height))
{
// The cache rectangle has changed under our fingers, drop this chunk
return;
}
m_Available[x + m_Width * z] = Item;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cBiomeCache::cItem:
cBiomeCache::cItem::cItem(int a_ChunkX, int a_ChunkZ) :
m_ChunkX(a_ChunkX),
m_ChunkZ(a_ChunkZ)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cBiomeCache::cThread:
cBiomeCache::cThread::cThread(cBiomeCache & a_Parent) :
super("Biome cache thread"),
m_Parent(a_Parent)
{
}
void cBiomeCache::cThread::Execute(void)
{
while (!m_ShouldTerminate && !m_Parent.m_IsTerminatingThreads)
{
m_Parent.thrProcessQueueItem();
}
}

View File

@ -1,96 +0,0 @@
// BiomeCache.h
// Declares the cBiomeCache class representing a biome source that caches data from the underlying biome source
/*
This cache works a bit differently than regular caches.
It first receives the hint of area that it will need to provide.
The Cache uses several threads to request biomes from the underlying source to fill that area.
While the area is being filled, requests for biomes may already come, such requests are answered with baLater if no data yet.
*/
#pragma once
#include "BiomeSource.h"
#include "../src/OSSupport/IsThread.h"
class cBiomeCache :
public cBiomeSource
{
public:
cBiomeCache(void);
~cBiomeCache();
// cBiomeSource overrides:
virtual eAvailability GetBiome(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_Biomes) override;
virtual void HintViewArea(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ) override;
void SetSource(cBiomeSource * a_Source); // Takes ownership of the source ptr
protected:
class cItem
{
public:
cItem(int a_ChunkX, int a_ChunkZ);
int m_ChunkX;
int m_ChunkZ;
bool m_IsValid;
cChunkDef::BiomeMap m_Biomes;
} ;
typedef cItem * pItem;
typedef std::list<pItem> cItems;
class cThread :
public cIsThread
{
typedef cIsThread super;
public:
cThread(cBiomeCache & a_Parent);
// cIsThread overrides:
virtual void Execute(void) override;
protected:
cBiomeCache & m_Parent;
} ;
typedef std::list<cThread *> cThreads;
cBiomeSource * m_Source;
cCriticalSection m_CS;
int m_BaseX; ///< MinChunkX for the m_Available rectangle
int m_BaseZ; ///< MinChunkZ for the m_Available rectangle
int m_Width; ///< Width of the m_Available rectangle
int m_Height; ///< Height of the m_Available rectangle
pItem * m_Available; ///< Items that have already been processed (baNow or baNever), [x + m_Width * z]
cItems m_Queue; ///< Items that are queued for processing (baLater)
cItems m_Pool; ///< Items that are not needed anymore, can be reused for other coords
cEvent m_evtQueued; // Triggerred when an item is added to m_Queue
cThreads m_Threads; // Threads that update the cache.
bool m_IsTerminatingThreads; // Set to true to indicate to all threads that they should exit
/// Removes from a_Items all items that are outside of the given coords, moves those into m_Pool
void FilterOutItems(cItems & a_Items, int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ);
/// Processes one item from m_Queue into m_Available. Blocks if m_Queue is empty; respects m_IsTerminatingThreads
void thrProcessQueueItem(void);
} ;

View File

@ -1,114 +0,0 @@
// BiomeColors.cpp
// Implements the g_BiomeColors[] array preparation based on a stored biome-to-color map
#include "Globals.h"
#include "BiomeColors.h"
int g_BiomeColors[256];
static struct
{
EMCSBiome Biome;
int Color;
} g_BiomeColorMap[] =
{
{ biOcean, 0x000070 },
{ biPlains, 0x8db360 },
{ biDesert, 0xfa9418 },
{ biExtremeHills, 0x606060 },
{ biForest, 0x056621 },
{ biTaiga, 0x0b6659 },
{ biSwampland, 0x2fffda },
{ biRiver, 0x3030af },
{ biHell, 0x7f0000 },
{ biSky, 0x007fff },
{ biFrozenOcean, 0xa0a0df },
{ biFrozenRiver, 0xa0a0ff },
{ biIcePlains, 0xffffff },
{ biIceMountains, 0xa0a0a0 },
{ biMushroomIsland, 0xff00ff },
{ biMushroomShore, 0xa000ff },
{ biBeach, 0xfade55 },
{ biDesertHills, 0xd25f12 },
{ biForestHills, 0x22551c },
{ biTaigaHills, 0x163933 },
{ biExtremeHillsEdge, 0x7f8f7f },
{ biJungle, 0x537b09 },
{ biJungleHills, 0x2c4205 },
{ biJungleEdge, 0x628b17 },
{ biDeepOcean, 0x000030 },
{ biStoneBeach, 0xa2a284 },
{ biColdBeach, 0xfaf0c0 },
{ biBirchForest, 0x307444 },
{ biBirchForestHills, 0x1f5f32 },
{ biRoofedForest, 0x40511a },
{ biColdTaiga, 0x31554a },
{ biColdTaigaHills, 0x597d72 },
{ biMegaTaiga, 0x596651 },
{ biMegaTaigaHills, 0x596659 },
{ biExtremeHillsPlus, 0x507050 },
{ biSavanna, 0xbdb25f },
{ biSavannaPlateau, 0xa79d64 },
{ biMesa, 0xd94515 },
{ biMesaPlateauF, 0xb09765 },
{ biMesaPlateau, 0xca8c65 },
// M variants:
{ biSunflowerPlains, 0xb5db88 },
{ biDesertM, 0xffbc40 },
{ biExtremeHillsM, 0x888888 },
{ biFlowerForest, 0x2d8e49 },
{ biTaigaM, 0x338e81 },
{ biSwamplandM, 0x07f9b2 },
{ biIcePlainsSpikes, 0xb4dcdc },
{ biJungleM, 0x7ba331 },
{ biJungleEdgeM, 0x628b17 },
{ biBirchForestM, 0x589c6c },
{ biBirchForestHillsM, 0x47875a },
{ biRoofedForestM, 0x687942 },
{ biColdTaigaM, 0x243f36 },
{ biMegaSpruceTaiga, 0x454f3e },
{ biMegaSpruceTaigaHills, 0x454f4e },
{ biExtremeHillsPlusM, 0x789878 },
{ biSavannaM, 0xe5da87 },
{ biSavannaPlateauM, 0xa79d74 },
{ biMesaBryce, 0xff6d3d },
{ biMesaPlateauFM, 0xd8bf8d },
{ biMesaPlateauM, 0xf2b48d },
} ;
static class cBiomeColorsInitializer
{
public:
cBiomeColorsInitializer(void)
{
// Reset all colors to gray:
for (size_t i = 0; i < ARRAYCOUNT(g_BiomeColors); i++)
{
g_BiomeColors[i] = 0x7f7f7f;
}
for (size_t i = 0; i < ARRAYCOUNT(g_BiomeColorMap); i++)
{
g_BiomeColors[g_BiomeColorMap[i].Biome] = g_BiomeColorMap[i].Color;
}
}
} g_Initializer;

View File

@ -1,15 +0,0 @@
// BiomeColors.h
// Declares the g_BiomeColors[] array used for biome color lookup
extern int g_BiomeColors[256];

View File

@ -1,119 +0,0 @@
// BiomeRenderer.cpp
// Implements the cBiomeRenderer class representing the rendering engine
#include "Globals.h"
#include "BiomeRenderer.h"
#include "Pixmap.h"
#include "Timer.h"
#include "BiomeColors.h"
cBiomeRenderer::cBiomeRenderer(void) :
m_OriginX(160),
m_OriginY(160),
m_Zoom(1)
{
}
void cBiomeRenderer::SetSource(cBiomeSource * a_Source)
{
m_Cache.SetSource(a_Source);
}
bool cBiomeRenderer::Render(cPixmap & a_Pixmap)
{
cTimer Timer("cBiomeRenderer::Render");
int Wid = a_Pixmap.GetWidth();
int Hei = a_Pixmap.GetHeight();
// Hint the approximate view area to the biome source so that it can adjust its caches:
int MinBlockX = ( - m_OriginX) * m_Zoom;
int MaxBlockX = (Wid - m_OriginX) * m_Zoom;
int MinBlockZ = ( - m_OriginY) * m_Zoom;
int MaxBlockZ = (Hei - m_OriginY) * m_Zoom;
m_Cache.HintViewArea(MinBlockX / 16 - 1, MaxBlockX / 16 + 1, MinBlockZ / 16 - 1, MaxBlockZ / 16 + 1);
// Hold one current chunk of biome data:
int CurChunkX = -10000;
int CurChunkZ = -10000;
cChunkDef::BiomeMap CurBiomes;
bool res = false;
for (int y = 0; y < Hei; y++)
{
int BlockZ = (y - m_OriginY) * m_Zoom;
int ChunkZ = (BlockZ >= 0) ? (BlockZ / 16) : ((BlockZ + 1) / 16 - 1);
int RelZ = BlockZ - ChunkZ * 16;
for (int x = 0; x < Wid; x++)
{
int BlockX = (x - m_OriginX) * m_Zoom;
int ChunkX = (BlockX >= 0) ? (BlockX / 16) : ((BlockX + 1) / 16 - 1);
int RelX = BlockX - ChunkX * 16;
if ((ChunkZ != CurChunkZ) || (ChunkX != CurChunkX))
{
CurChunkX = ChunkX;
CurChunkZ = ChunkZ;
switch (m_Cache.GetBiome(CurChunkX, CurChunkZ, CurBiomes))
{
case cBiomeSource::baLater:
{
res = true;
// fallthrough:
}
case cBiomeSource::baNever:
{
for (int i = 0; i < ARRAYCOUNT(CurBiomes); i++)
{
CurBiomes[i] = biInvalidBiome;
}
break;
}
} // switch (Biome availability)
}
EMCSBiome Biome = cChunkDef::GetBiome(CurBiomes, RelX, RelZ);
a_Pixmap.SetPixel(x, y, GetBiomeColor(Biome));
} // for x
} // for y
return res;
}
int cBiomeRenderer::GetBiomeColor(EMCSBiome a_Biome)
{
if ((a_Biome < 0) || (a_Biome >= ARRAYCOUNT(g_BiomeColors)))
{
return 0xff0000;
}
return g_BiomeColors[a_Biome];
}
void cBiomeRenderer::MoveViewBy(int a_OffsX, int a_OffsY)
{
m_OriginX += a_OffsX;
m_OriginY += a_OffsY;
}

View File

@ -1,55 +0,0 @@
// BiomeRenderer.h
// Declares the cBiomeRenderer class representing the rendering engine
#pragma once
#include "BiomeCache.h"
// fwd: Pixmap.h
class cPixmap;
class cBiomeRenderer
{
public:
cBiomeRenderer(void);
void SetSource(cBiomeSource * a_Source); // Takes ownership of the source
/// Renders the biomes into the given pixmap. Returns true if some biome data was missing and can be retrieved later
bool Render(cPixmap & a_Pixmap);
/// Returns the RGB color value for the specified biome
int GetBiomeColor(EMCSBiome a_Biome);
void MoveViewBy(int a_OffsX, int a_OffsY);
void SetZoom(int a_NewZoom)
{
m_Zoom = a_NewZoom;
}
protected:
cBiomeCache m_Cache;
int m_OriginX;
int m_OriginY;
int m_Zoom;
} ;

View File

@ -1,37 +0,0 @@
// BiomeSource.h
// Declares the cBiomeSource abstract class used as an interface for getting biomes from any source
#pragma once
#include "ChunkDef.h"
class cBiomeSource abstract
{
public:
enum eAvailability
{
baNow, // Data returned now
baLater, // Data not returned, but will be available later, try again after a while
baNever, // Data not returned, will not be available at all
} ;
/// Fills a_Biomes with the biomes for the chunk specified
virtual eAvailability GetBiome(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_Biomes) = 0;
/// Used to inform the source about the view area that will be queried in the near future.
virtual void HintViewArea(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ) = 0;
} ;

View File

@ -1,247 +0,0 @@
// BiomeViewWnd.cpp
// Implements the cBiomeViewWnd class representing the window that displays biomes
#include "Globals.h"
#include "BiomeViewWnd.h"
#include "BiomeCache.h"
#include "GeneratorBiomeSource.h"
#include "iniFile/iniFile.h"
const int TIMER_RERENDER = 1200;
cBiomeViewWnd::cBiomeViewWnd(void) :
m_Wnd(NULL),
m_Thunk(&cBiomeViewWnd::WndProc, this),
m_IsLButtonDown(false)
{
}
bool cBiomeViewWnd::Create(HWND a_ParentWnd, LPCTSTR a_Title)
{
ASSERT(m_Wnd == NULL);
InitBiomeView();
// Create a regular STATIC window, then override its window procedure with our own. No need for obnoxious RegisterWindowClass() stuff.
m_Wnd = CreateWindow("STATIC", a_Title, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 400, 300, a_ParentWnd, NULL, GetModuleHandle(NULL), NULL);
if (m_Wnd == NULL)
{
LOGERROR("Cannot create main window: %d", GetLastError());
return false;
}
SetWindowLongPtr(m_Wnd, GWLP_WNDPROC, m_Thunk);
return true;
}
void cBiomeViewWnd::InitBiomeView(void)
{
cIniFile IniFile;
IniFile.ReadFile("world.ini");
int Seed = IniFile.GetValueSetI("Generator", "Seed", 0);
bool CacheOffByDefault = false;
m_BiomeGen = cBiomeGen::CreateBiomeGen(IniFile, Seed, CacheOffByDefault);
m_Renderer.SetSource(new cGeneratorBiomeSource(m_BiomeGen));
IniFile.WriteFile("world.ini");
}
void cBiomeViewWnd::SetZoom(int a_NewZoom)
{
m_Renderer.SetZoom(a_NewZoom);
Redraw();
}
void cBiomeViewWnd::Redraw(void)
{
if (m_Renderer.Render(m_Pixmap))
{
SetTimer(m_Wnd, TIMER_RERENDER, 200, NULL);
}
InvalidateRect(m_Wnd, NULL, FALSE);
}
LRESULT cBiomeViewWnd::WndProc(HWND a_Wnd, UINT a_Msg, WPARAM wParam, LPARAM lParam)
{
switch (a_Msg)
{
case WM_CHAR: return OnChar (wParam, lParam);
case WM_CLOSE: return OnClose ();
case WM_COMMAND: return OnCommand (wParam, lParam);
case WM_LBUTTONDOWN: return OnLButtonDown(wParam, lParam);
case WM_LBUTTONUP: return OnLButtonUp (wParam, lParam);
case WM_MOUSEMOVE: return OnMouseMove (wParam, lParam);
case WM_PAINT: return OnPaint ();
case WM_TIMER: return OnTimer (wParam);
}
return ::DefWindowProc(a_Wnd, a_Msg, wParam, lParam);
}
LRESULT cBiomeViewWnd::OnChar(WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case '1': SetZoom(1); break;
case '2': SetZoom(2); break;
case '3': SetZoom(3); break;
case '4': SetZoom(4); break;
case '5': SetZoom(5); break;
case '6': SetZoom(6); break;
case '7': SetZoom(7); break;
case '8': SetZoom(8); break;
case 27:
{
// Esc pressed, exit
PostQuitMessage(0);
break;
}
}
return 0;
}
LRESULT cBiomeViewWnd::OnClose(void)
{
PostQuitMessage(0);
return 0;
}
LRESULT cBiomeViewWnd::OnCommand(WPARAM wParam, LPARAM lParam)
{
// TODO: Handle menu commands, when we get menu
return 0;
}
LRESULT cBiomeViewWnd::OnLButtonDown(WPARAM wParam, LPARAM lParam)
{
m_IsLButtonDown = true;
GetCursorPos(&m_MouseDown);
return 0;
}
LRESULT cBiomeViewWnd::OnMouseMove(WPARAM wParam, LPARAM lParam)
{
if (!m_IsLButtonDown)
{
return 0;
}
POINT pnt;
GetCursorPos(&pnt);
m_Renderer.MoveViewBy(pnt.x - m_MouseDown.x, pnt.y - m_MouseDown.y);
m_MouseDown = pnt;
Redraw();
return 0;
}
LRESULT cBiomeViewWnd::OnLButtonUp(WPARAM wParam, LPARAM lParam)
{
OnMouseMove(wParam, lParam); // Last movement - if the mouse move hasn't been reported due to speed
m_IsLButtonDown = false;
InvalidateRect(m_Wnd, NULL, FALSE);
return 0;
}
LRESULT cBiomeViewWnd::OnPaint(void)
{
PAINTSTRUCT ps;
HDC DC = BeginPaint(m_Wnd, &ps);
RECT rc;
GetClientRect(m_Wnd, &rc);
int Wid = rc.right - rc.left;
int Hei = rc.bottom - rc.top;
if ((m_Pixmap.GetWidth() != Wid) || (m_Pixmap.GetHeight() != Hei))
{
m_Pixmap.SetSize(Wid, Hei);
if (m_Renderer.Render(m_Pixmap))
{
SetTimer(m_Wnd, TIMER_RERENDER, 200, NULL);
}
}
m_Pixmap.DrawToDC(DC, 0, 0);
EndPaint(m_Wnd, &ps);
return 0;
}
LRESULT cBiomeViewWnd::OnTimer(WPARAM wParam)
{
switch (wParam)
{
case TIMER_RERENDER:
{
if (!m_Renderer.Render(m_Pixmap))
{
KillTimer(m_Wnd, TIMER_RERENDER);
}
InvalidateRect(m_Wnd, NULL, FALSE);
break;
}
}
return 0;
}

View File

@ -1,69 +0,0 @@
// BiomeViewWnd.h
// Declares the cBiomeViewWnd class representing the window that displays biomes
#pragma once
#include "WndProcThunk.h"
#include "BiomeRenderer.h"
#include "BiomeCache.h"
#include "Pixmap.h"
// fwd:
class cBiomeGen;
class cBiomeViewWnd
{
public:
cBiomeViewWnd(void);
bool Create(HWND a_ParentWnd, LPCTSTR a_Title);
protected:
HWND m_Wnd;
CWndProcThunk<cBiomeViewWnd> m_Thunk;
cBiomeRenderer m_Renderer;
cPixmap m_Pixmap;
/// The generator that is to be visualised
cBiomeGen * m_BiomeGen;
bool m_IsLButtonDown;
POINT m_MouseDown;
void InitBiomeView(void);
void SetZoom(int a_NewZoom);
void Redraw(void);
LRESULT WndProc(HWND a_Wnd, UINT a_Msg, WPARAM wParam, LPARAM lParam);
// Message handlers:
LRESULT OnChar (WPARAM wParam, LPARAM lParam);
LRESULT OnClose (void);
LRESULT OnCommand (WPARAM wParam, LPARAM lParam);
LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam);
LRESULT OnMouseMove (WPARAM wParam, LPARAM lParam);
LRESULT OnLButtonUp (WPARAM wParam, LPARAM lParam);
LRESULT OnPaint (void);
LRESULT OnTimer (WPARAM wParam);
} ;

View File

@ -1,52 +0,0 @@
// BiomeVisualiser.cpp
// Implements the cBiomeVisualiser class representing the entire app. Also implements the WinMain() entrypoint
#include "Globals.h"
#include "time.h"
#include "BiomeVisualiser.h"
int WINAPI WinMain(HINSTANCE a_Instance, HINSTANCE a_PrevInstance, LPSTR a_CmdLine, int a_ShowCmd)
{
cBiomeVisualiser App;
return App.Run();
}
cBiomeVisualiser::cBiomeVisualiser(void) :
m_Logger(new cMCLogger(Printf("BiomeVisualiser_%08x.log", time(NULL))))
{
}
int cBiomeVisualiser::Run(void)
{
if (!m_MainWnd.Create(GetDesktopWindow(), TEXT("BiomeVisualiser")))
{
LOGERROR("Cannot create main window: %d", GetLastError());
return 1;
}
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} // while (GetMessage)
return msg.lParam;
}

View File

@ -1,31 +0,0 @@
// BiomeVisualiser.h
// Declares the cBiomeVisualiser class representing the entire application
#include "BiomeViewWnd.h"
class cBiomeVisualiser
{
public:
cBiomeVisualiser(void);
int Run(void);
protected:
cBiomeViewWnd m_MainWnd;
cMCLogger * m_Logger;
} ;

View File

@ -1,23 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BiomeVisualiser", "BiomeVisualiser.vcproj", "{6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release profiled|Win32 = Release profiled|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}.Debug|Win32.ActiveCfg = Debug|Win32
{6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}.Debug|Win32.Build.0 = Debug|Win32
{6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}.Release profiled|Win32.ActiveCfg = Release profiled|Win32
{6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}.Release profiled|Win32.Build.0 = Release profiled|Win32
{6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}.Release|Win32.ActiveCfg = Release|Win32
{6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -1,527 +0,0 @@
<?xml version="1.0" encoding="windows-1250"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="BiomeVisualiser"
ProjectGUID="{6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}"
RootNamespace="BiomeVisualiser"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../src;../../lib"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="Globals.h"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
AdditionalIncludeDirectories="../../src;../../lib"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
EnableEnhancedInstructionSet="2"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="Globals.h"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release profiled|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
AdditionalIncludeDirectories="../../src;../../lib"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
EnableEnhancedInstructionSet="2"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="Globals.h"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
Profile="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\BiomeCache.cpp"
>
</File>
<File
RelativePath=".\BiomeCache.h"
>
</File>
<File
RelativePath=".\BiomeColors.cpp"
>
</File>
<File
RelativePath=".\BiomeColors.h"
>
</File>
<File
RelativePath=".\BiomeRenderer.cpp"
>
</File>
<File
RelativePath=".\BiomeRenderer.h"
>
</File>
<File
RelativePath=".\BiomeSource.h"
>
</File>
<File
RelativePath=".\BiomeViewWnd.cpp"
>
</File>
<File
RelativePath=".\BiomeViewWnd.h"
>
</File>
<File
RelativePath=".\BiomeVisualiser.cpp"
>
</File>
<File
RelativePath=".\BiomeVisualiser.h"
>
</File>
<File
RelativePath=".\GeneratorBiomeSource.h"
>
</File>
<File
RelativePath=".\Pixmap.cpp"
>
</File>
<File
RelativePath=".\Pixmap.h"
>
</File>
<File
RelativePath=".\Timer.h"
>
</File>
<File
RelativePath=".\WndProcThunk.h"
>
</File>
<Filter
Name="Shared"
>
<File
RelativePath="..\..\src\BiomeDef.cpp"
>
</File>
<File
RelativePath="..\..\src\BiomeDef.h"
>
</File>
<File
RelativePath="..\..\src\BlockID.cpp"
>
</File>
<File
RelativePath="..\..\src\BlockID.h"
>
</File>
<File
RelativePath="..\..\src\ChunkDef.h"
>
</File>
<File
RelativePath="..\..\src\Enchantments.cpp"
>
</File>
<File
RelativePath="..\..\src\Enchantments.h"
>
</File>
<File
RelativePath="..\..\src\WorldStorage\FastNBT.cpp"
>
</File>
<File
RelativePath="..\..\src\WorldStorage\FastNBT.h"
>
</File>
<File
RelativePath="..\..\src\FastRandom.cpp"
>
</File>
<File
RelativePath="..\..\src\FastRandom.h"
>
</File>
<File
RelativePath="..\..\src\Globals.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release profiled|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\src\Globals.h"
>
</File>
<File
RelativePath="..\..\src\Item.h"
>
</File>
<File
RelativePath="..\..\src\Log.cpp"
>
</File>
<File
RelativePath="..\..\src\Log.h"
>
</File>
<File
RelativePath="..\..\src\MCLogger.cpp"
>
</File>
<File
RelativePath="..\..\src\MCLogger.h"
>
</File>
<File
RelativePath="..\..\src\Noise.cpp"
>
</File>
<File
RelativePath="..\..\src\Noise.h"
>
</File>
<File
RelativePath="..\..\src\Noise.inc"
>
</File>
<File
RelativePath="..\..\src\StringUtils.cpp"
>
</File>
<File
RelativePath="..\..\src\StringUtils.h"
>
</File>
<File
RelativePath="..\..\src\VoronoiMap.cpp"
>
</File>
<File
RelativePath="..\..\src\VoronoiMap.h"
>
</File>
<Filter
Name="OSSupport"
>
<File
RelativePath="..\..\src\OSSupport\CriticalSection.cpp"
>
</File>
<File
RelativePath="..\..\src\OSSupport\CriticalSection.h"
>
</File>
<File
RelativePath="..\..\src\OSSupport\Event.cpp"
>
</File>
<File
RelativePath="..\..\src\OSSupport\Event.h"
>
</File>
<File
RelativePath="..\..\src\OSSupport\File.cpp"
>
</File>
<File
RelativePath="..\..\src\OSSupport\File.h"
>
</File>
<File
RelativePath="..\..\src\OSSupport\IsThread.cpp"
>
</File>
<File
RelativePath="..\..\src\OSSupport\IsThread.h"
>
</File>
<File
RelativePath="..\..\src\OSSupport\Sleep.h"
>
</File>
</Filter>
<Filter
Name="Generating"
>
<File
RelativePath="..\..\src\Generating\BioGen.cpp"
>
</File>
<File
RelativePath="..\..\src\Generating\BioGen.h"
>
</File>
<File
RelativePath="..\..\src\Generating\ComposableGenerator.h"
>
</File>
</Filter>
<Filter
Name="iniFile"
>
<File
RelativePath="..\..\lib\iniFile\iniFile.cpp"
>
</File>
<File
RelativePath="..\..\lib\iniFile\iniFile.h"
>
</File>
</Filter>
</Filter>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -1,42 +0,0 @@
// GeneratorBiomeSource.h
// Declares the cGeneratorBiomeSource that adapts a cBiomeGen into a cBiomeSource
#include "../src/Generating/BioGen.h"
#include "BiomeSource.h"
class cGeneratorBiomeSource :
public cBiomeSource
{
public:
cGeneratorBiomeSource(cBiomeGen * a_Generator) : m_Generator(a_Generator) {} // Takes ownership of the generator ptr
~cGeneratorBiomeSource()
{
delete m_Generator;
}
// cBiomeSource overrides:
virtual eAvailability GetBiome(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_Biomes) override
{
m_Generator->GenBiomes(a_ChunkX, a_ChunkZ, a_Biomes);
return baNow;
}
virtual void HintViewArea(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ) override
{
// Nothing needed
}
protected:
cBiomeGen * m_Generator;
} ;

View File

@ -1,120 +0,0 @@
// Pixmap.cpp
// Implements the cPixmap class that represents a RGB pixmap and allows simple operations on it
#include "Globals.h"
#include "Pixmap.h"
cPixmap::cPixmap(void) :
m_Width(0),
m_Height(0),
m_Stride(0),
m_Pixels(NULL)
{
}
cPixmap::cPixmap(int a_Width, int a_Height) :
m_Width(0),
m_Height(0),
m_Stride(0),
m_Pixels(NULL)
{
SetSize(a_Width, a_Height);
}
cPixmap::~cPixmap()
{
delete m_Pixels;
}
void cPixmap::SetSize(int a_Width, int a_Height)
{
delete m_Pixels;
m_Pixels = new int[a_Width * a_Height];
m_Width = a_Width;
m_Height = a_Height;
m_Stride = m_Width; // Currently we don't need a special stride value, but let's support it for the future :)
}
void cPixmap::SetPixel(int a_X, int a_Y, int a_Color)
{
ASSERT(a_X >= 0);
ASSERT(a_X < m_Width);
ASSERT(a_Y >= 0);
ASSERT(a_Y < m_Height);
m_Pixels[a_X + a_Y * m_Stride] = a_Color;
}
int cPixmap::GetPixel(int a_X, int a_Y) const
{
ASSERT(a_X >= 0);
ASSERT(a_X < m_Width);
ASSERT(a_Y >= 0);
ASSERT(a_Y < m_Height);
return m_Pixels[a_X + a_Y * m_Stride];
}
void cPixmap::Fill(int a_Color)
{
int NumElements = m_Height * m_Stride;
for (int i = 0; i < NumElements; i++)
{
m_Pixels[i] = a_Color;
}
}
void cPixmap::DrawToDC(HDC a_DC, int a_OriginX, int a_OriginY)
{
BITMAPINFO bmi;
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = m_Width;
bmi.bmiHeader.biHeight = -m_Height; // Negative, we are top-down, unlike BMPs
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = m_Stride * m_Height * 4;
bmi.bmiHeader.biXPelsPerMeter = 1440;
bmi.bmiHeader.biYPelsPerMeter = 1440;
bmi.bmiHeader.biClrUsed = 0;
bmi.bmiHeader.biClrImportant = 0;
SetDIBitsToDevice(a_DC, a_OriginX, a_OriginY, m_Width, m_Height, 0, 0, 0, m_Height, m_Pixels, &bmi, DIB_RGB_COLORS);
}

View File

@ -1,39 +0,0 @@
// Pixmap.h
// Declares a cPixmap class that represents a RGB pixmap and allows simple operations on it
#pragma once
class cPixmap
{
public:
cPixmap(void);
cPixmap(int a_Width, int a_Height);
~cPixmap();
void SetSize(int a_Width, int a_Height);
int GetWidth (void) const { return m_Width; }
int GetHeight(void) const { return m_Height; }
void SetPixel(int a_X, int a_Y, int a_Color);
int GetPixel(int a_X, int a_Y) const;
void Fill(int a_Color);
void DrawToDC(HDC a_DC, int a_OriginX, int a_OriginY);
protected:
int m_Width;
int m_Height;
int m_Stride;
int * m_Pixels;
} ;

View File

@ -1,40 +0,0 @@
// Timer.h
// Declares the cTimer class representing a RAII class that measures time from its creation till its destruction
#pragma once
#include "time.h"
class cTimer
{
public:
cTimer(const AString & a_Title) :
m_Title(a_Title),
m_StartTime(clock())
{
}
~cTimer()
{
clock_t NumTicks = clock() - m_StartTime;
LOG("%s took %d ticks (%.02f sec)", m_Title.c_str(), NumTicks, (double)NumTicks / CLOCKS_PER_SEC);
}
protected:
AString m_Title;
clock_t m_StartTime;
} ;

View File

@ -1,143 +0,0 @@
// WndProcThunk.h
// Interfaces to the CWndProcThunk class responsible for WNDPROC class-thunking
// For details, see http://www.hackcraft.net/cpp/windowsThunk/thiscall/
// Also available is a CDlgProcThunk class doing the same work for DIALOGPROC
// MD: Made NX-compat by allocating the code structure using VirtualAlloc(..., PAGE_EXECUTE_READWRITE)
// fwd:
template <class W> class CWndProcThunk;
#ifndef WNDPROCTHUNK_H_INCLUDED
#define WNDPROCTHUNK_H_INCLUDED
template<typename To, typename From> inline To union_cast(From fr) throw()
{
union
{
From f;
To t;
} uc;
uc.f = fr;
return uc.t;
}
#pragma warning(push)
#pragma warning(disable : 4355)
#if defined(_M_IX86)
#pragma pack(push,1)
template <class W> class CWndProcThunk
{
typedef ::LRESULT (W::* WndProc)(::HWND, ::UINT, ::WPARAM, ::LPARAM);
typedef CWndProcThunk ThisClass;
struct SCode
{
BYTE m_mov; // mov ECX, m_this
W * m_this; //
BYTE m_jmp; // jmp m_relproc
ptrdiff_t m_relproc; // relative jmp
};
SCode * Code;
public:
ThisClass(WndProc proc, W * obj)
{
Code = (SCode *)VirtualAlloc(NULL, sizeof(SCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Code->m_mov = 0xB9,
Code->m_this = obj,
Code->m_jmp = 0xE9,
Code->m_relproc = union_cast<char *>(proc) - reinterpret_cast<char *>(Code) - sizeof(*Code);
::FlushInstructionCache(::GetCurrentProcess(), Code, sizeof(*Code));
}
virtual ~CWndProcThunk()
{
VirtualFree(Code, sizeof(*Code), MEM_RELEASE);
Code = NULL;
}
operator ::WNDPROC() const {return reinterpret_cast<::WNDPROC>(Code); }
operator ::LONG_PTR() const {return reinterpret_cast<::LONG_PTR>(Code); }
} ;
template <class W> class CDlgProcThunk
{
typedef ::BOOL (W::* DlgProc)(::HWND, ::UINT, ::WPARAM, ::LPARAM);
typedef CDlgProcThunk ThisClass;
struct SCode
{
BYTE m_mov; // mov ECX, m_this
W * m_this; //
BYTE m_jmp; // jmp m_relproc
ptrdiff_t m_relproc; // relative jmp
};
SCode * Code;
public:
CDlgProcThunk(DlgProc proc, W * obj)
{
Code = (SCode *)VirtualAlloc(NULL, sizeof(SCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Code->m_mov = 0xB9,
Code->m_this = obj,
Code->m_jmp = 0xE9,
Code->m_relproc = union_cast<char *>(proc) - reinterpret_cast<char *>(Code) - sizeof(*Code);
::FlushInstructionCache(::GetCurrentProcess(), Code, sizeof(*Code));
}
virtual ~CDlgProcThunk()
{
VirtualFree(Code, sizeof(*Code), MEM_RELEASE);
Code = NULL;
}
operator ::DLGPROC() const {return reinterpret_cast<::DLGPROC>(Code); }
operator ::LONG_PTR() const {return reinterpret_cast<::LONG_PTR>(Code); }
} ;
#pragma pack(pop)
#else // _M_IX86
#error Only X86 supported
#endif
#endif // WNDPROCTHUNK_H_INCLUDED

View File

@ -1,70 +0,0 @@
@echo off
::
:: Profiling using a MSVC standalone profiler
::
:: See http://www.codeproject.com/Articles/144643/Profiling-of-C-Applications-in-Visual-Studio-for-F for details
::
set pt="C:\Program Files\Microsoft Visual Studio 9.0\Team Tools\Performance Tools"
set appdir="Release profiled"
set app="Release profiled\BiomeVisualiser.exe"
set args=""
:: outputdir is relative to appdir!
set outputdir=Profiling
set output=profile.vsp
::Create the output directory, if it didn't exist
mkdir %outputdir%
:: Start the profiler
%pt%\vsperfcmd /start:sample /output:%outputdir%\%output%
if errorlevel 1 goto haderror
:: Launch the application via the profiler
%pt%\vsperfcmd /launch:%app% /args:%args%
if errorlevel 1 goto haderror
:: Shut down the profiler (this command waits, until the application is terminated)
%pt%\vsperfcmd /shutdown
if errorlevel 1 goto haderror
:: cd to outputdir, so that the reports are generated there
cd %outputdir%
:: generate the report files (.csv)
%pt%\vsperfreport /summary:all %output% /symbolpath:"srv*C:\Programovani\Symbols*http://msdl.microsoft.com/download/symbols"
if errorlevel 1 goto haderror
goto finished
:haderror
echo An error was encountered
pause
:finished

View File

@ -39,14 +39,12 @@ set_exe_flags()
set(SHARED_SRC
../../src/StringCompression.cpp
../../src/StringUtils.cpp
../../src/Log.cpp
../../src/MCLogger.cpp
../../src/LoggerListeners.cpp
../../src/Logger.cpp
)
set(SHARED_HDR
../../src/ByteBuffer.h
../../src/StringUtils.h
../../src/Log.h
../../src/MCLogger.h
)
flatten_files(SHARED_SRC)
flatten_files(SHARED_HDR)

View File

@ -5,7 +5,8 @@
#include "Globals.h"
#include "MCADefrag.h"
#include "MCLogger.h"
#include "Logger.h"
#include "LoggerListeners.h"
#include "zlib/zlib.h"
@ -21,7 +22,13 @@ static const Byte g_Zeroes[4096] = {0};
int main(int argc, char ** argv)
{
new cMCLogger(Printf("Defrag_%08x.log", time(NULL)));
cLogger::cListener * consoleLogListener = MakeConsoleListener();
cLogger::cListener * fileLogListener = new cFileListener();
cLogger::GetInstance().AttachListener(consoleLogListener);
cLogger::GetInstance().AttachListener(fileLogListener);
cLogger::InitiateMultithreading();
cMCADefrag Defrag;
if (!Defrag.Init(argc, argv))
{
@ -30,6 +37,11 @@ int main(int argc, char ** argv)
Defrag.Run();
cLogger::GetInstance().DetachListener(consoleLogListener);
delete consoleLogListener;
cLogger::GetInstance().DetachListener(fileLogListener);
delete fileLogListener;
return 0;
}

View File

@ -34,20 +34,18 @@ set_exe_flags()
set(SHARED_SRC
../../src/ByteBuffer.cpp
../../src/StringUtils.cpp
../../src/Log.cpp
../../src/MCLogger.cpp
../../src/PolarSSL++/AesCfb128Decryptor.cpp
../../src/PolarSSL++/AesCfb128Encryptor.cpp
../../src/PolarSSL++/CryptoKey.cpp
../../src/PolarSSL++/CtrDrbgContext.cpp
../../src/PolarSSL++/EntropyContext.cpp
../../src/PolarSSL++/RsaPrivateKey.cpp
../../src/LoggerListeners.cpp
../../src/Logger.cpp
)
set(SHARED_HDR
../../src/ByteBuffer.h
../../src/StringUtils.h
../../src/Log.h
../../src/MCLogger.h
../../src/PolarSSL++/AesCfb128Decryptor.h
../../src/PolarSSL++/AesCfb128Encryptor.h
../../src/PolarSSL++/CryptoKey.h

View File

@ -1819,8 +1819,7 @@ bool cConnection::HandleServerKick(void)
Reason.append(Split[4]);
Reason.push_back(0);
Reason.append(Split[5]);
AString ReasonBE16;
UTF8ToRawBEUTF16(Reason.data(), Reason.size(), ReasonBE16);
AString ReasonBE16 = UTF8ToRawBEUTF16(Reason.data(), Reason.size());
AString PacketStart("\xff");
PacketStart.push_back((ReasonBE16.size() / 2) / 256);
PacketStart.push_back((ReasonBE16.size() / 2) % 256);

2
Tools/QtBiomeVisualiser/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.pro.user
*.pro.user.*

View File

@ -0,0 +1,414 @@
#include "Globals.h"
#include "BiomeView.h"
#include "QtChunk.h"
#include <QPainter>
#include <QResizeEvent>
static const int DELTA_STEP = 120; // The normal per-notch wheel delta
BiomeView::BiomeView(QWidget * parent) :
super(parent),
m_X(0),
m_Z(0),
m_Zoom(1),
m_IsMouseDragging(false),
m_MouseWheelDelta(0)
{
// Create the image used for undefined chunks:
int offset = 0;
for (int y = 0; y < 16; y++)
{
for (int x = 0; x < 16; x++)
{
uchar color = (((x & 8) ^ (y & 8)) == 0) ? 0x44 : 0x88;
m_EmptyChunkImage[offset++] = color;
m_EmptyChunkImage[offset++] = color;
m_EmptyChunkImage[offset++] = color;
m_EmptyChunkImage[offset++] = 0xff;
}
}
// Create the startup image:
redraw();
// Add a chunk-update callback mechanism:
connect(&m_Cache, SIGNAL(chunkAvailable(int, int)), this, SLOT(chunkAvailable(int, int)));
// Allow mouse and keyboard interaction:
setFocusPolicy(Qt::StrongFocus);
setMouseTracking(true);
}
QSize BiomeView::minimumSizeHint() const
{
return QSize(300, 300);
}
QSize BiomeView::sizeHint() const
{
return QSize(800, 600);
}
void BiomeView::setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource)
{
// Replace the source in the cache:
m_Cache.setChunkSource(a_ChunkSource);
// Redraw with the new source:
redraw();
}
void BiomeView::setPosition(int a_BlockX, int a_BlockZ)
{
m_X = a_BlockX;
m_Z = a_BlockZ;
redraw();
}
void BiomeView::setZoomLevel(double a_ZoomLevel)
{
m_Zoom = a_ZoomLevel;
redraw();
}
void BiomeView::redraw()
{
if (!hasData())
{
// No data means no image is displayed, no need to compose:
update();
return;
}
int chunksize = 16 * m_Zoom;
// first find the center block position
int centerchunkx = floor(m_X / 16);
int centerchunkz = floor(m_Z / 16);
// and the center of the screen
int centerx = m_Image.width() / 2;
int centery = m_Image.height() / 2;
// and align for panning
centerx -= (m_X - centerchunkx * 16) * m_Zoom;
centery -= (m_Z - centerchunkz * 16) * m_Zoom;
// now calculate the topleft block on the screen
int startx = centerchunkx - centerx / chunksize - 1;
int startz = centerchunkz - centery / chunksize - 1;
// and the dimensions of the screen in blocks
int blockswide = m_Image.width() / chunksize + 3;
int blockstall = m_Image.height() / chunksize + 3;
for (int z = startz; z < startz + blockstall; z++)
{
for (int x = startx; x < startx + blockswide; x++)
{
drawChunk(x, z);
}
}
update();
}
void BiomeView::chunkAvailable(int a_ChunkX, int a_ChunkZ)
{
drawChunk(a_ChunkX, a_ChunkZ);
update();
}
void BiomeView::reload()
{
if (!hasData())
{
return;
}
m_Cache.reload();
redraw();
}
void BiomeView::drawChunk(int a_ChunkX, int a_ChunkZ)
{
if (!hasData())
{
return;
}
//fetch the chunk:
ChunkPtr chunk = m_Cache.fetch(a_ChunkX, a_ChunkZ);
// Figure out where on the screen this chunk should be drawn:
// first find the center chunk
int centerchunkx = floor(m_X / 16);
int centerchunkz = floor(m_Z / 16);
// and the center chunk screen coordinates
int centerx = m_Image.width() / 2;
int centery = m_Image.height() / 2;
// which need to be shifted to account for panning inside that chunk
centerx -= (m_X - centerchunkx * 16) * m_Zoom;
centery -= (m_Z - centerchunkz * 16) * m_Zoom;
// centerx,y now points to the top left corner of the center chunk
// so now calculate our x,y in relation
double chunksize = 16 * m_Zoom;
centerx += (a_ChunkX - centerchunkx) * chunksize;
centery += (a_ChunkZ - centerchunkz) * chunksize;
int srcoffset = 0;
uchar * bits = m_Image.bits();
int imgstride = m_Image.bytesPerLine();
int skipx = 0,skipy = 0;
int blockwidth = chunksize, blockheight = chunksize;
// now if we're off the screen we need to crop
if (centerx < 0)
{
skipx = -centerx;
centerx = 0;
}
if (centery < 0)
{
skipy = -centery;
centery = 0;
}
// or the other side, we need to trim
if (centerx + blockwidth > m_Image.width())
{
blockwidth = m_Image.width() - centerx;
}
if (centery + blockheight > m_Image.height())
{
blockheight = m_Image.height() - centery;
}
if ((blockwidth <= 0) || (skipx >= blockwidth))
{
return;
}
int imgoffset = centerx * 4 + centery * imgstride;
// If the chunk is valid, use its data; otherwise use the empty placeholder:
const uchar * src = m_EmptyChunkImage;
if (chunk.get() != nullptr)
{
src = chunk->getImage();
}
// Blit or scale-blit the image:
for (int z = skipy; z < blockheight; z++, imgoffset += imgstride)
{
srcoffset = floor((double)z / m_Zoom) * 16 * 4;
if (m_Zoom == 1.0)
{
memcpy(bits + imgoffset, src + srcoffset + skipx * 4, (blockwidth - skipx) * 4);
}
else
{
int xofs = 0;
for (int x = skipx; x < blockwidth; x++, xofs +=4)
{
memcpy(bits + imgoffset + xofs, src + srcoffset + (int)floor((double)x / m_Zoom) * 4, 4);
}
}
}
}
void BiomeView::resizeEvent(QResizeEvent * a_Event)
{
m_Image = QImage(a_Event->size(), QImage::Format_RGB32);
redraw();
}
void BiomeView::paintEvent(QPaintEvent * a_Event)
{
QPainter p(this);
if (hasData())
{
p.drawImage(QPoint(0, 0), m_Image);
}
else
{
p.drawText(a_Event->rect(), Qt::AlignCenter, "No chunk source selected");
}
p.end();
}
void BiomeView::mousePressEvent(QMouseEvent * a_Event)
{
m_LastX = a_Event->x();
m_LastY = a_Event->y();
m_IsMouseDragging = true;
}
void BiomeView::mouseMoveEvent(QMouseEvent * a_Event)
{
// If there's no data displayed, bail out:
if (!hasData())
{
return;
}
if (m_IsMouseDragging)
{
// The user is dragging the mouse, move the view around:
m_X += (m_LastX - a_Event->x()) / m_Zoom;
m_Z += (m_LastY - a_Event->y()) / m_Zoom;
m_LastX = a_Event->x();
m_LastY = a_Event->y();
redraw();
return;
}
// Update the status bar info text:
int blockX = floor((a_Event->x() - width() / 2) / m_Zoom + m_X);
int blockZ = floor((a_Event->y() - height() / 2) / m_Zoom + m_Z);
int chunkX, chunkZ;
int relX = blockX, relY, relZ = blockZ;
cChunkDef::AbsoluteToRelative(relX, relY, relZ, chunkX, chunkZ);
auto chunk = m_Cache.fetch(chunkX, chunkZ);
int biome = (chunk.get() != nullptr) ? chunk->getBiome(relX, relZ) : biInvalidBiome;
emit hoverChanged(blockX, blockZ, biome);
}
void BiomeView::mouseReleaseEvent(QMouseEvent *)
{
m_IsMouseDragging = false;
}
void BiomeView::wheelEvent(QWheelEvent * a_Event)
{
m_MouseWheelDelta += a_Event->delta();
while (m_MouseWheelDelta >= DELTA_STEP)
{
emit wheelUp();
m_MouseWheelDelta -= DELTA_STEP;
}
while (m_MouseWheelDelta <= -DELTA_STEP)
{
emit wheelDown();
m_MouseWheelDelta += DELTA_STEP;
}
}
void BiomeView::keyPressEvent(QKeyEvent * a_Event)
{
switch (a_Event->key())
{
case Qt::Key_Up:
case Qt::Key_W:
{
m_Z -= 10.0 / m_Zoom;
redraw();
break;
}
case Qt::Key_Down:
case Qt::Key_S:
{
m_Z += 10.0 / m_Zoom;
redraw();
break;
}
case Qt::Key_Left:
case Qt::Key_A:
{
m_X -= 10.0 / m_Zoom;
redraw();
break;
}
case Qt::Key_Right:
case Qt::Key_D:
{
m_X += 10.0 / m_Zoom;
redraw();
break;
}
case Qt::Key_PageUp:
case Qt::Key_Q:
{
emit increaseZoom();
break;
}
case Qt::Key_PageDown:
case Qt::Key_E:
{
emit decreaseZoom();
break;
}
}
}

View File

@ -0,0 +1,114 @@
#pragma once
#include <QWidget>
#include <memory>
#include "ChunkCache.h"
#include "ChunkSource.h"
class BiomeView :
public QWidget
{
typedef QWidget super;
Q_OBJECT
public:
explicit BiomeView(QWidget * parent = NULL);
QSize minimumSizeHint() const;
QSize sizeHint() const;
/** Replaces the chunk source used by the biome view to get the chunk biome data.
The entire view is then invalidated and regenerated. */
void setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource);
/** Sets the position of the central pixel of the map to the specified point and redraws the view. */
void setPosition(int a_BlockX, int a_BlockZ);
/** Sets the zoom level to the specified value and redraws the view. */
void setZoomLevel(double a_ZoomLevel);
signals:
/** Signalled when the user uses the wheel to scroll upwards. */
void wheelUp();
/** Signalled when the user uses the wheel to scroll downwards. */
void wheelDown();
/** Signalled when the user presses a key to increase zoom. */
void increaseZoom();
/** Signalled when the user presses a key to decrease zoom. */
void decreaseZoom();
/** Emitted when the user moves the mouse, to reflect the current block under the cursor. */
void hoverChanged(int a_BlockX, int a_BlockZ, int a_Biome);
public slots:
/** Redraw the entire widget area. */
void redraw();
/** A specified chunk has become available, redraw it. */
void chunkAvailable(int a_ChunkX, int a_ChunkZ);
/** Reloads the current chunk source and redraws the entire workspace. */
void reload();
protected:
double m_X, m_Z;
double m_Zoom;
/** Cache for the loaded chunk data. */
ChunkCache m_Cache;
/** The entire view's contents in an offscreen image. */
QImage m_Image;
/** Coords of the mouse for the previous position, used while dragging. */
int m_LastX, m_LastY;
/** Set to true when the user has a mouse button depressed, and is dragging the view. */
bool m_IsMouseDragging;
/** Accumulator for the mouse wheel's delta. When the accumulator hits a threshold, the view zooms. */
int m_MouseWheelDelta;
/** Data used for rendering a chunk that hasn't been loaded yet */
uchar m_EmptyChunkImage[16 * 16 * 4];
/** Draws the specified chunk into m_Image */
void drawChunk(int a_ChunkX, int a_ChunkZ);
/** Returns true iff the biome view has been initialized to contain proper biome data. */
bool hasData(void) const { return m_Cache.hasData(); }
/** Called when the widget is resized */
virtual void resizeEvent(QResizeEvent *) override;
/** Paints the entire widget */
virtual void paintEvent(QPaintEvent *) override;
/** Called when the user presses any mouse button. */
virtual void mousePressEvent(QMouseEvent * a_Event);
/** Called when the user moves the mouse. */
virtual void mouseMoveEvent(QMouseEvent * a_Event);
/** Called when the user releases a previously held mouse button. */
virtual void mouseReleaseEvent(QMouseEvent * a_Event) override;
/** Called when the user rotates the mouse wheel. */
virtual void wheelEvent(QWheelEvent * a_Event) override;
/** Called when the user presses a key. */
virtual void keyPressEvent(QKeyEvent * a_Event) override;
};

View File

@ -0,0 +1,126 @@
#include "Globals.h"
#include "ChunkCache.h"
#include <QMutexLocker>
#include <QThreadPool>
#include "ChunkSource.h"
#include "ChunkLoader.h"
ChunkCache::ChunkCache(QObject * parent) :
super(parent)
{
m_Cache.setMaxCost(1024 * 1024 * 1024); // 1 GiB of memory for the cache
}
ChunkPtr ChunkCache::fetch(int a_ChunkX, int a_ChunkZ)
{
// Retrieve from the cache:
quint32 hash = getChunkHash(a_ChunkX, a_ChunkZ);
ChunkPtr * res;
{
QMutexLocker lock(&m_Mtx);
res = m_Cache[hash];
// If succesful and chunk loaded, return the retrieved value:
if ((res != nullptr) && (*res)->isValid())
{
return *res;
}
}
// If the chunk is in cache but not valid, it means it has been already queued for rendering, do nothing now:
if (res != nullptr)
{
return ChunkPtr(nullptr);
}
// There's no such item in the cache, create it now:
res = new ChunkPtr(new Chunk);
if (res == nullptr)
{
return ChunkPtr(nullptr);
}
{
QMutexLocker lock(&m_Mtx);
m_Cache.insert(hash, res, sizeof(Chunk));
}
// Queue the chunk for rendering:
queueChunkRender(a_ChunkX, a_ChunkZ, *res);
// Return failure, the chunk is not yet rendered:
return ChunkPtr(nullptr);
}
void ChunkCache::setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource)
{
// Replace the chunk source:
m_ChunkSource = a_ChunkSource;
// Clear the cache:
QMutexLocker lock(&m_Mtx);
m_Cache.clear();
}
void ChunkCache::reload()
{
assert(m_ChunkSource.get() != nullptr);
// Reload the chunk source:
m_ChunkSource->reload();
// Clear the cache:
QMutexLocker lock(&m_Mtx);
m_Cache.clear();
}
void ChunkCache::gotChunk(int a_ChunkX, int a_ChunkZ)
{
emit chunkAvailable(a_ChunkX, a_ChunkZ);
}
quint32 ChunkCache::getChunkHash(int a_ChunkX, int a_ChunkZ)
{
// Simply join the two coords into a single int
// The coords will never be larger than 16-bits, so we can do this safely
return (((static_cast<quint32>(a_ChunkX) & 0xffff) << 16) | (static_cast<quint32>(a_ChunkZ) & 0xffff));
}
void ChunkCache::queueChunkRender(int a_ChunkX, int a_ChunkZ, ChunkPtr & a_Chunk)
{
// Create a new loader task:
ChunkLoader * loader = new ChunkLoader(a_ChunkX, a_ChunkZ, a_Chunk, m_ChunkSource);
connect(loader, SIGNAL(loaded(int, int)), this, SLOT(gotChunk(int, int)));
QThreadPool::globalInstance()->start(loader);
}

View File

@ -0,0 +1,72 @@
#pragma once
#include <QObject>
#include <QCache>
#include <QMutex>
#include <memory>
class Chunk;
typedef std::shared_ptr<Chunk> ChunkPtr;
class ChunkSource;
/** Caches chunk data for reuse */
class ChunkCache :
public QObject
{
typedef QObject super;
Q_OBJECT
public:
explicit ChunkCache(QObject * parent = NULL);
/** Retrieves the specified chunk from the cache.
Only returns valid chunks; if the chunk is invalid, queues it for rendering and returns an empty ptr. */
ChunkPtr fetch(int a_ChunkX, int a_ChunkZ);
/** Replaces the chunk source used by the biome view to get the chunk biome data.
The cache is then invalidated. */
void setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource);
/** Returns true iff the chunk source has been initialized. */
bool hasData() const { return (m_ChunkSource.get() != nullptr); }
/** Reloads the current chunk source. */
void reload();
signals:
void chunkAvailable(int a_ChunkX, int a_ChunkZ);
protected slots:
void gotChunk(int a_ChunkX, int a_ChunkZ);
protected:
/** The cache of the chunks */
QCache<quint32, ChunkPtr> m_Cache;
/** Locks te cache against multithreaded access */
QMutex m_Mtx;
/** The source used to get the biome data. */
std::shared_ptr<ChunkSource> m_ChunkSource;
/** Returns the hash used by the chunk in the cache */
quint32 getChunkHash(int a_ChunkX, int a_ChunkZ);
/** Queues the specified chunk for rendering by m_ChunkSource. */
void queueChunkRender(int a_ChunkX, int a_ChunkZ, ChunkPtr & a_Chunk);
};

View File

@ -0,0 +1,29 @@
#include "Globals.h"
#include "ChunkLoader.h"
#include "ChunkSource.h"
ChunkLoader::ChunkLoader(int a_ChunkX, int a_ChunkZ, ChunkPtr a_Chunk, ChunkSourcePtr a_ChunkSource) :
m_ChunkX(a_ChunkX),
m_ChunkZ(a_ChunkZ),
m_Chunk(a_Chunk),
m_ChunkSource(a_ChunkSource)
{
}
void ChunkLoader::run()
{
m_ChunkSource->getChunkBiomes(m_ChunkX, m_ChunkZ, m_Chunk);
emit loaded(m_ChunkX, m_ChunkZ);
}

View File

@ -0,0 +1,45 @@
#pragma once
#include <QObject>
#include <QRunnable>
#include <memory>
// fwd:
class Chunk;
typedef std::shared_ptr<Chunk> ChunkPtr;
class ChunkSource;
typedef std::shared_ptr<ChunkSource> ChunkSourcePtr;
class ChunkLoader :
public QObject,
public QRunnable
{
Q_OBJECT
public:
ChunkLoader(int a_ChunkX, int a_ChunkZ, ChunkPtr a_Chunk, ChunkSourcePtr a_ChunkSource);
virtual ~ChunkLoader() {}
signals:
void loaded(int a_ChunkX, int a_ChunkZ);
protected:
virtual void run() override;
private:
int m_ChunkX, m_ChunkZ;
ChunkPtr m_Chunk;
ChunkSourcePtr m_ChunkSource;
};

View File

@ -0,0 +1,284 @@
#include "Globals.h"
#include "ChunkSource.h"
#include <QThread>
#include "src/Generating/BioGen.h"
#include "src/StringCompression.h"
#include "src/WorldStorage/FastNBT.h"
#include "inifile/iniFile.h"
////////////////////////////////////////////////////////////////////////////////
// BioGenSource:
BioGenSource::BioGenSource(cIniFilePtr a_IniFile) :
m_IniFile(a_IniFile),
m_Mtx(QMutex::Recursive)
{
reload();
}
void BioGenSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk)
{
cChunkDef::BiomeMap biomes;
{
QMutexLocker lock(&m_Mtx);
m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, biomes);
}
a_DestChunk->setBiomes(biomes);
}
void BioGenSource::reload()
{
int seed = m_IniFile->GetValueSetI("Seed", "Seed", 0);
bool unused = false;
QMutexLocker lock(&m_Mtx);
m_BiomeGen.reset(cBiomeGen::CreateBiomeGen(*m_IniFile, seed, unused));
}
////////////////////////////////////////////////////////////////////////////////
// AnvilSource::AnvilFile
class AnvilSource::AnvilFile
{
public:
/** Coordinates of the region file. */
int m_RegionX, m_RegionZ;
/** True iff the file contains proper data. */
bool m_IsValid;
/** Creates a new instance with the specified region coords. Reads the file header. */
AnvilFile(int a_RegionX, int a_RegionZ, const AString & a_WorldPath) :
m_RegionX(a_RegionX),
m_RegionZ(a_RegionZ),
m_IsValid(false)
{
readFile(Printf("%s/r.%d.%d.mca", a_WorldPath.c_str(), a_RegionX, a_RegionZ));
}
/** Returns the compressed data of the specified chunk.
Returns an empty string when chunk not present. */
AString getChunkData(int a_ChunkX, int a_ChunkZ)
{
if (!m_IsValid)
{
return "";
}
// Translate to local coords:
int RelChunkX = a_ChunkX - m_RegionX * 32;
int RelChunkZ = a_ChunkZ - m_RegionZ * 32;
ASSERT((RelChunkX >= 0) && (RelChunkX < 32));
ASSERT((RelChunkZ >= 0) && (RelChunkZ < 32));
// Get the chunk data location:
UInt32 chunkOffset = m_Header[RelChunkX + 32 * RelChunkZ] >> 8;
UInt32 numChunkSectors = m_Header[RelChunkX + 32 * RelChunkZ] & 0xff;
if ((chunkOffset < 2) || (numChunkSectors == 0))
{
return "";
}
// Get the real data size:
const char * chunkData = m_FileData.data() + chunkOffset * 4096;
UInt32 chunkSize = GetBEInt(chunkData);
if ((chunkSize < 2) || (chunkSize / 4096 > numChunkSectors))
{
// Bad data, bail out
return "";
}
// Check the compression method:
if (chunkData[4] != 2)
{
// Chunk is in an unknown compression
return "";
}
chunkSize--;
// Read the chunk data:
return m_FileData.substr(chunkOffset * 4096 + 5, chunkSize);
}
protected:
AString m_FileData;
UInt32 m_Header[2048];
/** Reads the whole specified file contents and parses the header. */
void readFile(const AString & a_FileName)
{
// Read the entire file:
m_FileData = cFile::ReadWholeFile(a_FileName);
if (m_FileData.size() < sizeof(m_Header))
{
return;
}
// Parse the header - change endianness:
const char * hdr = m_FileData.data();
for (size_t i = 0; i < ARRAYCOUNT(m_Header); i++)
{
m_Header[i] = GetBEInt(hdr + 4 * i);
}
m_IsValid = true;
}
};
////////////////////////////////////////////////////////////////////////////////
// AnvilSource:
AnvilSource::AnvilSource(QString a_WorldRegionFolder) :
m_WorldRegionFolder(a_WorldRegionFolder)
{
}
void AnvilSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk)
{
// Load the compressed data:
AString compressedChunkData = getCompressedChunkData(a_ChunkX, a_ChunkZ);
if (compressedChunkData.empty())
{
return;
}
// Uncompress the chunk data:
AString uncompressed;
int res = InflateString(compressedChunkData.data(), compressedChunkData.size(), uncompressed);
if (res != Z_OK)
{
return;
}
// Parse the NBT data:
cParsedNBT nbt(uncompressed.data(), uncompressed.size());
if (!nbt.IsValid())
{
return;
}
// Get the biomes out of the NBT:
int Level = nbt.FindChildByName(0, "Level");
if (Level < 0)
{
return;
}
cChunkDef::BiomeMap biomeMap;
int mcsBiomes = nbt.FindChildByName(Level, "MCSBiomes");
if ((mcsBiomes >= 0) && (nbt.GetDataLength(mcsBiomes) == sizeof(biomeMap)))
{
// Convert the biomes from BigEndian to platform native numbers:
const char * beBiomes = nbt.GetData(mcsBiomes);
for (size_t i = 0; i < ARRAYCOUNT(biomeMap); i++)
{
biomeMap[i] = (EMCSBiome)GetBEInt(beBiomes + 4 * i);
}
a_DestChunk->setBiomes(biomeMap);
return;
}
// MCS biomes not found, load Vanilla biomes instead:
int biomes = nbt.FindChildByName(Level, "Biomes");
if ((biomes < 0) || (nbt.GetDataLength(biomes) != ARRAYCOUNT(biomeMap)))
{
return;
}
// Convert the biomes from Vanilla to EMCSBiome:
const char * vanillaBiomes = nbt.GetData(biomes);
for (size_t i = 0; i < ARRAYCOUNT(biomeMap); i++)
{
biomeMap[i] = EMCSBiome(vanillaBiomes[i]);
}
a_DestChunk->setBiomes(biomeMap);
}
void AnvilSource::reload()
{
// Remove all files from the cache:
QMutexLocker lock(&m_Mtx);
m_Files.clear();
}
void AnvilSource::chunkToRegion(int a_ChunkX, int a_ChunkZ, int & a_RegionX, int & a_RegionZ)
{
a_RegionX = a_ChunkX >> 5;
a_RegionZ = a_ChunkZ >> 5;
}
AString AnvilSource::getCompressedChunkData(int a_ChunkX, int a_ChunkZ)
{
return getAnvilFile(a_ChunkX, a_ChunkZ)->getChunkData(a_ChunkX, a_ChunkZ);
}
AnvilSource::AnvilFilePtr AnvilSource::getAnvilFile(int a_ChunkX, int a_ChunkZ)
{
int RegionX, RegionZ;
chunkToRegion(a_ChunkX, a_ChunkZ, RegionX, RegionZ);
// Search the cache for the file:
QMutexLocker lock(&m_Mtx);
for (auto itr = m_Files.cbegin(), end = m_Files.cend(); itr != end; ++itr)
{
if (((*itr)->m_RegionX == RegionX) && ((*itr)->m_RegionZ == RegionZ))
{
// Found the file in the cache, move it to front and return it:
AnvilFilePtr file(*itr);
m_Files.erase(itr);
m_Files.push_front(file);
return file;
}
}
// File not in cache, create it:
AnvilFilePtr file(new AnvilFile(RegionX, RegionZ, m_WorldRegionFolder.toStdString()));
m_Files.push_front(file);
return file;
}

View File

@ -0,0 +1,107 @@
#pragma once
#include "Globals.h"
#include <QString>
#include <QMutex>
#include "QtChunk.h"
// fwd:
class cBiomeGen;
typedef std::shared_ptr<cBiomeGen> cBiomeGenPtr;
class cIniFile;
typedef std::shared_ptr<cIniFile> cIniFilePtr;
/** Abstract interface for getting biome data for chunks. */
class ChunkSource
{
public:
virtual ~ChunkSource() {}
/** Fills the a_DestChunk with the biomes for the specified coords.
It is expected to be thread-safe and re-entrant. Usually QThread::idealThreadCount() threads are used. */
virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) = 0;
/** Forces a fresh reload of the source. Useful mainly for the generator, whose underlying definition file may have been changed. */
virtual void reload() = 0;
};
class BioGenSource :
public ChunkSource
{
public:
/** Constructs a new BioGenSource based on the biome generator that is defined in the specified world.ini file. */
BioGenSource(cIniFilePtr a_IniFile);
// ChunkSource overrides:
virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) override;
virtual void reload(void) override;
protected:
/** The world.ini contents from which the generator is created and re-created on reload(). */
cIniFilePtr m_IniFile;
/** The generator used for generating biomes. */
std::unique_ptr<cBiomeGen> m_BiomeGen;
/** Guards m_BiomeGen against multithreaded access. */
QMutex m_Mtx;
};
class AnvilSource :
public ChunkSource
{
public:
/** Constructs a new AnvilSource based on the world path. */
AnvilSource(QString a_WorldRegionFolder);
// ChunkSource overrides:
virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) override;
virtual void reload() override;
protected:
class AnvilFile;
typedef std::shared_ptr<AnvilFile> AnvilFilePtr;
/** Folder where the individual Anvil Region files are located. */
QString m_WorldRegionFolder;
/** List of currently loaded files. Acts as a cache so that a file is not opened and closed over and over again.
Protected against multithreaded access by m_Mtx. */
std::list<AnvilFilePtr> m_Files;
/** Guards m_Files agains multithreaded access. */
QMutex m_Mtx;
/** Converts chunk coords to region coords. */
void chunkToRegion(int a_ChunkX, int a_ChunkZ, int & a_RegionX, int & a_RegionZ);
/** Returns the compressed data of the specified chunk.
Returns an empty string if the chunk is not available. */
AString getCompressedChunkData(int a_ChunkX, int a_ChunkZ);
/** Returns the file object that contains the specified chunk.
The file is taken from the cache if available there, otherwise it is created anew. */
AnvilFilePtr getAnvilFile(int a_ChunkX, int a_ChunkZ);
};

View File

@ -0,0 +1,158 @@
#include "Globals.h"
#include "GeneratorSetup.h"
#include <QLabel>
#include <QLineEdit>
#include "src/Generating/BioGen.h"
#include "inifile/iniFile.h"
static const QString s_GeneratorNames[] =
{
QString("Checkerboard"),
QString("Constant"),
QString("DistortedVoronoi"),
QString("MultiStepMap"),
QString("TwoLevel"),
QString("Voronoi"),
};
GeneratorSetup::GeneratorSetup(const AString & a_IniFileName, QWidget * a_Parent) :
super(a_Parent),
m_IniFile(new cIniFile())
{
// The seed and generator name is in a separate form layout at the top, always present:
m_eSeed = new QLineEdit();
m_eSeed->setValidator(new QIntValidator());
m_eSeed->setText("0");
m_eSeed->setProperty("INI.SectionName", QVariant("Seed"));
m_eSeed->setProperty("INI.ItemName", QVariant("Seed"));
m_cbGenerator = new QComboBox();
m_cbGenerator->setMinimumWidth(120);
for (size_t i = 0; i < ARRAYCOUNT(s_GeneratorNames); i++)
{
m_cbGenerator->addItem(s_GeneratorNames[i]);
}
QFormLayout * baseLayout = new QFormLayout();
baseLayout->addRow(new QLabel(tr("Seed")), m_eSeed);
baseLayout->addRow(new QLabel(tr("Generator")), m_cbGenerator);
// The rest of the controls are in a dynamically created form layout:
m_FormLayout = new QFormLayout();
// The main layout joins these two vertically:
m_MainLayout = new QVBoxLayout();
m_MainLayout->addLayout(baseLayout);
m_MainLayout->addLayout(m_FormLayout);
m_MainLayout->addStretch();
setLayout(m_MainLayout);
// Load the INI file, if specified, otherwise set defaults:
if (a_IniFileName.empty() || !m_IniFile->ReadFile(a_IniFileName))
{
m_IniFile->SetValue("Generator", "Generator", "Composable");
m_IniFile->SetValue("Generator", "BiomeGen", m_cbGenerator->currentText().toStdString());
bool dummy;
delete cBiomeGen::CreateBiomeGen(*m_IniFile, 0, dummy);
}
updateFromIni();
// Connect the change events only after the data has been loaded:
connect(m_cbGenerator, SIGNAL(currentIndexChanged(QString)), this, SLOT(generatorChanged(QString)));
connect(m_eSeed, SIGNAL(textChanged(QString)), this, SLOT(editChanged(QString)));
}
void GeneratorSetup::generatorChanged(const QString & a_NewName)
{
// Clear the current contents of the form layout by assigning it to a stack temporary:
{
m_MainLayout->takeAt(1);
QWidget().setLayout(m_FormLayout);
}
// Re-create the layout:
m_FormLayout = new QFormLayout();
m_MainLayout->insertLayout(1, m_FormLayout);
// Recreate the INI file:
m_IniFile->Clear();
m_IniFile->SetValue("Generator", "Generator", "Composable");
m_IniFile->SetValue("Generator", "BiomeGen", a_NewName.toStdString());
// Create a dummy biome gen from the INI file, this will create the defaults in the INI file:
bool dummy;
delete cBiomeGen::CreateBiomeGen(*m_IniFile, m_Seed, dummy);
// Read all values from the INI file and put them into the form layout:
updateFromIni();
// Notify of the changes:
emit generatorUpdated();
}
void GeneratorSetup::editChanged(const QString & a_NewValue)
{
QString sectionName = sender()->property("INI.SectionName").toString();
QString itemName = sender()->property("INI.ItemName").toString();
m_IniFile->SetValue(sectionName.toStdString(), itemName.toStdString(), a_NewValue.toStdString());
emit generatorUpdated();
}
void GeneratorSetup::updateFromIni()
{
m_eSeed->setText(QString::number(m_IniFile->GetValueI("Seed", "Seed", 0)));
int keyID = m_IniFile->FindKey("Generator");
if (keyID <= -1)
{
return;
}
int numItems = m_IniFile->GetNumValues(keyID);
AString generatorName = m_IniFile->GetValue("Generator", "BiomeGen");
size_t generatorNameLen = generatorName.length();
for (int i = 0; i < numItems; i++)
{
AString itemName = m_IniFile->GetValueName(keyID, i);
if ((itemName == "Generator") || (itemName == "BiomeGen"))
{
// These special cases are not to be added
continue;
}
AString itemValue = m_IniFile->GetValue(keyID, i);
QLineEdit * edit = new QLineEdit();
edit->setText(QString::fromStdString(itemValue));
edit->setProperty("INI.SectionName", QVariant("Generator"));
edit->setProperty("INI.ItemName", QVariant(QString::fromStdString(itemName)));
// Remove the generator name prefix from the item name, for clarity purposes:
if (NoCaseCompare(itemName.substr(0, generatorNameLen), generatorName) == 0)
{
itemName.erase(0, generatorNameLen);
}
connect(edit, SIGNAL(textChanged(QString)), this, SLOT(editChanged(QString)));
m_FormLayout->addRow(new QLabel(QString::fromStdString(itemName)), edit);
} // for i - INI values[]
}

View File

@ -0,0 +1,64 @@
#pragma once
#include <memory>
#include <QDialog>
#include <QComboBox>
#include <QVBoxLayout>
#include <QFormLayout>
class cIniFile;
typedef std::shared_ptr<cIniFile> cIniFilePtr;
class GeneratorSetup :
public QWidget
{
typedef QWidget super;
Q_OBJECT
public:
/** Creates the widget and loads the contents of the INI file, if not empty. */
explicit GeneratorSetup(const std::string & a_IniFileName, QWidget * parent = nullptr);
/** Returns the cIniFile instance that is being edited by this widget. */
cIniFilePtr getIniFile() { return m_IniFile; }
signals:
/** Emitted when the generator parameters have changed. */
void generatorUpdated();
public slots:
/** Called when the user selects a different generator from the top combobox.
Re-creates m_IniFile and updates the form layout. */
void generatorChanged(const QString & a_NewName);
protected slots:
/** Called when any of the edit widgets are changed. */
void editChanged(const QString & a_NewValue);
protected:
QComboBox * m_cbGenerator;
QLineEdit * m_eSeed;
QVBoxLayout * m_MainLayout;
QFormLayout * m_FormLayout;
cIniFilePtr m_IniFile;
int m_Seed;
/** Updates the form layout with the values from m_IniFile. */
void updateFromIni();
};

View File

@ -0,0 +1,395 @@
#pragma once
// Compiler-dependent stuff:
#if defined(_MSC_VER)
// MSVC produces warning C4481 on the override keyword usage, so disable the warning altogether
#pragma warning(disable:4481)
// Disable some warnings that we don't care about:
#pragma warning(disable:4100) // Unreferenced formal parameter
// Useful warnings from warning level 4:
#pragma warning(3 : 4127) // Conditional expression is constant
#pragma warning(3 : 4189) // Local variable is initialized but not referenced
#pragma warning(3 : 4245) // Conversion from 'type1' to 'type2', signed/unsigned mismatch
#pragma warning(3 : 4310) // Cast truncates constant value
#pragma warning(3 : 4389) // Signed/unsigned mismatch
#pragma warning(3 : 4505) // Unreferenced local function has been removed
#pragma warning(3 : 4701) // Potentially unitialized local variable used
#pragma warning(3 : 4702) // Unreachable code
#pragma warning(3 : 4706) // Assignment within conditional expression
// Disabling this warning, because we know what we're doing when we're doing this:
#pragma warning(disable: 4355) // 'this' used in initializer list
// Disabled because it's useless:
#pragma warning(disable: 4512) // 'class': assignment operator could not be generated - reported for each class that has a reference-type member
// 2014_01_06 xoft: Disabled this warning because MSVC is stupid and reports it in obviously wrong places
// #pragma warning(3 : 4244) // Conversion from 'type1' to 'type2', possible loss of data
#define OBSOLETE __declspec(deprecated)
// 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__)
// TODO: Can GCC explicitly mark classes as abstract (no instances can be created)?
#define abstract
// override is part of c++11
#if __cplusplus < 201103L
#define override
#endif
#define OBSOLETE __attribute__((deprecated))
#define ALIGN_8 __attribute__((aligned(8)))
#define ALIGN_16 __attribute__((aligned(16)))
// Some portability macros :)
#define stricmp strcasecmp
#define FORMATSTRING(formatIndex, va_argsIndex) __attribute__((format (printf, formatIndex, va_argsIndex)))
#if defined(_WIN32)
// We're compiling on MinGW, which uses an old MSVCRT library that has no support for size_t printfing.
// We need direct size formats:
#if defined(_WIN64)
#define SIZE_T_FMT "%I64u"
#define SIZE_T_FMT_PRECISION(x) "%" #x "I64u"
#define SIZE_T_FMT_HEX "%I64x"
#else
#define SIZE_T_FMT "%u"
#define SIZE_T_FMT_PRECISION(x) "%" #x "u"
#define SIZE_T_FMT_HEX "%x"
#endif
#else
// We're compiling on Linux, so we can use libc's size_t printf format:
#define SIZE_T_FMT "%zu"
#define SIZE_T_FMT_PRECISION(x) "%" #x "zu"
#define SIZE_T_FMT_HEX "%zx"
#endif
#define NORETURN __attribute((__noreturn__))
#else
#error "You are using an unsupported compiler, you might need to #define some stuff here for your compiler"
/*
// Copy and uncomment this into another #elif section based on your compiler identification
// Explicitly mark classes as abstract (no instances can be created)
#define abstract
// Mark virtual methods as overriding (forcing them to have a virtual function of the same signature in the base class)
#define override
// Mark functions as obsolete, so that their usage results in a compile-time warning
#define OBSOLETE
// Mark types / variables for alignment. Do the platforms need it?
#define ALIGN_8
#define ALIGN_16
*/
#endif
#ifdef _DEBUG
#define NORETURNDEBUG NORETURN
#else
#define NORETURNDEBUG
#endif
#include <stddef.h>
// Integral types with predefined sizes:
typedef long long Int64;
typedef int Int32;
typedef short Int16;
typedef unsigned long long UInt64;
typedef unsigned int UInt32;
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
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName &); \
void operator =(const TypeName &)
// A macro that is used to mark unused local variables, to avoid pedantic warnings in gcc / clang / MSVC
// Note that in MSVC it requires the full type of X to be known
#define UNUSED_VAR(X) (void)(X)
// A macro that is used to mark unused function parameters, to avoid pedantic warnings in gcc
// Written so that the full type of param needn't be known
#ifdef _MSC_VER
#define UNUSED(X)
#else
#define UNUSED UNUSED_VAR
#endif
// OS-dependent stuff:
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x501 // We want to target WinXP and higher
#include <Windows.h>
#include <winsock2.h>
#include <Ws2tcpip.h> // IPv6 stuff
// Windows SDK defines min and max macros, messing up with our std::min and std::max usage
#undef min
#undef max
// Windows SDK defines GetFreeSpace as a constant, probably a Win16 API remnant
#ifdef GetFreeSpace
#undef GetFreeSpace
#endif // GetFreeSpace
#else
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <dirent.h>
#include <errno.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
#include <fcntl.h>
#endif
#if defined(ANDROID_NDK)
#define FILE_IO_PREFIX "/sdcard/mcserver/"
#else
#define FILE_IO_PREFIX ""
#endif
// CRT stuff:
#include <sys/stat.h>
#include <assert.h>
#include <stdio.h>
#include <math.h>
#include <stdarg.h>
// STL stuff:
#include <vector>
#include <list>
#include <deque>
#include <string>
#include <map>
#include <algorithm>
#include <memory>
#include <set>
#include <queue>
#include <limits>
#ifndef TEST_GLOBALS
// Common headers (part 1, without macros):
#include "src/StringUtils.h"
#include "src/OSSupport/Sleep.h"
#include "src/OSSupport/CriticalSection.h"
#include "src/OSSupport/Semaphore.h"
#include "src/OSSupport/Event.h"
#include "src/OSSupport/Thread.h"
#include "src/OSSupport/File.h"
#include "src/Logger.h"
#else
// Logging functions
void inline LOGERROR(const char* a_Format, ...) FORMATSTRING(1, 2);
void inline LOGERROR(const char* a_Format, ...)
{
va_list argList;
va_start(argList, a_Format);
vprintf(a_Format, argList);
va_end(argList);
}
#endif
// Common definitions:
/// Evaluates to the number of elements in an array (compile-time!)
#define ARRAYCOUNT(X) (sizeof(X) / sizeof(*(X)))
/// Allows arithmetic expressions like "32 KiB" (but consider using parenthesis around it, "(32 KiB)")
#define KiB * 1024
#define MiB * 1024 * 1024
/// Faster than (int)floorf((float)x / (float)div)
#define FAST_FLOOR_DIV( x, div) (((x) - (((x) < 0) ? ((div) - 1) : 0)) / (div))
// Own version of assert() that writes failed assertions to the log for review
#ifdef TEST_GLOBALS
class cAssertFailure
{
};
#ifdef _WIN32
#if (defined(_MSC_VER) && defined(_DEBUG))
#define DBG_BREAK _CrtDbgBreak()
#else
#define DBG_BREAK
#endif
#define REPORT_ERROR(FMT, ...) \
{ \
AString msg = Printf(FMT, __VA_ARGS__); \
puts(msg.c_str()); \
fflush(stdout); \
OutputDebugStringA(msg.c_str()); \
DBG_BREAK; \
}
#else
#define REPORT_ERROR(FMT, ...) \
{ \
AString msg = Printf(FMT, __VA_ARGS__); \
puts(msg.c_str()); \
fflush(stdout); \
}
#endif
#define ASSERT(x) do { if (!(x)) { throw cAssertFailure();} } while (0)
#define testassert(x) do { if (!(x)) { REPORT_ERROR("Test failure: %s, file %s, line %d\n", #x, __FILE__, __LINE__); exit(1); } } while (0)
#define CheckAsserts(x) do { try {x} catch (cAssertFailure) { break; } REPORT_ERROR("Test failure: assert didn't fire for %s, file %s, line %d\n", #x, __FILE__, __LINE__); exit(1); } while (0)
#else
#ifdef _DEBUG
#define ASSERT( x) ( !!(x) || ( LOGERROR("Assertion failed: %s, file %s, line %i", #x, __FILE__, __LINE__), assert(0), 0))
#else
#define ASSERT(x) ((void)(x))
#endif
#endif
// 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
// Allow both Older versions of MSVC and newer versions of everything use a shared_ptr:
// Note that we cannot typedef, because C++ doesn't allow (partial) templates to be typedeffed.
#if (defined(_MSC_VER) && (_MSC_VER < 1600))
// MSVC before 2010 doesn't have std::shared_ptr, but has std::tr1::shared_ptr, defined in <memory> included earlier
#define SharedPtr std::tr1::shared_ptr
#elif (defined(_MSC_VER) || (__cplusplus >= 201103L))
// C++11 has std::shared_ptr in <memory>, included earlier
#define SharedPtr std::shared_ptr
#else
// C++03 has std::tr1::shared_ptr in <tr1/memory>
#include <tr1/memory>
#define SharedPtr std::tr1::shared_ptr
#endif
/** A generic interface used mainly in ForEach() functions */
template <typename Type> class cItemCallback
{
public:
virtual ~cItemCallback() {}
/** Called for each item in the internal list; return true to stop the loop, or false to continue enumerating */
virtual bool Item(Type * a_Type) = 0;
} ;
/** Clamp X to the specified range. */
template <typename T>
T Clamp(T a_Value, T a_Min, T a_Max)
{
return (a_Value < a_Min) ? a_Min : ((a_Value > a_Max) ? a_Max : a_Value);
}
#ifndef TOLUA_TEMPLATE_BIND
#define TOLUA_TEMPLATE_BIND(x)
#endif
// Common headers (part 2, with macros):
#include "src/ChunkDef.h"
#include "src/BiomeDef.h"
#include "src/BlockID.h"
#include "src/BlockInfo.h"

View File

@ -0,0 +1,440 @@
#include "Globals.h"
#include "MainWindow.h"
#include <QVBoxLayout>
#include <QAction>
#include <QMenuBar>
#include <QApplication>
#include <QFileDialog>
#include <QSettings>
#include <QDirIterator>
#include <QStatusBar>
#include "inifile/iniFile.h"
#include "ChunkSource.h"
#include "src/Generating/BioGen.h"
#include "src/StringCompression.h"
#include "src/WorldStorage/FastNBT.h"
#include "GeneratorSetup.h"
const double MainWindow::m_ViewZooms[] =
{
0.0625, 0.125, 0.25, 0.5, 1, 2, 4, 8, 16, 24,
};
MainWindow::MainWindow(QWidget * parent) :
QMainWindow(parent),
m_GeneratorSetup(nullptr),
m_LineSeparator(nullptr)
{
initMinecraftPath();
m_BiomeView = new BiomeView();
connect(m_BiomeView, SIGNAL(increaseZoom()), this, SLOT(increaseZoom()));
connect(m_BiomeView, SIGNAL(decreaseZoom()), this, SLOT(decreaseZoom()));
connect(m_BiomeView, SIGNAL(wheelUp()), this, SLOT(increaseZoom()));
connect(m_BiomeView, SIGNAL(wheelDown()), this, SLOT(decreaseZoom()));
m_StatusBar = new QStatusBar();
this->setStatusBar(m_StatusBar);
m_StatusBlockX = new QLabel(tr("X"));
m_StatusBlockZ = new QLabel(tr("Z"));
m_StatusBiome = new QLabel(tr("B"));
m_StatusBar->addPermanentWidget(m_StatusBlockX);
m_StatusBar->addPermanentWidget(m_StatusBlockZ);
m_StatusBar->addPermanentWidget(m_StatusBiome);
m_MainLayout = new QHBoxLayout();
m_MainLayout->addWidget(m_BiomeView, 1);
m_MainLayout->setMenuBar(menuBar());
m_MainLayout->setMargin(0);
QWidget * central = new QWidget();
central->setLayout(m_MainLayout);
setCentralWidget(central);
createActions();
createMenus();
connect(m_BiomeView, SIGNAL(hoverChanged(int, int, int)), this, SLOT(hoverChanged(int, int, int)));
}
MainWindow::~MainWindow()
{
}
void MainWindow::newGenerator()
{
// (Re-)open the generator setup dialog with empty settings:
openGeneratorSetup("");
// Set the chunk source:
cIniFilePtr iniFile = m_GeneratorSetup->getIniFile();
m_BiomeView->setChunkSource(std::shared_ptr<BioGenSource>(new BioGenSource(iniFile)));
m_BiomeView->redraw();
}
void MainWindow::openGenerator()
{
// Let the user specify the world.ini file:
QString worldIni = QFileDialog::getOpenFileName(this, tr("Open world.ini"), QString(), tr("world.ini (world.ini)"));
if (worldIni.isEmpty())
{
return;
}
// (Re-)open the generator setup dialog:
openGeneratorSetup(worldIni.toStdString());
// Set the chunk source:
m_BiomeView->setChunkSource(std::shared_ptr<BioGenSource>(new BioGenSource(m_GeneratorSetup->getIniFile())));
m_BiomeView->redraw();
}
void MainWindow::openWorld()
{
// Let the user specify the world:
QString regionFolder = QFileDialog::getExistingDirectory(this, tr("Select the region folder"), QString());
if (regionFolder.isEmpty())
{
return;
}
// Remove the generator setup dialog, if open:
closeGeneratorSetup();
// Set the chunk source:
m_BiomeView->setChunkSource(std::shared_ptr<AnvilSource>(new AnvilSource(regionFolder)));
m_BiomeView->redraw();
}
void MainWindow::openVanillaWorld()
{
// The world is stored in the sender action's data, retrieve it:
QAction * action = qobject_cast<QAction *>(sender());
if (action == nullptr)
{
return;
}
// Remove the generator setup dialog, if open:
closeGeneratorSetup();
// Set the chunk source:
m_BiomeView->setChunkSource(std::shared_ptr<AnvilSource>(new AnvilSource(action->data().toString())));
m_BiomeView->redraw();
}
void MainWindow::centerView()
{
m_BiomeView->setPosition(0, 0);
}
void MainWindow::setViewZoom()
{
// The zoom level is stored in the sender action's data, retrieve it:
QAction * action = qobject_cast<QAction *>(sender());
if (action == nullptr)
{
return;
}
double newZoom = m_ViewZooms[action->data().toInt()];
m_BiomeView->setZoomLevel(newZoom);
action->setChecked(true);
}
void MainWindow::increaseZoom()
{
// If already at max zoom, bail out:
if (m_CurrentZoomLevel >= ARRAYCOUNT(m_ViewZooms) - 1)
{
return;
}
// Increase the zoom level:
m_CurrentZoomLevel += 1;
m_actViewZoom[m_CurrentZoomLevel]->setChecked(true);
m_BiomeView->setZoomLevel(m_ViewZooms[m_CurrentZoomLevel]);
}
void MainWindow::decreaseZoom()
{
// If already at min zoom, bail out:
if (m_CurrentZoomLevel == 0)
{
return;
}
// Decrease the zoom level:
m_CurrentZoomLevel -= 1;
m_actViewZoom[m_CurrentZoomLevel]->setChecked(true);
m_BiomeView->setZoomLevel(m_ViewZooms[m_CurrentZoomLevel]);
}
void MainWindow::hoverChanged(int a_BlockX, int a_BlockZ, int a_Biome)
{
m_StatusBlockX->setText(tr("X: %1").arg(a_BlockX));
m_StatusBlockZ->setText(tr("Z: %1").arg(a_BlockZ));
m_StatusBiome->setText (tr("B: %1 (%2)").arg(BiomeToString(a_Biome).c_str()).arg(a_Biome));
}
void MainWindow::initMinecraftPath()
{
#ifdef Q_OS_MAC
m_MinecraftPath = QDir::homePath() + QDir::toNativeSeparators("/Library/Application Support/minecraft");
#elif defined Q_OS_WIN32
QSettings ini(QSettings::IniFormat, QSettings::UserScope, ".minecraft", "minecraft1");
m_MinecraftPath = QFileInfo(ini.fileName()).absolutePath();
#else
m_MinecraftPath = QDir::homePath() + QDir::toNativeSeparators("/.minecraft");
#endif
}
void MainWindow::createActions()
{
// Map menu:
createWorldActions();
m_actNewGen = new QAction(tr("&New generator"), this);
m_actNewGen->setShortcut(tr("Ctrl+N"));
m_actNewGen->setStatusTip(tr("Open a generator INI file and display the generated biomes"));
connect(m_actNewGen, SIGNAL(triggered()), this, SLOT(newGenerator()));
m_actOpenGen = new QAction(tr("&Open generator..."), this);
m_actOpenGen->setShortcut(tr("Ctrl+G"));
m_actOpenGen->setStatusTip(tr("Open a generator INI file and display the generated biomes"));
connect(m_actOpenGen, SIGNAL(triggered()), this, SLOT(openGenerator()));
m_actOpenWorld = new QAction(tr("&Open world..."), this);
m_actOpenWorld->setShortcut(tr("Ctrl+O"));
m_actOpenWorld->setStatusTip(tr("Open an existing world and display its biomes"));
connect(m_actOpenWorld, SIGNAL(triggered()), this, SLOT(openWorld()));
m_actReload = new QAction(tr("&Reload"), this);
m_actReload->setShortcut(tr("F5"));
m_actReload->setStatusTip(tr("Clear the view cache and force a reload of all the data"));
connect(m_actReload, SIGNAL(triggered()), m_BiomeView, SLOT(reload()));
m_actExit = new QAction(tr("E&xit"), this);
m_actExit->setShortcut(tr("Alt+X"));
m_actExit->setStatusTip(tr("Exit %1").arg(QApplication::instance()->applicationName()));
connect(m_actExit, SIGNAL(triggered()), this, SLOT(close()));
// View menu:
m_actViewCenter = new QAction(tr("&Reset to center"), this);
m_actViewCenter->setStatusTip(tr("Scrolls the view back to the map center"));
connect(m_actViewCenter, SIGNAL(triggered()), this, SLOT(centerView()));
QActionGroup * zoomGroup = new QActionGroup(this);
for (int i = 0; i < ARRAYCOUNT(m_ViewZooms); i++)
{
m_actViewZoom[i] = new QAction(tr("&Zoom %1%").arg(std::floor(m_ViewZooms[i] * 100)), this);
m_actViewZoom[i]->setCheckable(true);
if ((int)(m_ViewZooms[i] * 16) == 16)
{
m_actViewZoom[i]->setChecked(true);
m_CurrentZoomLevel = i;
}
m_actViewZoom[i]->setData(QVariant(i));
zoomGroup->addAction(m_actViewZoom[i]);
connect(m_actViewZoom[i], SIGNAL(triggered()), this, SLOT(setViewZoom()));
}
}
void MainWindow::createWorldActions()
{
QDir mc(m_MinecraftPath);
if (!mc.cd("saves"))
{
return;
}
QDirIterator it(mc);
int key = 1;
while (it.hasNext())
{
it.next();
if (!it.fileInfo().isDir())
{
continue;
}
QString name = getWorldName(it.filePath().toStdString());
if (name.isEmpty())
{
continue;
}
QAction * w = new QAction(this);
w->setText(name);
w->setData(it.filePath() + "/region");
if (key < 10)
{
w->setShortcut("Ctrl+" + QString::number(key));
key++;
}
connect(w, SIGNAL(triggered()), this, SLOT(openVanillaWorld()));
m_WorldActions.append(w);
}
}
void MainWindow::createMenus()
{
// Map menu:
QMenu * file = menuBar()->addMenu(tr("&Map"));
file->addAction(m_actNewGen);
file->addAction(m_actOpenGen);
file->addSeparator();
QMenu * worlds = file->addMenu(tr("Open &existing"));
worlds->addActions(m_WorldActions);
if (m_WorldActions.empty())
{
worlds->setEnabled(false);
}
file->addAction(m_actOpenWorld);
file->addSeparator();
file->addAction(m_actReload);
file->addSeparator();
file->addAction(m_actExit);
// View menu:
QMenu * view = menuBar()->addMenu(tr("&View"));
view->addAction(m_actViewCenter);
view->addSeparator();
for (size_t i = 0; i < ARRAYCOUNT(m_actViewZoom); i++)
{
view->addAction(m_actViewZoom[i]);
}
}
QString MainWindow::getWorldName(const AString & a_Path)
{
AString levelData = cFile::ReadWholeFile(a_Path + "/level.dat");
if (levelData.empty())
{
// No such file / no data
return QString();
}
AString uncompressed;
if (UncompressStringGZIP(levelData.data(), levelData.size(), uncompressed) != Z_OK)
{
return QString();
}
cParsedNBT nbt(uncompressed.data(), uncompressed.size());
if (!nbt.IsValid())
{
return QString();
}
AString name = nbt.GetName(1);
int levelNameTag = nbt.FindTagByPath(nbt.GetRoot(), "Data\\LevelName");
if ((levelNameTag <= 0) || (nbt.GetType(levelNameTag) != TAG_String))
{
return QString();
}
return QString::fromStdString(nbt.GetString(levelNameTag));
}
void MainWindow::openGeneratorSetup(const AString & a_IniFileName)
{
// Close any previous editor:
closeGeneratorSetup();
// Open up a new editor:
m_GeneratorSetup = new GeneratorSetup(a_IniFileName);
m_LineSeparator = new QWidget();
m_LineSeparator->setFixedWidth(2);
m_LineSeparator->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
m_LineSeparator->setStyleSheet(QString("background-color: #c0c0c0;"));
m_MainLayout->addWidget(m_LineSeparator);
m_MainLayout->addWidget(m_GeneratorSetup);
// Connect the signals from the setup pane:
connect(m_GeneratorSetup, SIGNAL(generatorUpdated()), m_BiomeView, SLOT(reload()));
}
void MainWindow::closeGeneratorSetup()
{
delete m_MainLayout->takeAt(2);
delete m_MainLayout->takeAt(1);
delete m_GeneratorSetup;
delete m_LineSeparator;
m_GeneratorSetup = nullptr;
m_LineSeparator = nullptr;
}

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