1
0

Merge remote-tracking branch 'origin/master' into minecartimprovements

This commit is contained in:
Tiger Wang 2014-01-19 13:55:22 +00:00
commit 82b2290b74
85 changed files with 1239 additions and 333 deletions

2
.gitignore vendored
View File

@ -1,4 +1,6 @@
build/
ipch/
Win32/
MCServer/MCServer
ChunkWorxSave.ini
doxy/

6
.gitmodules vendored
View File

@ -1,9 +1,9 @@
[submodule "MCServer/Plugins/Core"]
path = MCServer/Plugins/Core
url = git://github.com/mc-server/Core.git
url = https://github.com/mc-server/Core.git
[submodule "MCServer/Plugins/ProtectionAreas"]
path = MCServer/Plugins/ProtectionAreas
url = git://github.com/mc-server/ProtectionAreas.git
url = https://github.com/mc-server/ProtectionAreas.git
[submodule "MCServer/Plugins/TransAPI"]
path = MCServer/Plugins/TransAPI
url = git://github.com/bearbin/transapi.git
url = https://github.com/bearbin/transapi.git

View File

@ -47,6 +47,7 @@ elseif(APPLE)
#on os x clang adds pthread for us but we need to add it for gcc
if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_flags_cxx("-pthread")
add_flags_cxx("-std=c++11")
endif()
else()
# Let gcc / clang know that we're compiling a multi-threaded app:

View File

@ -81,8 +81,8 @@ This is useful if you want to compile MCServer to use on another 32-bit machine.
to your cmake command and 32 bit will be forced.
Compiling for another computer
------------------------------
### Compiling for another computer ###
When compiling for another computer it is important to set cross compiling mode. This tells the compiler not to optimise for your machine. It can be used with debug or release mode. To enable simply add:

View File

@ -20,5 +20,6 @@ worktycho
Sxw1212
tonibm19
Diusrex
structinf (xdot)
Please add yourself to this list if you contribute to MCServer.

View File

@ -1726,7 +1726,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
ForEachCommand = { Params = "CallbackFn", Return = "bool", Notes = "Calls the CallbackFn function for each command that has been bound using BindCommand(). The CallbackFn has the following signature: <pre class=\"prettyprint lang-lua\">function(Command, Permission, HelpString)</pre>. If the callback returns true, the enumeration is aborted and this API function returns false; if it returns false or no value, the enumeration continues with the next command, and the API function returns true." },
ForEachConsoleCommand = { Params = "CallbackFn", Return = "bool", Notes = "Calls the CallbackFn function for each command that has been bound using BindConsoleCommand(). The CallbackFn has the following signature: <pre class=\"prettyprint lang-lua\">function (Command, HelpString)</pre>. If the callback returns true, the enumeration is aborted and this API function returns false; if it returns false or no value, the enumeration continues with the next command, and the API function returns true." },
Get = { Params = "", Return = "cPluginManager", Notes = "(STATIC) Returns the single instance of the plugin manager" },
GetAllPlugins = { Params = "", Return = "table", Notes = "Returns a table (dictionary) of all plugins, [name => {{cPlugin}}] pairing." },
GetAllPlugins = { Params = "", Return = "table", Notes = "Returns a table (dictionary) of all plugins, [name => value], where value is a valid {{cPlugin}} if the plugin is loaded, or the bool value false if the plugin is not loaded." },
GetCommandPermission = { Params = "Command", Return = "Permission", Notes = "Returns the permission needed for executing the specified command" },
GetCurrentPlugin = { Params = "", Return = "{{cPlugin}}", Notes = "Returns the {{cPlugin}} object for the calling plugin. This is the same object that the Initialize function receives as the argument." },
GetNumPlugins = { Params = "", Return = "number", Notes = "Returns the number of plugins, including the disabled ones" },

@ -1 +1 @@
Subproject commit decc72f3a9134d80df5e14c3f2570e1479d521c6
Subproject commit e9695520248ef32f229162ba2b0ee6792749777d

View File

@ -77,8 +77,8 @@ endfunction()
# Include the libraries:
file(GLOB CRYPTOPP_SRC "../../lib/CryptoPP/*.cpp")
file(GLOB CRYPTOPP_HDR "../../lib/CryptoPP/*.h")
file(GLOB CRYPTOPP_SRC "../../lib/cryptopp/*.cpp")
file(GLOB CRYPTOPP_HDR "../../lib/cryptopp/*.h")
flatten_files(CRYPTOPP_SRC)
flatten_files(CRYPTOPP_HDR)
source_group("CryptoPP" FILES ${CRYPTOPP_SRC} ${CRYPTOPP_HDR})

View File

@ -155,6 +155,32 @@ AString PrintableAbsIntTriplet(int a_X, int a_Y, int a_Z, double a_Divisor = 32)
struct sCoords
{
int x, y, z;
sCoords(int a_X, int a_Y, int a_Z) : x(a_X), y(a_Y), z(a_Z) {}
} ;
struct sChunkMeta
{
int m_ChunkX, m_ChunkZ;
short m_PrimaryBitmap;
short m_AddBitmap;
sChunkMeta(int a_ChunkX, int a_ChunkZ, short a_PrimaryBitmap, short a_AddBitmap) :
m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ), m_PrimaryBitmap(a_PrimaryBitmap), m_AddBitmap(a_AddBitmap)
{
}
} ;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cConnection:
@ -220,7 +246,7 @@ void cConnection::Run(void)
int res = select(2, &ReadFDs, NULL, NULL, NULL);
if (res <= 0)
{
printf("select() failed: %d; aborting client", WSAGetLastError());
printf("select() failed: %d; aborting client", SocketError);
break;
}
if (FD_ISSET(m_ServerSocket, &ReadFDs))
@ -249,12 +275,10 @@ void cConnection::Run(void)
void cConnection::Log(const char * a_Format, ...)
{
va_list args, argsCopy;
va_list args;
va_start(args, a_Format);
va_start(argsCopy, a_Format);
AString msg;
AppendVPrintf(msg, a_Format, args, argsCopy);
va_end(argsCopy);
AppendVPrintf(msg, a_Format, args);
va_end(args);
AString FullMsg;
Printf(FullMsg, "[%5.3f] %s\n", GetRelativeTime(), msg.c_str());
@ -276,12 +300,10 @@ void cConnection::Log(const char * a_Format, ...)
void cConnection::DataLog(const void * a_Data, int a_Size, const char * a_Format, ...)
{
va_list args, argsCopy;
va_list args;
va_start(args, a_Format);
va_start(argsCopy, a_Format);
AString msg;
AppendVPrintf(msg, a_Format, args, argsCopy);
va_end(argsCopy);
AppendVPrintf(msg, a_Format, args);
va_end(args);
AString FullMsg;
AString Hex;
@ -323,7 +345,7 @@ bool cConnection::ConnectToServer(void)
localhost.sin_addr.s_addr = htonl(0x7f000001); // localhost
if (connect(m_ServerSocket, (sockaddr *)&localhost, sizeof(localhost)) != 0)
{
printf("connection to server failed: %d\n", WSAGetLastError());
printf("connection to server failed: %d\n", SocketError);
return false;
}
Log("Connected to SERVER");
@ -340,7 +362,7 @@ bool cConnection::RelayFromServer(void)
int res = recv(m_ServerSocket, Buffer, sizeof(Buffer), 0);
if (res <= 0)
{
Log("Server closed the socket: %d; %d; aborting connection", res, WSAGetLastError());
Log("Server closed the socket: %d; %d; aborting connection", res, SocketError);
return false;
}
@ -380,7 +402,7 @@ bool cConnection::RelayFromClient(void)
int res = recv(m_ClientSocket, Buffer, sizeof(Buffer), 0);
if (res <= 0)
{
Log("Client closed the socket: %d; %d; aborting connection", res, WSAGetLastError());
Log("Client closed the socket: %d; %d; aborting connection", res, SocketError);
return false;
}
@ -428,7 +450,7 @@ bool cConnection::SendData(SOCKET a_Socket, const char * a_Data, int a_Size, con
int res = send(a_Socket, a_Data, a_Size, 0);
if (res <= 0)
{
Log("%s closed the socket: %d, %d; aborting connection", a_Peer, res, WSAGetLastError());
Log("%s closed the socket: %d, %d; aborting connection", a_Peer, res, SocketError);
return false;
}
return true;
@ -1668,12 +1690,6 @@ bool cConnection::HandleServerExplosion(void)
HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosZ);
HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Force);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, NumRecords);
struct sCoords
{
int x, y, z;
sCoords(int a_X, int a_Y, int a_Z) : x(a_X), y(a_Y), z(a_Z) {}
} ;
std::vector<sCoords> Records;
Records.reserve(NumRecords);
int PosXI = (int)PosX, PosYI = (int)PosY, PosZI = (int)PosZ;
@ -1868,16 +1884,6 @@ bool cConnection::HandleServerMapChunkBulk(void)
// Read individual chunk metas.
// Need to read them first and only then start logging (in case we don't have the full packet yet)
struct sChunkMeta
{
int m_ChunkX, m_ChunkZ;
short m_PrimaryBitmap;
short m_AddBitmap;
sChunkMeta(int a_ChunkX, int a_ChunkZ, short a_PrimaryBitmap, short a_AddBitmap) :
m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ), m_PrimaryBitmap(a_PrimaryBitmap), m_AddBitmap(a_AddBitmap)
{
}
} ;
typedef std::vector<sChunkMeta> sChunkMetas;
sChunkMetas ChunkMetas;
ChunkMetas.reserve(ChunkCount);
@ -1907,7 +1913,6 @@ bool cConnection::HandleServerMapChunkBulk(void)
// TODO: Save the compressed data into a file for later analysis
COPY_TO_CLIENT();
Sleep(50);
return true;
}
@ -2857,8 +2862,8 @@ void cConnection::SendEncryptionKeyResponse(const AString & a_ServerPublicKey, c
int EncryptedLength = rsaEncryptor.FixedCiphertextLength();
ASSERT(EncryptedLength <= sizeof(EncryptedSecret));
rsaEncryptor.Encrypt(rng, SharedSecret, sizeof(SharedSecret), EncryptedSecret);
m_ServerEncryptor.SetKey(SharedSecret, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(SharedSecret, 16))(Name::FeedbackSize(), 1));
m_ServerDecryptor.SetKey(SharedSecret, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(SharedSecret, 16))(Name::FeedbackSize(), 1));
m_ServerEncryptor.SetKey(SharedSecret, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(SharedSecret, 16, true))(Name::FeedbackSize(), 1));
m_ServerDecryptor.SetKey(SharedSecret, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(SharedSecret, 16, true))(Name::FeedbackSize(), 1));
// Encrypt the nonce:
byte EncryptedNonce[128];

View File

@ -95,6 +95,7 @@ typedef unsigned short UInt16;
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
// Windows SDK defines min and max macros, messing up with our std::min and std::max usage
#undef min
@ -104,6 +105,8 @@ typedef unsigned short UInt16;
#ifdef GetFreeSpace
#undef GetFreeSpace
#endif // GetFreeSpace
#define SocketError WSAGetLastError()
#else
#include <sys/types.h>
#include <sys/stat.h> // for mkdir
@ -116,6 +119,7 @@ typedef unsigned short UInt16;
#include <dirent.h>
#include <errno.h>
#include <iostream>
#include <unistd.h>
#include <cstdio>
#include <cstring>
@ -123,6 +127,14 @@ typedef unsigned short UInt16;
#include <semaphore.h>
#include <errno.h>
#include <fcntl.h>
typedef int SOCKET;
enum
{
INVALID_SOCKET = -1,
};
#define closesocket close
#define SocketError errno
#if !defined(ANDROID_NDK)
#include <tr1/memory>
#endif
@ -211,10 +223,10 @@ public:
#include "CryptoPP/randpool.h"
#include "CryptoPP/aes.h"
#include "CryptoPP/rsa.h"
#include "CryptoPP/modes.h"
#include "cryptopp/randpool.h"
#include "cryptopp/aes.h"
#include "cryptopp/rsa.h"
#include "cryptopp/modes.h"
using namespace CryptoPP;

View File

