Merge remote-tracking branch 'origin/master' into minecartimprovements
This commit is contained in:
commit
82b2290b74
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,6 @@
|
||||
build/
|
||||
ipch/
|
||||
Win32/
|
||||
MCServer/MCServer
|
||||
ChunkWorxSave.ini
|
||||
doxy/
|
||||
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
||||
|
@ -20,5 +20,6 @@ worktycho
|
||||
Sxw1212
|
||||
tonibm19
|
||||
Diusrex
|
||||
structinf (xdot)
|
||||
|
||||
Please add yourself to this list if you contribute to MCServer.
|
||||
|
@ -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
|
@ -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})
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
||||
|
@ -22,6 +22,8 @@ cServer::cServer(void)
|
||||
int cServer::Init(short a_ListenPort, short a_ConnectPort)
|
||||
{
|
||||
m_ConnectPort = a_ConnectPort;
|
||||
|
||||
#ifdef _WIN32
|
||||
WSAData wsa;
|
||||
int res = WSAStartup(0x0202, &wsa);
|
||||
if (res != 0)
|
||||
@ -29,6 +31,7 @@ int cServer::Init(short a_ListenPort, short a_ConnectPort)
|
||||
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");
|
||||
|
@ -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"
|
||||
>
|
||||
|
@ -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()
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
@ -2273,6 +2274,7 @@ void ManualBindings::Bind(lua_State * tolua_S)
|
||||
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>);
|
||||
|
@ -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"
|
||||
@ -24,6 +25,7 @@ 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_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);
|
||||
|
197
src/BlockEntities/CommandBlockEntity.cpp
Normal file
197
src/BlockEntities/CommandBlockEntity.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
91
src/BlockEntities/CommandBlockEntity.h
Normal file
91
src/BlockEntities/CommandBlockEntity.h
Normal 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
|
||||
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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 (
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ public:
|
||||
}
|
||||
|
||||
a_BlockType = m_BlockType;
|
||||
a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation());
|
||||
a_BlockMeta = PlayerYawToMetaData(a_Player->GetYaw());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
} ;
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
) override
|
||||
{
|
||||
a_BlockType = m_BlockType;
|
||||
a_BlockMeta = RotationToMetaData(a_Player->GetRotation());
|
||||
a_BlockMeta = RotationToMetaData(a_Player->GetYaw());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ public:
|
||||
) override
|
||||
{
|
||||
a_BlockType = m_BlockType;
|
||||
a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation());
|
||||
a_BlockMeta = PlayerYawToMetaData(a_Player->GetYaw());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ public:
|
||||
) override
|
||||
{
|
||||
a_BlockType = m_BlockType;
|
||||
a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetRotation());
|
||||
a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetYaw());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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
|
||||
|
@ -46,6 +46,7 @@ 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
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -23,6 +23,7 @@ class cDropperEntity;
|
||||
class cDropSpenserEntity;
|
||||
class cFurnaceEntity;
|
||||
class cNoteEntity;
|
||||
class cCommandBlockEntity;
|
||||
class cPawn;
|
||||
class cPickup;
|
||||
class cChunkDataSerializer;
|
||||
@ -40,6 +41,7 @@ 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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -325,6 +325,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
|
||||
virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client
|
||||
|
@ -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,
|
||||
} ;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
class cFloater :
|
||||
public cEntity
|
||||
{
|
||||
@ -14,14 +15,17 @@ class cFloater :
|
||||
|
||||
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
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -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
|
||||
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()));
|
||||
|
||||
|
@ -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()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
32
src/Item.cpp
32
src/Item.cpp
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
39
src/Item.h
39
src/Item.h
@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
@ -113,6 +126,15 @@ public:
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
} ;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
} ;
|
||||
|
@ -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
|
||||
|
@ -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 );
|
||||
}
|
||||
|
||||
|
@ -354,7 +354,7 @@ 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.GetYaw() / 360.f) * 256));
|
||||
WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
|
||||
Flush();
|
||||
}
|
||||
@ -423,7 +423,7 @@ 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.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();
|
||||
}
|
||||
|
@ -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,7 +421,7 @@ 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.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));
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
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);
|
||||
@ -1824,7 +1891,22 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
|
||||
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);
|
||||
|
@ -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"
|
||||
@ -220,6 +221,7 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c
|
||||
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)
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
@ -2741,9 +2776,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);
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,7 @@ 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);
|
||||
|
||||
@ -464,6 +468,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;
|
||||
|
||||
|
@ -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"
|
||||
@ -228,6 +229,21 @@ void cNBTChunkSerializer::AddNoteEntity(cNoteEntity * a_Note)
|
||||
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cNBTChunkSerializer::AddSignEntity(cSignEntity * a_Sign)
|
||||
{
|
||||
m_Writer.BeginCompound("");
|
||||
@ -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();
|
||||
}
|
||||
@ -648,6 +664,7 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity)
|
||||
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");
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -47,7 +47,7 @@ class cWSSAnvil :
|
||||
|
||||
public:
|
||||
|
||||
cWSSAnvil(cWorld * a_World);
|
||||
cWSSAnvil(cWorld * a_World, int a_CompressionFactor);
|
||||
virtual ~cWSSAnvil();
|
||||
|
||||
protected:
|
||||
@ -90,6 +90,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);
|
||||
|
||||
@ -137,6 +139,7 @@ protected:
|
||||
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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
13
src/main.cpp
13
src/main.cpp
@ -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...
|
||||
|
Loading…
Reference in New Issue
Block a user