summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua2
-rw-r--r--README.md4
-rw-r--r--Tools/ProtoProxy/Connection.cpp752
-rw-r--r--Tools/ProtoProxy/Connection.h4
-rw-r--r--VC2008/MCServer.vcproj14
-rw-r--r--source/Bindings.cpp102
-rw-r--r--source/Bindings.h2
-rw-r--r--source/BlockEntities/DropSpenserEntity.cpp23
-rw-r--r--source/Blocks/BlockDirt.h4
-rw-r--r--source/Blocks/BlockFire.h190
-rw-r--r--source/Blocks/BlockHandler.cpp2
-rw-r--r--source/Blocks/BlockPortal.h108
-rw-r--r--source/Blocks/BlockRail.h8
-rw-r--r--source/ByteBuffer.cpp4
-rw-r--r--source/ByteBuffer.h4
-rw-r--r--source/Chunk.cpp47
-rw-r--r--source/Chunk.h4
-rw-r--r--source/ChunkMap.cpp19
-rw-r--r--source/ClientHandle.cpp4
-rw-r--r--source/Entities/Entity.cpp4
-rw-r--r--source/Entities/Entity.h6
-rw-r--r--source/Entities/Player.cpp19
-rw-r--r--source/Entities/Player.h4
-rw-r--r--source/Entities/ProjectileEntity.cpp13
-rw-r--r--source/Item.cpp1
-rw-r--r--source/Items/ItemBow.h5
-rw-r--r--source/Items/ItemThrowable.h6
-rw-r--r--source/MobSpawner.cpp143
-rw-r--r--source/MobSpawner.h5
-rw-r--r--source/Mobs/Horse.cpp5
-rw-r--r--source/Mobs/Pig.cpp4
-rw-r--r--source/Protocol/Protocol.h22
-rw-r--r--source/Protocol/Protocol125.h5
-rw-r--r--source/Protocol/Protocol17x.cpp1445
-rw-r--r--source/Protocol/Protocol17x.h252
-rw-r--r--source/Protocol/ProtocolRecognizer.cpp130
-rw-r--r--source/Protocol/ProtocolRecognizer.h23
-rw-r--r--source/World.cpp38
-rw-r--r--source/World.h7
39 files changed, 2914 insertions, 520 deletions
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 8b007101a..f8e201244 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -3017,7 +3017,7 @@ end;
HOOK_LOGIN =
{
- CalledWhen = "Right after player authentication. If auth is disabled, right after the player sends their name.",
+ CalledWhen = "Right before player authentication. If auth is disabled, right after the player sends their name.",
DefaultFnName = "OnLogin", -- also used as pagename
Desc = [[
This hook is called whenever a client logs in. It is called right before the client's name is sent
diff --git a/README.md b/README.md
index e9b1f14e7..255d9d467 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ Installation
To install MCServer, you can either download the repository and compile it, or download a pre-compiled version.
-If you are cloning the repository, you are required to recursively download the submodules also with `git clone -r`. When pulling, you should use `git pull --recurse-submodules`. You might want to set the base forms as aliases to these.
+After you've cloned the repository, you probably want to pull down the submodules (core plugins, some dependencies). This can be achieved with `git submodule init` and then on a regular basis (to keep up to date) `git submodule update`.
Compilation instructions are available in the COMPILING file.
@@ -27,3 +27,5 @@ Other Stuff
-----------
For other stuff, including plugins and discussion, check the [forums](http://forum.mc-server.org) and [wiki](http://mc-server.org/wiki/).
+
+Earn bitcoins for commits or donate to reward the MCServer developers: [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74)
diff --git a/Tools/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp
index 4b3442858..627b42052 100644
--- a/Tools/ProtoProxy/Connection.cpp
+++ b/Tools/ProtoProxy/Connection.cpp
@@ -112,7 +112,7 @@
#define HANDLE_CLIENT_READ(Proc) \
{ \
- if (!Proc()) \
+ if (!Proc) \
{ \
AString Leftover; \
m_ClientBuffer.ReadAgain(Leftover); \
@@ -124,7 +124,7 @@
#define HANDLE_SERVER_READ(Proc) \
{ \
- if (!Proc()) \
+ if (!Proc) \
{ \
m_ServerBuffer.ResetRead(); \
return true; \
@@ -143,112 +143,6 @@ typedef unsigned char Byte;
-enum
-{
- // client-bound packets:
- PACKET_C_KEEPALIVE = 0x00,
- PACKET_C_JOIN_GAME = 0x01,
- PACKET_C_CHAT_MESSAGE = 0x02,
-
- // server-bound packets:
- PACKET_S_KEEPALIVE = 0x00, // Also the initial handshake, as the very first packet
- PACKET_S_CHAT_MESSAGE = 0x01,
-
- PACKET_TIME_UPDATE = 0x03,
- PACKET_ENTITY_EQUIPMENT = 0x04,
- PACKET_SPAWN_POSITION = 0x05,
- PACKET_UPDATE_HEALTH = 0x06,
- PACKET_USE_ENTITY = 0x07,
- PACKET_PLAYER_ON_GROUND = 0x0a,
- PACKET_PLAYER_POSITION = 0x0b,
- PACKET_PLAYER_LOOK = 0x0c,
- PACKET_PLAYER_POSITION_LOOK = 0x0d,
- PACKET_BLOCK_DIG = 0x0e,
- PACKET_BLOCK_PLACE = 0x0f,
- PACKET_SLOT_SELECT = 0x10,
- PACKET_PLAYER_ANIMATION = 0x12,
- PACKET_ENTITY_ACTION = 0x13,
- PACKET_SPAWN_NAMED_ENTITY = 0x14,
- PACKET_SPAWN_PICKUP = 0x15,
- PACKET_COLLECT_PICKUP = 0x16,
- PACKET_SPAWN_OBJECT_VEHICLE = 0x17,
- PACKET_SPAWN_MOB = 0x18,
- PACKET_SPAWN_PAINTING = 0x19,
- PACKET_SPAWN_EXPERIENCE_ORB = 0x1a,
- PACKET_ENTITY_VELOCITY = 0x1c,
- PACKET_DESTROY_ENTITIES = 0x1d,
- PACKET_ENTITY = 0x1e,
- PACKET_ENTITY_RELATIVE_MOVE = 0x1f,
- PACKET_ENTITY_LOOK = 0x20,
- PACKET_ENTITY_RELATIVE_MOVE_LOOK = 0x21,
- PACKET_ENTITY_TELEPORT = 0x22,
- PACKET_ENTITY_HEAD_LOOK = 0x23,
- PACKET_ENTITY_STATUS = 0x26,
- PACKET_ATTACH_ENTITY = 0x27,
- PACKET_ENTITY_METADATA = 0x28,
- PACKET_ENTITY_EFFECT = 0x29,
- PACKET_ENTITY_EFFECT_REMOVE = 0x2a,
- PACKET_SET_EXPERIENCE = 0x2b,
- PACKET_ENTITY_PROPERTIES = 0x2c,
- PACKET_MAP_CHUNK = 0x33,
- PACKET_MULTI_BLOCK_CHANGE = 0x34,
- PACKET_BLOCK_CHANGE = 0x35,
- PACKET_BLOCK_ACTION = 0x36,
- PACKET_MAP_CHUNK_BULK = 0x38,
- PACKET_EXPLOSION = 0x3c,
- PACKET_SOUND_EFFECT = 0x3d,
- PACKET_NAMED_SOUND_EFFECT = 0x3e,
- PACKET_CHANGE_GAME_STATE = 0x46,
- PACKET_WINDOW_OPEN = 0x64,
- PACKET_WINDOW_CLOSE = 0x65,
- PACKET_WINDOW_CLICK = 0x66,
- PACKET_SET_SLOT = 0x67,
- PACKET_WINDOW_CONTENTS = 0x68,
- PACKET_CREATIVE_INVENTORY_ACTION = 0x6b,
- PACKET_UPDATE_SIGN = 0x82,
- PACKET_UPDATE_TILE_ENTITY = 0x84,
- PACKET_PLAYER_LIST_ITEM = 0xc9,
- PACKET_PLAYER_ABILITIES = 0xca,
- PACKET_INCREMENT_STATISTIC = 0xc8,
- PACKET_TAB_COMPLETION = 0xcb,
- PACKET_LOCALE_AND_VIEW = 0xcc,
- PACKET_CLIENT_STATUSES = 0xcd,
- PACKET_PLUGIN_MESSAGE = 0xfa,
- PACKET_ENCRYPTION_KEY_RESPONSE = 0xfc,
- PACKET_ENCRYPTION_KEY_REQUEST = 0xfd,
- PACKET_PING = 0xfe,
- PACKET_KICK = 0xff,
-
- // Synonyms:
- PACKET_DISCONNECT = PACKET_KICK,
-} ;
-
-
-
-
-enum
-{
- OBJECT_BOAT = 1,
- OBJECT_MINECART = 10,
- OBJECT_MINECART_STORAGE = 11,
- OBJECT_MINECART_POWERED = 12,
- OBJECT_MINECART_TNT = 13,
- OBJECT_MINECART_HOPPER = 14,
- OBJECT_TNT = 50,
- OBJECT_ENDERCRYSTAL = 51,
- OBJECT_ARROW = 60,
- OBJECT_SNOWBALL = 61,
- OBJECT_EGG = 62,
- OBJECT_FALLING_BLOCK = 70,
- OBJECT_EYE_OF_ENDER = 72,
- OBJECT_DRAGON_EGG = 74,
- OBJECT_FISHING_FLOAT = 90,
-} ;
-
-
-
-
-
AString PrintableAbsIntTriplet(int a_X, int a_Y, int a_Z, double a_Divisor = 32)
{
return Printf("<%d, %d, %d> ~ {%.02f, %.02f, %.02f}",
@@ -604,8 +498,10 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size)
// Not a complete packet yet
break;
}
- UInt32 PacketType;
+ UInt32 PacketType, PacketReadSoFar;
+ PacketReadSoFar = m_ClientBuffer.GetReadableSpace();
VERIFY(m_ClientBuffer.ReadVarInt(PacketType));
+ PacketReadSoFar -= m_ClientBuffer.GetReadableSpace();
Log("Decoding client's packets, there are now %d bytes in the queue; next packet is 0x%0x, %u bytes long", m_ClientBuffer.GetReadableSpace(), PacketType, PacketLen);
switch (m_ClientProtocolState)
{
@@ -614,7 +510,8 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size)
// No initial handshake received yet
switch (PacketType)
{
- case 0: HANDLE_CLIENT_READ(HandleClientHandshake); break;
+ case 0x00: HANDLE_CLIENT_READ(HandleClientHandshake()); break;
+ default: HANDLE_CLIENT_READ(HandleClientUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); break;
}
break;
} // case -1
@@ -624,8 +521,9 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size)
// Status query
switch (PacketType)
{
- case 0x00: HANDLE_CLIENT_READ(HandleClientStatusRequest); break;
- case 0x01: HANDLE_CLIENT_READ(HandleClientStatusPing); break;
+ case 0x00: HANDLE_CLIENT_READ(HandleClientStatusRequest()); break;
+ case 0x01: HANDLE_CLIENT_READ(HandleClientStatusPing()); break;
+ default: HANDLE_CLIENT_READ(HandleClientUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); break;
}
break;
}
@@ -635,8 +533,9 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size)
// Login
switch (PacketType)
{
- case 0x00: HANDLE_CLIENT_READ(HandleClientLoginStart); break;
- case 0x01: HANDLE_CLIENT_READ(HandleClientLoginEncryptionKeyResponse); break;
+ case 0x00: HANDLE_CLIENT_READ(HandleClientLoginStart()); break;
+ case 0x01: HANDLE_CLIENT_READ(HandleClientLoginEncryptionKeyResponse()); break;
+ default: HANDLE_CLIENT_READ(HandleClientUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); break;
}
break;
}
@@ -646,61 +545,38 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size)
// Game:
switch (PacketType)
{
- case PACKET_BLOCK_DIG: HANDLE_CLIENT_READ(HandleClientBlockDig); break;
- case PACKET_BLOCK_PLACE: HANDLE_CLIENT_READ(HandleClientBlockPlace); break;
- case PACKET_S_CHAT_MESSAGE: HANDLE_CLIENT_READ(HandleClientChatMessage); break;
- case PACKET_CLIENT_STATUSES: HANDLE_CLIENT_READ(HandleClientClientStatuses); break;
- case PACKET_CREATIVE_INVENTORY_ACTION: HANDLE_CLIENT_READ(HandleClientCreativeInventoryAction); break;
- case PACKET_DISCONNECT: HANDLE_CLIENT_READ(HandleClientDisconnect); break;
- case PACKET_ENTITY_ACTION: HANDLE_CLIENT_READ(HandleClientEntityAction); break;
- case PACKET_S_KEEPALIVE: HANDLE_CLIENT_READ(HandleClientKeepAlive); break;
- case PACKET_LOCALE_AND_VIEW: HANDLE_CLIENT_READ(HandleClientLocaleAndView); break;
- case PACKET_PING: HANDLE_CLIENT_READ(HandleClientPing); break;
- case PACKET_PLAYER_ABILITIES: HANDLE_CLIENT_READ(HandleClientPlayerAbilities); break;
- case PACKET_PLAYER_ANIMATION: HANDLE_CLIENT_READ(HandleClientAnimation); break;
- case PACKET_PLAYER_LOOK: HANDLE_CLIENT_READ(HandleClientPlayerLook); break;
- case PACKET_PLAYER_ON_GROUND: HANDLE_CLIENT_READ(HandleClientPlayerOnGround); break;
- case PACKET_PLAYER_POSITION: HANDLE_CLIENT_READ(HandleClientPlayerPosition); break;
- case PACKET_PLAYER_POSITION_LOOK: HANDLE_CLIENT_READ(HandleClientPlayerPositionLook); break;
- case PACKET_PLUGIN_MESSAGE: HANDLE_CLIENT_READ(HandleClientPluginMessage); break;
- case PACKET_SLOT_SELECT: HANDLE_CLIENT_READ(HandleClientSlotSelect); break;
- case PACKET_TAB_COMPLETION: HANDLE_CLIENT_READ(HandleClientTabCompletion); break;
- case PACKET_UPDATE_SIGN: HANDLE_CLIENT_READ(HandleClientUpdateSign); break;
- case PACKET_USE_ENTITY: HANDLE_CLIENT_READ(HandleClientUseEntity); break;
- case PACKET_WINDOW_CLICK: HANDLE_CLIENT_READ(HandleClientWindowClick); break;
- case PACKET_WINDOW_CLOSE: HANDLE_CLIENT_READ(HandleClientWindowClose); break;
+ case 0x00: HANDLE_CLIENT_READ(HandleClientKeepAlive()); break;
+ case 0x01: HANDLE_CLIENT_READ(HandleClientChatMessage()); break;
+ case 0x02: HANDLE_CLIENT_READ(HandleClientUseEntity()); break;
+ case 0x03: HANDLE_CLIENT_READ(HandleClientPlayerOnGround()); break;
+ case 0x04: HANDLE_CLIENT_READ(HandleClientPlayerPosition()); break;
+ case 0x05: HANDLE_CLIENT_READ(HandleClientPlayerLook()); break;
+ case 0x06: HANDLE_CLIENT_READ(HandleClientPlayerPositionLook()); break;
+ case 0x07: HANDLE_CLIENT_READ(HandleClientBlockDig()); break;
+ case 0x08: HANDLE_CLIENT_READ(HandleClientBlockPlace()); break;
+ case 0x09: HANDLE_CLIENT_READ(HandleClientSlotSelect()); break;
+ case 0x0a: HANDLE_CLIENT_READ(HandleClientAnimation()); break;
+ case 0x0b: HANDLE_CLIENT_READ(HandleClientEntityAction()); break;
+ case 0x0d: HANDLE_CLIENT_READ(HandleClientWindowClose()); break;
+ case 0x0e: HANDLE_CLIENT_READ(HandleClientWindowClick()); break;
+ case 0x10: HANDLE_CLIENT_READ(HandleClientCreativeInventoryAction()); break;
+ case 0x12: HANDLE_CLIENT_READ(HandleClientUpdateSign()); break;
+ case 0x13: HANDLE_CLIENT_READ(HandleClientPlayerAbilities()); break;
+ case 0x14: HANDLE_CLIENT_READ(HandleClientTabCompletion()); break;
+ case 0x15: HANDLE_CLIENT_READ(HandleClientLocaleAndView()); break;
+ case 0x16: HANDLE_CLIENT_READ(HandleClientClientStatuses()); break;
+ case 0x17: HANDLE_CLIENT_READ(HandleClientPluginMessage()); break;
+ default: HANDLE_CLIENT_READ(HandleClientUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); break;
}
break;
- } // case 2
+ } // case 3 - Game
default:
{
- // TODO: Move this elsewhere
- if (m_ClientState == csEncryptedUnderstood)
- {
- Log("****************** Unknown packet 0x%02x from the client while encrypted; continuing to relay blind only", PacketType);
- AString Data;
- m_ClientBuffer.ResetRead();
- m_ClientBuffer.ReadAll(Data);
- DataLog(Data.data(), Data.size(), "Current data in the client packet queue: %d bytes", Data.size());
- m_ClientState = csEncryptedUnknown;
- m_ClientBuffer.ResetRead();
- if (m_ServerState == csUnencrypted)
- {
- SERVERSEND(m_ClientBuffer);
- }
- else
- {
- SERVERENCRYPTSEND(m_ClientBuffer);
- }
- return true;
- }
- else
- {
- Log("Unknown packet 0x%02x from the client while unencrypted; aborting connection", PacketType);
- return false;
- }
- } // default
+ Log("Receiving server packets while in an unknown protocol state (%d)!", m_ClientProtocolState);
+ HANDLE_CLIENT_READ(HandleClientUnknownPacket(PacketType, PacketLen, PacketReadSoFar));
+ break;
+ }
} // switch (m_ProtocolState)
m_ClientBuffer.CommitRead();
} // while (true)
@@ -736,10 +612,22 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size)
)
{
// Not a complete packet yet
+ m_ServerBuffer.ResetRead();
+ break;
+ }
+ if (PacketLen == 0)
+ {
+ m_ServerBuffer.ResetRead();
+ AString All;
+ m_ServerBuffer.ReadAll(All);
+ DataLog(All.data(), All.size(), "====== Received a bad packet length? Inspect the contents below ======");
+ m_ServerBuffer.CommitRead(); // Try to recover by marking everything as read
break;
}
- UInt32 PacketType;
+ UInt32 PacketType, PacketReadSoFar;
+ PacketReadSoFar = m_ServerBuffer.GetReadableSpace();
VERIFY(m_ServerBuffer.ReadVarInt(PacketType));
+ PacketReadSoFar -= m_ServerBuffer.GetReadableSpace();
Log("Decoding server's packets, there are now %d bytes in the queue; next packet is 0x%0x, %u bytes long", m_ServerBuffer.GetReadableSpace(), PacketType, PacketLen);
LogFlush();
switch (m_ServerProtocolState)
@@ -747,6 +635,7 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size)
case -1:
{
Log("Receiving data from the server without an initial handshake message!");
+ HANDLE_SERVER_READ(HandleServerUnknownPacket(PacketType, PacketLen, PacketReadSoFar));
break;
}
@@ -755,8 +644,9 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size)
// Status query:
switch (PacketType)
{
- case 0: HANDLE_SERVER_READ(HandleServerStatusResponse); break;
- case 1: HANDLE_SERVER_READ(HandleServerStatusPing); break;
+ case 0x00: HANDLE_SERVER_READ(HandleServerStatusResponse()); break;
+ case 0x01: HANDLE_SERVER_READ(HandleServerStatusPing()); break;
+ default: HANDLE_SERVER_READ(HandleServerUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); break;
}
break;
}
@@ -766,9 +656,10 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size)
// Login:
switch (PacketType)
{
- case 0x00: HANDLE_SERVER_READ(HandleServerLoginDisconnect); break;
- case 0x01: HANDLE_SERVER_READ(HandleServerLoginEncryptionKeyRequest); break;
- case 0x02: HANDLE_SERVER_READ(HandleServerLoginSuccess); break;
+ case 0x00: HANDLE_SERVER_READ(HandleServerLoginDisconnect()); break;
+ case 0x01: HANDLE_SERVER_READ(HandleServerLoginEncryptionKeyRequest()); break;
+ case 0x02: HANDLE_SERVER_READ(HandleServerLoginSuccess()); break;
+ default: HANDLE_SERVER_READ(HandleServerUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); break;
}
break;
}
@@ -778,89 +669,69 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size)
// Game:
switch (PacketType)
{
- /*
- case 0x1b: HANDLE_SERVER_READ(HandleServerAttachEntity); break;
- case 0x24: HANDLE_SERVER_READ(HandleServerBlockAction); break;
- case 0x23: HANDLE_SERVER_READ(HandleServerBlockChange); break;
- case 0x2b: HANDLE_SERVER_READ(HandleServerChangeGameState); break;
- case 0x02: HANDLE_SERVER_READ(HandleServerChatMessage); break;
- case 0x0d: HANDLE_SERVER_READ(HandleServerCollectPickup); break;
- case 0x13: HANDLE_SERVER_READ(HandleServerDestroyEntities); break;
- */
- case PACKET_ENTITY: HANDLE_SERVER_READ(HandleServerEntity); break;
- case PACKET_ENTITY_EQUIPMENT: HANDLE_SERVER_READ(HandleServerEntityEquipment); break;
- case PACKET_ENTITY_HEAD_LOOK: HANDLE_SERVER_READ(HandleServerEntityHeadLook); break;
- case PACKET_ENTITY_LOOK: HANDLE_SERVER_READ(HandleServerEntityLook); break;
- case PACKET_ENTITY_METADATA: HANDLE_SERVER_READ(HandleServerEntityMetadata); break;
- case PACKET_ENTITY_PROPERTIES: HANDLE_SERVER_READ(HandleServerEntityProperties); break;
- case PACKET_ENTITY_RELATIVE_MOVE: HANDLE_SERVER_READ(HandleServerEntityRelativeMove); break;
- case PACKET_ENTITY_RELATIVE_MOVE_LOOK: HANDLE_SERVER_READ(HandleServerEntityRelativeMoveLook); break;
- case PACKET_ENTITY_STATUS: HANDLE_SERVER_READ(HandleServerEntityStatus); break;
- case PACKET_ENTITY_TELEPORT: HANDLE_SERVER_READ(HandleServerEntityTeleport); break;
- case PACKET_ENTITY_VELOCITY: HANDLE_SERVER_READ(HandleServerEntityVelocity); break;
- case PACKET_EXPLOSION: HANDLE_SERVER_READ(HandleServerExplosion); break;
- case PACKET_INCREMENT_STATISTIC: HANDLE_SERVER_READ(HandleServerIncrementStatistic); break;
- case PACKET_C_JOIN_GAME: HANDLE_SERVER_READ(HandleServerLogin); break;
- case PACKET_C_KEEPALIVE: HANDLE_SERVER_READ(HandleServerKeepAlive); break;
- case PACKET_KICK: HANDLE_SERVER_READ(HandleServerKick); break;
- case PACKET_MAP_CHUNK: HANDLE_SERVER_READ(HandleServerMapChunk); break;
- case PACKET_MAP_CHUNK_BULK: HANDLE_SERVER_READ(HandleServerMapChunkBulk); break;
- case PACKET_MULTI_BLOCK_CHANGE: HANDLE_SERVER_READ(HandleServerMultiBlockChange); break;
- case PACKET_NAMED_SOUND_EFFECT: HANDLE_SERVER_READ(HandleServerNamedSoundEffect); break;
- case PACKET_PLAYER_ABILITIES: HANDLE_SERVER_READ(HandleServerPlayerAbilities); break;
- case PACKET_PLAYER_ANIMATION: HANDLE_SERVER_READ(HandleServerPlayerAnimation); break;
- case PACKET_PLAYER_LIST_ITEM: HANDLE_SERVER_READ(HandleServerPlayerListItem); break;
- case PACKET_PLAYER_POSITION_LOOK: HANDLE_SERVER_READ(HandleServerPlayerPositionLook); break;
- case PACKET_PLUGIN_MESSAGE: HANDLE_SERVER_READ(HandleServerPluginMessage); break;
- case PACKET_SET_EXPERIENCE: HANDLE_SERVER_READ(HandleServerSetExperience); break;
- case PACKET_SET_SLOT: HANDLE_SERVER_READ(HandleServerSetSlot); break;
- case PACKET_SLOT_SELECT: HANDLE_SERVER_READ(HandleServerSlotSelect); break;
- case PACKET_SOUND_EFFECT: HANDLE_SERVER_READ(HandleServerSoundEffect); break;
- case PACKET_SPAWN_MOB: HANDLE_SERVER_READ(HandleServerSpawnMob); break;
- case PACKET_SPAWN_NAMED_ENTITY: HANDLE_SERVER_READ(HandleServerSpawnNamedEntity); break;
- case PACKET_SPAWN_OBJECT_VEHICLE: HANDLE_SERVER_READ(HandleServerSpawnObjectVehicle); break;
- case PACKET_SPAWN_PAINTING: HANDLE_SERVER_READ(HandleServerSpawnPainting); break;
- case PACKET_SPAWN_PICKUP: HANDLE_SERVER_READ(HandleServerSpawnPickup); break;
- case PACKET_SPAWN_POSITION: HANDLE_SERVER_READ(HandleServerCompass); break;
- case PACKET_TAB_COMPLETION: HANDLE_SERVER_READ(HandleServerTabCompletion); break;
- case PACKET_TIME_UPDATE: HANDLE_SERVER_READ(HandleServerTimeUpdate); break;
- case PACKET_UPDATE_HEALTH: HANDLE_SERVER_READ(HandleServerUpdateHealth); break;
- case PACKET_UPDATE_SIGN: HANDLE_SERVER_READ(HandleServerUpdateSign); break;
- case PACKET_UPDATE_TILE_ENTITY: HANDLE_SERVER_READ(HandleServerUpdateTileEntity); break;
- case PACKET_WINDOW_CLOSE: HANDLE_SERVER_READ(HandleServerWindowClose); break;
- case PACKET_WINDOW_CONTENTS: HANDLE_SERVER_READ(HandleServerWindowContents); break;
- case PACKET_WINDOW_OPEN: HANDLE_SERVER_READ(HandleServerWindowOpen); break;
+ case 0x00: HANDLE_SERVER_READ(HandleServerKeepAlive()); break;
+ case 0x01: HANDLE_SERVER_READ(HandleServerJoinGame()); break;
+ case 0x02: HANDLE_SERVER_READ(HandleServerChatMessage()); break;
+ case 0x03: HANDLE_SERVER_READ(HandleServerTimeUpdate()); break;
+ case 0x04: HANDLE_SERVER_READ(HandleServerEntityEquipment()); break;
+ case 0x05: HANDLE_SERVER_READ(HandleServerCompass()); break;
+ case 0x06: HANDLE_SERVER_READ(HandleServerUpdateHealth()); break;
+ case 0x07: HANDLE_SERVER_READ(HandleServerRespawn()); break;
+ case 0x08: HANDLE_SERVER_READ(HandleServerPlayerPositionLook()); break;
+ case 0x09: HANDLE_SERVER_READ(HandleServerSlotSelect()); break;
+ case 0x0a: HANDLE_SERVER_READ(HandleServerUseBed()); break;
+ case 0x0b: HANDLE_SERVER_READ(HandleServerPlayerAnimation()); break;
+ case 0x0c: HANDLE_SERVER_READ(HandleServerSpawnNamedEntity()); break;
+ case 0x0d: HANDLE_SERVER_READ(HandleServerCollectPickup()); break;
+ case 0x0e: HANDLE_SERVER_READ(HandleServerSpawnObjectVehicle()); break;
+ case 0x0f: HANDLE_SERVER_READ(HandleServerSpawnMob()); break;
+ case 0x10: HANDLE_SERVER_READ(HandleServerSpawnPainting()); break;
+ case 0x11: HANDLE_SERVER_READ(HandleServerSpawnExperienceOrbs()); break;
+ case 0x12: HANDLE_SERVER_READ(HandleServerEntityVelocity()); break;
+ case 0x13: HANDLE_SERVER_READ(HandleServerDestroyEntities()); break;
+ case 0x14: HANDLE_SERVER_READ(HandleServerEntity()); break;
+ case 0x15: HANDLE_SERVER_READ(HandleServerEntityRelativeMove()); break;
+ case 0x16: HANDLE_SERVER_READ(HandleServerEntityLook()); break;
+ case 0x17: HANDLE_SERVER_READ(HandleServerEntityRelativeMoveLook()); break;
+ case 0x18: HANDLE_SERVER_READ(HandleServerEntityTeleport()); break;
+ case 0x19: HANDLE_SERVER_READ(HandleServerEntityHeadLook()); break;
+ case 0x1a: HANDLE_SERVER_READ(HandleServerEntityStatus()); break;
+ case 0x1b: HANDLE_SERVER_READ(HandleServerAttachEntity()); break;
+ case 0x1c: HANDLE_SERVER_READ(HandleServerEntityMetadata()); break;
+ case 0x1f: HANDLE_SERVER_READ(HandleServerSetExperience()); break;
+ case 0x20: HANDLE_SERVER_READ(HandleServerEntityProperties()); break;
+ case 0x21: HANDLE_SERVER_READ(HandleServerMapChunk()); break;
+ case 0x22: HANDLE_SERVER_READ(HandleServerMultiBlockChange()); break;
+ case 0x23: HANDLE_SERVER_READ(HandleServerBlockChange()); break;
+ case 0x24: HANDLE_SERVER_READ(HandleServerBlockAction()); break;
+ case 0x26: HANDLE_SERVER_READ(HandleServerMapChunkBulk()); break;
+ case 0x27: HANDLE_SERVER_READ(HandleServerExplosion()); break;
+ case 0x28: HANDLE_SERVER_READ(HandleServerSoundEffect()); break;
+ case 0x29: HANDLE_SERVER_READ(HandleServerNamedSoundEffect()); break;
+ case 0x2b: HANDLE_SERVER_READ(HandleServerChangeGameState()); break;
+ case 0x2d: HANDLE_SERVER_READ(HandleServerWindowOpen()); break;
+ case 0x2e: HANDLE_SERVER_READ(HandleServerWindowClose()); break;
+ case 0x2f: HANDLE_SERVER_READ(HandleServerSetSlot()); break;
+ case 0x30: HANDLE_SERVER_READ(HandleServerWindowContents()); break;
+ case 0x33: HANDLE_SERVER_READ(HandleServerUpdateSign()); break;
+ case 0x35: HANDLE_SERVER_READ(HandleServerUpdateTileEntity()); break;
+ case 0x37: HANDLE_SERVER_READ(HandleServerStatistics()); break;
+ case 0x38: HANDLE_SERVER_READ(HandleServerPlayerListItem()); break;
+ case 0x39: HANDLE_SERVER_READ(HandleServerPlayerAbilities()); break;
+ case 0x3a: HANDLE_SERVER_READ(HandleServerTabCompletion()); break;
+ case 0x3f: HANDLE_SERVER_READ(HandleServerPluginMessage()); break;
+ case 0x40: HANDLE_SERVER_READ(HandleServerKick()); break;
+ default: HANDLE_SERVER_READ(HandleServerUnknownPacket(PacketType, PacketLen, PacketReadSoFar)); break;
} // switch (PacketType)
break;
- } // case 2
+ } // case 3 - Game
// TODO: Move this elsewhere
default:
{
- if (m_ServerState == csEncryptedUnderstood)
- {
- Log("********************** Unknown packet 0x%02x from the server while encrypted; continuing to relay blind only", PacketType);
- AString Data;
- m_ServerBuffer.ResetRead();
- m_ServerBuffer.ReadAll(Data);
- DataLog(Data.data(), Data.size(), "Current data in the server packet queue: %d bytes", Data.size());
- m_ServerState = csEncryptedUnknown;
- m_ServerBuffer.ResetRead();
- if (m_ClientState == csUnencrypted)
- {
- CLIENTSEND(m_ServerBuffer);
- }
- else
- {
- CLIENTENCRYPTSEND(m_ServerBuffer);
- }
- return true;
- }
- else
- {
- Log("Unknown packet 0x%02x from the server while unencrypted; aborting connection", PacketType);
- return false;
- }
+ Log("Received a packet from the server while in an unknown state: %d", m_ServerProtocolState);
+ HANDLE_SERVER_READ(HandleServerUnknownPacket(PacketType, PacketLen, PacketReadSoFar));
+ break;
}
} // switch (m_ProtocolState)
@@ -1006,7 +877,7 @@ bool cConnection::HandleClientBlockPlace(void)
bool cConnection::HandleClientChatMessage(void)
{
- HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Message);
+ HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Message);
Log("Received a PACKET_CHAT_MESSAGE from the client:");
Log(" Message = \"%s\"", Message.c_str());
COPY_TO_SERVER();
@@ -1052,7 +923,7 @@ bool cConnection::HandleClientCreativeInventoryAction(void)
bool cConnection::HandleClientDisconnect(void)
{
- HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Reason);
+ HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Reason);
Log("Received a PACKET_DISCONNECT from the client:");
Log(" Reason = \"%s\"", Reason.c_str());
COPY_TO_SERVER();
@@ -1067,11 +938,11 @@ bool cConnection::HandleClientEntityAction(void)
{
HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, PlayerID);
HANDLE_CLIENT_PACKET_READ(ReadByte, Byte, ActionType);
- HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, UnknownHorseVal);
+ HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, HorseJumpBoost);
Log("Received a PACKET_ENTITY_ACTION from the client:");
Log(" PlayerID = %d", PlayerID);
Log(" ActionType = %d", ActionType);
- Log(" UnknownHorseVal = %d (0x%08x)", UnknownHorseVal, UnknownHorseVal);
+ Log(" HorseJumpBoost = %d (0x%08x)", HorseJumpBoost, HorseJumpBoost);
COPY_TO_SERVER();
return true;
}
@@ -1094,11 +965,12 @@ bool cConnection::HandleClientKeepAlive(void)
bool cConnection::HandleClientLocaleAndView(void)
{
- HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Locale);
- HANDLE_CLIENT_PACKET_READ(ReadChar, char, ViewDistance);
- HANDLE_CLIENT_PACKET_READ(ReadChar, char, ChatFlags);
- HANDLE_CLIENT_PACKET_READ(ReadChar, char, Difficulty);
- HANDLE_CLIENT_PACKET_READ(ReadChar, char, ShowCape);
+ HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Locale);
+ HANDLE_CLIENT_PACKET_READ(ReadChar, char, ViewDistance);
+ HANDLE_CLIENT_PACKET_READ(ReadChar, char, ChatFlags);
+ HANDLE_CLIENT_PACKET_READ(ReadChar, char, Unused);
+ HANDLE_CLIENT_PACKET_READ(ReadChar, char, Difficulty);
+ HANDLE_CLIENT_PACKET_READ(ReadChar, char, ShowCape);
Log("Received a PACKET_LOCALE_AND_VIEW from the client");
COPY_TO_SERVER();
return true;
@@ -1123,7 +995,7 @@ bool cConnection::HandleClientPing(void)
bool cConnection::HandleClientPlayerAbilities(void)
{
- HANDLE_CLIENT_PACKET_READ(ReadChar, char, Flags);
+ HANDLE_CLIENT_PACKET_READ(ReadChar, char, Flags);
HANDLE_CLIENT_PACKET_READ(ReadBEFloat, float, FlyingSpeed);
HANDLE_CLIENT_PACKET_READ(ReadBEFloat, float, WalkingSpeed);
Log("Receives a PACKET_PLAYER_ABILITIES from the client:");
@@ -1154,7 +1026,7 @@ bool cConnection::HandleClientPlayerLook(void)
bool cConnection::HandleClientPlayerOnGround(void)
{
- HANDLE_CLIENT_PACKET_READ(ReadChar, char, OnGround);
+ HANDLE_CLIENT_PACKET_READ(ReadChar, char, OnGround);
Log("Received a PACKET_PLAYER_ON_GROUND from the client");
COPY_TO_SERVER();
return true;
@@ -1167,8 +1039,8 @@ bool cConnection::HandleClientPlayerOnGround(void)
bool cConnection::HandleClientPlayerPosition(void)
{
HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, PosX);
- HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, Stance);
HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, PosY);
+ HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, Stance);
HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, PosZ);
HANDLE_CLIENT_PACKET_READ(ReadChar, char, IsOnGround);
Log("Received a PACKET_PLAYER_POSITION from the client");
@@ -1186,8 +1058,8 @@ bool cConnection::HandleClientPlayerPosition(void)
bool cConnection::HandleClientPlayerPositionLook(void)
{
HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, PosX);
- HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, Stance);
HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, PosY);
+ HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, Stance);
HANDLE_CLIENT_PACKET_READ(ReadBEDouble, double, PosZ);
HANDLE_CLIENT_PACKET_READ(ReadBEFloat, float, Yaw);
HANDLE_CLIENT_PACKET_READ(ReadBEFloat, float, Pitch);
@@ -1195,7 +1067,7 @@ bool cConnection::HandleClientPlayerPositionLook(void)
Log("Received a PACKET_PLAYER_POSITION_LOOK from the client");
Log(" Pos = {%.03f, %.03f, %.03f}", PosX, PosY, PosZ);
Log(" Stance = %.03f", Stance);
- Log(" Y, P = %.03f, %.03f", Yaw, Pitch);
+ Log(" Yaw, Pitch = <%.03f, %.03f>", Yaw, Pitch);
Log(" IsOnGround = %s", IsOnGround ? "true" : "false");
COPY_TO_SERVER();
@@ -1208,7 +1080,7 @@ bool cConnection::HandleClientPlayerPositionLook(void)
bool cConnection::HandleClientPluginMessage(void)
{
- HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, ChannelName);
+ HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, ChannelName);
HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, Length);
AString Data;
if (!m_ClientBuffer.ReadString(Data, Length))
@@ -1265,7 +1137,7 @@ bool cConnection::HandleClientStatusRequest(void)
bool cConnection::HandleClientTabCompletion(void)
{
- HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Query);
+ HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Query);
Log("Received a PACKET_TAB_COMPLETION query from the client");
Log(" Query = \"%s\"", Query.c_str());
COPY_TO_SERVER();
@@ -1278,13 +1150,13 @@ bool cConnection::HandleClientTabCompletion(void)
bool cConnection::HandleClientUpdateSign(void)
{
- HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, BlockX);
- HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, BlockY);
- HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, BlockZ);
- HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Line1);
- HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Line2);
- HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Line3);
- HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Line4);
+ HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, BlockX);
+ HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, BlockY);
+ HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, BlockZ);
+ HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Line1);
+ HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Line2);
+ HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Line3);
+ HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, Line4);
Log("Received a PACKET_UPDATE_SIGN from the client:");
Log(" Block = {%d, %d, %d}", BlockX, BlockY, BlockZ);
Log(" Lines = \"%s\", \"%s\", \"%s\", \"%s\"", Line1.c_str(), Line2.c_str(), Line3.c_str(), Line4.c_str());
@@ -1298,11 +1170,9 @@ bool cConnection::HandleClientUpdateSign(void)
bool cConnection::HandleClientUseEntity(void)
{
- HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, PlayerID);
HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, EntityID);
HANDLE_CLIENT_PACKET_READ(ReadChar, char, MouseButton);
Log("Received a PACKET_USE_ENTITY from the client:");
- Log(" PlayerID = %d", PlayerID);
Log(" EntityID = %d", EntityID);
Log(" MouseButton = %d", MouseButton);
COPY_TO_SERVER();
@@ -1317,9 +1187,9 @@ bool cConnection::HandleClientWindowClick(void)
{
HANDLE_CLIENT_PACKET_READ(ReadChar, char, WindowID);
HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, SlotNum);
- HANDLE_CLIENT_PACKET_READ(ReadChar, char, IsRightClick);
+ HANDLE_CLIENT_PACKET_READ(ReadChar, char, Button);
HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, TransactionID);
- HANDLE_CLIENT_PACKET_READ(ReadChar, char, IsShiftClick);
+ HANDLE_CLIENT_PACKET_READ(ReadChar, char, Mode);
AString Item;
if (!ParseSlot(m_ClientBuffer, Item))
{
@@ -1328,7 +1198,7 @@ bool cConnection::HandleClientWindowClick(void)
Log("Received a PACKET_WINDOW_CLICK from the client");
Log(" WindowID = %d", WindowID);
Log(" SlotNum = %d", SlotNum);
- Log(" IsRclk = %d, IsShift = %d", IsRightClick, IsShiftClick);
+ Log(" Button = %d, Mode = %d", Button, Mode);
Log(" TransactionID = 0x%x", TransactionID);
Log(" ClickedItem = %s", Item.c_str());
COPY_TO_SERVER();
@@ -1352,6 +1222,22 @@ bool cConnection::HandleClientWindowClose(void)
+bool cConnection::HandleClientUnknownPacket(UInt32 a_PacketType, UInt32 a_PacketLen, UInt32 a_PacketReadSoFar)
+{
+ AString Data;
+ if (!m_ClientBuffer.ReadString(Data, a_PacketLen - a_PacketReadSoFar))
+ {
+ return false;
+ }
+ DataLog(Data.data(), Data.size(), "****************** Unknown packet 0x%x from the client; relaying and ignoring", a_PacketType);
+ COPY_TO_SERVER();
+ return true;
+}
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// packet handling, server-side, login:
@@ -1449,16 +1335,16 @@ bool cConnection::HandleServerAttachEntity(void)
bool cConnection::HandleServerBlockAction(void)
{
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX);
- HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockY);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ);
- HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Byte1);
- HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Byte2);
- HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockID);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX);
+ HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockY);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ);
+ HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Byte1);
+ HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Byte2);
+ HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, BlockID);
Log("Received a PACKET_BLOCK_ACTION from the server:");
Log(" Pos = {%d, %d, %d}", BlockX, BlockY, BlockZ);
Log(" Bytes = (%d, %d) == (0x%x, 0x%x)", Byte1, Byte2, Byte1, Byte2);
- Log(" BlockID = %d", BlockID);
+ Log(" BlockID = %u", BlockID);
COPY_TO_CLIENT();
return true;
}
@@ -1469,11 +1355,11 @@ bool cConnection::HandleServerBlockAction(void)
bool cConnection::HandleServerBlockChange(void)
{
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX);
- HANDLE_SERVER_PACKET_READ(ReadByte, Byte, BlockY);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ);
- HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockType);
- HANDLE_SERVER_PACKET_READ(ReadChar, char, BlockMeta);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX);
+ HANDLE_SERVER_PACKET_READ(ReadByte, Byte, BlockY);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ);
+ HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, BlockType);
+ HANDLE_SERVER_PACKET_READ(ReadChar, char, BlockMeta);
Log("Received a PACKET_BLOCK_CHANGE from the server");
COPY_TO_CLIENT();
return true;
@@ -1485,11 +1371,11 @@ bool cConnection::HandleServerBlockChange(void)
bool cConnection::HandleServerChangeGameState(void)
{
- HANDLE_SERVER_PACKET_READ(ReadChar, char, Reason);
- HANDLE_SERVER_PACKET_READ(ReadChar, char, Data);
+ HANDLE_SERVER_PACKET_READ(ReadChar, char, Reason);
+ HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Data);
Log("Received a PACKET_CHANGE_GAME_STATE from the server:");
Log(" Reason = %d", Reason);
- Log(" Data = %d", Data);
+ Log(" Data = %f", Data);
COPY_TO_CLIENT();
return true;
}
@@ -1500,7 +1386,7 @@ bool cConnection::HandleServerChangeGameState(void)
bool cConnection::HandleServerChatMessage(void)
{
- HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Message);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Message);
Log("Received a PACKET_CHAT_MESSAGE from the server:");
Log(" Message = \"%s\"", Message.c_str());
COPY_TO_CLIENT();
@@ -1656,20 +1542,18 @@ bool cConnection::HandleServerEntityProperties(void)
for (int i = 0; i < Count; i++)
{
- HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Key);
- HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, Value);
- Log(" \"%s\" = %f", Key.c_str(), Value);
- } // for i
-
- HANDLE_SERVER_PACKET_READ(ReadBEShort, short, ListLength);
- Log(" ListLength = %d", ListLength);
- for (int i = 0; i < ListLength; i++)
- {
- HANDLE_SERVER_PACKET_READ(ReadBEInt64, Int64, UUIDHi);
- HANDLE_SERVER_PACKET_READ(ReadBEInt64, Int64, UUIDLo);
- HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, DblVal);
- HANDLE_SERVER_PACKET_READ(ReadByte, Byte, ByteVal);
- Log(" [%d] = {0x%08llx%08llx, %f, %i}", i, UUIDHi, UUIDLo, DblVal, ByteVal);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Key);
+ HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, Value);
+ HANDLE_SERVER_PACKET_READ(ReadBEShort, short, ListLength);
+ Log(" \"%s\" = %f; %d modifiers", Key.c_str(), Value, ListLength);
+ for (short j = 0; j < ListLength; j++)
+ {
+ HANDLE_SERVER_PACKET_READ(ReadBEInt64, Int64, UUIDHi);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt64, Int64, UUIDLo);
+ HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, DblVal);
+ HANDLE_SERVER_PACKET_READ(ReadByte, Byte, ByteVal);
+ Log(" [%d] = {0x%08llx%08llx, %f, %u}", j, UUIDHi, UUIDLo, DblVal, ByteVal);
+ }
} // for i
COPY_TO_CLIENT();
return true;
@@ -1734,7 +1618,7 @@ bool cConnection::HandleServerEntityStatus(void)
bool cConnection::HandleServerEntityTeleport(void)
{
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, AbsX);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, AbsY);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, AbsZ);
@@ -1742,7 +1626,7 @@ bool cConnection::HandleServerEntityTeleport(void)
HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch);
Log("Received a PACKET_ENTITY_TELEPORT from the server:");
Log(" EntityID = %d", EntityID);
- Log(" Pos = (%d, %d, %d) ~ {%.02f, %.02f, %.02f}", AbsX, AbsY, AbsZ, (double)AbsX / 32, (double)AbsY / 32, (double)AbsZ / 32);
+ Log(" Pos = %s", PrintableAbsIntTriplet(AbsX, AbsY, AbsZ).c_str());
Log(" Yaw = %d", Yaw);
Log(" Pitch = %d", Pitch);
COPY_TO_CLIENT();
@@ -1772,11 +1656,11 @@ bool cConnection::HandleServerEntityVelocity(void)
bool cConnection::HandleServerExplosion(void)
{
- HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, PosX);
- HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, PosY);
- HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, PosZ);
- HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Force);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, NumRecords);
+ HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosX);
+ HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosY);
+ HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosZ);
+ HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Force);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, NumRecords);
struct sCoords
{
int x, y, z;
@@ -1829,6 +1713,29 @@ bool cConnection::HandleServerIncrementStatistic(void)
+bool cConnection::HandleServerJoinGame(void)
+{
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID);
+ HANDLE_SERVER_PACKET_READ(ReadChar, char, GameMode);
+ HANDLE_SERVER_PACKET_READ(ReadChar, char, Dimension);
+ HANDLE_SERVER_PACKET_READ(ReadChar, char, Difficulty);
+ HANDLE_SERVER_PACKET_READ(ReadChar, char, MaxPlayers);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, LevelType);
+ Log("Received a PACKET_LOGIN from the server:");
+ Log(" EntityID = %d", EntityID);
+ Log(" GameMode = %d", GameMode);
+ Log(" Dimension = %d", Dimension);
+ Log(" Difficulty = %d", Difficulty);
+ Log(" MaxPlayers = %d", MaxPlayers);
+ Log(" LevelType = \"%s\"", LevelType.c_str());
+ COPY_TO_CLIENT();
+ return true;
+}
+
+
+
+
+
bool cConnection::HandleServerKeepAlive(void)
{
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PingID);
@@ -1844,7 +1751,7 @@ bool cConnection::HandleServerKeepAlive(void)
bool cConnection::HandleServerKick(void)
{
- HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Reason);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Reason);
Log("Received PACKET_KICK from the SERVER:");
if (m_HasClientPinged)
{
@@ -1914,31 +1821,6 @@ bool cConnection::HandleServerKick(void)
-bool cConnection::HandleServerLogin(void)
-{
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID);
- HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, LevelType);
- HANDLE_SERVER_PACKET_READ(ReadChar, char, GameMode);
- HANDLE_SERVER_PACKET_READ(ReadChar, char, Dimension);
- HANDLE_SERVER_PACKET_READ(ReadChar, char, Difficulty);
- HANDLE_SERVER_PACKET_READ(ReadChar, char, Unused);
- HANDLE_SERVER_PACKET_READ(ReadChar, char, MaxPlayers);
- Log("Received a PACKET_LOGIN from the server:");
- Log(" EntityID = %d", EntityID);
- Log(" LevelType = \"%s\"", LevelType.c_str());
- Log(" GameMode = %d", GameMode);
- Log(" Dimension = %d", Dimension);
- Log(" Difficulty = %d", Difficulty);
- Log(" Unused = %d", Unused);
- Log(" MaxPlayers = %d", MaxPlayers);
- COPY_TO_CLIENT();
- return true;
-}
-
-
-
-
-
bool cConnection::HandleServerMapChunk(void)
{
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkX);
@@ -2018,6 +1900,7 @@ bool cConnection::HandleServerMapChunkBulk(void)
// TODO: Save the compressed data into a file for later analysis
COPY_TO_CLIENT();
+ Sleep(50);
return true;
}
@@ -2049,15 +1932,15 @@ bool cConnection::HandleServerMultiBlockChange(void)
bool cConnection::HandleServerNamedSoundEffect(void)
{
- HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, SoundName);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ);
- HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Volume);
- HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, SoundName);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ);
+ HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Volume);
+ HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch);
Log("Received a PACKET_NAMED_SOUND_EFFECT from the server:");
Log(" SoundName = \"%s\"", SoundName.c_str());
- Log(" Pos = (%d, %d, %d) ~ {%d, %d, %d}", PosX, PosY, PosZ, PosX / 8, PosY / 8, PosZ / 8);
+ Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ, 8).c_str());
Log(" Volume = %f", Volume);
Log(" Pitch = %d", Pitch);
COPY_TO_CLIENT();
@@ -2087,10 +1970,10 @@ bool cConnection::HandleServerPlayerAbilities(void)
bool cConnection::HandleServerPlayerAnimation(void)
{
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PlayerID);
- HANDLE_SERVER_PACKET_READ(ReadByte, Byte, AnimationID);
+ HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, PlayerID);
+ HANDLE_SERVER_PACKET_READ(ReadByte, Byte, AnimationID);
Log("Received a PACKET_PLAYER_ANIMATION from the server:");
- Log(" PlayerID: %d (0x%x)", PlayerID, PlayerID);
+ Log(" PlayerID: %u (0x%x)", PlayerID, PlayerID);
Log(" Animation: %d", AnimationID);
COPY_TO_CLIENT();
return true;
@@ -2102,7 +1985,7 @@ bool cConnection::HandleServerPlayerAnimation(void)
bool cConnection::HandleServerPlayerListItem(void)
{
- HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, PlayerName);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, PlayerName);
HANDLE_SERVER_PACKET_READ(ReadChar, char, IsOnline);
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, Ping);
Log("Received a PACKET_PLAYERLIST_ITEM from the server:");
@@ -2119,7 +2002,6 @@ bool cConnection::HandleServerPlayerListItem(void)
bool cConnection::HandleServerPlayerPositionLook(void)
{
HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, PosX);
- HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, Stance);
HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, PosY);
HANDLE_SERVER_PACKET_READ(ReadBEDouble, double, PosZ);
HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Yaw);
@@ -2139,7 +2021,7 @@ bool cConnection::HandleServerPlayerPositionLook(void)
bool cConnection::HandleServerPluginMessage(void)
{
- HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, ChannelName);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, ChannelName);
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, Length);
AString Data;
if (!m_ServerBuffer.ReadString(Data, Length))
@@ -2149,7 +2031,26 @@ bool cConnection::HandleServerPluginMessage(void)
Log("Received a PACKET_PLUGIN_MESSAGE from the server");
Log(" ChannelName = \"%s\"", ChannelName.c_str());
DataLog(Data.data(), Length, " Data: %d bytes", Length);
- COPY_TO_SERVER();
+ COPY_TO_CLIENT();
+ return true;
+}
+
+
+
+
+
+bool cConnection::HandleServerRespawn(void)
+{
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, Dimension);
+ HANDLE_SERVER_PACKET_READ(ReadChar, char, Difficulty);
+ HANDLE_SERVER_PACKET_READ(ReadChar, char, GameMode);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, LevelType);
+ Log("Received a respawn packet from the server:");
+ Log(" Dimension = %d", Dimension);
+ Log(" Difficulty = %d", Difficulty);
+ Log(" GameMode = %d", GameMode);
+ Log(" LevelType = \"%s\"", LevelType.c_str());
+ COPY_TO_CLIENT();
return true;
}
@@ -2197,7 +2098,7 @@ bool cConnection::HandleServerSetSlot(void)
bool cConnection::HandleServerSlotSelect(void)
{
- HANDLE_SERVER_PACKET_READ(ReadBEShort, short, SlotNum);
+ HANDLE_SERVER_PACKET_READ(ReadByte, Byte, SlotNum);
Log("Received a PACKET_SLOT_SELECT from the server:");
Log(" SlotNum = %d", SlotNum);
COPY_TO_CLIENT();
@@ -2229,6 +2130,25 @@ bool cConnection::HandleServerSoundEffect(void)
+bool cConnection::HandleServerSpawnExperienceOrbs(void)
+{
+ HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ);
+ HANDLE_SERVER_PACKET_READ(ReadBEShort, short, Count);
+ Log("Received a SPAWN_EXPERIENCE_ORBS packet from the server:");
+ Log(" EntityID = %u (0x%x)", EntityID, EntityID);
+ Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str());
+ Log(" Count = %d", Count);
+ COPY_TO_CLIENT();
+ return true;
+}
+
+
+
+
+
bool cConnection::HandleServerSpawnMob(void)
{
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID);
@@ -2267,14 +2187,15 @@ bool cConnection::HandleServerSpawnMob(void)
bool cConnection::HandleServerSpawnNamedEntity(void)
{
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID);
- HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, EntityName);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ);
- HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw);
- HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch);
- HANDLE_SERVER_PACKET_READ(ReadBEShort, short, CurrentItem);
+ HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, EntityUUID);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, EntityName);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ);
+ HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw);
+ HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch);
+ HANDLE_SERVER_PACKET_READ(ReadBEShort, short, CurrentItem);
AString Metadata;
if (!ParseMetadata(m_ServerBuffer, Metadata))
{
@@ -2283,7 +2204,8 @@ bool cConnection::HandleServerSpawnNamedEntity(void)
AString HexDump;
CreateHexDump(HexDump, Metadata.data(), Metadata.size(), 32);
Log("Received a PACKET_SPAWN_NAMED_ENTITY from the server:");
- Log(" EntityID = %d (0x%x)", EntityID, EntityID);
+ Log(" EntityID = %u (0x%x)", EntityID, EntityID);
+ Log(" UUID = %s", EntityUUID.c_str());
Log(" Name = %s", EntityName.c_str());
Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str());
Log(" Rotation = <yaw %d, pitch %d>", Yaw, Pitch);
@@ -2307,7 +2229,9 @@ bool cConnection::HandleServerSpawnObjectVehicle(void)
m_ServerBuffer.ResetRead();
m_ServerBuffer.ReadAll(Buffer);
m_ServerBuffer.ResetRead();
- m_ServerBuffer.SkipRead(1);
+ UInt32 PacketLen, PacketType;
+ m_ServerBuffer.ReadVarInt(PacketLen);
+ m_ServerBuffer.ReadVarInt(PacketType);
if (Buffer.size() > 128)
{
// Only log up to 128 bytes
@@ -2316,14 +2240,14 @@ bool cConnection::HandleServerSpawnObjectVehicle(void)
DataLog(Buffer.data(), Buffer.size(), "Buffer while parsing the PACKET_SPAWN_OBJECT_VEHICLE packet (%d bytes):", Buffer.size());
#endif // _DEBUG
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID);
- HANDLE_SERVER_PACKET_READ(ReadChar, char, ObjType);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ);
- HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw);
- HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, DataIndicator);
+ HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID);
+ HANDLE_SERVER_PACKET_READ(ReadByte, Byte, ObjType);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ);
+ HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch);
+ HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, DataIndicator);
AString ExtraData;
short VelocityX, VelocityY, VelocityZ;
if (DataIndicator != 0)
@@ -2356,7 +2280,7 @@ bool cConnection::HandleServerSpawnObjectVehicle(void)
*/
}
Log("Received a PACKET_SPAWN_OBJECT_VEHICLE from the server:");
- Log(" EntityID = %d (0x%x)", EntityID, EntityID);
+ Log(" EntityID = %u (0x%x)", EntityID, EntityID);
Log(" ObjType = %d (0x%x)", ObjType, ObjType);
Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str());
Log(" Rotation = <yaw %d, pitch %d>", Yaw, Pitch);
@@ -2376,14 +2300,14 @@ bool cConnection::HandleServerSpawnObjectVehicle(void)
bool cConnection::HandleServerSpawnPainting(void)
{
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID);
- HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, ImageName);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ);
- HANDLE_SERVER_PACKET_READ(ReadBEInt, int, Direction);
+ HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, ImageName);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, Direction);
Log("Received a PACKET_SPAWN_PAINTING from the server:");
- Log(" EntityID = %d", EntityID);
+ Log(" EntityID = %u", EntityID);
Log(" ImageName = \"%s\"", ImageName.c_str());
Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str());
Log(" Direction = %d", Direction);
@@ -2422,6 +2346,21 @@ bool cConnection::HandleServerSpawnPickup(void)
+bool cConnection::HandleServerStatistics(void)
+{
+ HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, NumEntries);
+ for (UInt32 i = 0; i < NumEntries; i++)
+ {
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, StatName);
+ HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, StatValue);
+ }
+ COPY_TO_CLIENT();
+ return true;
+}
+
+
+
+
bool cConnection::HandleServerStatusPing(void)
{
HANDLE_SERVER_PACKET_READ(ReadBEInt64, Int64, Time);
@@ -2464,7 +2403,8 @@ bool cConnection::HandleServerStatusResponse(void)
bool cConnection::HandleServerTabCompletion(void)
{
- HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Results);
+ HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, NumResults);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Results);
Log("Received a PACKET_TAB_COMPLETION from the server, results given:");
// Parse the zero-terminated list of results:
@@ -2522,10 +2462,10 @@ bool cConnection::HandleServerUpdateSign(void)
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX);
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, BlockY);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ);
- HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Line1);
- HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Line2);
- HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Line3);
- HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Line4);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Line1);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Line2);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Line3);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Line4);
Log("Received a PACKET_UPDATE_SIGN from the server:");
Log(" Block = {%d, %d, %d}", BlockX, BlockY, BlockZ);
Log(" Lines = \"%s\", \"%s\", \"%s\", \"%s\"", Line1.c_str(), Line2.c_str(), Line3.c_str(), Line4.c_str());
@@ -2552,7 +2492,24 @@ bool cConnection::HandleServerUpdateTileEntity(void)
Log("Received a PACKET_UPDATE_TILE_ENTITY from the server:");
Log(" Block = {%d, %d, %d}", BlockX, BlockY, BlockZ);
Log(" Action = %d", Action);
- DataLog(Data.data(), Data.size(), " Data (%d bytes)", Data.size());
+ DataLog(Data.data(), Data.size(), " Data (%u bytes)", Data.size());
+ COPY_TO_CLIENT();
+ return true;
+}
+
+
+
+
+
+bool cConnection::HandleServerUseBed(void)
+{
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BedX);
+ HANDLE_SERVER_PACKET_READ(ReadByte, Byte, BedY);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BedZ);
+ Log("Received a use bed packet from the server:");
+ Log(" EntityID = %d", EntityID);
+ Log(" Bed = {%d, %d, %d}", BedX, BedY, BedZ);
COPY_TO_CLIENT();
return true;
}
@@ -2604,14 +2561,14 @@ bool cConnection::HandleServerWindowOpen(void)
{
HANDLE_SERVER_PACKET_READ(ReadChar, char, WindowID);
HANDLE_SERVER_PACKET_READ(ReadChar, char, WindowType);
- HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Title);
+ HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Title);
HANDLE_SERVER_PACKET_READ(ReadByte, Byte, NumSlots);
HANDLE_SERVER_PACKET_READ(ReadByte, Byte, UseProvidedTitle);
- int HorseInt = 0;
+ int HorseEntityID = 0;
if (WindowType == 11) // Horse / Donkey / Mule
{
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, intHorseInt);
- HorseInt = intHorseInt;
+ HorseEntityID = intHorseInt;
}
Log("Received a PACKET_WINDOW_OPEN from the server:");
Log(" WindowID = %d", WindowID);
@@ -2620,8 +2577,25 @@ bool cConnection::HandleServerWindowOpen(void)
Log(" NumSlots = %d", NumSlots);
if (WindowType == 11)
{
- Log(" HorseInt = %d (0x%08x)", HorseInt, HorseInt);
+ Log(" HorseEntityID = %d (0x%08x)", HorseEntityID, HorseEntityID);
+ }
+ COPY_TO_CLIENT();
+ return true;
+}
+
+
+
+
+
+bool cConnection::HandleServerUnknownPacket(UInt32 a_PacketType, UInt32 a_PacketLen, UInt32 a_PacketReadSoFar)
+{
+ AString Data;
+ ASSERT(a_PacketLen >= a_PacketReadSoFar);
+ if (!m_ServerBuffer.ReadString(Data, a_PacketLen - a_PacketReadSoFar))
+ {
+ return false;
}
+ DataLog(Data.data(), Data.size(), "****************** Unknown packet 0x%x from the server; relaying and ignoring", a_PacketType);
COPY_TO_CLIENT();
return true;
}
diff --git a/Tools/ProtoProxy/Connection.h b/Tools/ProtoProxy/Connection.h
index 56d443b86..c2bce30fb 100644
--- a/Tools/ProtoProxy/Connection.h
+++ b/Tools/ProtoProxy/Connection.h
@@ -157,6 +157,8 @@ protected:
bool HandleClientUseEntity(void);
bool HandleClientWindowClick(void);
bool HandleClientWindowClose(void);
+
+ bool HandleClientUnknownPacket(UInt32 a_PacketType, UInt32 a_PacketLen, UInt32 a_PacketReadSoFar);
// Packet handling, server-side, login:
bool HandleServerLoginDisconnect(void);
@@ -222,6 +224,8 @@ protected:
bool HandleServerWindowContents(void);
bool HandleServerWindowOpen(void);
+ bool HandleServerUnknownPacket(UInt32 a_PacketType, UInt32 a_PacketLen, UInt32 a_PacketReadSoFar);
+
/// Parses the slot data in a_Buffer into item description; returns true if successful, false if not enough data
bool ParseSlot(cByteBuffer & a_Buffer, AString & a_ItemDesc);
diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj
index 8c432280f..a5b43348a 100644
--- a/VC2008/MCServer.vcproj
+++ b/VC2008/MCServer.vcproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
@@ -2260,6 +2260,10 @@
>
</File>
<File
+ RelativePath="..\source\blocks\BlockPortal.h"
+ >
+ </File>
+ <File
RelativePath="..\source\Blocks\BlockPumpkin.h"
>
</File>
@@ -2528,6 +2532,14 @@
>
</File>
<File
+ RelativePath="..\source\Protocol\Protocol17x.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\source\Protocol\Protocol17x.h"
+ >
+ </File>
+ <File
RelativePath="..\source\Protocol\ProtocolRecognizer.cpp"
>
</File>
diff --git a/source/Bindings.cpp b/source/Bindings.cpp
index 8259eda81..a052d1062 100644
--- a/source/Bindings.cpp
+++ b/source/Bindings.cpp
@@ -1,6 +1,6 @@
/*
** Lua binding: AllToLua
-** Generated automatically by tolua++-1.0.92 on 10/28/13 13:11:03.
+** Generated automatically by tolua++-1.0.92 on 11/02/13 17:43:37.
*/
#ifndef __cplusplus
@@ -5220,6 +5220,38 @@ static int tolua_AllToLua_cEntity_GetRotation00(lua_State* tolua_S)
}
#endif //#ifndef TOLUA_DISABLE
+/* method: GetYaw of class cEntity */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_GetYaw00
+static int tolua_AllToLua_cEntity_GetYaw00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,2,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0);
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetYaw'", NULL);
+#endif
+ {
+ double tolua_ret = (double) self->GetYaw();
+ tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'GetYaw'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
/* method: GetPitch of class cEntity */
#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_GetPitch00
static int tolua_AllToLua_cEntity_GetPitch00(lua_State* tolua_S)
@@ -5879,6 +5911,39 @@ static int tolua_AllToLua_cEntity_SetRotation00(lua_State* tolua_S)
}
#endif //#ifndef TOLUA_DISABLE
+/* method: SetYaw of class cEntity */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_SetYaw00
+static int tolua_AllToLua_cEntity_SetYaw00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,2,0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,3,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
+ double a_Yaw = ((double) tolua_tonumber(tolua_S,2,0));
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetYaw'", NULL);
+#endif
+ {
+ self->SetYaw(a_Yaw);
+ }
+ }
+ return 0;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'SetYaw'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
/* method: SetPitch of class cEntity */
#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_SetPitch00
static int tolua_AllToLua_cEntity_SetPitch00(lua_State* tolua_S)
@@ -7990,6 +8055,38 @@ static int tolua_AllToLua_cPlayer_GetGameMode00(lua_State* tolua_S)
}
#endif //#ifndef TOLUA_DISABLE
+/* method: GetEffectiveGameMode of class cPlayer */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetEffectiveGameMode00
+static int tolua_AllToLua_cPlayer_GetEffectiveGameMode00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"const cPlayer",0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,2,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ const cPlayer* self = (const cPlayer*) tolua_tousertype(tolua_S,1,0);
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetEffectiveGameMode'", NULL);
+#endif
+ {
+ eGameMode tolua_ret = (eGameMode) self->GetEffectiveGameMode();
+ tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'GetEffectiveGameMode'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
/* method: SetGameMode of class cPlayer */
#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_SetGameMode00
static int tolua_AllToLua_cPlayer_SetGameMode00(lua_State* tolua_S)
@@ -29965,6 +30062,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_function(tolua_S,"GetPosZ",tolua_AllToLua_cEntity_GetPosZ00);
tolua_function(tolua_S,"GetRot",tolua_AllToLua_cEntity_GetRot00);
tolua_function(tolua_S,"GetRotation",tolua_AllToLua_cEntity_GetRotation00);
+ tolua_function(tolua_S,"GetYaw",tolua_AllToLua_cEntity_GetYaw00);
tolua_function(tolua_S,"GetPitch",tolua_AllToLua_cEntity_GetPitch00);
tolua_function(tolua_S,"GetRoll",tolua_AllToLua_cEntity_GetRoll00);
tolua_function(tolua_S,"GetLookVector",tolua_AllToLua_cEntity_GetLookVector00);
@@ -29985,6 +30083,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_function(tolua_S,"SetPosition",tolua_AllToLua_cEntity_SetPosition01);
tolua_function(tolua_S,"SetRot",tolua_AllToLua_cEntity_SetRot00);
tolua_function(tolua_S,"SetRotation",tolua_AllToLua_cEntity_SetRotation00);
+ tolua_function(tolua_S,"SetYaw",tolua_AllToLua_cEntity_SetYaw00);
tolua_function(tolua_S,"SetPitch",tolua_AllToLua_cEntity_SetPitch00);
tolua_function(tolua_S,"SetRoll",tolua_AllToLua_cEntity_SetRoll00);
tolua_function(tolua_S,"SetSpeed",tolua_AllToLua_cEntity_SetSpeed00);
@@ -30058,6 +30157,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_function(tolua_S,"GetThrowStartPos",tolua_AllToLua_cPlayer_GetThrowStartPos00);
tolua_function(tolua_S,"GetThrowSpeed",tolua_AllToLua_cPlayer_GetThrowSpeed00);
tolua_function(tolua_S,"GetGameMode",tolua_AllToLua_cPlayer_GetGameMode00);
+ tolua_function(tolua_S,"GetEffectiveGameMode",tolua_AllToLua_cPlayer_GetEffectiveGameMode00);
tolua_function(tolua_S,"SetGameMode",tolua_AllToLua_cPlayer_SetGameMode00);
tolua_function(tolua_S,"IsGameModeCreative",tolua_AllToLua_cPlayer_IsGameModeCreative00);
tolua_function(tolua_S,"IsGameModeSurvival",tolua_AllToLua_cPlayer_IsGameModeSurvival00);
diff --git a/source/Bindings.h b/source/Bindings.h
index 411e608d9..455307a89 100644
--- a/source/Bindings.h
+++ b/source/Bindings.h
@@ -1,6 +1,6 @@
/*
** Lua binding: AllToLua
-** Generated automatically by tolua++-1.0.92 on 10/28/13 13:11:04.
+** Generated automatically by tolua++-1.0.92 on 11/02/13 17:43:38.
*/
/* Exported function */
diff --git a/source/BlockEntities/DropSpenserEntity.cpp b/source/BlockEntities/DropSpenserEntity.cpp
index a9fcdab17..25def9999 100644
--- a/source/BlockEntities/DropSpenserEntity.cpp
+++ b/source/BlockEntities/DropSpenserEntity.cpp
@@ -89,6 +89,8 @@ void cDropSpenserEntity::DropSpense(cChunk & a_Chunk)
int SmokeDir = 0;
switch (Meta)
{
+ case E_META_DROPSPENSER_FACING_YP: SmokeDir = 4; break; // YP & YM don't have associated smoke dirs, just do 4 (centre of block)
+ case E_META_DROPSPENSER_FACING_YM: SmokeDir = 4; break;
case E_META_DROPSPENSER_FACING_XM: SmokeDir = 3; break;
case E_META_DROPSPENSER_FACING_XP: SmokeDir = 5; break;
case E_META_DROPSPENSER_FACING_ZM: SmokeDir = 1; break;
@@ -237,7 +239,26 @@ void cDropSpenserEntity::DropFromSlot(cChunk & a_Chunk, int a_SlotNum)
cItems Pickups;
Pickups.push_back(m_Contents.RemoveOneItem(a_SlotNum));
- m_World->SpawnItemPickups(Pickups, DispX, DispY, DispZ);
+
+ const int PickupSpeed = m_World->GetTickRandomNumber(4) + 2; // At least 2, at most 6
+ int PickupSpeedX = 0, PickupSpeedY = 0, PickupSpeedZ = 0;
+ switch (Meta)
+ {
+ case E_META_DROPSPENSER_FACING_YP: PickupSpeedY = PickupSpeed; break;
+ case E_META_DROPSPENSER_FACING_YM: PickupSpeedY = -PickupSpeed; break;
+ case E_META_DROPSPENSER_FACING_XM: PickupSpeedX = -PickupSpeed; break;
+ case E_META_DROPSPENSER_FACING_XP: PickupSpeedX = PickupSpeed; break;
+ case E_META_DROPSPENSER_FACING_ZM: PickupSpeedZ = -PickupSpeed; break;
+ case E_META_DROPSPENSER_FACING_ZP: PickupSpeedZ = PickupSpeed; break;
+ }
+
+ double MicroX, MicroY, MicroZ;
+ MicroX = DispX + 0.5;
+ MicroY = DispY + 0.4; // Slightly less than half, to accomodate actual texture hole on DropSpenser
+ MicroZ = DispZ + 0.5;
+
+
+ m_World->SpawnItemPickups(Pickups, MicroX, MicroY, MicroZ, PickupSpeedX, PickupSpeedY, PickupSpeedZ);
}
diff --git a/source/Blocks/BlockDirt.h b/source/Blocks/BlockDirt.h
index b2bc4756c..c694d79f6 100644
--- a/source/Blocks/BlockDirt.h
+++ b/source/Blocks/BlockDirt.h
@@ -37,7 +37,7 @@ public:
if (a_BlockY < cChunkDef::Height - 1)
{
BLOCKTYPE Above = a_World->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ);
- if (!g_BlockTransparent[Above] && !g_BlockOneHitDig[Above])
+ if ((!g_BlockTransparent[Above] && !g_BlockOneHitDig[Above]) || IsBlockWater(Above))
{
a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DIRT, 0);
return;
@@ -69,7 +69,7 @@ public:
NIBBLETYPE AboveMeta;
IsValid = a_World->GetBlockTypeMeta(a_BlockX + OfsX, a_BlockY + OfsY + 1, a_BlockZ + OfsZ, AboveDest, AboveMeta);
ASSERT(IsValid); // WTF - how did we get the DestBlock if AboveBlock is not valid?
- if (g_BlockOneHitDig[AboveDest] || g_BlockTransparent[AboveDest])
+ if ((g_BlockOneHitDig[AboveDest] || g_BlockTransparent[AboveDest]) && !IsBlockWater(AboveDest))
{
a_World->FastSetBlock(a_BlockX + OfsX, a_BlockY + OfsY, a_BlockZ + OfsZ, E_BLOCK_GRASS, 0);
}
diff --git a/source/Blocks/BlockFire.h b/source/Blocks/BlockFire.h
index d3ba499b1..46b56d7e0 100644
--- a/source/Blocks/BlockFire.h
+++ b/source/Blocks/BlockFire.h
@@ -16,6 +16,28 @@ public:
{
}
+ /// Portal boundary and direction variables
+ int XZP, XZM, Dir; // For wont of a better name...
+
+ virtual void OnPlaced(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
+ {
+ /*
+ PORTAL FINDING ALGORITH
+ =======================
+ -Get clicked base block
+ -Trace upwards to find first obsidian block; aborts if anything other than obsidian or air is encountered.
+ Uses this value as a reference (the 'ceiling')
+ -For both directions (if one fails, try the other), BASE (clicked) block:
+ -Go in one direction, only stop if a non obsidian block is encountered (abort) OR a portal border is encountered (FindObsidianCeiling returns -1)
+ -If a border was encountered, go the other direction and repeat above
+ -Write borders to XZP and XZM, write direction portal faces to Dir
+ -Loop through boundary variables, and fill with portal blocks based on Dir with meta from Dir
+ */
+
+ a_BlockY--; // Because we want the block below the fire
+ FindAndSetPortalFrame(a_BlockX, a_BlockY, a_BlockZ, a_World); // Brought to you by Aperture Science
+ }
+
virtual void OnDigging(cWorld * a_World, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override
{
a_World->DigBlock(a_BlockX, a_BlockY, a_BlockZ);
@@ -30,12 +52,176 @@ public:
{
return true;
}
-
+
virtual const char * GetStepSound(void) override
{
return "step.wood";
}
-} ;
+
+ /// Traces along YP until it finds an obsidian block, returns Y difference or 0 if no portal, and -1 for border
+ /// Takes the X, Y, and Z of the base block; with an optional MaxY for portal border finding
+ int FindObsidianCeiling(int X, int Y, int Z, cWorld * a_World, int MaxY = 0)
+ {
+ if (a_World->GetBlock(X, Y, Z) != E_BLOCK_OBSIDIAN)
+ {
+ return 0;
+ }
+
+ int newY = Y + 1;
+
+ for (newY; newY < cChunkDef::Height; newY++)
+ {
+ BLOCKTYPE Block = a_World->GetBlock(X, newY, Z);
+ if ((Block == E_BLOCK_AIR) || (Block == E_BLOCK_FIRE))
+ {
+ continue;
+ }
+ else if (Block == E_BLOCK_OBSIDIAN)
+ {
+ // We found an obsidian ceiling
+ // Make sure MaxY has a value and newY ('ceiling' location) is at one above the base block
+ // This is because the frame is a solid obsidian pillar
+ if ((MaxY != 0) && (newY == Y + 1))
+ {
+ return EvaluatePortalBorder(X, newY, Z, MaxY, a_World);
+ }
+ else
+ {
+ // Return ceiling Y, whoever called this function will decide if it's part of a portal or not
+ return newY;
+ }
+ }
+ else { return 0; }
+ }
+
+ return 0;
+ }
+
+ /// Evaluates if coords have a valid border on top, based on MaxY
+ int EvaluatePortalBorder(int X, int FoundObsidianY, int Z, int MaxY, cWorld * a_World)
+ {
+ for (int checkBorder = FoundObsidianY + 1; checkBorder <= MaxY - 1; checkBorder++) // FoundObsidianY + 1: FoundObsidianY has already been checked in FindObsidianCeiling; MaxY - 1: portal doesn't need corners
+ {
+ if (a_World->GetBlock(X, checkBorder, Z) != E_BLOCK_OBSIDIAN)
+ {
+ // Base obsidian, base + 1 obsidian, base + x NOT obsidian -> not complete portal
+ return 0;
+ }
+ }
+ // Everything was obsidian, found a border!
+ return -1; // Return -1 for a frame border
+ }
+
+ /// Finds entire frame in any direction with the coordinates of a base block and fills hole with nether portal (START HERE)
+ void FindAndSetPortalFrame(int X, int Y, int Z, cWorld * a_World)
+ {
+ int MaxY = FindObsidianCeiling(X, Y, Z, a_World); // Get topmost obsidian block as reference for all other checks
+ int X1 = X + 1, Z1 = Z + 1, X2 = X - 1, Z2 = Z - 1; // Duplicate XZ values, add/subtract one as we've checked the original already the line above
+
+ if (MaxY == 0) // Oh noes! Not a portal coordinate :(
+ {
+ return;
+ }
+
+ if (!FindPortalSliceX(X1, X2, Y, Z, MaxY, a_World))
+ {
+ if (!FindPortalSliceZ(X, Y, Z1, Z2, MaxY, a_World))
+ {
+ return; // No eligible portal construct, abort abort abort!!
+ }
+ }
+
+ for (int Height = Y + 1; Height <= MaxY - 1; Height++) // Loop through boundary to set portal blocks
+ {
+ for (int Width = XZM; Width <= XZP; Width++)
+ {
+ if (Dir == 1)
+ {
+ a_World->SetBlock(Width, Height, Z, E_BLOCK_NETHER_PORTAL, Dir);
+ }
+ else
+ {
+ a_World->SetBlock(X, Height, Width, E_BLOCK_NETHER_PORTAL, Dir);
+ }
+ }
+ }
+
+ return;
+ }
+
+ /// Evaluates if coordinates are a portal going XP/XM; returns true if so, and writes boundaries to variable
+ /// Takes coordinates of base block and Y coord of target obsidian ceiling
+ bool FindPortalSliceX(int X1, int X2, int Y, int Z, int MaxY, cWorld * a_World)
+ {
+ Dir = 1; // Set assumed direction (will change if portal turns out to be facing the other direction)
+ bool FoundFrameXP = false, FoundFrameXM = false;
+ for (X1; ((a_World->GetBlock(X1, Y, Z) == E_BLOCK_OBSIDIAN) || (a_World->GetBlock(X1, Y + 1, Z) == E_BLOCK_OBSIDIAN)); X1++) // Check XP for obsidian blocks, exempting corners
+ {
+ int Value = FindObsidianCeiling(X1, Y, Z, a_World, MaxY);
+ int ValueTwo = FindObsidianCeiling(X1, Y + 1, Z, a_World, MaxY); // For corners without obsidian
+ if ((Value == -1) || (ValueTwo == -1)) // FindObsidianCeiling returns -1 upon frame-find
+ {
+ FoundFrameXP = true; // Found a frame border in this direction, proceed in other direction (don't go further)
+ break;
+ }
+ else if ((Value != MaxY) && (ValueTwo != MaxY)) // Make sure that there is a valid portal 'slice'
+ {
+ return false; // Not valid slice, no portal can be formed
+ }
+ } XZP = X1 - 1; // Set boundary of frame interior, note that for some reason, the loop of X and the loop of Z go to different numbers, hence -1 here and -2 there
+ for (X2; ((a_World->GetBlock(X2, Y, Z) == E_BLOCK_OBSIDIAN) || (a_World->GetBlock(X2, Y + 1, Z) == E_BLOCK_OBSIDIAN)); X2--) // Go the other direction (XM)
+ {
+ int Value = FindObsidianCeiling(X2, Y, Z, a_World, MaxY);
+ int ValueTwo = FindObsidianCeiling(X2, Y + 1, Z, a_World, MaxY);
+ if ((Value == -1) || (ValueTwo == -1))
+ {
+ FoundFrameXM = true;
+ break;
+ }
+ else if ((Value != MaxY) && (ValueTwo != MaxY))
+ {
+ return false;
+ }
+ } XZM = X2 + 1; // Set boundary, see previous
+ return (FoundFrameXP && FoundFrameXM);
+ }
+
+ /// Evaluates if coords are a portal going ZP/ZM; returns true if so, and writes boundaries to variable
+ bool FindPortalSliceZ(int X, int Y, int Z1, int Z2, int MaxY, cWorld * a_World)
+ {
+ Dir = 2;
+ bool FoundFrameZP = false, FoundFrameZM = false;
+ for (Z1; ((a_World->GetBlock(X, Y, Z1) == E_BLOCK_OBSIDIAN) || (a_World->GetBlock(X, Y + 1, Z1) == E_BLOCK_OBSIDIAN)); Z1++)
+ {
+ int Value = FindObsidianCeiling(X, Y, Z1, a_World, MaxY);
+ int ValueTwo = FindObsidianCeiling(X, Y + 1, Z1, a_World, MaxY);
+ if ((Value == -1) || (ValueTwo == -1))
+ {
+ FoundFrameZP = true;
+ continue;
+ }
+ else if ((Value != MaxY) && (ValueTwo != MaxY))
+ {
+ return false;
+ }
+ } XZP = Z1 - 2;
+ for (Z2; ((a_World->GetBlock(X, Y, Z2) == E_BLOCK_OBSIDIAN) || (a_World->GetBlock(X, Y + 1, Z2) == E_BLOCK_OBSIDIAN)); Z2--)
+ {
+ int Value = FindObsidianCeiling(X, Y, Z2, a_World, MaxY);
+ int ValueTwo = FindObsidianCeiling(X, Y + 1, Z2, a_World, MaxY);
+ if ((Value == -1) || (ValueTwo == -1))
+ {
+ FoundFrameZM = true;
+ continue;
+ }
+ else if ((Value != MaxY) && (ValueTwo != MaxY))
+ {
+ return false;
+ }
+ } XZM = Z2 + 2;
+ return (FoundFrameZP && FoundFrameZM);
+ }
+};
diff --git a/source/Blocks/BlockHandler.cpp b/source/Blocks/BlockHandler.cpp
index e59fee8ee..cd07b3021 100644
--- a/source/Blocks/BlockHandler.cpp
+++ b/source/Blocks/BlockHandler.cpp
@@ -44,6 +44,7 @@
#include "BlockOre.h"
#include "BlockPiston.h"
#include "BlockPlanks.h"
+#include "BlockPortal.h"
#include "BlockPumpkin.h"
#include "BlockRail.h"
#include "BlockRedstone.h"
@@ -159,6 +160,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_PISTON: return new cBlockPistonHandler (a_BlockType);
case E_BLOCK_PISTON_EXTENSION: return new cBlockPistonHeadHandler ( );
case E_BLOCK_PLANKS: return new cBlockPlanksHandler (a_BlockType);
+ case E_BLOCK_NETHER_PORTAL: return new cBlockPortalHandler (a_BlockType);
case E_BLOCK_PUMPKIN: return new cBlockPumpkinHandler (a_BlockType);
case E_BLOCK_JACK_O_LANTERN: return new cBlockPumpkinHandler (a_BlockType);
case E_BLOCK_PUMPKIN_STEM: return new cBlockStemsHandler (a_BlockType);
diff --git a/source/Blocks/BlockPortal.h b/source/Blocks/BlockPortal.h
new file mode 100644
index 000000000..c56f0cbc8
--- /dev/null
+++ b/source/Blocks/BlockPortal.h
@@ -0,0 +1,108 @@
+
+#pragma once
+
+#include "BlockHandler.h"
+
+
+
+
+
+class cBlockPortalHandler :
+ public cBlockHandler
+{
+public:
+ cBlockPortalHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+ virtual bool GetPlacementBlockTypeMeta(
+ 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,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ // We set to zero so MCS doesn't stop you from building weird portals like vanilla does
+ // CanBeAt doesn't do anything if meta is zero
+ // We set to zero because the client sends meta = 2 to the server (it calculates rotation itself)
+
+ a_BlockType = m_BlockType;
+ a_BlockMeta = 0;
+ return true;
+ }
+
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ return; // No pickups
+ }
+
+
+ virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
+ {
+ if ((a_RelY - 1 < 0) || (a_RelY + 1 > cChunkDef::Height))
+ {
+ return false; // In case someone places a portal with meta 1 or 2 at boundaries, and server tries to get invalid coords at Y - 1 or Y + 1
+ }
+
+ switch (a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ))
+ {
+ case 0x1:
+ {
+ static const struct
+ {
+ int x, y, z;
+ } PortalCheck[] =
+ {
+ { 0, 1, 0},
+ { 0,-1, 0},
+ { 1, 0, 0},
+ {-1, 0, 0},
+ } ;
+
+ for (int i = 0; i < ARRAYCOUNT(PortalCheck); i++)
+ {
+ BLOCKTYPE Block;
+ a_Chunk.UnboundedRelGetBlockType(a_RelX + PortalCheck[i].x, a_RelY + PortalCheck[i].y, a_RelZ + PortalCheck[i].z, Block);
+
+ if ((Block != E_BLOCK_NETHER_PORTAL) && (Block != E_BLOCK_OBSIDIAN))
+ {
+ return false;
+ }
+ }
+ break;
+ }
+ case 0x2:
+ {
+ static const struct
+ {
+ int x, y, z;
+ } PortalCheck[] =
+ {
+ { 0, 1, 0},
+ { 0,-1, 0},
+ { 0, 0, -1},
+ { 0, 0, 1},
+ } ;
+
+ for (int i = 0; i < ARRAYCOUNT(PortalCheck); i++)
+ {
+ BLOCKTYPE Block;
+ a_Chunk.UnboundedRelGetBlockType(a_RelX + PortalCheck[i].x, a_RelY + PortalCheck[i].y, a_RelZ + PortalCheck[i].z, Block);
+
+ if ((Block != E_BLOCK_NETHER_PORTAL) && (Block != E_BLOCK_OBSIDIAN))
+ {
+ return false;
+ }
+ }
+ break;
+ }
+ }
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/source/Blocks/BlockRail.h b/source/Blocks/BlockRail.h
index 0e83b952d..24a101652 100644
--- a/source/Blocks/BlockRail.h
+++ b/source/Blocks/BlockRail.h
@@ -22,6 +22,8 @@ enum ENUM_PURE
class cBlockRailHandler :
public cBlockHandler
{
+ typedef cBlockHandler super;
+
public:
cBlockRailHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
@@ -51,6 +53,12 @@ public:
}
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ super::ConvertToPickups(a_Pickups, 0);
+ }
+
+
virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
if (a_RelY <= 0)
diff --git a/source/ByteBuffer.cpp b/source/ByteBuffer.cpp
index 6659b4dd4..1cdd2f430 100644
--- a/source/ByteBuffer.cpp
+++ b/source/ByteBuffer.cpp
@@ -195,7 +195,7 @@ int cByteBuffer::GetUsedSpace(void) const
{
CHECK_THREAD;
CheckValid();
- return m_BufferSize - GetFreeSpace();
+ return m_BufferSize - GetFreeSpace() - 1;
}
@@ -555,7 +555,7 @@ bool cByteBuffer::WriteVarInt(UInt32 a_Value)
-bool cByteBuffer::WriteVarUTF8String(AString & a_Value)
+bool cByteBuffer::WriteVarUTF8String(const AString & a_Value)
{
CHECK_THREAD;
CheckValid();
diff --git a/source/ByteBuffer.h b/source/ByteBuffer.h
index 71ee4764e..21abb0377 100644
--- a/source/ByteBuffer.h
+++ b/source/ByteBuffer.h
@@ -62,7 +62,7 @@ public:
bool ReadVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8
/// Reads VarInt, assigns it to anything that can be assigned from an UInt32 (unsigned short, char, Byte, double, ...)
- template <typename T> bool ReadVarUInt(T & a_Value)
+ template <typename T> bool ReadVarInt(T & a_Value)
{
UInt32 v;
bool res = ReadVarInt(v);
@@ -84,7 +84,7 @@ public:
bool WriteBool (bool a_Value);
bool WriteBEUTF16String16(const AString & a_Value); // string length as BE short, then string as UTF-16BE
bool WriteVarInt (UInt32 a_Value);
- bool WriteVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8
+ bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8
/// Reads a_Count bytes into a_Buffer; returns true if successful
bool ReadBuf(void * a_Buffer, int a_Count);
diff --git a/source/Chunk.cpp b/source/Chunk.cpp
index c9d457af3..be75eae41 100644
--- a/source/Chunk.cpp
+++ b/source/Chunk.cpp
@@ -519,32 +519,28 @@ void cChunk::SpawnMobs(cMobSpawner& a_MobSpawner)
ASSERT(Try_Y > 0);
ASSERT(Try_Y < cChunkDef::Height-1);
- BLOCKTYPE BlockType;
- NIBBLETYPE BlockMeta;
- BLOCKTYPE BlockType_below;
- NIBBLETYPE BlockMeta_below;
- BLOCKTYPE BlockType_above;
- NIBBLETYPE BlockMeta_above;
- if (UnboundedRelGetBlock(Try_X, Try_Y , Try_Z, BlockType, BlockMeta) &&
- UnboundedRelGetBlock(Try_X, Try_Y-1, Try_Z, BlockType_below, BlockMeta_below)&&
- UnboundedRelGetBlock(Try_X, Try_Y+1, Try_Z, BlockType_above, BlockMeta_above)
- )
- {
- EMCSBiome Biome = m_ChunkMap->GetBiomeAt (Try_X, Try_Z);
- // MG TODO :
- // Moon cycle (for slime)
- // check player and playerspawn presence < 24 blocks
- // check mobs presence on the block
+ EMCSBiome Biome = m_ChunkMap->GetBiomeAt (Try_X, Try_Z);
+ // MG TODO :
+ // Moon cycle (for slime)
+ // check player and playerspawn presence < 24 blocks
+ // check mobs presence on the block
+
+ // MG TODO : check that "Level" really means Y
+
+ NIBBLETYPE SkyLight = 0;
- // MG TODO: fix the "light" thing, I'm pretty sure that UnboundedRelGetBlock s not returning the right thing
+ NIBBLETYPE BlockLight = 0;
- // MG TODO : check that "Level" really means Y
- cEntity* newMob = a_MobSpawner.TryToSpawnHere(BlockType, BlockMeta, BlockType_below, BlockMeta_below, BlockType_above, BlockMeta_above, Biome, Try_Y, MaxNbOfSuccess);
+ if (IsLightValid())
+ {
+ cEntity* newMob = a_MobSpawner.TryToSpawnHere(this, Try_X, Try_Y, Try_Z, Biome, MaxNbOfSuccess);
if (newMob)
{
int WorldX, WorldY, WorldZ;
PositionToWorldPosition(Try_X, Try_Y, Try_Z, WorldX, WorldY, WorldZ);
- newMob->SetPosition(WorldX, WorldY, WorldZ);
+ double ActualX = WorldX + 0.5;
+ double ActualZ = WorldZ + 0.5;
+ newMob->SetPosition(ActualX, WorldY, ActualZ);
LOGD("Spawning %s #%i at %d,%d,%d",newMob->GetClass(),newMob->GetUniqueID(),WorldX, WorldY, WorldZ);
NumberOfSuccess++;
}
@@ -2790,6 +2786,17 @@ Vector3i cChunk::PositionToWorldPosition(int a_RelX, int a_RelY, int a_RelZ)
+NIBBLETYPE cChunk::GetTimeAlteredLight(NIBBLETYPE a_Skylight) const
+{
+ a_Skylight -= m_World->GetSkyDarkness();
+ // Because NIBBLETYPE is unsigned, we clamp it to 0 .. 15 by checking for values above 15
+ return (a_Skylight < 16)? a_Skylight : 0;
+}
+
+
+
+
+
#if !C_CHUNK_USE_INLINE
# include "cChunk.inl.h"
#endif
diff --git a/source/Chunk.h b/source/Chunk.h
index ab110c7cb..63a8f75cd 100644
--- a/source/Chunk.h
+++ b/source/Chunk.h
@@ -329,6 +329,10 @@ public:
/// Same as QueueTickBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s in such a case), ignores unsuccessful attempts
void UnboundedQueueTickBlock(int a_RelX, int a_RelY, int a_RelZ);
+ /// Light alterations based on time
+ NIBBLETYPE GetTimeAlteredLight(NIBBLETYPE a_Skylight) const;
+
+
// Simulator data:
cFireSimulatorChunkData & GetFireSimulatorData (void) { return m_FireSimulatorData; }
cFluidSimulatorData * GetWaterSimulatorData(void) { return m_WaterSimulatorData; }
diff --git a/source/ChunkMap.cpp b/source/ChunkMap.cpp
index c3bd5f33d..d9de24cff 100644
--- a/source/ChunkMap.cpp
+++ b/source/ChunkMap.cpp
@@ -12,6 +12,7 @@
#include "BlockArea.h"
#include "PluginManager.h"
#include "Entities/TNTEntity.h"
+#include "Blocks/BlockHandler.h"
#include "MobCensus.h"
#include "MobSpawner.h"
@@ -1610,7 +1611,9 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
// Too far away
continue;
}
- switch (area.GetBlockType(bx + x, by + y, bz + z))
+
+ BLOCKTYPE Block = area.GetBlockType(bx + x, by + y, bz + z);
+ switch (Block)
{
case E_BLOCK_TNT:
{
@@ -1644,8 +1647,22 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
break;
}
+ case E_BLOCK_AIR:
+ {
+ // No pickups for air
+ break;
+ }
+
default:
{
+ if (m_World->GetTickRandomNumber(10) == 5)
+ {
+ cItems Drops;
+ cBlockHandler * Handler = BlockHandler(Block);
+
+ Handler->ConvertToPickups(Drops, area.GetBlockMeta(bx + x, by + y, bz + z));
+ m_World->SpawnItemPickups(Drops, bx + x, by + y, bz + z);
+ }
area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_AIR);
a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z));
}
diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp
index ea8b48f9d..6860a29ca 100644
--- a/source/ClientHandle.cpp
+++ b/source/ClientHandle.cpp
@@ -1470,7 +1470,7 @@ void cClientHandle::Tick(float a_Dt)
}
// If the chunk the player's in was just sent, spawn the player:
- if (m_HasSentPlayerChunk && (m_State != csPlaying))
+ if (m_HasSentPlayerChunk && (m_State != csPlaying) && !IsDestroying())
{
if (!cRoot::Get()->GetPluginManager()->CallHookPlayerJoined(*m_Player))
{
@@ -2138,7 +2138,7 @@ void cClientHandle::PacketUnknown(unsigned char a_PacketType)
LOGERROR("Unknown packet type 0x%02x from client \"%s\" @ %s", a_PacketType, m_Username.c_str(), m_IPString.c_str());
AString Reason;
- Printf(Reason, "[C->S] Unknown PacketID: 0x%02x", a_PacketType);
+ Printf(Reason, "Unknown [C->S] PacketType: 0x%02x", a_PacketType);
SendDisconnect(Reason);
Destroy();
}
diff --git a/source/Entities/Entity.cpp b/source/Entities/Entity.cpp
index d465c75bd..3bea7bc01 100644
--- a/source/Entities/Entity.cpp
+++ b/source/Entities/Entity.cpp
@@ -1178,9 +1178,9 @@ void cEntity::SetMass(double a_Mass)
-void cEntity::SetRotation(double a_Rotation)
+void cEntity::SetYaw(double a_Yaw)
{
- m_Rot.x = a_Rotation;
+ m_Rot.x = a_Yaw;
m_bDirtyOrientation = true;
WrapRotation();
}
diff --git a/source/Entities/Entity.h b/source/Entities/Entity.h
index c6b70a7fc..dafda7826 100644
--- a/source/Entities/Entity.h
+++ b/source/Entities/Entity.h
@@ -151,7 +151,8 @@ public:
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; }
+ double GetRotation (void) const { return m_Rot.x; } // OBSOLETE, use GetYaw() instead
+ double GetYaw (void) const { return m_Rot.x; }
double GetPitch (void) const { return m_Rot.y; }
double GetRoll (void) const { return m_Rot.z; }
Vector3d GetLookVector(void) const;
@@ -173,7 +174,8 @@ public:
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);
+ void SetRotation(double a_Rotation) { SetYaw(a_Rotation); } // OBSOLETE, use SetYaw() instead
+ void SetYaw (double a_Yaw);
void SetPitch (double a_Pitch);
void SetRoll (double a_Roll);
void SetSpeed (double a_SpeedX, double a_SpeedY, double a_SpeedZ);
diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp
index d94bc944c..2e4199629 100644
--- a/source/Entities/Player.cpp
+++ b/source/Entities/Player.cpp
@@ -297,7 +297,6 @@ void cPlayer::CancelChargingBow(void)
void cPlayer::SetTouchGround(bool a_bTouchGround)
{
- // If just
m_bTouchGround = a_bTouchGround;
if (!m_bTouchGround)
@@ -307,12 +306,11 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
m_LastJumpHeight = (float)GetPosY();
}
cWorld * World = GetWorld();
- if ((GetPosY() >= 0) && (GetPosY() < 256))
+ if ((GetPosY() >= 0) && (GetPosY() < cChunkDef::Height))
{
- BLOCKTYPE BlockType = World->GetBlock( float2int(GetPosX()), float2int(GetPosY()), float2int(GetPosZ()) );
+ BLOCKTYPE BlockType = World->GetBlock(float2int(GetPosX()), float2int(GetPosY()), float2int(GetPosZ()));
if (BlockType != E_BLOCK_AIR)
{
- // LOGD("TouchGround set to true by server");
m_bTouchGround = true;
}
if (
@@ -322,19 +320,18 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
(BlockType == E_BLOCK_VINES)
)
{
- // LOGD("Water / Ladder / Torch");
m_LastGroundHeight = (float)GetPosY();
}
}
}
-
- if (m_bTouchGround)
+ else
{
float Dist = (float)(m_LastGroundHeight - floor(GetPosY()));
int Damage = (int)(Dist - 3.f);
- if(m_LastJumpHeight > m_LastGroundHeight) Damage++;
+ if (m_LastJumpHeight > m_LastGroundHeight) Damage++;
m_LastJumpHeight = (float)GetPosY();
- if (Damage > 0)
+
+ if ((Damage > 0) && (!IsGameModeCreative()))
{
TakeDamage(dtFalling, NULL, Damage, Damage, 0);
}
@@ -1416,11 +1413,11 @@ cPlayer::StringList cPlayer::GetResolvedPermissions()
void cPlayer::UseEquippedItem(void)
{
- if (GetGameMode() == gmCreative) // No damage in creative
+ if (IsGameModeCreative()) // No damage in creative
{
return;
}
-
+
GetInventory().DamageEquippedItem();
}
diff --git a/source/Entities/Player.h b/source/Entities/Player.h
index 449a63231..01efa3681 100644
--- a/source/Entities/Player.h
+++ b/source/Entities/Player.h
@@ -4,6 +4,7 @@
#include "Pawn.h"
#include "../Inventory.h"
#include "../Defines.h"
+#include "../World.h"
@@ -99,6 +100,9 @@ public:
/// Returns the current gamemode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable
eGameMode GetGameMode(void) const { return m_GameMode; }
+ /// Returns the current effective gamemode (inherited gamemode is resolved before returning)
+ eGameMode GetEffectiveGameMode(void) const { return (m_GameMode == gmNotSet) ? m_World->GetGameMode() : m_GameMode; }
+
/** Sets the gamemode for the player.
The gamemode may be gmNotSet, in that case the player inherits the world's gamemode.
Updates the gamemode on the client (sends the packet)
diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp
index 4c8e680d0..1d5532718 100644
--- a/source/Entities/ProjectileEntity.cpp
+++ b/source/Entities/ProjectileEntity.cpp
@@ -474,8 +474,17 @@ cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y,
void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
{
- // TODO: Random-spawn a chicken or four
-
+ if (m_World->GetTickRandomNumber(7) == 1)
+ {
+ m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
+ }
+ else if (m_World->GetTickRandomNumber(32) == 1)
+ {
+ m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
+ m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
+ m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
+ m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
+ }
Destroy();
}
diff --git a/source/Item.cpp b/source/Item.cpp
index 31a09a608..5e0beb028 100644
--- a/source/Item.cpp
+++ b/source/Item.cpp
@@ -38,6 +38,7 @@ short cItem::GetMaxDamage(void) const
{
switch (m_ItemType)
{
+ case E_ITEM_BOW: return 384;
case E_ITEM_DIAMOND_AXE: return 1563;
case E_ITEM_DIAMOND_HOE: return 1563;
case E_ITEM_DIAMOND_PICKAXE: return 1563;
diff --git a/source/Items/ItemBow.h b/source/Items/ItemBow.h
index 845192ef7..7bce127b1 100644
--- a/source/Items/ItemBow.h
+++ b/source/Items/ItemBow.h
@@ -71,6 +71,11 @@ public:
return;
}
a_Player->GetWorld()->BroadcastSpawnEntity(*Arrow);
+
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->UseEquippedItem();
+ }
}
} ;
diff --git a/source/Items/ItemThrowable.h b/source/Items/ItemThrowable.h
index dacdb6157..85579daf2 100644
--- a/source/Items/ItemThrowable.h
+++ b/source/Items/ItemThrowable.h
@@ -28,9 +28,15 @@ public:
virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override
{
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
+
Vector3d Pos = a_Player->GetThrowStartPos();
Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff;
a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &Speed);
+
return true;
}
diff --git a/source/MobSpawner.cpp b/source/MobSpawner.cpp
index 1b3796f70..d4926bbe5 100644
--- a/source/MobSpawner.cpp
+++ b/source/MobSpawner.cpp
@@ -124,87 +124,104 @@ cMonster::eType cMobSpawner::ChooseMobType(EMCSBiome a_Biome)
-bool cMobSpawner::CanSpawnHere(cMonster::eType a_MobType, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, BLOCKTYPE a_BlockType_below, NIBBLETYPE a_BlockMeta_below, BLOCKTYPE a_BlockType_above, NIBBLETYPE a_BlockMeta_above, EMCSBiome a_Biome, int a_Level)
+bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, cMonster::eType a_MobType, EMCSBiome a_Biome)
{
- bool toReturn = false;
- std::set<cMonster::eType>::iterator itr = m_AllowedTypes.find(a_MobType);
- if (itr != m_AllowedTypes.end())
+ BLOCKTYPE TargetBlock;
+ if (m_AllowedTypes.find(a_MobType) != m_AllowedTypes.end() && a_Chunk->UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, TargetBlock))
{
- // MG TODO : find a nicer paging
- if (a_MobType == cMonster::mtSquid)
- {
- toReturn = (
- IsBlockLiquid(a_BlockType) &&
- a_Level >= 45 &&
- a_Level <= 62
- );
- }
- else if (a_MobType == cMonster::mtBat)
- {
- toReturn = a_Level <= 60; // MG TODO : find a real rule
- }
- else
+ NIBBLETYPE BlockLight = a_Chunk->GetBlockLight(a_RelX, a_RelY, a_RelZ);
+ NIBBLETYPE SkyLight = a_Chunk->GetSkyLight(a_RelX, a_RelY, a_RelZ);
+ BLOCKTYPE BlockAbove = a_Chunk->GetBlock(a_RelX, a_RelY + 1, a_RelZ);
+ BLOCKTYPE BlockBelow = a_Chunk->GetBlock(a_RelX, a_RelY - 1, a_RelZ);
+
+ SkyLight = a_Chunk->GetTimeAlteredLight(SkyLight);
+
+ switch(a_MobType)
{
- if (
- a_BlockType == E_BLOCK_AIR &&
- a_BlockType_above == E_BLOCK_AIR &&
- ! (g_BlockTransparent[a_BlockType_below])
- )
+ case cMonster::mtSquid:
+ return IsBlockWater(TargetBlock) && (a_RelY >= 45) && (a_RelY <= 62);
+
+ case cMonster::mtBat:
+ return (a_RelY <= 63) && (BlockLight <= 4) && (SkyLight <= 4) && (TargetBlock == E_BLOCK_AIR) && (!g_BlockTransparent[BlockAbove]);
+
+ case cMonster::mtChicken:
+ case cMonster::mtCow:
+ case cMonster::mtPig:
+ case cMonster::mtHorse:
+ case cMonster::mtSheep:
{
- if (a_MobType == cMonster::mtChicken || a_MobType == cMonster::mtPig || a_MobType == cMonster::mtCow || a_MobType == cMonster::mtSheep)
- {
- toReturn = (
- a_BlockType_below == E_BLOCK_GRASS /*&& // MG TODO
- a_LightLevel >= 9 */
- );
- }
- else if (a_MobType == cMonster::mtOcelot)
+ return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (!g_BlockTransparent[BlockBelow]) &&
+ (BlockBelow == E_BLOCK_GRASS) && (SkyLight >= 9);
+ }
+
+ case cMonster::mtOcelot:
+ {
+ return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) &&
+ ((BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES)) && (a_RelY >= 62) && (m_Random.NextInt(3,a_Biome) != 0);
+ }
+ case cMonster::mtEnderman:
+ {
+ if (a_RelY < 250)
{
- toReturn = (
- a_Level >= 62 &&
- (
- a_BlockType_below == E_BLOCK_GRASS ||
- a_BlockType_below == E_BLOCK_LEAVES
- ) &&
- m_Random.NextInt(3,a_Biome) != 0
- );
+ BLOCKTYPE BlockTop = a_Chunk->GetBlock(a_RelX, a_RelY + 2, a_RelZ);
+ if (BlockTop == E_BLOCK_AIR)
+ {
+ BlockTop = a_Chunk->GetBlock(a_RelX, a_RelY + 3, a_RelZ);
+ return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (BlockTop == E_BLOCK_AIR) && (!g_BlockTransparent[BlockBelow]) &&
+ (SkyLight <= 7) && (BlockLight <= 7);
+ }
}
- else if (a_MobType == cMonster::mtCreeper || a_MobType == cMonster::mtSkeleton || a_MobType == cMonster::mtZombie || a_MobType == cMonster::mtSpider || a_MobType == cMonster::mtEnderman || a_MobType == cMonster::mtZombiePigman)
+ break;
+ }
+ case cMonster::mtSpider:
+ {
+ bool CanSpawn = true;
+ bool HaveFloor = false;
+ for (int x = 0; x < 2; ++x)
{
- toReturn = true /*a_LightLevel <= 7 MG TODO*/;
- /*if (a_SunLight) MG TODO
+ for(int z = 0; z < 2; ++z)
{
- if (m_Random.NextInt(2,a_Biome) != 0)
+ CanSpawn = a_Chunk->UnboundedRelGetBlockType(a_RelX + x, a_RelY, a_RelZ + z, TargetBlock);
+ CanSpawn = CanSpawn && (TargetBlock == E_BLOCK_AIR);
+ if (!CanSpawn)
{
- toReturn = false;
+ return false;
}
- }*/
- }
- else if (a_MobType == cMonster::mtSlime)
- {
- toReturn = a_Level <= 40;
- // MG TODO : much more complicated rules
- }
- else if (a_MobType == cMonster::mtGhast)
- {
- toReturn = m_Random.NextInt(20,a_Biome) == 0;
- }
- else
- {
- LOGD("MG TODO : check I've got a Rule to write for type %d",a_MobType);
- toReturn = true;
+ if (!HaveFloor)
+ {
+ a_Chunk->UnboundedRelGetBlockType(a_RelX + x, a_RelY - 1, a_RelZ + z, TargetBlock);
+ HaveFloor = HaveFloor || !g_BlockTransparent[TargetBlock];
+ }
+ }
}
+ return CanSpawn && HaveFloor && (SkyLight <= 7) && (BlockLight <= 7);
+
}
+ case cMonster::mtCreeper:
+ case cMonster::mtZombie:
+ return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (!g_BlockTransparent[BlockBelow]) &&
+ (SkyLight <= 7) && (BlockLight <= 7) && (m_Random.NextInt(2,a_Biome) == 0);
+
+ case cMonster::mtSlime:
+ return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (!g_BlockTransparent[BlockBelow]) &&
+ ((a_RelY <= 40) || a_Biome == biSwampland);
+ case cMonster::mtGhast:
+ case cMonster::mtZombiePigman:
+ return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (!g_BlockTransparent[BlockBelow]) &&
+ (m_Random.NextInt(20,a_Biome) == 0);
+ default:
+ LOGD("MG TODO : check I've got a Rule to write for type %d",a_MobType);
+ return false;
}
}
- return toReturn;
+ return false;
}
-cMonster* cMobSpawner::TryToSpawnHere(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, BLOCKTYPE a_BlockType_below, NIBBLETYPE a_BlockMeta_below, BLOCKTYPE a_BlockType_above, NIBBLETYPE a_BlockMeta_above, EMCSBiome a_Biome, int a_Level, int& a_MaxPackSize)
+cMonster* cMobSpawner::TryToSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, EMCSBiome a_Biome, int& a_MaxPackSize)
{
cMonster* toReturn = NULL;
if (m_NewPack)
@@ -225,8 +242,10 @@ cMonster* cMobSpawner::TryToSpawnHere(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockM
m_NewPack = false;
}
+ // Make sure we are looking at the right chunk to spawn in
+ a_Chunk = a_Chunk->GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ);
- if (CanSpawnHere(m_MobType, a_BlockType, a_BlockMeta, a_BlockType_below, a_BlockMeta_below, a_BlockType_above, a_BlockMeta_above, a_Biome, a_Level))
+ if (CanSpawnHere(a_Chunk, a_RelX, a_RelY, a_RelZ, m_MobType, a_Biome))
{
cMonster * newMob = cMonster::NewMonsterFromType(m_MobType);
if (newMob)
diff --git a/source/MobSpawner.h b/source/MobSpawner.h
index ba2a18f2e..ea6636310 100644
--- a/source/MobSpawner.h
+++ b/source/MobSpawner.h
@@ -4,6 +4,7 @@
#include <set>
#include "BlockID.h"
#include "ChunkDef.h"
+#include "Chunk.h"
#include "FastRandom.h"
#include "Mobs/Monster.h" //this is a side-effect of keeping Mobfamily inside Monster class. I'd prefer to keep both (Mobfamily and Monster) inside a "Monster" namespace MG TODO : do it
@@ -38,7 +39,7 @@ public :
// if this is the first of a Pack : determine the type of monster
// BlockType & BlockMeta are used to decide what kind of Mob can Spawn here
// MaxPackSize is set to the maximal size for a pack this type of mob
- cMonster * TryToSpawnHere(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, BLOCKTYPE a_BlockType_below, NIBBLETYPE a_BlockMeta_below, BLOCKTYPE a_BlockType_above, NIBBLETYPE a_BlockMeta_above, EMCSBiome a_Biome, int a_Level, int& a_MaxPackSize);
+ cMonster * TryToSpawnHere(cChunk * a_Chunk, int A_RelX, int a_RelY, int a_RelZ, EMCSBiome a_Biome, int& a_MaxPackSize);
// mark the beginning of a new Pack
// all mobs of the same Pack are the same type
@@ -52,7 +53,7 @@ public :
protected :
// return true if specified type of mob can spawn on specified block
- bool CanSpawnHere(cMonster::eType a_MobType, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, BLOCKTYPE a_BlockType_below, NIBBLETYPE a_BlockMeta_below, BLOCKTYPE a_BlockType_above, NIBBLETYPE a_BlockMeta_above, EMCSBiome a_Biome, int a_Level);
+ bool CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, cMonster::eType a_MobType, EMCSBiome a_Biome);
// return a random type that can spawn on specified biome.
// returns E_ENTITY_TYPE_DONOTUSE if none is possible
diff --git a/source/Mobs/Horse.cpp b/source/Mobs/Horse.cpp
index f9705a451..d18887ea4 100644
--- a/source/Mobs/Horse.cpp
+++ b/source/Mobs/Horse.cpp
@@ -1,4 +1,3 @@
-
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Horse.h"
@@ -142,6 +141,10 @@ void cHorse::OnRightClicked(cPlayer & a_Player)
void cHorse::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 2, E_ITEM_LEATHER);
+ if (m_bIsSaddled)
+ {
+ a_Drops.push_back(cItem(E_ITEM_SADDLE, 1));
+ }
}
diff --git a/source/Mobs/Pig.cpp b/source/Mobs/Pig.cpp
index 5427cf35f..0871a38a9 100644
--- a/source/Mobs/Pig.cpp
+++ b/source/Mobs/Pig.cpp
@@ -22,6 +22,10 @@ cPig::cPig(void) :
void cPig::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 1, 3, IsOnFire() ? E_ITEM_COOKED_PORKCHOP : E_ITEM_RAW_PORKCHOP);
+ if (m_bIsSaddled)
+ {
+ a_Drops.push_back(cItem(E_ITEM_SADDLE, 1));
+ }
}
diff --git a/source/Protocol/Protocol.h b/source/Protocol/Protocol.h
index 5071f5961..6bea4edbb 100644
--- a/source/Protocol/Protocol.h
+++ b/source/Protocol/Protocol.h
@@ -77,6 +77,7 @@ public:
virtual void SendKeepAlive (int a_PingID) = 0;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) = 0;
virtual void SendPickupSpawn (const cPickup & a_Pickup) = 0;
+ virtual void SendPlayerAbilities (void) = 0;
virtual void SendPlayerAnimation (const cPlayer & a_Player, char a_Animation) = 0;
virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) = 0;
virtual void SendPlayerMaxSpeed (void) = 0; ///< Informs the client of the maximum player speed (1.6.1+)
@@ -186,6 +187,27 @@ protected:
WriteInt(a_Vector.y);
WriteInt(a_Vector.z);
}
+
+ void WriteVarInt(UInt32 a_Value)
+ {
+ // A 32-bit integer can be encoded by at most 5 bytes:
+ unsigned char b[5];
+ int idx = 0;
+ do
+ {
+ b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00);
+ a_Value = a_Value >> 7;
+ idx++;
+ } while (a_Value > 0);
+
+ SendData((const char *)b, idx);
+ }
+
+ void WriteVarUTF8String(const AString & a_String)
+ {
+ WriteVarInt(a_String.size());
+ SendData(a_String.data(), a_String.size());
+ }
} ;
diff --git a/source/Protocol/Protocol125.h b/source/Protocol/Protocol125.h
index ae198780c..1da50a1d4 100644
--- a/source/Protocol/Protocol125.h
+++ b/source/Protocol/Protocol125.h
@@ -54,6 +54,7 @@ public:
virtual void SendKeepAlive (int a_PingID) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
+ virtual void SendPlayerAbilities (void) override {} // This protocol doesn't support such message
virtual void SendPlayerAnimation (const cPlayer & a_Player, char a_Animation) override;
virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) override;
virtual void SendPlayerMaxSpeed (void) override;
@@ -92,9 +93,9 @@ protected:
PARSE_INCOMPLETE = -3,
} ;
- cByteBuffer m_ReceivedData; //< Buffer for the received data
+ cByteBuffer m_ReceivedData; ///< Buffer for the received data
- AString m_Username; //< Stored in ParseHandshake(), compared to Login username
+ AString m_Username; ///< Stored in ParseHandshake(), compared to Login username
virtual void SendData(const char * a_Data, int a_Size) override;
diff --git a/source/Protocol/Protocol17x.cpp b/source/Protocol/Protocol17x.cpp
new file mode 100644
index 000000000..38260d046
--- /dev/null
+++ b/source/Protocol/Protocol17x.cpp
@@ -0,0 +1,1445 @@
+
+// Protocol17x.cpp
+
+/*
+Implements the 1.7.x protocol classes:
+ - cProtocol172
+ - release 1.7.2 protocol (#4)
+(others may be added later in the future for the 1.7 release series)
+*/
+
+#include "Globals.h"
+#include "Protocol17x.h"
+#include "ChunkDataSerializer.h"
+#include "../ClientHandle.h"
+#include "../Root.h"
+#include "../Server.h"
+#include "../World.h"
+#include "../WorldStorage/FastNBT.h"
+#include "../StringCompression.h"
+#include "../Entities/FallingBlock.h"
+#include "../Entities/Pickup.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+#define HANDLE_PACKET_READ(Proc, Type, Var) \
+ Type Var; \
+ m_ReceivedData.Proc(Var);
+
+
+
+
+
+cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) :
+ super(a_Client),
+ m_ServerAddress(a_ServerAddress),
+ m_ServerPort(a_ServerPort),
+ m_State(a_State),
+ m_ReceivedData(32 KiB),
+ m_OutPacketBuffer(64 KiB),
+ m_OutPacketLenBuffer(20), // 20 bytes is more than enough for one VarInt
+ m_IsEncrypted(false)
+{
+}
+
+
+
+
+
+void cProtocol172::DataReceived(const char * a_Data, int a_Size)
+{
+ if (m_IsEncrypted)
+ {
+ byte Decrypted[512];
+ while (a_Size > 0)
+ {
+ int NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size;
+ m_Decryptor.ProcessData(Decrypted, (byte *)a_Data, NumBytes);
+ AddReceivedData((const char *)Decrypted, NumBytes);
+ a_Size -= NumBytes;
+ a_Data += NumBytes;
+ }
+ }
+ else
+ {
+ AddReceivedData(a_Data, a_Size);
+ }
+}
+
+
+
+
+
+void cProtocol172::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle)
+{
+ cPacketizer Pkt(*this, 0x1b); // Attach Entity packet
+ Pkt.WriteInt(a_Entity.GetUniqueID());
+ Pkt.WriteInt((a_Vehicle != NULL) ? a_Vehicle->GetUniqueID() : 0);
+ Pkt.WriteBool(false);
+}
+
+
+
+
+
+void cProtocol172::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType)
+{
+ cPacketizer Pkt(*this, 0x24); // Block Action packet
+ Pkt.WriteInt(a_BlockX);
+ Pkt.WriteShort(a_BlockY);
+ Pkt.WriteInt(a_BlockZ);
+ Pkt.WriteByte(a_Byte1);
+ Pkt.WriteByte(a_Byte2);
+ Pkt.WriteVarInt(a_BlockType);
+}
+
+
+
+
+
+void cProtocol172::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage)
+{
+ cPacketizer Pkt(*this, 0x24); // Block Break Animation packet
+ Pkt.WriteInt(a_EntityID);
+ Pkt.WriteInt(a_BlockX);
+ Pkt.WriteInt(a_BlockY);
+ Pkt.WriteInt(a_BlockZ);
+ Pkt.WriteChar(a_Stage);
+}
+
+
+
+
+
+void cProtocol172::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
+{
+ cPacketizer Pkt(*this, 0x23); // Block Change packet
+ Pkt.WriteInt(a_BlockX);
+ Pkt.WriteByte(a_BlockY);
+ Pkt.WriteInt(a_BlockZ);
+ Pkt.WriteVarInt(a_BlockType);
+ Pkt.WriteByte(a_BlockMeta);
+}
+
+
+
+
+
+void cProtocol172::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes)
+{
+ cPacketizer Pkt(*this, 0x22); // Multi Block Change packet
+ Pkt.WriteInt(a_ChunkX);
+ Pkt.WriteInt(a_ChunkZ);
+ Pkt.WriteShort((short)a_Changes.size());
+ Pkt.WriteInt(a_Changes.size() * 4);
+ for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr)
+ {
+ unsigned int Coords = itr->y | (itr->z << 8) | (itr->x << 12);
+ unsigned int Blocks = itr->BlockMeta | (itr->BlockType << 4);
+ Pkt.WriteInt((Coords << 16) | Blocks);
+ } // for itr - a_Changes[]
+}
+
+
+
+
+
+void cProtocol172::SendChat(const AString & a_Message)
+{
+ cPacketizer Pkt(*this, 0x02); // Chat Message packet
+ Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Message).c_str()));
+}
+
+
+
+
+
+void cProtocol172::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer)
+{
+ // Serialize first, before creating the Packetizer (the packetizer locks a CS)
+ // This contains the flags and bitmasks, too
+ const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_3_2);
+
+ cPacketizer Pkt(*this, 0x21); // Chunk Data packet
+ Pkt.WriteInt(a_ChunkX);
+ Pkt.WriteInt(a_ChunkZ);
+ Pkt.WriteBuf(ChunkData.data(), ChunkData.size());
+}
+
+
+
+
+
+void cProtocol172::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player)
+{
+ cPacketizer Pkt(*this, 0x0d); // Collect Item packet
+ Pkt.WriteInt(a_Pickup.GetUniqueID());
+ Pkt.WriteInt(a_Player.GetUniqueID());
+}
+
+
+
+
+
+void cProtocol172::SendDestroyEntity(const cEntity & a_Entity)
+{
+ cPacketizer Pkt(*this, 0x13); // Destroy Entities packet
+ Pkt.WriteByte(1);
+ Pkt.WriteInt(a_Entity.GetUniqueID());
+}
+
+
+
+
+
+void cProtocol172::SendDisconnect(const AString & a_Reason)
+{
+ cPacketizer Pkt(*this, 0x40);
+ Pkt.WriteString(a_Reason);
+}
+
+
+
+
+
+void cProtocol172::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ cPacketizer Pkt(*this, 0x36); // Sign Editor Open packet
+ Pkt.WriteInt(a_BlockX);
+ Pkt.WriteInt(a_BlockY);
+ Pkt.WriteInt(a_BlockZ);
+}
+
+
+
+
+
+void cProtocol172::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item)
+{
+ cPacketizer Pkt(*this, 0x04); // Entity Equipment packet
+ Pkt.WriteInt(a_Entity.GetUniqueID());
+ Pkt.WriteShort(a_SlotNum);
+ Pkt.WriteItem(a_Item);
+}
+
+
+
+
+
+void cProtocol172::SendEntityHeadLook(const cEntity & a_Entity)
+{
+ cPacketizer Pkt(*this, 0x19); // Entity Head Look packet
+ Pkt.WriteInt(a_Entity.GetUniqueID());
+ Pkt.WriteByteAngle(a_Entity.GetHeadYaw());
+}
+
+
+
+
+
+void cProtocol172::SendEntityLook(const cEntity & a_Entity)
+{
+ cPacketizer Pkt(*this, 0x16); // Entity Look packet
+ Pkt.WriteInt(a_Entity.GetUniqueID());
+ Pkt.WriteByteAngle(a_Entity.GetYaw());
+ Pkt.WriteByteAngle(a_Entity.GetPitch());
+}
+
+
+
+
+
+void cProtocol172::SendEntityMetadata(const cEntity & a_Entity)
+{
+ /*
+ // TODO
+ cPacketizer Pkt(*this, 0x1c); // Entity Metadata packet
+ Pkt.WriteInt(a_Entity.GetUniqueID());
+ Pkt.WriteEntityMetadata(a_Entity);
+ */
+}
+
+
+
+
+
+void cProtocol172::SendEntityProperties(const cEntity & a_Entity)
+{
+ /*
+ cPacketizer Pkt(*this, 0x20); // Entity Properties packet
+ Pkt.WriteInt(a_Entity.GetUniqueID());
+ // TODO
+ */
+}
+
+
+
+
+
+void cProtocol172::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
+{
+ cPacketizer Pkt(*this, 0x15); // Entity Relative Move packet
+ Pkt.WriteInt(a_Entity.GetUniqueID());
+ Pkt.WriteByte(a_RelX);
+ Pkt.WriteByte(a_RelY);
+ Pkt.WriteByte(a_RelZ);
+}
+
+
+
+
+
+void cProtocol172::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
+{
+ cPacketizer Pkt(*this, 0x17); // Entity Look And Relative Move packet
+ Pkt.WriteInt(a_Entity.GetUniqueID());
+ Pkt.WriteByte(a_RelX);
+ Pkt.WriteByte(a_RelY);
+ Pkt.WriteByte(a_RelZ);
+ Pkt.WriteByteAngle(a_Entity.GetYaw());
+ Pkt.WriteByteAngle(a_Entity.GetPitch());
+}
+
+
+
+
+
+void cProtocol172::SendEntityStatus(const cEntity & a_Entity, char a_Status)
+{
+ cPacketizer Pkt(*this, 0x1a); // Entity Status packet
+ Pkt.WriteInt(a_Entity.GetUniqueID());
+ Pkt.WriteChar(a_Status);
+}
+
+
+
+
+
+void cProtocol172::SendEntityVelocity(const cEntity & a_Entity)
+{
+ cPacketizer Pkt(*this, 0x12); // Entity Velocity packet
+ Pkt.WriteInt(a_Entity.GetUniqueID());
+ // 400 = 8000 / 20 ... Conversion from our speed in m/s to 8000 m/tick
+ Pkt.WriteShort((short)(a_Entity.GetSpeedX() * 400));
+ Pkt.WriteShort((short)(a_Entity.GetSpeedY() * 400));
+ Pkt.WriteShort((short)(a_Entity.GetSpeedZ() * 400));
+}
+
+
+
+
+
+void cProtocol172::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion)
+{
+ cPacketizer Pkt(*this, 0x27); // Explosion packet
+ Pkt.WriteFloat((float)a_BlockX);
+ Pkt.WriteFloat((float)a_BlockY);
+ Pkt.WriteFloat((float)a_BlockZ);
+ Pkt.WriteFloat((float)a_Radius);
+ Pkt.WriteInt(a_BlocksAffected.size());
+ for (cVector3iArray::const_iterator itr = a_BlocksAffected.begin(), end = a_BlocksAffected.end(); itr != end; ++itr)
+ {
+ Pkt.WriteChar((char)itr->x);
+ Pkt.WriteChar((char)itr->y);
+ Pkt.WriteChar((char)itr->z);
+ } // for itr - a_BlockAffected[]
+ Pkt.WriteFloat((float)a_PlayerMotion.x);
+ Pkt.WriteFloat((float)a_PlayerMotion.y);
+ Pkt.WriteFloat((float)a_PlayerMotion.z);
+}
+
+
+
+
+
+void cProtocol172::SendGameMode(eGameMode a_GameMode)
+{
+ cPacketizer Pkt(*this, 0x2b); // Change Game State packet
+ Pkt.WriteByte(3); // Reason: Change game mode
+ Pkt.WriteFloat((float)a_GameMode);
+}
+
+
+
+
+
+void cProtocol172::SendHealth(void)
+{
+ cPacketizer Pkt(*this, 0x06); // Update Health packet
+ Pkt.WriteFloat((float)m_Client->GetPlayer()->GetHealth());
+ Pkt.WriteShort(m_Client->GetPlayer()->GetFoodLevel());
+ Pkt.WriteFloat((float)m_Client->GetPlayer()->GetFoodSaturationLevel());
+}
+
+
+
+
+
+void cProtocol172::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item)
+{
+ cPacketizer Pkt(*this, 0x2f); // Set Slot packet
+ Pkt.WriteChar(a_WindowID);
+ Pkt.WriteShort(a_SlotNum);
+ Pkt.WriteItem(a_Item);
+}
+
+
+
+
+
+void cProtocol172::SendKeepAlive(int a_PingID)
+{
+ cPacketizer Pkt(*this, 0x00); // Keep Alive packet
+ Pkt.WriteInt(a_PingID);
+}
+
+
+
+
+
+void cProtocol172::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
+{
+ // Send the Join Game packet:
+ {
+ cPacketizer Pkt(*this, 0x01); // Join Game packet
+ Pkt.WriteInt(a_Player.GetUniqueID());
+ Pkt.WriteByte((Byte)a_Player.GetEffectiveGameMode());
+ Pkt.WriteChar((char)a_World.GetDimension());
+ Pkt.WriteByte(2); // TODO: Difficulty (set to Normal)
+ Pkt.WriteByte(cRoot::Get()->GetServer()->GetMaxPlayers());
+ Pkt.WriteString("default"); // Level type - wtf?
+ }
+
+ // Send the spawn position:
+ {
+ cPacketizer Pkt(*this, 0x05); // Spawn Position packet
+ Pkt.WriteInt((int)a_World.GetSpawnX());
+ Pkt.WriteInt((int)a_World.GetSpawnY());
+ Pkt.WriteInt((int)a_World.GetSpawnZ());
+ }
+
+ // Send player abilities:
+ SendPlayerAbilities();
+}
+
+
+
+
+
+void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup)
+{
+ {
+ cPacketizer Pkt(*this, 0x0e); // Spawn Object packet
+ Pkt.WriteInt(a_Pickup.GetUniqueID());
+ Pkt.WriteByte(2); // Type = Pickup
+ Pkt.WriteFPInt(a_Pickup.GetPosX());
+ Pkt.WriteFPInt(a_Pickup.GetPosY());
+ Pkt.WriteFPInt(a_Pickup.GetPosZ());
+ Pkt.WriteByteAngle(a_Pickup.GetYaw());
+ Pkt.WriteByteAngle(a_Pickup.GetPitch());
+ Pkt.WriteInt(0); // No object data
+ }
+ {
+ cPacketizer Pkt(*this, 0x1c); // Entity Metadata packet
+ Pkt.WriteInt(a_Pickup.GetUniqueID());
+ Pkt.WriteByte((0x05 << 5) | 10); // Slot type + index 10
+ Pkt.WriteItem(a_Pickup.GetItem());
+ Pkt.WriteByte(0x7f); // End of metadata
+ }
+}
+
+
+
+
+
+void cProtocol172::SendPlayerAbilities(void)
+{
+ cPacketizer Pkt(*this, 0x39); // Player Abilities packet
+ Byte Flags = 0;
+ if (m_Client->GetPlayer()->IsGameModeCreative())
+ {
+ Flags |= 0x01;
+ }
+ // TODO: Other flags (god mode, flying, can fly
+ Pkt.WriteByte(Flags);
+ // TODO: Pkt.WriteFloat(m_Client->GetPlayer()->GetMaxFlyingSpeed());
+ Pkt.WriteFloat(0.05f);
+ Pkt.WriteFloat((float)m_Client->GetPlayer()->GetMaxSpeed());
+}
+
+
+
+
+
+void cProtocol172::SendPlayerAnimation(const cPlayer & a_Player, char a_Animation)
+{
+ cPacketizer Pkt(*this, 0x0b); // Animation packet
+ Pkt.WriteInt(a_Player.GetUniqueID());
+ Pkt.WriteChar(a_Animation);
+}
+
+
+
+
+
+void cProtocol172::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
+{
+ cPacketizer Pkt(*this, 0x38); // Playerlist Item packet
+ Pkt.WriteString(a_Player.GetName());
+ Pkt.WriteBool(a_IsOnline);
+ Pkt.WriteShort(a_Player.GetClientHandle()->GetPing());
+}
+
+
+
+
+
+void cProtocol172::SendPlayerMaxSpeed(void)
+{
+ SendPlayerAbilities();
+}
+
+
+
+
+
+void cProtocol172::SendPlayerMoveLook(void)
+{
+ cPacketizer Pkt(*this, 0x08); // Player Position And Look packet
+ Pkt.WriteDouble(m_Client->GetPlayer()->GetPosX());
+ Pkt.WriteDouble(m_Client->GetPlayer()->GetPosY());
+ Pkt.WriteDouble(m_Client->GetPlayer()->GetPosZ());
+ Pkt.WriteFloat((float)m_Client->GetPlayer()->GetYaw());
+ Pkt.WriteFloat((float)m_Client->GetPlayer()->GetPitch());
+ Pkt.WriteBool(m_Client->GetPlayer()->IsOnGround());
+}
+
+
+
+
+
+void cProtocol172::SendPlayerPosition(void)
+{
+ // There is no dedicated packet for this, send the whole thing:
+ SendPlayerMoveLook();
+}
+
+
+
+
+
+void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player)
+{
+ // Called to spawn another player for the client
+ cPacketizer Pkt(*this, 0x0c); // Spawn Player packet
+ Pkt.WriteInt(a_Player.GetUniqueID());
+ Pkt.WriteString(Printf("%d", a_Player.GetUniqueID())); // TODO: Proper UUID
+ Pkt.WriteString(a_Player.GetName());
+ Pkt.WriteFPInt(a_Player.GetPosX());
+ Pkt.WriteFPInt(a_Player.GetPosY());
+ Pkt.WriteFPInt(a_Player.GetPosZ());
+ Pkt.WriteByteAngle(a_Player.GetYaw());
+ Pkt.WriteByteAngle(a_Player.GetPitch());
+ short ItemType = a_Player.GetEquippedItem().IsEmpty() ? 0 : a_Player.GetEquippedItem().m_ItemType;
+ Pkt.WriteShort(ItemType);
+ Pkt.WriteByte((3 << 5) | 6); // Metadata: float + index 6
+ Pkt.WriteFloat((float)a_Player.GetHealth());
+ Pkt.WriteByte(0x7f); // Metadata: end
+}
+
+
+
+
+
+void cProtocol172::SendRespawn(void)
+{
+ cPacketizer Pkt(*this, 0x07); // Respawn packet
+ Pkt.WriteInt(m_Client->GetPlayer()->GetWorld()->GetDimension());
+ Pkt.WriteByte(2); // TODO: Difficulty (set to Normal)
+ Pkt.WriteByte((Byte)m_Client->GetPlayer()->GetEffectiveGameMode());
+ Pkt.WriteString("default");
+}
+
+
+
+
+
+void cProtocol172::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) // a_Src coords are Block * 8
+{
+ cPacketizer Pkt(*this, 0x29); // Sound Effect packet
+ Pkt.WriteString(a_SoundName);
+ Pkt.WriteInt(a_SrcX);
+ Pkt.WriteInt(a_SrcY);
+ Pkt.WriteInt(a_SrcZ);
+ Pkt.WriteFloat(a_Volume);
+ Pkt.WriteByte((Byte)(a_Pitch * 63));
+}
+
+
+
+
+
+void cProtocol172::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data)
+{
+ cPacketizer Pkt(*this, 0x28); // Effect packet
+ Pkt.WriteInt(a_EffectID);
+ Pkt.WriteInt(a_SrcX);
+ Pkt.WriteInt(a_SrcY);
+ Pkt.WriteInt(a_SrcZ);
+ Pkt.WriteInt(a_Data);
+ Pkt.WriteBool(false);
+}
+
+
+
+
+
+void cProtocol172::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock)
+{
+ cPacketizer Pkt(*this, 0x0e); // Spawn Object packet
+ Pkt.WriteInt(a_FallingBlock.GetUniqueID());
+ Pkt.WriteByte(70); // Falling block
+ Pkt.WriteFPInt(a_FallingBlock.GetPosX());
+ Pkt.WriteFPInt(a_FallingBlock.GetPosY());
+ Pkt.WriteFPInt(a_FallingBlock.GetPosZ());
+ Pkt.WriteByteAngle(a_FallingBlock.GetYaw());
+ Pkt.WriteByteAngle(a_FallingBlock.GetPitch());
+ Pkt.WriteInt(((int)a_FallingBlock.GetBlockType()) | (((int)a_FallingBlock.GetBlockMeta()) << 12));
+ Pkt.WriteShort((short)(a_FallingBlock.GetSpeedX() * 400));
+ Pkt.WriteShort((short)(a_FallingBlock.GetSpeedY() * 400));
+ Pkt.WriteShort((short)(a_FallingBlock.GetSpeedZ() * 400));
+}
+
+
+
+
+
+void cProtocol172::SendSpawnMob(const cMonster & a_Mob)
+{
+ cPacketizer Pkt(*this, 0x0f); // Spawn Mob packet
+ Pkt.WriteInt(a_Mob.GetUniqueID());
+ Pkt.WriteByte((Byte)a_Mob.GetMobType());
+ Pkt.WriteFPInt(a_Mob.GetPosX());
+ Pkt.WriteFPInt(a_Mob.GetPosY());
+ Pkt.WriteFPInt(a_Mob.GetPosZ());
+ Pkt.WriteByteAngle(a_Mob.GetPitch());
+ Pkt.WriteByteAngle(a_Mob.GetHeadYaw());
+ Pkt.WriteByteAngle(a_Mob.GetYaw());
+ Pkt.WriteShort((short)(a_Mob.GetSpeedX() * 400));
+ Pkt.WriteShort((short)(a_Mob.GetSpeedY() * 400));
+ Pkt.WriteShort((short)(a_Mob.GetSpeedZ() * 400));
+ Pkt.WriteEntityMetadata(a_Mob);
+ Pkt.WriteByte(0x7f); // Metadata terminator
+}
+
+
+
+
+
+void cProtocol172::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch)
+{
+ cPacketizer Pkt(*this, 0xe); // Spawn Object packet
+ Pkt.WriteInt(a_Entity.GetUniqueID());
+ Pkt.WriteByte(a_ObjectType);
+ Pkt.WriteFPInt(a_Entity.GetPosX());
+ Pkt.WriteFPInt(a_Entity.GetPosY());
+ Pkt.WriteFPInt(a_Entity.GetPosZ());
+ Pkt.WriteByteAngle(a_Entity.GetYaw());
+ Pkt.WriteByteAngle(a_Entity.GetPitch());
+ Pkt.WriteInt(a_ObjectData);
+ if (a_ObjectData != 0)
+ {
+ Pkt.WriteShort((short)(a_Entity.GetSpeedX() * 400));
+ Pkt.WriteShort((short)(a_Entity.GetSpeedY() * 400));
+ Pkt.WriteShort((short)(a_Entity.GetSpeedZ() * 400));
+ }
+}
+
+
+
+
+
+void cProtocol172::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType)
+{
+ cPacketizer Pkt(*this, 0xe); // Spawn Object packet
+ Pkt.WriteInt(a_Vehicle.GetUniqueID());
+ Pkt.WriteByte(a_VehicleType);
+ Pkt.WriteFPInt(a_Vehicle.GetPosX());
+ Pkt.WriteFPInt(a_Vehicle.GetPosY());
+ Pkt.WriteFPInt(a_Vehicle.GetPosZ());
+ Pkt.WriteByteAngle(a_Vehicle.GetYaw());
+ Pkt.WriteByteAngle(a_Vehicle.GetPitch());
+ Pkt.WriteInt(a_VehicleSubType);
+ if (a_VehicleSubType != 0)
+ {
+ Pkt.WriteShort((short)(a_Vehicle.GetSpeedX() * 400));
+ Pkt.WriteShort((short)(a_Vehicle.GetSpeedY() * 400));
+ Pkt.WriteShort((short)(a_Vehicle.GetSpeedZ() * 400));
+ }
+}
+
+
+
+
+
+void cProtocol172::SendTabCompletionResults(const AStringVector & a_Results)
+{
+ AString Results;
+ Results.reserve(500); // Make a moderate reservation to avoid excessive reallocations
+ for (AStringVector::const_iterator itr = a_Results.begin(), end = a_Results.end(); itr != end; ++itr)
+ {
+ Results.append(*itr);
+ Results.push_back(0);
+ }
+
+ cPacketizer Pkt(*this, 0x3a); // Tab-Complete packet
+ Pkt.WriteVarInt(a_Results.size());
+ Pkt.WriteString(Results);
+}
+
+
+
+
+
+void cProtocol172::SendTeleportEntity(const cEntity & a_Entity)
+{
+ cPacketizer Pkt(*this, 0x18);
+ Pkt.WriteInt(a_Entity.GetUniqueID());
+ Pkt.WriteFPInt(a_Entity.GetPosX());
+ Pkt.WriteFPInt(a_Entity.GetPosY());
+ Pkt.WriteFPInt(a_Entity.GetPosZ());
+ Pkt.WriteByteAngle(a_Entity.GetYaw());
+ Pkt.WriteByteAngle(a_Entity.GetPitch());
+}
+
+
+
+
+
+void cProtocol172::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ cPacketizer Pkt(*this, 0x2c); // Spawn Global Entity packet
+ Pkt.WriteVarInt(0); // EntityID = 0, always
+ Pkt.WriteByte(1); // Type = Thunderbolt
+ Pkt.WriteFPInt(a_BlockX);
+ Pkt.WriteFPInt(a_BlockY);
+ Pkt.WriteFPInt(a_BlockZ);
+}
+
+
+
+
+
+void cProtocol172::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay)
+{
+ cPacketizer Pkt(*this, 0x03);
+ Pkt.WriteInt64(a_WorldAge);
+ Pkt.WriteInt64(a_TimeOfDay);
+}
+
+
+
+
+
+void cProtocol172::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ )
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::SendWeather(eWeather a_Weather)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::SendWholeInventory(const cInventory & a_Inventory)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::SendWholeInventory(const cWindow & a_Window)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::SendWindowClose(const cWindow & a_Window)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::SendWindowOpen(char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
+{
+ if (!m_ReceivedData.Write(a_Data, a_Size))
+ {
+ // Too much data in the incoming queue, report to caller:
+ m_Client->PacketBufferFull();
+ return;
+ }
+
+ // Handle all complete packets:
+ while (true)
+ {
+ UInt32 PacketLen;
+ if (!m_ReceivedData.ReadVarInt(PacketLen))
+ {
+ // Not enough data
+ return;
+ }
+ if (!m_ReceivedData.CanReadBytes(PacketLen))
+ {
+ // The full packet hasn't been received yet
+ return;
+ }
+ UInt32 PacketType;
+ UInt32 Mark1 = m_ReceivedData.GetReadableSpace();
+ if (!m_ReceivedData.ReadVarInt(PacketType))
+ {
+ // Not enough data
+ return;
+ }
+
+ UInt32 NumBytesRead = Mark1 - m_ReceivedData.GetReadableSpace();
+ HandlePacket(PacketType, PacketLen - NumBytesRead);
+
+ if (Mark1 - m_ReceivedData.GetReadableSpace() > PacketLen)
+ {
+ // Read more than packet length, report as error
+ m_Client->PacketError(PacketType);
+ }
+
+ // Go to packet end in any case:
+ m_ReceivedData.ResetRead();
+ m_ReceivedData.ReadVarInt(PacketType);
+ m_ReceivedData.SkipRead(PacketLen);
+ m_ReceivedData.CommitRead();
+ } // while (true)
+}
+
+
+
+
+void cProtocol172::HandlePacket(UInt32 a_PacketType, UInt32 a_RemainingBytes)
+{
+ switch (m_State)
+ {
+ case 1:
+ {
+ // Status
+ switch (a_PacketType)
+ {
+ case 0x00: HandlePacketStatusRequest(a_RemainingBytes); return;
+ case 0x01: HandlePacketStatusPing (a_RemainingBytes); return;
+ }
+ break;
+ }
+
+ case 2:
+ {
+ // Login
+ switch (a_PacketType)
+ {
+ case 0x00: HandlePacketLoginStart(a_RemainingBytes); return;
+ case 0x01: HandlePacketLoginEncryptionResponse(a_RemainingBytes); return;
+ }
+ break;
+ }
+
+ case 3:
+ {
+ // Game
+ switch (a_PacketType)
+ {
+ case 0x00: HandlePacketKeepAlive (a_RemainingBytes); return;
+ case 0x01: HandlePacketChatMessage (a_RemainingBytes); return;
+ case 0x02: HandlePacketUseEntity (a_RemainingBytes); return;
+ case 0x03: HandlePacketPlayer (a_RemainingBytes); return;
+ case 0x04: HandlePacketPlayerPos (a_RemainingBytes); return;
+ case 0x05: HandlePacketPlayerLook (a_RemainingBytes); return;
+ case 0x06: HandlePacketPlayerPosLook (a_RemainingBytes); return;
+ case 0x07: HandlePacketBlockDig (a_RemainingBytes); return;
+ case 0x08: HandlePacketBlockPlace (a_RemainingBytes); return;
+ case 0x09: HandlePacketSlotSelect (a_RemainingBytes); return;
+ case 0x0a: HandlePacketAnimation (a_RemainingBytes); return;
+ case 0x0b: HandlePacketEntityAction (a_RemainingBytes); return;
+ case 0x0c: HandlePacketSteerVehicle (a_RemainingBytes); return;
+ case 0x0d: HandlePacketWindowClose (a_RemainingBytes); return;
+ case 0x0e: HandlePacketWindowClick (a_RemainingBytes); return;
+ case 0x0f: // Confirm transaction - not used in MCS
+ case 0x10: HandlePacketCreativeInventoryAction(a_RemainingBytes); return;
+ case 0x12: HandlePacketUpdateSign (a_RemainingBytes); return;
+ case 0x13: HandlePacketPlayerAbilities (a_RemainingBytes); return;
+ case 0x14: HandlePacketTabComplete (a_RemainingBytes); return;
+ case 0x15: HandlePacketClientSettings (a_RemainingBytes); return;
+ case 0x16: HandlePacketClientStatus (a_RemainingBytes); return;
+ case 0x17: HandlePacketPluginMessage (a_RemainingBytes); return;
+ }
+ break;
+ }
+ } // switch (m_State)
+
+ // Unknown packet type, report to the client:
+ m_Client->PacketUnknown(a_PacketType);
+ m_ReceivedData.SkipRead(a_RemainingBytes);
+ m_ReceivedData.CommitRead();
+}
+
+
+
+
+
+void cProtocol172::HandlePacketStatusPing(UInt32 a_RemainingBytes)
+{
+ ASSERT(a_RemainingBytes == 8);
+ if (a_RemainingBytes != 8)
+ {
+ m_Client->PacketError(0x01);
+ m_ReceivedData.SkipRead(a_RemainingBytes);
+ m_ReceivedData.CommitRead();
+ return;
+ }
+ Int64 Timestamp;
+ m_ReceivedData.ReadBEInt64(Timestamp);
+ m_ReceivedData.CommitRead();
+
+ cPacketizer Pkt(*this, 0x01); // Ping packet
+ Pkt.WriteInt64(Timestamp);
+}
+
+
+
+
+
+void cProtocol172::HandlePacketStatusRequest(UInt32 a_RemainingBytes)
+{
+ // No more bytes in this packet
+ ASSERT(a_RemainingBytes == 0);
+ m_ReceivedData.CommitRead();
+
+ // Send the response:
+ AString Response = "{\"version\":{\"name\":\"1.7.2\",\"protocol\":4},\"players\":{";
+ AppendPrintf(Response, "\"max\":%u,\"online\":%u,\"sample\":[]},",
+ cRoot::Get()->GetServer()->GetMaxPlayers(),
+ cRoot::Get()->GetServer()->GetNumPlayers()
+ );
+ AppendPrintf(Response, "\"description\":{\"text\":\"%s\"}",
+ cRoot::Get()->GetServer()->GetDescription().c_str()
+ );
+ Response.append("}");
+
+ cPacketizer Pkt(*this, 0x00); // Response packet
+ Pkt.WriteString(Response);
+}
+
+
+
+
+
+void cProtocol172::HandlePacketLoginEncryptionResponse(UInt32 a_RemainingBytes)
+{
+ // TODO: Add protocol encryption
+}
+
+
+
+
+
+void cProtocol172::HandlePacketLoginStart(UInt32 a_RemainingBytes)
+{
+ AString Username;
+ m_ReceivedData.ReadVarUTF8String(Username);
+
+ // TODO: Protocol encryption should be set up here if not localhost / auth
+
+ // Send login success:
+ {
+ cPacketizer Pkt(*this, 0x02); // Login success packet
+ Pkt.WriteString(Printf("%d", m_Client->GetUniqueID())); // TODO: proper UUID
+ Pkt.WriteString(Username);
+ }
+
+ m_State = 3; // State = Game
+ m_Client->HandleLogin(4, Username);
+}
+
+
+
+
+
+void cProtocol172::HandlePacketAnimation(UInt32 a_RemainingBytes)
+{
+ HANDLE_PACKET_READ(ReadBEInt, int, EntityID);
+ HANDLE_PACKET_READ(ReadByte, Byte, Animation);
+ m_Client->HandleAnimation(Animation);
+}
+
+
+
+
+
+void cProtocol172::HandlePacketBlockDig(UInt32 a_RemainingBytes)
+{
+ HANDLE_PACKET_READ(ReadByte, Byte, Status);
+ HANDLE_PACKET_READ(ReadBEInt, int, BlockX);
+ HANDLE_PACKET_READ(ReadByte, Byte, BlockY);
+ HANDLE_PACKET_READ(ReadBEInt, int, BlockZ);
+ HANDLE_PACKET_READ(ReadByte, Byte, Face);
+ m_Client->HandleLeftClick(BlockX, BlockY, BlockZ, Face, Status);
+}
+
+
+
+
+
+void cProtocol172::HandlePacketBlockPlace(UInt32 a_RemainingBytes)
+{
+ HANDLE_PACKET_READ(ReadBEInt, int, BlockX);
+ HANDLE_PACKET_READ(ReadByte, Byte, BlockY);
+ HANDLE_PACKET_READ(ReadBEInt, int, BlockZ);
+ HANDLE_PACKET_READ(ReadByte, Byte, Face);
+ HANDLE_PACKET_READ(ReadByte, Byte, CursorX);
+ HANDLE_PACKET_READ(ReadByte, Byte, CursorY);
+ HANDLE_PACKET_READ(ReadByte, Byte, CursorZ);
+ m_Client->HandleRightClick(BlockX, BlockY, BlockZ, Face, CursorX, CursorY, CursorZ, m_Client->GetPlayer()->GetEquippedItem());
+}
+
+
+
+
+
+void cProtocol172::HandlePacketChatMessage(UInt32 a_RemainingBytes)
+{
+ HANDLE_PACKET_READ(ReadVarUTF8String, AString, Message);
+ m_Client->HandleChat(Message);
+}
+
+
+
+
+
+void cProtocol172::HandlePacketClientSettings(UInt32 a_RemainingBytes)
+{
+ HANDLE_PACKET_READ(ReadVarUTF8String, AString, Locale);
+ HANDLE_PACKET_READ(ReadByte, Byte, ViewDistance);
+ HANDLE_PACKET_READ(ReadByte, Byte, ChatFlags);
+ HANDLE_PACKET_READ(ReadByte, Byte, Unused);
+ HANDLE_PACKET_READ(ReadByte, Byte, Difficulty);
+ HANDLE_PACKET_READ(ReadByte, Byte, ShowCape);
+ // TODO: handle in m_Client
+}
+
+
+
+
+
+void cProtocol172::HandlePacketClientStatus(UInt32 a_RemainingBytes)
+{
+ HANDLE_PACKET_READ(ReadByte, Byte, ActionID);
+ switch (ActionID)
+ {
+ case 0:
+ {
+ // Respawn
+ m_Client->HandleRespawn();
+ break;
+ }
+ case 1:
+ {
+ // Request stats
+ // TODO
+ break;
+ }
+ case 2:
+ {
+ // Open Inventory achievement
+ // TODO
+ break;
+ }
+ }
+}
+
+
+
+
+
+void cProtocol172::HandlePacketCreativeInventoryAction(UInt32 a_RemainingBytes)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::HandlePacketEntityAction(UInt32 a_RemainingBytes)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::HandlePacketKeepAlive(UInt32 a_RemainingBytes)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::HandlePacketPlayer(UInt32 a_RemainingBytes)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::HandlePacketPlayerAbilities(UInt32 a_RemainingBytes)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::HandlePacketPlayerLook(UInt32 a_RemainingBytes)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::HandlePacketPlayerPos(UInt32 a_RemainingBytes)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::HandlePacketPlayerPosLook(UInt32 a_RemainingBytes)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::HandlePacketPluginMessage(UInt32 a_RemainingBytes)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::HandlePacketSlotSelect(UInt32 a_RemainingBytes)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::HandlePacketSteerVehicle(UInt32 a_RemainingBytes)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::HandlePacketTabComplete(UInt32 a_RemainingBytes)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::HandlePacketUpdateSign(UInt32 a_RemainingBytes)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::HandlePacketUseEntity(UInt32 a_RemainingBytes)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::HandlePacketWindowClick(UInt32 a_RemainingBytes)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::HandlePacketWindowClose(UInt32 a_RemainingBytes)
+{
+ // TODO
+}
+
+
+
+
+
+void cProtocol172::WritePacket(cByteBuffer & a_Packet)
+{
+ cCSLock Lock(m_CSPacket);
+ AString Pkt;
+ a_Packet.ReadAll(Pkt);
+ WriteVarInt(Pkt.size());
+ SendData(Pkt.data(), Pkt.size());
+ Flush();
+}
+
+
+
+
+
+void cProtocol172::SendData(const char * a_Data, int a_Size)
+{
+ if (m_IsEncrypted)
+ {
+ byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks)
+ while (a_Size > 0)
+ {
+ int NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size;
+ m_Encryptor.ProcessData(Encrypted, (byte *)a_Data, NumBytes);
+ m_Client->SendData((const char *)Encrypted, NumBytes);
+ a_Size -= NumBytes;
+ a_Data += NumBytes;
+ }
+ }
+ else
+ {
+ m_Client->SendData(a_Data, a_Size);
+ }
+}
+
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cProtocol172::cPacketizer:
+
+cProtocol172::cPacketizer::~cPacketizer()
+{
+ AString DataToSend;
+
+ // Send the packet length
+ UInt32 PacketLen = m_Out.GetUsedSpace();
+ m_Protocol.m_OutPacketLenBuffer.WriteVarInt(PacketLen);
+ m_Protocol.m_OutPacketLenBuffer.ReadAll(DataToSend);
+ m_Protocol.SendData(DataToSend.data(), DataToSend.size());
+ m_Protocol.m_OutPacketLenBuffer.CommitRead();
+
+ // Send the packet data:
+ m_Out.ReadAll(DataToSend);
+ m_Protocol.SendData(DataToSend.data(), DataToSend.size());
+ m_Out.CommitRead();
+}
+
+
+
+
+
+void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
+{
+ short ItemType = a_Item.m_ItemType;
+ ASSERT(ItemType >= -1); // Check validity of packets in debug runtime
+ if (ItemType <= 0)
+ {
+ // Fix, to make sure no invalid values are sent.
+ ItemType = -1;
+ }
+
+ if (a_Item.IsEmpty())
+ {
+ WriteShort(-1);
+ return;
+ }
+
+ WriteShort(ItemType);
+ WriteByte (a_Item.m_ItemCount);
+ WriteShort(a_Item.m_ItemDamage);
+
+ if (a_Item.m_Enchantments.IsEmpty())
+ {
+ WriteShort(-1);
+ return;
+ }
+
+ // Send the enchantments:
+ cFastNBTWriter Writer;
+ const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
+ a_Item.m_Enchantments.WriteToNBTCompound(Writer, TagName);
+ Writer.Finish();
+ AString Compressed;
+ CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
+ WriteShort(Compressed.size());
+ WriteBuf(Compressed.data(), Compressed.size());
+}
+
+
+
+
+
+void cProtocol172::cPacketizer::WriteByteAngle(double a_Angle)
+{
+ WriteByte((char)(255 * a_Angle / 360));
+}
+
+
+
+
+
+void cProtocol172::cPacketizer::WriteFPInt(double a_Value)
+{
+ int Value = (int)(a_Value * 32);
+ WriteInt(Value);
+}
+
+
+
+
+
+void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
+{
+ // Common metadata:
+ Byte Flags = 0;
+ if (a_Entity.IsOnFire())
+ {
+ Flags |= 0x01;
+ }
+ if (a_Entity.IsCrouched())
+ {
+ Flags |= 0x02;
+ }
+ if (a_Entity.IsSprinting())
+ {
+ Flags |= 0x08;
+ }
+ if (a_Entity.IsRclking())
+ {
+ Flags |= 0x10;
+ }
+ if (a_Entity.IsInvisible())
+ {
+ Flags |= 0x20;
+ }
+ WriteByte(0); // Byte(0) + index 0
+ WriteByte(Flags);
+
+ switch (a_Entity.GetEntityType())
+ {
+ case cEntity::etPlayer: break; // TODO?
+ case cEntity::etPickup:
+ {
+ WriteByte((5 << 5) | 10); // Slot(5) + index 10
+ WriteItem(((const cPickup &)a_Entity).GetItem());
+ break;
+ }
+ case cEntity::etMonster:
+ {
+ WriteMobMetadata((const cMonster &)a_Entity);
+ break;
+ }
+ // TODO: Other types
+ }
+}
+
+
+
+
+
+void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob)
+{
+ // TODO
+}
+
+
+
+
diff --git a/source/Protocol/Protocol17x.h b/source/Protocol/Protocol17x.h
new file mode 100644
index 000000000..e3a51b844
--- /dev/null
+++ b/source/Protocol/Protocol17x.h
@@ -0,0 +1,252 @@
+
+// Protocol17x.h
+
+/*
+Declares the 1.7.x protocol classes:
+ - cProtocol172
+ - release 1.7.2 protocol (#4)
+(others may be added later in the future for the 1.7 release series)
+*/
+
+
+
+
+
+#pragma once
+
+#include "Protocol.h"
+#include "../ByteBuffer.h"
+#include "../../CryptoPP/modes.h"
+#include "../../CryptoPP/aes.h"
+
+
+
+
+
+class cProtocol172 :
+ public cProtocol // TODO
+{
+ typedef cProtocol super; // TODO
+
+public:
+
+ cProtocol172(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State);
+
+ /// Called when client sends some data:
+ virtual void DataReceived(const char * a_Data, int a_Size) override;
+
+ /// Sending stuff to clients (alphabetically sorted):
+ virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
+ virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override;
+ virtual void SendBlockBreakAnim (int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override;
+ virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
+ virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override;
+ virtual void SendChat (const AString & a_Message) override;
+ virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override;
+ virtual void SendCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player) override;
+ virtual void SendDestroyEntity (const cEntity & a_Entity) override;
+ virtual void SendDisconnect (const AString & a_Reason) override;
+ virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) override; ///< Request the client to open up the sign editor for the sign (1.6+)
+ virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override;
+ virtual void SendEntityHeadLook (const cEntity & a_Entity) override;
+ virtual void SendEntityLook (const cEntity & a_Entity) override;
+ virtual void SendEntityMetadata (const cEntity & a_Entity) override;
+ virtual void SendEntityProperties (const cEntity & a_Entity) override;
+ virtual void SendEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override;
+ virtual void SendEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) override;
+ virtual void SendEntityStatus (const cEntity & a_Entity, char a_Status) override;
+ virtual void SendEntityVelocity (const cEntity & a_Entity) override;
+ virtual void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) override;
+ virtual void SendGameMode (eGameMode a_GameMode) override;
+ virtual void SendHealth (void) override;
+ virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
+ virtual void SendKeepAlive (int a_PingID) override;
+ virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
+ virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
+ virtual void SendPlayerAbilities (void) override;
+ virtual void SendPlayerAnimation (const cPlayer & a_Player, char a_Animation) override;
+ virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) override;
+ virtual void SendPlayerMaxSpeed (void) override;
+ virtual void SendPlayerMoveLook (void) override;
+ virtual void SendPlayerPosition (void) override;
+ virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
+ virtual void SendRespawn (void) override;
+ virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8
+ virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
+ virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override;
+ virtual void SendSpawnMob (const cMonster & a_Mob) override;
+ virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override;
+ virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override;
+ virtual void SendTabCompletionResults(const AStringVector & a_Results) override;
+ virtual void SendTeleportEntity (const cEntity & a_Entity) override;
+ virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
+ virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay) override;
+ virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
+ virtual void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) override;
+ virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override;
+ virtual void SendWeather (eWeather a_Weather) override;
+ virtual void SendWholeInventory (const cInventory & a_Inventory) override;
+ virtual void SendWholeInventory (const cWindow & a_Window) override;
+ virtual void SendWindowClose (const cWindow & a_Window) override;
+ virtual void SendWindowOpen (char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) override;
+ virtual void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value) override;
+
+ virtual AString GetAuthServerID(void) override { return m_AuthServerID; }
+
+protected:
+
+ /// Composes individual packets in the protocol's m_OutPacketBuffer; sends them upon being destructed
+ class cPacketizer
+ {
+ public:
+ cPacketizer(cProtocol172 & a_Protocol, UInt32 a_PacketType) :
+ m_Protocol(a_Protocol),
+ m_Out(a_Protocol.m_OutPacketBuffer),
+ m_Lock(a_Protocol.m_CSPacket)
+ {
+ m_Out.WriteVarInt(a_PacketType);
+ }
+
+ ~cPacketizer();
+
+ void WriteBool(bool a_Value)
+ {
+ m_Out.WriteBool(a_Value);
+ }
+
+ void WriteByte(Byte a_Value)
+ {
+ m_Out.WriteByte(a_Value);
+ }
+
+ void WriteChar(char a_Value)
+ {
+ m_Out.WriteChar(a_Value);
+ }
+
+ void WriteShort(short a_Value)
+ {
+ m_Out.WriteBEShort(a_Value);
+ }
+
+ void WriteInt(int a_Value)
+ {
+ m_Out.WriteBEInt(a_Value);
+ }
+
+ void WriteInt64(Int64 a_Value)
+ {
+ m_Out.WriteBEInt64(a_Value);
+ }
+
+ void WriteFloat(float a_Value)
+ {
+ m_Out.WriteBEFloat(a_Value);
+ }
+
+ void WriteDouble(double a_Value)
+ {
+ m_Out.WriteBEDouble(a_Value);
+ }
+
+ void WriteVarInt(UInt32 a_Value)
+ {
+ m_Out.WriteVarInt(a_Value);
+ }
+
+ void WriteString(const AString & a_Value)
+ {
+ m_Out.WriteVarUTF8String(a_Value);
+ }
+
+ void WriteBuf(const char * a_Data, int a_Size)
+ {
+ m_Out.Write(a_Data, a_Size);
+ }
+
+ void WriteItem(const cItem & a_Item);
+ void WriteByteAngle(double a_Angle); // Writes the specified angle using a single byte
+ void WriteFPInt(double a_Value); // Writes the double value as a 27:5 fixed-point integer
+ void WriteEntityMetadata(const cEntity & a_Entity); // Writes the metadata for the specified entity, not including the terminating 0x7f
+ void WriteMobMetadata(const cMonster & a_Mob); // Writes the mob-specific metadata for the specified mob
+
+ protected:
+ cProtocol172 & m_Protocol;
+ cByteBuffer & m_Out;
+ cCSLock m_Lock;
+ } ;
+
+ AString m_ServerAddress;
+
+ UInt16 m_ServerPort;
+
+ AString m_AuthServerID;
+
+ /// State of the protocol. 1 = status, 2 = login, 3 = game
+ UInt32 m_State;
+
+ /// Buffer for the received data
+ cByteBuffer m_ReceivedData;
+
+ /// Buffer for composing the outgoing packets, through cPacketizer
+ cByteBuffer m_OutPacketBuffer;
+
+ /// Buffer for composing packet length (so that each cPacketizer instance doesn't allocate a new cPacketBuffer)
+ cByteBuffer m_OutPacketLenBuffer;
+
+ bool m_IsEncrypted;
+ CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption m_Decryptor;
+ CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption m_Encryptor;
+
+
+ /// Adds the received (unencrypted) data to m_ReceivedData, parses complete packets
+ void AddReceivedData(const char * a_Data, int a_Size);
+
+ /// Reads and handles the packet. The packet length and type have already been read.
+ void HandlePacket(UInt32 a_PacketType, UInt32 a_RemainingBytes);
+
+ // Packet handlers while in the Status state (m_State == 1):
+ void HandlePacketStatusPing (UInt32 a_RemainingBytes);
+ void HandlePacketStatusRequest(UInt32 a_RemainingBytes);
+
+ // Packet handlers while in the Login state (m_State == 2):
+ void HandlePacketLoginEncryptionResponse(UInt32 a_RemainingBytes);
+ void HandlePacketLoginStart (UInt32 a_RemainingBytes);
+
+ // Packet handlers while in the Game state (m_State == 3):
+ void HandlePacketAnimation (UInt32 a_RemainingBytes);
+ void HandlePacketBlockDig (UInt32 a_RemainingBytes);
+ void HandlePacketBlockPlace (UInt32 a_RemainingBytes);
+ void HandlePacketChatMessage (UInt32 a_RemainingBytes);
+ void HandlePacketClientSettings (UInt32 a_RemainingBytes);
+ void HandlePacketClientStatus (UInt32 a_RemainingBytes);
+ void HandlePacketCreativeInventoryAction(UInt32 a_RemainingBytes);
+ void HandlePacketEntityAction (UInt32 a_RemainingBytes);
+ void HandlePacketKeepAlive (UInt32 a_RemainingBytes);
+ void HandlePacketPlayer (UInt32 a_RemainingBytes);
+ void HandlePacketPlayerAbilities (UInt32 a_RemainingBytes);
+ void HandlePacketPlayerLook (UInt32 a_RemainingBytes);
+ void HandlePacketPlayerPos (UInt32 a_RemainingBytes);
+ void HandlePacketPlayerPosLook (UInt32 a_RemainingBytes);
+ void HandlePacketPluginMessage (UInt32 a_RemainingBytes);
+ void HandlePacketSlotSelect (UInt32 a_RemainingBytes);
+ void HandlePacketSteerVehicle (UInt32 a_RemainingBytes);
+ void HandlePacketTabComplete (UInt32 a_RemainingBytes);
+ void HandlePacketUpdateSign (UInt32 a_RemainingBytes);
+ void HandlePacketUseEntity (UInt32 a_RemainingBytes);
+ void HandlePacketWindowClick (UInt32 a_RemainingBytes);
+ void HandlePacketWindowClose (UInt32 a_RemainingBytes);
+
+
+ /// Writes an entire packet into the output stream. a_Packet is expected to start with the packet type; data length is prepended here.
+ void WritePacket(cByteBuffer & a_Packet);
+
+ /// Sends the data to the client, encrypting them if needed.
+ virtual void SendData(const char * a_Data, int a_Size) override;
+
+ void SendCompass(const cWorld & a_World);
+} ;
+
+
+
+
diff --git a/source/Protocol/ProtocolRecognizer.cpp b/source/Protocol/ProtocolRecognizer.cpp
index ceada1944..67f924d7e 100644
--- a/source/Protocol/ProtocolRecognizer.cpp
+++ b/source/Protocol/ProtocolRecognizer.cpp
@@ -12,6 +12,7 @@
#include "Protocol14x.h"
#include "Protocol15x.h"
#include "Protocol16x.h"
+#include "Protocol17x.h"
#include "../ClientHandle.h"
#include "../Root.h"
#include "../Server.h"
@@ -384,6 +385,16 @@ void cProtocolRecognizer::SendPickupSpawn(const cPickup & a_Pickup)
+void cProtocolRecognizer::SendPlayerAbilities(void)
+{
+ ASSERT(m_Protocol != NULL);
+ m_Protocol->SendPlayerAbilities();
+}
+
+
+
+
+
void cProtocolRecognizer::SendPlayerAnimation(const cPlayer & a_Player, char a_Animation)
{
ASSERT(m_Protocol != NULL);
@@ -667,11 +678,65 @@ bool cProtocolRecognizer::TryRecognizeProtocol(void)
}
switch (PacketType)
{
- case 0x02: break; // Handshake, continue recognizing
- case 0xfe: HandleServerPing(); return false;
- default: return false;
+ case 0x02: return TryRecognizeLengthlessProtocol(); // Handshake, continue recognizing
+ case 0xfe:
+ {
+ // This may be either a packet length or the length-less Ping packet
+ Byte NextByte;
+ if (!m_Buffer.ReadByte(NextByte))
+ {
+ // Not enough data for either protocol
+ // This could actually happen with the 1.2 / 1.3 client, but their support is fading out anyway
+ return false;
+ }
+ if (NextByte != 0x01)
+ {
+ // This is definitely NOT a length-less Ping packet, handle as lengthed protocol:
+ break;
+ }
+ if (!m_Buffer.ReadByte(NextByte))
+ {
+ // There is no more data. Although this *could* mean TCP fragmentation, it is highly unlikely
+ // and rather this is a 1.4 client sending a regular Ping packet (without the following Plugin message)
+ SendLengthlessServerPing();
+ return false;
+ }
+ if (NextByte == 0xfa)
+ {
+ // Definitely a length-less Ping followed by a Plugin message
+ SendLengthlessServerPing();
+ return false;
+ }
+ // Definitely a lengthed Initial handshake, handle below:
+ break;
+ }
+ } // switch (PacketType)
+
+ // This must be a lengthed protocol, try if it has the entire initial handshake packet:
+ m_Buffer.ResetRead();
+ UInt32 PacketLen;
+ UInt32 ReadSoFar = m_Buffer.GetReadableSpace();
+ if (!m_Buffer.ReadVarInt(PacketLen))
+ {
+ // Not enough bytes for the packet length, keep waiting
+ return false;
}
-
+ ReadSoFar -= m_Buffer.GetReadableSpace();
+ if (!m_Buffer.CanReadBytes(PacketLen))
+ {
+ // Not enough bytes for the packet, keep waiting
+ return false;
+ }
+ return TryRecognizeLengthedProtocol(PacketLen - ReadSoFar);
+}
+
+
+
+
+
+bool cProtocolRecognizer::TryRecognizeLengthlessProtocol(void)
+{
+ // The comm started with 0x02, which is a Handshake packet in the length-less protocol family
// 1.3.2 starts with 0x02 0x39 <name-length-short>
// 1.2.5 starts with 0x02 <name-length-short> and name is expected to less than 0x3900 long :)
char ch;
@@ -724,7 +789,56 @@ bool cProtocolRecognizer::TryRecognizeProtocol(void)
-void cProtocolRecognizer::HandleServerPing(void)
+bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining)
+{
+ UInt32 PacketType;
+ UInt32 NumBytesRead = m_Buffer.GetReadableSpace();
+ if (!m_Buffer.ReadVarInt(PacketType))
+ {
+ return false;
+ }
+ if (PacketType != 0x00)
+ {
+ // Not an initial handshake packet, we don't know how to talk to them
+ LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, initial packet %u)",
+ m_Client->GetIPString().c_str(), PacketType
+ );
+ m_Client->Kick("Unsupported protocol version");
+ return false;
+ }
+ UInt32 ProtocolVersion;
+ if (!m_Buffer.ReadVarInt(ProtocolVersion))
+ {
+ return false;
+ }
+ NumBytesRead -= m_Buffer.GetReadableSpace();
+ switch (ProtocolVersion)
+ {
+ case PROTO_VERSION_1_7_2:
+ {
+ AString ServerAddress;
+ short ServerPort;
+ UInt32 NextState;
+ m_Buffer.ReadVarUTF8String(ServerAddress);
+ m_Buffer.ReadBEShort(ServerPort);
+ m_Buffer.ReadVarInt(NextState);
+ m_Buffer.CommitRead();
+ m_Protocol = new cProtocol172(m_Client, ServerAddress, ServerPort, NextState);
+ return true;
+ }
+ }
+ LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, version %u)",
+ m_Client->GetIPString().c_str(), ProtocolVersion
+ );
+ m_Client->Kick("Unsupported protocol version");
+ return false;
+}
+
+
+
+
+
+void cProtocolRecognizer::SendLengthlessServerPing(void)
{
AString Reply;
switch (cRoot::Get()->GetPrimaryServerVersion())
@@ -757,10 +871,12 @@ void cProtocolRecognizer::HandleServerPing(void)
// http://wiki.vg/wiki/index.php?title=Protocol&oldid=3101#Server_List_Ping_.280xFE.29
// _X 2012_10_31: I know that this needn't eat the byte, since it still may be in transit.
// Who cares? We're disconnecting anyway.
- if (m_Buffer.CanReadBytes(1))
+ m_Buffer.ResetRead();
+ if (m_Buffer.CanReadBytes(2))
{
byte val;
- m_Buffer.ReadByte(val);
+ m_Buffer.ReadByte(val); // Packet type - Serverlist ping
+ m_Buffer.ReadByte(val); // 0x01 magic value
ASSERT(val == 0x01);
}
diff --git a/source/Protocol/ProtocolRecognizer.h b/source/Protocol/ProtocolRecognizer.h
index c53288230..79dc5568f 100644
--- a/source/Protocol/ProtocolRecognizer.h
+++ b/source/Protocol/ProtocolRecognizer.h
@@ -47,6 +47,9 @@ public:
PROTO_VERSION_NEXT,
PROTO_VERSION_LATEST = PROTO_VERSION_NEXT - 1, ///< Automatically assigned to the last protocol version, this serves as the default for PrimaryServerVersion
+
+ // These will be kept "under" the next / latest, because the next and latest are only needed for previous protocols
+ PROTO_VERSION_1_7_2 = 4,
} ;
cProtocolRecognizer(cClientHandle * a_Client);
@@ -86,6 +89,7 @@ public:
virtual void SendKeepAlive (int a_PingID) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
+ virtual void SendPlayerAbilities (void) override;
virtual void SendPlayerAnimation (const cPlayer & a_Player, char a_Animation) override;
virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) override;
virtual void SendPlayerMaxSpeed (void) override;
@@ -124,8 +128,23 @@ protected:
/// Tries to recognize protocol based on m_Buffer contents; returns true if recognized
bool TryRecognizeProtocol(void);
- /// Called when the recognizer gets a server ping packet; responds with server stats and destroys the client
- void HandleServerPing(void);
+ /** Tries to recognize a protocol in the length-less family, based on m_Buffer; returns true if recognized.
+ Handles protocols before release 1.7, that didn't include packet lengths, and started with a 0x02 handshake packet
+ Note that length-less server ping is handled directly in TryRecognizeProtocol(), this function is called only
+ when the 0x02 Handshake packet has been received
+ */
+ bool TryRecognizeLengthlessProtocol(void);
+
+ /** Tries to recognize a protocol in the leghted family (1.7+), based on m_Buffer; returns true if recognized.
+ The packet length and type have already been read, type is 0
+ The number of bytes remaining in the packet is passed as a_PacketLengthRemaining
+ **/
+ bool TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining);
+
+ /** Called when the recognizer gets a length-less protocol's server ping packet
+ Responds with server stats and destroys the client.
+ */
+ void SendLengthlessServerPing(void);
} ;
diff --git a/source/World.cpp b/source/World.cpp
index 786d97a4d..dd3965e3d 100644
--- a/source/World.cpp
+++ b/source/World.cpp
@@ -55,6 +55,12 @@
/// Up to this many m_SpreadQueue elements are handled each world tick
const int MAX_LIGHTING_SPREAD_PER_TICK = 10;
+const int TIME_SUNSET = 12000;
+const int TIME_NIGHT_START = 13187;
+const int TIME_NIGHT_END = 22812;
+const int TIME_SUNRISE = 23999;
+const int TIME_SPAWN_DIVISOR = 148;
+
@@ -229,7 +235,8 @@ cWorld::cWorld(const AString & a_WorldName) :
m_RSList(0),
m_Weather(eWeather_Sunny),
m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :)
- m_TickThread(*this)
+ m_TickThread(*this),
+ m_SkyDarkness(0)
{
LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str());
@@ -608,6 +615,9 @@ void cWorld::Tick(float a_Dt)
m_WorldAge = (Int64)(m_WorldAgeSecs * 20.0);
m_TimeOfDay = (Int64)(m_TimeOfDaySecs * 20.0);
+ // Updates the sky darkness based on current time of day
+ UpdateSkyDarkness();
+
// Broadcast time update every 40 ticks (2 seconds)
if (m_LastTimeUpdate < m_WorldAge - 40)
{
@@ -868,6 +878,31 @@ void cWorld::TickClients(float a_Dt)
+void cWorld::UpdateSkyDarkness(void)
+{
+ int TempTime = (int)m_TimeOfDay;
+ if (TempTime <= TIME_SUNSET)
+ {
+ m_SkyDarkness = 0;
+ }
+ else if (TempTime <= TIME_NIGHT_START)
+ {
+ m_SkyDarkness = (TIME_NIGHT_START - TempTime) / TIME_SPAWN_DIVISOR;
+ }
+ else if (TempTime <= TIME_NIGHT_END)
+ {
+ m_SkyDarkness = 8;
+ }
+ else
+ {
+ m_SkyDarkness = (TIME_SUNRISE - TempTime) / TIME_SPAWN_DIVISOR;
+ }
+}
+
+
+
+
+
void cWorld::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ)
{
return m_ChunkMap->WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
@@ -2676,3 +2711,4 @@ void cWorld::cTaskSaveAllChunks::Run(cWorld & a_World)
+
diff --git a/source/World.h b/source/World.h
index f174a1c2c..c4fd06d0b 100644
--- a/source/World.h
+++ b/source/World.h
@@ -592,6 +592,9 @@ public:
/// Appends all usernames starting with a_Text (case-insensitive) into Results
void TabCompleteUserName(const AString & a_Text, AStringVector & a_Results);
+ /// Get the current darkness level based on the time
+ NIBBLETYPE GetSkyDarkness() { return m_SkyDarkness; }
+
private:
friend class cRoot;
@@ -636,6 +639,8 @@ private:
Int64 m_LastSave; // The last WorldAge (in ticks) in which save-all was triggerred
std::map<cMonster::eFamily,Int64> m_LastSpawnMonster; // The last WorldAge (in ticks) in which a monster was spawned (for each megatype of monster) // MG TODO : find a way to optimize without creating unmaintenability (if mob IDs are becoming unrowed)
+ NIBBLETYPE m_SkyDarkness;
+
eGameMode m_GameMode;
bool m_bEnabledPVP;
bool m_IsDeepSnowEnabled;
@@ -727,6 +732,8 @@ private:
/// Ticks all clients that are in this world
void TickClients(float a_Dt);
+
+ void UpdateSkyDarkness();
/// Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section)
cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock);