1
0

Merge branch 'master' into Inventory

This commit is contained in:
Howaner 2015-01-25 00:34:19 +01:00
commit 1eedccc56a
232 changed files with 5200 additions and 1556 deletions

1
.gitignore vendored
View File

@ -3,6 +3,7 @@ nbproject/
ipch/ ipch/
Win32/ Win32/
MCServer/MCServer MCServer/MCServer
MCServer/itemblacklist
ChunkWorxSave.ini ChunkWorxSave.ini
doxy/ doxy/
Profiling Profiling

3
.gitmodules vendored
View File

@ -25,3 +25,6 @@
[submodule "lib/SQLiteCpp"] [submodule "lib/SQLiteCpp"]
path = lib/SQLiteCpp path = lib/SQLiteCpp
url = https://github.com/mc-server/SQLiteCpp.git url = https://github.com/mc-server/SQLiteCpp.git
[submodule "lib/libevent"]
path = lib/libevent
url = https://github.com/mc-server/libevent.git

View File

@ -13,6 +13,9 @@ before_install:
install: install:
# g++4.8 and clang # g++4.8 and clang
- sudo apt-get install -qq g++-4.8 - sudo apt-get install -qq g++-4.8
# lua, needed for style checking and possibly later on for bindings generation
- sudo apt-get install -qq lua5.1
# g++4.8 # g++4.8
- if [ "$CXX" == "g++" ]; then export CXX="g++-4.8"; export CC="gcc-4.8"; fi - if [ "$CXX" == "g++" ]; then export CXX="g++-4.8"; export CC="gcc-4.8"; fi

View File

@ -7,6 +7,9 @@ export MCSERVER_BUILD_ID=$TRAVIS_JOB_NUMBER
export MCSERVER_BUILD_DATETIME=`date` export MCSERVER_BUILD_DATETIME=`date`
cmake . -DBUILD_TOOLS=1 -DSELF_TEST=1; cmake . -DBUILD_TOOLS=1 -DSELF_TEST=1;
cd src
lua CheckBasicStyle.lua
cd ..
make -j 2; make -j 2;
make -j 2 test; make -j 2 test;
cd MCServer/; cd MCServer/;

View File

