1
0
Fork 0

Merge branch 'master' into Inventory

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

1
.gitignore vendored
View File

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

3
.gitmodules vendored
View File

@ -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

View File

@ -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

View File

@ -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/;

View File

@ -95,6 +95,24 @@ set(SQLITECPP_BUILD_EXAMPLES OFF CACHE BOOL "Build examples."
set(SQLITECPP_BUILD_TESTS OFF CACHE BOOL "Build and run tests." FORCE)
set(SQLITECPP_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()

View File

@ -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 ###

View File

@ -1840,7 +1840,9 @@ a_Player:OpenWindow(Window);
MoveToWorld = { Params = "WorldName", Return = "bool", Return = "Moves the player to the specified world. Returns true if successful." },
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." },

View File

@ -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" },
},

View File

@ -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" },
},

View File

@ -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" },

View File

@ -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

View File

@ -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>

View File

@ -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:

View File

@ -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"},

View File

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

View File

@ -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

View File

@ -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"

View File

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

View File

@ -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

View File

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

View File

@ -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:

View File

@ -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);

View File

@ -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

View File

@ -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

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

View File

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

View File

@ -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);

View File

@ -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.

View File

@ -857,14 +857,19 @@ bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d & a_OldPositi
bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange)
{
cCSLock Lock(m_CriticalSection);
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];

View File

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

View File

@ -771,7 +771,7 @@ bool cPluginManager::CallHookPlayerFoodLevelChange(cPlayer & a_Player, int a_New
bool cPluginManager::CallHookPlayerFished(cPlayer & a_Player, const cItems a_Reward)
bool cPluginManager::CallHookPlayerFished(cPlayer & a_Player, const cItems & a_Reward)
{
FIND_HOOK(HOOK_PLAYER_FISHED);
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;

View File

@ -203,14 +203,14 @@ public:
bool CallHookPlayerBrokenBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
bool 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

View File

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

View File

@ -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) */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
{

View File

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

View File

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

View File

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

View File

@ -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

View File

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

View File

@ -14,24 +14,6 @@
void cBlockBedHandler::OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
)
{
if (a_BlockMeta < 8)
{
Vector3i Direction = MetaDataToDirection(a_BlockMeta);
a_ChunkInterface.SetBlock(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z, E_BLOCK_BED, a_BlockMeta | 0x8);
}
}
void cBlockBedHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
{
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
}
}
}

View File

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

View File

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

View File

@ -62,50 +62,11 @@ public:
}
// Single chest, get meta from rotation only
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;
}
}

View File

@ -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,

View File

@ -101,14 +101,6 @@ public:
}
virtual void OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
) override;
virtual bool IsUseable(void) override
{
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;
}

View File

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

View File

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

View File

@ -42,15 +42,12 @@ public:
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
);
/// 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>

View File

@ -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[]
}
}
} ;

View File

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

View File

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

View File

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

View File

@ -13,6 +13,15 @@
/** When defined, each access to a cByteBuffer object is checked whether it's done in the same thread.
cByteBuffer assumes that it is not used by multiple threads at once, this macro adds a runtime check for that.
Unfortunately it is very slow, so it is disabled even for regular DEBUG builds. */
// #define DEBUG_SINGLE_THREAD_ACCESS
// Try to determine endianness:
#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

View File

@ -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);

View File

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

View File

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

View File

@ -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);

View File

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

View File

@ -1101,17 +1101,17 @@ void cChunkMap::FastSetBlocks(sSetBlockList & a_BlockList)
// Process all items from a_BlockList, either successfully or by placing into Failed
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++)
{

View File

@ -143,7 +143,13 @@ public:
void FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
void 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);

View File

@ -1349,12 +1349,19 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
if (ItemHandler->IsPlaceable() && (a_BlockFace != BLOCK_FACE_NONE))
{
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");

View File

@ -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);

View File

@ -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();
}

View File

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

View File

@ -174,20 +174,20 @@ void cArrowEntity::CollectedBy(cPlayer & a_Dest)
void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk)
void cArrowEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
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;

View File

@ -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

View File

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

View File

@ -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);

View File

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

View File

@ -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

View File

@ -772,7 +772,7 @@ void cEntity::SetHealth(int a_Health)
void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
void cEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
m_TicksAlive++;
@ -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());
}
}

View File

@ -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);

View File

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

View File

@ -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

View File

@ -31,7 +31,7 @@ void cFallingBlock::SpawnOn(cClientHandle & a_ClientHandle)
void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
void cFallingBlock::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
// GetWorld()->BroadcastTeleportEntity(*this); // Test position
@ -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);

View File

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

View File

@ -19,7 +19,7 @@ cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, do
void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
void cFireworkEntity::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
int 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);

View File

@ -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:

View File

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

View File

@ -21,7 +21,7 @@ public:
cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID, int a_CountDownTime);
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; }

View File

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

View File

@ -112,7 +112,7 @@ void cMinecart::SpawnOn(cClientHandle & a_ClientHandle)
void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
void cMinecart::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
if (IsDestroyed()) // Mainly to stop detector rails triggering again after minecart is dead
{
@ -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);

View File

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

View File

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

View File

@ -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
{

View File

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

View File

@ -20,7 +20,7 @@ public:
cPawn(eEntityType a_EntityType, double a_Width, double a_Height);
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

View File

@ -86,7 +86,7 @@ protected:
cPickup::cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, bool IsPlayerCreated, float a_SpeedX /* = 0.f */, float a_SpeedY /* = 0.f */, float a_SpeedZ /* = 0.f */)
: 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;
}

View File

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

View File

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

View File

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

View File

@ -331,7 +331,7 @@ AString cProjectileEntity::GetMCAClassName(void) const
void cProjectileEntity::Tick(float a_Dt, cChunk & a_Chunk)
void cProjectileEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
@ -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)
{

View File

@ -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