@ -22,13 +22,16 @@ cServer::cServer(void)
int cServer::Init(short a_ListenPort, short a_ConnectPort)
{
m_ConnectPort = a_ConnectPort;
WSAData wsa;
int res = WSAStartup(0x0202, &wsa);
if (res != 0)
{
printf("Cannot initialize WinSock: %d\n", res);
return res;
}
#ifdef _WIN32
WSAData wsa;
int res = WSAStartup(0x0202, &wsa);
if (res != 0)
{
printf("Cannot initialize WinSock: %d\n", res);
return res;
}
#endif // _WIN32
printf("Generating protocol encryption keypair...\n");
time_t CurTime = time(NULL);
@ -62,12 +65,12 @@ void cServer::Run(void)
while (true)
{
sockaddr_in Addr;
ZeroMemory(&Addr, sizeof(Addr));
int AddrSize = sizeof(Addr);
memset(&Addr, 0, sizeof(Addr));
socklen_t AddrSize = sizeof(Addr);
SOCKET client = accept(m_ListenSocket, (sockaddr *)&Addr, &AddrSize);
if (client == INVALID_SOCKET)
{
printf("accept returned an error: %d; bailing out.\n", WSAGetLastError());
printf("accept returned an error: %d; bailing out.\n", SocketError);
return;
}
printf("Client connected, proxying...\n");

View File

@ -2910,6 +2910,14 @@
RelativePath="..\src\BlockEntities\ChestEntity.h"
>
</File>
<File
RelativePath="..\src\BlockEntities\CommandBlockEntity.cpp"
>
</File>
<File
RelativePath="..\src\BlockEntities\CommandBlockEntity.h"
>
</File>
<File
RelativePath="..\src\BlockEntities\DispenserEntity.cpp"
>

View File

@ -1,5 +1,5 @@
cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.8.2)
project (lua)
include_directories ("${PROJECT_SOURCE_DIR}/../../src/")
@ -25,7 +25,15 @@ if (WIN32)
# Output the executable into the $/MCServer folder, so that MCServer can find it:
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/MCServer)
SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES
SET_TARGET_PROPERTIES(lua PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/MCServer
ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/MCServer
ARCHIVE_OUTPUT_DIRECTORY_DEBUGPROFILE ${CMAKE_SOURCE_DIR}/MCServer
ARCHIVE_OUTPUT_DIRECTORY_RELEASEPROFILE ${CMAKE_SOURCE_DIR}/MCServer
LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/MCServer
LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/MCServer
LIBRARY_OUTPUT_DIRECTORY_DEBUGPROFILE ${CMAKE_SOURCE_DIR}/MCServer
LIBRARY_OUTPUT_DIRECTORY_RELEASEPROFILE ${CMAKE_SOURCE_DIR}/MCServer
RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/MCServer
RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/MCServer
RUNTIME_OUTPUT_DIRECTORY_DEBUGPROFILE ${CMAKE_SOURCE_DIR}/MCServer
@ -38,6 +46,9 @@ if (WIN32)
lua PROPERTIES COMPILE_FLAGS "-D_CRT_SECURE_NO_WARNINGS"
)
endif()
# NOTE: The DLL for each configuration is stored at the same place, thus overwriting each other.
# This is known, however such behavior is needed for LuaRocks - they always load "lua.dll"
else()
add_library(lua ${SOURCE})
endif()

View File

@ -31,6 +31,7 @@ $cfile "../Defines.h"
$cfile "../ChatColor.h"
$cfile "../ClientHandle.h"
$cfile "../Entities/Entity.h"
$cfile "../Entities/Floater.h"
$cfile "../Entities/Pawn.h"
$cfile "../Entities/Player.h"
$cfile "../Entities/Pickup.h"

View File

@ -14,6 +14,7 @@
#include "../WebAdmin.h"
#include "../ClientHandle.h"
#include "../BlockEntities/ChestEntity.h"
#include "../BlockEntities/CommandBlockEntity.h"
#include "../BlockEntities/DispenserEntity.h"
#include "../BlockEntities/DropperEntity.h"
#include "../BlockEntities/FurnaceEntity.h"
@ -2265,16 +2266,17 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cWorld");
tolua_function(tolua_S, "DoWithBlockEntityAt", tolua_DoWithXYZ<cWorld, cBlockEntity, &cWorld::DoWithBlockEntityAt>);
tolua_function(tolua_S, "DoWithChestAt", tolua_DoWithXYZ<cWorld, cChestEntity, &cWorld::DoWithChestAt>);
tolua_function(tolua_S, "DoWithDispenserAt", tolua_DoWithXYZ<cWorld, cDispenserEntity, &cWorld::DoWithDispenserAt>);
tolua_function(tolua_S, "DoWithDropSpenserAt", tolua_DoWithXYZ<cWorld, cDropSpenserEntity, &cWorld::DoWithDropSpenserAt>);
tolua_function(tolua_S, "DoWithDropperAt", tolua_DoWithXYZ<cWorld, cDropperEntity, &cWorld::DoWithDropperAt>);
tolua_function(tolua_S, "DoWithEntityByID", tolua_DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>);
tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>);
tolua_function(tolua_S, "DoWithNoteBlockAt", tolua_DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>);
tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>);
tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>);
tolua_function(tolua_S, "DoWithBlockEntityAt", tolua_DoWithXYZ<cWorld, cBlockEntity, &cWorld::DoWithBlockEntityAt>);
tolua_function(tolua_S, "DoWithChestAt", tolua_DoWithXYZ<cWorld, cChestEntity, &cWorld::DoWithChestAt>);
tolua_function(tolua_S, "DoWithDispenserAt", tolua_DoWithXYZ<cWorld, cDispenserEntity, &cWorld::DoWithDispenserAt>);
tolua_function(tolua_S, "DoWithDropSpenserAt", tolua_DoWithXYZ<cWorld, cDropSpenserEntity, &cWorld::DoWithDropSpenserAt>);
tolua_function(tolua_S, "DoWithDropperAt", tolua_DoWithXYZ<cWorld, cDropperEntity, &cWorld::DoWithDropperAt>);
tolua_function(tolua_S, "DoWithEntityByID", tolua_DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>);
tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>);
tolua_function(tolua_S, "DoWithNoteBlockAt", tolua_DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>);
tolua_function(tolua_S, "DoWithCommandBlockAt", tolua_DoWithXYZ<cWorld, cCommandBlockEntity, &cWorld::DoWithCommandBlockAt>);
tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>);
tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>);
tolua_function(tolua_S, "ForEachBlockEntityInChunk", tolua_ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>);
tolua_function(tolua_S, "ForEachChestInChunk", tolua_ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>);
tolua_function(tolua_S, "ForEachEntity", tolua_ForEach< cWorld, cEntity, &cWorld::ForEachEntity>);

View File

@ -6,6 +6,7 @@
#include "Globals.h"
#include "BlockEntity.h"
#include "ChestEntity.h"
#include "CommandBlockEntity.h"
#include "DispenserEntity.h"
#include "DropperEntity.h"
#include "EnderChestEntity.h"
@ -23,17 +24,18 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
{
switch (a_BlockType)
{
case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_WALLSIGN: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_NOTE_BLOCK: return new cNoteEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_COMMAND_BLOCK: return new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_WALLSIGN: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_NOTE_BLOCK: return new cNoteEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
}
LOGD("%s: Requesting creation of an unknown block entity - block type %d (%s)",
__FUNCTION__, a_BlockType, ItemTypeToString(a_BlockType).c_str()

View File

@ -0,0 +1,197 @@
// CommandBlockEntity.cpp
// Implements the cCommandBlockEntity class representing a single command block in the world
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "json/json.h"
#include "CommandBlockEntity.h"
#include "../Entities/Player.h"
#include "../CommandOutput.h"
#include "../Root.h"
#include "../Server.h" // ExecuteConsoleCommand()
cCommandBlockEntity::cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World) :
super(E_BLOCK_COMMAND_BLOCK, a_X, a_Y, a_Z, a_World),
m_ShouldExecute(false),
m_IsPowered(false)
{}
void cCommandBlockEntity::UsedBy(cPlayer * a_Player)
{
// Nothing to do
UNUSED(a_Player);
}
void cCommandBlockEntity::SetCommand(const AString & a_Cmd)
{
m_Command = a_Cmd;
}
void cCommandBlockEntity::SetLastOutput(const AString & a_LastOut)
{
m_LastOutput = a_LastOut;
}
void cCommandBlockEntity::SetResult(const NIBBLETYPE a_Result)
{
m_Result = a_Result;
}
const AString & cCommandBlockEntity::GetCommand(void) const
{
return m_Command;
}
const AString & cCommandBlockEntity::GetLastOutput(void) const
{
return m_LastOutput;
}
NIBBLETYPE cCommandBlockEntity::GetResult(void) const
{
return m_Result;
}
void cCommandBlockEntity::Activate(void)
{
m_ShouldExecute = true;
}
void cCommandBlockEntity::SetRedstonePower(bool a_IsPowered)
{
if (a_IsPowered && !m_IsPowered)
{
Activate();
}
m_IsPowered = a_IsPowered;
}
bool cCommandBlockEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
if (!m_ShouldExecute)
{
return false;
}
m_ShouldExecute = false;
Execute();
return true;
}
void cCommandBlockEntity::SendTo(cClientHandle & a_Client)
{
// Nothing needs to be sent
UNUSED(a_Client);
}
bool cCommandBlockEntity::LoadFromJson(const Json::Value & a_Value)
{
m_Command = a_Value.get("Command", "").asString();
m_LastOutput = a_Value.get("LastOutput", "").asString();
return true;
}
void cCommandBlockEntity::SaveToJson(Json::Value & a_Value)
{
a_Value["Command"] = m_Command;
a_Value["LastOutput"] = m_LastOutput;
}
void cCommandBlockEntity::Execute()
{
class CommandBlockOutCb :
public cCommandOutputCallback
{
cCommandBlockEntity* m_CmdBlock;
public:
CommandBlockOutCb(cCommandBlockEntity* a_CmdBlock) : m_CmdBlock(a_CmdBlock) {}
virtual void Out(const AString & a_Text)
{
ASSERT(m_CmdBlock != NULL);
// Overwrite field
m_CmdBlock->SetLastOutput(a_Text);
}
} CmdBlockOutCb(this);
LOGD("cCommandBlockEntity: Executing command %s", m_Command.c_str());
cServer* Server = cRoot::Get()->GetServer();
Server->ExecuteConsoleCommand(m_Command, CmdBlockOutCb);
// TODO 2014-01-18 xdot: Update the signal strength.
m_Result = 0;
}

View File

@ -0,0 +1,91 @@
// CommandBlockEntity.h
// Declares the cCommandBlockEntity class representing a single command block in the world
#pragma once
#include "BlockEntity.h"
namespace Json
{
class Value;
}
// tolua_begin
class cCommandBlockEntity :
public cBlockEntity
{
typedef cBlockEntity super;
public:
// tolua_end
/// Creates a new empty command block entity
cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World);
bool LoadFromJson( const Json::Value& a_Value );
virtual void SaveToJson(Json::Value& a_Value ) override;
virtual bool Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void SendTo(cClientHandle & a_Client) override;
virtual void UsedBy(cPlayer * a_Player) override;
void SetLastOutput(const AString & a_LastOut);
void SetResult(const NIBBLETYPE a_Result);
// tolua_begin
/// Sets the internal redstone power flag to "on" or "off", depending on the parameter. Calls Activate() if appropriate
void SetRedstonePower(bool a_IsPowered);
/// Sets the command block to execute a command in the next tick
void Activate(void);
/// Sets the command
void SetCommand(const AString & a_Cmd);
/// Retrieves stored command
const AString & GetCommand(void) const;
/// Retrieves the last line of output generated by the command block
const AString & GetLastOutput(void) const;
/// Retrieves the result (signal strength) of the last operation
NIBBLETYPE GetResult(void) const;
// tolua_end
private:
/// Executes the associated command
void Execute();
bool m_ShouldExecute;
bool m_IsPowered;
AString m_Command;
AString m_LastOutput;
NIBBLETYPE m_Result;
} ; // tolua_export

View File

@ -307,7 +307,7 @@ void cFurnaceEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
/// Updates the current recipe, based on the current input
void cFurnaceEntity::UpdateInput(void)
{
if (!m_Contents.GetSlot(fsInput).IsStackableWith(m_LastInput))
if (!m_Contents.GetSlot(fsInput).IsEqual(m_LastInput))
{
// The input is different from what we had before, reset the cooking time
m_TimeCooked = 0;
@ -417,7 +417,7 @@ bool cFurnaceEntity::CanCookInputToOutput(void) const
return true;
}
if (!m_Contents.GetSlot(fsOutput).IsStackableWith(*m_CurrentRecipe->Out))
if (!m_Contents.GetSlot(fsOutput).IsEqual(*m_CurrentRecipe->Out))
{
// The output slot is blocked with something that cannot be stacked with the recipe's output
return false;

View File

@ -407,7 +407,7 @@ bool cHopperEntity::MoveItemsFromSlot(cBlockEntityWithItems & a_Entity, int a_Sl
m_Contents.SetSlot(i, One);
return true;
}
else if (m_Contents.GetSlot(i).IsStackableWith(One))
else if (m_Contents.GetSlot(i).IsEqual(One))
{
if (cPluginManager::Get()->CallHookHopperPullingItem(*m_World, *this, i, a_Entity, a_SlotNum))
{
@ -544,7 +544,7 @@ bool cHopperEntity::MoveItemsToSlot(cBlockEntityWithItems & a_Entity, int a_DstS
}
for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
{
if (m_Contents.GetSlot(i).IsStackableWith(DestSlot))
if (m_Contents.GetSlot(i).IsEqual(DestSlot))
{
if (cPluginManager::Get()->CallHookHopperPushingItem(*m_World, *this, i, a_Entity, a_DstSlotNum))
{

View File

@ -42,13 +42,13 @@ public:
{
return false;
}
double rot = a_Player->GetRotation();
double yaw = a_Player->GetYaw();
if (
(Area.GetRelBlockType(0, 0, 1) == E_BLOCK_CHEST) ||
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST)
)
{
a_BlockMeta = ((rot >= -90) && (rot < 90)) ? 2 : 3;
a_BlockMeta = ((yaw >= -90) && (yaw < 90)) ? 2 : 3;
return true;
}
if (
@ -56,12 +56,12 @@ public:
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST)
)
{
a_BlockMeta = (rot < 0) ? 4 : 5;
a_BlockMeta = (yaw < 0) ? 4 : 5;
return true;
}
// Single chest, get meta from rotation only
a_BlockMeta = RotationToMetaData(rot);
a_BlockMeta = RotationToMetaData(yaw);
return true;
}
@ -80,7 +80,7 @@ public:
return;
}
double rot = a_Player->GetRotation();
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 (

View File

@ -53,7 +53,7 @@ public:
) override
{
a_BlockType = m_BlockType;
a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation());
a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetYaw());
return true;
}

View File

@ -42,7 +42,7 @@ public:
}
a_BlockType = m_BlockType;
a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation());
a_BlockMeta = PlayerYawToMetaData(a_Player->GetYaw());
return true;
}

