Merge branch 'master' into Inventory
This commit is contained in:
commit
1eedccc56a
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,6 +3,7 @@ nbproject/
|
||||
ipch/
|
||||
Win32/
|
||||
MCServer/MCServer
|
||||
MCServer/itemblacklist
|
||||
ChunkWorxSave.ini
|
||||
doxy/
|
||||
Profiling
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -25,3 +25,6 @@
|
||||
[submodule "lib/SQLiteCpp"]
|
||||
path = lib/SQLiteCpp
|
||||
url = https://github.com/mc-server/SQLiteCpp.git
|
||||
[submodule "lib/libevent"]
|
||||
path = lib/libevent
|
||||
url = https://github.com/mc-server/libevent.git
|
||||
|
@ -13,6 +13,9 @@ before_install:
|
||||
install:
|
||||
# g++4.8 and clang
|
||||
- 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
|
||||
- if [ "$CXX" == "g++" ]; then export CXX="g++-4.8"; export CC="gcc-4.8"; fi
|
||||
|
@ -7,6 +7,9 @@ export MCSERVER_BUILD_ID=$TRAVIS_JOB_NUMBER
|
||||
export MCSERVER_BUILD_DATETIME=`date`
|
||||
|
||||
cmake . -DBUILD_TOOLS=1 -DSELF_TEST=1;
|
||||
cd src
|
||||
lua CheckBasicStyle.lua
|
||||
cd ..
|
||||
make -j 2;
|
||||
make -j 2 test;
|
||||
cd MCServer/;
|
||||
|
@ -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_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:
|
||||
add_subdirectory(lib/jsoncpp/)
|
||||
add_subdirectory(lib/zlib/)
|
||||
@ -104,6 +122,7 @@ add_subdirectory(lib/sqlite/)
|
||||
add_subdirectory(lib/SQLiteCpp/)
|
||||
add_subdirectory(lib/expat/)
|
||||
add_subdirectory(lib/luaexpat/)
|
||||
add_subdirectory(lib/libevent/)
|
||||
|
||||
# Add proper include directories so that SQLiteCpp can find SQLite3:
|
||||
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(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)
|
||||
add_subdirectory(lib/luaproxy/)
|
||||
endif()
|
||||
@ -118,13 +140,14 @@ endif()
|
||||
|
||||
# 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)
|
||||
include(lib/polarssl.cmake)
|
||||
include(lib/polarssl.cmake EXCLUDE_FROM_ALL)
|
||||
|
||||
set_exe_flags()
|
||||
|
||||
add_subdirectory (src)
|
||||
|
||||
if(${SELF_TEST})
|
||||
message("Tests enabled")
|
||||
enable_testing()
|
||||
add_subdirectory (tests)
|
||||
endif()
|
||||
|
@ -69,9 +69,9 @@ After doing so, run the command `xcodebuild lib/polarssl/POLARSSL.xcodeproj` in
|
||||
|
||||
## 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 ###
|
||||
|
@ -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." },
|
||||
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." },
|
||||
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." },
|
||||
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." },
|
||||
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." },
|
||||
|
@ -12,7 +12,11 @@ return
|
||||
Use the {{cPlayer}}:GetWorld() function to get the world to which the block belongs.</p>
|
||||
<p>
|
||||
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 =
|
||||
{
|
||||
@ -20,10 +24,6 @@ return
|
||||
{ Name = "BlockX", Type = "number", Notes = "X-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 = "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 = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block" },
|
||||
},
|
||||
|
@ -15,7 +15,11 @@ return
|
||||
Use the {{cPlayer}}:GetWorld() function to get the world to which the block belongs.</p>
|
||||
<p>
|
||||
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 =
|
||||
{
|
||||
@ -23,10 +27,6 @@ return
|
||||
{ Name = "BlockX", Type = "number", Notes = "X-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 = "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 = "BlockMeta", Type = "NIBBLETYPE", Notes = "The block meta of the block" },
|
||||
},
|
||||
|
@ -7,7 +7,10 @@ return
|
||||
Desc = [[
|
||||
A plugin may implement an OnServerPing() function and register it as a Hook to process pings from
|
||||
clients in the server server list. It can change the logged in players and player capacity, as well
|
||||
as the server description and the favicon, that are displayed to the client in the server list.
|
||||
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 = {
|
||||
{ Name = "ClientHandle", Type = "{{cClientHandle}}", Notes = "The client handle that pinged the server" },
|
||||
|
@ -1,56 +1,14 @@
|
||||
[Spider]
|
||||
[Bat]
|
||||
AttackRange=2.0
|
||||
AttackRate=1
|
||||
AttackDamage=2.0
|
||||
AttackDamage=0.0
|
||||
SightDistance=25.0
|
||||
MaxHealth=16
|
||||
MaxHealth=6
|
||||
|
||||
[Chicken]
|
||||
AttackRange=2.0
|
||||
[Blaze]
|
||||
AttackRange=15.0
|
||||
AttackRate=1
|
||||
AttackDamage=1.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
|
||||
AttackDamage=6.0
|
||||
SightDistance=25.0
|
||||
MaxHealth=20
|
||||
IsFireproof=1
|
||||
@ -62,6 +20,20 @@ AttackDamage=2.0
|
||||
SightDistance=25.0
|
||||
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]
|
||||
AttackRange=3.0
|
||||
AttackRate=1
|
||||
@ -69,6 +41,21 @@ AttackDamage=0.0
|
||||
SightDistance=25.0
|
||||
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]
|
||||
AttackRange=50.0
|
||||
AttackRate=1
|
||||
@ -77,6 +64,77 @@ SightDistance=50.0
|
||||
MaxHealth=10
|
||||
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]
|
||||
AttackRange=2.0
|
||||
AttackRate=1
|
||||
@ -97,27 +155,26 @@ AttackDamage=4.0
|
||||
SightDistance=25.0
|
||||
MaxHealth=16
|
||||
|
||||
[Zombie]
|
||||
[SnowGolem]
|
||||
AttackRange=2.0
|
||||
AttackRate=1
|
||||
AttackDamage=4.0
|
||||
AttackDamage=0.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
|
||||
AttackRate=1
|
||||
AttackDamage=4.0
|
||||
AttackDamage=0.0
|
||||
SightDistance=25.0
|
||||
MaxHealth=20
|
||||
|
||||
[Blaze]
|
||||
AttackRange=15.0
|
||||
AttackRate=1
|
||||
AttackDamage=6.0
|
||||
SightDistance=25.0
|
||||
MaxHealth=20
|
||||
IsFireproof=1
|
||||
MaxHealth=10
|
||||
|
||||
[Villager]
|
||||
AttackRange=2.0
|
||||
@ -125,7 +182,6 @@ AttackRate=1
|
||||
AttackDamage=0.0
|
||||
SightDistance=25.0
|
||||
MaxHealth=20
|
||||
IsFireproof=0
|
||||
|
||||
[Witch]
|
||||
AttackRange=2.0
|
||||
@ -134,61 +190,24 @@ AttackDamage=0.0
|
||||
SightDistance=25.0
|
||||
MaxHealth=26
|
||||
|
||||
|
||||
[Ocelot]
|
||||
[Wolf]
|
||||
AttackRange=2.0
|
||||
AttackRate=1
|
||||
AttackDamage=0.0
|
||||
AttackDamage=4.0
|
||||
SightDistance=25.0
|
||||
MaxHealth=10
|
||||
MaxHealth=20
|
||||
|
||||
[Mooshroom]
|
||||
[Zombie]
|
||||
AttackRange=2.0
|
||||
AttackRate=1
|
||||
AttackDamage=0.0
|
||||
AttackDamage=4.0
|
||||
SightDistance=25.0
|
||||
MaxHealth=10
|
||||
MaxHealth=20
|
||||
|
||||
[MagmaCube]
|
||||
[ZombiePigman]
|
||||
AttackRange=2.0
|
||||
AttackRate=1
|
||||
AttackDamage=6.0
|
||||
AttackDamage=7.0
|
||||
SightDistance=25.0
|
||||
MaxHealth=16
|
||||
MaxHealth=20
|
||||
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
|
||||
|
||||
|
@ -58,6 +58,7 @@ function ShowPage(WebAdmin, TemplateRequest)
|
||||
SiteContent = {}
|
||||
local BaseURL = WebAdmin:GetBaseURL(TemplateRequest.Request.Path)
|
||||
local Title = "MCServer WebAdmin"
|
||||
local NumPlayers = cRoot:Get():GetServer():GetNumPlayers()
|
||||
local MemoryUsageKiB = cRoot:GetPhysicalRAMUsage()
|
||||
local NumChunks = cRoot:Get():GetTotalChunkCount()
|
||||
local PluginPage = WebAdmin:GetPage(TemplateRequest.Request)
|
||||
@ -102,6 +103,7 @@ function ShowPage(WebAdmin, TemplateRequest)
|
||||
<div class="wrapper">
|
||||
<ul class="menu top_links">
|
||||
<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>Chunks: <strong>]] .. NumChunks .. [[</strong></a></li>
|
||||
</ul>
|
||||
|
@ -9,8 +9,7 @@ We currently support Release 1.7 and 1.8 (not beta) Minecraft protocol versions.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
[![Install on DigitalOcean](http://doinstall.bearbin.net/button.svg)](http://doinstall.bearbin.net/install?url=https://github.com/mc-server/MCServer)
|
||||
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.
|
||||
|
||||
For Linux there is an easy installation method, just run this in your terminal:
|
||||
|
||||
|
@ -26,11 +26,13 @@ struct
|
||||
{entEnderman, "Enderman"},
|
||||
{entGhast, "Ghast"},
|
||||
{entGiant, "Giant"},
|
||||
{entGuardian, "Guardian"},
|
||||
{entLavaSlime, "LavaSlime"},
|
||||
{entMushroomCow, "MushroomCow"},
|
||||
{entOzelot, "Ozelot"},
|
||||
{entPig, "Pig"},
|
||||
{entPigZombie, "PigZombie"},
|
||||
{entRabbit, "Rabbit"},
|
||||
{entSheep, "Sheep"},
|
||||
{entSilverfish, "Slverfish"},
|
||||
{entSkeleton, "Skeleton"},
|
||||
|
@ -25,11 +25,13 @@ enum eEntityType
|
||||
entEnderman,
|
||||
entGhast,
|
||||
entGiant,
|
||||
entGuardian,
|
||||
entLavaSlime,
|
||||
entMushroomCow,
|
||||
entOzelot,
|
||||
entPig,
|
||||
entPigZombie,
|
||||
entRabbit,
|
||||
entSheep,
|
||||
entSilverfish,
|
||||
entSkeleton,
|
||||
|
@ -53,6 +53,7 @@ source_group("Shared" FILES ${SHARED_SRC} ${SHARED_HDR})
|
||||
|
||||
set(SHARED_OSS_SRC
|
||||
../../src/OSSupport/CriticalSection.cpp
|
||||
../../src/OSSupport/Event.cpp
|
||||
../../src/OSSupport/File.cpp
|
||||
../../src/OSSupport/IsThread.cpp
|
||||
../../src/OSSupport/StackTrace.cpp
|
||||
@ -60,6 +61,7 @@ set(SHARED_OSS_SRC
|
||||
|
||||
set(SHARED_OSS_HDR
|
||||
../../src/OSSupport/CriticalSection.h
|
||||
../../src/OSSupport/Event.h
|
||||
../../src/OSSupport/File.h
|
||||
../../src/OSSupport/IsThread.h
|
||||
../../src/OSSupport/StackTrace.h
|
||||
|
@ -201,6 +201,7 @@ typedef unsigned char Byte;
|
||||
// Common headers (without macros):
|
||||
#include "StringUtils.h"
|
||||
#include "OSSupport/CriticalSection.h"
|
||||
#include "OSSupport/Event.h"
|
||||
#include "OSSupport/IsThread.h"
|
||||
#include "OSSupport/File.h"
|
||||
|
||||
|
@ -269,7 +269,7 @@ bool cMCADefrag::cThread::ReadChunk(cFile & a_File, const Byte * a_LocationRaw)
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
return false;
|
||||
|
@ -55,12 +55,14 @@ set(SHARED_HDR
|
||||
)
|
||||
set(SHARED_OSS_SRC
|
||||
../../src/OSSupport/CriticalSection.cpp
|
||||
../../src/OSSupport/Event.cpp
|
||||
../../src/OSSupport/File.cpp
|
||||
../../src/OSSupport/IsThread.cpp
|
||||
../../src/OSSupport/StackTrace.cpp
|
||||
)
|
||||
set(SHARED_OSS_HDR
|
||||
../../src/OSSupport/CriticalSection.h
|
||||
../../src/OSSupport/Event.h
|
||||
../../src/OSSupport/File.h
|
||||
../../src/OSSupport/IsThread.h
|
||||
../../src/OSSupport/StackTrace.h
|
||||
|
@ -100,13 +100,11 @@
|
||||
CLIENTENCRYPTSEND(ToClient.data(), ToClient.size()); \
|
||||
break; \
|
||||
} \
|
||||
/* case csWaitingForEncryption: \
|
||||
case csWaitingForEncryption: \
|
||||
{ \
|
||||
Log("Waiting for client encryption, queued %u bytes", ToClient.size()); \
|
||||
m_ClientEncryptionBuffer.append(ToClient.data(), ToClient.size()); \
|
||||
break; \
|
||||
} \
|
||||
*/ \
|
||||
\
|
||||
} \
|
||||
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}",
|
||||
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_start(args, a_Format);
|
||||
@ -359,14 +363,14 @@ bool cConnection::ConnectToServer(void)
|
||||
bool cConnection::RelayFromServer(void)
|
||||
{
|
||||
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)
|
||||
{
|
||||
Log("Server closed the socket: %d; %d; aborting connection", res, SocketError);
|
||||
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)
|
||||
{
|
||||
@ -377,15 +381,15 @@ bool cConnection::RelayFromServer(void)
|
||||
}
|
||||
case csEncryptedUnderstood:
|
||||
{
|
||||
m_ServerDecryptor.ProcessData((Byte *)Buffer, (Byte *)Buffer, res);
|
||||
DataLog(Buffer, res, "Decrypted %d bytes from the SERVER", res);
|
||||
m_ServerDecryptor.ProcessData(reinterpret_cast<Byte *>(Buffer), reinterpret_cast<Byte *>(Buffer), static_cast<size_t>(res));
|
||||
DataLog(Buffer, static_cast<size_t>(res), "Decrypted %d bytes from the SERVER", res);
|
||||
return DecodeServersPackets(Buffer, res);
|
||||
}
|
||||
case csEncryptedUnknown:
|
||||
{
|
||||
m_ServerDecryptor.ProcessData((Byte *)Buffer, (Byte *)Buffer, res);
|
||||
DataLog(Buffer, res, "Decrypted %d bytes from the SERVER", res);
|
||||
return CLIENTSEND(Buffer, res);
|
||||
m_ServerDecryptor.ProcessData(reinterpret_cast<Byte *>(Buffer), reinterpret_cast<Byte *>(Buffer), static_cast<size_t>(res));
|
||||
DataLog(Buffer, static_cast<size_t>(res), "Decrypted %d bytes from the SERVER", res);
|
||||
return CLIENTSEND(Buffer, static_cast<size_t>(res));
|
||||
}
|
||||
}
|
||||
ASSERT(!"Unhandled server state while relaying from server");
|
||||
@ -399,14 +403,14 @@ bool cConnection::RelayFromServer(void)
|
||||
bool cConnection::RelayFromClient(void)
|
||||
{
|
||||
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)
|
||||
{
|
||||
Log("Client closed the socket: %d; %d; aborting connection", res, SocketError);
|
||||
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)
|
||||
{
|
||||
@ -421,9 +425,9 @@ bool cConnection::RelayFromClient(void)
|
||||
}
|
||||
case csEncryptedUnknown:
|
||||
{
|
||||
DataLog(Buffer, res, "Decrypted %d bytes from the CLIENT", res);
|
||||
m_ServerEncryptor.ProcessData((Byte *)Buffer, (Byte *)Buffer, res);
|
||||
return SERVERSEND(Buffer, res);
|
||||
DataLog(Buffer, static_cast<size_t>(res), "Decrypted %d bytes from the CLIENT", res);
|
||||
m_ServerEncryptor.ProcessData(reinterpret_cast<Byte *>(Buffer), reinterpret_cast<Byte *>(Buffer), static_cast<size_t>(res));
|
||||
return SERVERSEND(Buffer, static_cast<size_t>(res));
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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");
|
||||
return false;
|
||||
@ -529,10 +533,12 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size)
|
||||
break;
|
||||
}
|
||||
UInt32 PacketType, PacketReadSoFar;
|
||||
PacketReadSoFar = m_ClientBuffer.GetReadableSpace();
|
||||
PacketReadSoFar = static_cast<UInt32>(m_ClientBuffer.GetReadableSpace());
|
||||
VERIFY(m_ClientBuffer.ReadVarInt(PacketType));
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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");
|
||||
return false;
|
||||
@ -655,7 +661,7 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size)
|
||||
break;
|
||||
}
|
||||
UInt32 PacketType, PacketReadSoFar;
|
||||
PacketReadSoFar = m_ServerBuffer.GetReadableSpace();
|
||||
PacketReadSoFar = static_cast<UInt32>(m_ServerBuffer.GetReadableSpace());
|
||||
VERIFY(m_ServerBuffer.ReadVarInt(PacketType));
|
||||
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);
|
||||
@ -1111,7 +1117,7 @@ bool cConnection::HandleClientPlayerPositionLook(void)
|
||||
bool cConnection::HandleClientPluginMessage(void)
|
||||
{
|
||||
HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, ChannelName);
|
||||
HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, Length);
|
||||
HANDLE_CLIENT_PACKET_READ(ReadBEUInt16, UInt16, Length);
|
||||
AString Data;
|
||||
if (!m_ClientBuffer.ReadString(Data, Length))
|
||||
{
|
||||
@ -1119,7 +1125,7 @@ bool cConnection::HandleClientPluginMessage(void)
|
||||
}
|
||||
Log("Received a PACKET_PLUGIN_MESSAGE from the client");
|
||||
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();
|
||||
return true;
|
||||
}
|
||||
@ -1288,13 +1294,13 @@ bool cConnection::HandleServerLoginEncryptionKeyRequest(void)
|
||||
{
|
||||
// Read the packet from the server:
|
||||
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, ServerID);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, PublicKeyLength);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, PublicKeyLength);
|
||||
AString PublicKey;
|
||||
if (!m_ServerBuffer.ReadString(PublicKey, PublicKeyLength))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, NonceLength);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, NonceLength);
|
||||
AString Nonce;
|
||||
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(ReadChar, char, BlockMeta);
|
||||
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();
|
||||
return true;
|
||||
}
|
||||
@ -1461,12 +1470,12 @@ bool cConnection::HandleServerCompass(void)
|
||||
bool cConnection::HandleServerDestroyEntities(void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
Log("Received PACKET_DESTROY_ENTITIES from the server:");
|
||||
Log(" NumEntities = %d", NumEntities);
|
||||
Log(" NumEntities = %u", NumEntities);
|
||||
COPY_TO_CLIENT();
|
||||
return true;
|
||||
}
|
||||
@ -1687,15 +1696,15 @@ bool cConnection::HandleServerEntityVelocity(void)
|
||||
|
||||
bool cConnection::HandleServerExplosion(void)
|
||||
{
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosX);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosY);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosZ);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Force);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, NumRecords);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosX);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosY);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosZ);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Force);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, NumRecords);
|
||||
std::vector<sCoords> Records;
|
||||
Records.reserve(NumRecords);
|
||||
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, ry);
|
||||
@ -1708,10 +1717,10 @@ bool cConnection::HandleServerExplosion(void)
|
||||
Log("Received a PACKET_EXPLOSION from the server:");
|
||||
Log(" Pos = {%.02f, %.02f, %.02f}", PosX, PosY, PosZ);
|
||||
Log(" Force = %.02f", Force);
|
||||
Log(" NumRecords = %d", NumRecords);
|
||||
for (int i = 0; i < NumRecords; i++)
|
||||
Log(" NumRecords = %u", NumRecords);
|
||||
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);
|
||||
COPY_TO_CLIENT();
|
||||
@ -1822,8 +1831,8 @@ bool cConnection::HandleServerKick(void)
|
||||
Reason.append(Split[5]);
|
||||
AString ReasonBE16 = UTF8ToRawBEUTF16(Reason.data(), Reason.size());
|
||||
AString PacketStart("\xff");
|
||||
PacketStart.push_back((ReasonBE16.size() / 2) / 256);
|
||||
PacketStart.push_back((ReasonBE16.size() / 2) % 256);
|
||||
PacketStart.push_back(static_cast<char>((ReasonBE16.size() / 2) / 256));
|
||||
PacketStart.push_back(static_cast<char>((ReasonBE16.size() / 2) % 256));
|
||||
CLIENTSEND(PacketStart.data(), PacketStart.size());
|
||||
CLIENTSEND(ReasonBE16.data(), ReasonBE16.size());
|
||||
return true;
|
||||
@ -1847,12 +1856,12 @@ bool cConnection::HandleServerKick(void)
|
||||
|
||||
bool cConnection::HandleServerMapChunk(void)
|
||||
{
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkX);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkZ);
|
||||
HANDLE_SERVER_PACKET_READ(ReadChar, char, IsContiguous);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, PrimaryBitmap);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, AdditionalBitmap);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, CompressedSize);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkX);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkZ);
|
||||
HANDLE_SERVER_PACKET_READ(ReadChar, char, IsContiguous);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, PrimaryBitmap);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, AdditionalBitmap);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, CompressedSize);
|
||||
AString CompressedData;
|
||||
if (!m_ServerBuffer.ReadString(CompressedData, CompressedSize))
|
||||
{
|
||||
@ -1860,7 +1869,7 @@ bool cConnection::HandleServerMapChunk(void)
|
||||
}
|
||||
Log("Received a PACKET_MAP_CHUNK from the server:");
|
||||
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
|
||||
|
||||
@ -1874,9 +1883,9 @@ bool cConnection::HandleServerMapChunk(void)
|
||||
|
||||
bool cConnection::HandleServerMapChunkBulk(void)
|
||||
{
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, ChunkCount);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, CompressedSize);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBool, bool, IsSkyLightSent);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, ChunkCount);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, CompressedSize);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBool, bool, IsSkyLightSent);
|
||||
AString CompressedData;
|
||||
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(" ChunkCount = %d", ChunkCount);
|
||||
Log(" Compressed size = %d (0x%x)", CompressedSize, CompressedSize);
|
||||
Log(" ChunkCount = %u", ChunkCount);
|
||||
Log(" Compressed size = %u (0x%x)", CompressedSize, CompressedSize);
|
||||
Log(" IsSkyLightSent = %s", IsSkyLightSent ? "true" : "false");
|
||||
|
||||
// Log individual chunk coords:
|
||||
@ -1923,10 +1932,10 @@ bool cConnection::HandleServerMapChunkBulk(void)
|
||||
|
||||
bool cConnection::HandleServerMultiBlockChange(void)
|
||||
{
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkX);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkZ);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, NumBlocks);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, DataSize);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkX);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkZ);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, NumBlocks);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEUInt32, UInt32, DataSize);
|
||||
AString BlockChangeData;
|
||||
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(" Chunk = [%d, %d]", ChunkX, ChunkZ);
|
||||
Log(" NumBlocks = %d", NumBlocks);
|
||||
Log(" NumBlocks = %u", NumBlocks);
|
||||
COPY_TO_CLIENT();
|
||||
return true;
|
||||
}
|
||||
@ -2035,7 +2044,7 @@ bool cConnection::HandleServerPlayerPositionLook(void)
|
||||
bool cConnection::HandleServerPluginMessage(void)
|
||||
{
|
||||
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, ChannelName);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, Length);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, Length);
|
||||
AString Data;
|
||||
if (!m_ServerBuffer.ReadString(Data, Length))
|
||||
{
|
||||
@ -2043,7 +2052,7 @@ bool cConnection::HandleServerPluginMessage(void)
|
||||
}
|
||||
Log("Received a PACKET_PLUGIN_MESSAGE from the server");
|
||||
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();
|
||||
return true;
|
||||
}
|
||||
@ -2530,11 +2539,11 @@ bool cConnection::HandleServerUpdateSign(void)
|
||||
|
||||
bool cConnection::HandleServerUpdateTileEntity(void)
|
||||
{
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockY);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ);
|
||||
HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Action);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, DataLength);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockY);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ);
|
||||
HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Action);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEUInt16, UInt16, DataLength);
|
||||
|
||||
AString Data;
|
||||
if ((DataLength > 0) && !m_ServerBuffer.ReadString(Data, DataLength))
|
||||
@ -2548,7 +2557,7 @@ bool cConnection::HandleServerUpdateTileEntity(void)
|
||||
|
||||
// Save metadata to a file:
|
||||
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");
|
||||
if (f != NULL)
|
||||
{
|
||||
@ -2686,10 +2695,10 @@ bool cConnection::ParseSlot(cByteBuffer & a_Buffer, AString & a_ItemDesc)
|
||||
}
|
||||
char ItemCount;
|
||||
short ItemDamage;
|
||||
short MetadataLength;
|
||||
a_Buffer.ReadChar(ItemCount);
|
||||
UInt16 MetadataLength;
|
||||
a_Buffer.ReadChar(ItemCount); // We already know we can read these bytes - we checked before.
|
||||
a_Buffer.ReadBEShort(ItemDamage);
|
||||
a_Buffer.ReadBEShort(MetadataLength);
|
||||
a_Buffer.ReadBEUInt16(MetadataLength);
|
||||
Printf(a_ItemDesc, "%d:%d * %d", ItemType, ItemDamage, ItemCount);
|
||||
if (MetadataLength <= 0)
|
||||
{
|
||||
@ -2697,13 +2706,13 @@ bool cConnection::ParseSlot(cByteBuffer & a_Buffer, AString & a_ItemDesc)
|
||||
}
|
||||
AString Metadata;
|
||||
Metadata.resize(MetadataLength);
|
||||
if (!a_Buffer.ReadBuf((void *)Metadata.data(), MetadataLength))
|
||||
if (!a_Buffer.ReadBuf(const_cast<char *>(Metadata.data()), MetadataLength))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
AString MetaHex;
|
||||
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:
|
||||
AString fnam;
|
||||
@ -2725,17 +2734,19 @@ bool cConnection::ParseSlot(cByteBuffer & a_Buffer, AString & a_ItemDesc)
|
||||
|
||||
bool cConnection::ParseMetadata(cByteBuffer & a_Buffer, AString & a_Metadata)
|
||||
{
|
||||
char x;
|
||||
if (!a_Buffer.ReadChar(x))
|
||||
Byte x;
|
||||
if (!a_Buffer.ReadByte(x))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
a_Metadata.push_back(x);
|
||||
a_Metadata.push_back(static_cast<char>(x));
|
||||
while (x != 0x7f)
|
||||
{
|
||||
// int Index = ((unsigned)((unsigned char)x)) & 0x1f; // Lower 5 bits = index
|
||||
int Type = ((unsigned)((unsigned char)x)) >> 5; // Upper 3 bits = type
|
||||
int Length = 0;
|
||||
// int Index = static_cast<unsigned>(x) & 0x1f; // Lower 5 bits = index
|
||||
int Type = static_cast<unsigned>(x) >> 5; // Upper 3 bits = type
|
||||
|
||||
// Get the length of the data for this item:
|
||||
UInt32 Length = 0;
|
||||
switch (Type)
|
||||
{
|
||||
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
|
||||
{
|
||||
UInt32 Len;
|
||||
int rs = a_Buffer.GetReadableSpace();
|
||||
int rs = static_cast<int>(a_Buffer.GetReadableSpace());
|
||||
if (!a_Buffer.ReadVarInt(Len))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
rs = rs - a_Buffer.GetReadableSpace();
|
||||
rs = rs - static_cast<int>(a_Buffer.GetReadableSpace());
|
||||
cByteBuffer LenBuf(8);
|
||||
LenBuf.WriteVarInt(Len);
|
||||
AString VarLen;
|
||||
@ -2759,18 +2770,18 @@ bool cConnection::ParseMetadata(cByteBuffer & a_Buffer, AString & a_Metadata)
|
||||
Length = Len;
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
case 5: // Item, in "slot" format
|
||||
{
|
||||
int Before = a_Buffer.GetReadableSpace();
|
||||
size_t Before = a_Buffer.GetReadableSpace();
|
||||
AString ItemDesc;
|
||||
if (!ParseSlot(a_Buffer, ItemDesc))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int After = a_Buffer.GetReadableSpace();
|
||||
size_t After = a_Buffer.GetReadableSpace();
|
||||
a_Buffer.ResetRead();
|
||||
a_Buffer.SkipRead(a_Buffer.GetReadableSpace() - Before);
|
||||
Length = Before - After;
|
||||
Length = static_cast<UInt32>(Before - After);
|
||||
break;
|
||||
}
|
||||
case 6: Length = 12; break; // 3 * int
|
||||
@ -2781,17 +2792,19 @@ bool cConnection::ParseMetadata(cByteBuffer & a_Buffer, AString & a_Metadata)
|
||||
break;
|
||||
}
|
||||
} // switch (Type)
|
||||
|
||||
// Read the data in this item:
|
||||
AString data;
|
||||
if (!a_Buffer.ReadString(data, Length))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
a_Metadata.append(data);
|
||||
if (!a_Buffer.ReadChar(x))
|
||||
if (!a_Buffer.ReadByte(x))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
a_Metadata.push_back(x);
|
||||
a_Metadata.push_back(static_cast<char>(x));
|
||||
} // while (x != 0x7f)
|
||||
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)
|
||||
{
|
||||
AString Indent(a_IndentCount, ' ');
|
||||
int pos = 0;
|
||||
size_t pos = 0;
|
||||
while (a_Metadata[pos] != 0x7f)
|
||||
{
|
||||
int Index = ((unsigned)((unsigned char)a_Metadata[pos])) & 0x1f; // Lower 5 bits = index
|
||||
int Type = ((unsigned)((unsigned char)a_Metadata[pos])) >> 5; // Upper 3 bits = type
|
||||
unsigned Index = static_cast<unsigned>(static_cast<unsigned char>(a_Metadata[pos])) & 0x1f; // Lower 5 bits = index
|
||||
unsigned Type = static_cast<unsigned>(static_cast<unsigned char>(a_Metadata[pos])) >> 5; // Upper 3 bits = type
|
||||
// int Length = 0;
|
||||
switch (Type)
|
||||
{
|
||||
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;
|
||||
break;
|
||||
}
|
||||
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;
|
||||
break;
|
||||
}
|
||||
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;
|
||||
break;
|
||||
}
|
||||
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;
|
||||
break;
|
||||
}
|
||||
case 4: // UTF-8 string with VarInt length
|
||||
{
|
||||
cByteBuffer bb(10);
|
||||
int RestLen = (int)a_Metadata.size() - pos - 1;
|
||||
size_t RestLen = a_Metadata.size() - pos - 1;
|
||||
if (RestLen > 8)
|
||||
{
|
||||
RestLen = 8;
|
||||
}
|
||||
bb.Write(a_Metadata.data() + pos + 1, RestLen);
|
||||
UInt32 Length;
|
||||
int rs = bb.GetReadableSpace();
|
||||
bb.ReadVarInt(Length);
|
||||
size_t rs = bb.GetReadableSpace();
|
||||
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();
|
||||
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;
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
int BytesLeft = a_Metadata.size() - pos - 1;
|
||||
size_t BytesLeft = a_Metadata.size() - pos - 1;
|
||||
cByteBuffer bb(BytesLeft);
|
||||
bb.Write(a_Metadata.data() + pos + 1, BytesLeft);
|
||||
AString ItemDesc;
|
||||
@ -2863,16 +2880,16 @@ void cConnection::LogMetadata(const AString & a_Metadata, size_t a_IndentCount)
|
||||
ASSERT(!"Cannot parse item description from metadata");
|
||||
return;
|
||||
}
|
||||
// int After = bb.GetReadableSpace();
|
||||
int BytesConsumed = BytesLeft - bb.GetReadableSpace();
|
||||
// size_t After = 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;
|
||||
break;
|
||||
}
|
||||
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 + 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]
|
||||
@ -2931,7 +2948,7 @@ void cConnection::SendEncryptionKeyResponse(const AString & a_ServerPublicKey, c
|
||||
DataLog(EncryptedSecret, sizeof(EncryptedSecret), "Encrypted secret (%u bytes)", (unsigned)sizeof(EncryptedSecret));
|
||||
DataLog(EncryptedNonce, sizeof(EncryptedNonce), "Encrypted nonce (%u bytes)", (unsigned)sizeof(EncryptedNonce));
|
||||
cByteBuffer Len(5);
|
||||
Len.WriteVarInt(ToServer.GetReadableSpace());
|
||||
Len.WriteVarInt(static_cast<UInt32>(ToServer.GetReadableSpace()));
|
||||
SERVERSEND(Len);
|
||||
SERVERSEND(ToServer);
|
||||
m_ServerState = csEncryptedUnderstood;
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
void Run(void);
|
||||
|
||||
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);
|
||||
|
||||
protected:
|
||||
|
@ -38,13 +38,41 @@ int cServer::Init(short a_ListenPort, short a_ConnectPort)
|
||||
m_PublicKeyDER = m_PrivateKey.GetPubKeyDER();
|
||||
|
||||
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;
|
||||
memset(&local, 0, sizeof(local));
|
||||
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);
|
||||
bind(m_ListenSocket, (sockaddr *)&local, sizeof(local));
|
||||
listen(m_ListenSocket, 1);
|
||||
if (!bind(m_ListenSocket, (sockaddr *)&local, sizeof(local)))
|
||||
{
|
||||
#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);
|
||||
|
||||
|
8
app.yml
8
app.yml
@ -3,9 +3,7 @@ image: ubuntu-14-04-x64
|
||||
config:
|
||||
#cloud-config
|
||||
packages:
|
||||
- curl
|
||||
- screen
|
||||
- git
|
||||
runcmd:
|
||||
- mkdir /minecraft
|
||||
- cd /minecraft && curl -s https://raw.githubusercontent.com/mc-server/MCServer/master/easyinstall.sh | sh
|
||||
- cd /minecraft/MCServer && screen -S mcserver -d -m ./MCServer
|
||||
- cd /tmp && git clone https://github.com/cuberite/mcserver-ocean.git
|
||||
- cd /tmp/mcserver-ocean && ./initialinstall.sh
|
||||
|
@ -7,7 +7,7 @@ case $PLATFORM in
|
||||
"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" ;;
|
||||
# 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
|
||||
|
||||
echo "Downloading precompiled binaries."
|
||||
|
1
lib/libevent
Submodule
1
lib/libevent
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 0b49ae34594533daa82c06a506078de9e336a013
|
@ -839,6 +839,13 @@ void cLuaState::Push(void * a_Ptr)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -217,6 +217,7 @@ public:
|
||||
void Push(Vector3d * a_Vector);
|
||||
void Push(Vector3i * a_Vector);
|
||||
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 */
|
||||
void GetStackValue(int a_StackPos, bool & a_Value);
|
||||
|
@ -76,8 +76,8 @@ public:
|
||||
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 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 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 OnPlayerPlacedBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange) = 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 OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity) = 0;
|
||||
virtual bool OnPlayerShooting (cPlayer & a_Player) = 0;
|
||||
@ -104,7 +104,7 @@ public:
|
||||
virtual bool OnWeatherChanged (cWorld & a_World) = 0;
|
||||
virtual bool OnWeatherChanging (cWorld & a_World, eWeather & a_NewWeather) = 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.
|
||||
Command permissions have already been checked.
|
||||
|
@ -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);
|
||||
bool res = false;
|
||||
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACED_BLOCK];
|
||||
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)
|
||||
{
|
||||
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);
|
||||
bool res = false;
|
||||
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACING_BLOCK];
|
||||
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)
|
||||
{
|
||||
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);
|
||||
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WORLD_TICK];
|
||||
|
@ -100,8 +100,8 @@ public:
|
||||
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 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 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 OnPlayerPlacedBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange) 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 OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity) override;
|
||||
virtual bool OnPlayerShooting (cPlayer & a_Player) override;
|
||||
@ -128,7 +128,7 @@ public:
|
||||
virtual bool OnWeatherChanged (cWorld & a_World) override;
|
||||
virtual bool OnWeatherChanging (cWorld & a_World, eWeather & a_NewWeather) 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;
|
||||
|
||||
|
@ -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);
|
||||
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);
|
||||
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);
|
||||
VERIFY_HOOK;
|
||||
|
||||
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;
|
||||
}
|
||||
@ -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);
|
||||
VERIFY_HOOK;
|
||||
|
||||
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;
|
||||
}
|
||||
@ -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);
|
||||
VERIFY_HOOK;
|
||||
|
@ -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 CallHookPlayerDestroyed (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 CallHookPlayerFoodLevelChange (cPlayer & a_Player, int a_NewFoodLevel);
|
||||
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 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 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 CallHookPlayerMoving (cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition);
|
||||
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 CallHookPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity);
|
||||
bool CallHookPlayerShooting (cPlayer & a_Player);
|
||||
@ -237,7 +237,7 @@ public:
|
||||
bool CallHookWeatherChanged (cWorld & a_World);
|
||||
bool CallHookWeatherChanging (cWorld & a_World, eWeather & a_NewWeather);
|
||||
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 LoadPlugin (const AString & a_PluginName); // tolua_export
|
||||
|
@ -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
|
||||
if ((GetWorld()->GetWorldAge() % 80) == 0)
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
|
||||
// cBlockEntity overrides:
|
||||
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;
|
||||
|
||||
/** Modify the beacon level. (It is needed to load the beacon corectly) */
|
||||
|
@ -110,7 +110,7 @@ public:
|
||||
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.
|
||||
virtual bool Tick(float a_Dt, cChunk & a_Chunk)
|
||||
virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
UNUSED(a_Dt);
|
||||
return false;
|
||||
|
@ -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_Chunk);
|
||||
|
@ -33,7 +33,7 @@ public:
|
||||
/// Creates a new empty command block entity
|
||||
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 UsedBy(cPlayer * a_Player) override;
|
||||
|
||||
|
@ -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);
|
||||
if (!m_ShouldDropSpense)
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
virtual ~cDropSpenserEntity();
|
||||
|
||||
// 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 UsedBy(cPlayer * a_Player) override;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -42,7 +42,7 @@ public:
|
||||
|
||||
// cBlockEntity overrides:
|
||||
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 Destroy() override
|
||||
{
|
||||
|
@ -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);
|
||||
Int64 CurrentTick = a_Chunk.GetWorld()->GetWorldAge();
|
||||
|
@ -48,7 +48,7 @@ protected:
|
||||
Int64 m_LastMoveItemsOutTick;
|
||||
|
||||
// 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 UsedBy(cPlayer * a_Player) override;
|
||||
|
||||
|
@ -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
|
||||
if ((m_World->GetWorldAge() % 100) == 0)
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
|
||||
virtual void SendTo(cClientHandle & a_Client) 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
|
||||
|
||||
|
@ -959,6 +959,7 @@ enum
|
||||
E_META_SPAWN_EGG_WITHER = 64,
|
||||
E_META_SPAWN_EGG_BAT = 65,
|
||||
E_META_SPAWN_EGG_WITCH = 66,
|
||||
E_META_SPAWN_EGG_GUARDIAN = 68,
|
||||
E_META_SPAWN_EGG_PIG = 90,
|
||||
E_META_SPAWN_EGG_SHEEP = 91,
|
||||
E_META_SPAWN_EGG_COW = 92,
|
||||
@ -970,6 +971,7 @@ enum
|
||||
E_META_SPAWN_EGG_OCELOT = 98,
|
||||
E_META_SPAWN_EGG_IRON_GOLEM = 99,
|
||||
E_META_SPAWN_EGG_HORSE = 100,
|
||||
E_META_SPAWN_EGG_RABBIT = 101,
|
||||
E_META_SPAWN_EGG_VILLAGER = 120,
|
||||
E_META_SPAWN_EGG_ENDER_CRYSTAL = 200,
|
||||
} ;
|
||||
|
@ -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)
|
||||
{
|
||||
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);
|
||||
a_WorldInterface.ForEachPlayer(Unsetter);
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 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;
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
|
||||
|
@ -62,50 +62,11 @@ public:
|
||||
}
|
||||
|
||||
// Single chest, get meta from rotation only
|
||||
a_BlockMeta = RotationToMetaData(yaw);
|
||||
a_BlockMeta = PlayerYawToMetaData(yaw);
|
||||
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
|
||||
{
|
||||
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
|
||||
static NIBBLETYPE RotationToMetaData(double a_Rotation)
|
||||
/** Translates player yaw when placing a chest into the chest block metadata. Valid for single chests only */
|
||||
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
|
||||
{
|
||||
return 0x3;
|
||||
return 0x03;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ void cBlockDoorHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldIn
|
||||
if (OldMeta & 8)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
@ -31,7 +31,7 @@ void cBlockDoorHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldIn
|
||||
else
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
if (a_Meta & 0x08)
|
||||
{
|
||||
// The meta doesn't change for the top block
|
||||
return a_Meta;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Rotate the bottom block
|
||||
return super::MetaRotateCCW(a_Meta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
NIBBLETYPE cBlockDoorHandler::MetaRotateCW(NIBBLETYPE a_Meta)
|
||||
{
|
||||
if (a_Meta & 0x08)
|
||||
{
|
||||
// The meta doesn't change for the top block
|
||||
return a_Meta;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Rotate the bottom block
|
||||
return super::MetaRotateCW(a_Meta);
|
||||
}
|
||||
}
|
||||
@ -138,8 +120,10 @@ NIBBLETYPE cBlockDoorHandler::MetaRotateCW(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
|
||||
// in only the bottom tile while the hinge position is in the top tile. This function only operates on one tile at a time,
|
||||
|
@ -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
|
||||
{
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -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 */
|
||||
inline static bool IsDoor(BLOCKTYPE a_Block)
|
||||
inline static bool IsDoorBlockType(BLOCKTYPE 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
BLOCKTYPE Block = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
||||
if (!IsDoor(Block))
|
||||
if (!IsDoorBlockType(Block))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -12,7 +12,8 @@ class cBlockFireHandler :
|
||||
{
|
||||
public:
|
||||
cBlockFireHandler(BLOCKTYPE a_BlockType)
|
||||
: cBlockHandler(a_BlockType)
|
||||
: cBlockHandler(a_BlockType),
|
||||
XZP(0), XZM(0), Dir(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -42,15 +42,12 @@ public:
|
||||
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);
|
||||
|
||||
/// 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(
|
||||
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
|
||||
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, const sSetBlock & a_BlockChange
|
||||
);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// 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);
|
||||
|
||||
/** Indicates whether the client will click through this block.
|
||||
@ -109,20 +107,21 @@ public:
|
||||
*/
|
||||
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)
|
||||
{
|
||||
UNUSED(a_Meta);
|
||||
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);
|
||||
|
||||
/** Called when one of the neighbors gets set; equivalent to MC block update.
|
||||
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);
|
||||
|
||||
/// <summary>Rotates a given block meta counter-clockwise. Default: no change</summary>
|
||||
|
@ -12,16 +12,18 @@ class cBlockMobHeadHandler :
|
||||
public cBlockEntityHandler
|
||||
{
|
||||
public:
|
||||
cBlockMobHeadHandler(BLOCKTYPE a_BlockType)
|
||||
: cBlockEntityHandler(a_BlockType)
|
||||
cBlockMobHeadHandler(BLOCKTYPE a_BlockType):
|
||||
cBlockEntityHandler(a_BlockType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
if (a_Player->IsGameModeCreative())
|
||||
@ -61,202 +63,6 @@ public:
|
||||
|
||||
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[]
|
||||
}
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -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(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
|
@ -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
|
||||
{
|
||||
return (a_Meta + 4) & 0x0f;
|
||||
|
@ -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
|
||||
{
|
||||
int BlockX = (a_Chunk.GetPosX() * cChunkDef::Width) + a_RelX;
|
||||
|
@ -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:
|
||||
#if ( \
|
||||
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.
|
||||
It requires the monitored object to provide the storage for a thread ID.
|
||||
@ -122,7 +131,7 @@ public:
|
||||
{
|
||||
ASSERT(
|
||||
(*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:
|
||||
@ -138,8 +147,13 @@ public:
|
||||
protected:
|
||||
/** Points to the storage used for ID of the thread using the object. */
|
||||
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);
|
||||
|
||||
#else
|
||||
@ -330,12 +344,28 @@ bool cByteBuffer::ReadByte(unsigned char & 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
|
||||
CheckValid();
|
||||
NEEDBYTES(2);
|
||||
ReadBuf(&a_Value, 2);
|
||||
a_Value = (short)ntohs((u_short)a_Value);
|
||||
a_Value = ntohs(a_Value);
|
||||
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)
|
||||
{
|
||||
CHECK_THREAD
|
||||
|
@ -55,7 +55,9 @@ public:
|
||||
bool ReadChar (char & a_Value);
|
||||
bool ReadByte (unsigned char & a_Value);
|
||||
bool ReadBEShort (short & a_Value);
|
||||
bool ReadBEUInt16 (UInt16 & a_Value);
|
||||
bool ReadBEInt (int & a_Value);
|
||||
bool ReadBEUInt32 (UInt32 & a_Value);
|
||||
bool ReadBEInt64 (Int64 & a_Value);
|
||||
bool ReadBEFloat (float & a_Value);
|
||||
bool ReadBEDouble (double & a_Value);
|
||||
|
@ -5,6 +5,7 @@ project (MCServer)
|
||||
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/polarssl/include")
|
||||
include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/libevent/include")
|
||||
|
||||
set(FOLDERS
|
||||
OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++ Bindings
|
||||
@ -323,4 +324,4 @@ endif ()
|
||||
if (WIN32)
|
||||
target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib)
|
||||
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)
|
||||
|
@ -49,14 +49,14 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// sSetBlock:
|
||||
|
||||
sSetBlock::sSetBlock( int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) // absolute block position
|
||||
: x( a_BlockX)
|
||||
, y( a_BlockY)
|
||||
, z( a_BlockZ)
|
||||
, BlockType( a_BlockType)
|
||||
, BlockMeta( a_BlockMeta)
|
||||
sSetBlock::sSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta):
|
||||
m_RelX(a_BlockX),
|
||||
m_RelY(a_BlockY),
|
||||
m_RelZ(a_BlockZ),
|
||||
m_BlockType(a_BlockType),
|
||||
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
|
||||
) :
|
||||
m_Presence(cpInvalid),
|
||||
m_ShouldGenerateIfLoadFailed(false),
|
||||
m_IsLightValid(false),
|
||||
m_IsDirty(false),
|
||||
m_IsSaving(false),
|
||||
@ -93,6 +94,7 @@ cChunk::cChunk(
|
||||
m_WaterSimulatorData(a_World->GetWaterSimulator()->CreateChunkData()),
|
||||
m_LavaSimulatorData (a_World->GetLavaSimulator ()->CreateChunkData()),
|
||||
m_RedstoneSimulatorData(a_World->GetRedstoneSimulator()->CreateChunkData()),
|
||||
m_IsRedstoneDirty(false),
|
||||
m_AlwaysTicked(0)
|
||||
{
|
||||
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();
|
||||
|
||||
|
@ -160,7 +160,7 @@ public:
|
||||
/** Try to Spawn Monsters inside chunk */
|
||||
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 */
|
||||
void TickBlock(int a_RelX, int a_RelY, int a_RelZ);
|
||||
|
@ -347,18 +347,32 @@ public:
|
||||
|
||||
struct sSetBlock
|
||||
{
|
||||
int x, y, z;
|
||||
int ChunkX, ChunkZ;
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
int m_RelX, m_RelY, m_RelZ;
|
||||
int m_ChunkX, m_ChunkZ;
|
||||
BLOCKTYPE m_BlockType;
|
||||
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_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),
|
||||
ChunkX(a_ChunkX), ChunkZ(a_ChunkZ),
|
||||
BlockType(a_BlockType),
|
||||
BlockMeta(a_BlockMeta)
|
||||
{}
|
||||
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_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) :
|
||||
m_RelX(a_RelX), m_RelY(a_RelY), m_RelZ(a_RelZ),
|
||||
m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ),
|
||||
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;
|
||||
@ -385,6 +399,17 @@ public:
|
||||
typedef std::list<cChunkCoords> cChunkCoordsList;
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
107
src/ChunkMap.cpp
107
src/ChunkMap.cpp
@ -1101,17 +1101,17 @@ void cChunkMap::FastSetBlocks(sSetBlockList & a_BlockList)
|
||||
// Process all items from a_BlockList, either successfully or by placing into Failed
|
||||
while (!a_BlockList.empty())
|
||||
{
|
||||
int ChunkX = a_BlockList.front().ChunkX;
|
||||
int ChunkZ = a_BlockList.front().ChunkZ;
|
||||
int ChunkX = a_BlockList.front().m_ChunkX;
|
||||
int ChunkZ = a_BlockList.front().m_ChunkZ;
|
||||
cCSLock Lock(m_CSLayers);
|
||||
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ);
|
||||
if ((Chunk != nullptr) && Chunk->IsValid())
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
@ -1125,7 +1125,7 @@ void cChunkMap::FastSetBlocks(sSetBlockList & a_BlockList)
|
||||
// The chunk is not valid, move all blocks within this chunk to Failed
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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:
|
||||
{
|
||||
int X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
|
||||
int ChunkX, ChunkZ;
|
||||
cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ);
|
||||
cCSLock Lock(m_CSFastSetBlock);
|
||||
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[]
|
||||
}
|
||||
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);
|
||||
cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ);
|
||||
if ((Chunk != nullptr) && Chunk->IsValid())
|
||||
{
|
||||
return Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
||||
return Chunk->GetBlock(X, Y, Z);
|
||||
}
|
||||
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)
|
||||
{
|
||||
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:
|
||||
{
|
||||
cCSLock Lock(m_CSFastSetBlock);
|
||||
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[]
|
||||
}
|
||||
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);
|
||||
cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ);
|
||||
cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ);
|
||||
if ((Chunk != nullptr) && Chunk->IsValid())
|
||||
{
|
||||
return Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ);
|
||||
return Chunk->GetMeta(X, Y, Z);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1373,14 +1404,14 @@ void cChunkMap::ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_Filt
|
||||
cCSLock Lock(m_CSLayers);
|
||||
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())
|
||||
{
|
||||
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);
|
||||
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())
|
||||
{
|
||||
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:
|
||||
{
|
||||
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;
|
||||
}
|
||||
case E_BLOCK_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;
|
||||
}
|
||||
@ -1507,7 +1538,7 @@ bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
|
||||
cCSLock Lock(m_CSLayers);
|
||||
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 (!a_ContinueOnFailure)
|
||||
@ -1517,8 +1548,8 @@ bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
|
||||
res = false;
|
||||
continue;
|
||||
}
|
||||
itr->BlockType = Chunk->GetBlock(itr->x, itr->y, itr->z);
|
||||
itr->BlockMeta = Chunk->GetMeta(itr->x, itr->y, itr->z);
|
||||
itr->m_BlockType = Chunk->GetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ);
|
||||
itr->m_BlockMeta = Chunk->GetMeta(itr->m_RelX, itr->m_RelY, itr->m_RelZ);
|
||||
}
|
||||
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);
|
||||
@ -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);
|
||||
m_World->GetSimulatorManager()->WakeUp(a_X, a_Y, a_Z, DestChunk);
|
||||
m_World->GetSimulatorManager()->WakeUp(a_BlockX, a_BlockY, a_BlockZ, DestChunk);
|
||||
}
|
||||
|
||||
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);
|
||||
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++)
|
||||
{
|
||||
|
@ -143,7 +143,13 @@ public:
|
||||
void FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
||||
|
||||
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);
|
||||
|
||||
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. */
|
||||
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 DigBlock (int a_X, int a_Y, int a_Z);
|
||||
void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player);
|
||||
/** Removes the block at the specified coords and wakes up simulators.
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
void TickBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||
@ -400,7 +415,7 @@ private:
|
||||
/** Try to Spawn Monsters inside all Chunks */
|
||||
void SpawnMobs(cMobSpawner& a_MobSpawner);
|
||||
|
||||
void Tick(float a_Dt);
|
||||
void Tick(std::chrono::milliseconds a_Dt);
|
||||
|
||||
void RemoveClient(cClientHandle * a_Client);
|
||||
|
||||
|
@ -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))
|
||||
{
|
||||
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)))
|
||||
{
|
||||
if ((m_Player->IsSatiated() || m_Player->IsGameModeCreative()) &&
|
||||
ItemHandler->IsFood() && (Equipped.m_ItemType != E_ITEM_GOLDEN_APPLE))
|
||||
if (
|
||||
(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
|
||||
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)
|
||||
{
|
||||
// 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))
|
||||
{
|
||||
@ -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());
|
||||
SendDisconnect("Protocol error");
|
||||
|
@ -251,10 +251,10 @@ public:
|
||||
// Calls that cProtocol descendants use to report state:
|
||||
void PacketBufferFull(void);
|
||||
void PacketUnknown(UInt32 a_PacketType);
|
||||
void PacketError(unsigned char a_PacketType);
|
||||
void PacketError(UInt32 a_PacketType);
|
||||
|
||||
// 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
|
||||
an item in the anvil UI. */
|
||||
@ -459,9 +459,6 @@ private:
|
||||
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) */
|
||||
bool CheckBlockInteractionsRate(void);
|
||||
|
||||
|
@ -183,6 +183,7 @@ int cEnchantments::StringToEnchantmentID(const AString & a_EnchantmentName)
|
||||
{ enchRespiration, "Respiration"},
|
||||
{ enchAquaAffinity, "AquaAffinity"},
|
||||
{ enchThorns, "Thorns"},
|
||||
{ enchDepthStrider, "DepthStrider"},
|
||||
{ enchSharpness, "Sharpness"},
|
||||
{ enchSmite, "Smite"},
|
||||
{ enchBaneOfArthropods, "BaneOfArthropods"},
|
||||
@ -506,6 +507,20 @@ void cEnchantments::AddItemEnchantmentWeights(cWeightedEnchantments & a_Enchantm
|
||||
{
|
||||
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;
|
||||
for (const auto Enchantment : a_Enchantments)
|
||||
{
|
||||
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);
|
||||
int RandomNumber = Noise.IntNoise1DInt(AllWeights) / 7 % AllWeights;
|
||||
|
||||
for (const auto Enchantment : a_Enchantments)
|
||||
{
|
||||
RandomNumber -= Enchantment.m_Weight;
|
||||
if (RandomNumber < 0)
|
||||
if (RandomNumber <= 0)
|
||||
{
|
||||
return Enchantment.m_Enchantments;
|
||||
}
|
||||
}
|
||||
|
||||
// No enchantment picked, return an empty one (we probably shouldn't ever get here):
|
||||
return cEnchantments();
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@ public:
|
||||
enchRespiration = 5,
|
||||
enchAquaAffinity = 6,
|
||||
enchThorns = 7,
|
||||
enchDepthStrider = 8,
|
||||
enchSharpness = 16,
|
||||
enchSmite = 17,
|
||||
enchBaneOfArthropods = 18,
|
||||
@ -128,8 +129,10 @@ public:
|
||||
/** Gets random enchantment from Vector and returns it */
|
||||
static cEnchantments GetRandomEnchantmentFromVector(cWeightedEnchantments & a_Enchantments);
|
||||
|
||||
/** Returns an enchantment from a Vector using cNoise. Mostly used for generators.*/
|
||||
static cEnchantments GenerateEnchantmentFromVector(cWeightedEnchantments & a_Enchantments, int a_Seed);
|
||||
/** Selects one enchantment from a Vector using cNoise. Mostly used for generators.
|
||||
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 */
|
||||
bool operator !=(const cEnchantments & a_Other) const;
|
||||
|
@ -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);
|
||||
m_Timer += a_Dt;
|
||||
|
||||
if (m_bIsCollected)
|
||||
{
|
||||
if (m_Timer > 500.f) // 0.5 seconds
|
||||
if (m_Timer > std::chrono::milliseconds(500))
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (m_Timer > 1000 * 60 * 5) // 5 minutes
|
||||
else if (m_Timer > std::chrono::minutes(5))
|
||||
{
|
||||
Destroy();
|
||||
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_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_HasTeleported = true;
|
||||
|
@ -85,10 +85,10 @@ protected:
|
||||
bool m_IsCritical;
|
||||
|
||||
/** 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 */
|
||||
float m_HitGroundTimer;
|
||||
std::chrono::milliseconds m_HitGroundTimer;
|
||||
|
||||
// Whether the arrow has already been teleported into the proper position in the ground.
|
||||
bool m_HasTeleported;
|
||||
@ -103,6 +103,6 @@ protected:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) 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
|
||||
|
@ -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);
|
||||
BroadcastMovementUpdate();
|
||||
|
@ -27,7 +27,7 @@ public:
|
||||
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
|
||||
virtual void OnRightClicked(cPlayer & a_Player) 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;
|
||||
|
||||
cBoat(double a_X, double a_Y, double a_Z);
|
||||
|
@ -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);
|
||||
// No further processing (physics e.t.c.) is needed
|
||||
|
@ -23,7 +23,7 @@ private:
|
||||
|
||||
// cEntity overrides:
|
||||
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;
|
||||
|
||||
}; // tolua_export
|
||||
|
@ -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++;
|
||||
|
||||
@ -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 BlockY = POSY_TOINT;
|
||||
@ -851,15 +851,15 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
GET_AND_VERIFY_CURRENT_CHUNK(NextChunk, BlockX, BlockZ)
|
||||
|
||||
// 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 NextSpeed = Vector3d(GetSpeedX(), GetSpeedY(), GetSpeedZ());
|
||||
|
||||
if ((BlockY >= cChunkDef::Height) || (BlockY < 0))
|
||||
{
|
||||
// Outside of the world
|
||||
AddSpeedY(m_Gravity * a_Dt);
|
||||
AddPosition(GetSpeed() * a_Dt);
|
||||
AddSpeedY(m_Gravity * DtSec.count());
|
||||
AddPosition(GetSpeed() * DtSec.count());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -927,11 +927,11 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
|
||||
if (!m_bOnGround)
|
||||
{
|
||||
float fallspeed;
|
||||
double fallspeed;
|
||||
if (IsBlockWater(BlockIn))
|
||||
{
|
||||
fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water
|
||||
ApplyFriction(NextSpeed, 0.7, a_Dt);
|
||||
fallspeed = m_Gravity * DtSec.count() / 3; // Fall 3x slower in water
|
||||
ApplyFriction(NextSpeed, 0.7, static_cast<float>(DtSec.count()));
|
||||
}
|
||||
else if (BlockIn == E_BLOCK_COBWEB)
|
||||
{
|
||||
@ -941,13 +941,13 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
else
|
||||
{
|
||||
// Normal gravity
|
||||
fallspeed = m_Gravity * a_Dt;
|
||||
fallspeed = m_Gravity * DtSec.count();
|
||||
}
|
||||
NextSpeed.y += fallspeed;
|
||||
NextSpeed.y += static_cast<float>(fallspeed);
|
||||
}
|
||||
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
|
||||
@ -1002,14 +1002,14 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
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
|
||||
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);
|
||||
|
||||
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)
|
||||
// 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
|
||||
// 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
|
||||
// be henceforth seen again in the time of programmers and man alike
|
||||
// </&sensationalist>
|
||||
NextPos += (NextSpeed * a_Dt);
|
||||
NextPos += (NextSpeed * DtSec.count());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We didn't hit anything, so move =]
|
||||
NextPos += (NextSpeed * a_Dt);
|
||||
NextPos += (NextSpeed * DtSec.count());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -326,10 +326,10 @@ public:
|
||||
|
||||
// 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
|
||||
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
|
||||
virtual void TickBurning(cChunk & a_Chunk);
|
||||
|
@ -8,7 +8,7 @@
|
||||
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)
|
||||
, m_Reward(a_Reward)
|
||||
, m_Timer(0.f)
|
||||
, m_Timer(0)
|
||||
{
|
||||
SetMaxHealth(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)
|
||||
: cEntity(etExpOrb, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98)
|
||||
, m_Reward(a_Reward)
|
||||
, m_Timer(0.f)
|
||||
, m_Timer(0)
|
||||
{
|
||||
SetMaxHealth(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));
|
||||
if (a_ClosestPlayer != nullptr)
|
||||
@ -70,7 +70,7 @@ void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
HandlePhysics(a_Dt, a_Chunk);
|
||||
|
||||
m_Timer += a_Dt;
|
||||
if (m_Timer >= 1000 * 60 * 5) // 5 minutes
|
||||
if (m_Timer >= std::chrono::minutes(5))
|
||||
{
|
||||
Destroy(true);
|
||||
}
|
||||
|
@ -22,14 +22,14 @@ public:
|
||||
cExpOrb(const Vector3d & a_Pos, int a_Reward);
|
||||
|
||||
// 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;
|
||||
|
||||
/** 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 */
|
||||
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 */
|
||||
int GetReward(void) const { return m_Reward; } // tolua_export
|
||||
@ -41,5 +41,5 @@ protected:
|
||||
int m_Reward;
|
||||
|
||||
/** 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
|
||||
|
@ -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
|
||||
|
||||
@ -82,7 +82,7 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
return;
|
||||
}
|
||||
|
||||
float MilliDt = a_Dt * 0.001f;
|
||||
float MilliDt = a_Dt.count() * 0.001f;
|
||||
AddSpeedY(MilliDt * -9.8f);
|
||||
AddPosition(GetSpeed() * MilliDt);
|
||||
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
|
||||
// cEntity overrides:
|
||||
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:
|
||||
BLOCKTYPE m_BlockType;
|
||||
|
@ -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 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))
|
||||
{
|
||||
AddSpeedY(1);
|
||||
AddPosition(GetSpeed() * (a_Dt / 1000));
|
||||
AddPosition(GetSpeed() * (static_cast<double>(a_Dt.count()) / 1000));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -53,14 +53,14 @@ void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -49,8 +49,8 @@ public:
|
||||
protected:
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -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);
|
||||
if (IsBlockWater(m_World->GetBlock((int) GetPosX(), (int) GetPosY(), (int) GetPosZ())) && m_World->GetBlockMeta((int) GetPosX(), (int) GetPosY(), (int) GetPosZ()) == 0)
|
||||
|
@ -21,7 +21,7 @@ public:
|
||||
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 Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
// tolua_begin
|
||||
bool CanPickup(void) const { return m_CanPickupItem; }
|
||||
|
@ -43,7 +43,7 @@ public:
|
||||
private:
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
@ -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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
@ -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,
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
|
||||
// cEntity overrides:
|
||||
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 void Destroyed() override;
|
||||
|
||||
@ -56,7 +56,7 @@ protected:
|
||||
/** 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
|
||||
*/
|
||||
void HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt);
|
||||
void HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt);
|
||||
|
||||
/** Handles powered rail physics
|
||||
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
|
||||
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 */
|
||||
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
|
||||
For curved rails, it changes the cart's direction as well as snapping it to axis */
|
||||
@ -171,7 +171,7 @@ public:
|
||||
|
||||
// cEntity overrides:
|
||||
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.
|
||||
void SetIsFueled(bool a_IsFueled, int a_FueledTimeLeft = -1) {m_IsFueled = a_IsFueled; m_FueledTimeLeft = a_FueledTimeLeft;}
|
||||
|
@ -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_Chunk);
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
private:
|
||||
|
||||
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 KilledBy(TakeDamageInfo & a_TDI) override
|
||||
{
|
||||
|
@ -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
|
||||
for (tEffectMap::iterator iter = m_EntityEffects.begin(); iter != m_EntityEffects.end();)
|
||||
|
@ -20,7 +20,7 @@ public:
|
||||
|
||||
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;
|
||||
|
||||
// tolua_begin
|
||||
|
@ -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 */)
|
||||
: cEntity(etPickup, a_PosX, a_PosY, a_PosZ, 0.2, 0.2)
|
||||
, m_Timer(0.f)
|
||||
, m_Timer(0)
|
||||
, m_Item(a_Item)
|
||||
, m_bCollected(false)
|
||||
, 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);
|
||||
BroadcastMovementUpdate(); // Notify clients of position
|
||||
@ -141,9 +141,9 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
)
|
||||
{
|
||||
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.
|
||||
if (m_Timer > 500.f)
|
||||
if (m_Timer > std::chrono::milliseconds(500))
|
||||
{
|
||||
Destroy(true);
|
||||
return;
|
||||
@ -167,14 +167,14 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Timer > 500.f) // 0.5 second
|
||||
if (m_Timer > std::chrono::milliseconds(500)) // 0.5 second
|
||||
{
|
||||
Destroy(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Timer > 1000 * 60 * 5) // 5 minutes
|
||||
if (m_Timer > std::chrono::minutes(5)) // 5 minutes
|
||||
{
|
||||
Destroy(true);
|
||||
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
|
||||
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());
|
||||
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
|
||||
m_bCollected = true;
|
||||
}
|
||||
m_Timer = 0;
|
||||
m_Timer = std::chrono::milliseconds(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -34,13 +34,13 @@ public:
|
||||
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
bool IsCollected(void) const { return m_bCollected; } // tolua_export
|
||||
@ -51,7 +51,7 @@ public:
|
||||
private:
|
||||
|
||||
/** 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;
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "Player.h"
|
||||
#include <unordered_map>
|
||||
#include "../ChatColor.h"
|
||||
#include "../Server.h"
|
||||
#include "../UI/InventoryWindow.h"
|
||||
@ -19,6 +20,10 @@
|
||||
#include "../WorldStorage/StatSerializer.h"
|
||||
#include "../CompositeChat.h"
|
||||
|
||||
#include "../Blocks/BlockHandler.h"
|
||||
#include "../Blocks/BlockSlab.h"
|
||||
#include "../Blocks/ChunkInterface.h"
|
||||
|
||||
#include "../IniFile.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)
|
||||
{
|
||||
@ -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()
|
||||
{
|
||||
super::Detach();
|
||||
|
@ -46,9 +46,9 @@ public:
|
||||
|
||||
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 */
|
||||
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. */
|
||||
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
|
||||
|
||||
/** 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:
|
||||
virtual bool IsCrouched (void) const { return m_IsCrouched; }
|
||||
virtual bool IsSprinting(void) const { return m_IsSprinting; }
|
||||
|
@ -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);
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
@ -118,8 +118,8 @@ protected:
|
||||
bool m_IsInGround;
|
||||
|
||||
// cEntity overrides:
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void Tick(std::chrono::milliseconds 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;
|
||||
|
||||
} ; // tolua_export
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user