@ -95,6 +95,24 @@ set(SQLITECPP_BUILD_EXAMPLES OFF CACHE BOOL "Build examples."
set(SQLITECPP_BUILD_TESTS OFF CACHE BOOL "Build and run tests." 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) set(SQLITECPP_INTERNAL_SQLITE OFF CACHE BOOL "Add the internal SQLite3 source to the project." FORCE)
# Set options for LibEvent, disable all their tests and benchmarks:
set(EVENT__DISABLE_OPENSSL YES CACHE BOOL "Disable OpenSSL in LibEvent" FORCE)
set(EVENT__DISABLE_BENCHMARK YES CACHE BOOL "Disable LibEvent benchmarks" FORCE)
set(EVENT__DISABLE_TESTS YES CACHE BOOL "Disable LibEvent tests" FORCE)
set(EVENT__DISABLE_REGRESS YES CACHE BOOL "Disable LibEvent regression tests" FORCE)
set(EVENT__DISABLE_SAMPLES YES CACHE BOOL "Disable LibEvent samples" FORCE)
# Check that the libraries are present:
if (NOT EXISTS ${CMAKE_SOURCE_DIR}/lib/SQLiteCpp/CMakeLists.txt)
message(FATAL_ERROR "SQLiteCpp is missing in folder lib/SQLiteCpp. Have you initialized the submodules / downloaded the extra libraries?")
endif()
if (NOT EXISTS ${CMAKE_SOURCE_DIR}/lib/polarssl/CMakeLists.txt)
message(FATAL_ERROR "PolarSSL is missing in folder lib/polarssl. Have you initialized the submodules / downloaded the extra libraries?")
endif()
if (NOT EXISTS ${CMAKE_SOURCE_DIR}/lib/libevent/CMakeLists.txt)
message(FATAL_ERROR "LibEvent is missing in folder lib/libevent. Have you initialized and updated the submodules / downloaded the extra libraries?")
endif()
# Include all the libraries: # Include all the libraries:
add_subdirectory(lib/jsoncpp/) add_subdirectory(lib/jsoncpp/)
add_subdirectory(lib/zlib/) add_subdirectory(lib/zlib/)
@ -104,6 +122,7 @@ add_subdirectory(lib/sqlite/)
add_subdirectory(lib/SQLiteCpp/) add_subdirectory(lib/SQLiteCpp/)
add_subdirectory(lib/expat/) add_subdirectory(lib/expat/)
add_subdirectory(lib/luaexpat/) add_subdirectory(lib/luaexpat/)
add_subdirectory(lib/libevent/)
# Add proper include directories so that SQLiteCpp can find SQLite3: # Add proper include directories so that SQLiteCpp can find SQLite3:
get_property(SQLITECPP_INCLUDES DIRECTORY "lib/SQLiteCpp/" PROPERTY INCLUDE_DIRECTORIES) get_property(SQLITECPP_INCLUDES DIRECTORY "lib/SQLiteCpp/" PROPERTY INCLUDE_DIRECTORIES)
@ -111,6 +130,9 @@ set(SQLITECPP_INCLUDES "${SQLITECPP_INCLUDES}" "${CMAKE_CURRENT_SOURCE_DIR}/lib/
set_property(DIRECTORY lib/SQLiteCpp/ PROPERTY INCLUDE_DIRECTORIES "${SQLITECPP_INCLUDES}") set_property(DIRECTORY lib/SQLiteCpp/ PROPERTY INCLUDE_DIRECTORIES "${SQLITECPP_INCLUDES}")
set_property(TARGET SQLiteCpp PROPERTY INCLUDE_DIRECTORIES "${SQLITECPP_INCLUDES}") set_property(TARGET SQLiteCpp PROPERTY INCLUDE_DIRECTORIES "${SQLITECPP_INCLUDES}")
# Add proper includes for LibEvent's event-config.h header:
include_directories(SYSTEM ${LIBEVENT_INCLUDE_DIRS})
if (WIN32) if (WIN32)
add_subdirectory(lib/luaproxy/) add_subdirectory(lib/luaproxy/)
endif() endif()
@ -118,13 +140,14 @@ endif()
# We use EXCLUDE_FROM_ALL so that only the explicit dependencies are used # We use EXCLUDE_FROM_ALL so that only the explicit dependencies are used
# (PolarSSL also has test and example programs in their CMakeLists.txt, we don't want those) # (PolarSSL also has test and example programs in their CMakeLists.txt, we don't want those)
include(lib/polarssl.cmake) include(lib/polarssl.cmake EXCLUDE_FROM_ALL)
set_exe_flags() set_exe_flags()
add_subdirectory (src) add_subdirectory (src)
if(${SELF_TEST}) if(${SELF_TEST})
message("Tests enabled")
enable_testing() enable_testing()
add_subdirectory (tests) add_subdirectory (tests)
endif() endif()

View File

@ -69,9 +69,9 @@ After doing so, run the command `xcodebuild lib/polarssl/POLARSSL.xcodeproj` in
## Linux, FreeBSD etc. ## ## Linux, FreeBSD etc. ##
Install git, cmake and gcc or clang, using your platform's package manager: Install git, make, cmake and gcc or clang, using your platform's package manager:
``` ```
sudo apt-get install git cmake gcc g++ sudo apt-get install git make cmake gcc g++
``` ```
### Getting the sources ### ### Getting the sources ###

View File

@ -1840,7 +1840,9 @@ a_Player:OpenWindow(Window);
MoveToWorld = { Params = "WorldName", Return = "bool", Return = "Moves the player to the specified world. Returns true if successful." }, 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." }, OpenWindow = { Params = "{{cWindow|Window}}", Return = "", Notes = "Opens the specified UI window for the player." },
PermissionMatches = { Params = "Permission, Template", Return = "bool", Notes = "(STATIC) Returns true if the specified permission matches the specified template. The template may contain wildcards." }, PermissionMatches = { Params = "Permission, Template", Return = "bool", Notes = "(STATIC) Returns true if the specified permission matches the specified template. The template may contain wildcards." },
PlaceBlock = { Params = "BlockX, BlockY, BlockZ, BlockType, BlockMeta", Return = "bool", Notes = "Places a block while impersonating the player. The {{OnPlayerPlacingBlock|HOOK_PLAYER_PLACING_BLOCK}} hook is called before the placement, and if it succeeds, the block is placed and the {{OnPlayerPlacedBlock|HOOK_PLAYER_PLACED_BLOCK}} hook is called. Returns true iff the block is successfully placed. Assumes that the block is in a currently loaded chunk." },
Respawn = { Params = "", Return = "", Notes = "Restores the health, extinguishes fire, makes visible and sends the Respawn packet." }, Respawn = { Params = "", Return = "", Notes = "Restores the health, extinguishes fire, makes visible and sends the Respawn packet." },
SendBlocksAround = { Params = "BlockX, BlockY, BlockZ, [Range]", Return = "", Notes = "Sends all the world's blocks in Range from the specified coords to the player, as a BlockChange packet. Range defaults to 1 (only one block sent)." },
SendMessage = { Params = "Message", Return = "", Notes = "Sends the specified message to the player." }, SendMessage = { Params = "Message", Return = "", Notes = "Sends the specified message to the player." },
SendMessageFailure = { Params = "Message", Return = "", Notes = "Prepends Rose [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For a command that failed to run because of insufficient permissions, etc." }, SendMessageFailure = { Params = "Message", Return = "", Notes = "Prepends Rose [INFO] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For a command that failed to run because of insufficient permissions, etc." },
SendMessageFatal = { Params = "Message", Return = "", Notes = "Prepends Red [FATAL] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For something serious, such as a plugin crash, etc." }, SendMessageFatal = { Params = "Message", Return = "", Notes = "Prepends Red [FATAL] / colours entire text (depending on ShouldUseChatPrefixes()) and sends message to player. For something serious, such as a plugin crash, etc." },

View File

@ -12,7 +12,11 @@ return
Use the {{cPlayer}}:GetWorld() function to get the world to which the block belongs.</p> Use the {{cPlayer}}:GetWorld() function to get the world to which the block belongs.</p>
<p> <p>
See also the {{OnPlayerPlacingBlock|HOOK_PLAYER_PLACING_BLOCK}} hook for a similar hook called See also the {{OnPlayerPlacingBlock|HOOK_PLAYER_PLACING_BLOCK}} hook for a similar hook called
before the placement. before the placement.</p>
<p>
If the client action results in multiple blocks being placed (such as a bed or a door), each separate
block is reported through this hook. All the blocks are already present in the world before the first
instance of this hook is called.
]], ]],
Params = Params =
{ {
@ -20,10 +24,6 @@ return
{ Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, { Name = "BlockX", Type = "number", Notes = "X-coord of the block" },
{ Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" },
{ Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" },
{ Name = "BlockFace", Type = "number", Notes = "Face of the existing block upon which the player interacted. One of the BLOCK_FACE_ constants" },
{ Name = "CursorX", Type = "number", Notes = "X-coord of the cursor within the block face (0 .. 15)" },
{ Name = "CursorY", Type = "number", Notes = "Y-coord of the cursor within the block face (0 .. 15)" },
{ Name = "CursorZ", Type = "number", Notes = "Z-coord of the cursor within the block face (0 .. 15)" },
{ Name = "BlockType", Type = "BLOCKTYPE", Notes = "The block type of the block" }, { Name = "BlockType", Type = "BLOCKTYPE", Notes = "The block type of the block" },
{ Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block" }, { Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block" },
}, },

View File

@ -15,7 +15,11 @@ return
Use the {{cPlayer}}:GetWorld() function to get the world to which the block belongs.</p> Use the {{cPlayer}}:GetWorld() function to get the world to which the block belongs.</p>
<p> <p>
See also the {{OnPlayerPlacedBlock|HOOK_PLAYER_PLACED_BLOCK}} hook for a similar hook called after See also the {{OnPlayerPlacedBlock|HOOK_PLAYER_PLACED_BLOCK}} hook for a similar hook called after
the placement. the placement.</p>
<p>
If the client action results in multiple blocks being placed (such as a bed or a door), each separate
block is reported through this hook and only if all of them succeed, all the blocks are placed. If
any one of the calls are refused by the plugin, all the blocks are refused and reverted on the client.
]], ]],
Params = Params =
{ {
@ -23,10 +27,6 @@ return
{ Name = "BlockX", Type = "number", Notes = "X-coord of the block" }, { Name = "BlockX", Type = "number", Notes = "X-coord of the block" },
{ Name = "BlockY", Type = "number", Notes = "Y-coord of the block" }, { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" },
{ Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" }, { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" },
{ Name = "BlockFace", Type = "number", Notes = "Face of the existing block upon which the player is interacting. One of the BLOCK_FACE_ constants" },
{ Name = "CursorX", Type = "number", Notes = "X-coord of the cursor within the block face (0 .. 15)" },
{ Name = "CursorY", Type = "number", Notes = "Y-coord of the cursor within the block face (0 .. 15)" },
{ Name = "CursorZ", Type = "number", Notes = "Z-coord of the cursor within the block face (0 .. 15)" },
{ Name = "BlockType", Type = "BLOCKTYPE", Notes = "The block type of the block" }, { Name = "BlockType", Type = "BLOCKTYPE", Notes = "The block type of the block" },
{ Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block" }, { Name = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block" },
}, },

View File

@ -7,7 +7,10 @@ return
Desc = [[ Desc = [[
A plugin may implement an OnServerPing() function and register it as a Hook to process pings from 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 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. as the server description and the favicon, that are displayed to the client in the server list.</p>
<p>
The client handle already has its protocol version assigned to it, so the plugin can check that; however,
there's no username associated with the client yet, and no player object.
]], ]],
Params = { Params = {
{ Name = "ClientHandle", Type = "{{cClientHandle}}", Notes = "The client handle that pinged the server" }, { Name = "ClientHandle", Type = "{{cClientHandle}}", Notes = "The client handle that pinged the server" },

View File

@ -1,56 +1,14 @@
[Spider] [Bat]
AttackRange=2.0 AttackRange=2.0
AttackRate=1 AttackRate=1
AttackDamage=2.0 AttackDamage=0.0
SightDistance=25.0 SightDistance=25.0
MaxHealth=16 MaxHealth=6
[Chicken] [Blaze]
AttackRange=2.0 AttackRange=15.0
AttackRate=1 AttackRate=1
AttackDamage=1.0 AttackDamage=6.0
SightDistance=25.0
MaxHealth=4
[Cow]
AttackRange=2.0
AttackRate=1
AttackDamage=1.0
SightDistance=25.0
MaxHealth=10
[Pig]
AttackRange=2.0
AttackRate=1
AttackDamage=1.0
SightDistance=25.0
MaxHealth=10
[Sheep]
AttackRange=2.0
AttackRate=1
AttackDamage=1.0
SightDistance=25.0
MaxHealth=8
[Squid]
AttackRange=2.0
AttackRate=1
AttackDamage=1.0
SightDistance=25.0
MaxHealth=10
[Enderman]
AttackRange=2.0
AttackRate=1
AttackDamage=4.0
SightDistance=64.0
MaxHealth=40
[ZombiePigman]
AttackRange=2.0
AttackRate=1
AttackDamage=7.0
SightDistance=25.0 SightDistance=25.0
MaxHealth=20 MaxHealth=20
IsFireproof=1 IsFireproof=1
@ -62,6 +20,20 @@ AttackDamage=2.0
SightDistance=25.0 SightDistance=25.0
MaxHealth=12 MaxHealth=12
[Chicken]
AttackRange=2.0
AttackRate=1
AttackDamage=0.0
SightDistance=25.0
MaxHealth=4
[Cow]
AttackRange=2.0
AttackRate=1
AttackDamage=0.0
SightDistance=25.0
MaxHealth=10
[Creeper] [Creeper]
AttackRange=3.0 AttackRange=3.0
AttackRate=1 AttackRate=1
@ -69,6 +41,21 @@ AttackDamage=0.0
SightDistance=25.0 SightDistance=25.0
MaxHealth=20 MaxHealth=20
[EnderDragon]
AttackRange=2.0
AttackRate=1
AttackDamage=6.0
SightDistance=25.0
MaxHealth=200
[Enderman]
AttackRange=2.0
AttackRate=1
AttackDamage=4.0
SightDistance=64.0
MaxHealth=40
[Ghast] [Ghast]
AttackRange=50.0 AttackRange=50.0
AttackRate=1 AttackRate=1
@ -77,6 +64,77 @@ SightDistance=50.0
MaxHealth=10 MaxHealth=10
IsFireproof=1 IsFireproof=1
[Giant]
AttackRange=2.0
AttackRate=1
AttackDamage=6.0
SightDistance=25.0
MaxHealth=100
[Guardian]
AttackRange=2.0
AttackRate=1
AttackDamage=9.0
SightDistance=25.0
MaxHealth=30
[Horse]
AttackRange=2.0
AttackRate=1
AttackDamage=6.0
SightDistance=25.0
MaxHealth=30
[IronGolem]
AttackRange=2.0
AttackRate=1
AttackDamage=6.0
SightDistance=25.0
MaxHealth=100
[MagmaCube]
AttackRange=2.0
AttackRate=1
AttackDamage=6.0
SightDistance=25.0
MaxHealth=16
IsFireproof=1
[Mooshroom]
AttackRange=2.0
AttackRate=1
AttackDamage=0.0
SightDistance=25.0
MaxHealth=10
[Ocelot]
AttackRange=2.0
AttackRate=1
AttackDamage=0.0
SightDistance=25.0
MaxHealth=10
[Pig]
AttackRange=2.0
AttackRate=1
AttackDamage=0.0
SightDistance=25.0
MaxHealth=10
[Rabbit]
AttackRange=2.0
AttackRate=1
AttackDamage=0.0
SightDistance=25.0
MaxHealth=10
[Sheep]
AttackRange=2.0
AttackRate=1
AttackDamage=0.0
SightDistance=25.0
MaxHealth=8
[Silverfish] [Silverfish]
AttackRange=2.0 AttackRange=2.0
AttackRate=1 AttackRate=1
@ -97,27 +155,26 @@ AttackDamage=4.0
SightDistance=25.0 SightDistance=25.0
MaxHealth=16 MaxHealth=16
[Zombie] [SnowGolem]
AttackRange=2.0 AttackRange=2.0
AttackRate=1 AttackRate=1
AttackDamage=4.0 AttackDamage=0.0
SightDistance=25.0 SightDistance=25.0
MaxHealth=20 MaxHealth=4
[Wolf] [Spider]
AttackRange=2.0
AttackRate=1
AttackDamage=2.0
SightDistance=25.0
MaxHealth=16
[Squid]
AttackRange=2.0 AttackRange=2.0
AttackRate=1 AttackRate=1
AttackDamage=4.0 AttackDamage=0.0
SightDistance=25.0 SightDistance=25.0
MaxHealth=20 MaxHealth=10
[Blaze]
AttackRange=15.0
AttackRate=1
AttackDamage=6.0
SightDistance=25.0
MaxHealth=20
IsFireproof=1
[Villager] [Villager]
AttackRange=2.0 AttackRange=2.0
@ -125,7 +182,6 @@ AttackRate=1
AttackDamage=0.0 AttackDamage=0.0
SightDistance=25.0 SightDistance=25.0
MaxHealth=20 MaxHealth=20
IsFireproof=0
[Witch] [Witch]
AttackRange=2.0 AttackRange=2.0
@ -134,61 +190,24 @@ AttackDamage=0.0
SightDistance=25.0 SightDistance=25.0
MaxHealth=26 MaxHealth=26
[Wolf]
[Ocelot]
AttackRange=2.0 AttackRange=2.0
AttackRate=1 AttackRate=1
AttackDamage=0.0 AttackDamage=4.0
SightDistance=25.0 SightDistance=25.0
MaxHealth=10 MaxHealth=20
[Mooshroom] [Zombie]
AttackRange=2.0 AttackRange=2.0
AttackRate=1 AttackRate=1
AttackDamage=0.0 AttackDamage=4.0
SightDistance=25.0 SightDistance=25.0
MaxHealth=10 MaxHealth=20
[MagmaCube] [ZombiePigman]
AttackRange=2.0 AttackRange=2.0
AttackRate=1 AttackRate=1
AttackDamage=6.0 AttackDamage=7.0
SightDistance=25.0 SightDistance=25.0
MaxHealth=16 MaxHealth=20
IsFireproof=1 IsFireproof=1
[Horse]
AttackRange=2.0
AttackRate=1
AttackDamage=6.0
SightDistance=25.0
MaxHealth=30
[EnderDragon]
AttackRange=2.0
AttackRate=1
AttackDamage=6.0
SightDistance=25.0
MaxHealth=200
[Giant]
AttackRange=2.0
AttackRate=1
AttackDamage=6.0
SightDistance=25.0
MaxHealth=100
[IronGolem]
AttackRange=2.0
AttackRate=1
AttackDamage=6.0
SightDistance=25.0
MaxHealth=100
[Bat]
AttackRange=2.0
AttackRate=1
AttackDamage=0.0
SightDistance=25.0
MaxHealth=6

View File

@ -58,6 +58,7 @@ function ShowPage(WebAdmin, TemplateRequest)
SiteContent = {} SiteContent = {}
local BaseURL = WebAdmin:GetBaseURL(TemplateRequest.Request.Path) local BaseURL = WebAdmin:GetBaseURL(TemplateRequest.Request.Path)
local Title = "MCServer WebAdmin" local Title = "MCServer WebAdmin"
local NumPlayers = cRoot:Get():GetServer():GetNumPlayers()
local MemoryUsageKiB = cRoot:GetPhysicalRAMUsage() local MemoryUsageKiB = cRoot:GetPhysicalRAMUsage()
local NumChunks = cRoot:Get():GetTotalChunkCount() local NumChunks = cRoot:Get():GetTotalChunkCount()
local PluginPage = WebAdmin:GetPage(TemplateRequest.Request) local PluginPage = WebAdmin:GetPage(TemplateRequest.Request)
@ -102,6 +103,7 @@ function ShowPage(WebAdmin, TemplateRequest)
<div class="wrapper"> <div class="wrapper">
<ul class="menu top_links"> <ul class="menu top_links">
<li><a>Server Name: <strong>]] .. cRoot:Get():GetServer():GetServerID() .. [[</strong></a></li> <li><a>Server Name: <strong>]] .. cRoot:Get():GetServer():GetServerID() .. [[</strong></a></li>
<li><a>Players online: <strong>]] .. NumPlayers .. [[</strong></a></li>
<li><a>Memory: <strong>]] .. MemoryUsageKiB / 1024 .. [[MB</strong></a></li> <li><a>Memory: <strong>]] .. MemoryUsageKiB / 1024 .. [[MB</strong></a></li>
<li><a>Chunks: <strong>]] .. NumChunks .. [[</strong></a></li> <li><a>Chunks: <strong>]] .. NumChunks .. [[</strong></a></li>
</ul> </ul>

View File

@ -9,8 +9,7 @@ We currently support Release 1.7 and 1.8 (not beta) Minecraft protocol versions.
Installation Installation
------------ ------------
Hosted MCServer is available DIY on DigitalOcean: [![Install on DigitalOcean](http://doinstall.bearbin.net/button.svg)](http://doinstall.bearbin.net/install?url=https://github.com/mc-server/MCServer) and [Gamososm](https://gamocosm.com) also offers MCServer support.
[![Install on DigitalOcean](http://doinstall.bearbin.net/button.svg)](http://doinstall.bearbin.net/install?url=https://github.com/mc-server/MCServer)
For Linux there is an easy installation method, just run this in your terminal: For Linux there is an easy installation method, just run this in your terminal:

View File

@ -26,11 +26,13 @@ struct
{entEnderman, "Enderman"}, {entEnderman, "Enderman"},
{entGhast, "Ghast"}, {entGhast, "Ghast"},
{entGiant, "Giant"}, {entGiant, "Giant"},
{entGuardian, "Guardian"},
{entLavaSlime, "LavaSlime"}, {entLavaSlime, "LavaSlime"},
{entMushroomCow, "MushroomCow"}, {entMushroomCow, "MushroomCow"},
{entOzelot, "Ozelot"}, {entOzelot, "Ozelot"},
{entPig, "Pig"}, {entPig, "Pig"},
{entPigZombie, "PigZombie"}, {entPigZombie, "PigZombie"},
{entRabbit, "Rabbit"},
{entSheep, "Sheep"}, {entSheep, "Sheep"},
{entSilverfish, "Slverfish"}, {entSilverfish, "Slverfish"},
{entSkeleton, "Skeleton"}, {entSkeleton, "Skeleton"},

View File

@ -25,11 +25,13 @@ enum eEntityType
entEnderman, entEnderman,
entGhast, entGhast,
entGiant, entGiant,
entGuardian,
entLavaSlime, entLavaSlime,
entMushroomCow, entMushroomCow,
entOzelot, entOzelot,
entPig, entPig,
entPigZombie, entPigZombie,
entRabbit,
entSheep, entSheep,
entSilverfish, entSilverfish,
entSkeleton, entSkeleton,

View File

@ -53,6 +53,7 @@ source_group("Shared" FILES ${SHARED_SRC} ${SHARED_HDR})
set(SHARED_OSS_SRC set(SHARED_OSS_SRC
../../src/OSSupport/CriticalSection.cpp ../../src/OSSupport/CriticalSection.cpp
../../src/OSSupport/Event.cpp
../../src/OSSupport/File.cpp ../../src/OSSupport/File.cpp
../../src/OSSupport/IsThread.cpp ../../src/OSSupport/IsThread.cpp
../../src/OSSupport/StackTrace.cpp ../../src/OSSupport/StackTrace.cpp
@ -60,6 +61,7 @@ set(SHARED_OSS_SRC
set(SHARED_OSS_HDR set(SHARED_OSS_HDR
../../src/OSSupport/CriticalSection.h ../../src/OSSupport/CriticalSection.h
../../src/OSSupport/Event.h
../../src/OSSupport/File.h ../../src/OSSupport/File.h
../../src/OSSupport/IsThread.h ../../src/OSSupport/IsThread.h
../../src/OSSupport/StackTrace.h ../../src/OSSupport/StackTrace.h

View File

@ -201,6 +201,7 @@ typedef unsigned char Byte;
// Common headers (without macros): // Common headers (without macros):
#include "StringUtils.h" #include "StringUtils.h"
#include "OSSupport/CriticalSection.h" #include "OSSupport/CriticalSection.h"
#include "OSSupport/Event.h"
#include "OSSupport/IsThread.h" #include "OSSupport/IsThread.h"
#include "OSSupport/File.h" #include "OSSupport/File.h"

View File

@ -269,7 +269,7 @@ bool cMCADefrag::cThread::ReadChunk(cFile & a_File, const Byte * a_LocationRaw)
return false; return false;
} }
m_CompressedChunkDataSize = (Buf[0] << 24) | (Buf[1] << 16) | (Buf[2] << 8) | Buf[3]; m_CompressedChunkDataSize = (Buf[0] << 24) | (Buf[1] << 16) | (Buf[2] << 8) | Buf[3];
if (m_CompressedChunkDataSize > SizeInSectors) if ((m_CompressedChunkDataSize > SizeInSectors) || (m_CompressedChunkDataSize < 0))
{ {
LOGWARNING("Invalid chunk data - SizeInSectors (%d) smaller that RealSize (%d)", SizeInSectors, m_CompressedChunkDataSize); LOGWARNING("Invalid chunk data - SizeInSectors (%d) smaller that RealSize (%d)", SizeInSectors, m_CompressedChunkDataSize);
return false; return false;

View File

@ -55,12 +55,14 @@ set(SHARED_HDR
) )
set(SHARED_OSS_SRC set(SHARED_OSS_SRC
../../src/OSSupport/CriticalSection.cpp ../../src/OSSupport/CriticalSection.cpp
../../src/OSSupport/Event.cpp
../../src/OSSupport/File.cpp ../../src/OSSupport/File.cpp
../../src/OSSupport/IsThread.cpp ../../src/OSSupport/IsThread.cpp
../../src/OSSupport/StackTrace.cpp ../../src/OSSupport/StackTrace.cpp
) )
set(SHARED_OSS_HDR set(SHARED_OSS_HDR
../../src/OSSupport/CriticalSection.h ../../src/OSSupport/CriticalSection.h
../../src/OSSupport/Event.h
../../src/OSSupport/File.h ../../src/OSSupport/File.h
../../src/OSSupport/IsThread.h ../../src/OSSupport/IsThread.h
../../src/OSSupport/StackTrace.h ../../src/OSSupport/StackTrace.h

View File

@ -100,13 +100,11 @@
CLIENTENCRYPTSEND(ToClient.data(), ToClient.size()); \ CLIENTENCRYPTSEND(ToClient.data(), ToClient.size()); \
break; \ break; \
} \ } \
/* case csWaitingForEncryption: \ case csWaitingForEncryption: \
{ \ { \
Log("Waiting for client encryption, queued %u bytes", ToClient.size()); \
m_ClientEncryptionBuffer.append(ToClient.data(), ToClient.size()); \
break; \ break; \
} \ } \
*/ \ \
} \ } \
DebugSleep(50); \ DebugSleep(50); \
} }
@ -141,8 +139,14 @@ typedef unsigned char Byte;
// fwd declarations, to avoid clang warnings:
AString PrintableAbsIntTriplet(int a_X, int a_Y, int a_Z, double a_Divisor = 32);
AString PrintableAbsIntTriplet(int a_X, int a_Y, int a_Z, double a_Divisor = 32)
AString PrintableAbsIntTriplet(int a_X, int a_Y, int a_Z, double a_Divisor)
{ {
return Printf("<%d, %d, %d> ~ {%.02f, %.02f, %.02f}", return Printf("<%d, %d, %d> ~ {%.02f, %.02f, %.02f}",
a_X, a_Y, a_Z, a_X, a_Y, a_Z,
@ -298,7 +302,7 @@ void cConnection::Log(const char * a_Format, ...)
void cConnection::DataLog(const void * a_Data, int a_Size, const char * a_Format, ...) void cConnection::DataLog(const void * a_Data, size_t a_Size, const char * a_Format, ...)
{ {
va_list args; va_list args;
va_start(args, a_Format); va_start(args, a_Format);
@ -359,14 +363,14 @@ bool cConnection::ConnectToServer(void)
bool cConnection::RelayFromServer(void) bool cConnection::RelayFromServer(void)
{ {
char Buffer[64 KiB]; char Buffer[64 KiB];
int res = recv(m_ServerSocket, Buffer, sizeof(Buffer), 0); int res = static_cast<int>(recv(m_ServerSocket, Buffer, sizeof(Buffer), 0)); // recv returns int on windows, ssize_t on linux
if (res <= 0) if (res <= 0)
{ {
Log("Server closed the socket: %d; %d; aborting connection", res, SocketError); Log("Server closed the socket: %d; %d; aborting connection", res, SocketError);
return false; return false;
} }
DataLog(Buffer, res, "Received %d bytes from the SERVER", res); DataLog(Buffer, static_cast<size_t>(res), "Received %d bytes from the SERVER", res);
switch (m_ServerState) switch (m_ServerState)
{ {
@ -377,15 +381,15 @@ bool cConnection::RelayFromServer(void)
} }
case csEncryptedUnderstood: case csEncryptedUnderstood:
{ {
m_ServerDecryptor.ProcessData((Byte *)Buffer, (Byte *)Buffer, res); m_ServerDecryptor.ProcessData(reinterpret_cast<Byte *>(Buffer), reinterpret_cast<Byte *>(Buffer), static_cast<size_t>(res));
DataLog(Buffer, res, "Decrypted %d bytes from the SERVER", res); DataLog(Buffer, static_cast<size_t>(res), "Decrypted %d bytes from the SERVER", res);
return DecodeServersPackets(Buffer, res); return DecodeServersPackets(Buffer, res);
} }
case csEncryptedUnknown: case csEncryptedUnknown:
{ {
m_ServerDecryptor.ProcessData((Byte *)Buffer, (Byte *)Buffer, res); m_ServerDecryptor.ProcessData(reinterpret_cast<Byte *>(Buffer), reinterpret_cast<Byte *>(Buffer), static_cast<size_t>(res));
DataLog(Buffer, res, "Decrypted %d bytes from the SERVER", res); DataLog(Buffer, static_cast<size_t>(res), "Decrypted %d bytes from the SERVER", res);
return CLIENTSEND(Buffer, res); return CLIENTSEND(Buffer, static_cast<size_t>(res));
} }
} }
ASSERT(!"Unhandled server state while relaying from server"); ASSERT(!"Unhandled server state while relaying from server");
@ -399,14 +403,14 @@ bool cConnection::RelayFromServer(void)
bool cConnection::RelayFromClient(void) bool cConnection::RelayFromClient(void)
{ {
char Buffer[64 KiB]; char Buffer[64 KiB];
int res = recv(m_ClientSocket, Buffer, sizeof(Buffer), 0); int res = static_cast<int>(recv(m_ClientSocket, Buffer, sizeof(Buffer), 0)); // recv returns int on Windows, ssize_t on Linux
if (res <= 0) if (res <= 0)
{ {
Log("Client closed the socket: %d; %d; aborting connection", res, SocketError); Log("Client closed the socket: %d; %d; aborting connection", res, SocketError);
return false; return false;
} }
DataLog(Buffer, res, "Received %d bytes from the CLIENT", res); DataLog(Buffer, static_cast<size_t>(res), "Received %d bytes from the CLIENT", res);
switch (m_ClientState) switch (m_ClientState)
{ {
@ -421,9 +425,9 @@ bool cConnection::RelayFromClient(void)
} }
case csEncryptedUnknown: case csEncryptedUnknown:
{ {
DataLog(Buffer, res, "Decrypted %d bytes from the CLIENT", res); DataLog(Buffer, static_cast<size_t>(res), "Decrypted %d bytes from the CLIENT", res);
m_ServerEncryptor.ProcessData((Byte *)Buffer, (Byte *)Buffer, res); m_ServerEncryptor.ProcessData(reinterpret_cast<Byte *>(Buffer), reinterpret_cast<Byte *>(Buffer), static_cast<size_t>(res));
return SERVERSEND(Buffer, res); return SERVERSEND(Buffer, static_cast<size_t>(res));
} }
} }
ASSERT(!"Unhandled server state while relaying from client"); ASSERT(!"Unhandled server state while relaying from client");
@ -446,9 +450,9 @@ double cConnection::GetRelativeTime(void)
bool cConnection::SendData(SOCKET a_Socket, const char * a_Data, size_t a_Size, const char * a_Peer) bool cConnection::SendData(SOCKET a_Socket, const char * a_Data, size_t a_Size, const char * a_Peer)
{ {
DataLog(a_Data, a_Size, "Sending data to %s, %u bytes", a_Peer, (unsigned)a_Size); DataLog(a_Data, a_Size, "Sending data to %s, %u bytes", a_Peer, static_cast<unsigned>(a_Size));
int res = send(a_Socket, a_Data, (int)a_Size, 0); int res = static_cast<int>(send(a_Socket, a_Data, a_Size, 0)); // Windows uses int for a_Size, Linux uses size_t; but Windows doesn't complain. Return type is int on Windows and ssize_t on Linux
if (res <= 0) if (res <= 0)
{ {
Log("%s closed the socket: %d, %d; aborting connection", a_Peer, res, SocketError); Log("%s closed the socket: %d, %d; aborting connection", a_Peer, res, SocketError);
@ -511,7 +515,7 @@ bool cConnection::SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Enc
bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size) bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size)
{ {
if (!m_ClientBuffer.Write(a_Data, a_Size)) if (!m_ClientBuffer.Write(a_Data, static_cast<size_t>(a_Size)))
{ {
Log("Too much queued data for the server, aborting connection"); Log("Too much queued data for the server, aborting connection");
return false; return false;
@ -529,10 +533,12 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size)
break; break;
} }
UInt32 PacketType, PacketReadSoFar; UInt32 PacketType, PacketReadSoFar;
PacketReadSoFar = m_ClientBuffer.GetReadableSpace(); PacketReadSoFar = static_cast<UInt32>(m_ClientBuffer.GetReadableSpace());
VERIFY(m_ClientBuffer.ReadVarInt(PacketType)); VERIFY(m_ClientBuffer.ReadVarInt(PacketType));
PacketReadSoFar -= m_ClientBuffer.GetReadableSpace(); PacketReadSoFar -= m_ClientBuffer.GetReadableSpace();
Log("Decoding client's packets, there are now %d bytes in the queue; next packet is 0x%0x, %u bytes long", m_ClientBuffer.GetReadableSpace(), PacketType, PacketLen); Log("Decoding client's packets, there are now %u bytes in the queue; next packet is 0x%02x, %u bytes long",
static_cast<unsigned>(m_ClientBuffer.GetReadableSpace()), PacketType, PacketLen
);
switch (m_ClientProtocolState) switch (m_ClientProtocolState)
{ {
case -1: case -1:
@ -619,7 +625,7 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size)
bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size) bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size)
{ {
if (!m_ServerBuffer.Write(a_Data, a_Size)) if (!m_ServerBuffer.Write(a_Data, static_cast<size_t>(a_Size)))
{ {
Log("Too much queued data for the client, aborting connection"); Log("Too much queued data for the client, aborting connection");
return false; return false;
@ -655,7 +661,7 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size)
break; break;
} }
UInt32 PacketType, PacketReadSoFar; UInt32 PacketType, PacketReadSoFar;
PacketReadSoFar = m_ServerBuffer.GetReadableSpace(); PacketReadSoFar = static_cast<UInt32>(m_ServerBuffer.GetReadableSpace());
VERIFY(m_ServerBuffer.ReadVarInt(PacketType)); VERIFY(m_ServerBuffer.ReadVarInt(PacketType));
PacketReadSoFar -= m_ServerBuffer.GetReadableSpace(); PacketReadSoFar -= m_ServerBuffer.GetReadableSpace();
Log("Decoding server's packets, there are now %d bytes in the queue; next packet is 0x%0x, %u bytes long", m_ServerBuffer.GetReadableSpace(), PacketType, PacketLen); Log("Decoding server's packets, there are now %d bytes in the queue; next packet is 0x%0x, %u bytes long", m_ServerBuffer.GetReadableSpace(), PacketType, PacketLen);
@ -1111,7 +1117,7 @@ bool cConnection::HandleClientPlayerPositionLook(void)
bool cConnection::HandleClientPluginMessage(void) bool cConnection::HandleClientPluginMessage(void)
{ {
HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, ChannelName); HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, ChannelName);
HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, Length); HANDLE_CLIENT_PACKET_READ(ReadBEUInt16, UInt16, Length);
AString Data; AString Data;
if (!m_ClientBuffer.ReadString(Data, Length)) if (!m_ClientBuffer.ReadString(Data, Length))
{ {
@ -1119,7 +1125,7 @@ bool cConnection::HandleClientPluginMessage(void)
} }
Log("Received a PACKET_PLUGIN_MESSAGE from the client"); Log("Received a PACKET_PLUGIN_MESSAGE from the client");
Log(" ChannelName = \"%s\"", ChannelName.c_str()); Log(" ChannelName = \"%s\"", ChannelName.c_str());
DataLog(Data.data(), Length, " Data: %d bytes", Length); DataLog(Data.data(), Length, " Data: %u bytes", Length);
COPY_TO_SERVER(); COPY_TO_SERVER();
return true; return true;
} }
@ -1288,13 +1294,13 @@ bool cConnection::HandleServerLoginEncryptionKeyRequest(void)
{ {
// Read the packet from the server: // Read the packet from the server:
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, ServerID); HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, ServerID);
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, PublicKeyLength); HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, PublicKeyLength);
AString PublicKey; AString PublicKey;
if (!m_ServerBuffer.ReadString(PublicKey, PublicKeyLength)) if (!m_ServerBuffer.ReadString(PublicKey, PublicKeyLength))
{ {
return false; return false;
} }
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, NonceLength); HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, NonceLength);
AString Nonce; AString Nonce;
if (!m_ServerBuffer.ReadString(Nonce, NonceLength)) if (!m_ServerBuffer.ReadString(Nonce, NonceLength))
{ {
@ -1392,6 +1398,9 @@ bool cConnection::HandleServerBlockChange(void)
HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, BlockType); HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, BlockType);
HANDLE_SERVER_PACKET_READ(ReadChar, char, BlockMeta); HANDLE_SERVER_PACKET_READ(ReadChar, char, BlockMeta);
Log("Received a PACKET_BLOCK_CHANGE from the server"); Log("Received a PACKET_BLOCK_CHANGE from the server");
Log(" Pos = {%d, %d, %d}", BlockX, BlockY, BlockZ);
Log(" BlockType = %d (0x%x", BlockType, BlockType);
Log(" BlockMeta = %d", BlockMeta);
COPY_TO_CLIENT(); COPY_TO_CLIENT();
return true; return true;
} }
@ -1461,12 +1470,12 @@ bool cConnection::HandleServerCompass(void)
bool cConnection::HandleServerDestroyEntities(void) bool cConnection::HandleServerDestroyEntities(void)
{ {
HANDLE_SERVER_PACKET_READ(ReadByte, Byte, NumEntities); HANDLE_SERVER_PACKET_READ(ReadByte, Byte, NumEntities);
if (!m_ServerBuffer.SkipRead((int)NumEntities * 4)) if (!m_ServerBuffer.SkipRead(static_cast<size_t>(NumEntities) * 4))
{ {
return false; return false;
} }
Log("Received PACKET_DESTROY_ENTITIES from the server:"); Log("Received PACKET_DESTROY_ENTITIES from the server:");
Log(" NumEntities = %d", NumEntities); Log(" NumEntities = %u", NumEntities);
COPY_TO_CLIENT(); COPY_TO_CLIENT();
return true; return true;
} }
@ -1687,15 +1696,15 @@ bool cConnection::HandleServerEntityVelocity(void)
bool cConnection::HandleServerExplosion(void) bool cConnection::HandleServerExplosion(void)
{ {
HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosX); HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosX);
HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosY); HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosY);
HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosZ); HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosZ);
HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Force); HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Force);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, NumRecords); HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, NumRecords);
std::vector<sCoords> Records; std::vector<sCoords> Records;
Records.reserve(NumRecords); Records.reserve(NumRecords);
int PosXI = (int)PosX, PosYI = (int)PosY, PosZI = (int)PosZ; int PosXI = (int)PosX, PosYI = (int)PosY, PosZI = (int)PosZ;
for (int i = 0; i < NumRecords; i++) for (UInt32 i = 0; i < NumRecords; i++)
{ {
HANDLE_SERVER_PACKET_READ(ReadChar, char, rx); HANDLE_SERVER_PACKET_READ(ReadChar, char, rx);
HANDLE_SERVER_PACKET_READ(ReadChar, char, ry); HANDLE_SERVER_PACKET_READ(ReadChar, char, ry);
@ -1708,10 +1717,10 @@ bool cConnection::HandleServerExplosion(void)
Log("Received a PACKET_EXPLOSION from the server:"); Log("Received a PACKET_EXPLOSION from the server:");
Log(" Pos = {%.02f, %.02f, %.02f}", PosX, PosY, PosZ); Log(" Pos = {%.02f, %.02f, %.02f}", PosX, PosY, PosZ);
Log(" Force = %.02f", Force); Log(" Force = %.02f", Force);
Log(" NumRecords = %d", NumRecords); Log(" NumRecords = %u", NumRecords);
for (int i = 0; i < NumRecords; i++) for (UInt32 i = 0; i < NumRecords; i++)
{ {
Log(" Records[%d] = {%d, %d, %d}", i, Records[i].x, Records[i].y, Records[i].z); Log(" Records[%u] = {%d, %d, %d}", i, Records[i].x, Records[i].y, Records[i].z);
} }
Log(" Player motion = <%.02f, %.02f, %.02f>", PlayerMotionX, PlayerMotionY, PlayerMotionZ); Log(" Player motion = <%.02f, %.02f, %.02f>", PlayerMotionX, PlayerMotionY, PlayerMotionZ);
COPY_TO_CLIENT(); COPY_TO_CLIENT();
@ -1822,8 +1831,8 @@ bool cConnection::HandleServerKick(void)
Reason.append(Split[5]); Reason.append(Split[5]);
AString ReasonBE16 = UTF8ToRawBEUTF16(Reason.data(), Reason.size()); AString ReasonBE16 = UTF8ToRawBEUTF16(Reason.data(), Reason.size());
AString PacketStart("\xff"); AString PacketStart("\xff");
PacketStart.push_back((ReasonBE16.size() / 2) / 256); PacketStart.push_back(static_cast<char>((ReasonBE16.size() / 2) / 256));
PacketStart.push_back((ReasonBE16.size() / 2) % 256); PacketStart.push_back(static_cast<char>((ReasonBE16.size() / 2) % 256));
CLIENTSEND(PacketStart.data(), PacketStart.size()); CLIENTSEND(PacketStart.data(), PacketStart.size());
CLIENTSEND(ReasonBE16.data(), ReasonBE16.size()); CLIENTSEND(ReasonBE16.data(), ReasonBE16.size());
return true; return true;
@ -1847,12 +1856,12 @@ bool cConnection::HandleServerKick(void)
bool cConnection::HandleServerMapChunk(void) bool cConnection::HandleServerMapChunk(void)
{ {
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkX); HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkX);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkZ); HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkZ);
HANDLE_SERVER_PACKET_READ(ReadChar, char, IsContiguous); HANDLE_SERVER_PACKET_READ(ReadChar, char, IsContiguous);
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, PrimaryBitmap); HANDLE_SERVER_PACKET_READ(ReadBEShort, short, PrimaryBitmap);
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, AdditionalBitmap); HANDLE_SERVER_PACKET_READ(ReadBEShort, short, AdditionalBitmap);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, CompressedSize); HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, CompressedSize);
AString CompressedData; AString CompressedData;
if (!m_ServerBuffer.ReadString(CompressedData, CompressedSize)) if (!m_ServerBuffer.ReadString(CompressedData, CompressedSize))
{ {
@ -1860,7 +1869,7 @@ bool cConnection::HandleServerMapChunk(void)
} }
Log("Received a PACKET_MAP_CHUNK from the server:"); Log("Received a PACKET_MAP_CHUNK from the server:");
Log(" ChunkPos = [%d, %d]", ChunkX, ChunkZ); Log(" ChunkPos = [%d, %d]", ChunkX, ChunkZ);
Log(" Compressed size = %d (0x%x)", CompressedSize, CompressedSize); Log(" Compressed size = %u (0x%x)", CompressedSize, CompressedSize);
// TODO: Save the compressed data into a file for later analysis // TODO: Save the compressed data into a file for later analysis
@ -1874,9 +1883,9 @@ bool cConnection::HandleServerMapChunk(void)
bool cConnection::HandleServerMapChunkBulk(void) bool cConnection::HandleServerMapChunkBulk(void)
{ {
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, ChunkCount); HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, ChunkCount);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, CompressedSize); HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, CompressedSize);
HANDLE_SERVER_PACKET_READ(ReadBool, bool, IsSkyLightSent); HANDLE_SERVER_PACKET_READ(ReadBool, bool, IsSkyLightSent);
AString CompressedData; AString CompressedData;
if (!m_ServerBuffer.ReadString(CompressedData, CompressedSize)) if (!m_ServerBuffer.ReadString(CompressedData, CompressedSize))
{ {
@ -1898,8 +1907,8 @@ bool cConnection::HandleServerMapChunkBulk(void)
} }
Log("Received a PACKET_MAP_CHUNK_BULK from the server:"); Log("Received a PACKET_MAP_CHUNK_BULK from the server:");
Log(" ChunkCount = %d", ChunkCount); Log(" ChunkCount = %u", ChunkCount);
Log(" Compressed size = %d (0x%x)", CompressedSize, CompressedSize); Log(" Compressed size = %u (0x%x)", CompressedSize, CompressedSize);
Log(" IsSkyLightSent = %s", IsSkyLightSent ? "true" : "false"); Log(" IsSkyLightSent = %s", IsSkyLightSent ? "true" : "false");
// Log individual chunk coords: // Log individual chunk coords:
@ -1923,10 +1932,10 @@ bool cConnection::HandleServerMapChunkBulk(void)
bool cConnection::HandleServerMultiBlockChange(void) bool cConnection::HandleServerMultiBlockChange(void)
{ {
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkX); HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkX);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkZ); HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkZ);
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, NumBlocks); HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, NumBlocks);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, DataSize); HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, DataSize);
AString BlockChangeData; AString BlockChangeData;
if (!m_ServerBuffer.ReadString(BlockChangeData, DataSize)) if (!m_ServerBuffer.ReadString(BlockChangeData, DataSize))
{ {
@ -1934,7 +1943,7 @@ bool cConnection::HandleServerMultiBlockChange(void)
} }
Log("Received a PACKET_MULTI_BLOCK_CHANGE packet from the server:"); Log("Received a PACKET_MULTI_BLOCK_CHANGE packet from the server:");
Log(" Chunk = [%d, %d]", ChunkX, ChunkZ); Log(" Chunk = [%d, %d]", ChunkX, ChunkZ);
Log(" NumBlocks = %d", NumBlocks); Log(" NumBlocks = %u", NumBlocks);
COPY_TO_CLIENT(); COPY_TO_CLIENT();
return true; return true;
} }
@ -2035,7 +2044,7 @@ bool cConnection::HandleServerPlayerPositionLook(void)
bool cConnection::HandleServerPluginMessage(void) bool cConnection::HandleServerPluginMessage(void)
{ {
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, ChannelName); HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, ChannelName);
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, Length); HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, Length);
AString Data; AString Data;
if (!m_ServerBuffer.ReadString(Data, Length)) if (!m_ServerBuffer.ReadString(Data, Length))
{ {
@ -2043,7 +2052,7 @@ bool cConnection::HandleServerPluginMessage(void)
} }
Log("Received a PACKET_PLUGIN_MESSAGE from the server"); Log("Received a PACKET_PLUGIN_MESSAGE from the server");
Log(" ChannelName = \"%s\"", ChannelName.c_str()); Log(" ChannelName = \"%s\"", ChannelName.c_str());
DataLog(Data.data(), Length, " Data: %d bytes", Length); DataLog(Data.data(), Length, " Data: %u bytes", Length);
COPY_TO_CLIENT(); COPY_TO_CLIENT();
return true; return true;
} }
@ -2530,11 +2539,11 @@ bool cConnection::HandleServerUpdateSign(void)
bool cConnection::HandleServerUpdateTileEntity(void) bool cConnection::HandleServerUpdateTileEntity(void)
{ {
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX); HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX);
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockY); HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockY);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ); HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ);
HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Action); HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Action);
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, DataLength); HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, DataLength);
AString Data; AString Data;
if ((DataLength > 0) && !m_ServerBuffer.ReadString(Data, DataLength)) if ((DataLength > 0) && !m_ServerBuffer.ReadString(Data, DataLength))
@ -2548,7 +2557,7 @@ bool cConnection::HandleServerUpdateTileEntity(void)
// Save metadata to a file: // Save metadata to a file:
AString fnam; AString fnam;
Printf(fnam, "%s_item_%08x.nbt", m_LogNameBase.c_str(), m_ItemIdx++); Printf(fnam, "%s_tile_%08x.nbt", m_LogNameBase.c_str(), m_ItemIdx++);
FILE * f = fopen(fnam.c_str(), "wb"); FILE * f = fopen(fnam.c_str(), "wb");
if (f != NULL) if (f != NULL)
{ {
@ -2686,10 +2695,10 @@ bool cConnection::ParseSlot(cByteBuffer & a_Buffer, AString & a_ItemDesc)
} }
char ItemCount; char ItemCount;
short ItemDamage; short ItemDamage;
short MetadataLength; UInt16 MetadataLength;
a_Buffer.ReadChar(ItemCount); a_Buffer.ReadChar(ItemCount); // We already know we can read these bytes - we checked before.
a_Buffer.ReadBEShort(ItemDamage); a_Buffer.ReadBEShort(ItemDamage);
a_Buffer.ReadBEShort(MetadataLength); a_Buffer.ReadBEUInt16(MetadataLength);
Printf(a_ItemDesc, "%d:%d * %d", ItemType, ItemDamage, ItemCount); Printf(a_ItemDesc, "%d:%d * %d", ItemType, ItemDamage, ItemCount);
if (MetadataLength <= 0) if (MetadataLength <= 0)
{ {
@ -2697,13 +2706,13 @@ bool cConnection::ParseSlot(cByteBuffer & a_Buffer, AString & a_ItemDesc)
} }
AString Metadata; AString Metadata;
Metadata.resize(MetadataLength); Metadata.resize(MetadataLength);
if (!a_Buffer.ReadBuf((void *)Metadata.data(), MetadataLength)) if (!a_Buffer.ReadBuf(const_cast<char *>(Metadata.data()), MetadataLength))
{ {
return false; return false;
} }
AString MetaHex; AString MetaHex;
CreateHexDump(MetaHex, Metadata.data(), Metadata.size(), 16); CreateHexDump(MetaHex, Metadata.data(), Metadata.size(), 16);
AppendPrintf(a_ItemDesc, "; %d bytes of meta:\n%s", MetadataLength, MetaHex.c_str()); AppendPrintf(a_ItemDesc, "; %u bytes of meta:\n%s", MetadataLength, MetaHex.c_str());
// Save metadata to a file: // Save metadata to a file:
AString fnam; AString fnam;
@ -2725,17 +2734,19 @@ bool cConnection::ParseSlot(cByteBuffer & a_Buffer, AString & a_ItemDesc)
bool cConnection::ParseMetadata(cByteBuffer & a_Buffer, AString & a_Metadata) bool cConnection::ParseMetadata(cByteBuffer & a_Buffer, AString & a_Metadata)
{ {
char x; Byte x;
if (!a_Buffer.ReadChar(x)) if (!a_Buffer.ReadByte(x))
{ {
return false; return false;
} }
a_Metadata.push_back(x); a_Metadata.push_back(static_cast<char>(x));
while (x != 0x7f) while (x != 0x7f)
{ {
// int Index = ((unsigned)((unsigned char)x)) & 0x1f; // Lower 5 bits = index // int Index = static_cast<unsigned>(x) & 0x1f; // Lower 5 bits = index
int Type = ((unsigned)((unsigned char)x)) >> 5; // Upper 3 bits = type int Type = static_cast<unsigned>(x) >> 5; // Upper 3 bits = type
int Length = 0;
// Get the length of the data for this item:
UInt32 Length = 0;
switch (Type) switch (Type)
{ {
case 0: Length = 1; break; // Byte case 0: Length = 1; break; // Byte
@ -2745,12 +2756,12 @@ bool cConnection::ParseMetadata(cByteBuffer & a_Buffer, AString & a_Metadata)
case 4: // UTF-8 string with VarInt length case 4: // UTF-8 string with VarInt length
{ {
UInt32 Len; UInt32 Len;
int rs = a_Buffer.GetReadableSpace(); int rs = static_cast<int>(a_Buffer.GetReadableSpace());
if (!a_Buffer.ReadVarInt(Len)) if (!a_Buffer.ReadVarInt(Len))
{ {
return false; return false;
} }
rs = rs - a_Buffer.GetReadableSpace(); rs = rs - static_cast<int>(a_Buffer.GetReadableSpace());
cByteBuffer LenBuf(8); cByteBuffer LenBuf(8);
LenBuf.WriteVarInt(Len); LenBuf.WriteVarInt(Len);
AString VarLen; AString VarLen;
@ -2759,18 +2770,18 @@ bool cConnection::ParseMetadata(cByteBuffer & a_Buffer, AString & a_Metadata)
Length = Len; Length = Len;
break; break;
} }
case 5: case 5: // Item, in "slot" format
{ {
int Before = a_Buffer.GetReadableSpace(); size_t Before = a_Buffer.GetReadableSpace();
AString ItemDesc; AString ItemDesc;
if (!ParseSlot(a_Buffer, ItemDesc)) if (!ParseSlot(a_Buffer, ItemDesc))
{ {
return false; return false;
} }
int After = a_Buffer.GetReadableSpace(); size_t After = a_Buffer.GetReadableSpace();
a_Buffer.ResetRead(); a_Buffer.ResetRead();
a_Buffer.SkipRead(a_Buffer.GetReadableSpace() - Before); a_Buffer.SkipRead(a_Buffer.GetReadableSpace() - Before);
Length = Before - After; Length = static_cast<UInt32>(Before - After);
break; break;
} }
case 6: Length = 12; break; // 3 * int case 6: Length = 12; break; // 3 * int
@ -2781,17 +2792,19 @@ bool cConnection::ParseMetadata(cByteBuffer & a_Buffer, AString & a_Metadata)
break; break;
} }
} // switch (Type) } // switch (Type)
// Read the data in this item:
AString data; AString data;
if (!a_Buffer.ReadString(data, Length)) if (!a_Buffer.ReadString(data, Length))
{ {
return false; return false;
} }
a_Metadata.append(data); a_Metadata.append(data);
if (!a_Buffer.ReadChar(x)) if (!a_Buffer.ReadByte(x))
{ {
return false; return false;
} }
a_Metadata.push_back(x); a_Metadata.push_back(static_cast<char>(x));
} // while (x != 0x7f) } // while (x != 0x7f)
return true; return true;
} }
@ -2803,58 +2816,62 @@ bool cConnection::ParseMetadata(cByteBuffer & a_Buffer, AString & a_Metadata)
void cConnection::LogMetadata(const AString & a_Metadata, size_t a_IndentCount) void cConnection::LogMetadata(const AString & a_Metadata, size_t a_IndentCount)
{ {
AString Indent(a_IndentCount, ' '); AString Indent(a_IndentCount, ' ');
int pos = 0; size_t pos = 0;
while (a_Metadata[pos] != 0x7f) while (a_Metadata[pos] != 0x7f)
{ {
int Index = ((unsigned)((unsigned char)a_Metadata[pos])) & 0x1f; // Lower 5 bits = index unsigned Index = static_cast<unsigned>(static_cast<unsigned char>(a_Metadata[pos])) & 0x1f; // Lower 5 bits = index
int Type = ((unsigned)((unsigned char)a_Metadata[pos])) >> 5; // Upper 3 bits = type unsigned Type = static_cast<unsigned>(static_cast<unsigned char>(a_Metadata[pos])) >> 5; // Upper 3 bits = type
// int Length = 0; // int Length = 0;
switch (Type) switch (Type)
{ {
case 0: case 0:
{ {
Log("%sbyte[%d] = %d", Indent.c_str(), Index, a_Metadata[pos + 1]); Log("%sbyte[%u] = %d", Indent.c_str(), Index, a_Metadata[pos + 1]);
pos += 1; pos += 1;
break; break;
} }
case 1: case 1:
{ {
Log("%sshort[%d] = %d", Indent.c_str(), Index, (a_Metadata[pos + 1] << 8) | a_Metadata[pos + 2]); Log("%sshort[%u] = %d", Indent.c_str(), Index, (a_Metadata[pos + 1] << 8) | a_Metadata[pos + 2]);
pos += 2; pos += 2;
break; break;
} }
case 2: case 2:
{ {
Log("%sint[%d] = %d", Indent.c_str(), Index, (a_Metadata[pos + 1] << 24) | (a_Metadata[pos + 2] << 16) | (a_Metadata[pos + 3] << 8) | a_Metadata[pos + 4]); Log("%sint[%u] = %d", Indent.c_str(), Index, (a_Metadata[pos + 1] << 24) | (a_Metadata[pos + 2] << 16) | (a_Metadata[pos + 3] << 8) | a_Metadata[pos + 4]);
pos += 4; pos += 4;
break; break;
} }
case 3: case 3:
{ {
Log("%sfloat[%d] = 0x%x", Indent.c_str(), Index, (a_Metadata[pos + 1] << 24) | (a_Metadata[pos + 2] << 16) | (a_Metadata[pos + 3] << 8) | a_Metadata[pos + 4]); Log("%sfloat[%u] = 0x%x", Indent.c_str(), Index, (a_Metadata[pos + 1] << 24) | (a_Metadata[pos + 2] << 16) | (a_Metadata[pos + 3] << 8) | a_Metadata[pos + 4]);
pos += 4; pos += 4;
break; break;
} }
case 4: // UTF-8 string with VarInt length case 4: // UTF-8 string with VarInt length
{ {
cByteBuffer bb(10); cByteBuffer bb(10);
int RestLen = (int)a_Metadata.size() - pos - 1; size_t RestLen = a_Metadata.size() - pos - 1;
if (RestLen > 8) if (RestLen > 8)
{ {
RestLen = 8; RestLen = 8;
} }
bb.Write(a_Metadata.data() + pos + 1, RestLen); bb.Write(a_Metadata.data() + pos + 1, RestLen);
UInt32 Length; UInt32 Length;
int rs = bb.GetReadableSpace(); size_t rs = bb.GetReadableSpace();
bb.ReadVarInt(Length); if (!bb.ReadVarInt(Length))
{
Log("Invalid metadata value, was supposed to be a varint-prefixed string, but cannot read the varint");
break;
}
rs = rs - bb.GetReadableSpace(); rs = rs - bb.GetReadableSpace();
Log("%sstring[%d] = \"%*s\"", Indent.c_str(), Index, Length, a_Metadata.c_str() + pos + rs + 1); Log("%sstring[%u] = \"%*s\"", Indent.c_str(), Index, Length, a_Metadata.c_str() + pos + rs + 1);
pos += Length + rs + 2; pos += Length + rs + 2;
break; break;
} }
case 5: case 5:
{ {
int BytesLeft = a_Metadata.size() - pos - 1; size_t BytesLeft = a_Metadata.size() - pos - 1;
cByteBuffer bb(BytesLeft); cByteBuffer bb(BytesLeft);
bb.Write(a_Metadata.data() + pos + 1, BytesLeft); bb.Write(a_Metadata.data() + pos + 1, BytesLeft);
AString ItemDesc; AString ItemDesc;
@ -2863,16 +2880,16 @@ void cConnection::LogMetadata(const AString & a_Metadata, size_t a_IndentCount)
ASSERT(!"Cannot parse item description from metadata"); ASSERT(!"Cannot parse item description from metadata");
return; return;
} }
// int After = bb.GetReadableSpace(); // size_t After = bb.GetReadableSpace();
int BytesConsumed = BytesLeft - bb.GetReadableSpace(); size_t BytesConsumed = BytesLeft - bb.GetReadableSpace();
Log("%sslot[%d] = %s (%d bytes)", Indent.c_str(), Index, ItemDesc.c_str(), BytesConsumed); Log("%sslot[%u] = %s (%u bytes)", Indent.c_str(), Index, ItemDesc.c_str(), static_cast<unsigned>(BytesConsumed));
pos += BytesConsumed; pos += BytesConsumed;
break; break;
} }
case 6: case 6:
{ {
Log("%spos[%d] = <%d, %d, %d>", Indent.c_str(), Index, Log("%spos[%u] = <%d, %d, %d>", Indent.c_str(), Index,
(a_Metadata[pos + 1] << 24) | (a_Metadata[pos + 2] << 16) | (a_Metadata[pos + 3] << 8) | a_Metadata[pos + 4], (a_Metadata[pos + 1] << 24) | (a_Metadata[pos + 2] << 16) | (a_Metadata[pos + 3] << 8) | a_Metadata[pos + 4],
(a_Metadata[pos + 5] << 24) | (a_Metadata[pos + 6] << 16) | (a_Metadata[pos + 7] << 8) | a_Metadata[pos + 8], (a_Metadata[pos + 5] << 24) | (a_Metadata[pos + 6] << 16) | (a_Metadata[pos + 7] << 8) | a_Metadata[pos + 8],
(a_Metadata[pos + 9] << 24) | (a_Metadata[pos + 10] << 16) | (a_Metadata[pos + 11] << 8) | a_Metadata[pos + 12] (a_Metadata[pos + 9] << 24) | (a_Metadata[pos + 10] << 16) | (a_Metadata[pos + 11] << 8) | a_Metadata[pos + 12]
@ -2931,7 +2948,7 @@ void cConnection::SendEncryptionKeyResponse(const AString & a_ServerPublicKey, c
DataLog(EncryptedSecret, sizeof(EncryptedSecret), "Encrypted secret (%u bytes)", (unsigned)sizeof(EncryptedSecret)); DataLog(EncryptedSecret, sizeof(EncryptedSecret), "Encrypted secret (%u bytes)", (unsigned)sizeof(EncryptedSecret));
DataLog(EncryptedNonce, sizeof(EncryptedNonce), "Encrypted nonce (%u bytes)", (unsigned)sizeof(EncryptedNonce)); DataLog(EncryptedNonce, sizeof(EncryptedNonce), "Encrypted nonce (%u bytes)", (unsigned)sizeof(EncryptedNonce));
cByteBuffer Len(5); cByteBuffer Len(5);
Len.WriteVarInt(ToServer.GetReadableSpace()); Len.WriteVarInt(static_cast<UInt32>(ToServer.GetReadableSpace()));
SERVERSEND(Len); SERVERSEND(Len);
SERVERSEND(ToServer); SERVERSEND(ToServer);
m_ServerState = csEncryptedUnderstood; m_ServerState = csEncryptedUnderstood;

View File

@ -58,7 +58,7 @@ public:
void Run(void); void Run(void);
void Log(const char * a_Format, ...); void Log(const char * a_Format, ...);
void DataLog(const void * a_Data, int a_Size, const char * a_Format, ...); void DataLog(const void * a_Data, size_t a_Size, const char * a_Format, ...);
void LogFlush(void); void LogFlush(void);
protected: protected:

View File

@ -38,13 +38,41 @@ int cServer::Init(short a_ListenPort, short a_ConnectPort)
m_PublicKeyDER = m_PrivateKey.GetPubKeyDER(); m_PublicKeyDER = m_PrivateKey.GetPubKeyDER();
m_ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); m_ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_ListenSocket < 0)
{
#ifdef _WIN32
int err = WSAGetLastError();
#else
int err = errno;
#endif
printf("Failed to create listener socket: %d\n", err);
return err;
}
sockaddr_in local; sockaddr_in local;
memset(&local, 0, sizeof(local)); memset(&local, 0, sizeof(local));
local.sin_family = AF_INET; local.sin_family = AF_INET;
local.sin_addr.s_addr = 0; // All interfaces local.sin_addr.s_addr = 130; // INADDR_ANY; // All interfaces
local.sin_port = htons(a_ListenPort); local.sin_port = htons(a_ListenPort);
bind(m_ListenSocket, (sockaddr *)&local, sizeof(local)); if (!bind(m_ListenSocket, (sockaddr *)&local, sizeof(local)))
listen(m_ListenSocket, 1); {
#ifdef _WIN32
int err = WSAGetLastError();
#else
int err = errno;
#endif
printf("Failed to bind listener socket: %d\n", err);
return err;
}
if (listen(m_ListenSocket, 1) != 0)
{
#ifdef _WIN32
int err = WSAGetLastError();
#else
int err = errno;
#endif
printf("Failed to listen on socket: %d\n", err);
return err;
}
printf("Listening on port %d, connecting to localhost:%d\n", a_ListenPort, a_ConnectPort); printf("Listening on port %d, connecting to localhost:%d\n", a_ListenPort, a_ConnectPort);

View File

@ -3,9 +3,7 @@ image: ubuntu-14-04-x64
config: config:
#cloud-config #cloud-config
packages: packages:
- curl - git
- screen
runcmd: runcmd:
- mkdir /minecraft - cd /tmp && git clone https://github.com/cuberite/mcserver-ocean.git
- cd /minecraft && curl -s https://raw.githubusercontent.com/mc-server/MCServer/master/easyinstall.sh | sh - cd /tmp/mcserver-ocean && ./initialinstall.sh
- cd /minecraft/MCServer && screen -S mcserver -d -m ./MCServer

View File

@ -7,7 +7,7 @@ case $PLATFORM in
"i686") DOWNLOADURL="http://builds.cuberite.org/job/MCServer%20Linux%20x86/lastSuccessfulBuild/artifact/MCServer.tar" ;; "i686") DOWNLOADURL="http://builds.cuberite.org/job/MCServer%20Linux%20x86/lastSuccessfulBuild/artifact/MCServer.tar" ;;
"x86_64") DOWNLOADURL="http://builds.cuberite.org/job/MCServer%20Linux%20x64/lastSuccessfulBuild/artifact/MCServer.tar" ;; "x86_64") DOWNLOADURL="http://builds.cuberite.org/job/MCServer%20Linux%20x64/lastSuccessfulBuild/artifact/MCServer.tar" ;;
# Assume that all arm devices are a raspi for now. # Assume that all arm devices are a raspi for now.
"arm*") DOWNLOADURL="http://builds.cuberite.org/job/MCServer%20Linux%20armhf/lastSuccessfulBuild/artifact/MCServer.tar" "arm*") DOWNLOADURL="http://builds.cuberite.org/job/MCServer%20Linux%20armhf/lastSuccessfulBuild/artifact/MCServer/MCServer.tar"
esac esac
echo "Downloading precompiled binaries." echo "Downloading precompiled binaries."

1
lib/libevent Submodule

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

View File

@ -839,6 +839,13 @@ void cLuaState::Push(void * a_Ptr)
m_NumCurrentFunctionArgs += 1; m_NumCurrentFunctionArgs += 1;
} }
void cLuaState::Push(std::chrono::milliseconds a_Value)
{
ASSERT(IsValid());
tolua_pushnumber(m_LuaState, static_cast<lua_Number>(a_Value.count()));
m_NumCurrentFunctionArgs += 1;
}

View File

@ -217,6 +217,7 @@ public:
void Push(Vector3d * a_Vector); void Push(Vector3d * a_Vector);
void Push(Vector3i * a_Vector); void Push(Vector3i * a_Vector);
void Push(void * a_Ptr); void Push(void * a_Ptr);
void Push(std::chrono::milliseconds a_time);
/** Retrieve value at a_StackPos, if it is a valid bool. If not, a_Value is unchanged */ /** Retrieve value at a_StackPos, if it is a valid bool. If not, a_Value is unchanged */
void GetStackValue(int a_StackPos, bool & a_Value); void GetStackValue(int a_StackPos, bool & a_Value);

View File

@ -76,8 +76,8 @@ public:
virtual bool OnPlayerJoined (cPlayer & a_Player) = 0; virtual bool OnPlayerJoined (cPlayer & a_Player) = 0;
virtual bool OnPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) = 0; virtual bool OnPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) = 0;
virtual bool OnPlayerMoving (cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) = 0; virtual bool OnPlayerMoving (cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) = 0;
virtual bool OnPlayerPlacedBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; virtual bool OnPlayerPlacedBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange) = 0;
virtual bool OnPlayerPlacingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; virtual bool OnPlayerPlacingBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange) = 0;
virtual bool OnPlayerRightClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0; virtual bool OnPlayerRightClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0;
virtual bool OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity) = 0; virtual bool OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity) = 0;
virtual bool OnPlayerShooting (cPlayer & a_Player) = 0; virtual bool OnPlayerShooting (cPlayer & a_Player) = 0;
@ -104,7 +104,7 @@ public:
virtual bool OnWeatherChanged (cWorld & a_World) = 0; virtual bool OnWeatherChanged (cWorld & a_World) = 0;
virtual bool OnWeatherChanging (cWorld & a_World, eWeather & a_NewWeather) = 0; virtual bool OnWeatherChanging (cWorld & a_World, eWeather & a_NewWeather) = 0;
virtual bool OnWorldStarted (cWorld & a_World) = 0; virtual bool OnWorldStarted (cWorld & a_World) = 0;
virtual bool OnWorldTick (cWorld & a_World, float a_Dt, int a_LastTickDurationMSec) = 0; virtual bool OnWorldTick (cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec) = 0;
/** Handles the command split into a_Split, issued by player a_Player. /** Handles the command split into a_Split, issued by player a_Player.
Command permissions have already been checked. Command permissions have already been checked.

View File

@ -857,14 +857,19 @@ bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d & a_OldPositi
bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange)
{ {
cCSLock Lock(m_CriticalSection); cCSLock Lock(m_CriticalSection);
bool res = false; bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACED_BLOCK]; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACED_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{ {
m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res); m_LuaState.Call((int)(**itr), &a_Player,
a_BlockChange.GetX(), a_BlockChange.GetY(), a_BlockChange.GetZ(),
a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta,
cLuaState::Return,
res
);
if (res) if (res)
{ {
return true; return true;
@ -877,14 +882,19 @@ bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, int a_BlockX, int a_Blo
bool cPluginLua::OnPlayerPlacingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) bool cPluginLua::OnPlayerPlacingBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange)
{ {
cCSLock Lock(m_CriticalSection); cCSLock Lock(m_CriticalSection);
bool res = false; bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACING_BLOCK]; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACING_BLOCK];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{ {
m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res); m_LuaState.Call((int)(**itr), &a_Player,
a_BlockChange.GetX(), a_BlockChange.GetY(), a_BlockChange.GetZ(),
a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta,
cLuaState::Return,
res
);
if (res) if (res)
{ {
return true; return true;
@ -1420,7 +1430,7 @@ bool cPluginLua::OnWorldStarted(cWorld & a_World)
bool cPluginLua::OnWorldTick(cWorld & a_World, float a_Dt, int a_LastTickDurationMSec) bool cPluginLua::OnWorldTick(cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec)
{ {
cCSLock Lock(m_CriticalSection); cCSLock Lock(m_CriticalSection);
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WORLD_TICK]; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WORLD_TICK];

View File

@ -100,8 +100,8 @@ public:
virtual bool OnPlayerJoined (cPlayer & a_Player) override; virtual bool OnPlayerJoined (cPlayer & a_Player) override;
virtual bool OnPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) override; virtual bool OnPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) override;
virtual bool OnPlayerMoving (cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) override; virtual bool OnPlayerMoving (cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) override;
virtual bool OnPlayerPlacedBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; virtual bool OnPlayerPlacedBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange) override;
virtual bool OnPlayerPlacingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; virtual bool OnPlayerPlacingBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange) override;
virtual bool OnPlayerRightClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; virtual bool OnPlayerRightClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
virtual bool OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity) override; virtual bool OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity) override;
virtual bool OnPlayerShooting (cPlayer & a_Player) override; virtual bool OnPlayerShooting (cPlayer & a_Player) override;
@ -128,7 +128,7 @@ public:
virtual bool OnWeatherChanged (cWorld & a_World) override; virtual bool OnWeatherChanged (cWorld & a_World) override;
virtual bool OnWeatherChanging (cWorld & a_World, eWeather & a_NewWeather) override; virtual bool OnWeatherChanging (cWorld & a_World, eWeather & a_NewWeather) override;
virtual bool OnWorldStarted (cWorld & a_World) override; virtual bool OnWorldStarted (cWorld & a_World) override;
virtual bool OnWorldTick (cWorld & a_World, float a_Dt, int a_LastTickDurationMSec) override; virtual bool OnWorldTick (cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec) override;
virtual bool HandleCommand(const AStringVector & a_Split, cPlayer & a_Player) override; virtual bool HandleCommand(const AStringVector & a_Split, cPlayer & a_Player) override;

View File

@ -771,7 +771,7 @@ bool cPluginManager::CallHookPlayerFoodLevelChange(cPlayer & a_Player, int a_New
bool cPluginManager::CallHookPlayerFished(cPlayer & a_Player, const cItems a_Reward) bool cPluginManager::CallHookPlayerFished(cPlayer & a_Player, const cItems & a_Reward)
{ {
FIND_HOOK(HOOK_PLAYER_FISHED); FIND_HOOK(HOOK_PLAYER_FISHED);
VERIFY_HOOK; VERIFY_HOOK;
@ -847,7 +847,7 @@ bool cPluginManager::CallHookPlayerLeftClick(cPlayer & a_Player, int a_BlockX, i
bool cPluginManager::CallHookPlayerMoving(cPlayer & a_Player, const Vector3d a_OldPosition, const Vector3d a_NewPosition) bool cPluginManager::CallHookPlayerMoving(cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition)
{ {
FIND_HOOK(HOOK_PLAYER_MOVING); FIND_HOOK(HOOK_PLAYER_MOVING);
VERIFY_HOOK; VERIFY_HOOK;
@ -866,14 +866,14 @@ bool cPluginManager::CallHookPlayerMoving(cPlayer & a_Player, const Vector3d a_O
bool cPluginManager::CallHookPlayerPlacedBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) bool cPluginManager::CallHookPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange)
{ {
FIND_HOOK(HOOK_PLAYER_PLACED_BLOCK); FIND_HOOK(HOOK_PLAYER_PLACED_BLOCK);
VERIFY_HOOK; VERIFY_HOOK;
for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
{ {
if ((*itr)->OnPlayerPlacedBlock(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta)) if ((*itr)->OnPlayerPlacedBlock(a_Player, a_BlockChange))
{ {
return true; return true;
} }
@ -885,14 +885,14 @@ bool cPluginManager::CallHookPlayerPlacedBlock(cPlayer & a_Player, int a_BlockX,
bool cPluginManager::CallHookPlayerPlacingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) bool cPluginManager::CallHookPlayerPlacingBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange)
{ {
FIND_HOOK(HOOK_PLAYER_PLACING_BLOCK); FIND_HOOK(HOOK_PLAYER_PLACING_BLOCK);
VERIFY_HOOK; VERIFY_HOOK;
for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
{ {
if ((*itr)->OnPlayerPlacingBlock(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta)) if ((*itr)->OnPlayerPlacingBlock(a_Player, a_BlockChange))
{ {
return true; return true;
} }
@ -1394,7 +1394,7 @@ bool cPluginManager::CallHookWorldStarted(cWorld & a_World)
bool cPluginManager::CallHookWorldTick(cWorld & a_World, float a_Dt, int a_LastTickDurationMSec) bool cPluginManager::CallHookWorldTick(cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec)
{ {
FIND_HOOK(HOOK_WORLD_TICK); FIND_HOOK(HOOK_WORLD_TICK);
VERIFY_HOOK; VERIFY_HOOK;

View File

@ -203,14 +203,14 @@ public:
bool CallHookPlayerBrokenBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); bool CallHookPlayerBrokenBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
bool CallHookPlayerDestroyed (cPlayer & a_Player); bool CallHookPlayerDestroyed (cPlayer & a_Player);
bool CallHookPlayerEating (cPlayer & a_Player); bool CallHookPlayerEating (cPlayer & a_Player);
bool CallHookPlayerFished (cPlayer & a_Player, const cItems a_Reward); bool CallHookPlayerFished (cPlayer & a_Player, const cItems & a_Reward);
bool CallHookPlayerFishing (cPlayer & a_Player, cItems a_Reward); bool CallHookPlayerFishing (cPlayer & a_Player, cItems a_Reward);
bool CallHookPlayerFoodLevelChange (cPlayer & a_Player, int a_NewFoodLevel); bool CallHookPlayerFoodLevelChange (cPlayer & a_Player, int a_NewFoodLevel);
bool CallHookPlayerJoined (cPlayer & a_Player); bool CallHookPlayerJoined (cPlayer & a_Player);
bool CallHookPlayerMoving (cPlayer & a_Player, const Vector3d a_OldPosition, const Vector3d a_NewPosition);
bool CallHookPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status); bool CallHookPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status);
bool CallHookPlayerPlacedBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); bool CallHookPlayerMoving (cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition);
bool CallHookPlayerPlacingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); bool CallHookPlayerPlacedBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange);
bool CallHookPlayerPlacingBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange);
bool CallHookPlayerRightClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ); bool CallHookPlayerRightClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ);
bool CallHookPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity); bool CallHookPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity);
bool CallHookPlayerShooting (cPlayer & a_Player); bool CallHookPlayerShooting (cPlayer & a_Player);
@ -237,7 +237,7 @@ public:
bool CallHookWeatherChanged (cWorld & a_World); bool CallHookWeatherChanged (cWorld & a_World);
bool CallHookWeatherChanging (cWorld & a_World, eWeather & a_NewWeather); bool CallHookWeatherChanging (cWorld & a_World, eWeather & a_NewWeather);
bool CallHookWorldStarted (cWorld & a_World); bool CallHookWorldStarted (cWorld & a_World);
bool CallHookWorldTick (cWorld & a_World, float a_Dt, int a_LastTickDurationMSec); bool CallHookWorldTick (cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec);
bool DisablePlugin(const AString & a_PluginName); // tolua_export bool DisablePlugin(const AString & a_PluginName); // tolua_export
bool LoadPlugin (const AString & a_PluginName); // tolua_export bool LoadPlugin (const AString & a_PluginName); // tolua_export

View File

@ -267,7 +267,7 @@ void cBeaconEntity::GiveEffects(void)
bool cBeaconEntity::Tick(float a_Dt, cChunk & a_Chunk) bool cBeaconEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
// Update the beacon every 4 seconds // Update the beacon every 4 seconds
if ((GetWorld()->GetWorldAge() % 80) == 0) if ((GetWorld()->GetWorldAge() % 80) == 0)

View File

@ -30,7 +30,7 @@ public:
// cBlockEntity overrides: // cBlockEntity overrides:
virtual void SendTo(cClientHandle & a_Client) override; virtual void SendTo(cClientHandle & a_Client) override;
virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void UsedBy(cPlayer * a_Player) override; virtual void UsedBy(cPlayer * a_Player) override;
/** Modify the beacon level. (It is needed to load the beacon corectly) */ /** Modify the beacon level. (It is needed to load the beacon corectly) */