View File

@ -31,7 +31,7 @@ public:
a_BlockType = m_BlockType;
// FIXME: Do not use cPiston class for dispenser placement!
a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetRotation(), a_Player->GetPitch());
a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
return true;
}
} ;

View File

@ -30,7 +30,7 @@ public:
) override
{
a_BlockType = m_BlockType;
a_BlockMeta = RotationToMetaData(a_Player->GetRotation());
a_BlockMeta = RotationToMetaData(a_Player->GetYaw());
return true;
}

View File

@ -25,7 +25,7 @@ public:
) override
{
a_BlockType = m_BlockType;
a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation());
a_BlockMeta = PlayerYawToMetaData(a_Player->GetYaw());
return true;
}
@ -33,7 +33,7 @@ public:
virtual void OnUse(cWorld * a_World, 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
{
NIBBLETYPE OldMetaData = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
NIBBLETYPE NewMetaData = PlayerYawToMetaData(a_Player->GetRotation());
NIBBLETYPE NewMetaData = PlayerYawToMetaData(a_Player->GetYaw());
OldMetaData ^= 4; // Toggle the gate
if ((OldMetaData & 1) == (NewMetaData & 1))
{

View File

@ -35,7 +35,7 @@ public:
a_BlockType = m_BlockType;
// FIXME: Do not use cPiston class for furnace placement!
a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetRotation(), 0);
a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), 0);
return true;
}

View File

@ -60,7 +60,7 @@ bool cBlockPistonHandler::GetPlacementBlockTypeMeta(
)
{
a_BlockType = m_BlockType;
a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetRotation(), a_Player->GetPitch());
a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
return true;
}

View File

@ -86,7 +86,7 @@ public:
) override
{
a_BlockType = m_BlockType;
a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation());
a_BlockMeta = PlayerYawToMetaData(a_Player->GetYaw());
return true;
}

View File

@ -25,7 +25,7 @@ public:
) override
{
a_BlockType = m_BlockType;
a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetRotation());
a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetYaw());
return true;
}

View File

@ -26,7 +26,7 @@ public:
) override
{
a_BlockType = m_BlockType;
a_BlockMeta = RotationToMetaData(a_Player->GetRotation());
a_BlockMeta = RotationToMetaData(a_Player->GetYaw());
switch (a_BlockFace)
{
case BLOCK_FACE_TOP: break;

View File

@ -2,10 +2,6 @@
cmake_minimum_required (VERSION 2.8.2)
project (MCServer)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03")
endif()
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/")
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/jsoncpp/include")

View File

@ -1298,6 +1298,7 @@ void cChunk::CreateBlockEntities(void)
switch (BlockType)
{
case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DISPENSER:
case E_BLOCK_DROPPER:
case E_BLOCK_ENDER_CHEST:
@ -1425,6 +1426,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
switch (a_BlockType)
{
case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DISPENSER:
case E_BLOCK_DROPPER:
case E_BLOCK_ENDER_CHEST:
@ -2268,6 +2270,38 @@ bool cChunk::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBl
bool cChunk::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback)
{
// The blockentity list is locked by the parent chunkmap's CS
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2)
{
++itr2;
if (((*itr)->GetPosX() != a_BlockX) || ((*itr)->GetPosY() != a_BlockY) || ((*itr)->GetPosZ() != a_BlockZ))
{
continue;
}
if ((*itr)->GetBlockType() != E_BLOCK_COMMAND_BLOCK)
{
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false;
}
// The correct block entity is here,
if (a_Callback.Item((cCommandBlockEntity *)*itr))
{
return false;
}
return true;
} // for itr - m_BlockEntitites[]
// Not found:
return false;
}
bool cChunk::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4)
{
// The blockentity list is locked by the parent chunkmap's CS

View File

@ -40,12 +40,13 @@ class cFluidSimulatorData;
class cMobCensus;
class cMobSpawner;
typedef std::list<cClientHandle *> cClientHandleList;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef std::list<cClientHandle *> cClientHandleList;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
@ -237,6 +238,9 @@ public:
/// Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found
bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback);
/// Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found
bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback);
/// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible

View File

@ -1968,6 +1968,23 @@ bool cChunkMap::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNot
bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback)
{
int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
{
return false;
}
return Chunk->DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
}
bool cChunkMap::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4)
{

View File

@ -23,6 +23,7 @@ class cDropperEntity;
class cDropSpenserEntity;
class cFurnaceEntity;
class cNoteEntity;
class cCommandBlockEntity;
class cPawn;
class cPickup;
class cChunkDataSerializer;
@ -32,15 +33,16 @@ class cMobSpawner;
typedef std::list<cClientHandle *> cClientHandleList;
typedef cChunk * cChunkPtr;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cBlockEntity> cBlockEntityCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cDropperEntity> cDropperCallback;
typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cChunk> cChunkCallback;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cBlockEntity> cBlockEntityCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cDropperEntity> cDropperCallback;
typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
typedef cItemCallback<cChunk> cChunkCallback;
@ -236,6 +238,9 @@ public:
/// Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found
bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); // Lua-accessible
/// Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found
bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Lua-accessible
/// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible

View File

@ -8,6 +8,7 @@
#include "Entities/Player.h"
#include "Inventory.h"
#include "BlockEntities/ChestEntity.h"
#include "BlockEntities/CommandBlockEntity.h"
#include "BlockEntities/SignEntity.h"
#include "UI/Window.h"
#include "Item.h"
@ -545,6 +546,15 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ,
void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString & a_Message)
{
if (a_Channel == "MC|AdvCdm") // Command block
{
const char* Data = a_Message.c_str();
HandleCommandBlockMessage(Data, a_Message.size());
return;
}
cPluginManager::Get()->CallHookPluginMessage(*this, a_Channel, a_Message);
}
@ -552,6 +562,67 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString
void cClientHandle::HandleCommandBlockMessage(const char* a_Data, unsigned int a_Length)
{
if (a_Length < 14)
{
LOGD("Malformed MC|AdvCdm packet.");
return;
}
cByteBuffer Buffer(a_Length);
Buffer.Write(a_Data, a_Length);
int BlockX, BlockY, BlockZ;
AString Command;
char Mode;
Buffer.ReadChar(Mode);
switch (Mode)
{
case 0x00:
{
Buffer.ReadBEInt(BlockX);
Buffer.ReadBEInt(BlockY);
Buffer.ReadBEInt(BlockZ);
Buffer.ReadVarUTF8String(Command);
break;
}
default:
{
LOGD("Unhandled MC|AdvCdm packet mode.");
return;
}
}
class cUpdateCommandBlock :
public cCommandBlockCallback
{
AString m_Command;
public:
cUpdateCommandBlock(const AString & a_Command) : m_Command(a_Command) {}
virtual bool Item(cCommandBlockEntity * a_CommandBlock) override
{
a_CommandBlock->SetCommand(m_Command);
return false;
}
} CmdBlockCB (Command);
cWorld * World = m_Player->GetWorld();
World->DoWithCommandBlockAt(BlockX, BlockY, BlockZ, CmdBlockCB);
}
void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status)
{
LOGD("HandleLeftClick: {%i, %i, %i}; Face: %i; Stat: %i",
@ -629,6 +700,17 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, ch
return;
}
case DIG_STATUS_DROP_STACK:
{
if (PlgMgr->CallHookPlayerTossingItem(*m_Player))
{
// A plugin doesn't agree with the tossing. The plugin itself is responsible for handling the consequences (possible inventory mismatch)
return;
}
m_Player->TossItem(false, 64); // Toss entire slot - if there aren't enough items, the maximum will be ejected
return;
}
default:
{
ASSERT(!"Unhandled DIG_STATUS");
@ -1026,7 +1108,7 @@ void cClientHandle::HandlePlayerLook(float a_Rotation, float a_Pitch, bool a_IsO
return;
}
m_Player->SetRotation (a_Rotation);
m_Player->SetYaw (a_Rotation);
m_Player->SetHeadYaw (a_Rotation);
m_Player->SetPitch (a_Pitch);
m_Player->SetTouchGround(a_IsOnGround);
@ -1058,7 +1140,7 @@ void cClientHandle::HandlePlayerMoveLook(double a_PosX, double a_PosY, double a_
m_Player->SetStance (a_Stance);
m_Player->SetTouchGround(a_IsOnGround);
m_Player->SetHeadYaw (a_Rotation);
m_Player->SetRotation (a_Rotation);
m_Player->SetYaw (a_Rotation);
m_Player->SetPitch (a_Pitch);
}

View File

@ -324,6 +324,9 @@ private:
/// Handles the DIG_FINISHED dig packet:
void HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_OldBlock, NIBBLETYPE a_OldMeta);
/// Handles the "MC|AdvCdm" plugin message
void HandleCommandBlockMessage(const char* a_Data, unsigned int a_Length);
// cSocketThreads::cCallback overrides:
virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client

View File

@ -85,6 +85,7 @@ enum
DIG_STATUS_STARTED = 0,
DIG_STATUS_CANCELLED = 1,
DIG_STATUS_FINISHED = 2,
DIG_STATUS_DROP_STACK= 3,
DIG_STATUS_DROP_HELD = 4,
DIG_STATUS_SHOOT_EAT = 5,
} ;

View File

@ -263,16 +263,16 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R
void cEntity::SetRotationFromSpeed(void)
void cEntity::SetYawFromSpeed(void)
{
const double EPS = 0.0000001;
if ((abs(m_Speed.x) < EPS) && (abs(m_Speed.z) < EPS))
{
// atan2() may overflow or is undefined, pick any number
SetRotation(0);
SetYaw(0);
return;
}
SetRotation(atan2(m_Speed.x, m_Speed.z) * 180 / PI);
SetYaw(atan2(m_Speed.x, m_Speed.z) * 180 / PI);
}

View File

@ -154,8 +154,7 @@ public:
double GetPosX (void) const { return m_Pos.x; }
double GetPosY (void) const { return m_Pos.y; }
double GetPosZ (void) const { return m_Pos.z; }
const Vector3d & GetRot (void) const { return m_Rot; }
double GetRotation (void) const { return m_Rot.x; } // OBSOLETE, use GetYaw() instead
const Vector3d & GetRot (void) const { return m_Rot; } // OBSOLETE, use individual GetYaw(), GetPitch, GetRoll() components
double GetYaw (void) const { return m_Rot.x; }
double GetPitch (void) const { return m_Rot.y; }
double GetRoll (void) const { return m_Rot.z; }
@ -177,8 +176,7 @@ public:
void SetPosZ (double a_PosZ);
void SetPosition(double a_PosX, double a_PosY, double a_PosZ);
void SetPosition(const Vector3d & a_Pos) { SetPosition(a_Pos.x, a_Pos.y, a_Pos.z); }
void SetRot (const Vector3f & a_Rot);
void SetRotation(double a_Rotation) { SetYaw(a_Rotation); } // OBSOLETE, use SetYaw() instead
void SetRot (const Vector3f & a_Rot); // OBSOLETE, use individual SetYaw(), SetPitch(), SetRoll() components
void SetYaw (double a_Yaw);
void SetPitch (double a_Pitch);
void SetRoll (double a_Roll);
@ -223,7 +221,7 @@ public:
void SetGravity(float a_Gravity) { m_Gravity = a_Gravity; }
/// Sets the rotation to match the speed vector (entity goes "face-forward")
void SetRotationFromSpeed(void);
void SetYawFromSpeed(void);
/// Sets the pitch to match the speed vector (entity gies "face-forward")
void SetPitchFromSpeed(void);

View File

@ -7,21 +7,25 @@
// tolua_begin
class cFloater :
public cEntity
{
typedef cFloater super;
public:
//tolua_end
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;
// tolua_begin
bool CanPickup(void) const { return m_CanPickupItem; }
int GetOwnerID(void) const { return m_PlayerID; }
int GetAttachedMobID(void) const { return m_AttachedMobID; }
// tolua_end
protected:
// Position
@ -37,4 +41,4 @@ protected:
// Entity IDs
int m_PlayerID;
int m_AttachedMobID;
} ;
} ; // tolua_export

View File

