openspades/Sources/Client/NetClient.cpp

1725 lines
49 KiB
C++
Raw Normal View History

2013-08-29 11:45:22 +09:00
/*
Copyright (c) 2013 yvt
2013-09-05 00:52:03 +09:00
based on code of pysnip (c) Mathias Kaerlev 2011-2012.
2016-11-20 19:13:00 +09:00
2013-08-29 11:45:22 +09:00
This file is part of OpenSpades.
2016-11-20 19:13:00 +09:00
2013-08-29 11:45:22 +09:00
OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
2016-11-20 19:13:00 +09:00
2013-08-29 11:45:22 +09:00
OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
2016-11-20 19:13:00 +09:00
2013-08-29 11:45:22 +09:00
You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
2016-11-20 19:13:00 +09:00
2013-08-29 11:45:22 +09:00
*/
2013-08-18 16:18:06 +09:00
#include <math.h>
#include <string.h>
#include <vector>
#include "CTFGameMode.h"
#include "Client.h"
#include "GameMap.h"
#include "Grenade.h"
#include "NetClient.h"
#include "Player.h"
#include "TCGameMode.h"
#include "World.h"
#include <Core/CP437.h>
#include <Core/Debug.h>
#include <Core/Debug.h>
#include <Core/DeflateStream.h>
#include <Core/Exception.h>
#include <Core/Math.h>
#include <Core/MemoryStream.h>
#include <Core/Settings.h>
2014-02-28 16:22:00 +09:00
#include <Core/Strings.h>
#include <enet/enet.h>
2016-11-19 21:03:51 +09:00
DEFINE_SPADES_SETTING(cg_protocolVersion, "3");
DEFINE_SPADES_SETTING(cg_unicode, "1");
2013-08-18 16:18:06 +09:00
namespace spades {
namespace client {
2016-11-20 19:13:00 +09:00
2013-12-29 23:08:57 +09:00
static const char UtfSign = -1;
2016-11-20 19:13:00 +09:00
enum { BLUE_FLAG = 0, GREEN_FLAG = 1, BLUE_BASE = 2, GREEN_BASE = 3 };
2013-08-18 16:18:06 +09:00
enum PacketType {
PacketTypePositionData = 0,
PacketTypeOrientationData = 1,
PacketTypeWorldUpdate = 2,
PacketTypeInputData = 3,
PacketTypeWeaponInput = 4,
PacketTypeHitPacket = 5, // C2S
PacketTypeSetHP = 5, // S2C
2013-08-18 16:18:06 +09:00
PacketTypeGrenadePacket = 6,
PacketTypeSetTool = 7,
PacketTypeSetColour = 8,
PacketTypeExistingPlayer = 9,
PacketTypeShortPlayerData = 10,
PacketTypeMoveObject = 11,
PacketTypeCreatePlayer = 12,
PacketTypeBlockAction = 13,
PacketTypeBlockLine = 14,
PacketTypeStateData = 15,
PacketTypeKillAction = 16,
PacketTypeChatMessage = 17,
PacketTypeMapStart = 18, // S2C
PacketTypeMapChunk = 19, // S2C
PacketTypePlayerLeft = 20, // S2P
PacketTypeTerritoryCapture = 21, // S2P
2013-08-18 16:18:06 +09:00
PacketTypeProgressBar = 22,
PacketTypeIntelCapture = 23, // S2P
PacketTypeIntelPickup = 24, // S2P
PacketTypeIntelDrop = 25, // S2P
PacketTypeRestock = 26, // S2P
PacketTypeFogColour = 27, // S2C
PacketTypeWeaponReload = 28, // C2S2P
PacketTypeChangeTeam = 29, // C2S2P
PacketTypeChangeWeapon = 30, // C2S2P
PacketTypeHandShakeInit = 31, // S2C
2013-11-07 00:40:03 +10:00
PacketTypeHandShakeReturn = 32, // C2S
PacketTypeVersionGet = 33, // S2C
PacketTypeVersionSend = 34, // C2S
2013-11-07 00:40:03 +10:00
2013-08-18 16:18:06 +09:00
};
2016-11-20 19:13:00 +09:00
2013-12-29 23:08:57 +09:00
static std::string EncodeString(std::string str) {
auto str2 = CP437::Encode(str, -1);
if (!cg_unicode) {
2013-12-31 14:06:17 +09:00
// ignore fallbacks
return str2;
}
if (str2.find(-1) != std::string::npos) {
2013-12-29 23:08:57 +09:00
// some fallbacks; always use UTF8
str.insert(0, &UtfSign, 1);
} else {
2013-12-31 14:06:17 +09:00
str = str2;
2013-12-29 23:08:57 +09:00
}
return str;
}
2016-11-20 19:13:00 +09:00
2013-12-29 23:08:57 +09:00
static std::string DecodeString(std::string s) {
if (s.size() > 0 && s[0] == UtfSign) {
2013-12-29 23:08:57 +09:00
return s.substr(1);
}
2013-12-31 14:06:17 +09:00
return CP437::Decode(s);
2013-12-29 23:08:57 +09:00
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
class NetPacketReader {
std::vector<char> data;
size_t pos;
2013-08-18 16:18:06 +09:00
public:
NetPacketReader(ENetPacket *packet) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
data.resize(packet->dataLength);
memcpy(data.data(), packet->data, packet->dataLength);
enet_packet_destroy(packet);
pos = 1;
}
2016-11-20 19:13:00 +09:00
NetPacketReader(const std::vector<char> inData) {
2013-08-18 16:18:06 +09:00
data = inData;
pos = 1;
}
PacketType GetType() { return (PacketType)data[0]; }
2013-08-18 16:18:06 +09:00
uint32_t ReadInt() {
SPADES_MARK_FUNCTION();
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
uint32_t value = 0;
if (pos + 4 > data.size()) {
2013-08-18 16:18:06 +09:00
SPRaise("Received packet truncated");
}
value |= ((uint32_t)(uint8_t)data[pos++]);
value |= ((uint32_t)(uint8_t)data[pos++]) << 8;
value |= ((uint32_t)(uint8_t)data[pos++]) << 16;
value |= ((uint32_t)(uint8_t)data[pos++]) << 24;
return value;
}
2013-08-18 16:18:06 +09:00
uint16_t ReadShort() {
SPADES_MARK_FUNCTION();
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
uint32_t value = 0;
if (pos + 2 > data.size()) {
2013-08-18 16:18:06 +09:00
SPRaise("Received packet truncated");
}
value |= ((uint32_t)(uint8_t)data[pos++]);
value |= ((uint32_t)(uint8_t)data[pos++]) << 8;
return (uint16_t)value;
}
2013-08-18 16:18:06 +09:00
uint8_t ReadByte() {
SPADES_MARK_FUNCTION();
2016-11-20 19:13:00 +09:00
if (pos >= data.size()) {
2013-08-18 16:18:06 +09:00
SPRaise("Received packet truncated");
}
return (uint8_t)data[pos++];
}
2013-08-18 16:18:06 +09:00
float ReadFloat() {
SPADES_MARK_FUNCTION();
union {
float f;
uint32_t v;
};
v = ReadInt();
return f;
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
IntVector3 ReadIntColor() {
SPADES_MARK_FUNCTION();
IntVector3 col;
col.z = ReadByte();
col.y = ReadByte();
col.x = ReadByte();
return col;
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Vector3 ReadFloatColor() {
SPADES_MARK_FUNCTION();
Vector3 col;
col.z = ReadByte() / 255.f;
col.y = ReadByte() / 255.f;
col.x = ReadByte() / 255.f;
return col;
}
2016-11-20 19:13:00 +09:00
std::vector<char> GetData() { return data; }
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
std::string ReadData(size_t siz) {
if (pos + siz > data.size()) {
2013-08-18 16:18:06 +09:00
SPRaise("Received packet truncated");
}
std::string s = std::string(data.data() + pos, siz);
pos += siz;
return s;
}
std::string ReadRemainingData() {
return std::string(data.data() + pos, data.size() - pos);
2013-08-18 16:18:06 +09:00
}
2016-11-20 19:13:00 +09:00
std::string ReadString(size_t siz) {
2013-08-18 16:18:06 +09:00
// convert to C string once so that
// null-chars are removed
2013-12-29 23:08:57 +09:00
std::string s = ReadData(siz).c_str();
s = DecodeString(s);
return s;
2013-08-18 16:18:06 +09:00
}
std::string ReadRemainingString() {
2013-08-26 19:24:15 +09:00
// convert to C string once so that
// null-chars are removed
2013-12-29 23:08:57 +09:00
std::string s = ReadRemainingData().c_str();
s = DecodeString(s);
return s;
2013-08-18 16:18:06 +09:00
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
void DumpDebug() {
#if 1
2013-08-26 01:27:44 +09:00
char buf[1024];
std::string str;
sprintf(buf, "Packet 0x%02x [len=%d]", (int)GetType(), (int)data.size());
2013-08-26 01:27:44 +09:00
str = buf;
2013-08-18 16:18:06 +09:00
int bytes = (int)data.size();
if (bytes > 64) {
2013-08-18 16:18:06 +09:00
bytes = 64;
}
for (int i = 0; i < bytes; i++) {
2013-08-26 01:27:44 +09:00
sprintf(buf, " %02x", (unsigned int)(unsigned char)data[i]);
str += buf;
}
2016-11-20 19:13:00 +09:00
2013-08-26 01:27:44 +09:00
SPLog("%s", str.c_str());
2013-08-18 16:18:06 +09:00
#endif
}
};
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
class NetPacketWriter {
std::vector<char> data;
2013-08-18 16:18:06 +09:00
public:
NetPacketWriter(PacketType type) { data.push_back(type); }
2016-11-20 19:13:00 +09:00
void Write(uint8_t v) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION_DEBUG();
data.push_back(v);
}
void Write(uint16_t v) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION_DEBUG();
data.push_back((char)(v));
data.push_back((char)(v >> 8));
}
void Write(uint32_t v) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION_DEBUG();
data.push_back((char)(v));
data.push_back((char)(v >> 8));
data.push_back((char)(v >> 16));
data.push_back((char)(v >> 24));
}
void Write(float v) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION_DEBUG();
union {
float f;
uint32_t i;
2013-08-18 16:18:06 +09:00
};
f = v;
Write(i);
}
void WriteColor(IntVector3 v) {
2013-08-18 16:18:06 +09:00
Write((uint8_t)v.z);
Write((uint8_t)v.y);
Write((uint8_t)v.x);
}
2016-11-20 19:13:00 +09:00
void Write(std::string str) {
2013-12-29 23:08:57 +09:00
str = EncodeString(str);
data.insert(data.end(), str.begin(), str.end());
2013-08-18 16:18:06 +09:00
}
2016-11-20 19:13:00 +09:00
void Write(std::string str, size_t fillLen) {
2013-12-29 23:08:57 +09:00
str = EncodeString(str);
2013-08-18 16:18:06 +09:00
Write(str.substr(0, fillLen));
size_t sz = str.size();
while (sz < fillLen) {
2013-08-18 16:18:06 +09:00
Write((uint8_t)0);
sz++;
}
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
ENetPacket *CreatePacket(int flag = ENET_PACKET_FLAG_RELIABLE) {
return enet_packet_create(data.data(), data.size(), flag);
2013-08-18 16:18:06 +09:00
}
};
2016-11-20 19:13:00 +09:00
NetClient::NetClient(Client *c) : client(c), host(nullptr), peer(nullptr) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
enet_initialize();
2013-08-26 01:27:44 +09:00
SPLog("ENet initialized");
2016-11-20 19:13:00 +09:00
host = enet_host_create(NULL, 1, 1, 100000, 100000);
2013-08-26 01:27:44 +09:00
SPLog("ENet host created");
if (!host) {
2013-08-18 16:18:06 +09:00
SPRaise("Failed to create ENet host");
}
2016-11-20 19:13:00 +09:00
if (enet_host_compress_with_range_coder(host) < 0)
2013-08-18 16:18:06 +09:00
SPRaise("Failed to enable ENet Range coder.");
2016-11-20 19:13:00 +09:00
2013-08-26 01:27:44 +09:00
SPLog("ENet Range Coder Enabled");
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
peer = NULL;
status = NetClientStatusNotConnected;
2016-11-20 19:13:00 +09:00
lastPlayerInput = 0;
lastWeaponInput = 0;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
savedPlayerPos.resize(32);
savedPlayerFront.resize(32);
savedPlayerTeam.resize(32);
playerPosRecords.resize(32);
2016-11-20 19:13:00 +09:00
std::fill(savedPlayerTeam.begin(), savedPlayerTeam.end(), -1);
2016-11-20 19:13:00 +09:00
2014-03-31 23:09:47 +09:00
bandwidthMonitor.reset(new BandwidthMonitor(host));
2013-08-18 16:18:06 +09:00
}
NetClient::~NetClient() {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Disconnect();
if (host)
2014-03-31 23:09:47 +09:00
enet_host_destroy(host);
bandwidthMonitor.reset();
2013-08-26 01:27:44 +09:00
SPLog("ENet host destroyed");
2013-08-18 16:18:06 +09:00
}
2016-11-20 19:13:00 +09:00
void NetClient::Connect(const ServerAddress &hostname) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Disconnect();
SPAssert(status == NetClientStatusNotConnected);
2016-11-20 19:13:00 +09:00
if (hostname.protocol() != ProtocolVersion::Unknown) {
cg_protocolVersion = (int)hostname.protocol();
}
switch ((int)cg_protocolVersion) {
case 3: SPLog("Using Ace of Spades 0.75 protocol"); break;
case 4: SPLog("Using Ace of Spades 0.76 protocol"); break;
default: SPRaise("Invalid cg_protocolVersion, should be 3 or 4"); break;
}
ENetAddress addr = hostname.asAddress();
SPLog("Connecting to %u:%u", (unsigned int)addr.host, (unsigned int)addr.port);
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
savedPackets.clear();
2016-11-20 19:13:00 +09:00
peer = enet_host_connect(host, &addr, 1, (int)cg_protocolVersion);
if (peer == NULL) {
2013-08-18 16:18:06 +09:00
SPRaise("Failed to create ENet peer");
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
status = NetClientStatusConnecting;
2014-02-28 16:22:00 +09:00
statusString = _Tr("NetClient", "Connecting to the server");
2013-08-18 16:18:06 +09:00
timeToTryMapLoad = 0;
2016-11-20 19:13:00 +09:00
protocolVersion = cg_protocolVersion;
2013-08-18 16:18:06 +09:00
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
void NetClient::Disconnect() {
SPADES_MARK_FUNCTION();
2016-11-20 19:13:00 +09:00
if (!peer)
2013-08-18 16:18:06 +09:00
return;
enet_peer_disconnect(peer, 0);
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
status = NetClientStatusNotConnected;
2014-02-28 16:22:00 +09:00
statusString = _Tr("NetClient", "Not connected");
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
savedPackets.clear();
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
ENetEvent event;
2013-08-26 01:27:44 +09:00
SPLog("Waiting for graceful disconnection");
while (enet_host_service(host, &event, 1000) > 0) {
switch (event.type) {
case ENET_EVENT_TYPE_RECEIVE: enet_packet_destroy(event.packet); break;
2013-08-18 16:18:06 +09:00
case ENET_EVENT_TYPE_DISCONNECT:
// disconnected safely
// FIXME: release peer
enet_peer_reset(peer);
peer = NULL;
return;
default:;
// discard
}
}
2016-11-20 19:13:00 +09:00
2013-08-26 01:27:44 +09:00
SPLog("Connection terminated");
2013-08-18 16:18:06 +09:00
enet_peer_reset(peer);
// FXIME: release peer
peer = NULL;
}
2016-11-20 19:13:00 +09:00
2014-03-16 01:23:30 +09:00
int NetClient::GetPing() {
SPADES_MARK_FUNCTION();
2016-11-20 19:13:00 +09:00
if (status == NetClientStatusNotConnected)
2014-03-16 01:23:30 +09:00
return -1;
2016-11-20 19:13:00 +09:00
2014-03-16 01:23:30 +09:00
auto rtt = peer->roundTripTime;
if (rtt == 0)
return -1;
2014-03-16 01:23:30 +09:00
return static_cast<int>(rtt);
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
void NetClient::DoEvents(int timeout) {
SPADES_MARK_FUNCTION();
2016-11-20 19:13:00 +09:00
if (status == NetClientStatusNotConnected)
2013-08-18 16:18:06 +09:00
return;
2016-11-20 19:13:00 +09:00
// don't allow changin cg_protocolVersion
if ((int)cg_protocolVersion != protocolVersion) {
cg_protocolVersion = protocolVersion;
}
2016-11-20 19:13:00 +09:00
if (bandwidthMonitor)
2014-03-31 23:09:47 +09:00
bandwidthMonitor->Update();
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
ENetEvent event;
while (enet_host_service(host, &event, timeout) > 0) {
if (event.type == ENET_EVENT_TYPE_DISCONNECT) {
if (GetWorld()) {
2013-08-18 16:18:06 +09:00
client->SetWorld(NULL);
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
enet_peer_reset(peer);
peer = NULL;
status = NetClientStatusNotConnected;
2016-11-20 19:13:00 +09:00
SPLog("Disconnected (data = 0x%08x)", (unsigned int)event.data);
2013-08-18 16:18:06 +09:00
statusString = "Disconnected: " + DisconnectReasonString(event.data);
SPRaise("Disconnected: %s", DisconnectReasonString(event.data).c_str());
}
if (status == NetClientStatusConnecting) {
if (event.type == ENET_EVENT_TYPE_CONNECT) {
2014-03-30 02:44:43 +09:00
statusString = _Tr("NetClient", "Awaiting for state");
} else if (event.type == ENET_EVENT_TYPE_RECEIVE) {
2013-08-18 16:18:06 +09:00
NetPacketReader reader(event.packet);
reader.DumpDebug();
if (reader.GetType() != PacketTypeMapStart) {
2013-10-08 22:01:07 +02:00
SPRaise("Unexpected packet: %d", (int)reader.GetType());
2013-08-18 16:18:06 +09:00
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
mapSize = reader.ReadInt();
status = NetClientStatusReceivingMap;
2014-02-28 16:22:00 +09:00
statusString = _Tr("NetClient", "Loading snapshot");
2013-08-18 16:18:06 +09:00
timeToTryMapLoad = 30;
tryMapLoadOnPacketType = true;
}
} else if (status == NetClientStatusReceivingMap) {
if (event.type == ENET_EVENT_TYPE_RECEIVE) {
2013-08-18 16:18:06 +09:00
NetPacketReader reader(event.packet);
2016-11-20 19:13:00 +09:00
if (reader.GetType() == PacketTypeMapChunk) {
2013-08-18 16:18:06 +09:00
std::vector<char> dt = reader.GetData();
dt.erase(dt.begin());
mapData.insert(mapData.end(), dt.begin(), dt.end());
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
timeToTryMapLoad = 200;
2016-11-20 19:13:00 +09:00
2014-02-28 16:22:00 +09:00
statusString = _Tr("NetClient", "Loading snapshot ({0}/{1})",
mapData.size(), mapSize);
2016-11-20 19:13:00 +09:00
if (mapSize == mapData.size()) {
2013-08-18 16:18:06 +09:00
status = NetClientStatusConnected;
2014-02-28 16:22:00 +09:00
statusString = _Tr("NetClient", "Connected");
2016-11-20 19:13:00 +09:00
try {
2013-08-18 16:18:06 +09:00
MapLoaded();
} catch (const std::exception &ex) {
if (strstr(ex.what(), "File truncated") ||
strstr(ex.what(), "EOF reached")) {
SPLog("Map decoder returned error. Maybe we will get more "
"data...:\n%s",
ex.what());
2013-08-18 16:18:06 +09:00
// hack: more data to load...
status = NetClientStatusReceivingMap;
2014-02-28 16:22:00 +09:00
statusString = _Tr("NetClient", "Still loading...");
} else {
2013-08-18 16:18:06 +09:00
Disconnect();
2014-02-28 16:22:00 +09:00
statusString = _Tr("NetClient", "Error");
2013-08-18 16:18:06 +09:00
throw;
}
2016-11-20 19:13:00 +09:00
} catch (...) {
2013-08-18 16:18:06 +09:00
Disconnect();
2014-02-28 16:22:00 +09:00
statusString = _Tr("NetClient", "Error");
2013-08-18 16:18:06 +09:00
throw;
}
}
2016-11-20 19:13:00 +09:00
} else {
2013-08-18 16:18:06 +09:00
reader.DumpDebug();
2016-11-20 19:13:00 +09:00
if (reader.GetType() != PacketTypeWorldUpdate &&
reader.GetType() != PacketTypeExistingPlayer &&
reader.GetType() != PacketTypeCreatePlayer &&
tryMapLoadOnPacketType) {
2013-08-18 16:18:06 +09:00
status = NetClientStatusConnected;
2014-02-28 16:22:00 +09:00
statusString = _Tr("NetClient", "Connected");
2016-11-20 19:13:00 +09:00
try {
2013-08-18 16:18:06 +09:00
MapLoaded();
} catch (const std::exception &ex) {
2013-08-18 16:18:06 +09:00
tryMapLoadOnPacketType = false;
if (strstr(ex.what(), "File truncated") ||
strstr(ex.what(), "EOF reached")) {
SPLog("Map decoder returned error. Maybe we will get more "
"data...:\n%s",
ex.what());
2013-08-18 16:18:06 +09:00
// hack: more data to load...
status = NetClientStatusReceivingMap;
2014-02-28 16:22:00 +09:00
statusString = _Tr("NetClient", "Still loading...");
2013-08-18 16:18:06 +09:00
goto stillLoading;
} else {
2013-08-18 16:18:06 +09:00
Disconnect();
2014-02-28 16:22:00 +09:00
statusString = _Tr("NetClient", "Error");
2013-08-18 16:18:06 +09:00
throw;
}
} catch (...) {
2013-08-18 16:18:06 +09:00
Disconnect();
2014-02-28 16:22:00 +09:00
statusString = _Tr("NetClient", "Error");
2013-08-18 16:18:06 +09:00
throw;
}
Handle(reader);
} else {
2013-08-18 16:18:06 +09:00
stillLoading:
savedPackets.push_back(reader.GetData());
}
2016-11-20 19:13:00 +09:00
// Handle(reader);
2013-08-18 16:18:06 +09:00
}
}
} else if (status == NetClientStatusConnected) {
if (event.type == ENET_EVENT_TYPE_RECEIVE) {
2013-08-18 16:18:06 +09:00
NetPacketReader reader(event.packet);
// reader.DumpDebug();
try {
2013-08-18 16:18:06 +09:00
Handle(reader);
} catch (const std::exception &ex) {
2013-08-18 16:18:06 +09:00
int type = reader.GetType();
reader.DumpDebug();
SPRaise("Exception while handling packet type 0x%08x:\n%s", type,
ex.what());
2013-08-18 16:18:06 +09:00
}
}
}
}
2016-11-20 19:13:00 +09:00
if (status == NetClientStatusReceivingMap) {
if (timeToTryMapLoad > 0) {
2013-08-18 16:18:06 +09:00
timeToTryMapLoad--;
if (timeToTryMapLoad == 0) {
try {
2013-08-18 16:18:06 +09:00
MapLoaded();
} catch (const std::exception &ex) {
if ((strstr(ex.what(), "File truncated") ||
strstr(ex.what(), "EOF reached")) &&
savedPackets.size() < 400) {
2013-08-18 16:18:06 +09:00
// hack: more data to load...
SPLog(
"Map decoder returned error. Maybe we will get more data...:\n%s",
ex.what());
2013-08-18 16:18:06 +09:00
status = NetClientStatusReceivingMap;
2014-02-28 16:22:00 +09:00
statusString = _Tr("NetClient", "Still loading...");
2013-08-18 16:18:06 +09:00
timeToTryMapLoad = 200;
} else {
2013-08-18 16:18:06 +09:00
Disconnect();
2014-02-28 16:22:00 +09:00
statusString = _Tr("NetClient", "Error");
2013-08-18 16:18:06 +09:00
throw;
}
} catch (...) {
2013-08-18 16:18:06 +09:00
Disconnect();
2014-02-28 16:22:00 +09:00
statusString = _Tr("NetClient", "Error");
2013-08-18 16:18:06 +09:00
throw;
}
}
}
}
}
2016-11-20 19:13:00 +09:00
World *NetClient::GetWorld() { return client->GetWorld(); }
2016-11-20 19:13:00 +09:00
Player *NetClient::GetPlayerOrNull(int pId) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
if (!GetWorld())
2013-08-18 16:18:06 +09:00
SPRaise("Invalid Player ID %d: No world", pId);
if (pId < 0 || pId >= GetWorld()->GetNumPlayerSlots())
2013-08-18 16:18:06 +09:00
return NULL;
return GetWorld()->GetPlayer(pId);
}
Player *NetClient::GetPlayer(int pId) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
if (!GetWorld())
2013-08-18 16:18:06 +09:00
SPRaise("Invalid Player ID %d: No world", pId);
if (pId < 0 || pId >= GetWorld()->GetNumPlayerSlots())
2013-08-18 16:18:06 +09:00
SPRaise("Invalid Player ID %d: Out of range", pId);
if (!GetWorld()->GetPlayer(pId))
2013-08-18 16:18:06 +09:00
SPRaise("Invalid Player ID %d: Doesn't exist", pId);
return GetWorld()->GetPlayer(pId);
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Player *NetClient::GetLocalPlayer() {
SPADES_MARK_FUNCTION();
if (!GetWorld())
2013-08-18 16:18:06 +09:00
SPRaise("Failed to get local player: no world");
if (!GetWorld()->GetLocalPlayer())
2013-08-18 16:18:06 +09:00
SPRaise("Failed to get local player: no local player");
return GetWorld()->GetLocalPlayer();
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Player *NetClient::GetLocalPlayerOrNull() {
SPADES_MARK_FUNCTION();
if (!GetWorld())
2013-08-18 16:18:06 +09:00
SPRaise("Failed to get local player: no world");
return GetWorld()->GetLocalPlayer();
}
PlayerInput ParsePlayerInput(uint8_t bits) {
2013-08-18 16:18:06 +09:00
PlayerInput inp;
inp.moveForward = (bits & (1)) != 0;
inp.moveBackward = (bits & (1 << 1)) != 0;
inp.moveLeft = (bits & (1 << 2)) != 0;
inp.moveRight = (bits & (1 << 3)) != 0;
inp.jump = (bits & (1 << 4)) != 0;
inp.crouch = (bits & (1 << 5)) != 0;
inp.sneak = (bits & (1 << 6)) != 0;
inp.sprint = (bits & (1 << 7)) != 0;
return inp;
}
2016-11-20 19:13:00 +09:00
WeaponInput ParseWeaponInput(uint8_t bits) {
2013-08-18 16:18:06 +09:00
WeaponInput inp;
inp.primary = ((bits & (1)) != 0);
inp.secondary = ((bits & (1 << 1)) != 0);
return inp;
}
2016-11-20 19:13:00 +09:00
std::string NetClient::DisconnectReasonString(enet_uint32 num) {
switch (num) {
case 1: return _Tr("NetClient", "You are banned from this server.");
2013-08-18 16:18:06 +09:00
case 2:
// FIXME: this number seems to be used when per-IP connection limit was
// exceeded.
2014-02-28 16:22:00 +09:00
// we need to check other usages
return _Tr("NetClient", "You were kicked from this server.");
case 3: return _Tr("NetClient", "Incompatible client protocol version.");
case 4: return _Tr("NetClient", "Server full");
case 10: return _Tr("NetClient", "You were kicked from this server.");
default: return _Tr("NetClient", "Unknown Reason");
2013-08-18 16:18:06 +09:00
}
}
2016-11-20 19:13:00 +09:00
void NetClient::Handle(spades::client::NetPacketReader &reader) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
2016-11-20 19:13:00 +09:00
switch (reader.GetType()) {
case PacketTypePositionData: {
2013-08-18 16:18:06 +09:00
Player *p = GetLocalPlayer();
Vector3 pos;
if (reader.GetData().size() < 12) {
2013-08-18 16:18:06 +09:00
// sometimes 00 00 00 00 packet is sent.
// ignore this now
break;
}
pos.x = reader.ReadFloat();
pos.y = reader.ReadFloat();
pos.z = reader.ReadFloat();
p->SetPosition(pos);
} break;
case PacketTypeOrientationData: {
2013-08-18 16:18:06 +09:00
Player *p = GetLocalPlayer();
Vector3 pos;
pos.x = reader.ReadFloat();
pos.y = reader.ReadFloat();
pos.z = reader.ReadFloat();
p->SetOrientation(pos);
} break;
case PacketTypeWorldUpdate: {
// reader.DumpDebug();
int bytesPerEntry = 24;
if ((int)cg_protocolVersion == 4)
bytesPerEntry++;
int entries = static_cast<int>(reader.GetData().size() / bytesPerEntry);
for (int i = 0; i < entries; i++) {
int idx = i;
if ((int)cg_protocolVersion == 4) {
idx = reader.ReadByte();
if (idx < 0 || idx >= 32) {
SPRaise("Invalid player number %d received with WorldUpdate", idx);
}
}
2013-08-18 16:18:06 +09:00
Vector3 pos, front;
pos.x = reader.ReadFloat();
pos.y = reader.ReadFloat();
pos.z = reader.ReadFloat();
front.x = reader.ReadFloat();
front.y = reader.ReadFloat();
front.z = reader.ReadFloat();
2016-11-20 19:13:00 +09:00
savedPlayerPos[idx] = pos;
savedPlayerFront[idx] = front;
if (pos.x != 0.f || pos.y != 0.f || pos.z != 0.f || front.x != 0.f ||
front.y != 0.f || front.z != 0.f) {
2013-08-18 16:18:06 +09:00
Player *p;
SPAssert(!isnan(pos.x));
SPAssert(!isnan(pos.y));
SPAssert(!isnan(pos.z));
SPAssert(!isnan(front.x));
SPAssert(!isnan(front.y));
SPAssert(!isnan(front.z));
SPAssert(front.GetLength() < 40.f);
if (GetWorld()) {
p = GetWorld()->GetPlayer(idx);
if (p) {
if (p != GetWorld()->GetLocalPlayer()) {
2013-08-18 16:18:06 +09:00
p->SetPosition(pos);
p->SetOrientation(front);
2016-11-20 19:13:00 +09:00
PosRecord &rec = playerPosRecords[idx];
if (rec.valid) {
float timespan = GetWorld()->GetTime() - rec.time;
2013-09-03 01:42:10 +09:00
timespan = std::max(0.16f, timespan);
Vector3 vel = (pos - rec.pos) / timespan;
vel *= 1.f / 32.f;
p->SetVelocity(vel);
}
2016-11-20 19:13:00 +09:00
rec.valid = true;
rec.pos = pos;
rec.time = GetWorld()->GetTime();
2013-08-18 16:18:06 +09:00
}
}
}
}
}
SPAssert(reader.ReadRemainingData().empty());
} break;
2013-08-18 16:18:06 +09:00
case PacketTypeInputData:
if (!GetWorld())
2013-08-18 16:18:06 +09:00
break;
{
int pId = reader.ReadByte();
Player *p = GetPlayer(pId);
2016-11-20 19:13:00 +09:00
PlayerInput inp = ParsePlayerInput(reader.ReadByte());
2016-11-20 19:13:00 +09:00
if (GetWorld()->GetLocalPlayer() == p) {
// handle "/fly" jump
if (inp.jump) {
p->ForceJump();
}
break;
2014-03-30 01:42:18 +09:00
}
2016-11-20 19:13:00 +09:00
p->SetInput(inp);
}
2013-08-18 16:18:06 +09:00
break;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
case PacketTypeWeaponInput:
if (!GetWorld())
2013-08-18 16:18:06 +09:00
break;
{
int pId = reader.ReadByte();
Player *p = GetPlayer(pId);
2016-11-20 19:13:00 +09:00
WeaponInput inp = ParseWeaponInput(reader.ReadByte());
2016-11-20 19:13:00 +09:00
if (GetWorld()->GetLocalPlayer() == p)
break;
2016-11-20 19:13:00 +09:00
p->SetWeaponInput(inp);
}
2013-08-18 16:18:06 +09:00
break;
2016-11-20 19:13:00 +09:00
// Hit Packet is Client-to-Server!
case PacketTypeSetHP: {
2013-08-18 16:18:06 +09:00
Player *p = GetLocalPlayer();
int hp = reader.ReadByte();
int type = reader.ReadByte(); // 0=fall, 1=weap
Vector3 hurtPos;
hurtPos.x = reader.ReadFloat();
hurtPos.y = reader.ReadFloat();
hurtPos.z = reader.ReadFloat();
p->SetHP(hp, type ? HurtTypeWeapon : HurtTypeFall, hurtPos);
} break;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
case PacketTypeGrenadePacket:
if (!GetWorld())
2013-08-18 16:18:06 +09:00
break;
{
reader.ReadByte(); // skip player Id
// Player *p = GetPlayerOrNull(reader.ReadByte());
float fuseLen = reader.ReadFloat();
Vector3 pos, vel;
pos.x = reader.ReadFloat();
pos.y = reader.ReadFloat();
pos.z = reader.ReadFloat();
vel.x = reader.ReadFloat();
vel.y = reader.ReadFloat();
vel.z = reader.ReadFloat();
/* blockpower mode may emit local player's grenade
if(p == GetLocalPlayerOrNull()){
// local player's grenade is already
// emit by Player
break;
}*/
Grenade *g = new Grenade(GetWorld(), pos, vel, fuseLen);
GetWorld()->AddGrenade(g);
}
2013-08-18 16:18:06 +09:00
break;
2016-11-20 19:13:00 +09:00
case PacketTypeSetTool: {
2013-08-18 16:18:06 +09:00
Player *p = GetPlayer(reader.ReadByte());
int tool = reader.ReadByte();
switch (tool) {
2013-08-18 16:18:06 +09:00
case 0: p->SetTool(Player::ToolSpade); break;
case 1: p->SetTool(Player::ToolBlock); break;
case 2: p->SetTool(Player::ToolWeapon); break;
case 3: p->SetTool(Player::ToolGrenade); break;
default: SPRaise("Received invalid tool type: %d", tool);
2013-08-18 16:18:06 +09:00
}
} break;
case PacketTypeSetColour: {
2013-08-18 16:18:06 +09:00
Player *p = GetPlayerOrNull(reader.ReadByte());
IntVector3 col = reader.ReadIntColor();
if (p)
2013-08-18 16:18:06 +09:00
p->SetHeldBlockColor(col);
else
temporaryPlayerBlockColor = col;
} break;
2013-08-18 16:18:06 +09:00
case PacketTypeExistingPlayer:
if (!GetWorld())
2013-08-18 16:18:06 +09:00
break;
{
int pId = reader.ReadByte();
int team = reader.ReadByte();
int weapon = reader.ReadByte();
int tool = reader.ReadByte();
int kills = reader.ReadInt();
IntVector3 color = reader.ReadIntColor();
std::string name = reader.ReadRemainingString();
// TODO: decode name?
WeaponType wType;
switch (weapon) {
case 0: wType = RIFLE_WEAPON; break;
case 1: wType = SMG_WEAPON; break;
case 2: wType = SHOTGUN_WEAPON; break;
default: SPRaise("Received invalid weapon: %d", weapon);
}
2016-11-20 19:13:00 +09:00
Player *p = new Player(GetWorld(), pId, wType, team, savedPlayerPos[pId],
GetWorld()->GetTeam(team).color);
p->SetHeldBlockColor(color);
// p->SetOrientation(savedPlayerFront[pId]);
GetWorld()->SetPlayer(pId, p);
switch (tool) {
case 0: p->SetTool(Player::ToolSpade); break;
case 1: p->SetTool(Player::ToolBlock); break;
case 2: p->SetTool(Player::ToolWeapon); break;
case 3: p->SetTool(Player::ToolGrenade); break;
default: SPRaise("Received invalid tool type: %d", tool);
}
2016-11-20 19:13:00 +09:00
World::PlayerPersistent &pers = GetWorld()->GetPlayerPersistent(pId);
pers.name = name;
pers.kills = kills;
2016-11-20 19:13:00 +09:00
savedPlayerTeam[pId] = team;
2013-08-18 16:18:06 +09:00
}
break;
case PacketTypeShortPlayerData: SPRaise("Unexpected: received Short Player Data");
2013-08-18 16:18:06 +09:00
case PacketTypeMoveObject:
if (!GetWorld())
SPRaise("No world");
{
uint8_t type = reader.ReadByte();
uint8_t state = reader.ReadByte();
Vector3 pos;
pos.x = reader.ReadFloat();
pos.y = reader.ReadFloat();
pos.z = reader.ReadFloat();
2016-11-20 19:13:00 +09:00
IGameMode *mode = GetWorld()->GetMode();
if (mode && IGameMode::m_CTF == mode->ModeType()) {
CTFGameMode *ctf = static_cast<CTFGameMode *>(mode);
switch (type) {
case BLUE_BASE: ctf->GetTeam(0).basePos = pos; break;
case BLUE_FLAG: ctf->GetTeam(0).flagPos = pos; break;
case GREEN_BASE: ctf->GetTeam(1).basePos = pos; break;
case GREEN_FLAG: ctf->GetTeam(1).flagPos = pos; break;
}
} else if (mode && IGameMode::m_TC == mode->ModeType()) {
TCGameMode *tc = static_cast<TCGameMode *>(mode);
if (type >= tc->GetNumTerritories()) {
SPRaise("Invalid territory id specified: %d (max = %d)", (int)type,
tc->GetNumTerritories() - 1);
}
2016-11-20 19:13:00 +09:00
if (state > 2) {
SPRaise("Invalid state %d specified for territory owner.",
(int)state);
}
2016-11-20 19:13:00 +09:00
TCGameMode::Territory *t = tc->GetTerritory(type);
t->pos = pos;
t->ownerTeamId = state; /*
t->progressBasePos = 0.f;
t->progressRate = 0.f;
t->progressStartTime = 0.f;
t->capturingTeamId = -1;*/
}
2013-08-18 16:18:06 +09:00
}
break;
case PacketTypeCreatePlayer: {
if (!GetWorld())
2013-08-18 16:18:06 +09:00
SPRaise("No world");
int pId = reader.ReadByte();
int weapon = reader.ReadByte();
int team = reader.ReadByte();
Vector3 pos;
pos.x = reader.ReadFloat();
pos.y = reader.ReadFloat();
pos.z = reader.ReadFloat() - 2.f;
std::string name = reader.ReadRemainingString();
// TODO: decode name?
2016-11-20 19:13:00 +09:00
if (pId < 0 || pId >= 32) {
SPLog("Ignoring player 32 (bug in pyspades?: %s)", name.c_str());
2013-10-08 22:01:07 +02:00
break;
}
2013-08-18 16:18:06 +09:00
WeaponType wType;
switch (weapon) {
case 0: wType = RIFLE_WEAPON; break;
case 1: wType = SMG_WEAPON; break;
case 2: wType = SHOTGUN_WEAPON; break;
default: SPRaise("Received invalid weapon: %d", weapon);
2013-08-18 16:18:06 +09:00
}
2016-11-20 19:13:00 +09:00
Player *p = new Player(GetWorld(), pId, wType, team, savedPlayerPos[pId],
2016-11-20 19:13:00 +09:00
GetWorld()->GetTeam(team).color);
2013-08-18 16:18:06 +09:00
p->SetPosition(pos);
GetWorld()->SetPlayer(pId, p);
2016-11-20 19:13:00 +09:00
World::PlayerPersistent &pers = GetWorld()->GetPlayerPersistent(pId);
2016-11-20 19:13:00 +09:00
if (!name.empty()) // sometimes becomes empty
2013-08-18 16:18:06 +09:00
pers.name = name;
2016-11-20 19:13:00 +09:00
playerPosRecords[pId].valid = false;
2016-11-20 19:13:00 +09:00
if (pId == GetWorld()->GetLocalPlayerIndex()) {
2013-08-18 16:18:06 +09:00
client->LocalPlayerCreated();
lastPlayerInput = 0xffffffff;
lastWeaponInput = 0xffffffff;
2016-11-20 19:13:00 +09:00
SendHeldBlockColor(); // ensure block color synchronized
} else {
if (team < 2 && pId < (int)playerPosRecords.size()) {
PosRecord &rec = playerPosRecords[pId];
2016-11-20 19:13:00 +09:00
rec.valid = true;
rec.pos = pos;
rec.time = GetWorld()->GetTime();
}
if (savedPlayerTeam[pId] != team && team < 2) {
2016-11-20 19:13:00 +09:00
client->PlayerJoinedTeam(p);
2016-11-20 19:13:00 +09:00
savedPlayerTeam[pId] = team;
}
}
2016-11-20 19:13:00 +09:00
} break;
case PacketTypeBlockAction: {
2013-08-18 16:18:06 +09:00
Player *p = GetPlayerOrNull(reader.ReadByte());
int action = reader.ReadByte();
IntVector3 pos;
pos.x = reader.ReadInt();
pos.y = reader.ReadInt();
pos.z = reader.ReadInt();
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
std::vector<IntVector3> cells;
if (action == 0) {
2014-03-13 14:01:53 +09:00
bool replace = GetWorld()->GetMap()->IsSolidWrapped(pos.x, pos.y, pos.z);
if (!p) {
2013-08-18 16:18:06 +09:00
GetWorld()->CreateBlock(pos, temporaryPlayerBlockColor);
} else {
2013-08-18 16:18:06 +09:00
GetWorld()->CreateBlock(pos, p->GetBlockColor());
client->PlayerCreatedBlock(p);
if (!replace) {
2014-03-13 14:01:53 +09:00
p->UsedBlocks(1);
}
2013-08-18 16:18:06 +09:00
}
} else if (action == 1) {
2013-08-18 16:18:06 +09:00
cells.push_back(pos);
client->PlayerDestroyedBlockWithWeaponOrTool(pos);
GetWorld()->DestroyBlock(cells);
2016-11-20 19:13:00 +09:00
if (p && p->GetTool() == Player::ToolSpade) {
2013-08-18 16:18:06 +09:00
p->GotBlock();
}
} else if (action == 2) {
2013-08-18 16:18:06 +09:00
// dig
client->PlayerDiggedBlock(pos);
for (int z = -1; z <= 1; z++)
2013-08-18 16:18:06 +09:00
cells.push_back(IntVector3::Make(pos.x, pos.y, pos.z + z));
GetWorld()->DestroyBlock(cells);
} else if (action == 3) {
2013-08-18 16:18:06 +09:00
// grenade
client->GrenadeDestroyedBlock(pos);
for (int x = -1; x <= 1; x++)
for (int y = -1; y <= 1; y++)
for (int z = -1; z <= 1; z++)
cells.push_back(
IntVector3::Make(pos.x + x, pos.y + y, pos.z + z));
2013-08-18 16:18:06 +09:00
GetWorld()->DestroyBlock(cells);
}
} break;
case PacketTypeBlockLine: {
2013-08-18 16:18:06 +09:00
Player *p = GetPlayerOrNull(reader.ReadByte());
IntVector3 pos1, pos2;
pos1.x = reader.ReadInt();
pos1.y = reader.ReadInt();
pos1.z = reader.ReadInt();
pos2.x = reader.ReadInt();
pos2.y = reader.ReadInt();
pos2.z = reader.ReadInt();
2016-11-20 19:13:00 +09:00
IntVector3 col = p ? p->GetBlockColor() : temporaryPlayerBlockColor;
2013-08-18 16:18:06 +09:00
std::vector<IntVector3> cells;
cells = GetWorld()->CubeLine(pos1, pos2, 50);
2016-11-20 19:13:00 +09:00
for (size_t i = 0; i < cells.size(); i++) {
if (!GetWorld()->GetMap()->IsSolid(cells[i].x, cells[i].y, cells[i].z)) {
2013-08-18 16:18:06 +09:00
GetWorld()->CreateBlock(cells[i], col);
}
}
2016-11-20 19:13:00 +09:00
if (p) {
p->UsedBlocks(static_cast<int>(cells.size()));
2013-08-18 16:18:06 +09:00
client->PlayerCreatedBlock(p);
}
} break;
2013-08-18 16:18:06 +09:00
case PacketTypeStateData:
if (!GetWorld())
2013-08-18 16:18:06 +09:00
break;
{
// receives my player info.
int pId = reader.ReadByte();
IntVector3 fogColor = reader.ReadIntColor();
IntVector3 teamColors[2];
teamColors[0] = reader.ReadIntColor();
teamColors[1] = reader.ReadIntColor();
std::string teamNames[2];
teamNames[0] = reader.ReadString(10);
teamNames[1] = reader.ReadString(10);
World::Team &t1 = GetWorld()->GetTeam(0);
World::Team &t2 = GetWorld()->GetTeam(1);
t1.color = teamColors[0];
t2.color = teamColors[1];
t1.name = teamNames[0];
t2.name = teamNames[1];
GetWorld()->SetFogColor(fogColor);
GetWorld()->SetLocalPlayerIndex(pId);
int mode = reader.ReadByte();
if (mode == 0) {
// CTF
CTFGameMode *mode = new CTFGameMode();
try {
CTFGameMode::Team &mt1 = mode->GetTeam(0);
CTFGameMode::Team &mt2 = mode->GetTeam(1);
mt1.score = reader.ReadByte();
mt2.score = reader.ReadByte();
mode->SetCaptureLimit(reader.ReadByte());
int intelFlags = reader.ReadByte();
mt1.hasIntel = (intelFlags & 1) != 0;
mt2.hasIntel = (intelFlags & 2) != 0;
if (mt2.hasIntel) {
mt1.carrier = reader.ReadByte();
reader.ReadData(11);
} else {
mt1.flagPos.x = reader.ReadFloat();
mt1.flagPos.y = reader.ReadFloat();
mt1.flagPos.z = reader.ReadFloat();
}
2016-11-20 19:13:00 +09:00
if (mt1.hasIntel) {
mt2.carrier = reader.ReadByte();
reader.ReadData(11);
} else {
mt2.flagPos.x = reader.ReadFloat();
mt2.flagPos.y = reader.ReadFloat();
mt2.flagPos.z = reader.ReadFloat();
}
2016-11-20 19:13:00 +09:00
mt1.basePos.x = reader.ReadFloat();
mt1.basePos.y = reader.ReadFloat();
mt1.basePos.z = reader.ReadFloat();
2016-11-20 19:13:00 +09:00
mt2.basePos.x = reader.ReadFloat();
mt2.basePos.y = reader.ReadFloat();
mt2.basePos.z = reader.ReadFloat();
2016-11-20 19:13:00 +09:00
GetWorld()->SetMode(mode);
} catch (...) {
delete mode;
throw;
2013-08-18 16:18:06 +09:00
}
} else {
// TC
TCGameMode *mode = new TCGameMode(GetWorld());
try {
int numTer = reader.ReadByte();
for (int i = 0; i < numTer; i++) {
TCGameMode::Territory ter;
ter.pos.x = reader.ReadFloat();
ter.pos.y = reader.ReadFloat();
ter.pos.z = reader.ReadFloat();
int state = reader.ReadByte();
ter.ownerTeamId = state;
ter.progressBasePos = 0.f;
ter.progressStartTime = 0.f;
ter.progressRate = 0.f;
ter.capturingTeamId = -1;
ter.mode = mode;
mode->AddTerritory(ter);
}
2016-11-20 19:13:00 +09:00
GetWorld()->SetMode(mode);
} catch (...) {
delete mode;
throw;
}
2013-08-18 16:18:06 +09:00
}
client->JoinedGame();
2013-08-18 16:18:06 +09:00
}
break;
case PacketTypeKillAction: {
2013-08-18 16:18:06 +09:00
Player *p = GetPlayer(reader.ReadByte());
Player *killer = GetPlayer(reader.ReadByte());
int kt = reader.ReadByte();
KillType type;
switch (kt) {
2013-08-18 16:18:06 +09:00
case 0: type = KillTypeWeapon; break;
case 1: type = KillTypeHeadshot; break;
case 2: type = KillTypeMelee; break;
case 3: type = KillTypeGrenade; break;
case 4: type = KillTypeFall; break;
case 5: type = KillTypeTeamChange; break;
case 6: type = KillTypeClassChange; break;
default: SPInvalidEnum("kt", kt);
2013-08-18 16:18:06 +09:00
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
int respawnTime = reader.ReadByte();
switch (type) {
2013-08-18 16:18:06 +09:00
case KillTypeFall:
case KillTypeClassChange:
case KillTypeTeamChange: killer = p; break;
default: break;
2013-08-18 16:18:06 +09:00
}
p->KilledBy(type, killer, respawnTime);
if (p != killer) {
2013-08-18 16:18:06 +09:00
GetWorld()->GetPlayerPersistent(killer->GetId()).kills += 1;
}
} break;
case PacketTypeChatMessage: {
2013-08-18 16:18:06 +09:00
// might be wrong player id for server message
uint8_t pId = reader.ReadByte();
Player *p;
if (pId < 32) {
p = GetPlayerOrNull(pId);
} else {
2013-08-18 16:18:06 +09:00
p = NULL;
}
int type = reader.ReadByte();
std::string txt = reader.ReadRemainingString();
if (p) {
switch (type) {
2013-08-18 16:18:06 +09:00
case 0: // all
client->PlayerSentChatMessage(p, true, txt);
break;
case 1: // team
client->PlayerSentChatMessage(p, false, txt);
break;
case 2: // system???
client->ServerSentMessage(txt);
/*SPRaise("Player #%d %s sent system message", p->GetId(),
* p->GetName().c_str());*/
2013-08-18 16:18:06 +09:00
}
} else {
2013-08-18 16:18:06 +09:00
client->ServerSentMessage(txt);
}
} break;
case PacketTypeMapStart: {
2013-08-18 16:18:06 +09:00
// next map!
client->SetWorld(NULL);
mapSize = reader.ReadInt();
status = NetClientStatusReceivingMap;
2014-02-28 16:22:00 +09:00
statusString = _Tr("NetClient", "Loading snapshot");
} break;
case PacketTypeMapChunk: SPRaise("Unexpected: received Map Chunk while game");
case PacketTypePlayerLeft: {
2013-08-18 16:18:06 +09:00
Player *p = GetPlayer(reader.ReadByte());
2016-11-20 19:13:00 +09:00
client->PlayerLeaving(p);
2016-11-20 19:13:00 +09:00
savedPlayerTeam[p->GetId()] = -1;
playerPosRecords[p->GetId()].valid = false;
2013-08-18 16:18:06 +09:00
GetWorld()->SetPlayer(p->GetId(), NULL);
// TODO: message
} break;
case PacketTypeTerritoryCapture: {
2013-08-18 16:18:06 +09:00
int territoryId = reader.ReadByte();
bool winning = reader.ReadByte() != 0;
int state = reader.ReadByte();
2016-11-20 19:13:00 +09:00
IGameMode *mode = GetWorld()->GetMode();
if (mode == NULL)
break;
if (mode->ModeType() != IGameMode::m_TC) {
SPRaise("Received PacketTypeTerritoryCapture in non-TC gamemode");
}
TCGameMode *tc = static_cast<TCGameMode *>(mode);
2016-11-20 19:13:00 +09:00
if (territoryId >= tc->GetNumTerritories()) {
2013-08-18 16:18:06 +09:00
SPRaise("Invalid territory id %d specified (max = %d)", territoryId,
tc->GetNumTerritories() - 1);
2013-08-18 16:18:06 +09:00
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
client->TeamCapturedTerritory(state, territoryId);
2016-11-20 19:13:00 +09:00
TCGameMode::Territory *t = tc->GetTerritory(territoryId);
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
t->ownerTeamId = state;
t->progressBasePos = 0.f;
t->progressRate = 0.f;
t->progressStartTime = 0.f;
t->capturingTeamId = -1;
2016-11-20 19:13:00 +09:00
if (winning)
2013-08-18 16:18:06 +09:00
client->TeamWon(state);
} break;
case PacketTypeProgressBar: {
2013-08-18 16:18:06 +09:00
int territoryId = reader.ReadByte();
int capturingTeam = reader.ReadByte();
int rate = (int8_t)reader.ReadByte();
float progress = reader.ReadFloat();
2016-11-20 19:13:00 +09:00
IGameMode *mode = GetWorld()->GetMode();
if (mode == NULL)
break;
if (mode->ModeType() != IGameMode::m_TC) {
SPRaise("Received PacketTypeProgressBar in non-TC gamemode");
}
TCGameMode *tc = static_cast<TCGameMode *>(mode);
2016-11-20 19:13:00 +09:00
if (territoryId >= tc->GetNumTerritories()) {
2013-08-18 16:18:06 +09:00
SPRaise("Invalid territory id %d specified (max = %d)", territoryId,
tc->GetNumTerritories() - 1);
2013-08-18 16:18:06 +09:00
}
2016-11-20 19:13:00 +09:00
if (progress < -0.1f || progress > 1.1f)
2013-08-18 16:18:06 +09:00
SPRaise("Progress value out of range(%f)", progress);
2016-11-20 19:13:00 +09:00
TCGameMode::Territory *t = tc->GetTerritory(territoryId);
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
t->progressBasePos = progress;
t->progressRate = (float)rate * TC_CAPTURE_RATE;
t->progressStartTime = GetWorld()->GetTime();
t->capturingTeamId = capturingTeam;
} break;
case PacketTypeIntelCapture: {
if (!GetWorld())
SPRaise("No world");
IGameMode *mode = GetWorld()->GetMode();
if (mode == NULL)
break;
if (mode->ModeType() != IGameMode::m_CTF) {
SPRaise("Received PacketTypeIntelCapture in non-TC gamemode");
}
CTFGameMode *ctf = static_cast<CTFGameMode *>(mode);
2013-08-18 16:18:06 +09:00
Player *p = GetPlayer(reader.ReadByte());
client->PlayerCapturedIntel(p);
GetWorld()->GetPlayerPersistent(p->GetId()).kills += 10;
ctf->GetTeam(p->GetTeamId()).hasIntel = false;
ctf->GetTeam(p->GetTeamId()).score++;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
bool winning = reader.ReadByte() != 0;
if (winning)
2013-08-18 16:18:06 +09:00
client->TeamWon(p->GetTeamId());
} break;
case PacketTypeIntelPickup: {
2013-08-18 16:18:06 +09:00
Player *p = GetPlayer(reader.ReadByte());
IGameMode *mode = GetWorld()->GetMode();
if (mode == NULL)
break;
if (mode->ModeType() != IGameMode::m_CTF) {
SPRaise("Received PacketTypeIntelPickup in non-TC gamemode");
}
CTFGameMode *ctf = static_cast<CTFGameMode *>(mode);
CTFGameMode::Team &team = ctf->GetTeam(p->GetTeamId());
2013-08-18 16:18:06 +09:00
team.hasIntel = true;
team.carrier = p->GetId();
client->PlayerPickedIntel(p);
} break;
case PacketTypeIntelDrop: {
2013-08-18 16:18:06 +09:00
Player *p = GetPlayer(reader.ReadByte());
IGameMode *mode = GetWorld()->GetMode();
if (mode == NULL)
break;
if (mode->ModeType() != IGameMode::m_CTF) {
SPRaise("Received PacketTypeIntelPickup in non-TC gamemode");
}
CTFGameMode *ctf = static_cast<CTFGameMode *>(mode);
CTFGameMode::Team &team = ctf->GetTeam(p->GetTeamId());
2013-08-18 16:18:06 +09:00
team.hasIntel = false;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Vector3 pos;
pos.x = reader.ReadFloat();
pos.y = reader.ReadFloat();
pos.z = reader.ReadFloat();
2016-11-20 19:13:00 +09:00
ctf->GetTeam(1 - p->GetTeamId()).flagPos = pos;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
client->PlayerDropIntel(p);
} break;
case PacketTypeRestock: {
Player *p = GetLocalPlayer(); // GetPlayer(reader.ReadByte());
2013-08-18 16:18:06 +09:00
p->Restock();
} break;
case PacketTypeFogColour: {
if (GetWorld()) {
2013-08-18 16:18:06 +09:00
reader.ReadByte(); // skip
GetWorld()->SetFogColor(reader.ReadIntColor());
}
} break;
case PacketTypeWeaponReload: {
2013-08-18 16:18:06 +09:00
Player *p = GetPlayer(reader.ReadByte());
if (p != GetLocalPlayerOrNull())
2013-08-18 16:18:06 +09:00
p->Reload();
else {
int clip = reader.ReadByte();
int reserve = reader.ReadByte();
if (clip < 255 && reserve < 255) {
p->ReloadDone(clip, reserve);
}
}
2013-08-18 16:18:06 +09:00
// FIXME: use of "clip ammo" and "reserve ammo"?
} break;
case PacketTypeChangeTeam: {
2013-08-18 16:18:06 +09:00
Player *p = GetPlayer(reader.ReadByte());
int team = reader.ReadByte();
if (team < 0 || team > 2)
2013-08-18 16:18:06 +09:00
SPRaise("Received invalid team: %d", team);
p->SetTeam(team);
}
case PacketTypeChangeWeapon: {
reader.ReadByte();
2013-08-18 16:18:06 +09:00
WeaponType wType;
int weapon = reader.ReadByte();
switch (weapon) {
case 0: wType = RIFLE_WEAPON; break;
case 1: wType = SMG_WEAPON; break;
case 2: wType = SHOTGUN_WEAPON; break;
default: SPRaise("Received invalid weapon: %d", weapon);
2013-08-18 16:18:06 +09:00
}
// maybe this command is intended to change local player's
// weapon...
// p->SetWeaponType(wType);
} break;
case PacketTypeHandShakeInit: SendHandShakeValid(reader.ReadInt()); break;
case PacketTypeVersionGet: SendVersion(); break;
2013-08-18 16:18:06 +09:00
default:
printf("WARNING: dropped packet %d\n", (int)reader.GetType());
reader.DumpDebug();
}
}
2016-11-20 19:13:00 +09:00
void NetClient::SendJoin(int team, WeaponType weapType, std::string name, int kills) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
int weapId;
switch (weapType) {
2013-08-18 16:18:06 +09:00
case RIFLE_WEAPON: weapId = 0; break;
case SMG_WEAPON: weapId = 1; break;
case SHOTGUN_WEAPON: weapId = 2; break;
default: SPInvalidEnum("weapType", weapType);
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
NetPacketWriter wri(PacketTypeExistingPlayer);
wri.Write((uint8_t)GetWorld()->GetLocalPlayerIndex());
wri.Write((uint8_t)team);
wri.Write((uint8_t)weapId);
wri.Write((uint8_t)2); // TODO: change tool
wri.Write((uint32_t)kills);
wri.WriteColor(GetWorld()->GetTeam(team).color);
wri.Write(name, 16);
enet_peer_send(peer, 0, wri.CreatePacket());
}
2016-11-20 19:13:00 +09:00
void NetClient::SendPosition() {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypePositionData);
// wri.Write((uint8_t)pId);
2013-08-18 16:18:06 +09:00
Player *p = GetLocalPlayer();
Vector3 v = p->GetPosition();
wri.Write(v.x);
wri.Write(v.y);
wri.Write(v.z);
enet_peer_send(peer, 0, wri.CreatePacket());
// printf("> (%f %f %f)\n", v.x, v.y, v.z);
2013-08-18 16:18:06 +09:00
}
2016-11-20 19:13:00 +09:00
void NetClient::SendOrientation(spades::Vector3 v) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeOrientationData);
// wri.Write((uint8_t)pId);
2013-08-18 16:18:06 +09:00
wri.Write(v.x);
wri.Write(v.y);
wri.Write(v.z);
enet_peer_send(peer, 0, wri.CreatePacket());
// printf("> (%f %f %f)\n", v.x, v.y, v.z);
2013-08-18 16:18:06 +09:00
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
void NetClient::SendPlayerInput(PlayerInput inp) {
SPADES_MARK_FUNCTION();
2013-08-18 16:18:06 +09:00
uint8_t bits = 0;
if (inp.moveForward)
bits |= 1 << 0;
if (inp.moveBackward)
bits |= 1 << 1;
if (inp.moveLeft)
bits |= 1 << 2;
if (inp.moveRight)
bits |= 1 << 3;
if (inp.jump)
bits |= 1 << 4;
if (inp.crouch)
bits |= 1 << 5;
if (inp.sneak)
bits |= 1 << 6;
if (inp.sprint)
bits |= 1 << 7;
if ((unsigned int)bits == lastPlayerInput)
return;
lastPlayerInput = bits;
NetPacketWriter wri(PacketTypeInputData);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
wri.Write(bits);
2013-08-18 16:18:06 +09:00
enet_peer_send(peer, 0, wri.CreatePacket());
}
2016-11-20 19:13:00 +09:00
void NetClient::SendWeaponInput(WeaponInput inp) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
uint8_t bits = 0;
if (inp.primary)
bits |= 1 << 0;
if (inp.secondary)
bits |= 1 << 1;
if ((unsigned int)bits == lastWeaponInput)
return;
lastWeaponInput = bits;
NetPacketWriter wri(PacketTypeWeaponInput);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
wri.Write(bits);
2013-08-18 16:18:06 +09:00
enet_peer_send(peer, 0, wri.CreatePacket());
}
2016-11-20 19:13:00 +09:00
void NetClient::SendBlockAction(spades::IntVector3 v, BlockActionType type) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeBlockAction);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
2016-11-20 19:13:00 +09:00
switch (type) {
2013-08-18 16:18:06 +09:00
case BlockActionCreate: wri.Write((uint8_t)0); break;
case BlockActionTool: wri.Write((uint8_t)1); break;
case BlockActionDig: wri.Write((uint8_t)2); break;
case BlockActionGrenade: wri.Write((uint8_t)3); break;
default: SPInvalidEnum("type", type);
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
wri.Write((uint32_t)v.x);
wri.Write((uint32_t)v.y);
wri.Write((uint32_t)v.z);
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
enet_peer_send(peer, 0, wri.CreatePacket());
}
2016-11-20 19:13:00 +09:00
void NetClient::SendBlockLine(spades::IntVector3 v1, spades::IntVector3 v2) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeBlockLine);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
wri.Write((uint32_t)v1.x);
wri.Write((uint32_t)v1.y);
wri.Write((uint32_t)v1.z);
wri.Write((uint32_t)v2.x);
wri.Write((uint32_t)v2.y);
wri.Write((uint32_t)v2.z);
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
enet_peer_send(peer, 0, wri.CreatePacket());
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
void NetClient::SendReload() {
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeWeaponReload);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
2016-11-20 19:13:00 +09:00
// these value should be 255, or
// NetClient will think reload was done when
// it receives echoed WeaponReload packet
wri.Write((uint8_t)255); // clip_ammo; not used?
wri.Write((uint8_t)255); // reserve_ammo; not used?
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
enet_peer_send(peer, 0, wri.CreatePacket());
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
void NetClient::SendHeldBlockColor() {
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeSetColour);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
IntVector3 v = GetLocalPlayer()->GetBlockColor();
wri.WriteColor(v);
enet_peer_send(peer, 0, wri.CreatePacket());
}
2016-11-20 19:13:00 +09:00
void NetClient::SendTool() {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeSetTool);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
switch (GetLocalPlayer()->GetTool()) {
case Player::ToolSpade: wri.Write((uint8_t)0); break;
case Player::ToolBlock: wri.Write((uint8_t)1); break;
case Player::ToolWeapon: wri.Write((uint8_t)2); break;
case Player::ToolGrenade: wri.Write((uint8_t)3); break;
default: SPInvalidEnum("tool", GetLocalPlayer()->GetTool());
2013-08-18 16:18:06 +09:00
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
enet_peer_send(peer, 0, wri.CreatePacket());
}
2016-11-20 19:13:00 +09:00
void NetClient::SendGrenade(spades::client::Grenade *g) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeGrenadePacket);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
wri.Write(g->GetFuse());
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Vector3 v = g->GetPosition();
wri.Write(v.x);
wri.Write(v.y);
wri.Write(v.z);
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
v = g->GetVelocity();
wri.Write(v.x);
wri.Write(v.y);
wri.Write(v.z);
enet_peer_send(peer, 0, wri.CreatePacket());
}
2016-11-20 19:13:00 +09:00
void NetClient::SendHit(int targetPlayerId, HitType type) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeHitPacket);
wri.Write((uint8_t)targetPlayerId);
2016-11-20 19:13:00 +09:00
switch (type) {
case HitTypeTorso: wri.Write((uint8_t)0); break;
case HitTypeHead: wri.Write((uint8_t)1); break;
case HitTypeArms: wri.Write((uint8_t)2); break;
case HitTypeLegs: wri.Write((uint8_t)3); break;
case HitTypeMelee: wri.Write((uint8_t)4); break;
default: SPInvalidEnum("type", type);
2013-08-18 16:18:06 +09:00
}
enet_peer_send(peer, 0, wri.CreatePacket());
}
2016-11-20 19:13:00 +09:00
void NetClient::SendChat(std::string text, bool global) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeChatMessage);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
wri.Write((uint8_t)(global ? 0 : 1));
2013-08-18 16:18:06 +09:00
wri.Write(text);
wri.Write((uint8_t)0);
enet_peer_send(peer, 0, wri.CreatePacket());
}
2016-11-20 19:13:00 +09:00
void NetClient::SendWeaponChange(WeaponType wt) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeChangeWeapon);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
switch (wt) {
case RIFLE_WEAPON: wri.Write((uint8_t)0); break;
case SMG_WEAPON: wri.Write((uint8_t)1); break;
case SHOTGUN_WEAPON: wri.Write((uint8_t)2); break;
2013-08-18 16:18:06 +09:00
}
enet_peer_send(peer, 0, wri.CreatePacket());
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
void NetClient::SendTeamChange(int team) {
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeChangeTeam);
wri.Write((uint8_t)GetLocalPlayer()->GetId());
wri.Write((uint8_t)team);
enet_peer_send(peer, 0, wri.CreatePacket());
2013-11-07 00:40:03 +10:00
}
void NetClient::SendHandShakeValid(int challenge) {
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeHandShakeReturn);
wri.Write((uint32_t)challenge);
SPLog("Sending hand shake back.");
enet_peer_send(peer, 0, wri.CreatePacket());
}
void NetClient::SendVersion() {
SPADES_MARK_FUNCTION();
NetPacketWriter wri(PacketTypeVersionSend);
wri.Write((uint8_t)'o');
wri.Write((uint8_t)OpenSpades_VERSION_MAJOR);
wri.Write((uint8_t)OpenSpades_VERSION_MINOR);
wri.Write((uint8_t)OpenSpades_VERSION_REVISION);
wri.Write(VersionInfo::GetVersionInfo());
SPLog("Sending version back.");
enet_peer_send(peer, 0, wri.CreatePacket());
2013-08-18 16:18:06 +09:00
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
void NetClient::MapLoaded() {
SPADES_MARK_FUNCTION();
MemoryStream compressed(mapData.data(), mapData.size());
2013-08-18 16:18:06 +09:00
DeflateStream inflate(&compressed, CompressModeDecompress, false);
GameMap *map;
map = GameMap::Load(&inflate);
2016-11-20 19:13:00 +09:00
2013-08-26 01:27:44 +09:00
SPLog("Map decoding succeeded.");
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
// now initialize world
World *w = new World();
w->SetMap(map);
map->Release();
2013-08-26 01:27:44 +09:00
SPLog("World initialized.");
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
client->SetWorld(w);
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
mapData.clear();
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
SPAssert(GetWorld());
2016-11-20 19:13:00 +09:00
SPLog("World loaded. Processing saved packets (%d)...", (int)savedPackets.size());
2016-11-20 19:13:00 +09:00
for (size_t i = 0; i < playerPosRecords.size(); i++)
playerPosRecords[i].valid = false;
std::fill(savedPlayerTeam.begin(), savedPlayerTeam.end(), -1);
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
// do saved packets
try {
for (size_t i = 0; i < savedPackets.size(); i++) {
2013-08-18 16:18:06 +09:00
NetPacketReader r(savedPackets[i]);
Handle(r);
}
savedPackets.clear();
2013-08-26 01:27:44 +09:00
SPLog("Done.");
} catch (...) {
2013-08-18 16:18:06 +09:00
savedPackets.clear();
throw;
}
}
2016-11-20 19:13:00 +09:00
NetClient::BandwidthMonitor::BandwidthMonitor(ENetHost *host)
: host(host), lastDown(0.0), lastUp(0.0) {
2014-03-31 23:09:47 +09:00
sw.Reset();
}
2016-11-20 19:13:00 +09:00
2014-03-31 23:09:47 +09:00
void NetClient::BandwidthMonitor::Update() {
if (sw.GetTime() > 0.5) {
2014-03-31 23:09:47 +09:00
lastUp = host->totalSentData / sw.GetTime();
lastDown = host->totalReceivedData / sw.GetTime();
host->totalSentData = 0;
host->totalReceivedData = 0;
sw.Reset();
}
}
2013-08-18 16:18:06 +09:00
}
}