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
|
|
|
|
2013-09-15 04:19:34 +02:00
|
|
|
#include <math.h>
|
2016-12-03 18:23:47 +09:00
|
|
|
#include <string.h>
|
|
|
|
#include <vector>
|
2013-09-15 04:19:34 +02:00
|
|
|
|
2016-12-03 19:04:58 +09:00
|
|
|
#include <enet/enet.h>
|
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
#include "CTFGameMode.h"
|
|
|
|
#include "Client.h"
|
|
|
|
#include "GameMap.h"
|
2019-05-19 16:25:39 +09:00
|
|
|
#include "GameMapLoader.h"
|
2016-12-03 18:23:47 +09:00
|
|
|
#include "Grenade.h"
|
2013-09-15 04:19:34 +02:00
|
|
|
#include "NetClient.h"
|
2016-12-03 18:23:47 +09:00
|
|
|
#include "Player.h"
|
|
|
|
#include "TCGameMode.h"
|
|
|
|
#include "World.h"
|
2017-09-03 16:56:01 +09:00
|
|
|
#include "GameProperties.h"
|
2016-12-03 18:23:47 +09:00
|
|
|
#include <Core/CP437.h>
|
2013-09-15 04:19:34 +02:00
|
|
|
#include <Core/Debug.h>
|
|
|
|
#include <Core/Debug.h>
|
|
|
|
#include <Core/DeflateStream.h>
|
2016-12-03 18:23:47 +09:00
|
|
|
#include <Core/Exception.h>
|
|
|
|
#include <Core/Math.h>
|
2013-09-15 04:19:34 +02:00
|
|
|
#include <Core/MemoryStream.h>
|
|
|
|
#include <Core/Settings.h>
|
2014-02-28 16:22:00 +09:00
|
|
|
#include <Core/Strings.h>
|
2017-12-30 04:28:50 +09:00
|
|
|
#include <Core/TMPUtils.h>
|
2013-08-27 12:07:20 +12:00
|
|
|
|
2016-11-19 21:03:51 +09:00
|
|
|
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
|
|
|
|
2017-02-11 16:24:53 +09:00
|
|
|
namespace {
|
|
|
|
const char UtfSign = -1;
|
|
|
|
|
|
|
|
enum { BLUE_FLAG = 0, GREEN_FLAG = 1, BLUE_BASE = 2, GREEN_BASE = 3 };
|
|
|
|
enum PacketType {
|
|
|
|
PacketTypePositionData = 0,
|
|
|
|
PacketTypeOrientationData = 1,
|
|
|
|
PacketTypeWorldUpdate = 2,
|
|
|
|
PacketTypeInputData = 3,
|
|
|
|
PacketTypeWeaponInput = 4,
|
|
|
|
PacketTypeHitPacket = 5, // C2S
|
|
|
|
PacketTypeSetHP = 5, // S2C
|
|
|
|
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
|
|
|
|
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
|
|
|
|
PacketTypeHandShakeReturn = 32, // C2S
|
|
|
|
PacketTypeVersionGet = 33, // S2C
|
|
|
|
PacketTypeVersionSend = 34, // C2S
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class VersionInfoPropertyId : std::uint8_t {
|
|
|
|
ApplicationNameAndVersion = 0,
|
|
|
|
UserLocale = 1,
|
|
|
|
ClientFeatureFlags1 = 2
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class ClientFeatureFlags1 : std::uint32_t { None = 0, SupportsUnicode = 1 << 0 };
|
|
|
|
|
|
|
|
ClientFeatureFlags1 operator|(ClientFeatureFlags1 a, ClientFeatureFlags1 b) {
|
|
|
|
return (ClientFeatureFlags1)((uint32_t)a | (uint32_t)b);
|
2013-12-31 14:06:17 +09:00
|
|
|
}
|
2017-02-11 16:24:53 +09:00
|
|
|
ClientFeatureFlags1 &operator|=(ClientFeatureFlags1 &a, ClientFeatureFlags1 b) {
|
|
|
|
return a = a | b;
|
2013-12-29 23:08:57 +09:00
|
|
|
}
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2017-02-11 16:24:53 +09:00
|
|
|
std::string EncodeString(std::string str) {
|
|
|
|
auto str2 = CP437::Encode(str, -1);
|
|
|
|
if (!cg_unicode) {
|
|
|
|
// ignore fallbacks
|
|
|
|
return str2;
|
|
|
|
}
|
|
|
|
if (str2.find(-1) != std::string::npos) {
|
|
|
|
// some fallbacks; always use UTF8
|
|
|
|
str.insert(0, &UtfSign, 1);
|
|
|
|
} else {
|
|
|
|
str = str2;
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string DecodeString(std::string s) {
|
|
|
|
if (s.size() > 0 && s[0] == UtfSign) {
|
|
|
|
return s.substr(1);
|
|
|
|
}
|
|
|
|
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;
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
public:
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
NetPacketReader(const std::vector<char> inData) {
|
2013-08-18 16:18:06 +09:00
|
|
|
data = inData;
|
|
|
|
pos = 1;
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
|
|
|
|
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;
|
2016-12-03 18:23:47 +09:00
|
|
|
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;
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
|
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;
|
2016-12-03 18:23:47 +09:00
|
|
|
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;
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
uint8_t ReadByte() {
|
|
|
|
SPADES_MARK_FUNCTION();
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
if (pos >= data.size()) {
|
2013-08-18 16:18:06 +09:00
|
|
|
SPRaise("Received packet truncated");
|
|
|
|
}
|
|
|
|
return (uint8_t)data[pos++];
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
|
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
|
|
|
|
2017-02-11 16:24:53 +09:00
|
|
|
std::size_t GetNumRemainingBytes() { return data.size() - pos; }
|
|
|
|
|
2016-12-03 18:23:47 +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) {
|
2016-12-03 18:23:47 +09:00
|
|
|
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() {
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +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;
|
2016-12-03 18:23:47 +09:00
|
|
|
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();
|
2016-12-03 18:23:47 +09:00
|
|
|
if (bytes > 64) {
|
2013-08-18 16:18:06 +09:00
|
|
|
bytes = 64;
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
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;
|
2016-12-03 18:23:47 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
public:
|
2016-12-03 18:23:47 +09:00
|
|
|
NetPacketWriter(PacketType type) { data.push_back(type); }
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
void Write(uint8_t v) {
|
2013-08-18 16:18:06 +09:00
|
|
|
SPADES_MARK_FUNCTION_DEBUG();
|
|
|
|
data.push_back(v);
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
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));
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
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));
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
void Write(float v) {
|
2013-08-18 16:18:06 +09:00
|
|
|
SPADES_MARK_FUNCTION_DEBUG();
|
|
|
|
union {
|
2016-12-03 18:23:47 +09:00
|
|
|
float f;
|
|
|
|
uint32_t i;
|
2013-08-18 16:18:06 +09:00
|
|
|
};
|
|
|
|
f = v;
|
|
|
|
Write(i);
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
void Write(std::string str) {
|
2013-12-29 23:08:57 +09:00
|
|
|
str = EncodeString(str);
|
2016-12-03 18:23:47 +09:00
|
|
|
data.insert(data.end(), str.begin(), str.end());
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +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();
|
2016-12-03 18:23:47 +09:00
|
|
|
while (sz < fillLen) {
|
2013-08-18 16:18:06 +09:00
|
|
|
Write((uint8_t)0);
|
|
|
|
sz++;
|
|
|
|
}
|
|
|
|
}
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2017-02-11 16:24:53 +09:00
|
|
|
std::size_t GetPosition() { return data.size(); }
|
|
|
|
|
|
|
|
void Update(std::size_t position, std::uint8_t newValue) {
|
|
|
|
SPADES_MARK_FUNCTION_DEBUG();
|
|
|
|
|
|
|
|
if (position >= data.size()) {
|
|
|
|
SPRaise("Invalid write (%d should be less than %d)", (int)position,
|
|
|
|
(int)data.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
data[position] = static_cast<char>(newValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Update(std::size_t position, std::uint32_t newValue) {
|
|
|
|
SPADES_MARK_FUNCTION_DEBUG();
|
|
|
|
|
|
|
|
if (position + 4 > data.size()) {
|
|
|
|
SPRaise("Invalid write (%d should be less than or equal to %d)",
|
|
|
|
(int)(position + 4), (int)data.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Assuming the target platform is little endian and supports
|
|
|
|
// unaligned memory access...
|
|
|
|
*reinterpret_cast<std::uint32_t *>(data.data() + position) = newValue;
|
|
|
|
}
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
ENetPacket *CreatePacket(int flag = ENET_PACKET_FLAG_RELIABLE) {
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
host = enet_host_create(NULL, 1, 1, 100000, 100000);
|
2013-08-26 01:27:44 +09:00
|
|
|
SPLog("ENet host created");
|
2016-12-03 18:23:47 +09:00
|
|
|
if (!host) {
|
2013-08-18 16:18:06 +09:00
|
|
|
SPRaise("Failed to create ENet host");
|
|
|
|
}
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2013-08-31 12:53:44 +09:00
|
|
|
lastPlayerInput = 0;
|
|
|
|
lastWeaponInput = 0;
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2017-09-04 14:39:24 +09:00
|
|
|
savedPlayerPos.resize(128);
|
|
|
|
savedPlayerFront.resize(128);
|
|
|
|
savedPlayerTeam.resize(128);
|
|
|
|
playerPosRecords.resize(128);
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
}
|
2016-12-03 18:23:47 +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();
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2017-01-05 03:03:39 +09:00
|
|
|
switch (hostname.GetProtocolVersion()) {
|
|
|
|
case ProtocolVersion::v075:
|
|
|
|
SPLog("Using Ace of Spades 0.75 protocol");
|
|
|
|
protocolVersion = 3;
|
|
|
|
break;
|
|
|
|
case ProtocolVersion::v076:
|
|
|
|
SPLog("Using Ace of Spades 0.76 protocol");
|
|
|
|
protocolVersion = 4;
|
|
|
|
break;
|
|
|
|
default: SPRaise("Invalid ProtocolVersion"); break;
|
2013-09-15 04:19:34 +02:00
|
|
|
}
|
|
|
|
|
2017-01-05 03:03:39 +09:00
|
|
|
ENetAddress addr = hostname.GetENetAddress();
|
2013-09-15 04:19:34 +02:00
|
|
|
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
|
|
|
|
2017-01-05 03:03:39 +09:00
|
|
|
peer = enet_host_connect(host, &addr, 1, protocolVersion);
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2017-09-11 20:49:21 +09:00
|
|
|
properties.reset(new GameProperties(hostname.GetProtocolVersion()));
|
|
|
|
|
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
|
|
|
}
|
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
|
|
|
|
2016-12-03 18:23:47 +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");
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +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;
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
if (status == NetClientStatusNotConnected)
|
2013-08-18 16:18:06 +09:00
|
|
|
return;
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +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;
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +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());
|
|
|
|
}
|
2017-12-29 20:46:35 +09:00
|
|
|
|
2017-12-30 04:28:50 +09:00
|
|
|
stmp::optional<NetPacketReader> readerOrNone;
|
|
|
|
|
2017-12-29 20:46:35 +09:00
|
|
|
if (event.type == ENET_EVENT_TYPE_RECEIVE) {
|
2017-12-30 04:28:50 +09:00
|
|
|
readerOrNone.reset(event.packet);
|
|
|
|
auto &reader = readerOrNone.value();
|
|
|
|
|
2017-12-29 20:46:35 +09:00
|
|
|
try {
|
|
|
|
if (HandleHandshakePacket(reader)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} catch (const std::exception &ex) {
|
|
|
|
int type = reader.GetType();
|
|
|
|
reader.DumpDebug();
|
|
|
|
SPRaise("Exception while handling packet type 0x%08x:\n%s", type,
|
|
|
|
ex.what());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
if (status == NetClientStatusConnecting) {
|
|
|
|
if (event.type == ENET_EVENT_TYPE_CONNECT) {
|
2014-03-30 02:44:43 +09:00
|
|
|
statusString = _Tr("NetClient", "Awaiting for state");
|
2016-12-03 18:23:47 +09:00
|
|
|
} else if (event.type == ENET_EVENT_TYPE_RECEIVE) {
|
2017-12-30 04:28:50 +09:00
|
|
|
auto &reader = readerOrNone.value();
|
2013-08-18 16:18:06 +09:00
|
|
|
reader.DumpDebug();
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2019-05-19 16:25:39 +09:00
|
|
|
auto mapSize = reader.ReadInt();
|
|
|
|
SPLog("Map size advertised by the server: %lu", (unsigned long)mapSize);
|
|
|
|
|
|
|
|
mapLoader.reset(new GameMapLoader());
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
status = NetClientStatusReceivingMap;
|
2014-02-28 16:22:00 +09:00
|
|
|
statusString = _Tr("NetClient", "Loading snapshot");
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
} else if (status == NetClientStatusReceivingMap) {
|
2019-05-19 16:25:39 +09:00
|
|
|
SPAssert(mapLoader);
|
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
if (event.type == ENET_EVENT_TYPE_RECEIVE) {
|
2017-12-30 04:28:50 +09:00
|
|
|
auto &reader = readerOrNone.value();
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
if (reader.GetType() == PacketTypeMapChunk) {
|
2013-08-18 16:18:06 +09:00
|
|
|
std::vector<char> dt = reader.GetData();
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2019-05-19 16:25:39 +09:00
|
|
|
mapLoader->AddRawChunk(dt.data() + 1, dt.size() - 1);
|
2016-12-03 18:23:47 +09:00
|
|
|
} else {
|
2013-08-18 16:18:06 +09:00
|
|
|
reader.DumpDebug();
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2019-05-04 18:51:46 +02:00
|
|
|
// The actual size of the map data cannot be known beforehand because
|
|
|
|
// of compression. This means we must detect the end of the map
|
|
|
|
// transfer in another way.
|
2017-12-16 23:38:15 +09:00
|
|
|
//
|
2019-05-04 18:51:46 +02:00
|
|
|
// We do this by checking for a StateData packet, which is sent
|
|
|
|
// directly after the map transfer completes.
|
|
|
|
//
|
|
|
|
// A number of other packets can also be received while loading the map:
|
2017-12-16 23:38:15 +09:00
|
|
|
//
|
|
|
|
// - World update packets (WorldUpdate, ExistingPlayer, and
|
|
|
|
// CreatePlayer) for the current round. We must store such packets
|
2019-05-04 18:51:46 +02:00
|
|
|
// temporarily and process them later when a `World` is created.
|
2017-12-16 23:38:15 +09:00
|
|
|
//
|
|
|
|
// - Leftover reload packet from the previous round. This happens when
|
|
|
|
// you initiate the reload action and a map change occurs before it
|
2019-05-04 18:51:46 +02:00
|
|
|
// is completed. In pyspades, sending a reload packet is implemented
|
|
|
|
// by registering a callback function to the Twisted reactor. This
|
2017-12-16 23:38:15 +09:00
|
|
|
// callback function sends a reload packet, but it does not check if
|
|
|
|
// the current game round is finished, nor is it unregistered on a
|
|
|
|
// map change.
|
|
|
|
//
|
|
|
|
// Such a reload packet would not (and should not) have any effect on
|
|
|
|
// the current round. Also, an attempt to process it would result in
|
|
|
|
// an "invalid player ID" exception, so we simply drop it during
|
|
|
|
// map load sequence.
|
|
|
|
//
|
2019-05-04 18:51:46 +02:00
|
|
|
|
|
|
|
if (reader.GetType() == PacketTypeStateData) {
|
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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
try {
|
2013-08-18 16:18:06 +09:00
|
|
|
MapLoaded();
|
2016-12-03 18:23:47 +09:00
|
|
|
} catch (const std::exception &ex) {
|
|
|
|
if (strstr(ex.what(), "File truncated") ||
|
|
|
|
strstr(ex.what(), "EOF reached")) {
|
2019-05-19 16:25:39 +09:00
|
|
|
SPLog("Map decoder returned error:\n%s", ex.what());
|
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-12-03 18:23:47 +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;
|
|
|
|
}
|
2017-12-29 20:46:35 +09:00
|
|
|
HandleGamePacket(reader);
|
2019-05-04 20:21:44 +02:00
|
|
|
} else if (reader.GetType() == PacketTypeWeaponReload) {
|
2019-05-04 18:51:46 +02:00
|
|
|
// Drop the reload packet. Pyspades does not
|
|
|
|
// cancel the reload packets on map change and
|
|
|
|
// they would cause an error if we would
|
|
|
|
// process them
|
2019-05-19 16:25:39 +09:00
|
|
|
} else {
|
2019-05-04 20:21:44 +02:00
|
|
|
// Save the packet for later
|
2013-08-18 16:18:06 +09:00
|
|
|
savedPackets.push_back(reader.GetData());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
} else if (status == NetClientStatusConnected) {
|
|
|
|
if (event.type == ENET_EVENT_TYPE_RECEIVE) {
|
2017-12-30 04:28:50 +09:00
|
|
|
auto &reader = readerOrNone.value();
|
2016-12-03 18:23:47 +09:00
|
|
|
// reader.DumpDebug();
|
|
|
|
try {
|
2017-12-29 20:46:35 +09:00
|
|
|
HandleGamePacket(reader);
|
2016-12-03 18:23:47 +09:00
|
|
|
} catch (const std::exception &ex) {
|
2013-08-18 16:18:06 +09:00
|
|
|
int type = reader.GetType();
|
|
|
|
reader.DumpDebug();
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
World *NetClient::GetWorld() { return client->GetWorld(); }
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
Player *NetClient::GetPlayerOrNull(int pId) {
|
2013-08-18 16:18:06 +09:00
|
|
|
SPADES_MARK_FUNCTION();
|
2016-12-03 18:23:47 +09:00
|
|
|
if (!GetWorld())
|
2013-08-18 16:18:06 +09:00
|
|
|
SPRaise("Invalid Player ID %d: No world", pId);
|
2016-12-03 18:23:47 +09:00
|
|
|
if (pId < 0 || pId >= GetWorld()->GetNumPlayerSlots())
|
2013-08-18 16:18:06 +09:00
|
|
|
return NULL;
|
|
|
|
return GetWorld()->GetPlayer(pId);
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
Player *NetClient::GetPlayer(int pId) {
|
2013-08-18 16:18:06 +09:00
|
|
|
SPADES_MARK_FUNCTION();
|
2016-12-03 18:23:47 +09:00
|
|
|
if (!GetWorld())
|
2013-08-18 16:18:06 +09:00
|
|
|
SPRaise("Invalid Player ID %d: No world", pId);
|
2016-12-03 18:23:47 +09:00
|
|
|
if (pId < 0 || pId >= GetWorld()->GetNumPlayerSlots())
|
2013-08-18 16:18:06 +09:00
|
|
|
SPRaise("Invalid Player ID %d: Out of range", pId);
|
2016-12-03 18:23:47 +09:00
|
|
|
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();
|
2016-12-03 18:23:47 +09:00
|
|
|
if (!GetWorld())
|
2013-08-18 16:18:06 +09:00
|
|
|
SPRaise("Failed to get local player: no world");
|
2016-12-03 18:23:47 +09:00
|
|
|
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();
|
2016-12-03 18:23:47 +09:00
|
|
|
if (!GetWorld())
|
2013-08-18 16:18:06 +09:00
|
|
|
SPRaise("Failed to get local player: no world");
|
|
|
|
return GetWorld()->GetLocalPlayer();
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +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:
|
2016-12-03 18:23:47 +09:00
|
|
|
// 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.");
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2017-12-29 20:46:35 +09:00
|
|
|
bool NetClient::HandleHandshakePacket(spades::client::NetPacketReader &reader) {
|
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
|
|
|
|
switch (reader.GetType()) {
|
|
|
|
case PacketTypeHandShakeInit: SendHandShakeValid(reader.ReadInt()); return true;
|
|
|
|
case PacketTypeVersionGet: {
|
|
|
|
if (reader.GetNumRemainingBytes() > 0) {
|
|
|
|
// Enhanced variant
|
|
|
|
std::set<std::uint8_t> propertyIds;
|
|
|
|
while (reader.GetNumRemainingBytes()) {
|
|
|
|
propertyIds.insert(reader.ReadByte());
|
|
|
|
}
|
|
|
|
SendVersionEnhanced(propertyIds);
|
|
|
|
} else {
|
|
|
|
// Simple variant
|
|
|
|
SendVersion();
|
|
|
|
}
|
2017-12-29 20:49:10 +09:00
|
|
|
}
|
|
|
|
return true;
|
2017-12-29 20:47:20 +09:00
|
|
|
default: return false;
|
2017-12-29 20:46:35 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NetClient::HandleGamePacket(spades::client::NetPacketReader &reader) {
|
2013-08-18 16:18:06 +09:00
|
|
|
SPADES_MARK_FUNCTION();
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
switch (reader.GetType()) {
|
|
|
|
case PacketTypePositionData: {
|
2013-08-18 16:18:06 +09:00
|
|
|
Player *p = GetLocalPlayer();
|
|
|
|
Vector3 pos;
|
2016-12-03 18:23:47 +09:00
|
|
|
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);
|
2016-12-03 18:23:47 +09:00
|
|
|
} 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);
|
2016-12-03 18:23:47 +09:00
|
|
|
} break;
|
|
|
|
case PacketTypeWorldUpdate: {
|
|
|
|
// reader.DumpDebug();
|
2013-08-27 12:07:20 +12:00
|
|
|
int bytesPerEntry = 24;
|
2017-01-05 03:03:39 +09:00
|
|
|
if (protocolVersion == 4)
|
2013-08-27 12:07:20 +12:00
|
|
|
bytesPerEntry++;
|
|
|
|
|
2018-01-06 11:38:14 +01:00
|
|
|
client->MarkWorldUpdate();
|
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
int entries = static_cast<int>(reader.GetData().size() / bytesPerEntry);
|
|
|
|
for (int i = 0; i < entries; i++) {
|
2013-08-27 12:07:20 +12:00
|
|
|
int idx = i;
|
2017-01-05 03:03:39 +09:00
|
|
|
if (protocolVersion == 4) {
|
2013-08-27 12:07:20 +12:00
|
|
|
idx = reader.ReadByte();
|
2017-09-04 14:39:24 +09:00
|
|
|
if (idx < 0 || idx >= properties->GetMaxNumPlayerSlots()) {
|
2013-09-03 01:23:28 +09:00
|
|
|
SPRaise("Invalid player number %d received with WorldUpdate", idx);
|
|
|
|
}
|
2013-08-27 12:07:20 +12:00
|
|
|
}
|
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
|
|
|
|
2013-09-03 01:23:28 +09:00
|
|
|
savedPlayerPos[idx] = pos;
|
|
|
|
savedPlayerFront[idx] = front;
|
2016-12-03 18:23:47 +09:00
|
|
|
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;
|
2016-12-04 20:01:37 +00:00
|
|
|
SPAssert(!std::isnan(pos.x));
|
|
|
|
SPAssert(!std::isnan(pos.y));
|
|
|
|
SPAssert(!std::isnan(pos.z));
|
|
|
|
SPAssert(!std::isnan(front.x));
|
|
|
|
SPAssert(!std::isnan(front.y));
|
|
|
|
SPAssert(!std::isnan(front.z));
|
2013-08-18 16:18:06 +09:00
|
|
|
SPAssert(front.GetLength() < 40.f);
|
2016-12-03 18:23:47 +09:00
|
|
|
if (GetWorld()) {
|
2013-08-27 12:07:20 +12:00
|
|
|
p = GetWorld()->GetPlayer(idx);
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
PosRecord &rec = playerPosRecords[idx];
|
|
|
|
if (rec.valid) {
|
2013-09-03 01:23:28 +09:00
|
|
|
float timespan = GetWorld()->GetTime() - rec.time;
|
2013-09-03 01:42:10 +09:00
|
|
|
timespan = std::max(0.16f, timespan);
|
2013-09-03 01:23:28 +09:00
|
|
|
Vector3 vel = (pos - rec.pos) / timespan;
|
|
|
|
vel *= 1.f / 32.f;
|
|
|
|
p->SetVelocity(vel);
|
|
|
|
}
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2013-09-03 01:23:28 +09:00
|
|
|
rec.valid = true;
|
|
|
|
rec.pos = pos;
|
|
|
|
rec.time = GetWorld()->GetTime();
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SPAssert(reader.ReadRemainingData().empty());
|
2016-12-03 18:23:47 +09:00
|
|
|
} break;
|
2013-08-18 16:18:06 +09:00
|
|
|
case PacketTypeInputData:
|
2016-12-03 18:23:47 +09:00
|
|
|
if (!GetWorld())
|
2013-08-18 16:18:06 +09:00
|
|
|
break;
|
2016-12-03 18:23:47 +09:00
|
|
|
{
|
|
|
|
int pId = reader.ReadByte();
|
|
|
|
Player *p = GetPlayer(pId);
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
PlayerInput inp = ParsePlayerInput(reader.ReadByte());
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
if (GetWorld()->GetLocalPlayer() == p) {
|
|
|
|
// handle "/fly" jump
|
|
|
|
if (inp.jump) {
|
2017-01-05 04:11:42 +09:00
|
|
|
if (!p) {
|
|
|
|
SPRaise("Local player is null");
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
p->ForceJump();
|
|
|
|
}
|
|
|
|
break;
|
2014-03-30 01:42:18 +09:00
|
|
|
}
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +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:
|
2016-12-03 18:23:47 +09:00
|
|
|
if (!GetWorld())
|
2013-08-18 16:18:06 +09:00
|
|
|
break;
|
2016-12-03 18:23:47 +09:00
|
|
|
{
|
|
|
|
int pId = reader.ReadByte();
|
|
|
|
Player *p = GetPlayer(pId);
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
WeaponInput inp = ParseWeaponInput(reader.ReadByte());
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
if (GetWorld()->GetLocalPlayer() == p)
|
|
|
|
break;
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
p->SetWeaponInput(inp);
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
break;
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +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();
|
2016-12-03 18:23:47 +09:00
|
|
|
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:
|
2016-12-03 18:23:47 +09:00
|
|
|
if (!GetWorld())
|
2013-08-18 16:18:06 +09:00
|
|
|
break;
|
2016-12-03 18:23:47 +09:00
|
|
|
{
|
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
case PacketTypeSetTool: {
|
2013-08-18 16:18:06 +09:00
|
|
|
Player *p = GetPlayer(reader.ReadByte());
|
|
|
|
int tool = reader.ReadByte();
|
2016-12-03 18:23:47 +09:00
|
|
|
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;
|
2016-12-03 18:23:47 +09:00
|
|
|
default: SPRaise("Received invalid tool type: %d", tool);
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
} break;
|
|
|
|
case PacketTypeSetColour: {
|
2013-08-18 16:18:06 +09:00
|
|
|
Player *p = GetPlayerOrNull(reader.ReadByte());
|
|
|
|
IntVector3 col = reader.ReadIntColor();
|
2016-12-03 18:23:47 +09:00
|
|
|
if (p)
|
2013-08-18 16:18:06 +09:00
|
|
|
p->SetHeldBlockColor(col);
|
|
|
|
else
|
|
|
|
temporaryPlayerBlockColor = col;
|
2016-12-03 18:23:47 +09:00
|
|
|
} break;
|
2013-08-18 16:18:06 +09:00
|
|
|
case PacketTypeExistingPlayer:
|
2016-12-03 18:23:47 +09:00
|
|
|
if (!GetWorld())
|
2013-08-18 16:18:06 +09:00
|
|
|
break;
|
2016-12-03 18:23:47 +09:00
|
|
|
{
|
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
World::PlayerPersistent &pers = GetWorld()->GetPlayerPersistent(pId);
|
|
|
|
pers.name = name;
|
|
|
|
pers.kills = kills;
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
savedPlayerTeam[pId] = team;
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
break;
|
2016-12-03 18:23:47 +09:00
|
|
|
case PacketTypeShortPlayerData: SPRaise("Unexpected: received Short Player Data");
|
2013-08-18 16:18:06 +09:00
|
|
|
case PacketTypeMoveObject:
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
if (state > 2) {
|
|
|
|
SPRaise("Invalid state %d specified for territory owner.",
|
|
|
|
(int)state);
|
|
|
|
}
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +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;
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2017-09-04 14:39:24 +09:00
|
|
|
if (pId < 0 || pId >= properties->GetMaxNumPlayerSlots()) {
|
|
|
|
SPLog("Ignoring invalid player number %d (bug in pyspades?: %s)", pId,
|
|
|
|
name.c_str());
|
2013-10-08 22:01:07 +02:00
|
|
|
break;
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
WeaponType wType;
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
Player *p = new Player(GetWorld(), pId, wType, team, savedPlayerPos[pId],
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
World::PlayerPersistent &pers = GetWorld()->GetPlayerPersistent(pId);
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2013-09-03 01:23:28 +09:00
|
|
|
playerPosRecords[pId].valid = false;
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
if (pId == GetWorld()->GetLocalPlayerIndex()) {
|
2013-08-18 16:18:06 +09:00
|
|
|
client->LocalPlayerCreated();
|
2013-08-31 12:53:44 +09:00
|
|
|
lastPlayerInput = 0xffffffff;
|
|
|
|
lastWeaponInput = 0xffffffff;
|
2016-11-20 19:13:00 +09:00
|
|
|
SendHeldBlockColor(); // ensure block color synchronized
|
2016-12-03 18:23:47 +09:00
|
|
|
} 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();
|
|
|
|
}
|
2017-09-03 16:00:30 +09:00
|
|
|
if (savedPlayerTeam[pId] != team) {
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2013-09-02 00:42:45 +09:00
|
|
|
client->PlayerJoinedTeam(p);
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2013-09-02 00:42:45 +09:00
|
|
|
savedPlayerTeam[pId] = team;
|
|
|
|
}
|
2013-08-31 12:53:44 +09:00
|
|
|
}
|
2017-09-03 16:56:01 +09:00
|
|
|
client->PlayerSpawned(p);
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +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;
|
2016-12-03 18:23:47 +09:00
|
|
|
if (action == 0) {
|
2014-03-13 14:01:53 +09:00
|
|
|
bool replace = GetWorld()->GetMap()->IsSolidWrapped(pos.x, pos.y, pos.z);
|
2016-12-03 18:23:47 +09:00
|
|
|
if (!p) {
|
2013-08-18 16:18:06 +09:00
|
|
|
GetWorld()->CreateBlock(pos, temporaryPlayerBlockColor);
|
2016-12-03 18:23:47 +09:00
|
|
|
} else {
|
2013-08-18 16:18:06 +09:00
|
|
|
GetWorld()->CreateBlock(pos, p->GetBlockColor());
|
|
|
|
client->PlayerCreatedBlock(p);
|
2016-12-03 18:23:47 +09:00
|
|
|
if (!replace) {
|
2014-03-13 14:01:53 +09:00
|
|
|
p->UsedBlocks(1);
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
if (p && p->GetTool() == Player::ToolSpade) {
|
2013-08-18 16:18:06 +09:00
|
|
|
p->GotBlock();
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
} else if (action == 2) {
|
2013-08-18 16:18:06 +09:00
|
|
|
// dig
|
|
|
|
client->PlayerDiggedBlock(pos);
|
2016-12-03 18:23:47 +09:00
|
|
|
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);
|
2016-12-03 18:23:47 +09:00
|
|
|
} else if (action == 3) {
|
2013-08-18 16:18:06 +09:00
|
|
|
// grenade
|
|
|
|
client->GrenadeDestroyedBlock(pos);
|
2016-12-03 18:23:47 +09:00
|
|
|
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);
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
} 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
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
if (p) {
|
|
|
|
p->UsedBlocks(static_cast<int>(cells.size()));
|
2013-08-18 16:18:06 +09:00
|
|
|
client->PlayerCreatedBlock(p);
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
} break;
|
2013-08-18 16:18:06 +09:00
|
|
|
case PacketTypeStateData:
|
2016-12-03 18:23:47 +09:00
|
|
|
if (!GetWorld())
|
2013-08-18 16:18:06 +09:00
|
|
|
break;
|
2016-12-03 18:23:47 +09:00
|
|
|
{
|
|
|
|
// 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
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
GetWorld()->SetMode(mode);
|
|
|
|
} catch (...) {
|
|
|
|
delete mode;
|
|
|
|
throw;
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
GetWorld()->SetMode(mode);
|
|
|
|
} catch (...) {
|
|
|
|
delete mode;
|
|
|
|
throw;
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
client->JoinedGame();
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
break;
|
2016-12-03 18:23:47 +09:00
|
|
|
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;
|
2016-12-03 18:23:47 +09:00
|
|
|
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;
|
2016-12-03 18:23:47 +09:00
|
|
|
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();
|
2016-12-03 18:23:47 +09:00
|
|
|
switch (type) {
|
2013-08-18 16:18:06 +09:00
|
|
|
case KillTypeFall:
|
|
|
|
case KillTypeClassChange:
|
2016-12-03 18:23:47 +09:00
|
|
|
case KillTypeTeamChange: killer = p; break;
|
|
|
|
default: break;
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
p->KilledBy(type, killer, respawnTime);
|
2016-12-03 18:23:47 +09:00
|
|
|
if (p != killer) {
|
2013-08-18 16:18:06 +09:00
|
|
|
GetWorld()->GetPlayerPersistent(killer->GetId()).kills += 1;
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
} break;
|
|
|
|
case PacketTypeChatMessage: {
|
2013-08-18 16:18:06 +09:00
|
|
|
// might be wrong player id for server message
|
|
|
|
uint8_t pId = reader.ReadByte();
|
2017-09-04 14:39:24 +09:00
|
|
|
Player *p = GetPlayerOrNull(pId);
|
2013-08-18 16:18:06 +09:00
|
|
|
int type = reader.ReadByte();
|
|
|
|
std::string txt = reader.ReadRemainingString();
|
2016-12-03 18:23:47 +09:00
|
|
|
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);
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
} else {
|
2013-08-18 16:18:06 +09:00
|
|
|
client->ServerSentMessage(txt);
|
2017-09-03 16:56:01 +09:00
|
|
|
|
|
|
|
// Speculate the best game properties based on the server generated
|
|
|
|
// messages
|
|
|
|
properties->HandleServerMessage(txt);
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
} break;
|
|
|
|
case PacketTypeMapStart: {
|
2013-08-18 16:18:06 +09:00
|
|
|
// next map!
|
|
|
|
client->SetWorld(NULL);
|
2019-05-19 16:25:39 +09:00
|
|
|
|
|
|
|
auto mapSize = reader.ReadInt();
|
|
|
|
SPLog("Map size advertised by the server: %lu", (unsigned long)mapSize);
|
|
|
|
|
|
|
|
mapLoader.reset(new GameMapLoader());
|
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
status = NetClientStatusReceivingMap;
|
2014-02-28 16:22:00 +09:00
|
|
|
statusString = _Tr("NetClient", "Loading snapshot");
|
2016-12-03 18:23:47 +09:00
|
|
|
} 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
|
|
|
|
2013-09-02 00:42:45 +09:00
|
|
|
client->PlayerLeaving(p);
|
2017-09-03 16:59:33 +09:00
|
|
|
GetWorld()->GetPlayerPersistent(p->GetId()).kills = 0;
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2013-09-02 00:42:45 +09:00
|
|
|
savedPlayerTeam[p->GetId()] = -1;
|
2013-09-03 01:23:28 +09:00
|
|
|
playerPosRecords[p->GetId()].valid = false;
|
2013-08-18 16:18:06 +09:00
|
|
|
GetWorld()->SetPlayer(p->GetId(), NULL);
|
|
|
|
// TODO: message
|
2016-12-03 18:23:47 +09:00
|
|
|
} 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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
IGameMode *mode = GetWorld()->GetMode();
|
|
|
|
if (mode == NULL)
|
|
|
|
break;
|
|
|
|
if (mode->ModeType() != IGameMode::m_TC) {
|
2013-12-07 16:58:39 +01:00
|
|
|
SPRaise("Received PacketTypeTerritoryCapture in non-TC gamemode");
|
|
|
|
}
|
|
|
|
TCGameMode *tc = static_cast<TCGameMode *>(mode);
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
if (territoryId >= tc->GetNumTerritories()) {
|
2013-08-18 16:18:06 +09:00
|
|
|
SPRaise("Invalid territory id %d specified (max = %d)", territoryId,
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2013-12-07 16:58:39 +01: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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
if (winning)
|
2013-08-18 16:18:06 +09:00
|
|
|
client->TeamWon(state);
|
2016-12-03 18:23:47 +09:00
|
|
|
} 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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
IGameMode *mode = GetWorld()->GetMode();
|
|
|
|
if (mode == NULL)
|
|
|
|
break;
|
|
|
|
if (mode->ModeType() != IGameMode::m_TC) {
|
2013-12-07 16:58:39 +01:00
|
|
|
SPRaise("Received PacketTypeProgressBar in non-TC gamemode");
|
|
|
|
}
|
|
|
|
TCGameMode *tc = static_cast<TCGameMode *>(mode);
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
if (territoryId >= tc->GetNumTerritories()) {
|
2013-08-18 16:18:06 +09:00
|
|
|
SPRaise("Invalid territory id %d specified (max = %d)", territoryId,
|
2016-12-03 18:23:47 +09:00
|
|
|
tc->GetNumTerritories() - 1);
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2013-12-07 16:58:39 +01: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;
|
2016-12-03 18:23:47 +09:00
|
|
|
} break;
|
|
|
|
case PacketTypeIntelCapture: {
|
|
|
|
if (!GetWorld())
|
|
|
|
SPRaise("No world");
|
|
|
|
IGameMode *mode = GetWorld()->GetMode();
|
|
|
|
if (mode == NULL)
|
|
|
|
break;
|
|
|
|
if (mode->ModeType() != IGameMode::m_CTF) {
|
2013-12-07 16:58:39 +01:00
|
|
|
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;
|
2013-12-07 16:58:39 +01:00
|
|
|
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;
|
2016-12-03 18:23:47 +09:00
|
|
|
if (winning)
|
2013-08-18 16:18:06 +09:00
|
|
|
client->TeamWon(p->GetTeamId());
|
2016-12-03 18:23:47 +09:00
|
|
|
} break;
|
|
|
|
case PacketTypeIntelPickup: {
|
2013-08-18 16:18:06 +09:00
|
|
|
Player *p = GetPlayer(reader.ReadByte());
|
2016-12-03 18:23:47 +09:00
|
|
|
IGameMode *mode = GetWorld()->GetMode();
|
|
|
|
if (mode == NULL)
|
|
|
|
break;
|
|
|
|
if (mode->ModeType() != IGameMode::m_CTF) {
|
2013-12-07 16:58:39 +01:00
|
|
|
SPRaise("Received PacketTypeIntelPickup in non-TC gamemode");
|
|
|
|
}
|
|
|
|
CTFGameMode *ctf = static_cast<CTFGameMode *>(mode);
|
2016-12-03 18:23:47 +09:00
|
|
|
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);
|
2016-12-03 18:23:47 +09:00
|
|
|
} break;
|
|
|
|
case PacketTypeIntelDrop: {
|
2013-08-18 16:18:06 +09:00
|
|
|
Player *p = GetPlayer(reader.ReadByte());
|
2016-12-03 18:23:47 +09:00
|
|
|
IGameMode *mode = GetWorld()->GetMode();
|
|
|
|
if (mode == NULL)
|
|
|
|
break;
|
|
|
|
if (mode->ModeType() != IGameMode::m_CTF) {
|
2013-12-07 16:58:39 +01:00
|
|
|
SPRaise("Received PacketTypeIntelPickup in non-TC gamemode");
|
|
|
|
}
|
|
|
|
CTFGameMode *ctf = static_cast<CTFGameMode *>(mode);
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2013-12-07 16:58:39 +01: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);
|
2016-12-03 18:23:47 +09:00
|
|
|
} break;
|
|
|
|
case PacketTypeRestock: {
|
|
|
|
Player *p = GetLocalPlayer(); // GetPlayer(reader.ReadByte());
|
2013-08-18 16:18:06 +09:00
|
|
|
p->Restock();
|
2016-12-03 18:23:47 +09:00
|
|
|
} break;
|
|
|
|
case PacketTypeFogColour: {
|
|
|
|
if (GetWorld()) {
|
2013-08-18 16:18:06 +09:00
|
|
|
reader.ReadByte(); // skip
|
|
|
|
GetWorld()->SetFogColor(reader.ReadIntColor());
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
} break;
|
|
|
|
case PacketTypeWeaponReload: {
|
2013-08-18 16:18:06 +09:00
|
|
|
Player *p = GetPlayer(reader.ReadByte());
|
2016-12-03 18:23:47 +09:00
|
|
|
if (p != GetLocalPlayerOrNull())
|
2013-08-18 16:18:06 +09:00
|
|
|
p->Reload();
|
2016-12-03 18:23:47 +09:00
|
|
|
else {
|
2013-08-31 02:50:51 +09:00
|
|
|
int clip = reader.ReadByte();
|
|
|
|
int reserve = reader.ReadByte();
|
2017-01-05 04:11:42 +09:00
|
|
|
if (clip < 255 && reserve < 255 && p) {
|
2013-08-31 02:50:51 +09:00
|
|
|
p->ReloadDone(clip, reserve);
|
|
|
|
}
|
|
|
|
}
|
2013-08-18 16:18:06 +09:00
|
|
|
// FIXME: use of "clip ammo" and "reserve ammo"?
|
2016-12-03 18:23:47 +09:00
|
|
|
} break;
|
|
|
|
case PacketTypeChangeTeam: {
|
2013-08-18 16:18:06 +09:00
|
|
|
Player *p = GetPlayer(reader.ReadByte());
|
|
|
|
int team = reader.ReadByte();
|
2016-12-03 18:23:47 +09:00
|
|
|
if (team < 0 || team > 2)
|
2013-08-18 16:18:06 +09:00
|
|
|
SPRaise("Received invalid team: %d", team);
|
|
|
|
p->SetTeam(team);
|
|
|
|
}
|
2016-12-03 18:23:47 +09:00
|
|
|
case PacketTypeChangeWeapon: {
|
2014-04-20 13:00:05 +02:00
|
|
|
reader.ReadByte();
|
2013-08-18 16:18:06 +09:00
|
|
|
WeaponType wType;
|
|
|
|
int weapon = reader.ReadByte();
|
2016-12-03 18:23:47 +09:00
|
|
|
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...
|
2016-12-03 18:23:47 +09:00
|
|
|
// p->SetWeaponType(wType);
|
|
|
|
} 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
|
|
|
|
2017-02-11 16:24:53 +09:00
|
|
|
void NetClient::SendVersionEnhanced(const std::set<std::uint8_t> &propertyIds) {
|
|
|
|
NetPacketWriter wri(PacketTypeExistingPlayer);
|
|
|
|
wri.Write((uint8_t)'x');
|
|
|
|
|
|
|
|
for (std::uint8_t propertyId : propertyIds) {
|
|
|
|
wri.Write(propertyId);
|
|
|
|
|
|
|
|
auto lengthLabel = wri.GetPosition();
|
|
|
|
wri.Write((uint8_t)0); // dummy data for "Payload Length"
|
|
|
|
|
|
|
|
auto beginLabel = wri.GetPosition();
|
|
|
|
switch (static_cast<VersionInfoPropertyId>(propertyId)) {
|
|
|
|
case VersionInfoPropertyId::ApplicationNameAndVersion:
|
|
|
|
wri.Write((uint8_t)OpenSpades_VERSION_MAJOR);
|
|
|
|
wri.Write((uint8_t)OpenSpades_VERSION_MINOR);
|
|
|
|
wri.Write((uint8_t)OpenSpades_VERSION_REVISION);
|
|
|
|
wri.Write("OpenSpades");
|
|
|
|
break;
|
|
|
|
case VersionInfoPropertyId::UserLocale:
|
|
|
|
wri.Write(GetCurrentLocaleAndRegion());
|
|
|
|
break;
|
|
|
|
case VersionInfoPropertyId::ClientFeatureFlags1: {
|
|
|
|
auto flags = ClientFeatureFlags1::None;
|
|
|
|
|
|
|
|
if (cg_unicode) {
|
|
|
|
flags |= ClientFeatureFlags1::SupportsUnicode;
|
|
|
|
}
|
|
|
|
|
|
|
|
wri.Write(static_cast<uint32_t>(flags));
|
|
|
|
} break;
|
|
|
|
default:
|
|
|
|
// Just return empty payload for an unrecognized property
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
wri.Update(lengthLabel, (uint8_t)(wri.GetPosition() - beginLabel));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-03 18:23:47 +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;
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
void NetClient::SendPosition() {
|
2013-08-18 16:18:06 +09:00
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
NetPacketWriter wri(PacketTypePositionData);
|
2016-12-03 18:23:47 +09:00
|
|
|
// 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());
|
2016-12-03 18:23:47 +09:00
|
|
|
// 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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
void NetClient::SendOrientation(spades::Vector3 v) {
|
2013-08-18 16:18:06 +09:00
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
NetPacketWriter wri(PacketTypeOrientationData);
|
2016-12-03 18:23:47 +09:00
|
|
|
// 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());
|
2016-12-03 18:23:47 +09:00
|
|
|
// 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-11-03 17:13:49 +01:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
uint8_t bits = 0;
|
2016-12-03 18:23:47 +09:00
|
|
|
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)
|
2013-08-31 12:53:44 +09:00
|
|
|
return;
|
|
|
|
lastPlayerInput = bits;
|
2013-11-03 17:13:49 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
void NetClient::SendWeaponInput(WeaponInput inp) {
|
2013-08-18 16:18:06 +09:00
|
|
|
SPADES_MARK_FUNCTION();
|
|
|
|
uint8_t bits = 0;
|
2016-12-03 18:23:47 +09:00
|
|
|
if (inp.primary)
|
|
|
|
bits |= 1 << 0;
|
|
|
|
if (inp.secondary)
|
|
|
|
bits |= 1 << 1;
|
2013-11-03 17:13:49 +01:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
if ((unsigned int)bits == lastWeaponInput)
|
2013-08-31 12:53:44 +09:00
|
|
|
return;
|
|
|
|
lastWeaponInput = bits;
|
2013-11-03 17:13:49 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2013-08-31 02:50:51 +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
|
|
|
|
2016-12-03 18:23:47 +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());
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +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
|
|
|
|
2016-12-03 18:23:47 +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());
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
|
2016-12-03 18:23:47 +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());
|
2016-12-03 18:23:47 +09:00
|
|
|
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();
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2019-05-19 16:25:39 +09:00
|
|
|
SPAssert(mapLoader);
|
|
|
|
|
|
|
|
// Move `mapLoader` to a local variable so that the associated resources
|
|
|
|
// are released as soon as possible when no longer needed
|
|
|
|
std::unique_ptr<GameMapLoader> mapLoader = std::move(this->mapLoader);
|
|
|
|
|
|
|
|
SPLog("Waiting for the game map decoding to complete...");
|
|
|
|
mapLoader->MarkEOF();
|
|
|
|
mapLoader->WaitComplete();
|
|
|
|
GameMap *map = mapLoader->TakeGameMap();
|
|
|
|
SPLog("The game map was decoded successfully.");
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2013-08-18 16:18:06 +09:00
|
|
|
// now initialize world
|
2017-09-11 20:59:39 +09:00
|
|
|
World *w = new World(properties);
|
2013-08-18 16:18:06 +09:00
|
|
|
w->SetMap(map);
|
2013-09-14 12:06:11 +09:00
|
|
|
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
|
|
|
SPAssert(GetWorld());
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
SPLog("World loaded. Processing saved packets (%d)...", (int)savedPackets.size());
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2016-12-03 18:23:47 +09:00
|
|
|
for (size_t i = 0; i < playerPosRecords.size(); i++)
|
2013-09-03 01:23:28 +09:00
|
|
|
playerPosRecords[i].valid = false;
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
2016-12-03 18:23:47 +09:00
|
|
|
try {
|
|
|
|
for (size_t i = 0; i < savedPackets.size(); i++) {
|
2013-08-18 16:18:06 +09:00
|
|
|
NetPacketReader r(savedPackets[i]);
|
2017-12-29 20:46:35 +09:00
|
|
|
HandleGamePacket(r);
|
2013-08-18 16:18:06 +09:00
|
|
|
}
|
|
|
|
savedPackets.clear();
|
2013-08-26 01:27:44 +09:00
|
|
|
SPLog("Done.");
|
2016-12-03 18:23:47 +09:00
|
|
|
} catch (...) {
|
2013-08-18 16:18:06 +09:00
|
|
|
savedPackets.clear();
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
2016-11-20 19:13:00 +09:00
|
|
|
|
2019-05-19 16:25:39 +09:00
|
|
|
float NetClient::GetMapReceivingProgress() {
|
|
|
|
SPAssert(status == NetClientStatusReceivingMap);
|
|
|
|
|
|
|
|
return mapLoader->GetProgress();
|
|
|
|
}
|
|
|
|
|
2016-12-03 18:23:47 +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() {
|
2016-12-03 18:23:47 +09:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|