@ -118,6 +118,7 @@ void cMinecart::SpawnOn(cClientHandle & a_ClientHandle)
}
}
a_ClientHandle.SendSpawnVehicle(*this, 10, SubType); // 10 = Minecarts, SubType = What type of Minecart
a_ClientHandle.SendEntityMetadata(*this);
}
@ -212,7 +213,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
{
case E_META_RAIL_ZM_ZP: // NORTHSOUTH
{
SetRotation(270);
SetYaw(270);
SetPosY(floor(GetPosY()) + 0.55);
SetSpeedY(0); // Don't move vertically as on ground
SetSpeedX(0); // Correct diagonal movement from curved rails
@ -238,7 +239,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_XM_XP: // EASTWEST
{
SetRotation(180);
SetYaw(180);
SetPosY(floor(GetPosY()) + 0.55);
SetSpeedY(0);
SetSpeedZ(0);
@ -261,7 +262,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_ASCEND_ZM: // ASCEND NORTH
{
SetRotation(270);
SetYaw(270);
SetSpeedX(0);
if (GetSpeedZ() >= 0)
@ -283,7 +284,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_ASCEND_ZP: // ASCEND SOUTH
{
SetRotation(270);
SetYaw(270);
SetSpeedX(0);
if (GetSpeedZ() > 0)
@ -305,7 +306,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_ASCEND_XM: // ASCEND EAST
{
SetRotation(180);
SetYaw(180);
SetSpeedZ(0);
if (GetSpeedX() >= 0)
@ -325,7 +326,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_ASCEND_XP: // ASCEND WEST
{
SetRotation(180);
SetYaw(180);
SetSpeedZ(0);
if (GetSpeedX() > 0)
@ -345,7 +346,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_CURVED_ZM_XM: // Ends pointing NORTH and WEST
{
SetRotation(315); // Set correct rotation server side
SetYaw(315); // Set correct rotation server side
SetPosY(floor(GetPosY()) + 0.55); // Levitate dat cart
TestBlockCollision(a_RailMeta);
@ -357,7 +358,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_CURVED_ZM_XP: // Curved NORTH EAST
{
SetRotation(225);
SetYaw(225);
SetPosY(floor(GetPosY()) + 0.55);
TestBlockCollision(a_RailMeta);
@ -367,7 +368,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_CURVED_ZP_XM: // Curved SOUTH WEST
{
SetRotation(135);
SetYaw(135);
SetPosY(floor(GetPosY()) + 0.55);
TestBlockCollision(a_RailMeta);
@ -377,7 +378,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
case E_META_RAIL_CURVED_ZP_XP: // Curved SOUTH EAST
{
SetRotation(45);
SetYaw(45);
SetPosY(floor(GetPosY()) + 0.55);
TestBlockCollision(a_RailMeta);
@ -413,7 +414,7 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta)
{
case E_META_RAIL_ZM_ZP: // NORTHSOUTH
{
SetRotation(270);
SetYaw(270);
SetPosY(floor(GetPosY()) + 0.55);
SetSpeedY(0);
SetSpeedX(0);
@ -435,7 +436,7 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta)
}
case E_META_RAIL_XM_XP: // EASTWEST
{
SetRotation(180);
SetYaw(180);
SetPosY(floor(GetPosY()) + 0.55);
SetSpeedY(0);
SetSpeedZ(0);
@ -841,10 +842,12 @@ void cMinecart::Destroyed()
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cEmptyMinecart:
// cRideableMinecart:
cEmptyMinecart::cEmptyMinecart(double a_X, double a_Y, double a_Z) :
super(mpNone, a_X, a_Y, a_Z)
cRideableMinecart::cRideableMinecart(double a_X, double a_Y, double a_Z, const cItem & a_Content, int a_Height) :
super(mpNone, a_X, a_Y, a_Z),
m_Content(a_Content),
m_Height(a_Height)
{
}
@ -852,7 +855,7 @@ cEmptyMinecart::cEmptyMinecart(double a_X, double a_Y, double a_Z) :
void cEmptyMinecart::OnRightClicked(cPlayer & a_Player)
void cRideableMinecart::OnRightClicked(cPlayer & a_Player)
{
if (m_Attachee != NULL)
{

View File

@ -93,18 +93,24 @@ protected:
class cEmptyMinecart :
class cRideableMinecart :
public cMinecart
{
typedef cMinecart super;
public:
CLASS_PROTODEF(cEmptyMinecart);
CLASS_PROTODEF(cRideableMinecart);
cEmptyMinecart(double a_X, double a_Y, double a_Z);
cRideableMinecart(double a_X, double a_Y, double a_Z, const cItem & a_Content, int a_Height);
const cItem & GetContent(void) const {return m_Content;}
int GetBlockHeight(void) const {return m_Height;}
// cEntity overrides:
virtual void OnRightClicked(cPlayer & a_Player) override;
protected:
cItem m_Content;
int m_Height;
} ;

View File

@ -1382,16 +1382,21 @@ void cPlayer::TossItem(
cItem DroppedItem(GetInventory().GetEquippedItem());
if (!DroppedItem.IsEmpty())
{
if (GetInventory().RemoveOneEquippedItem())
char NewAmount = a_Amount;
if (NewAmount > GetInventory().GetEquippedItem().m_ItemCount)
{
DroppedItem.m_ItemCount = 1; // RemoveItem decreases the count, so set it to 1 again
Drops.push_back(DroppedItem);
NewAmount = GetInventory().GetEquippedItem().m_ItemCount; // Drop only what's there
}
GetInventory().GetHotbarGrid().ChangeSlotCount(GetInventory().GetEquippedSlotNum() /* Returns hotbar subslot, which HotbarGrid takes */, -a_Amount);
DroppedItem.m_ItemCount = NewAmount;
Drops.push_back(DroppedItem);
}
}
}
double vX = 0, vY = 0, vZ = 0;
EulerToVector(-GetRotation(), GetPitch(), vZ, vX, vY);
EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY);
vY = -vY * 2 + 1.f;
m_World->SpawnItemPickups(Drops, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player
}
@ -1523,7 +1528,7 @@ bool cPlayer::LoadFromDisk()
Json::Value & JSON_PlayerRotation = root["rotation"];
if (JSON_PlayerRotation.size() == 3)
{
SetRotation ((float)JSON_PlayerRotation[(unsigned int)0].asDouble());
SetYaw ((float)JSON_PlayerRotation[(unsigned int)0].asDouble());
SetPitch ((float)JSON_PlayerRotation[(unsigned int)1].asDouble());
SetRoll ((float)JSON_PlayerRotation[(unsigned int)2].asDouble());
}
@ -1586,7 +1591,7 @@ bool cPlayer::SaveToDisk()
JSON_PlayerPosition.append(Json::Value(GetPosZ()));
Json::Value JSON_PlayerRotation;
JSON_PlayerRotation.append(Json::Value(GetRotation()));
JSON_PlayerRotation.append(Json::Value(GetYaw()));
JSON_PlayerRotation.append(Json::Value(GetPitch()));
JSON_PlayerRotation.append(Json::Value(GetRoll()));

View File

@ -206,7 +206,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve
m_IsInGround(false)
{
SetSpeed(a_Speed);
SetRotationFromSpeed();
SetYawFromSpeed();
SetPitchFromSpeed();
}
@ -350,7 +350,7 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
NewSpeed.y += m_Gravity / 20;
NewSpeed *= TracerCallback.GetSlowdownCoeff();
SetSpeed(NewSpeed);
SetRotationFromSpeed();
SetYawFromSpeed();
SetPitchFromSpeed();
// DEBUG:
@ -358,7 +358,7 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
m_UniqueID,
GetPosX(), GetPosY(), GetPosZ(),
GetSpeedX(), GetSpeedY(), GetSpeedZ(),
GetRotation(), GetPitch()
GetYaw(), GetPitch()
);
}
@ -369,7 +369,7 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
void cProjectileEntity::SpawnOn(cClientHandle & a_Client)
{
// Default spawning - use the projectile kind to spawn an object:
a_Client.SendSpawnObject(*this, m_ProjectileKind, 12, ANGLE_TO_PROTO(GetRotation()), ANGLE_TO_PROTO(GetPitch()));
a_Client.SendSpawnObject(*this, m_ProjectileKind, 12, ANGLE_TO_PROTO(GetYaw()), ANGLE_TO_PROTO(GetPitch()));
a_Client.SendEntityMetadata(*this);
}
@ -402,11 +402,11 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a
{
SetSpeed(a_Speed);
SetMass(0.1);
SetRotationFromSpeed();
SetYawFromSpeed();
SetPitchFromSpeed();
LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}",
m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(),
GetRotation(), GetPitch()
GetYaw(), GetPitch()
);
}

View File

@ -367,10 +367,10 @@ void cComposableGenerator::InitStructureGens(cIniFile & a_IniFile)
void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{
int Seed = m_ChunkGenerator.GetSeed();
AString Structures = a_IniFile.GetValueSet("Generator", "Finishers", "SprinkleFoliage,Ice,Snow,Lilypads,BottomLava,DeadBushes,PreSimulator");
eDimension Dimension = StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld"));
AStringVector Str = StringSplitAndTrim(Structures, ",");
AString Finishers = a_IniFile.GetValueSet("Generator", "Finishers", "SprinkleFoliage,Ice,Snow,Lilypads,BottomLava,DeadBushes,PreSimulator");
AStringVector Str = StringSplitAndTrim(Finishers, ",");
for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
{
// Finishers, alpha-sorted:
@ -396,6 +396,10 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{
m_FinishGens.push_back(new cFinishGenSingleBiomeSingleTopBlock(Seed, E_BLOCK_LILY_PAD, biSwampland, 4, E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER));
}
else if (NoCaseCompare(*itr, "NetherClumpFoliage") == 0)
{
m_FinishGens.push_back(new cFinishGenNetherClumpFoliage(Seed));
}
else if (NoCaseCompare(*itr, "PreSimulator") == 0)
{
m_FinishGens.push_back(new cFinishGenPreSimulator);

View File

@ -13,6 +13,7 @@
#include "../Noise.h"
#include "../BlockID.h"
#include "../Simulator/FluidSimulator.h" // for cFluidSimulator::CanWashAway()
#include "../Simulator/FireSimulator.h"
#include "../World.h"
@ -39,6 +40,125 @@ static inline bool IsWater(BLOCKTYPE a_BlockType)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cFinishGenNetherClumpFoliage:
void cFinishGenNetherClumpFoliage::GenFinish(cChunkDesc & a_ChunkDesc)
{
double ChunkX = a_ChunkDesc.GetChunkX() + 0.1; // We can't devide through 0 so lets add 0.1 to all the chunk coordinates.
double ChunkZ = a_ChunkDesc.GetChunkZ() + 0.1;
NOISE_DATATYPE Val1 = m_Noise.CubicNoise2D((float) (ChunkX * ChunkZ * 0.01f), (float) (ChunkZ / ChunkX * 0.01f));
NOISE_DATATYPE Val2 = m_Noise.CubicNoise2D((float) (ChunkX / ChunkZ / 0.01f), (float) (ChunkZ * ChunkX / 0.01f));
if (Val1 < 0)
{
Val1 = -Val1;
}
if (Val2 < 0)
{
Val2 = -Val2;
}
int PosX, PosZ;
// Calculate PosX
if (Val1 <= 1)
{
PosX = (int) floor(Val1 * 16);
}
else
{
PosX = (int) floor(16 / Val1);
}
// Calculate PosZ
if (Val2 <= 1)
{
PosZ = (int) floor(Val2 * 16);
}
else
{
PosZ = (int) floor(16 / Val2);
}
for (int y = 1; y < cChunkDef::Height; y++)
{
if (a_ChunkDesc.GetBlockType(PosX, y, PosZ) != E_BLOCK_AIR)
{
continue;
}
if (!g_BlockIsSolid[a_ChunkDesc.GetBlockType(PosX, y - 1, PosZ)]) // Only place on solid blocks
{
continue;
}
NOISE_DATATYPE BlockType = m_Noise.CubicNoise1D((float) (ChunkX * ChunkZ) / (y * 0.1f));
if (BlockType < -0.7)
{
TryPlaceClump(a_ChunkDesc, PosX, y, PosZ, E_BLOCK_BROWN_MUSHROOM);
}
else if (BlockType < 0)
{
TryPlaceClump(a_ChunkDesc, PosX, y, PosZ, E_BLOCK_RED_MUSHROOM);
}
else if (BlockType < 0.7)
{
TryPlaceClump(a_ChunkDesc, PosX, y, PosZ, E_BLOCK_FIRE);
}
}
}
void cFinishGenNetherClumpFoliage::TryPlaceClump(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Block)
{
bool IsFireBlock = a_Block == E_BLOCK_FIRE;
for (int x = a_RelX - 4; x < a_RelX + 4; x++)
{
float xx = (float) a_ChunkDesc.GetChunkX() * cChunkDef::Width + x;
for (int z = a_RelZ - 4; z < a_RelZ + 4; z++)
{
float zz = (float) a_ChunkDesc.GetChunkZ() * cChunkDef::Width + z;
for (int y = a_RelY - 2; y < a_RelY + 2; y++)
{
if (a_ChunkDesc.GetBlockType(x, y, z) != E_BLOCK_AIR) // Don't replace non air blocks.
{
continue;
}
BLOCKTYPE BlockBelow = a_ChunkDesc.GetBlockType(x, y - 1, z);
if (!g_BlockIsSolid[BlockBelow]) // Only place on solid blocks
{
continue;
}
if (IsFireBlock) // don't place fire on non-forever burning blocks.
{
if (!cFireSimulator::DoesBurnForever(BlockBelow))
{
continue;
}
}
NOISE_DATATYPE Val = m_Noise.CubicNoise2D(xx, zz);
if (Val < -0.70)
{
a_ChunkDesc.SetBlockType(x, y, z, a_Block);
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cFinishGenSprinkleFoliage:

View File

@ -47,6 +47,28 @@ protected:
class cFinishGenNetherClumpFoliage :
public cFinishGen
{
public:
cFinishGenNetherClumpFoliage(int a_Seed) :
m_Noise(a_Seed),
m_Seed(a_Seed)
{
}
protected:
cNoise m_Noise;
int m_Seed;
void TryPlaceClump(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Block);
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
} ;
class cFinishGenSprinkleFoliage :
public cFinishGen
{
@ -117,6 +139,7 @@ public:
{
}
int GetLevel(void) const { return m_Level; }
protected:
int m_Level;

View File

@ -205,6 +205,12 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size)
{
m_State = wcsRecvIdle;
m_HTTPServer.RequestFinished(*this, *m_CurrentRequest);
if (!m_CurrentRequest->DoesAllowKeepAlive())
{
m_State = wcsInvalid;
m_HTTPServer.CloseConnection(*this);
return;
}
delete m_CurrentRequest;
m_CurrentRequest = NULL;
}

View File

@ -41,49 +41,52 @@ public:
cHTTPConnection(cHTTPServer & a_HTTPServer);
virtual ~cHTTPConnection();
/// Sends HTTP status code together with a_Reason (used for HTTP errors)
/** Sends HTTP status code together with a_Reason (used for HTTP errors) */
void SendStatusAndReason(int a_StatusCode, const AString & a_Reason);
/// Sends the "401 unauthorized" reply together with instructions on authorizing, using the specified realm
/** Sends the "401 unauthorized" reply together with instructions on authorizing, using the specified realm */
void SendNeedAuth(const AString & a_Realm);
/// Sends the headers contained in a_Response
/** Sends the headers contained in a_Response */
void Send(const cHTTPResponse & a_Response);
/// Sends the data as the response (may be called multiple times)
/** Sends the data as the response (may be called multiple times) */
void Send(const void * a_Data, int a_Size);
/// Sends the data as the response (may be called multiple times)
/** Sends the data as the response (may be called multiple times) */
void Send(const AString & a_Data) { Send(a_Data.data(), a_Data.size()); }
/// Indicates that the current response is finished, gets ready for receiving another request (HTTP 1.1 keepalive)
/** Indicates that the current response is finished, gets ready for receiving another request (HTTP 1.1 keepalive) */
void FinishResponse(void);
/// Resets the connection for a new request. Depending on the state, this will send an "InternalServerError" status or a "ResponseEnd"
/** Resets the internal connection state for a new request.
Depending on the state, this will send an "InternalServerError" status or a "ResponseEnd" */
void AwaitNextRequest(void);
/// Terminates the connection; finishes any request being currently processed
/** Terminates the connection; finishes any request being currently processed */
void Terminate(void);
protected:
typedef std::map<AString, AString> cNameValueMap;
/// The parent webserver that is to be notified of events on this connection
/** The parent webserver that is to be notified of events on this connection */
cHTTPServer & m_HTTPServer;
/// All the incoming data until the entire request header is parsed
/** All the incoming data until the entire request header is parsed */
AString m_IncomingHeaderData;
/// Status in which the request currently is
/** Status in which the request currently is */
eState m_State;
/// Data that is queued for sending, once the socket becomes writable
/** Data that is queued for sending, once the socket becomes writable */
AString m_OutgoingData;
/// The request being currently received (valid only between having parsed the headers and finishing receiving the body)
/** The request being currently received
Valid only between having parsed the headers and finishing receiving the body. */
cHTTPRequest * m_CurrentRequest;
/// Number of bytes that remain to read for the complete body of the message to be received. Valid only in wcsRecvBody
/** Number of bytes that remain to read for the complete body of the message to be received.
Valid only in wcsRecvBody */
int m_CurrentRequestBodyRemaining;

View File

@ -72,7 +72,8 @@ cHTTPRequest::cHTTPRequest(void) :
m_EnvelopeParser(*this),
m_IsValid(true),
m_UserData(NULL),
m_HasAuth(false)
m_HasAuth(false),
m_AllowKeepAlive(false)
{
}
@ -236,6 +237,10 @@ void cHTTPRequest::OnHeaderLine(const AString & a_Key, const AString & a_Value)
m_HasAuth = true;
}
}
if ((a_Key == "Connection") && (NoCaseCompare(a_Value, "keep-alive") == 0))
{
m_AllowKeepAlive = true;
}
AddHeader(a_Key, a_Value);
}

View File

@ -35,7 +35,7 @@ public:
// Force a virtual destructor in all descendants
virtual ~cHTTPMessage() {};
/// Adds a header into the internal map of headers. Recognizes special headers: Content-Type and Content-Length
/** Adds a header into the internal map of headers. Recognizes special headers: Content-Type and Content-Length */
void AddHeader(const AString & a_Key, const AString & a_Value);
void SetContentType (const AString & a_ContentType) { m_ContentType = a_ContentType; }
@ -51,10 +51,10 @@ protected:
cNameValueMap m_Headers;
/// Type of the content; parsed by AddHeader(), set directly by SetContentLength()
/** Type of the content; parsed by AddHeader(), set directly by SetContentLength() */
AString m_ContentType;
/// Length of the content that is to be received. -1 when the object is created, parsed by AddHeader() or set directly by SetContentLength()
/** Length of the content that is to be received. -1 when the object is created, parsed by AddHeader() or set directly by SetContentLength() */
int m_ContentLength;
} ;
@ -76,64 +76,71 @@ public:
*/
int ParseHeaders(const char * a_Data, int a_Size);
/// Returns true if the request did contain a Content-Length header
/** Returns true if the request did contain a Content-Length header */
bool HasReceivedContentLength(void) const { return (m_ContentLength >= 0); }
/// Returns the method used in the request
/** Returns the method used in the request */
const AString & GetMethod(void) const { return m_Method; }
/// Returns the URL used in the request
/** Returns the URL used in the request */
const AString & GetURL(void) const { return m_URL; }
/// Returns the URL used in the request, without any parameters
/** Returns the URL used in the request, without any parameters */
AString GetBareURL(void) const;
/// Sets the UserData pointer that is stored within this request. The request doesn't touch this data (doesn't delete it)!
/** Sets the UserData pointer that is stored within this request.
The request doesn't touch this data (doesn't delete it)! */
void SetUserData(void * a_UserData) { m_UserData = a_UserData; }
/// Retrieves the UserData pointer that has been stored within this request.
/** Retrieves the UserData pointer that has been stored within this request. */
void * GetUserData(void) const { return m_UserData; }
/// Returns true if more data is expected for the request headers
/** Returns true if more data is expected for the request headers */
bool IsInHeaders(void) const { return m_EnvelopeParser.IsInHeaders(); }
/// Returns true if the request did present auth data that was understood by the parser
/** Returns true if the request did present auth data that was understood by the parser */
bool HasAuth(void) const { return m_HasAuth; }
/// Returns the username that the request presented. Only valid if HasAuth() is true
/** Returns the username that the request presented. Only valid if HasAuth() is true */
const AString & GetAuthUsername(void) const { return m_AuthUsername; }
/// Returns the password that the request presented. Only valid if HasAuth() is true
/** Returns the password that the request presented. Only valid if HasAuth() is true */
const AString & GetAuthPassword(void) const { return m_AuthPassword; }
bool DoesAllowKeepAlive(void) const { return m_AllowKeepAlive; }
protected:
/// Parser for the envelope data
/** Parser for the envelope data */
cEnvelopeParser m_EnvelopeParser;
/// True if the data received so far is parsed successfully. When false, all further parsing is skipped
/** True if the data received so far is parsed successfully. When false, all further parsing is skipped */
bool m_IsValid;
/// Bufferred incoming data, while parsing for the request line
/** Bufferred incoming data, while parsing for the request line */
AString m_IncomingHeaderData;
/// Method of the request (GET / PUT / POST / ...)
/** Method of the request (GET / PUT / POST / ...) */
AString m_Method;
/// Full URL of the request
/** Full URL of the request */
AString m_URL;
/// Data that the HTTPServer callbacks are allowed to store.
/** Data that the HTTPServer callbacks are allowed to store. */
void * m_UserData;
/// Set to true if the request contains auth data that was understood by the parser
/** Set to true if the request contains auth data that was understood by the parser */
bool m_HasAuth;
/// The username used for auth
/** The username used for auth */
AString m_AuthUsername;
/// The password used for auth
/** The password used for auth */
AString m_AuthPassword;
/** Set to true if the request indicated that it supports keepalives.
If false, the server will close the connection once the request is finished */
bool m_AllowKeepAlive;
/** Parses the incoming data for the first line (RequestLine)
Returns the number of bytes consumed, or -1 for an error

View File

@ -83,7 +83,7 @@ int cInventory::HowManyCanFit(const cItem & a_ItemStack, int a_BeginSlotNum, int
{
NumLeft -= MaxStack;
}
else if (Slot.IsStackableWith(a_ItemStack))
else if (Slot.IsEqual(a_ItemStack))
{
NumLeft -= MaxStack - Slot.m_ItemCount;
}

View File

@ -91,28 +91,6 @@ bool cItem::DamageItem(short a_Amount)
bool cItem::IsStackableWith(const cItem & a_OtherStack) const
{
if (a_OtherStack.m_ItemType != m_ItemType)
{
return false;
}
if (a_OtherStack.m_ItemDamage != m_ItemDamage)
{
return false;
}
if (a_OtherStack.m_Enchantments != m_Enchantments)
{
return false;
}
return true;
}
bool cItem::IsFullStack(void) const
{
return (m_ItemCount >= ItemHandler(m_ItemType)->GetMaxStackSize());
@ -153,6 +131,14 @@ void cItem::GetJson(Json::Value & a_OutValue) const
{
a_OutValue["ench"] = Enchantments;
}
if (!IsCustomNameEmpty())
{
a_OutValue["Name"] = m_CustomName;
}
if (!IsLoreEmpty())
{
a_OutValue["Lore"] = m_Lore;
}
}
}
@ -169,6 +155,8 @@ void cItem::FromJson(const Json::Value & a_Value)
m_ItemDamage = (short)a_Value.get("Health", -1 ).asInt();
m_Enchantments.Clear();
m_Enchantments.AddFromString(a_Value.get("ench", "").asString());
m_CustomName = a_Value.get("Name", "").asString();
m_Lore = a_Value.get("Lore", "").asString();
}
}

View File

@ -36,7 +36,9 @@ public:
cItem(void) :
m_ItemType(E_ITEM_EMPTY),
m_ItemCount(0),
m_ItemDamage(0)
m_ItemDamage(0),
m_CustomName(""),
m_Lore("")
{
}
@ -46,12 +48,16 @@ public:
short a_ItemType,
char a_ItemCount = 1,
short a_ItemDamage = 0,
const AString & a_Enchantments = ""
const AString & a_Enchantments = "",
const AString & a_CustomName = "",
const AString & a_Lore = ""
) :
m_ItemType (a_ItemType),
m_ItemCount (a_ItemCount),
m_ItemDamage (a_ItemDamage),
m_Enchantments(a_Enchantments)
m_Enchantments(a_Enchantments),
m_CustomName (a_CustomName),
m_Lore (a_Lore)
{
if (!IsValidItem(m_ItemType))
{
@ -69,7 +75,9 @@ public:
m_ItemType (a_CopyFrom.m_ItemType),
m_ItemCount (a_CopyFrom.m_ItemCount),
m_ItemDamage (a_CopyFrom.m_ItemDamage),
m_Enchantments(a_CopyFrom.m_Enchantments)
m_Enchantments(a_CopyFrom.m_Enchantments),
m_CustomName (a_CopyFrom.m_CustomName),
m_Lore (a_CopyFrom.m_Lore)
{
}
@ -80,6 +88,8 @@ public:
m_ItemCount = 0;
m_ItemDamage = 0;
m_Enchantments.Clear();
m_CustomName = "";
m_Lore = "";
}
@ -96,13 +106,16 @@ public:
return ((m_ItemType <= 0) || (m_ItemCount <= 0));
}
/* Returns true if this itemstack can stack with the specified stack (types match, enchantments etc.) ItemCounts are ignored!
*/
bool IsEqual(const cItem & a_Item) const
{
return (
IsSameType(a_Item) &&
(m_ItemDamage == a_Item.m_ItemDamage) &&
(m_Enchantments == a_Item.m_Enchantments)
(m_Enchantments == a_Item.m_Enchantments) &&
(m_CustomName == a_Item.m_CustomName) &&
(m_Lore == a_Item.m_Lore)
);
}
@ -111,7 +124,16 @@ public:
{
return (m_ItemType == a_Item.m_ItemType) || (IsEmpty() && a_Item.IsEmpty());
}
bool IsBothNameAndLoreEmpty(void) const
{
return (m_CustomName.empty() && m_Lore.empty());
}
bool IsCustomNameEmpty(void) const { return (m_CustomName.empty()); }
bool IsLoreEmpty(void) const { return (m_Lore.empty()); }
/// Returns a copy of this item with m_ItemCount set to 1. Useful to preserve enchantments etc. on stacked items
cItem CopyOne(void) const;
@ -127,9 +149,6 @@ public:
inline bool IsDamageable(void) const { return (GetMaxDamage() > 0); }
/// Returns true if this itemstack can stack with the specified stack (types match, enchantments etc.) ItemCounts are ignored!
bool IsStackableWith(const cItem & a_OtherStack) const;
/// Returns true if the item is stacked up to its maximum stacking.
bool IsFullStack(void) const;
@ -155,6 +174,8 @@ public:
short m_ItemType;
char m_ItemCount;
short m_ItemDamage;
AString m_CustomName;
AString m_Lore;
cEnchantments m_Enchantments;
};
// tolua_end

View File

@ -226,7 +226,7 @@ int cItemGrid::HowManyCanFit(const cItem & a_ItemStack, bool a_AllowNewStacks)
NumLeft -= MaxStack;
}
}
else if (m_Slots[i].IsStackableWith(a_ItemStack))
else if (m_Slots[i].IsEqual(a_ItemStack))
{
NumLeft -= MaxStack - m_Slots[i].m_ItemCount;
}
@ -275,7 +275,7 @@ int cItemGrid::AddItem(cItem & a_ItemStack, bool a_AllowNewStacks, int a_Priorit
(a_PrioritarySlot != -1) &&
(
m_Slots[a_PrioritarySlot].IsEmpty() ||
m_Slots[a_PrioritarySlot].IsStackableWith(a_ItemStack)
m_Slots[a_PrioritarySlot].IsEqual(a_ItemStack)
)
)
{
@ -285,7 +285,7 @@ int cItemGrid::AddItem(cItem & a_ItemStack, bool a_AllowNewStacks, int a_Priorit
// Scan existing stacks:
for (int i = m_NumSlots - 1; i >= 0; i--)
{
if (m_Slots[i].IsStackableWith(a_ItemStack))
if (m_Slots[i].IsEqual(a_ItemStack))
{
NumLeft -= AddItemToSlot(a_ItemStack, i, NumLeft, MaxStack);
}
@ -438,7 +438,7 @@ int cItemGrid::HowManyItems(const cItem & a_Item)
int res = 0;
for (int i = 0; i < m_NumSlots; i++)
{
if (m_Slots[i].IsStackableWith(a_Item))
if (m_Slots[i].IsEqual(a_Item))
{
res += m_Slots[i].m_ItemCount;
}

View File

@ -37,7 +37,7 @@ public:
return false;
}
a_BlockMeta = cBlockBedHandler::RotationToMetaData(a_Player->GetRotation());
a_BlockMeta = cBlockBedHandler::RotationToMetaData(a_Player->GetYaw());
// Check if there is empty space for the foot section:
Vector3i Direction = cBlockBedHandler::MetaDataToDirection(a_BlockMeta);

View File

@ -30,7 +30,7 @@ public:
) override
{
a_BlockType = E_BLOCK_INACTIVE_COMPARATOR;
a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation());
a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetYaw());
return true;
}
} ;

View File

@ -60,7 +60,7 @@ public:
cMinecart * Minecart = NULL;
switch (m_ItemType)
{
case E_ITEM_MINECART: Minecart = new cEmptyMinecart (x, y, z); break;
case E_ITEM_MINECART: Minecart = new cRideableMinecart (x, y, z, cItem(), 1); break;
case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (x, y, z); break;
case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace (x, y, z); break;
case E_ITEM_MINECART_WITH_TNT: Minecart = new cMinecartWithTNT (x, y, z); break;

View File

@ -30,7 +30,7 @@ public:
) override
{
a_BlockType = E_BLOCK_REDSTONE_REPEATER_OFF;
a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation());
a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetYaw());
return true;
}
} ;

View File

@ -34,7 +34,7 @@ public:
{
if (a_BlockFace == BLOCK_FACE_TOP)
{
a_BlockMeta = cBlockSignHandler::RotationToMetaData(a_Player->GetRotation());
a_BlockMeta = cBlockSignHandler::RotationToMetaData(a_Player->GetYaw());
a_BlockType = E_BLOCK_SIGN_POST;
}
else

View File

@ -208,7 +208,7 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
Distance.Normalize();
VectorToEuler( Distance.x, Distance.y, Distance.z, Rotation, Pitch );
SetHeadYaw (Rotation);
SetRotation( Rotation );
SetYaw( Rotation );
SetPitch( -Pitch );
}

View File

@ -354,8 +354,8 @@ void cProtocol125::SendEntityLook(const cEntity & a_Entity)
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_ENT_LOOK);
WriteInt (a_Entity.GetUniqueID());
WriteByte((char)((a_Entity.GetRotation() / 360.f) * 256));
WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
WriteByte((char)((a_Entity.GetYaw() / 360.f) * 256));
WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
Flush();
}
@ -423,8 +423,8 @@ void cProtocol125::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX,
WriteByte(a_RelX);
WriteByte(a_RelY);
WriteByte(a_RelZ);
WriteByte((char)((a_Entity.GetRotation() / 360.f) * 256));
WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
WriteByte((char)((a_Entity.GetYaw() / 360.f) * 256));
WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
Flush();
}
@ -664,7 +664,7 @@ void cProtocol125::SendPlayerMoveLook(void)
WriteDouble(Player->GetStance() + 0.03); // Add a small amount so that the player doesn't start inside a block
WriteDouble(Player->GetPosY() + 0.03); // Add a small amount so that the player doesn't start inside a block
WriteDouble(Player->GetPosZ());
WriteFloat ((float)(Player->GetRotation()));
WriteFloat ((float)(Player->GetYaw()));
WriteFloat ((float)(Player->GetPitch()));
WriteBool (Player->IsOnGround());
Flush();
@ -694,8 +694,8 @@ void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player)
WriteInt ((int)(a_Player.GetPosX() * 32));
WriteInt ((int)(a_Player.GetPosY() * 32));
WriteInt ((int)(a_Player.GetPosZ() * 32));
WriteByte ((char)((a_Player.GetRot().x / 360.f) * 256));
WriteByte ((char)((a_Player.GetRot().y / 360.f) * 256));
WriteByte ((char)((a_Player.GetYaw() / 360.f) * 256));
WriteByte ((char)((a_Player.GetPitch() / 360.f) * 256));
WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType);
Flush();
}
@ -864,7 +864,7 @@ void cProtocol125::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp
WriteInt ((int)(a_Vehicle.GetPosY() * 32));
WriteInt ((int)(a_Vehicle.GetPosZ() * 32));
WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256));
WriteByte ((Byte)((a_Vehicle.GetRotation() / 360.f) * 256));
WriteByte ((Byte)((a_Vehicle.GetYaw() / 360.f) * 256));
WriteInt (a_VehicleSubType);
if (a_VehicleSubType != 0)
{
@ -897,7 +897,7 @@ void cProtocol125::SendTeleportEntity(const cEntity & a_Entity)
WriteInt ((int)(floor(a_Entity.GetPosX() * 32)));
WriteInt ((int)(floor(a_Entity.GetPosY() * 32)));
WriteInt ((int)(floor(a_Entity.GetPosZ() * 32)));
WriteByte ((char)((a_Entity.GetRotation() / 360.f) * 256));
WriteByte ((char)((a_Entity.GetYaw() / 360.f) * 256));
WriteByte ((char)((a_Entity.GetPitch() / 360.f) * 256));
Flush();
}