View File

@ -110,7 +110,7 @@ public:
virtual void SendTo(cClientHandle & a_Client) = 0; virtual void SendTo(cClientHandle & a_Client) = 0;
/// Ticks the entity; returns true if the chunk should be marked as dirty as a result of this ticking. By default does nothing. /// Ticks the entity; returns true if the chunk should be marked as dirty as a result of this ticking. By default does nothing.
virtual bool Tick(float a_Dt, cChunk & a_Chunk) virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
UNUSED(a_Dt); UNUSED(a_Dt);
return false; return false;

View File

@ -125,7 +125,7 @@ void cCommandBlockEntity::SetRedstonePower(bool a_IsPowered)
bool cCommandBlockEntity::Tick(float a_Dt, cChunk & a_Chunk) bool cCommandBlockEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
UNUSED(a_Dt); UNUSED(a_Dt);
UNUSED(a_Chunk); UNUSED(a_Chunk);

View File

@ -33,7 +33,7 @@ public:
/// Creates a new empty command block entity /// Creates a new empty command block entity
cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World); cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World);
virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void SendTo(cClientHandle & a_Client) override; virtual void SendTo(cClientHandle & a_Client) override;
virtual void UsedBy(cPlayer * a_Player) override; virtual void UsedBy(cPlayer * a_Player) override;

View File

@ -126,7 +126,7 @@ void cDropSpenserEntity::SetRedstonePower(bool a_IsPowered)
bool cDropSpenserEntity::Tick(float a_Dt, cChunk & a_Chunk) bool cDropSpenserEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
UNUSED(a_Dt); UNUSED(a_Dt);
if (!m_ShouldDropSpense) if (!m_ShouldDropSpense)

View File

@ -47,7 +47,7 @@ public:
virtual ~cDropSpenserEntity(); virtual ~cDropSpenserEntity();
// cBlockEntity overrides: // cBlockEntity overrides:
virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void SendTo(cClientHandle & a_Client) override; virtual void SendTo(cClientHandle & a_Client) override;
virtual void UsedBy(cPlayer * a_Player) override; virtual void UsedBy(cPlayer * a_Player) override;

View File

@ -90,7 +90,7 @@ bool cFurnaceEntity::ContinueCooking(void)
bool cFurnaceEntity::Tick(float a_Dt, cChunk & a_Chunk) bool cFurnaceEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
UNUSED(a_Dt); UNUSED(a_Dt);

View File

@ -42,7 +42,7 @@ public:
// cBlockEntity overrides: // cBlockEntity overrides:
virtual void SendTo(cClientHandle & a_Client) override; virtual void SendTo(cClientHandle & a_Client) override;
virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void UsedBy(cPlayer * a_Player) override; virtual void UsedBy(cPlayer * a_Player) override;
virtual void Destroy() override virtual void Destroy() override
{ {

View File

@ -55,7 +55,7 @@ bool cHopperEntity::GetOutputBlockPos(NIBBLETYPE a_BlockMeta, int & a_OutputX, i
bool cHopperEntity::Tick(float a_Dt, cChunk & a_Chunk) bool cHopperEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
UNUSED(a_Dt); UNUSED(a_Dt);
Int64 CurrentTick = a_Chunk.GetWorld()->GetWorldAge(); Int64 CurrentTick = a_Chunk.GetWorld()->GetWorldAge();

View File

@ -48,7 +48,7 @@ protected:
Int64 m_LastMoveItemsOutTick; Int64 m_LastMoveItemsOutTick;
// cBlockEntity overrides: // cBlockEntity overrides:
virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void SendTo(cClientHandle & a_Client) override; virtual void SendTo(cClientHandle & a_Client) override;
virtual void UsedBy(cPlayer * a_Player) override; virtual void UsedBy(cPlayer * a_Player) override;

View File

@ -73,7 +73,7 @@ void cMobSpawnerEntity::UpdateActiveState(void)
bool cMobSpawnerEntity::Tick(float a_Dt, cChunk & a_Chunk) bool cMobSpawnerEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
// Update the active flag every 5 seconds // Update the active flag every 5 seconds
if ((m_World->GetWorldAge() % 100) == 0) if ((m_World->GetWorldAge() % 100) == 0)

View File

@ -29,7 +29,7 @@ public:
virtual void SendTo(cClientHandle & a_Client) override; virtual void SendTo(cClientHandle & a_Client) override;
virtual void UsedBy(cPlayer * a_Player) override; virtual void UsedBy(cPlayer * a_Player) override;
virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
// tolua_begin // tolua_begin

View File

@ -959,6 +959,7 @@ enum
E_META_SPAWN_EGG_WITHER = 64, E_META_SPAWN_EGG_WITHER = 64,
E_META_SPAWN_EGG_BAT = 65, E_META_SPAWN_EGG_BAT = 65,
E_META_SPAWN_EGG_WITCH = 66, E_META_SPAWN_EGG_WITCH = 66,
E_META_SPAWN_EGG_GUARDIAN = 68,
E_META_SPAWN_EGG_PIG = 90, E_META_SPAWN_EGG_PIG = 90,
E_META_SPAWN_EGG_SHEEP = 91, E_META_SPAWN_EGG_SHEEP = 91,
E_META_SPAWN_EGG_COW = 92, E_META_SPAWN_EGG_COW = 92,
@ -970,6 +971,7 @@ enum
E_META_SPAWN_EGG_OCELOT = 98, E_META_SPAWN_EGG_OCELOT = 98,
E_META_SPAWN_EGG_IRON_GOLEM = 99, E_META_SPAWN_EGG_IRON_GOLEM = 99,
E_META_SPAWN_EGG_HORSE = 100, E_META_SPAWN_EGG_HORSE = 100,
E_META_SPAWN_EGG_RABBIT = 101,
E_META_SPAWN_EGG_VILLAGER = 120, E_META_SPAWN_EGG_VILLAGER = 120,
E_META_SPAWN_EGG_ENDER_CRYSTAL = 200, E_META_SPAWN_EGG_ENDER_CRYSTAL = 200,
} ; } ;

View File

@ -14,24 +14,6 @@
void cBlockBedHandler::OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
)
{
if (a_BlockMeta < 8)
{
Vector3i Direction = MetaDataToDirection(a_BlockMeta);
a_ChunkInterface.SetBlock(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z, E_BLOCK_BED, a_BlockMeta | 0x8);
}
}
void cBlockBedHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) void cBlockBedHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
@ -151,7 +133,7 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
cPlayerBedStateUnsetter Unsetter(Vector3i(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z), a_WorldInterface); cPlayerBedStateUnsetter Unsetter(Vector3i(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z), a_WorldInterface);
a_WorldInterface.ForEachPlayer(Unsetter); a_WorldInterface.ForEachPlayer(Unsetter);
a_WorldInterface.SetTimeOfDay(0); a_WorldInterface.SetTimeOfDay(0);
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta & 0xB); // Where 0xB = 1011, and zero is to make sure 'occupied' bit is always unset a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta & 0x0b); // Clear the "occupied" bit of the bed's block
} }
} }
} }

View File

@ -23,7 +23,6 @@ public:
} }
virtual void OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override; virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override;
virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;

View File

@ -85,18 +85,6 @@ public:
} }
virtual void OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
) override
{
int Meta = (((int)floor(a_Player->GetYaw() * 4.0 / 360.0 + 0.5) & 0x3) + 2) % 4;
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY + 1, a_BlockZ, m_BlockType, 0x8 | Meta);
}
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override
{ {
NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);

View File

@ -62,50 +62,11 @@ public:
} }
// Single chest, get meta from rotation only // Single chest, get meta from rotation only
a_BlockMeta = RotationToMetaData(yaw); a_BlockMeta = PlayerYawToMetaData(yaw);
return true; return true;
} }
virtual void OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
) override
{
// Check if this forms a doublechest, if so, need to adjust the meta:
cBlockArea Area;
if (!Area.Read(&a_ChunkInterface, a_BlockX - 1, a_BlockX + 1, a_BlockY, a_BlockY, a_BlockZ - 1, a_BlockZ + 1))
{
return;
}
double rot = a_Player->GetYaw(); // FIXME: Rename rot to yaw
// Choose meta from player rotation, choose only between 2 or 3
NIBBLETYPE NewMeta = ((rot >= -90) && (rot < 90)) ? 2 : 3;
if (
CheckAndAdjustNeighbor(a_ChunkInterface, Area, 0, 1, NewMeta) ||
CheckAndAdjustNeighbor(a_ChunkInterface, Area, 2, 1, NewMeta)
)
{
// Forming a double chest in the X direction
return;
}
// Choose meta from player rotation, choose only between 4 or 5
NewMeta = (rot < 0) ? 4 : 5;
if (
CheckAndAdjustNeighbor(a_ChunkInterface, Area, 1, 0, NewMeta) ||
CheckAndAdjustNeighbor(a_ChunkInterface, Area, 2, 2, NewMeta)
)
{
// Forming a double chest in the Z direction
return;
}
// Single chest, no further processing needed
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{ {
int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
@ -180,30 +141,30 @@ public:
} }
/// Translates player rotation when placing a chest into the chest block metadata. Valid for single chests only /** Translates player yaw when placing a chest into the chest block metadata. Valid for single chests only */
static NIBBLETYPE RotationToMetaData(double a_Rotation) static NIBBLETYPE PlayerYawToMetaData(double a_Yaw)
{ {
a_Rotation += 90 + 45; // So its not aligned with axis a_Yaw += 90 + 45; // So its not aligned with axis
if (a_Rotation > 360.f) if (a_Yaw > 360.f)
{ {
a_Rotation -= 360.f; a_Yaw -= 360.f;
} }
if ((a_Rotation >= 0.f) && (a_Rotation < 90.f)) if ((a_Yaw >= 0.f) && (a_Yaw < 90.f))
{ {
return 0x4; return 0x04;
} }
else if ((a_Rotation >= 180) && (a_Rotation < 270)) else if ((a_Yaw >= 180) && (a_Yaw < 270))
{ {
return 0x5; return 0x05;
} }
else if ((a_Rotation >= 90) && (a_Rotation < 180)) else if ((a_Yaw >= 90) && (a_Yaw < 180))
{ {
return 0x2; return 0x02;
} }
else else
{ {
return 0x3; return 0x03;
} }
} }

View File

@ -23,7 +23,7 @@ void cBlockDoorHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldIn
if (OldMeta & 8) if (OldMeta & 8)
{ {
// Was upper part of door // Was upper part of door
if (IsDoor(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ))) if (IsDoorBlockType(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)))
{ {
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
} }
@ -31,7 +31,7 @@ void cBlockDoorHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldIn
else else
{ {
// Was lower part // Was lower part
if (IsDoor(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ))) if (IsDoorBlockType(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ)))
{ {
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY + 1, a_BlockZ, E_BLOCK_AIR, 0); a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY + 1, a_BlockZ, E_BLOCK_AIR, 0);
} }
@ -84,52 +84,34 @@ void cBlockDoorHandler::OnCancelRightClick(cChunkInterface & a_ChunkInterface, c
void cBlockDoorHandler::OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
)
{
NIBBLETYPE a_TopBlockMeta = 8;
if (
((a_BlockMeta == 0) && (a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1) == m_BlockType)) ||
((a_BlockMeta == 1) && (a_ChunkInterface.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ) == m_BlockType)) ||
((a_BlockMeta == 2) && (a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1) == m_BlockType)) ||
((a_BlockMeta == 3) && (a_ChunkInterface.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ) == m_BlockType))
)
{
a_TopBlockMeta = 9;
}
a_ChunkInterface.SetBlock(a_BlockX, a_BlockY + 1, a_BlockZ, m_BlockType, a_TopBlockMeta);
}
NIBBLETYPE cBlockDoorHandler::MetaRotateCCW(NIBBLETYPE a_Meta) NIBBLETYPE cBlockDoorHandler::MetaRotateCCW(NIBBLETYPE a_Meta)
{ {
if (a_Meta & 0x08) if (a_Meta & 0x08)
{ {
// The meta doesn't change for the top block
return a_Meta; return a_Meta;
} }
else else
{ {
// Rotate the bottom block
return super::MetaRotateCCW(a_Meta); return super::MetaRotateCCW(a_Meta);
} }
} }
NIBBLETYPE cBlockDoorHandler::MetaRotateCW(NIBBLETYPE a_Meta) NIBBLETYPE cBlockDoorHandler::MetaRotateCW(NIBBLETYPE a_Meta)
{ {
if (a_Meta & 0x08) if (a_Meta & 0x08)
{ {
// The meta doesn't change for the top block
return a_Meta; return a_Meta;
} }
else else
{ {
// Rotate the bottom block
return super::MetaRotateCW(a_Meta); return super::MetaRotateCW(a_Meta);
} }
} }
@ -138,8 +120,10 @@ NIBBLETYPE cBlockDoorHandler::MetaRotateCW(NIBBLETYPE a_Meta)
NIBBLETYPE cBlockDoorHandler::MetaMirrorXY(NIBBLETYPE a_Meta) NIBBLETYPE cBlockDoorHandler::MetaMirrorXY(NIBBLETYPE a_Meta)
{ {
// Top bit (0x08) contains door panel type (Top/Bottom panel) Only Bottom panels contain position data /*
// Return a_Meta if panel is a top panel (0x08 bit is set to 1) Top bit (0x08) contains door block position (Top / Bottom). Only Bottom blocks contain position data
Return a_Meta if panel is a top panel (0x08 bit is set to 1)
*/
// Note: Currently, you can not properly mirror the hinges on a double door. The orientation of the door is stored // Note: Currently, you can not properly mirror the hinges on a double door. The orientation of the door is stored
// in only the bottom tile while the hinge position is in the top tile. This function only operates on one tile at a time, // in only the bottom tile while the hinge position is in the top tile. This function only operates on one tile at a time,

View File

@ -101,14 +101,6 @@ public:
} }
virtual void OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
) override;
virtual bool IsUseable(void) override virtual bool IsUseable(void) override
{ {
return true; return true;
@ -117,11 +109,20 @@ public:
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{ {
return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR)); return ((a_RelY > 0) && CanBeOn(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)));
} }
bool CanReplaceBlock(BLOCKTYPE a_BlockType) /** Returns true if door can be placed on the specified block type. */
static bool CanBeOn(BLOCKTYPE a_BlockType)
{
// Vanilla refuses to place doors on transparent blocks
// We need to keep the door compatible with itself, otherwise the top half drops while the bottom half stays
return !cBlockInfo::IsTransparent(a_BlockType) || IsDoorBlockType(a_BlockType);
}
static bool CanReplaceBlock(BLOCKTYPE a_BlockType)
{ {
switch (a_BlockType) switch (a_BlockType)
{ {
@ -170,8 +171,21 @@ public:
} }
/** Returns a vector pointing one block in the direction the door is facing (where the outside is). */
inline static Vector3i GetRelativeDirectionToOutside(NIBBLETYPE a_BlockMeta)
{
switch (a_BlockMeta & 0x03)
{
case 0: return Vector3i(-1, 0, 0); // Facing West / XM
case 1: return Vector3i( 0, 0, -1); // Facing North / ZM
case 2: return Vector3i( 1, 0, 0); // Facing East / XP
default: return Vector3i( 0, 0, 1); // Facing South / ZP
}
}
/** Returns true if the specified blocktype is any kind of door */ /** Returns true if the specified blocktype is any kind of door */
inline static bool IsDoor(BLOCKTYPE a_Block) inline static bool IsDoorBlockType(BLOCKTYPE a_Block)
{ {
switch (a_Block) switch (a_Block)
{ {
@ -193,6 +207,8 @@ public:
} }
/** Returns true iff the door at the specified coords is open.
The coords may point to either the top part or the bottom part of the door. */
static NIBBLETYPE IsOpen(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) static NIBBLETYPE IsOpen(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
@ -237,7 +253,7 @@ public:
static void SetOpen(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Open) static void SetOpen(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Open)
{ {
BLOCKTYPE Block = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ); BLOCKTYPE Block = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
if (!IsDoor(Block)) if (!IsDoorBlockType(Block))
{ {
return; return;
} }

View File

@ -12,7 +12,8 @@ class cBlockFireHandler :
{ {
public: public:
cBlockFireHandler(BLOCKTYPE a_BlockType) cBlockFireHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType) : cBlockHandler(a_BlockType),
XZP(0), XZM(0), Dir(0)
{ {
} }

View File

@ -369,7 +369,7 @@ void cBlockHandler::OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface
void cBlockHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) void cBlockHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, const sSetBlock & a_BlockChange)
{ {
} }

View File

@ -42,15 +42,12 @@ public:
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
); );
/// Called by cWorld::SetBlock() after the block has been set /** Called by cWorld::SetBlock() after the block has been set */
virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
/// Called by cClientHandle::HandlePlaceBlock() after the player has placed a new block. Called after OnPlaced(). /** Called by cPlayer::PlaceBlocks() for each block after it has been set to the world. Called after OnPlaced(). */
virtual void OnPlacedByPlayer( virtual void OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, const sSetBlock & a_BlockChange
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
); );
/// Called before the player has destroyed a block /// Called before the player has destroyed a block
@ -96,7 +93,8 @@ public:
*/ */
// virtual bool CanBePlacedAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir); // virtual bool CanBePlacedAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir);
/// Called to check whether this block supports a rclk action. If it returns true, OnUse() is called /** Called to check whether this block supports a rclk action.
If it returns true, OnUse() is called */
virtual bool IsUseable(void); virtual bool IsUseable(void);
/** Indicates whether the client will click through this block. /** Indicates whether the client will click through this block.
@ -109,20 +107,21 @@ public:
*/ */
virtual bool DoesIgnoreBuildCollision(void); virtual bool DoesIgnoreBuildCollision(void);
/// <summary>Similar to DoesIgnoreBuildCollision(void), but is used for cases where block meta/player item-in-hand is needed to determine collision (thin snow)</summary> /** Similar to DoesIgnoreBuildCollision(void), but is used for cases where block's meta or
player's item-in-hand is needed to determine collision (thin snow) */
virtual bool DoesIgnoreBuildCollision(cPlayer *, NIBBLETYPE a_Meta) virtual bool DoesIgnoreBuildCollision(cPlayer *, NIBBLETYPE a_Meta)
{ {
UNUSED(a_Meta); UNUSED(a_Meta);
return DoesIgnoreBuildCollision(); return DoesIgnoreBuildCollision();
} }
/// <summary>Returns if this block drops if it gets destroyed by an unsuitable situation. Default: true</summary> /** Returns if this block drops if it gets destroyed by an unsuitable situation.
Default: true */
virtual bool DoesDropOnUnsuitable(void); virtual bool DoesDropOnUnsuitable(void);
/** Called when one of the neighbors gets set; equivalent to MC block update. /** Called when one of the neighbors gets set; equivalent to MC block update.
By default drops if position no more suitable (CanBeAt(), DoesDropOnUnsuitable(), Drop()), By default drops if position no more suitable (CanBeAt(), DoesDropOnUnsuitable(), Drop()),
and wakes up all simulators on the block. and wakes up all simulators on the block. */
*/
virtual void Check(cChunkInterface & ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk); virtual void Check(cChunkInterface & ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk);
/// <summary>Rotates a given block meta counter-clockwise. Default: no change</summary> /// <summary>Rotates a given block meta counter-clockwise. Default: no change</summary>

View File

@ -12,16 +12,18 @@ class cBlockMobHeadHandler :
public cBlockEntityHandler public cBlockEntityHandler
{ {
public: public:
cBlockMobHeadHandler(BLOCKTYPE a_BlockType) cBlockMobHeadHandler(BLOCKTYPE a_BlockType):
: cBlockEntityHandler(a_BlockType) cBlockEntityHandler(a_BlockType)
{ {
} }
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{ {
// The drop spawn is in OnDestroyed method // The drop spawn is in the OnDestroyedByPlayer method
} }
virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override
{ {
if (a_Player->IsGameModeCreative()) if (a_Player->IsGameModeCreative())
@ -61,202 +63,6 @@ public:
a_WorldInterface.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, Callback); a_WorldInterface.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
} }
bool TrySpawnWither(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
{
if (a_BlockY < 2)
{
return false;
}
class cCallback : public cBlockEntityCallback
{
bool m_IsWither;
virtual bool Item(cBlockEntity * a_BlockEntity)
{
if (a_BlockEntity->GetBlockType() != E_BLOCK_HEAD)
{
return false;
}
cMobHeadEntity * MobHeadEntity = static_cast<cMobHeadEntity*>(a_BlockEntity);
m_IsWither = (MobHeadEntity->GetType() == SKULL_TYPE_WITHER);
return false;
}
public:
cCallback () : m_IsWither(false) {}
bool IsWither(void) const { return m_IsWither; }
void Reset(void) { m_IsWither = false; }
} CallbackA, CallbackB;
class cPlayerCallback : public cPlayerListCallback
{
Vector3f m_Pos;
virtual bool Item(cPlayer * a_Player)
{
// TODO 2014-05-21 xdot: Vanilla minecraft uses an AABB check instead of a radius one
double Dist = (a_Player->GetPosition() - m_Pos).Length();
if (Dist < 50.0)
{
// If player is close, award achievement
a_Player->AwardAchievement(achSpawnWither);
}
return false;
}
public:
cPlayerCallback(const Vector3f & a_Pos) : m_Pos(a_Pos) {}
} PlayerCallback(Vector3f((float)a_BlockX, (float)a_BlockY, (float)a_BlockZ));
a_WorldInterface.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, CallbackA);
if (!CallbackA.IsWither())
{
return false;
}
CallbackA.Reset();
BLOCKTYPE BlockY1 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
BLOCKTYPE BlockY2 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ);
if ((BlockY1 != E_BLOCK_SOULSAND) || (BlockY2 != E_BLOCK_SOULSAND))
{
return false;
}
a_WorldInterface.DoWithBlockEntityAt(a_BlockX - 1, a_BlockY, a_BlockZ, CallbackA);
a_WorldInterface.DoWithBlockEntityAt(a_BlockX + 1, a_BlockY, a_BlockZ, CallbackB);
BLOCKTYPE Block1 = a_ChunkInterface.GetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ);
BLOCKTYPE Block2 = a_ChunkInterface.GetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ);
if ((Block1 == E_BLOCK_SOULSAND) && (Block2 == E_BLOCK_SOULSAND) && CallbackA.IsWither() && CallbackB.IsWither())
{
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
// Block entities
a_ChunkInterface.SetBlock(a_BlockX + 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.SetBlock(a_BlockX - 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
// Spawn the wither:
a_WorldInterface.SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, mtWither);
// Award Achievement
a_WorldInterface.ForEachPlayer(PlayerCallback);
return true;
}
CallbackA.Reset();
CallbackB.Reset();
a_WorldInterface.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ - 1, CallbackA);
a_WorldInterface.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ + 1, CallbackB);
Block1 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1);
Block2 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1);
if ((Block1 == E_BLOCK_SOULSAND) && (Block2 == E_BLOCK_SOULSAND) && CallbackA.IsWither() && CallbackB.IsWither())
{
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
// Block entities
a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ + 1, E_BLOCK_AIR, 0);
a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ - 1, E_BLOCK_AIR, 0);
// Spawn the wither:
a_WorldInterface.SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, mtWither);
// Award Achievement
a_WorldInterface.ForEachPlayer(PlayerCallback);
return true;
}
return false;
}
virtual void OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
) override
{
class cCallback : public cBlockEntityCallback
{
cPlayer * m_Player;
NIBBLETYPE m_OldBlockMeta;
NIBBLETYPE m_NewBlockMeta;
virtual bool Item(cBlockEntity * a_BlockEntity)
{
if (a_BlockEntity->GetBlockType() != E_BLOCK_HEAD)
{
return false;
}
cMobHeadEntity * MobHeadEntity = static_cast<cMobHeadEntity*>(a_BlockEntity);
int Rotation = 0;
if (m_NewBlockMeta == 1)
{
Rotation = (int) floor(m_Player->GetYaw() * 16.0F / 360.0F + 0.5) & 0xF;
}
MobHeadEntity->SetType(static_cast<eMobHeadType>(m_OldBlockMeta));
MobHeadEntity->SetRotation(static_cast<eMobHeadRotation>(Rotation));
MobHeadEntity->GetWorld()->BroadcastBlockEntity(MobHeadEntity->GetPosX(), MobHeadEntity->GetPosY(), MobHeadEntity->GetPosZ());
return false;
}
public:
cCallback (cPlayer * a_CBPlayer, NIBBLETYPE a_OldBlockMeta, NIBBLETYPE a_NewBlockMeta) :
m_Player(a_CBPlayer),
m_OldBlockMeta(a_OldBlockMeta),
m_NewBlockMeta(a_NewBlockMeta)
{}
};
cCallback Callback(a_Player, a_BlockMeta, static_cast<NIBBLETYPE>(a_BlockFace));
a_BlockMeta = (NIBBLETYPE)a_BlockFace;
a_WorldInterface.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta);
if (a_BlockMeta == SKULL_TYPE_WITHER)
{
static const Vector3i Coords[] =
{
Vector3i( 0, 0, 0),
Vector3i( 1, 0, 0),
Vector3i(-1, 0, 0),
Vector3i( 0, 0, 1),
Vector3i( 0, 0, -1),
};
for (size_t i = 0; i < ARRAYCOUNT(Coords); ++i)
{
if (TrySpawnWither(a_ChunkInterface, a_WorldInterface, a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z))
{
break;
}
} // for i - Coords[]
}
}
} ; } ;

View File

@ -17,70 +17,6 @@ public:
} }
virtual void OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
{
// Check whether the pumpkin is a part of a golem or a snowman
if (a_BlockY < 2)
{
// The pumpkin is too low for a golem / snowman
return;
}
BLOCKTYPE BlockY1 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
BLOCKTYPE BlockY2 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ);
// Check for a snow golem:
if ((BlockY1 == E_BLOCK_SNOW_BLOCK) && (BlockY2 == E_BLOCK_SNOW_BLOCK))
{
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
a_WorldInterface.SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, mtSnowGolem);
return;
}
// Check for an iron golem. First check only the body and legs, since those are the same for both orientations:
if ((BlockY1 != E_BLOCK_IRON_BLOCK) || (BlockY2 != E_BLOCK_IRON_BLOCK))
{
// One of the blocks is not an iron, no chance of a golem here
return;
}
// Now check both orientations for hands:
if (
(a_ChunkInterface.GetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ) == E_BLOCK_IRON_BLOCK) &&
(a_ChunkInterface.GetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ) == E_BLOCK_IRON_BLOCK)
)
{
// Remove the iron blocks:
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
// Spawn the golem:
a_WorldInterface.SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, mtIronGolem);
}
else if (
(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1) == E_BLOCK_IRON_BLOCK) &&
(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1) == E_BLOCK_IRON_BLOCK)
)
{
// Remove the iron blocks:
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
// Spawn the golem:
a_WorldInterface.SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, mtIronGolem);
}
}
virtual bool GetPlacementBlockTypeMeta( virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer * a_Player, cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,

View File

@ -53,17 +53,6 @@ public:
} }
virtual void OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
) override
{
a_Player->GetClientHandle()->SendEditSign(a_BlockX, a_BlockY, a_BlockZ);
}
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
{ {
return (a_Meta + 4) & 0x0f; return (a_Meta + 4) & 0x0f;

View File

@ -27,17 +27,6 @@ public:
} }
virtual void OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
) override
{
a_Player->GetClientHandle()->SendEditSign(a_BlockX, a_BlockY, a_BlockZ);
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{ {
int BlockX = (a_Chunk.GetPosX() * cChunkDef::Width) + a_RelX; int BlockX = (a_Chunk.GetPosX() * cChunkDef::Width) + a_RelX;

View File

@ -13,6 +13,15 @@
/** When defined, each access to a cByteBuffer object is checked whether it's done in the same thread.
cByteBuffer assumes that it is not used by multiple threads at once, this macro adds a runtime check for that.
Unfortunately it is very slow, so it is disabled even for regular DEBUG builds. */
// #define DEBUG_SINGLE_THREAD_ACCESS
// Try to determine endianness: // Try to determine endianness:
#if ( \ #if ( \
defined(__i386__) || defined(__alpha__) || \ defined(__i386__) || defined(__alpha__) || \
@ -109,7 +118,7 @@ public:
#ifdef _DEBUG #ifdef DEBUG_SINGLE_THREAD_ACCESS
/** Simple RAII class that is used for checking that no two threads are using an object simultanously. /** Simple RAII class that is used for checking that no two threads are using an object simultanously.
It requires the monitored object to provide the storage for a thread ID. It requires the monitored object to provide the storage for a thread ID.
@ -122,7 +131,7 @@ public:
{ {
ASSERT( ASSERT(
(*a_ThreadID == std::this_thread::get_id()) || // Either the object is used by current thread... (*a_ThreadID == std::this_thread::get_id()) || // Either the object is used by current thread...
(*a_ThreadID == std::thread::id()) // ... or by no thread at all (*a_ThreadID == m_EmptyThreadID) // ... or by no thread at all
); );
// Mark as being used by this thread: // Mark as being used by this thread:
@ -138,8 +147,13 @@ public:
protected: protected:
/** Points to the storage used for ID of the thread using the object. */ /** Points to the storage used for ID of the thread using the object. */
std::thread::id * m_ThreadID; std::thread::id * m_ThreadID;
/** The value of an unassigned thread ID, used to speed up checking. */
static std::thread::id m_EmptyThreadID;
}; };
std::thread::id cSingleThreadAccessChecker::m_EmptyThreadID;
#define CHECK_THREAD cSingleThreadAccessChecker Checker(&m_ThreadID); #define CHECK_THREAD cSingleThreadAccessChecker Checker(&m_ThreadID);
#else #else
@ -330,12 +344,28 @@ bool cByteBuffer::ReadByte(unsigned char & a_Value)
bool cByteBuffer::ReadBEShort(short & a_Value) bool cByteBuffer::ReadBEShort(short & a_Value)
{
CHECK_THREAD
CheckValid();
NEEDBYTES(2);
Int16 val;
ReadBuf(&val, 2);
val = ntohs(val);
a_Value = *(reinterpret_cast<short *>(&val));
return true;
}
bool cByteBuffer::ReadBEUInt16(UInt16 & a_Value)
{ {
CHECK_THREAD CHECK_THREAD
CheckValid(); CheckValid();
NEEDBYTES(2); NEEDBYTES(2);
ReadBuf(&a_Value, 2); ReadBuf(&a_Value, 2);
a_Value = (short)ntohs((u_short)a_Value); a_Value = ntohs(a_Value);
return true; return true;
} }
@ -357,6 +387,20 @@ bool cByteBuffer::ReadBEInt(int & a_Value)
bool cByteBuffer::ReadBEUInt32(UInt32 & a_Value)
{
CHECK_THREAD
CheckValid();
NEEDBYTES(4);
ReadBuf(&a_Value, 4);
a_Value = ntohl(a_Value);
return true;
}
bool cByteBuffer::ReadBEInt64(Int64 & a_Value) bool cByteBuffer::ReadBEInt64(Int64 & a_Value)
{ {
CHECK_THREAD CHECK_THREAD

View File

@ -55,7 +55,9 @@ public:
bool ReadChar (char & a_Value); bool ReadChar (char & a_Value);
bool ReadByte (unsigned char & a_Value); bool ReadByte (unsigned char & a_Value);
bool ReadBEShort (short & a_Value); bool ReadBEShort (short & a_Value);
bool ReadBEUInt16 (UInt16 & a_Value);
bool ReadBEInt (int & a_Value); bool ReadBEInt (int & a_Value);
bool ReadBEUInt32 (UInt32 & a_Value);
bool ReadBEInt64 (Int64 & a_Value); bool ReadBEInt64 (Int64 & a_Value);
bool ReadBEFloat (float & a_Value); bool ReadBEFloat (float & a_Value);
bool ReadBEDouble (double & a_Value); bool ReadBEDouble (double & a_Value);

View File

@ -5,6 +5,7 @@ project (MCServer)
include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/") include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/")
include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/jsoncpp/include") include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/jsoncpp/include")
include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/polarssl/include") include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/polarssl/include")
include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/libevent/include")
set(FOLDERS set(FOLDERS
OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++ Bindings OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++ Bindings
@ -323,4 +324,4 @@ endif ()
if (WIN32) if (WIN32)
target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib) target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib)
endif() endif()
target_link_libraries(${EXECUTABLE} luaexpat jsoncpp polarssl zlib sqlite lua SQLiteCpp) target_link_libraries(${EXECUTABLE} luaexpat jsoncpp polarssl zlib sqlite lua SQLiteCpp event_core event_extra)