View File

@ -367,8 +367,8 @@ void cProtocol132::SendPlayerSpawn(const cPlayer & a_Player)
WriteInt ((int)(a_Player.GetPosX() * 32));
WriteInt ((int)(a_Player.GetPosY() * 32));
WriteInt ((int)(a_Player.GetPosZ() * 32));
WriteByte ((char)((a_Player.GetRot().x / 360.f) * 256));
WriteByte ((char)((a_Player.GetRot().y / 360.f) * 256));
WriteByte ((char)((a_Player.GetYaw() / 360.f) * 256));
WriteByte ((char)((a_Player.GetPitch() / 360.f) * 256));
WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType);
// Player metadata: just use a default metadata value, since the client doesn't like starting without any metadata:
WriteByte (0); // Index 0, byte (flags)
@ -421,8 +421,8 @@ void cProtocol132::SendSpawnMob(const cMonster & a_Mob)
WriteInt (a_Mob.GetUniqueID());
WriteByte (a_Mob.GetMobType());
WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32));
WriteByte ((Byte)((a_Mob.GetRotation() / 360.f) * 256));
WriteByte ((Byte)((a_Mob.GetPitch() / 360.f) * 256));
WriteByte ((Byte)((a_Mob.GetYaw() / 360.f) * 256));
WriteByte ((Byte)((a_Mob.GetPitch() / 360.f) * 256));
WriteByte ((Byte)((a_Mob.GetHeadYaw() / 360.f) * 256));
WriteShort ((short)(a_Mob.GetSpeedX() * 400));
WriteShort ((short)(a_Mob.GetSpeedY() * 400));

View File

@ -250,7 +250,7 @@ void cProtocol146::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp
WriteInt ((int)(a_Vehicle.GetPosY() * 32));
WriteInt ((int)(a_Vehicle.GetPosZ() * 32));
WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256));
WriteByte ((Byte)((a_Vehicle.GetRotation() / 360.f) * 256));
WriteByte ((Byte)((a_Vehicle.GetYaw() / 360.f) * 256));
WriteInt (a_VehicleSubType);
if (a_VehicleSubType != 0)
{

View File

@ -1040,7 +1040,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
if (!HandlePacket(bb, PacketType))
{
// Unknown packet, already been reported, but without the length. Log the length here:
LOGWARNING("Unhandled packet: type 0x%x, length %u", PacketType, PacketLen);
LOGWARNING("Unhandled packet: type 0x%x, state %d, length %u", PacketType, m_State, PacketLen);
#ifdef _DEBUG
// Dump the packet contents into the log:
@ -1059,8 +1059,8 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
if (bb.GetReadableSpace() != 1)
{
// Read more or less than packet length, report as error
LOGWARNING("Protocol 1.7: Wrong number of bytes read for packet 0x%x. Read %u bytes, packet contained %u bytes",
PacketType, bb.GetUsedSpace() - bb.GetReadableSpace(), PacketLen
LOGWARNING("Protocol 1.7: Wrong number of bytes read for packet 0x%x, state %d. Read %u bytes, packet contained %u bytes",
PacketType, m_State, bb.GetUsedSpace() - bb.GetReadableSpace(), PacketLen
);
ASSERT(!"Read wrong number of bytes!");
m_Client->PacketError(PacketType);
@ -1128,9 +1128,26 @@ bool cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
}
break;
}
default:
{
// Received a packet in an unknown state, report:
LOGWARNING("Received a packet in an unknown protocol state %d. Ignoring further packets.", m_State);
// Cannot kick the client - we don't know this state and thus the packet number for the kick packet
// Switch to a state when all further packets are silently ignored:
m_State = 255;
return false;
}
case 255:
{
// This is the state used for "not processing packets anymore" when we receive a bad packet from a client.
// Do not output anything (the caller will do that for us), just return failure
return false;
}
} // switch (m_State)
// Unknown packet type, report to the client:
// Unknown packet type, report to the ClientHandle:
m_Client->PacketUnknown(a_PacketType);
return false;
}
@ -1668,7 +1685,7 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
return;
}
// Load enchantments from the NBT:
// Load enchantments and custom display names from the NBT data:
for (int tag = NBT.GetFirstChild(NBT.GetRoot()); tag >= 0; tag = NBT.GetNextSibling(tag))
{
if (
@ -1681,6 +1698,27 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
{
a_Item.m_Enchantments.ParseFromNBT(NBT, tag);
}
else if ((NBT.GetType(tag) == TAG_Compound) && (NBT.GetName(tag) == "display")) // Custom name and lore tag
{
for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag))
{
if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag
{
a_Item.m_CustomName = NBT.GetString(displaytag);
}
else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag
{
AString Lore;
for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings
{
AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a newline, used internally by MCS to display a new line in the client; don't forget to c_str ;)
}
a_Item.m_Lore = Lore;
}
}
}
}
}
@ -1732,16 +1770,45 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
WriteByte (a_Item.m_ItemCount);
WriteShort(a_Item.m_ItemDamage);
if (a_Item.m_Enchantments.IsEmpty())
if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty())
{
WriteShort(-1);
return;
}
// Send the enchantments:
// Send the enchantments and custom names:
cFastNBTWriter Writer;
const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
a_Item.m_Enchantments.WriteToNBTCompound(Writer, TagName);
if (!a_Item.m_Enchantments.IsEmpty())
{
const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
a_Item.m_Enchantments.WriteToNBTCompound(Writer, TagName);
}
if (!a_Item.IsBothNameAndLoreEmpty())
{
Writer.BeginCompound("display");
if (!a_Item.IsCustomNameEmpty())
{
Writer.AddString("Name", a_Item.m_CustomName.c_str());
}
if (!a_Item.IsLoreEmpty())
{
Writer.BeginList("Lore", TAG_String);
AStringVector Decls = StringSplit(a_Item.m_Lore, "`");
for (AStringVector::const_iterator itr = Decls.begin(), end = Decls.end(); itr != end; ++itr)
{
if (itr->empty())
{
// The decl is empty (two `s), ignore
continue;
}
Writer.AddString("", itr->c_str());
}
Writer.EndList();
}
Writer.EndCompound();
}
Writer.Finish();
AString Compressed;
CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
@ -1823,8 +1890,23 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
WriteInt(1); // Shaking direction, doesn't seem to affect anything
WriteByte(0x73);
WriteFloat((float)(((const cMinecart &)a_Entity).LastDamage() + 10)); // Damage taken / shake effect multiplyer
if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace)
if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpNone)
{
cRideableMinecart & RideableMinecart = ((cRideableMinecart &)a_Entity);
if (!RideableMinecart.GetContent().IsEmpty())
{
WriteByte(0x54);
int Content = RideableMinecart.GetContent().m_ItemType;
Content |= RideableMinecart.GetContent().m_ItemDamage << 8;
WriteInt(Content);
WriteByte(0x55);
WriteInt(RideableMinecart.GetBlockHeight());
WriteByte(0x56);
WriteByte(1);
}
}
else if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace)
{
WriteByte(0x10);
WriteByte(((const cMinecartWithFurnace &)a_Entity).IsFueled() ? 1 : 0);

View File

@ -459,7 +459,7 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac
{
return;
}
// Special handling: "stop" and "restart" are built in
if ((split[0].compare("stop") == 0) || (split[0].compare("restart") == 0))
{

View File

@ -4,6 +4,7 @@
#include "RedstoneSimulator.h"
#include "../BlockEntities/DropSpenserEntity.h"
#include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/CommandBlockEntity.h"
#include "../Entities/TNTEntity.h"
#include "../Blocks/BlockTorch.h"
#include "../Blocks/BlockDoor.h"
@ -215,11 +216,12 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c
{
case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break;
case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break;
case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break;
case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break;
case E_BLOCK_TRAPDOOR: HandleTrapdoor(a_X, dataitr->y, a_Z); break;
case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(a_X, dataitr->y, a_Z); break;
case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(a_X, dataitr->y, a_Z); break;
case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(a_X, dataitr->y, a_Z); break;
case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(a_X, dataitr->y, a_Z); break;
case E_BLOCK_REDSTONE_TORCH_OFF:
case E_BLOCK_REDSTONE_TORCH_ON:
@ -763,6 +765,29 @@ void cRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ)
void cRedstoneSimulator::HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
{
class cSetPowerToCommandBlock :
public cCommandBlockCallback
{
bool m_IsPowered;
public:
cSetPowerToCommandBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {}
virtual bool Item(cCommandBlockEntity * a_CommandBlock) override
{
a_CommandBlock->SetRedstonePower(m_IsPowered);
return false;
}
} CmdBlockSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ));
m_World.DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, CmdBlockSP);
}
void cRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType)
{
switch (a_MyType)

View File

@ -110,6 +110,8 @@ private:
void HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState);
/** Handles doords */
void HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ);
/** Handles command blocks */
void HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
/** Handles activator, detector, and powered rails */
void HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType);
/** Handles trapdoors */
@ -166,6 +168,7 @@ private:
switch (Block)
{
case E_BLOCK_ACTIVATOR_RAIL:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_PISTON:
case E_BLOCK_STICKY_PISTON:
case E_BLOCK_DISPENSER:
@ -220,6 +223,7 @@ private:
case E_BLOCK_ACTIVATOR_RAIL:
case E_BLOCK_ACTIVE_COMPARATOR:
case E_BLOCK_BLOCK_OF_REDSTONE:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DETECTOR_RAIL:
case E_BLOCK_DISPENSER:
case E_BLOCK_DAYLIGHT_SENSOR:

View File

@ -11,7 +11,7 @@
/// Compresses a_Data into a_Compressed; returns Z_XXX error constants same as zlib's compress2()
int CompressString(const char * a_Data, int a_Length, AString & a_Compressed)
int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, int a_Factor)
{
uLongf CompressedSize = compressBound(a_Length);
@ -19,7 +19,7 @@ int CompressString(const char * a_Data, int a_Length, AString & a_Compressed)
// It saves us one allocation and one memcpy of the entire compressed data
// It may not work on some STL implementations! (Confirmed working on MSVC 2008 & 2010)
a_Compressed.resize(CompressedSize);
int errorcode = compress2( (Bytef*)a_Compressed.data(), &CompressedSize, (const Bytef*)a_Data, a_Length, Z_DEFAULT_COMPRESSION);
int errorcode = compress2( (Bytef*)a_Compressed.data(), &CompressedSize, (const Bytef*)a_Data, a_Length, a_Factor);
if (errorcode != Z_OK)
{
return errorcode;

View File

@ -10,7 +10,7 @@
/// Compresses a_Data into a_Compressed using ZLIB; returns Z_XXX error constants same as zlib's compress2()
extern int CompressString(const char * a_Data, int a_Length, AString & a_Compressed);
extern int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, int a_Factor);
/// Uncompresses a_Data into a_Uncompressed; returns Z_XXX error constants same as zlib's decompress()
extern int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed, int a_UncompressedSize);