View File

@ -49,14 +49,14 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// sSetBlock: // sSetBlock:
sSetBlock::sSetBlock( int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) // absolute block position sSetBlock::sSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta):
: x( a_BlockX) m_RelX(a_BlockX),
, y( a_BlockY) m_RelY(a_BlockY),
, z( a_BlockZ) m_RelZ(a_BlockZ),
, BlockType( a_BlockType) m_BlockType(a_BlockType),
, BlockMeta( a_BlockMeta) m_BlockMeta(a_BlockMeta)
{ {
cChunkDef::AbsoluteToRelative(x, y, z, ChunkX, ChunkZ); cChunkDef::AbsoluteToRelative(m_RelX, m_RelY, m_RelZ, m_ChunkX, m_ChunkZ);
} }
@ -73,6 +73,7 @@ cChunk::cChunk(
cAllocationPool<cChunkData::sChunkSection> & a_Pool cAllocationPool<cChunkData::sChunkSection> & a_Pool
) : ) :
m_Presence(cpInvalid), m_Presence(cpInvalid),
m_ShouldGenerateIfLoadFailed(false),
m_IsLightValid(false), m_IsLightValid(false),
m_IsDirty(false), m_IsDirty(false),
m_IsSaving(false), m_IsSaving(false),
@ -93,6 +94,7 @@ cChunk::cChunk(
m_WaterSimulatorData(a_World->GetWaterSimulator()->CreateChunkData()), m_WaterSimulatorData(a_World->GetWaterSimulator()->CreateChunkData()),
m_LavaSimulatorData (a_World->GetLavaSimulator ()->CreateChunkData()), m_LavaSimulatorData (a_World->GetLavaSimulator ()->CreateChunkData()),
m_RedstoneSimulatorData(a_World->GetRedstoneSimulator()->CreateChunkData()), m_RedstoneSimulatorData(a_World->GetRedstoneSimulator()->CreateChunkData()),
m_IsRedstoneDirty(false),
m_AlwaysTicked(0) m_AlwaysTicked(0)
{ {
if (a_NeighborXM != nullptr) if (a_NeighborXM != nullptr)
@ -599,7 +601,7 @@ void cChunk::SpawnMobs(cMobSpawner& a_MobSpawner)
void cChunk::Tick(float a_Dt) void cChunk::Tick(std::chrono::milliseconds a_Dt)
{ {
BroadcastPendingBlockChanges(); BroadcastPendingBlockChanges();

View File

@ -160,7 +160,7 @@ public:
/** Try to Spawn Monsters inside chunk */ /** Try to Spawn Monsters inside chunk */
void SpawnMobs(cMobSpawner& a_MobSpawner); void SpawnMobs(cMobSpawner& a_MobSpawner);
void Tick(float a_Dt); void Tick(std::chrono::milliseconds a_Dt);
/** Ticks a single block. Used by cWorld::TickQueuedBlocks() to tick the queued blocks */ /** Ticks a single block. Used by cWorld::TickQueuedBlocks() to tick the queued blocks */
void TickBlock(int a_RelX, int a_RelY, int a_RelZ); void TickBlock(int a_RelX, int a_RelY, int a_RelZ);

View File

@ -347,18 +347,32 @@ public:
struct sSetBlock struct sSetBlock
{ {
int x, y, z; int m_RelX, m_RelY, m_RelZ;
int ChunkX, ChunkZ; int m_ChunkX, m_ChunkZ;
BLOCKTYPE BlockType; BLOCKTYPE m_BlockType;
NIBBLETYPE BlockMeta; NIBBLETYPE m_BlockMeta;
sSetBlock( int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); // absolute block position sSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
sSetBlock(int a_ChunkX, int a_ChunkZ, int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) :
x(a_X), y(a_Y), z(a_Z), sSetBlock(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) :
ChunkX(a_ChunkX), ChunkZ(a_ChunkZ), m_RelX(a_RelX), m_RelY(a_RelY), m_RelZ(a_RelZ),
BlockType(a_BlockType), m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ),
BlockMeta(a_BlockMeta) m_BlockType(a_BlockType),
{} m_BlockMeta(a_BlockMeta)
{
ASSERT((a_RelX >= 0) && (a_RelX < cChunkDef::Width));
ASSERT((a_RelZ >= 0) && (a_RelZ < cChunkDef::Width));
}
/** Returns the absolute X coord of the stored block. */
int GetX(void) const { return m_RelX + cChunkDef::Width * m_ChunkX; }
/** Returns the absolute Y coord of the stored block.
Is the same as relative Y coords, because there's no Y relativization. */
int GetY(void) const { return m_RelY; }
/** Returns the absolute Z coord of the stored block. */
int GetZ(void) const { return m_RelZ + cChunkDef::Width * m_ChunkZ; }
}; };
typedef std::list<sSetBlock> sSetBlockList; typedef std::list<sSetBlock> sSetBlockList;
@ -385,6 +399,17 @@ public:
typedef std::list<cChunkCoords> cChunkCoordsList; typedef std::list<cChunkCoords> cChunkCoordsList;
typedef std::vector<cChunkCoords> cChunkCoordsVector; typedef std::vector<cChunkCoords> cChunkCoordsVector;
/** A simple hash function for chunk coords, we assume that chunk coords won't use more than 16 bits, so the hash is almost an identity.
Used for std::unordered_map<cChunkCoords, ...> */
class cChunkCoordsHash
{
public:
size_t operator () (const cChunkCoords & a_Coords) const
{
return (static_cast<size_t>(a_Coords.m_ChunkX) << 16) ^ static_cast<size_t>(a_Coords.m_ChunkZ);
}
};

View File

@ -1101,17 +1101,17 @@ void cChunkMap::FastSetBlocks(sSetBlockList & a_BlockList)
// Process all items from a_BlockList, either successfully or by placing into Failed // Process all items from a_BlockList, either successfully or by placing into Failed
while (!a_BlockList.empty()) while (!a_BlockList.empty())
{ {
int ChunkX = a_BlockList.front().ChunkX; int ChunkX = a_BlockList.front().m_ChunkX;
int ChunkZ = a_BlockList.front().ChunkZ; int ChunkZ = a_BlockList.front().m_ChunkZ;
cCSLock Lock(m_CSLayers); cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ);
if ((Chunk != nullptr) && Chunk->IsValid()) if ((Chunk != nullptr) && Chunk->IsValid())
{ {
for (sSetBlockList::iterator itr = a_BlockList.begin(); itr != a_BlockList.end();) for (sSetBlockList::iterator itr = a_BlockList.begin(); itr != a_BlockList.end();)
{ {
if ((itr->ChunkX == ChunkX) && (itr->ChunkZ == ChunkZ)) if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ))
{ {
Chunk->FastSetBlock(itr->x, itr->y, itr->z, itr->BlockType, itr->BlockMeta); Chunk->FastSetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta);
itr = a_BlockList.erase(itr); itr = a_BlockList.erase(itr);
} }
else else
@ -1125,7 +1125,7 @@ void cChunkMap::FastSetBlocks(sSetBlockList & a_BlockList)
// The chunk is not valid, move all blocks within this chunk to Failed // The chunk is not valid, move all blocks within this chunk to Failed
for (sSetBlockList::iterator itr = a_BlockList.begin(); itr != a_BlockList.end();) for (sSetBlockList::iterator itr = a_BlockList.begin(); itr != a_BlockList.end();)
{ {
if ((itr->ChunkX == ChunkX) && (itr->ChunkZ == ChunkZ)) if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ))
{ {
Failed.push_back(*itr); Failed.push_back(*itr);
itr = a_BlockList.erase(itr); itr = a_BlockList.erase(itr);
@ -1146,6 +1146,34 @@ void cChunkMap::FastSetBlocks(sSetBlockList & a_BlockList)
void cChunkMap::SetBlocks(const sSetBlockVector & a_Blocks)
{
cCSLock lock(m_CSLayers);
cChunkPtr chunk = nullptr;
int lastChunkX = 0x7fffffff; // Bogus coords so that chunk is updated on first pass
int lastChunkZ = 0x7fffffff;
for (auto block: a_Blocks)
{
// Update the chunk, if different from last time:
if ((block.m_ChunkX != lastChunkX) || (block.m_ChunkZ != lastChunkZ))
{
lastChunkX = block.m_ChunkX;
lastChunkZ = block.m_ChunkZ;
chunk = GetChunk(lastChunkX, lastChunkZ);
}
// If the chunk is valid, set the block:
if (chunk != nullptr)
{
chunk->SetBlock(block.m_RelX, block.m_RelY, block.m_RelZ, block.m_BlockType, block.m_BlockMeta);
}
} // for block - a_Blocks[]
}
void cChunkMap::CollectPickupsByPlayer(cPlayer & a_Player) void cChunkMap::CollectPickupsByPlayer(cPlayer & a_Player)
{ {
int BlockX = (int)(a_Player.GetPosX()); // Truncating doesn't matter much; we're scanning entire chunks anyway int BlockX = (int)(a_Player.GetPosX()); // Truncating doesn't matter much; we're scanning entire chunks anyway
@ -1175,28 +1203,28 @@ void cChunkMap::CollectPickupsByPlayer(cPlayer & a_Player)
BLOCKTYPE cChunkMap::GetBlock(int a_BlockX, int a_BlockY, int a_BlockZ) BLOCKTYPE cChunkMap::GetBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
int X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
int ChunkX, ChunkZ;
cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ);
// First check if it isn't queued in the m_FastSetBlockQueue: // First check if it isn't queued in the m_FastSetBlockQueue:
{ {
int X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
int ChunkX, ChunkZ;
cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ);
cCSLock Lock(m_CSFastSetBlock); cCSLock Lock(m_CSFastSetBlock);
for (sSetBlockList::iterator itr = m_FastSetBlockQueue.begin(); itr != m_FastSetBlockQueue.end(); ++itr) for (sSetBlockList::iterator itr = m_FastSetBlockQueue.begin(); itr != m_FastSetBlockQueue.end(); ++itr)
{ {
if ((itr->x == X) && (itr->y == Y) && (itr->z == Z) && (itr->ChunkX == ChunkX) && (itr->ChunkZ == ChunkZ)) if ((itr->m_RelX == X) && (itr->m_RelY == Y) && (itr->m_RelZ == Z) && (itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ))
{ {
return itr->BlockType; return itr->m_BlockType;
} }
} // for itr - m_FastSetBlockQueue[] } // for itr - m_FastSetBlockQueue[]
} }
int ChunkX, ChunkZ;
cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); // Not in the queue, query the chunk, if loaded:
cCSLock Lock(m_CSLayers); cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ);
if ((Chunk != nullptr) && Chunk->IsValid()) if ((Chunk != nullptr) && Chunk->IsValid())
{ {
return Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ); return Chunk->GetBlock(X, Y, Z);
} }
return 0; return 0;
} }
@ -1207,25 +1235,28 @@ BLOCKTYPE cChunkMap::GetBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
NIBBLETYPE cChunkMap::GetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ) NIBBLETYPE cChunkMap::GetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
int X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
int ChunkX, ChunkZ;
cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ);
// First check if it isn't queued in the m_FastSetBlockQueue: // First check if it isn't queued in the m_FastSetBlockQueue:
{ {
cCSLock Lock(m_CSFastSetBlock); cCSLock Lock(m_CSFastSetBlock);
for (sSetBlockList::iterator itr = m_FastSetBlockQueue.begin(); itr != m_FastSetBlockQueue.end(); ++itr) for (sSetBlockList::iterator itr = m_FastSetBlockQueue.begin(); itr != m_FastSetBlockQueue.end(); ++itr)
{ {
if ((itr->x == a_BlockX) && (itr->y == a_BlockY) && (itr->z == a_BlockZ)) if ((itr->m_RelX == X) && (itr->m_RelY == Y) && (itr->m_RelZ == Z) && (itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ))
{ {
return itr->BlockMeta; return itr->m_BlockMeta;
} }
} // for itr - m_FastSetBlockQueue[] } // for itr - m_FastSetBlockQueue[]
} }
int ChunkX, ChunkZ;
cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); // Not in the queue, query the chunk, if loaded:
cCSLock Lock(m_CSLayers); cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ);
if ((Chunk != nullptr) && Chunk->IsValid()) if ((Chunk != nullptr) && Chunk->IsValid())
{ {
return Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ); return Chunk->GetMeta(X, Y, Z);
} }
return 0; return 0;
} }
@ -1373,14 +1404,14 @@ void cChunkMap::ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_Filt
cCSLock Lock(m_CSLayers); cCSLock Lock(m_CSLayers);
for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr)
{ {
cChunkPtr Chunk = GetChunk(itr->ChunkX, itr->ChunkZ); cChunkPtr Chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkZ);
if ((Chunk == nullptr) || !Chunk->IsValid()) if ((Chunk == nullptr) || !Chunk->IsValid())
{ {
continue; continue;
} }
if (Chunk->GetBlock(itr->x, itr->y, itr->z) == a_FilterBlockType) if (Chunk->GetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ) == a_FilterBlockType)
{ {
Chunk->SetBlock(itr->x, itr->y, itr->z, itr->BlockType, itr->BlockMeta); Chunk->SetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta);
} }
} }
} }
@ -1394,24 +1425,24 @@ void cChunkMap::ReplaceTreeBlocks(const sSetBlockVector & a_Blocks)
cCSLock Lock(m_CSLayers); cCSLock Lock(m_CSLayers);
for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr)
{ {
cChunkPtr Chunk = GetChunk(itr->ChunkX, itr->ChunkZ); cChunkPtr Chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkZ);
if ((Chunk == nullptr) || !Chunk->IsValid()) if ((Chunk == nullptr) || !Chunk->IsValid())
{ {
continue; continue;
} }
switch (Chunk->GetBlock(itr->x, itr->y, itr->z)) switch (Chunk->GetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ))
{ {
CASE_TREE_OVERWRITTEN_BLOCKS: CASE_TREE_OVERWRITTEN_BLOCKS:
{ {
Chunk->SetBlock(itr->x, itr->y, itr->z, itr->BlockType, itr->BlockMeta); Chunk->SetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta);
break; break;
} }
case E_BLOCK_LEAVES: case E_BLOCK_LEAVES:
case E_BLOCK_NEW_LEAVES: case E_BLOCK_NEW_LEAVES:
{ {
if ((itr->BlockType == E_BLOCK_LOG) || (itr->BlockType == E_BLOCK_NEW_LOG)) if ((itr->m_BlockType == E_BLOCK_LOG) || (itr->m_BlockType == E_BLOCK_NEW_LOG))
{ {
Chunk->SetBlock(itr->x, itr->y, itr->z, itr->BlockType, itr->BlockMeta); Chunk->SetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta);
} }
break; break;
} }
@ -1507,7 +1538,7 @@ bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
cCSLock Lock(m_CSLayers); cCSLock Lock(m_CSLayers);
for (sSetBlockVector::iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) for (sSetBlockVector::iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr)
{ {
cChunkPtr Chunk = GetChunk(itr->ChunkX, itr->ChunkZ); cChunkPtr Chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkZ);
if ((Chunk == nullptr) || !Chunk->IsValid()) if ((Chunk == nullptr) || !Chunk->IsValid())
{ {
if (!a_ContinueOnFailure) if (!a_ContinueOnFailure)
@ -1517,8 +1548,8 @@ bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
res = false; res = false;
continue; continue;
} }
itr->BlockType = Chunk->GetBlock(itr->x, itr->y, itr->z); itr->m_BlockType = Chunk->GetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ);
itr->BlockMeta = Chunk->GetMeta(itr->x, itr->y, itr->z); itr->m_BlockMeta = Chunk->GetMeta(itr->m_RelX, itr->m_RelY, itr->m_RelZ);
} }
return res; return res;
} }
@ -1527,11 +1558,11 @@ bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
bool cChunkMap::DigBlock(int a_X, int a_Y, int a_Z) bool cChunkMap::DigBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
int PosX = a_X, PosY = a_Y, PosZ = a_Z, ChunkX, ChunkZ; int PosX = a_BlockX, PosY = a_BlockY, PosZ = a_BlockZ, ChunkX, ChunkZ;
cChunkDef::AbsoluteToRelative( PosX, PosY, PosZ, ChunkX, ChunkZ); cChunkDef::AbsoluteToRelative(PosX, PosY, PosZ, ChunkX, ChunkZ);
{ {
cCSLock Lock(m_CSLayers); cCSLock Lock(m_CSLayers);
@ -1542,7 +1573,7 @@ bool cChunkMap::DigBlock(int a_X, int a_Y, int a_Z)
} }
DestChunk->SetBlock(PosX, PosY, PosZ, E_BLOCK_AIR, 0); DestChunk->SetBlock(PosX, PosY, PosZ, E_BLOCK_AIR, 0);
m_World->GetSimulatorManager()->WakeUp(a_X, a_Y, a_Z, DestChunk); m_World->GetSimulatorManager()->WakeUp(a_BlockX, a_BlockY, a_BlockZ, DestChunk);
} }
return true; return true;
@ -2689,7 +2720,7 @@ void cChunkMap::SpawnMobs(cMobSpawner& a_MobSpawner)
void cChunkMap::Tick(float a_Dt) void cChunkMap::Tick(std::chrono::milliseconds a_Dt)
{ {
cCSLock Lock(m_CSLayers); cCSLock Lock(m_CSLayers);
for (cChunkLayerList::iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr) for (cChunkLayerList::iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr)
@ -2917,7 +2948,7 @@ void cChunkMap::cChunkLayer::SpawnMobs(cMobSpawner& a_MobSpawner)
void cChunkMap::cChunkLayer::Tick(float a_Dt) void cChunkMap::cChunkLayer::Tick(std::chrono::milliseconds a_Dt)
{ {
for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++)
{ {

View File

@ -143,7 +143,13 @@ public:
void FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); void FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
void FastSetQueuedBlocks(); void FastSetQueuedBlocks();
void FastSetBlocks (sSetBlockList & a_BlockList); void FastSetBlocks(sSetBlockList & a_BlockList);
/** Performs the specified single-block set operations simultaneously, as if SetBlock() was called for each item.
Is more efficient than calling SetBlock() multiple times.
If the chunk for any of the blocks is not loaded, the set operation is ignored silently. */
void SetBlocks(const sSetBlockVector & a_Blocks);
void CollectPickupsByPlayer(cPlayer & a_Player); void CollectPickupsByPlayer(cPlayer & a_Player);
BLOCKTYPE GetBlock (int a_BlockX, int a_BlockY, int a_BlockZ); BLOCKTYPE GetBlock (int a_BlockX, int a_BlockY, int a_BlockZ);
@ -173,11 +179,20 @@ public:
(Re)sends the chunks to their relevant clients if successful. */ (Re)sends the chunks to their relevant clients if successful. */
bool SetAreaBiome(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, EMCSBiome a_Biome); bool SetAreaBiome(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, EMCSBiome a_Biome);
/** Retrieves block types of the specified blocks. If a chunk is not loaded, doesn't modify the block. Returns true if all blocks were read. */ /** Retrieves block types and metas of the specified blocks.
If a chunk is not loaded, doesn't modify the block and consults a_ContinueOnFailure whether to process the rest of the array.
Returns true if all blocks were read, false if any one failed. */
bool GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure); bool GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure);
bool DigBlock (int a_X, int a_Y, int a_Z); /** Removes the block at the specified coords and wakes up simulators.
void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player); Returns false if the chunk is not loaded (and the block is not dug).
Returns true if successful. */
bool DigBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
/** Sends the block at the specified coords to the specified player.
Uses a blockchange packet to send the block.
If the relevant chunk isn't loaded, doesn't do anything. */
void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer * a_Player);
/** Compares clients of two chunks, calls the callback accordingly */ /** Compares clients of two chunks, calls the callback accordingly */
void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback); void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback);
@ -333,7 +348,7 @@ public:
/** Try to Spawn Monsters inside all Chunks */ /** Try to Spawn Monsters inside all Chunks */
void SpawnMobs(cMobSpawner& a_MobSpawner); void SpawnMobs(cMobSpawner& a_MobSpawner);
void Tick(float a_Dt); void Tick(std::chrono::milliseconds a_Dt);
/** Ticks a single block. Used by cWorld::TickQueuedBlocks() to tick the queued blocks */ /** Ticks a single block. Used by cWorld::TickQueuedBlocks() to tick the queued blocks */
void TickBlock(int a_BlockX, int a_BlockY, int a_BlockZ); void TickBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
@ -400,7 +415,7 @@ private:
/** Try to Spawn Monsters inside all Chunks */ /** Try to Spawn Monsters inside all Chunks */
void SpawnMobs(cMobSpawner& a_MobSpawner); void SpawnMobs(cMobSpawner& a_MobSpawner);
void Tick(float a_Dt); void Tick(std::chrono::milliseconds a_Dt);
void RemoveClient(cClientHandle * a_Client); void RemoveClient(cClientHandle * a_Client);

View File

@ -1349,12 +1349,19 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
if (ItemHandler->IsPlaceable() && (a_BlockFace != BLOCK_FACE_NONE)) if (ItemHandler->IsPlaceable() && (a_BlockFace != BLOCK_FACE_NONE))
{ {
HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler); if (!ItemHandler->OnPlayerPlace(*World, *m_Player, Equipped, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
{
// Placement failed, bail out
return;
}
} }
else if ((ItemHandler->IsFood() || ItemHandler->IsDrinkable(EquippedDamage))) else if ((ItemHandler->IsFood() || ItemHandler->IsDrinkable(EquippedDamage)))
{ {
if ((m_Player->IsSatiated() || m_Player->IsGameModeCreative()) && if (
ItemHandler->IsFood() && (Equipped.m_ItemType != E_ITEM_GOLDEN_APPLE)) (m_Player->IsSatiated() || m_Player->IsGameModeCreative()) && // Only creative or hungry players can eat
ItemHandler->IsFood() &&
(Equipped.m_ItemType != E_ITEM_GOLDEN_APPLE) // Golden apple is a special case, it is used instead of eaten
)
{ {
// The player is satiated or in creative, and trying to eat // The player is satiated or in creative, and trying to eat
return; return;
@ -1382,151 +1389,6 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, cItemHandler & a_ItemHandler)
{
BLOCKTYPE EquippedBlock = (BLOCKTYPE)(m_Player->GetEquippedItem().m_ItemType);
if (a_BlockFace < 0)
{
// Clicked in air
return;
}
cWorld * World = m_Player->GetWorld();
BLOCKTYPE ClickedBlock;
NIBBLETYPE ClickedBlockMeta;
NIBBLETYPE EquippedBlockDamage = (NIBBLETYPE)(m_Player->GetEquippedItem().m_ItemDamage);
if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
{
// The block is being placed outside the world, ignore this packet altogether (#128)
return;
}
World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlock, ClickedBlockMeta);
// Special slab handling - placing a slab onto another slab produces a dblslab instead:
if (
cBlockSlabHandler::IsAnySlabType(ClickedBlock) && // Is there a slab already?
cBlockSlabHandler::IsAnySlabType(EquippedBlock) && // Is the player placing another slab?
((ClickedBlockMeta & 0x07) == EquippedBlockDamage) && // Is it the same slab type?
(
(a_BlockFace == BLOCK_FACE_TOP) || // Clicking the top of a bottom slab
(a_BlockFace == BLOCK_FACE_BOTTOM) // Clicking the bottom of a top slab
)
)
{
// Coordinates at clicked block, which was an eligible slab, and either top or bottom faces were clicked
// If clicked top face and slab occupies the top voxel, we want a slab to be placed above it (therefore increment Y)
// Else if clicked bottom face and slab occupies the bottom voxel, decrement Y for the same reason
// Don't touch coordinates if anything else because a dblslab opportunity is present
if ((ClickedBlockMeta & 0x08) && (a_BlockFace == BLOCK_FACE_TOP))
{
++a_BlockY;
}
else if (!(ClickedBlockMeta & 0x08) && (a_BlockFace == BLOCK_FACE_BOTTOM))
{
--a_BlockY;
}
World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlock, ClickedBlockMeta);
}
else
{
// Check if the block ignores build collision (water, grass etc.):
if (
BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision() ||
BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision(m_Player, ClickedBlockMeta)
)
{
cChunkInterface ChunkInterface(World->GetChunkMap());
BlockHandler(ClickedBlock)->OnDestroyedByPlayer(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ);
}
else
{
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
{
// The block is being placed outside the world, ignore this packet altogether (#128)
return;
}
NIBBLETYPE PlaceMeta;
BLOCKTYPE PlaceBlock;
World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, PlaceBlock, PlaceMeta);
// Clicked on side of block, make sure that placement won't be cancelled if there is a slab able to be double slabbed.
// No need to do combinability (dblslab) checks, client will do that here.
if (cBlockSlabHandler::IsAnySlabType(PlaceBlock))
{
// It's a slab, don't do checks and proceed to double-slabbing
}
else
{
if (
!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision() &&
!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision(m_Player, PlaceMeta)
)
{
// Tried to place a block *into* another?
// Happens when you place a block aiming at side of block with a torch on it or stem beside it
return;
}
}
}
}
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
if (!a_ItemHandler.GetPlacementBlockTypeMeta(World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
{
// Handler refused the placement, send that information back to the client:
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
m_Player->GetInventory().SendEquippedSlot();
return;
}
cBlockHandler * NewBlock = BlockHandler(BlockType);
if (cRoot::Get()->GetPluginManager()->CallHookPlayerPlacingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
{
// A plugin doesn't agree with placing the block, revert the block on the client:
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
m_Player->GetInventory().SendEquippedSlot();
return;
}
// The actual block placement:
World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
if (!m_Player->IsGameModeCreative())
{
m_Player->GetInventory().RemoveOneEquippedItem();
}
cChunkInterface ChunkInterface(World->GetChunkMap());
NewBlock->OnPlacedByPlayer(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
AString PlaceSound = cBlockInfo::GetPlaceSound(BlockType);
float Volume = 1.0f, Pitch = 0.8f;
if (PlaceSound == "dig.metal")
{
Pitch = 1.2f;
PlaceSound = "dig.stone";
}
else if (PlaceSound == "random.anvil_land")
{
Volume = 0.65f;
}
World->BroadcastSoundEffect(PlaceSound, a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, Volume, Pitch);
cRoot::Get()->GetPluginManager()->CallHookPlayerPlacedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
}
void cClientHandle::HandleChat(const AString & a_Message) void cClientHandle::HandleChat(const AString & a_Message)
{ {
// We no longer need to postpone message processing, because the messages already arrive in the Tick thread // We no longer need to postpone message processing, because the messages already arrive in the Tick thread
@ -1586,7 +1448,7 @@ void cClientHandle::HandlePlayerMoveLook(double a_PosX, double a_PosY, double a_
void cClientHandle::HandleAnimation(char a_Animation) void cClientHandle::HandleAnimation(int a_Animation)
{ {
if (cPluginManager::Get()->CallHookPlayerAnimation(*m_Player, a_Animation)) if (cPluginManager::Get()->CallHookPlayerAnimation(*m_Player, a_Animation))
{ {
@ -2973,7 +2835,7 @@ void cClientHandle::PacketUnknown(UInt32 a_PacketType)
void cClientHandle::PacketError(unsigned char a_PacketType) void cClientHandle::PacketError(UInt32 a_PacketType)
{ {
LOGERROR("Protocol error while parsing packet type 0x%02x; disconnecting client \"%s\"", a_PacketType, m_Username.c_str()); LOGERROR("Protocol error while parsing packet type 0x%02x; disconnecting client \"%s\"", a_PacketType, m_Username.c_str());
SendDisconnect("Protocol error"); SendDisconnect("Protocol error");

View File

@ -251,10 +251,10 @@ public:
// Calls that cProtocol descendants use to report state: // Calls that cProtocol descendants use to report state:
void PacketBufferFull(void); void PacketBufferFull(void);
void PacketUnknown(UInt32 a_PacketType); void PacketUnknown(UInt32 a_PacketType);
void PacketError(unsigned char a_PacketType); void PacketError(UInt32 a_PacketType);
// Calls that cProtocol descendants use for handling packets: // Calls that cProtocol descendants use for handling packets:
void HandleAnimation(char a_Animation); void HandleAnimation(int a_Animation);
/** Called when the protocol receives a MC|ItemName plugin message, indicating that the player named /** Called when the protocol receives a MC|ItemName plugin message, indicating that the player named
an item in the anvil UI. */ an item in the anvil UI. */
@ -459,9 +459,6 @@ private:
UInt32 m_ProtocolVersion; UInt32 m_ProtocolVersion;
/** Handles the block placing packet when it is a real block placement (not block-using, item-using or eating) */
void HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, cItemHandler & a_ItemHandler);
/** Returns true if the rate block interactions is within a reasonable limit (bot protection) */ /** Returns true if the rate block interactions is within a reasonable limit (bot protection) */
bool CheckBlockInteractionsRate(void); bool CheckBlockInteractionsRate(void);

View File

@ -183,6 +183,7 @@ int cEnchantments::StringToEnchantmentID(const AString & a_EnchantmentName)
{ enchRespiration, "Respiration"}, { enchRespiration, "Respiration"},
{ enchAquaAffinity, "AquaAffinity"}, { enchAquaAffinity, "AquaAffinity"},
{ enchThorns, "Thorns"}, { enchThorns, "Thorns"},
{ enchDepthStrider, "DepthStrider"},
{ enchSharpness, "Sharpness"}, { enchSharpness, "Sharpness"},
{ enchSmite, "Smite"}, { enchSmite, "Smite"},
{ enchBaneOfArthropods, "BaneOfArthropods"}, { enchBaneOfArthropods, "BaneOfArthropods"},
@ -506,6 +507,20 @@ void cEnchantments::AddItemEnchantmentWeights(cWeightedEnchantments & a_Enchantm
{ {
AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 1); AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 1);
} }
// Depth Strider
if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 45))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchDepthStrider, 3);
}
else if ((a_EnchantmentLevel >= 20) && (a_EnchantmentLevel <= 35))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchDepthStrider, 2);
}
else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 25))
{
AddEnchantmentWeightToVector(a_Enchantments, 2, enchDepthStrider, 1);
}
} }
} }
@ -1021,26 +1036,34 @@ cEnchantments cEnchantments::GetRandomEnchantmentFromVector(cWeightedEnchantment
cEnchantments cEnchantments::GenerateEnchantmentFromVector(cWeightedEnchantments & a_Enchantments, int a_Seed) cEnchantments cEnchantments::SelectEnchantmentFromVector(const cWeightedEnchantments & a_Enchantments, int a_Seed)
{ {
// Sum up all the enchantments' weights:
int AllWeights = 0; int AllWeights = 0;
for (const auto Enchantment : a_Enchantments) for (const auto Enchantment : a_Enchantments)
{ {
AllWeights += Enchantment.m_Weight; AllWeights += Enchantment.m_Weight;
} }
// If there's no weight for any of the enchantments, return an empty enchantment
if (AllWeights <= 0)
{
return cEnchantments();
}
// Pick a random enchantment:
cNoise Noise(a_Seed); cNoise Noise(a_Seed);
int RandomNumber = Noise.IntNoise1DInt(AllWeights) / 7 % AllWeights; int RandomNumber = Noise.IntNoise1DInt(AllWeights) / 7 % AllWeights;
for (const auto Enchantment : a_Enchantments) for (const auto Enchantment : a_Enchantments)
{ {
RandomNumber -= Enchantment.m_Weight; RandomNumber -= Enchantment.m_Weight;
if (RandomNumber < 0) if (RandomNumber <= 0)
{ {
return Enchantment.m_Enchantments; return Enchantment.m_Enchantments;
} }
} }
// No enchantment picked, return an empty one (we probably shouldn't ever get here):
return cEnchantments(); return cEnchantments();
} }

View File

@ -53,6 +53,7 @@ public:
enchRespiration = 5, enchRespiration = 5,
enchAquaAffinity = 6, enchAquaAffinity = 6,
enchThorns = 7, enchThorns = 7,
enchDepthStrider = 8,
enchSharpness = 16, enchSharpness = 16,
enchSmite = 17, enchSmite = 17,
enchBaneOfArthropods = 18, enchBaneOfArthropods = 18,
@ -128,8 +129,10 @@ public:
/** Gets random enchantment from Vector and returns it */ /** Gets random enchantment from Vector and returns it */
static cEnchantments GetRandomEnchantmentFromVector(cWeightedEnchantments & a_Enchantments); static cEnchantments GetRandomEnchantmentFromVector(cWeightedEnchantments & a_Enchantments);
/** Returns an enchantment from a Vector using cNoise. Mostly used for generators.*/ /** Selects one enchantment from a Vector using cNoise. Mostly used for generators.
static cEnchantments GenerateEnchantmentFromVector(cWeightedEnchantments & a_Enchantments, int a_Seed); Uses the enchantments' weights for the random distribution.
If a_Enchantments is empty, returns an empty enchantment. */
static cEnchantments SelectEnchantmentFromVector(const cWeightedEnchantments & a_Enchantments, int a_Seed);
/** Returns true if a_Other doesn't contain exactly the same enchantments and levels */ /** Returns true if a_Other doesn't contain exactly the same enchantments and levels */
bool operator !=(const cEnchantments & a_Other) const; bool operator !=(const cEnchantments & a_Other) const;

View File

@ -174,20 +174,20 @@ void cArrowEntity::CollectedBy(cPlayer & a_Dest)
void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk) void cArrowEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
super::Tick(a_Dt, a_Chunk); super::Tick(a_Dt, a_Chunk);
m_Timer += a_Dt; m_Timer += a_Dt;
if (m_bIsCollected) if (m_bIsCollected)
{ {
if (m_Timer > 500.f) // 0.5 seconds if (m_Timer > std::chrono::milliseconds(500))
{ {
Destroy(); Destroy();
return; return;
} }
} }
else if (m_Timer > 1000 * 60 * 5) // 5 minutes else if (m_Timer > std::chrono::minutes(5))
{ {
Destroy(); Destroy();
return; return;
@ -202,7 +202,7 @@ void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk)
if (!m_HasTeleported) // Sent a teleport already, don't do again if (!m_HasTeleported) // Sent a teleport already, don't do again
{ {
if (m_HitGroundTimer > 500.f) // Send after half a second, could be less, but just in case if (m_HitGroundTimer > std::chrono::milliseconds(500))
{ {
m_World->BroadcastTeleportEntity(*this); m_World->BroadcastTeleportEntity(*this);
m_HasTeleported = true; m_HasTeleported = true;

View File

@ -85,10 +85,10 @@ protected:
bool m_IsCritical; bool m_IsCritical;
/** Timer for pickup collection animation or five minute timeout */ /** Timer for pickup collection animation or five minute timeout */
float m_Timer; std::chrono::milliseconds m_Timer;
/** Timer for client arrow position confirmation via TeleportEntity */ /** Timer for client arrow position confirmation via TeleportEntity */
float m_HitGroundTimer; std::chrono::milliseconds m_HitGroundTimer;
// Whether the arrow has already been teleported into the proper position in the ground. // Whether the arrow has already been teleported into the proper position in the ground.
bool m_HasTeleported; bool m_HasTeleported;
@ -103,6 +103,6 @@ protected:
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
virtual void CollectedBy(cPlayer & a_Player) override; virtual void CollectedBy(cPlayer & a_Player) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
}; // tolua_export }; // tolua_export

View File

@ -91,7 +91,7 @@ void cBoat::OnRightClicked(cPlayer & a_Player)
void cBoat::Tick(float a_Dt, cChunk & a_Chunk) void cBoat::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
super::Tick(a_Dt, a_Chunk); super::Tick(a_Dt, a_Chunk);
BroadcastMovementUpdate(); BroadcastMovementUpdate();

View File

@ -27,7 +27,7 @@ public:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void OnRightClicked(cPlayer & a_Player) override; virtual void OnRightClicked(cPlayer & a_Player) override;
virtual bool DoTakeDamage(TakeDamageInfo & TDI) override; virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void HandleSpeedFromAttachee(float a_Forward, float a_Sideways) override; virtual void HandleSpeedFromAttachee(float a_Forward, float a_Sideways) override;
cBoat(double a_X, double a_Y, double a_Z); cBoat(double a_X, double a_Y, double a_Z);

View File

@ -29,7 +29,7 @@ void cEnderCrystal::SpawnOn(cClientHandle & a_ClientHandle)
void cEnderCrystal::Tick(float a_Dt, cChunk & a_Chunk) void cEnderCrystal::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
UNUSED(a_Dt); UNUSED(a_Dt);
// No further processing (physics e.t.c.) is needed // No further processing (physics e.t.c.) is needed

View File

@ -23,7 +23,7 @@ private:
// cEntity overrides: // cEntity overrides:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void KilledBy(TakeDamageInfo & a_TDI) override; virtual void KilledBy(TakeDamageInfo & a_TDI) override;
}; // tolua_export }; // tolua_export

View File

@ -772,7 +772,7 @@ void cEntity::SetHealth(int a_Health)
void cEntity::Tick(float a_Dt, cChunk & a_Chunk) void cEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
m_TicksAlive++; m_TicksAlive++;
@ -841,7 +841,7 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) void cEntity::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
int BlockX = POSX_TOINT; int BlockX = POSX_TOINT;
int BlockY = POSY_TOINT; int BlockY = POSY_TOINT;
@ -851,15 +851,15 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
GET_AND_VERIFY_CURRENT_CHUNK(NextChunk, BlockX, BlockZ) GET_AND_VERIFY_CURRENT_CHUNK(NextChunk, BlockX, BlockZ)
// TODO Add collision detection with entities. // TODO Add collision detection with entities.
a_Dt /= 1000; // Convert from msec to sec auto DtSec = std::chrono::duration_cast<std::chrono::duration<double>>(a_Dt);
Vector3d NextPos = Vector3d(GetPosX(), GetPosY(), GetPosZ()); Vector3d NextPos = Vector3d(GetPosX(), GetPosY(), GetPosZ());
Vector3d NextSpeed = Vector3d(GetSpeedX(), GetSpeedY(), GetSpeedZ()); Vector3d NextSpeed = Vector3d(GetSpeedX(), GetSpeedY(), GetSpeedZ());
if ((BlockY >= cChunkDef::Height) || (BlockY < 0)) if ((BlockY >= cChunkDef::Height) || (BlockY < 0))
{ {
// Outside of the world // Outside of the world
AddSpeedY(m_Gravity * a_Dt); AddSpeedY(m_Gravity * DtSec.count());
AddPosition(GetSpeed() * a_Dt); AddPosition(GetSpeed() * DtSec.count());
return; return;
} }
@ -927,11 +927,11 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
if (!m_bOnGround) if (!m_bOnGround)
{ {
float fallspeed; double fallspeed;
if (IsBlockWater(BlockIn)) if (IsBlockWater(BlockIn))
{ {
fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water fallspeed = m_Gravity * DtSec.count() / 3; // Fall 3x slower in water
ApplyFriction(NextSpeed, 0.7, a_Dt); ApplyFriction(NextSpeed, 0.7, static_cast<float>(DtSec.count()));
} }
else if (BlockIn == E_BLOCK_COBWEB) else if (BlockIn == E_BLOCK_COBWEB)
{ {
@ -941,13 +941,13 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
else else
{ {
// Normal gravity // Normal gravity
fallspeed = m_Gravity * a_Dt; fallspeed = m_Gravity * DtSec.count();
} }
NextSpeed.y += fallspeed; NextSpeed.y += static_cast<float>(fallspeed);
} }
else else
{ {
ApplyFriction(NextSpeed, 0.7, a_Dt); ApplyFriction(NextSpeed, 0.7, static_cast<float>(DtSec.count()));
} }
// Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we // Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we
@ -1002,14 +1002,14 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{ {
cTracer Tracer(GetWorld()); cTracer Tracer(GetWorld());
// Distance traced is an integer, so we round up from the distance we should go (Speed * Delta), else we will encounter collision detection failurse // Distance traced is an integer, so we round up from the distance we should go (Speed * Delta), else we will encounter collision detection failurse
int DistanceToTrace = (int)(ceil((NextSpeed * a_Dt).SqrLength()) * 2); int DistanceToTrace = (int)(ceil((NextSpeed * DtSec.count()).SqrLength()) * 2);
bool HasHit = Tracer.Trace(NextPos, NextSpeed, DistanceToTrace); bool HasHit = Tracer.Trace(NextPos, NextSpeed, DistanceToTrace);
if (HasHit) if (HasHit)
{ {
// Oh noez! We hit something: verify that the (hit position - current) was smaller or equal to the (position that we should travel without obstacles - current) // Oh noez! We hit something: verify that the (hit position - current) was smaller or equal to the (position that we should travel without obstacles - current)
// This is because previously, we traced with a length that was rounded up (due to integer limitations), and in the case that something was hit, we don't want to overshoot our projected movement // This is because previously, we traced with a length that was rounded up (due to integer limitations), and in the case that something was hit, we don't want to overshoot our projected movement
if ((Tracer.RealHit - NextPos).SqrLength() <= (NextSpeed * a_Dt).SqrLength()) if ((Tracer.RealHit - NextPos).SqrLength() <= (NextSpeed * DtSec.count()).SqrLength())
{ {
// Block hit was within our projected path // Block hit was within our projected path
// Begin by stopping movement in the direction that we hit something. The Normal is the line perpendicular to a 2D face and in this case, stores what block face was hit through either -1 or 1. // Begin by stopping movement in the direction that we hit something. The Normal is the line perpendicular to a 2D face and in this case, stores what block face was hit through either -1 or 1.
@ -1044,13 +1044,13 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
// and that this piece of software will come to be hailed as the epitome of performance and functionality in C++, never before seen, and of such a like that will never // and that this piece of software will come to be hailed as the epitome of performance and functionality in C++, never before seen, and of such a like that will never
// be henceforth seen again in the time of programmers and man alike // be henceforth seen again in the time of programmers and man alike
// </&sensationalist> // </&sensationalist>
NextPos += (NextSpeed * a_Dt); NextPos += (NextSpeed * DtSec.count());
} }
} }
else else
{ {
// We didn't hit anything, so move =] // We didn't hit anything, so move =]
NextPos += (NextSpeed * a_Dt); NextPos += (NextSpeed * DtSec.count());
} }
} }

View File

@ -326,10 +326,10 @@ public:
// tolua_end // tolua_end
virtual void Tick(float a_Dt, cChunk & a_Chunk); virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk);
/// Handles the physics of the entity - updates position based on speed, updates speed based on environment /// Handles the physics of the entity - updates position based on speed, updates speed based on environment
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk); virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk);
/// Updates the state related to this entity being on fire /// Updates the state related to this entity being on fire
virtual void TickBurning(cChunk & a_Chunk); virtual void TickBurning(cChunk & a_Chunk);

View File

@ -8,7 +8,7 @@
cExpOrb::cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward) cExpOrb::cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward)
: cEntity(etExpOrb, a_X, a_Y, a_Z, 0.98, 0.98) : cEntity(etExpOrb, a_X, a_Y, a_Z, 0.98, 0.98)
, m_Reward(a_Reward) , m_Reward(a_Reward)
, m_Timer(0.f) , m_Timer(0)
{ {
SetMaxHealth(5); SetMaxHealth(5);
SetHealth(5); SetHealth(5);
@ -21,7 +21,7 @@ cExpOrb::cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward)
cExpOrb::cExpOrb(const Vector3d & a_Pos, int a_Reward) cExpOrb::cExpOrb(const Vector3d & a_Pos, int a_Reward)
: cEntity(etExpOrb, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98) : cEntity(etExpOrb, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98)
, m_Reward(a_Reward) , m_Reward(a_Reward)
, m_Timer(0.f) , m_Timer(0)
{ {
SetMaxHealth(5); SetMaxHealth(5);
SetHealth(5); SetHealth(5);
@ -42,7 +42,7 @@ void cExpOrb::SpawnOn(cClientHandle & a_Client)
void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk) void cExpOrb::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
cPlayer * a_ClosestPlayer(m_World->FindClosestPlayer(Vector3f(GetPosition()), 5)); cPlayer * a_ClosestPlayer(m_World->FindClosestPlayer(Vector3f(GetPosition()), 5));
if (a_ClosestPlayer != nullptr) if (a_ClosestPlayer != nullptr)
@ -70,7 +70,7 @@ void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk)
HandlePhysics(a_Dt, a_Chunk); HandlePhysics(a_Dt, a_Chunk);
m_Timer += a_Dt; m_Timer += a_Dt;
if (m_Timer >= 1000 * 60 * 5) // 5 minutes if (m_Timer >= std::chrono::minutes(5))
{ {
Destroy(true); Destroy(true);
} }

View File

@ -22,14 +22,14 @@ public:
cExpOrb(const Vector3d & a_Pos, int a_Reward); cExpOrb(const Vector3d & a_Pos, int a_Reward);
// Override functions // Override functions
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void SpawnOn(cClientHandle & a_Client) override; virtual void SpawnOn(cClientHandle & a_Client) override;
/** Returns the number of ticks that this entity has existed */ /** Returns the number of ticks that this entity has existed */
int GetAge(void) const { return (int)(m_Timer / 50); } // tolua_export int GetAge(void) const { return std::chrono::duration_cast<cTickTime>(m_Timer).count(); } // tolua_export
/** Set the number of ticks that this entity has existed */ /** Set the number of ticks that this entity has existed */
void SetAge(int a_Age) { m_Timer = (float)(a_Age * 50); } // tolua_export void SetAge(int a_Age) { m_Timer = cTickTime(a_Age); } // tolua_export
/** Get the exp amount */ /** Get the exp amount */
int GetReward(void) const { return m_Reward; } // tolua_export int GetReward(void) const { return m_Reward; } // tolua_export
@ -41,5 +41,5 @@ protected:
int m_Reward; int m_Reward;
/** The number of ticks that the entity has existed / timer between collect and destroy; in msec */ /** The number of ticks that the entity has existed / timer between collect and destroy; in msec */
float m_Timer; std::chrono::milliseconds m_Timer;
} ; // tolua_export } ; // tolua_export