View File

@ -85,10 +85,10 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA
{
if (DraggingItem.m_ItemType <= 0) // Empty-handed?
{
DraggingItem = Slot.CopyOne(); // Obtain copy of slot to preserve lore, enchantments, etc.
DraggingItem.m_ItemCount = (char)(((float)Slot.m_ItemCount) / 2.f + 0.5f);
Slot.m_ItemCount -= DraggingItem.m_ItemCount;
DraggingItem.m_ItemType = Slot.m_ItemType;
DraggingItem.m_ItemDamage = Slot.m_ItemDamage;
if (Slot.m_ItemCount <= 0)
{
@ -101,9 +101,12 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA
cItemHandler * Handler = ItemHandler(Slot.m_ItemType);
if ((DraggingItem.m_ItemCount > 0) && (Slot.m_ItemCount < Handler->GetMaxStackSize()))
{
Slot.m_ItemType = DraggingItem.m_ItemType;
Slot.m_ItemCount++;
Slot.m_ItemDamage = DraggingItem.m_ItemDamage;
char OldSlotCount = Slot.m_ItemCount;
Slot = DraggingItem.CopyOne(); // See above
OldSlotCount++;
Slot.m_ItemCount = OldSlotCount;
DraggingItem.m_ItemCount--;
}
if (DraggingItem.m_ItemCount <= 0)
@ -226,7 +229,7 @@ void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_
for (int i = 0; i < m_NumSlots; i++)
{
const cItem * Slot = GetSlot(i, a_Player);
if (!Slot->IsStackableWith(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots))
if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots))
{
// Different items
continue;
@ -265,7 +268,7 @@ bool cSlotArea::CollectItemsToHand(cItem & a_Dragging, cPlayer & a_Player, bool
for (int i = 0; i < NumSlots; i++)
{
const cItem & SlotItem = *GetSlot(i, a_Player);
if (!SlotItem.IsStackableWith(a_Dragging))
if (!SlotItem.IsEqual(a_Dragging))
{
continue;
}
@ -908,7 +911,7 @@ void cSlotAreaTemporary::TossItems(cPlayer & a_Player, int a_Begin, int a_End)
} // for i - itr->second[]
double vX = 0, vY = 0, vZ = 0;
EulerToVector(-a_Player.GetRotation(), a_Player.GetPitch(), vZ, vX, vY);
EulerToVector(-a_Player.GetYaw(), a_Player.GetPitch(), vZ, vX, vY);
vY = -vY * 2 + 1.f;
a_Player.GetWorld()->SpawnItemPickups(Drops, a_Player.GetPosX(), a_Player.GetPosY() + 1.6f, a_Player.GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because player created
}

View File

@ -642,7 +642,7 @@ int cWindow::DistributeItemToSlots(cPlayer & a_Player, const cItem & a_Item, int
Area->SetSlot(LocalSlotNum, a_Player, ToStore);
NumDistributed += ToStore.m_ItemCount;
}
else if (AtSlot.IsStackableWith(a_Item))
else if (AtSlot.IsEqual(a_Item))
{
// Occupied, add and cap at MaxStack:
int CanStore = std::min(a_NumToEachSlot, (int)MaxStack - AtSlot.m_ItemCount);

View File

@ -16,6 +16,7 @@
// Entities (except mobs):
#include "Entities/ExpOrb.h"
#include "Entities/FallingBlock.h"
#include "Entities/Minecart.h"
#include "Entities/Pickup.h"
#include "Entities/Player.h"
#include "Entities/TNTEntity.h"
@ -230,6 +231,7 @@ cWorld::cWorld(const AString & a_WorldName) :
m_WorldName(a_WorldName),
m_IniFileName(m_WorldName + "/world.ini"),
m_StorageSchema("Default"),
m_StorageCompressionFactor(6),
m_IsSpawnExplicitlySet(false),
m_WorldAgeSecs(0),
m_TimeOfDaySecs(0),
@ -511,6 +513,7 @@ void cWorld::Start(void)
}
m_StorageSchema = IniFile.GetValueSet ("Storage", "Schema", m_StorageSchema);
m_StorageCompressionFactor = IniFile.GetValueSetI ("Storage", "CompressionFactor", m_StorageCompressionFactor);
m_MaxCactusHeight = IniFile.GetValueSetI("Plants", "MaxCactusHeight", 3);
m_MaxSugarcaneHeight = IniFile.GetValueSetI("Plants", "MaxSugarcaneHeight", 3);
m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false);
@ -584,7 +587,7 @@ void cWorld::Start(void)
m_SimulatorManager->RegisterSimulator(m_RedstoneSimulator, 1);
m_Lighting.Start(this);
m_Storage.Start(this, m_StorageSchema);
m_Storage.Start(this, m_StorageSchema, m_StorageCompressionFactor );
m_Generator.Start(m_GeneratorCallbacks, m_GeneratorCallbacks, IniFile);
m_ChunkSender.Start(this);
m_TickThread.Start();
@ -1146,6 +1149,15 @@ bool cWorld::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBl
bool cWorld::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback)
{
return m_ChunkMap->DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
}
bool cWorld::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4)
{
return m_ChunkMap->GetSignLines(a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4);
@ -1673,6 +1685,29 @@ int cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward)
int cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content, int a_BlockHeight)
{
cMinecart * Minecart;
switch (a_MinecartType)
{
case E_ITEM_MINECART: Minecart = new cRideableMinecart (a_X, a_Y, a_Z, a_Content, a_BlockHeight); break;
case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (a_X, a_Y, a_Z); break;
case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace (a_X, a_Y, a_Z); break;
case E_ITEM_MINECART_WITH_TNT: Minecart = new cMinecartWithTNT (a_X, a_Y, a_Z); break;
case E_ITEM_MINECART_WITH_HOPPER: Minecart = new cMinecartWithHopper (a_X, a_Y, a_Z); break;
default:
{
return -1;
}
} // switch (a_MinecartType)
Minecart->Initialize(this);
return Minecart->GetUniqueID();
}
void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff)
{
UNUSED(a_InitialVelocityCoeff);
@ -2740,9 +2775,6 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eTyp
{
Monster->SetPosition(a_PosX, a_PosY, a_PosZ);
}
// Because it's logical that ALL mob spawns need spawn effects, not just spawners
BroadcastSoundParticleEffect(2004, (int)a_PosX, (int)a_PosY, (int)a_PosZ, 0);
return SpawnMobFinalize(Monster);
}

View File

@ -46,12 +46,13 @@ class cMobCensus;
typedef std::list< cPlayer * > cPlayerList;
typedef cItemCallback<cPlayer> cPlayerListCallback;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cPlayer> cPlayerListCallback;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
@ -374,6 +375,9 @@ public:
/// Spawns an falling block entity at the given position. It returns the UniqueID of the spawned falling block.
int SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta);
/// Spawns an minecart at the given coordinates.
int SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content = cItem(), int a_BlockHeight = 1);
/// Spawns an experience orb at the given location with the given reward. It returns the UniqueID of the spawned experience orb.
int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward);
@ -463,6 +467,9 @@ public:
/// Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found
bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); // Exported in ManualBindings.cpp
/// Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found
bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Exported in ManualBindings.cpp
/// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Exported in ManualBindings.cpp
@ -678,6 +685,8 @@ private:
/// Name of the storage schema used to load and save chunks
AString m_StorageSchema;
int m_StorageCompressionFactor;
/// The dimension of the world, used by the client to provide correct lighting scheme
eDimension m_Dimension;

View File

@ -10,6 +10,7 @@
#include "FastNBT.h"
#include "../BlockEntities/ChestEntity.h"
#include "../BlockEntities/CommandBlockEntity.h"
#include "../BlockEntities/DispenserEntity.h"
#include "../BlockEntities/DropperEntity.h"
#include "../BlockEntities/FurnaceEntity.h"
@ -219,8 +220,23 @@ void cNBTChunkSerializer::AddJukeboxEntity(cJukeboxEntity * a_Jukebox)
void cNBTChunkSerializer::AddNoteEntity(cNoteEntity * a_Note)
{
m_Writer.BeginCompound("");
AddBasicTileEntity(a_Note, "Music");
m_Writer.AddByte("note", a_Note->GetPitch());
AddBasicTileEntity(a_Note, "Music");
m_Writer.AddByte("note", a_Note->GetPitch());
m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddCommandBlockEntity(cCommandBlockEntity * a_CmdBlock)
{
m_Writer.BeginCompound("");
AddBasicTileEntity(a_CmdBlock, "Control");
m_Writer.AddString("Command", a_CmdBlock->GetCommand());
m_Writer.AddInt ("SuccessCount", a_CmdBlock->GetResult());
m_Writer.AddString("LastOutput", a_CmdBlock->GetLastOutput());
m_Writer.AddByte ("TrackOutput", 1); // TODO 2014-01-18 xdot: Figure out what TrackOutput is and save it.
m_Writer.EndCompound();
}
@ -257,7 +273,7 @@ void cNBTChunkSerializer::AddBasicEntity(cEntity * a_Entity, const AString & a_C
m_Writer.AddDouble("", a_Entity->GetSpeedZ());
m_Writer.EndList();
m_Writer.BeginList("Rotation", TAG_Double);
m_Writer.AddDouble("", a_Entity->GetRotation());
m_Writer.AddDouble("", a_Entity->GetYaw());
m_Writer.AddDouble("", a_Entity->GetPitch());
m_Writer.EndList();
}
@ -639,15 +655,16 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity)
// Add tile-entity into NBT:
switch (a_Entity->GetBlockType())
{
case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break;
case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break;
case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break;
case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break;
case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break;
case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break;
case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break;
case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break;
case E_BLOCK_SIGN_POST:
case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break;
case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break;
case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break;
case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break;
case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break;
case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break;
case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity((cCommandBlockEntity *) a_Entity); break;
default:
{
ASSERT(!"Unhandled block entity saved into Anvil");

View File

@ -21,6 +21,7 @@ class cEntity;
class cBlockEntity;
class cBoat;
class cChestEntity;
class cCommandBlockEntity;
class cDispenserEntity;
class cDropperEntity;
class cFurnaceEntity;
@ -92,6 +93,7 @@ protected:
void AddJukeboxEntity (cJukeboxEntity * a_Jukebox);
void AddNoteEntity (cNoteEntity * a_Note);
void AddSignEntity (cSignEntity * a_Sign);
void AddCommandBlockEntity(cCommandBlockEntity * a_CmdBlock);
// Entities:
void AddBasicEntity (cEntity * a_Entity, const AString & a_ClassName);

View File

@ -15,6 +15,7 @@
#include "../StringCompression.h"
#include "../BlockEntities/ChestEntity.h"
#include "../BlockEntities/CommandBlockEntity.h"
#include "../BlockEntities/DispenserEntity.h"
#include "../BlockEntities/DropperEntity.h"
#include "../BlockEntities/FurnaceEntity.h"
@ -58,8 +59,9 @@ Since only the header is actually in the memory, this number can be high, but st
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cWSSAnvil:
cWSSAnvil::cWSSAnvil(cWorld * a_World) :
super(a_World)
cWSSAnvil::cWSSAnvil(cWorld * a_World, int a_CompressionFactor) :
super(a_World),
m_CompressionFactor(a_CompressionFactor)
{
// Create a level.dat file for mapping tools, if it doesn't already exist:
AString fnam;
@ -272,7 +274,7 @@ bool cWSSAnvil::SaveChunkToData(const cChunkCoords & a_Chunk, AString & a_Data)
}
Writer.Finish();
CompressString(Writer.GetResult().data(), Writer.GetResult().size(), a_Data);
CompressString(Writer.GetResult().data(), Writer.GetResult().size(), a_Data, m_CompressionFactor);
return true;
}
@ -566,6 +568,10 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
{
LoadChestFromNBT(a_BlockEntities, a_NBT, Child);
}
else if (strncmp(a_NBT.GetData(sID), "Control", a_NBT.GetDataLength(sID)) == 0)
{
LoadCommandBlockFromNBT(a_BlockEntities, a_NBT, Child);
}
else if (strncmp(a_NBT.GetData(sID), "Dropper", a_NBT.GetDataLength(sID)) == 0)
{
LoadDropperFromNBT(a_BlockEntities, a_NBT, Child);
@ -914,6 +920,43 @@ void cWSSAnvil::LoadSignFromNBT(cBlockEntityList & a_BlockEntities, const cParse
void cWSSAnvil::LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
{
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
int x, y, z;
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
{
return;
}
std::auto_ptr<cCommandBlockEntity> CmdBlock(new cCommandBlockEntity(x, y, z, m_World));
int currentLine = a_NBT.FindChildByName(a_TagIdx, "Command");
if (currentLine >= 0)
{
CmdBlock->SetCommand(a_NBT.GetString(currentLine));
}
currentLine = a_NBT.FindChildByName(a_TagIdx, "SuccessCount");
if (currentLine >= 0)
{
CmdBlock->SetResult(a_NBT.GetInt(currentLine));
}
currentLine = a_NBT.FindChildByName(a_TagIdx, "LastOutput");
if (currentLine >= 0)
{
CmdBlock->SetLastOutput(a_NBT.GetString(currentLine));
}
// TODO 2014-01-18 xdot: Figure out what TrackOutput is and parse it.
a_BlockEntities.push_back(CmdBlock.release());
}
void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength)
{
if (strncmp(a_IDTag, "Boat", a_IDTagLength) == 0)
@ -1150,7 +1193,7 @@ void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedN
void cWSSAnvil::LoadMinecartRFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
std::auto_ptr<cEmptyMinecart> Minecart(new cEmptyMinecart(0, 0, 0));
std::auto_ptr<cRideableMinecart> Minecart(new cRideableMinecart(0, 0, 0, cItem(), 1)); // TODO: Load the block and the height
if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx))
{
return;
@ -1891,7 +1934,7 @@ bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_N
{
return false;
}
a_Entity.SetRotation(Rotation[0]);
a_Entity.SetYaw(Rotation[0]);
a_Entity.SetRoll (Rotation[1]);
return true;

View File

@ -47,7 +47,7 @@ class cWSSAnvil :
public:
cWSSAnvil(cWorld * a_World);
cWSSAnvil(cWorld * a_World, int a_CompressionFactor);
virtual ~cWSSAnvil();
protected:
@ -89,6 +89,8 @@ protected:
cCriticalSection m_CS;
cMCAFiles m_Files; // a MRU cache of MCA files
int m_CompressionFactor;
/// Gets chunk data from the correct file; locks file CS as needed
bool GetChunkData(const cChunkCoords & a_Chunk, AString & a_Data);
@ -129,14 +131,15 @@ protected:
*/
void LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a_NBT, int a_ItemsTagIdx, int s_SlotOffset = 0);
void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadFurnaceFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas);
void LoadHopperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadJukeboxFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadNoteFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadSignFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadFurnaceFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas);
void LoadHopperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadJukeboxFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadNoteFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadSignFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength);

View File

@ -193,7 +193,7 @@ cWSSCompact::cPAKFile * cWSSCompact::LoadPAKFile(const cChunkCoords & a_Chunk)
// Load it anew:
AString FileName;
Printf(FileName, "%s/X%i_Z%i.pak", m_World->GetName().c_str(), LayerX, LayerZ );
cPAKFile * f = new cPAKFile(FileName, LayerX, LayerZ);
cPAKFile * f = new cPAKFile(FileName, LayerX, LayerZ, m_CompressionFactor);
if (f == NULL)
{
return NULL;
@ -399,8 +399,9 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En
return; \
}
cWSSCompact::cPAKFile::cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ) :
cWSSCompact::cPAKFile::cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ, int a_CompressionFactor) :
m_FileName(a_FileName),
m_CompressionFactor(a_CompressionFactor),
m_LayerX(a_LayerX),
m_LayerZ(a_LayerZ),
m_NumDirty(0),
@ -648,7 +649,7 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2()
// Re-compress data
AString CompressedData;
{
int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData);
int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData,m_CompressionFactor);
if (errorcode != Z_OK)
{
LOGERROR("Error %d compressing data for chunk [%d, %d]",
@ -786,7 +787,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
// Re-compress data
AString CompressedData;
{
int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData);
int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData, m_CompressionFactor);
if (errorcode != Z_OK)
{
LOGERROR("Error %d compressing data for chunk [%d, %d]",
@ -939,7 +940,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld
// Compress the data:
AString CompressedData;
int errorcode = CompressString(Data.data(), Data.size(), CompressedData);
int errorcode = CompressString(Data.data(), Data.size(), CompressedData, m_CompressionFactor);
if ( errorcode != Z_OK )
{
LOGERROR("Error %i compressing data for chunk [%d, %d, %d]", errorcode, a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ);

View File

@ -53,7 +53,7 @@ class cWSSCompact :
public cWSSchema
{
public:
cWSSCompact(cWorld * a_World) : cWSSchema(a_World) {}
cWSSCompact(cWorld * a_World, int a_CompressionFactor) : cWSSchema(a_World), m_CompressionFactor(a_CompressionFactor) {}
virtual ~cWSSCompact();
protected:
@ -74,7 +74,7 @@ protected:
{
public:
cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ);
cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ, int a_CompressionFactor);
~cPAKFile();
bool GetChunkData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, AString & a_Data);
@ -95,6 +95,7 @@ protected:
protected:
AString m_FileName;
int m_CompressionFactor;
int m_LayerX;
int m_LayerZ;
@ -119,6 +120,8 @@ protected:
cCriticalSection m_CS;
cPAKFiles m_PAKFiles; // A MRU cache of PAK files
int m_CompressionFactor;
/// Loads the correct PAK file either from cache or from disk, manages the m_PAKFiles cache
cPAKFile * LoadPAKFile(const cChunkCoords & a_Chunk);

View File

@ -68,11 +68,11 @@ cWorldStorage::~cWorldStorage()
bool cWorldStorage::Start(cWorld * a_World, const AString & a_StorageSchemaName)
bool cWorldStorage::Start(cWorld * a_World, const AString & a_StorageSchemaName, int a_StorageCompressionFactor )
{
m_World = a_World;
m_StorageSchemaName = a_StorageSchemaName;
InitSchemas();
InitSchemas(a_StorageCompressionFactor);
return super::Start();
}
@ -197,11 +197,11 @@ void cWorldStorage::UnqueueSave(const cChunkCoords & a_Chunk)
void cWorldStorage::InitSchemas(void)
void cWorldStorage::InitSchemas(int a_StorageCompressionFactor)
{
// The first schema added is considered the default
m_Schemas.push_back(new cWSSAnvil (m_World));
m_Schemas.push_back(new cWSSCompact (m_World));
m_Schemas.push_back(new cWSSAnvil (m_World,a_StorageCompressionFactor));
m_Schemas.push_back(new cWSSCompact (m_World,a_StorageCompressionFactor));
m_Schemas.push_back(new cWSSForgetful(m_World));
// Add new schemas here

View File

@ -76,7 +76,7 @@ public:
void UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
void UnqueueSave(const cChunkCoords & a_Chunk);
bool Start(cWorld * a_World, const AString & a_StorageSchemaName); // Hide the cIsThread's Start() method, we need to provide args
bool Start(cWorld * a_World, const AString & a_StorageSchemaName, int a_StorageCompressionFactor); // Hide the cIsThread's Start() method, we need to provide args
void Stop(void); // Hide the cIsThread's Stop() method, we need to signal the event
void WaitForFinish(void);
void WaitForLoadQueueEmpty(void);
@ -126,7 +126,7 @@ protected:
/// The one storage schema used for saving
cWSSchema * m_SaveSchema;
void InitSchemas(void);
void InitSchemas(int a_StorageCompressionFactor);
virtual void Execute(void) override;

View File

@ -47,9 +47,20 @@ void NonCtrlHandler(int a_Signal)
case SIGSEGV:
{
std::signal(SIGSEGV, SIG_DFL);
LOGWARN("Segmentation fault; MCServer has crashed :(");
LOGERROR(" D: | MCServer has encountered an error and needs to close");
LOGERROR("Details | SIGSEGV: Segmentation fault");
exit(EXIT_FAILURE);
}
case SIGABRT:
#ifdef SIGABRT_COMPAT
case SIGABRT_COMPAT:
#endif
{
std::signal(a_Signal, SIG_DFL);
LOGERROR(" D: | MCServer has encountered an error and needs to close");
LOGERROR("Details | SIGABRT: Server self-terminated due to an internal fault");
break;
}
case SIGTERM:
{
std::signal(SIGTERM, SIG_IGN); // Server is shutting down, wait for it...