View File

@ -31,7 +31,7 @@ void cFallingBlock::SpawnOn(cClientHandle & a_ClientHandle)
void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk) void cFallingBlock::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
// GetWorld()->BroadcastTeleportEntity(*this); // Test position // GetWorld()->BroadcastTeleportEntity(*this); // Test position
@ -82,7 +82,7 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
return; return;
} }
float MilliDt = a_Dt * 0.001f; float MilliDt = a_Dt.count() * 0.001f;
AddSpeedY(MilliDt * -9.8f); AddSpeedY(MilliDt * -9.8f);
AddPosition(GetSpeed() * MilliDt); AddPosition(GetSpeed() * MilliDt);

View File

@ -30,7 +30,7 @@ public:
// cEntity overrides: // cEntity overrides:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
private: private:
BLOCKTYPE m_BlockType; BLOCKTYPE m_BlockType;

View File

@ -19,7 +19,7 @@ cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, do
void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) void cFireworkEntity::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width; int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width; int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
@ -28,7 +28,7 @@ void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
if ((PosY < 0) || (PosY >= cChunkDef::Height)) if ((PosY < 0) || (PosY >= cChunkDef::Height))
{ {
AddSpeedY(1); AddSpeedY(1);
AddPosition(GetSpeed() * (a_Dt / 1000)); AddPosition(GetSpeed() * (static_cast<double>(a_Dt.count()) / 1000));
return; return;
} }
@ -53,14 +53,14 @@ void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
} }
AddSpeedY(1); AddSpeedY(1);
AddPosition(GetSpeed() * (a_Dt / 1000)); AddPosition(GetSpeed() * (static_cast<double>(a_Dt.count()) / 1000));
} }
void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk) void cFireworkEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
super::Tick(a_Dt, a_Chunk); super::Tick(a_Dt, a_Chunk);

View File

@ -49,8 +49,8 @@ public:
protected: protected:
// cProjectileEntity overrides: // cProjectileEntity overrides:
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
private: private:

View File

@ -125,7 +125,7 @@ void cFloater::SpawnOn(cClientHandle & a_Client)
void cFloater::Tick(float a_Dt, cChunk & a_Chunk) void cFloater::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
HandlePhysics(a_Dt, a_Chunk); HandlePhysics(a_Dt, a_Chunk);
if (IsBlockWater(m_World->GetBlock((int) GetPosX(), (int) GetPosY(), (int) GetPosZ())) && m_World->GetBlockMeta((int) GetPosX(), (int) GetPosY(), (int) GetPosZ()) == 0) if (IsBlockWater(m_World->GetBlock((int) GetPosX(), (int) GetPosY(), (int) GetPosZ())) && m_World->GetBlockMeta((int) GetPosX(), (int) GetPosY(), (int) GetPosZ()) == 0)

View File

@ -21,7 +21,7 @@ public:
cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID, int a_CountDownTime); cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID, int a_CountDownTime);
virtual void SpawnOn(cClientHandle & a_Client) override; virtual void SpawnOn(cClientHandle & a_Client) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
// tolua_begin // tolua_begin
bool CanPickup(void) const { return m_CanPickupItem; } bool CanPickup(void) const { return m_CanPickupItem; }

View File

@ -43,7 +43,7 @@ public:
private: private:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override {} virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override {}
eBlockFace m_Facing; eBlockFace m_Facing;

View File

@ -112,7 +112,7 @@ void cMinecart::SpawnOn(cClientHandle & a_ClientHandle)
void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk) void cMinecart::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
if (IsDestroyed()) // Mainly to stop detector rails triggering again after minecart is dead if (IsDestroyed()) // Mainly to stop detector rails triggering again after minecart is dead
{ {
@ -178,7 +178,7 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
default: VERIFY(!"Unhandled rail type despite checking if block was rail!"); break; default: VERIFY(!"Unhandled rail type despite checking if block was rail!"); break;
} }
AddPosition(GetSpeed() * (a_Dt / 1000)); // Commit changes; as we use our own engine when on rails, this needs to be done, whereas it is normally in Entity.cpp AddPosition(GetSpeed() * (static_cast<double>(a_Dt.count()) / 1000)); // Commit changes; as we use our own engine when on rails, this needs to be done, whereas it is normally in Entity.cpp
} }
else else
{ {
@ -206,7 +206,7 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt) void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt)
{ {
/* /*
NOTE: Please bear in mind that taking away from negatives make them even more negative, NOTE: Please bear in mind that taking away from negatives make them even more negative,
@ -566,7 +566,7 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta)
void cMinecart::HandleDetectorRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt) void cMinecart::HandleDetectorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt)
{ {
m_World->SetBlockMeta(m_DetectorRailPosition, a_RailMeta | 0x08); m_World->SetBlockMeta(m_DetectorRailPosition, a_RailMeta | 0x08);
@ -577,7 +577,7 @@ void cMinecart::HandleDetectorRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
void cMinecart::HandleActivatorRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt) void cMinecart::HandleActivatorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt)
{ {
HandleRailPhysics(a_RailMeta & 0x07, a_Dt); HandleRailPhysics(a_RailMeta & 0x07, a_Dt);
} }
@ -1214,7 +1214,7 @@ void cMinecartWithFurnace::OnRightClicked(cPlayer & a_Player)
void cMinecartWithFurnace::Tick(float a_Dt, cChunk & a_Chunk) void cMinecartWithFurnace::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
super::Tick(a_Dt, a_Chunk); super::Tick(a_Dt, a_Chunk);

View File

@ -38,7 +38,7 @@ public:
// cEntity overrides: // cEntity overrides:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual bool DoTakeDamage(TakeDamageInfo & TDI) override; virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
virtual void Destroyed() override; virtual void Destroyed() override;
@ -56,7 +56,7 @@ protected:
/** Handles physics on normal rails /** Handles physics on normal rails
For each tick, slow down on flat rails, speed up or slow down on ascending/descending rails (depending on direction), and turn on curved rails For each tick, slow down on flat rails, speed up or slow down on ascending/descending rails (depending on direction), and turn on curved rails
*/ */
void HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt); void HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt);
/** Handles powered rail physics /** Handles powered rail physics
Each tick, speed up or slow down cart, depending on metadata of rail (powered or not) Each tick, speed up or slow down cart, depending on metadata of rail (powered or not)
@ -66,10 +66,10 @@ protected:
/** Handles detector rail activation /** Handles detector rail activation
Activates detector rails when a minecart is on them. Calls HandleRailPhysics() for physics simulations Activates detector rails when a minecart is on them. Calls HandleRailPhysics() for physics simulations
*/ */
void HandleDetectorRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt); void HandleDetectorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt);
/** Handles activator rails - placeholder for future implementation */ /** Handles activator rails - placeholder for future implementation */
void HandleActivatorRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt); void HandleActivatorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt);
/** Snaps a mincecart to a rail's axis, resetting its speed /** Snaps a mincecart to a rail's axis, resetting its speed
For curved rails, it changes the cart's direction as well as snapping it to axis */ For curved rails, it changes the cart's direction as well as snapping it to axis */
@ -171,7 +171,7 @@ public:
// cEntity overrides: // cEntity overrides:
virtual void OnRightClicked(cPlayer & a_Player) override; virtual void OnRightClicked(cPlayer & a_Player) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
// Set functions. // Set functions.
void SetIsFueled(bool a_IsFueled, int a_FueledTimeLeft = -1) {m_IsFueled = a_IsFueled; m_FueledTimeLeft = a_FueledTimeLeft;} void SetIsFueled(bool a_IsFueled, int a_FueledTimeLeft = -1) {m_IsFueled = a_IsFueled; m_FueledTimeLeft = a_FueledTimeLeft;}

View File

@ -31,7 +31,7 @@ void cPainting::SpawnOn(cClientHandle & a_Client)
void cPainting::Tick(float a_Dt, cChunk & a_Chunk) void cPainting::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
UNUSED(a_Dt); UNUSED(a_Dt);
UNUSED(a_Chunk); UNUSED(a_Chunk);

View File

@ -31,7 +31,7 @@ public:
private: private:
virtual void SpawnOn(cClientHandle & a_Client) override; virtual void SpawnOn(cClientHandle & a_Client) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override; virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override;
virtual void KilledBy(TakeDamageInfo & a_TDI) override virtual void KilledBy(TakeDamageInfo & a_TDI) override
{ {

View File

@ -19,7 +19,7 @@ cPawn::cPawn(eEntityType a_EntityType, double a_Width, double a_Height) :
void cPawn::Tick(float a_Dt, cChunk & a_Chunk) void cPawn::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
// Iterate through this entity's applied effects // Iterate through this entity's applied effects
for (tEffectMap::iterator iter = m_EntityEffects.begin(); iter != m_EntityEffects.end();) for (tEffectMap::iterator iter = m_EntityEffects.begin(); iter != m_EntityEffects.end();)

View File

@ -20,7 +20,7 @@ public:
cPawn(eEntityType a_EntityType, double a_Width, double a_Height); cPawn(eEntityType a_EntityType, double a_Width, double a_Height);
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void KilledBy(TakeDamageInfo & a_TDI) override; virtual void KilledBy(TakeDamageInfo & a_TDI) override;
// tolua_begin // tolua_begin

View File

@ -86,7 +86,7 @@ protected:
cPickup::cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, bool IsPlayerCreated, float a_SpeedX /* = 0.f */, float a_SpeedY /* = 0.f */, float a_SpeedZ /* = 0.f */) cPickup::cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, bool IsPlayerCreated, float a_SpeedX /* = 0.f */, float a_SpeedY /* = 0.f */, float a_SpeedZ /* = 0.f */)
: cEntity(etPickup, a_PosX, a_PosY, a_PosZ, 0.2, 0.2) : cEntity(etPickup, a_PosX, a_PosY, a_PosZ, 0.2, 0.2)
, m_Timer(0.f) , m_Timer(0)
, m_Item(a_Item) , m_Item(a_Item)
, m_bCollected(false) , m_bCollected(false)
, m_bIsPlayerCreated(IsPlayerCreated) , m_bIsPlayerCreated(IsPlayerCreated)
@ -110,7 +110,7 @@ void cPickup::SpawnOn(cClientHandle & a_Client)
void cPickup::Tick(float a_Dt, cChunk & a_Chunk) void cPickup::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
super::Tick(a_Dt, a_Chunk); super::Tick(a_Dt, a_Chunk);
BroadcastMovementUpdate(); // Notify clients of position BroadcastMovementUpdate(); // Notify clients of position
@ -141,9 +141,9 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
) )
{ {
m_bCollected = true; m_bCollected = true;
m_Timer = 0; // We have to reset the timer. m_Timer = std::chrono::milliseconds(0); // We have to reset the timer.
m_Timer += a_Dt; // In case we have to destroy the pickup in the same tick. m_Timer += a_Dt; // In case we have to destroy the pickup in the same tick.
if (m_Timer > 500.f) if (m_Timer > std::chrono::milliseconds(500))
{ {
Destroy(true); Destroy(true);
return; return;
@ -167,14 +167,14 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
} }
else else
{ {
if (m_Timer > 500.f) // 0.5 second if (m_Timer > std::chrono::milliseconds(500)) // 0.5 second
{ {
Destroy(true); Destroy(true);
return; return;
} }
} }
if (m_Timer > 1000 * 60 * 5) // 5 minutes if (m_Timer > std::chrono::minutes(5)) // 5 minutes
{ {
Destroy(true); Destroy(true);
return; return;
@ -200,7 +200,7 @@ bool cPickup::CollectedBy(cPlayer & a_Dest)
} }
// Two seconds if player created the pickup (vomiting), half a second if anything else // Two seconds if player created the pickup (vomiting), half a second if anything else
if (m_Timer < (m_bIsPlayerCreated ? 2000.f : 500.f)) if (m_Timer < (m_bIsPlayerCreated ? std::chrono::seconds(2) : std::chrono::milliseconds(500)))
{ {
// LOG("Pickup %d cannot be collected by \"%s\", because it is not old enough.", m_UniqueID, a_Dest->GetName().c_str()); // LOG("Pickup %d cannot be collected by \"%s\", because it is not old enough.", m_UniqueID, a_Dest->GetName().c_str());
return false; // Not old enough return false; // Not old enough
@ -234,7 +234,7 @@ bool cPickup::CollectedBy(cPlayer & a_Dest)
// All of the pickup has been collected, schedule the pickup for destroying // All of the pickup has been collected, schedule the pickup for destroying
m_bCollected = true; m_bCollected = true;
} }
m_Timer = 0; m_Timer = std::chrono::milliseconds(0);
return true; return true;
} }

View File

@ -34,13 +34,13 @@ public:
bool CollectedBy(cPlayer & a_Dest); // tolua_export bool CollectedBy(cPlayer & a_Dest); // tolua_export
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
/** Returns the number of ticks that this entity has existed */ /** Returns the number of ticks that this entity has existed */
int GetAge(void) const { return static_cast<int>(m_Timer / 50); } // tolua_export int GetAge(void) const { return std::chrono::duration_cast<cTickTime>(m_Timer).count(); } // tolua_export
/** Set the number of ticks that this entity has existed */ /** Set the number of ticks that this entity has existed */
void SetAge(int a_Age) { m_Timer = static_cast<float>(a_Age * 50); } // tolua_export void SetAge(int a_Age) { m_Timer = cTickTime(a_Age); } // tolua_export
/** Returns true if the pickup has already been collected */ /** Returns true if the pickup has already been collected */
bool IsCollected(void) const { return m_bCollected; } // tolua_export bool IsCollected(void) const { return m_bCollected; } // tolua_export
@ -51,7 +51,7 @@ public:
private: private:
/** The number of ticks that the entity has existed / timer between collect and destroy; in msec */ /** The number of ticks that the entity has existed / timer between collect and destroy; in msec */
float m_Timer; std::chrono::milliseconds m_Timer;
cItem m_Item; cItem m_Item;

View File

@ -2,6 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Player.h" #include "Player.h"
#include <unordered_map>
#include "../ChatColor.h" #include "../ChatColor.h"
#include "../Server.h" #include "../Server.h"
#include "../UI/InventoryWindow.h" #include "../UI/InventoryWindow.h"
@ -19,6 +20,10 @@
#include "../WorldStorage/StatSerializer.h" #include "../WorldStorage/StatSerializer.h"
#include "../CompositeChat.h" #include "../CompositeChat.h"
#include "../Blocks/BlockHandler.h"
#include "../Blocks/BlockSlab.h"
#include "../Blocks/ChunkInterface.h"
#include "../IniFile.h" #include "../IniFile.h"
#include "json/json.h" #include "json/json.h"
@ -186,7 +191,7 @@ void cPlayer::SpawnOn(cClientHandle & a_Client)
void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
if (m_ClientHandle != nullptr) if (m_ClientHandle != nullptr)
{ {
@ -2168,6 +2173,97 @@ void cPlayer::LoadRank(void)
bool cPlayer::PlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
sSetBlockVector blk{{a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta}};
return PlaceBlocks(blk);
}
void cPlayer::SendBlocksAround(int a_BlockX, int a_BlockY, int a_BlockZ, int a_Range)
{
// Collect the coords of all the blocks to send:
sSetBlockVector blks;
for (int y = a_BlockY - a_Range + 1; y < a_BlockY + a_Range; y++)
{
for (int z = a_BlockZ - a_Range + 1; z < a_BlockZ + a_Range; z++)
{
for (int x = a_BlockX - a_Range + 1; x < a_BlockX + a_Range; x++)
{
blks.emplace_back(x, y, z, E_BLOCK_AIR, 0); // Use fake blocktype, it will get set later on.
};
};
} // for y
// Get the values of all the blocks:
if (!m_World->GetBlocks(blks, false))
{
LOGD("%s: Cannot query all blocks, not sending an update", __FUNCTION__);
return;
}
// Divide the block changes by their respective chunks:
std::unordered_map<cChunkCoords, sSetBlockVector, cChunkCoordsHash> Changes;
for (const auto & blk: blks)
{
Changes[cChunkCoords(blk.m_ChunkX, blk.m_ChunkZ)].push_back(blk);
} // for blk - blks[]
blks.clear();
// Send the blocks for each affected chunk:
for (auto itr = Changes.cbegin(), end = Changes.cend(); itr != end; ++itr)
{
m_ClientHandle->SendBlockChanges(itr->first.m_ChunkX, itr->first.m_ChunkZ, itr->second);
}
}
bool cPlayer::PlaceBlocks(const sSetBlockVector & a_Blocks)
{
// Call the "placing" hooks; if any fail, abort:
cPluginManager * pm = cPluginManager::Get();
for (auto blk: a_Blocks)
{
if (pm->CallHookPlayerPlacingBlock(*this, blk))
{
// Abort - re-send all the current blocks in the a_Blocks' coords to the client:
for (auto blk2: a_Blocks)
{
m_World->SendBlockTo(blk2.GetX(), blk2.GetY(), blk2.GetZ(), this);
}
return false;
}
} // for blk - a_Blocks[]
// Set the blocks:
m_World->SetBlocks(a_Blocks);
// Notify the blockhandlers:
cChunkInterface ChunkInterface(m_World->GetChunkMap());
for (auto blk: a_Blocks)
{
cBlockHandler * newBlock = BlockHandler(blk.m_BlockType);
newBlock->OnPlacedByPlayer(ChunkInterface, *m_World, this, blk);
}
// Call the "placed" hooks:
for (auto blk: a_Blocks)
{
pm->CallHookPlayerPlacedBlock(*this, blk);
}
return true;
}
void cPlayer::Detach() void cPlayer::Detach()
{ {
super::Detach(); super::Detach();

View File

@ -46,9 +46,9 @@ public:
virtual void SpawnOn(cClientHandle & a_Client) override; virtual void SpawnOn(cClientHandle & a_Client) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void HandlePhysics(float a_Dt, cChunk &) override { UNUSED(a_Dt); } virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk &) override { UNUSED(a_Dt); }
/** Returns the curently equipped weapon; empty item if none */ /** Returns the curently equipped weapon; empty item if none */
virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); } virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); }
@ -440,8 +440,27 @@ public:
Loads the m_Rank, m_Permissions, m_MsgPrefix, m_MsgSuffix and m_MsgNameColorCode members. */ Loads the m_Rank, m_Permissions, m_MsgPrefix, m_MsgSuffix and m_MsgNameColorCode members. */
void LoadRank(void); void LoadRank(void);
/** Calls the block-placement hook and places the block in the world, unless refused by the hook.
If the hook prevents the placement, sends the current block at the specified coords back to the client.
Assumes that the block is in a currently loaded chunk.
Returns true if the block is successfully placed. */
bool PlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
/** Sends the block in the specified range around the specified coord to the client
as a block change packet.
The blocks in range (a_BlockX - a_Range, a_BlockX + a_Range) are sent (NY-metric). */
void SendBlocksAround(int a_BlockX, int a_BlockY, int a_BlockZ, int a_Range = 1);
// tolua_end // tolua_end
/** Calls the block placement hooks and places the blocks in the world.
First the "placing" hooks for all the blocks are called, then the blocks are placed, and finally
the "placed" hooks are called.
If the any of the "placing" hooks aborts, none of the blocks are placed and the function returns false.
Returns true if all the blocks are placed.
Assumes that all the blocks are in currently loaded chunks. */
bool PlaceBlocks(const sSetBlockVector & a_Blocks);
// cEntity overrides: // cEntity overrides:
virtual bool IsCrouched (void) const { return m_IsCrouched; } virtual bool IsCrouched (void) const { return m_IsCrouched; }
virtual bool IsSprinting(void) const { return m_IsSprinting; } virtual bool IsSprinting(void) const { return m_IsSprinting; }

View File

@ -331,7 +331,7 @@ AString cProjectileEntity::GetMCAClassName(void) const
void cProjectileEntity::Tick(float a_Dt, cChunk & a_Chunk) void cProjectileEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
super::Tick(a_Dt, a_Chunk); super::Tick(a_Dt, a_Chunk);
@ -346,7 +346,7 @@ void cProjectileEntity::Tick(float a_Dt, cChunk & a_Chunk)
void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) void cProjectileEntity::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
if (m_IsInGround) if (m_IsInGround)
{ {

View File

@ -118,8 +118,8 @@ protected:
bool m_IsInGround; bool m_IsInGround;
// cEntity overrides: // cEntity overrides:
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void SpawnOn(cClientHandle & a_Client) override; virtual void SpawnOn(cClientHandle & a_Client) override;
} ; // tolua_export } ; // tolua_export

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