support for protocol 810
* change in protocol/network classes to make compatible with older protocols * use filestream for reading dat * add many ifdefs for multi-protocol support
This commit is contained in:
parent
e1fad92110
commit
5a47e9d8a9
1
BUGS
1
BUGS
|
@ -4,6 +4,7 @@ modules recursivity makes client crash, it should generate a warning
|
||||||
== P1 BUGS (affects game play)
|
== P1 BUGS (affects game play)
|
||||||
sometimes minimap desync Z pos
|
sometimes minimap desync Z pos
|
||||||
follow and autowalk doesn't cancel when walking via hotkeys
|
follow and autowalk doesn't cancel when walking via hotkeys
|
||||||
|
when reading invalid spr/dat the client crashs
|
||||||
|
|
||||||
when walking on a tile with too many creatures, the following errors occurrs:
|
when walking on a tile with too many creatures, the following errors occurrs:
|
||||||
ERROR: [ProtocolGame::parseCreatureHealth] could not get greature
|
ERROR: [ProtocolGame::parseCreatureHealth] could not get greature
|
||||||
|
|
1
TODO
1
TODO
|
@ -44,6 +44,7 @@ multisample option in map view
|
||||||
move rendering of creatures names, skulls, etc to UI and scripts
|
move rendering of creatures names, skulls, etc to UI and scripts
|
||||||
clean sprites cache periodically
|
clean sprites cache periodically
|
||||||
handle corrupt errors in dat/spr
|
handle corrupt errors in dat/spr
|
||||||
|
throw exceptions when fail to read a file
|
||||||
|
|
||||||
* framework
|
* framework
|
||||||
rework Settings/g_configs
|
rework Settings/g_configs
|
||||||
|
|
|
@ -29,8 +29,28 @@ InputMessage::InputMessage()
|
||||||
|
|
||||||
void InputMessage::reset()
|
void InputMessage::reset()
|
||||||
{
|
{
|
||||||
m_readPos = 0;
|
m_messageSize = 0;
|
||||||
m_messageSize = 2;
|
m_readPos = MAX_HEADER_SIZE;
|
||||||
|
m_headerPos = MAX_HEADER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputMessage::setHeaderSize(uint16 size)
|
||||||
|
{
|
||||||
|
m_headerPos = MAX_HEADER_SIZE - size;
|
||||||
|
m_readPos = m_headerPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputMessage::fillBuffer(uint8 *buffer, uint16 size)
|
||||||
|
{
|
||||||
|
memcpy(m_buffer + m_readPos, buffer, size);
|
||||||
|
m_messageSize += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InputMessage::readChecksum()
|
||||||
|
{
|
||||||
|
uint32_t receivedCheck = getU32();
|
||||||
|
uint32 checksum = Fw::getAdlerChecksum(m_buffer + m_readPos, getUnreadSize());
|
||||||
|
return receivedCheck == checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 InputMessage::getU8(bool peek)
|
uint8 InputMessage::getU8(bool peek)
|
||||||
|
@ -88,7 +108,7 @@ std::string InputMessage::getString()
|
||||||
|
|
||||||
bool InputMessage::canRead(int bytes)
|
bool InputMessage::canRead(int bytes)
|
||||||
{
|
{
|
||||||
if((m_readPos + bytes > m_messageSize) || (m_readPos + bytes > BUFFER_MAXSIZE))
|
if((m_readPos - m_headerPos + bytes > m_messageSize) || (m_readPos + bytes > BUFFER_MAXSIZE))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,34 +31,43 @@ class InputMessage
|
||||||
public:
|
public:
|
||||||
enum {
|
enum {
|
||||||
BUFFER_MAXSIZE = 16384,
|
BUFFER_MAXSIZE = 16384,
|
||||||
HEADER_POS = 0,
|
MAX_HEADER_SIZE = 8,
|
||||||
HEADER_LENGTH = 2,
|
|
||||||
CHECKSUM_POS = 2,
|
|
||||||
CHECKSUM_LENGTH = 4,
|
|
||||||
DATA_POS = 6,
|
|
||||||
UNENCRYPTED_DATA_POS = 8
|
|
||||||
};
|
};
|
||||||
|
|
||||||
InputMessage();
|
InputMessage();
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
void fillBuffer(uint8 *buffer, uint16 size);
|
||||||
|
uint16 readSize() { return getU16(); }
|
||||||
|
bool readChecksum();
|
||||||
|
|
||||||
|
void setHeaderSize(uint16 size);
|
||||||
|
void setMessageSize(uint16 size) { m_messageSize = size; }
|
||||||
|
|
||||||
|
void skipBytes(uint16 bytes) { m_readPos += bytes; }
|
||||||
|
|
||||||
uint8 getU8(bool peek = false);
|
uint8 getU8(bool peek = false);
|
||||||
uint16 getU16(bool peek = false);
|
uint16 getU16(bool peek = false);
|
||||||
uint32 getU32(bool peek = false);
|
uint32 getU32(bool peek = false);
|
||||||
uint64 getU64(bool peek = false);
|
uint64 getU64(bool peek = false);
|
||||||
std::string getString();
|
std::string getString();
|
||||||
|
|
||||||
void skipBytes(uint16 bytes) { m_readPos += bytes; }
|
uint8* getReadBuffer() { return m_buffer + m_readPos; }
|
||||||
uint8* getBuffer() { return m_buffer; }
|
uint8* getHeaderBuffer() { return m_buffer + m_headerPos; }
|
||||||
|
uint8* getDataBuffer() { return m_buffer + MAX_HEADER_SIZE; }
|
||||||
|
uint16 getHeaderSize() { return (MAX_HEADER_SIZE - m_headerPos); }
|
||||||
uint16 getMessageSize() { return m_messageSize; }
|
uint16 getMessageSize() { return m_messageSize; }
|
||||||
void setMessageSize(uint16 messageSize) { m_messageSize = messageSize; }
|
int getReadSize() { return m_readPos - m_headerPos; }
|
||||||
bool eof() { return m_readPos >= m_messageSize; }
|
int getUnreadSize() { return m_messageSize - (m_readPos - m_headerPos); }
|
||||||
|
|
||||||
|
bool eof() { return (m_readPos - m_headerPos) >= m_messageSize; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool canRead(int bytes);
|
bool canRead(int bytes);
|
||||||
void checkRead(int bytes);
|
void checkRead(int bytes);
|
||||||
|
|
||||||
|
uint16 m_headerPos;
|
||||||
uint16 m_readPos;
|
uint16 m_readPos;
|
||||||
uint16 m_messageSize;
|
uint16 m_messageSize;
|
||||||
uint8 m_buffer[BUFFER_MAXSIZE];
|
uint8 m_buffer[BUFFER_MAXSIZE];
|
||||||
|
|
|
@ -29,7 +29,8 @@ OutputMessage::OutputMessage()
|
||||||
|
|
||||||
void OutputMessage::reset()
|
void OutputMessage::reset()
|
||||||
{
|
{
|
||||||
m_writePos = DATA_POS;
|
m_writePos = MAX_HEADER_SIZE;
|
||||||
|
m_headerPos = MAX_HEADER_SIZE;
|
||||||
m_messageSize = 0;
|
m_messageSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +92,23 @@ void OutputMessage::addPaddingBytes(int bytes, uint8 byte)
|
||||||
m_messageSize += bytes;
|
m_messageSize += bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OutputMessage::writeChecksum()
|
||||||
|
{
|
||||||
|
uint32 checksum = Fw::getAdlerChecksum(m_buffer + m_headerPos, m_messageSize);
|
||||||
|
assert(m_headerPos - 4 >= 0);
|
||||||
|
m_headerPos -= 4;
|
||||||
|
Fw::writeLE32(m_buffer + m_headerPos, checksum);
|
||||||
|
m_messageSize += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputMessage::writeMessageSize()
|
||||||
|
{
|
||||||
|
assert(m_headerPos - 2 >= 0);
|
||||||
|
m_headerPos -= 2;
|
||||||
|
Fw::writeLE16(m_buffer + m_headerPos, m_messageSize);
|
||||||
|
m_messageSize += 2;
|
||||||
|
}
|
||||||
|
|
||||||
bool OutputMessage::canWrite(int bytes)
|
bool OutputMessage::canWrite(int bytes)
|
||||||
{
|
{
|
||||||
if(m_writePos + bytes > BUFFER_MAXSIZE)
|
if(m_writePos + bytes > BUFFER_MAXSIZE)
|
||||||
|
|
|
@ -34,11 +34,7 @@ class OutputMessage : public LuaObject
|
||||||
public:
|
public:
|
||||||
enum {
|
enum {
|
||||||
BUFFER_MAXSIZE = 1024,
|
BUFFER_MAXSIZE = 1024,
|
||||||
HEADER_POS = 0,
|
MAX_HEADER_SIZE = 8
|
||||||
HEADER_LENGTH = 2,
|
|
||||||
CHECKSUM_POS = 2,
|
|
||||||
CHECKSUM_LENGTH = 4,
|
|
||||||
DATA_POS = 6
|
|
||||||
};
|
};
|
||||||
|
|
||||||
OutputMessage();
|
OutputMessage();
|
||||||
|
@ -53,15 +49,19 @@ public:
|
||||||
void addString(const std::string& value);
|
void addString(const std::string& value);
|
||||||
void addPaddingBytes(int bytes, uint8 byte = 0);
|
void addPaddingBytes(int bytes, uint8 byte = 0);
|
||||||
|
|
||||||
uint8* getBuffer() { return m_buffer; }
|
uint8* getWriteBuffer() { return m_buffer + m_writePos; }
|
||||||
|
uint8* getHeaderBuffer() { return m_buffer + m_headerPos; }
|
||||||
|
uint8* getDataBuffer() { return m_buffer + MAX_HEADER_SIZE; }
|
||||||
uint16 getMessageSize() { return m_messageSize; }
|
uint16 getMessageSize() { return m_messageSize; }
|
||||||
void setMessageSize(uint16 messageSize) { m_messageSize = messageSize; }
|
|
||||||
void setWritePos(uint16 writePos) { m_writePos = writePos; }
|
void writeChecksum();
|
||||||
|
void writeMessageSize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool canWrite(int bytes);
|
bool canWrite(int bytes);
|
||||||
void checkWrite(int bytes);
|
void checkWrite(int bytes);
|
||||||
|
|
||||||
|
uint16 m_headerPos;
|
||||||
uint16 m_writePos;
|
uint16 m_writePos;
|
||||||
uint16 m_messageSize;
|
uint16 m_messageSize;
|
||||||
uint8 m_buffer[BUFFER_MAXSIZE];
|
uint8 m_buffer[BUFFER_MAXSIZE];
|
||||||
|
|
|
@ -69,40 +69,44 @@ void Protocol::send(OutputMessage& outputMessage)
|
||||||
if(m_xteaEncryptionEnabled)
|
if(m_xteaEncryptionEnabled)
|
||||||
xteaEncrypt(outputMessage);
|
xteaEncrypt(outputMessage);
|
||||||
|
|
||||||
// set checksum
|
// write checksum
|
||||||
uint32 checksum = getAdlerChecksum(outputMessage.getBuffer() + OutputMessage::DATA_POS, outputMessage.getMessageSize());
|
if(m_checksumEnabled)
|
||||||
outputMessage.setWritePos(OutputMessage::CHECKSUM_POS);
|
outputMessage.writeChecksum();
|
||||||
outputMessage.addU32(checksum);
|
|
||||||
|
|
||||||
// set size
|
// wirte message size
|
||||||
uint16 messageSize = outputMessage.getMessageSize();
|
outputMessage.writeMessageSize();
|
||||||
outputMessage.setWritePos(OutputMessage::HEADER_POS);
|
|
||||||
outputMessage.addU16(messageSize);
|
|
||||||
|
|
||||||
// send
|
// send
|
||||||
if(m_connection)
|
if(m_connection)
|
||||||
m_connection->write(outputMessage.getBuffer(), outputMessage.getMessageSize());
|
m_connection->write(outputMessage.getHeaderBuffer(), outputMessage.getMessageSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Protocol::recv()
|
void Protocol::recv()
|
||||||
{
|
{
|
||||||
m_inputMessage.reset();
|
m_inputMessage.reset();
|
||||||
|
|
||||||
|
// first update message header size
|
||||||
|
int headerSize = 2; // 2 bytes for message size
|
||||||
|
if(m_checksumEnabled)
|
||||||
|
headerSize += 4; // 4 bytes for checksum
|
||||||
|
if(m_xteaEncryptionEnabled)
|
||||||
|
headerSize += 2; // 2 bytes for XTEA encrypted message size
|
||||||
|
m_inputMessage.setHeaderSize(headerSize);
|
||||||
|
|
||||||
|
// read the first 2 bytes which contain the message size
|
||||||
if(m_connection)
|
if(m_connection)
|
||||||
m_connection->read(InputMessage::HEADER_LENGTH, std::bind(&Protocol::internalRecvHeader, asProtocol(), std::placeholders::_1, std::placeholders::_2));
|
m_connection->read(2, std::bind(&Protocol::internalRecvHeader, asProtocol(), std::placeholders::_1, std::placeholders::_2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Protocol::internalRecvHeader(uint8* buffer, uint16 size)
|
void Protocol::internalRecvHeader(uint8* buffer, uint16 size)
|
||||||
{
|
{
|
||||||
memcpy(m_inputMessage.getBuffer() + InputMessage::HEADER_POS, buffer, size);
|
|
||||||
|
|
||||||
// read message size
|
// read message size
|
||||||
uint16 dataSize = m_inputMessage.getU16();
|
m_inputMessage.fillBuffer(buffer, size);
|
||||||
m_inputMessage.setMessageSize(dataSize);
|
uint16 remainingSize = m_inputMessage.readSize();
|
||||||
|
|
||||||
// schedule read for message data
|
// read remaining message data
|
||||||
if(m_connection)
|
if(m_connection)
|
||||||
m_connection->read(dataSize, std::bind(&Protocol::internalRecvData, asProtocol(), std::placeholders::_1, std::placeholders::_2));
|
m_connection->read(remainingSize, std::bind(&Protocol::internalRecvData, asProtocol(), std::placeholders::_1, std::placeholders::_2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Protocol::internalRecvData(uint8* buffer, uint16 size)
|
void Protocol::internalRecvData(uint8* buffer, uint16 size)
|
||||||
|
@ -113,18 +117,15 @@ void Protocol::internalRecvData(uint8* buffer, uint16 size)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(m_inputMessage.getBuffer() + InputMessage::CHECKSUM_POS, buffer, size);
|
m_inputMessage.fillBuffer(buffer, size);
|
||||||
|
|
||||||
if(m_checksumEnabled) {
|
if(m_checksumEnabled && !m_inputMessage.readChecksum()) {
|
||||||
uint32 checksum = getAdlerChecksum(m_inputMessage.getBuffer() + InputMessage::DATA_POS, m_inputMessage.getMessageSize() - InputMessage::CHECKSUM_LENGTH);
|
|
||||||
if(m_inputMessage.getU32() != checksum) {
|
|
||||||
logTraceError("got a network message with invalid checksum");
|
logTraceError("got a network message with invalid checksum");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(m_xteaEncryptionEnabled) {
|
if(m_xteaEncryptionEnabled && !xteaDecrypt(m_inputMessage)) {
|
||||||
if(!xteaDecrypt(m_inputMessage))
|
logTraceError("failed to decrypt message");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,16 +144,16 @@ void Protocol::generateXteaKey()
|
||||||
|
|
||||||
bool Protocol::xteaDecrypt(InputMessage& inputMessage)
|
bool Protocol::xteaDecrypt(InputMessage& inputMessage)
|
||||||
{
|
{
|
||||||
uint16 messageSize = inputMessage.getMessageSize() - InputMessage::CHECKSUM_LENGTH;
|
uint16 encryptedSize = inputMessage.getUnreadSize();
|
||||||
if(messageSize % 8 != 0) {
|
if(encryptedSize % 8 != 0) {
|
||||||
logTraceError("invalid encrypted network message");
|
logTraceError("invalid encrypted network message");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 *buffer = (uint32*)(inputMessage.getBuffer() + InputMessage::DATA_POS);
|
uint32 *buffer = (uint32*)(inputMessage.getReadBuffer());
|
||||||
int readPos = 0;
|
int readPos = 0;
|
||||||
|
|
||||||
while(readPos < messageSize/4) {
|
while(readPos < encryptedSize/4) {
|
||||||
uint32 v0 = buffer[readPos], v1 = buffer[readPos + 1];
|
uint32 v0 = buffer[readPos], v1 = buffer[readPos + 1];
|
||||||
uint32 delta = 0x61C88647;
|
uint32 delta = 0x61C88647;
|
||||||
uint32 sum = 0xC6EF3720;
|
uint32 sum = 0xC6EF3720;
|
||||||
|
@ -166,37 +167,32 @@ bool Protocol::xteaDecrypt(InputMessage& inputMessage)
|
||||||
readPos = readPos + 2;
|
readPos = readPos + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tmp = inputMessage.getU16();
|
uint16 decryptedSize = inputMessage.getU16() + 2;
|
||||||
if(tmp > inputMessage.getMessageSize() - 4) {
|
int sizeDelta = decryptedSize - encryptedSize;
|
||||||
|
if(sizeDelta > 0 || -sizeDelta > encryptedSize) {
|
||||||
logTraceError("invalid decrypted a network message");
|
logTraceError("invalid decrypted a network message");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inputMessage.setMessageSize(tmp + InputMessage::UNENCRYPTED_DATA_POS);
|
inputMessage.setMessageSize(inputMessage.getMessageSize() + sizeDelta);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Protocol::xteaEncrypt(OutputMessage& outputMessage)
|
void Protocol::xteaEncrypt(OutputMessage& outputMessage)
|
||||||
{
|
{
|
||||||
uint16 messageLength = outputMessage.getMessageSize();
|
outputMessage.writeMessageSize();
|
||||||
|
uint16 encryptedSize = outputMessage.getMessageSize();
|
||||||
memmove(outputMessage.getBuffer() + OutputMessage::DATA_POS + 2, outputMessage.getBuffer() + OutputMessage::DATA_POS, messageLength);
|
|
||||||
*(uint16*)(outputMessage.getBuffer() + OutputMessage::DATA_POS) = messageLength;
|
|
||||||
|
|
||||||
messageLength += 2;
|
|
||||||
outputMessage.setMessageSize(messageLength);
|
|
||||||
outputMessage.setWritePos(messageLength + OutputMessage::DATA_POS);
|
|
||||||
|
|
||||||
//add bytes until reach 8 multiple
|
//add bytes until reach 8 multiple
|
||||||
if((messageLength % 8) != 0) {
|
if((encryptedSize % 8) != 0) {
|
||||||
uint16 n = 8 - (messageLength % 8);
|
uint16 n = 8 - (encryptedSize % 8);
|
||||||
outputMessage.addPaddingBytes(n);
|
outputMessage.addPaddingBytes(n);
|
||||||
messageLength += n;
|
encryptedSize += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int readPos = 0;
|
int readPos = 0;
|
||||||
uint32 *buffer = (uint32*)(outputMessage.getBuffer() + OutputMessage::DATA_POS);
|
uint32 *buffer = (uint32*)(outputMessage.getDataBuffer() - 2);
|
||||||
while(readPos < messageLength / 4) {
|
while(readPos < encryptedSize / 4) {
|
||||||
uint32 v0 = buffer[readPos], v1 = buffer[readPos + 1];
|
uint32 v0 = buffer[readPos], v1 = buffer[readPos + 1];
|
||||||
uint32 delta = 0x61C88647;
|
uint32 delta = 0x61C88647;
|
||||||
uint32 sum = 0;
|
uint32 sum = 0;
|
||||||
|
@ -210,21 +206,3 @@ void Protocol::xteaEncrypt(OutputMessage& outputMessage)
|
||||||
readPos = readPos + 2;
|
readPos = readPos + 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Protocol::getAdlerChecksum(uint8* buffer, uint16 size)
|
|
||||||
{
|
|
||||||
uint32 a = 1, b = 0;
|
|
||||||
while (size > 0) {
|
|
||||||
size_t tlen = size > 5552 ? 5552 : size;
|
|
||||||
size -= tlen;
|
|
||||||
do {
|
|
||||||
a += *buffer++;
|
|
||||||
b += a;
|
|
||||||
} while (--tlen);
|
|
||||||
|
|
||||||
a %= 65521;
|
|
||||||
b %= 65521;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (b << 16) | a;
|
|
||||||
}
|
|
||||||
|
|
|
@ -64,7 +64,6 @@ protected:
|
||||||
private:
|
private:
|
||||||
bool xteaDecrypt(InputMessage& inputMessage);
|
bool xteaDecrypt(InputMessage& inputMessage);
|
||||||
void xteaEncrypt(OutputMessage& outputMessage);
|
void xteaEncrypt(OutputMessage& outputMessage);
|
||||||
uint32 getAdlerChecksum(uint8* buffer, uint16 size);
|
|
||||||
|
|
||||||
bool m_checksumEnabled;
|
bool m_checksumEnabled;
|
||||||
bool m_xteaEncryptionEnabled;
|
bool m_xteaEncryptionEnabled;
|
||||||
|
|
|
@ -326,6 +326,22 @@ inline float randomRange<float>(float min, float max) {
|
||||||
return min + (max - min)*dis(gen);
|
return min + (max - min)*dis(gen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline uint32 getAdlerChecksum(uint8* buffer, uint16 size) {
|
||||||
|
register uint32 a = 1, b = 0, tlen;
|
||||||
|
while(size > 0) {
|
||||||
|
tlen = size > 5552 ? 5552 : size;
|
||||||
|
size -= tlen;
|
||||||
|
do {
|
||||||
|
a += *buffer++;
|
||||||
|
b += a;
|
||||||
|
} while (--tlen);
|
||||||
|
|
||||||
|
a %= 65521;
|
||||||
|
b %= 65521;
|
||||||
|
}
|
||||||
|
return (b << 16) | a;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// shortcut for Fw::dump
|
// shortcut for Fw::dump
|
||||||
|
|
|
@ -269,16 +269,22 @@ CreaturePtr Map::getCreatureById(uint32 id)
|
||||||
LocalPlayerPtr localPlayer = g_game.getLocalPlayer();
|
LocalPlayerPtr localPlayer = g_game.getLocalPlayer();
|
||||||
if(localPlayer && localPlayer->getId() == id)
|
if(localPlayer && localPlayer->getId() == id)
|
||||||
return localPlayer;
|
return localPlayer;
|
||||||
return m_knownCreatures[id];
|
auto it = m_knownCreatures.find(id);
|
||||||
|
if(it == m_knownCreatures.end())
|
||||||
|
return nullptr;
|
||||||
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::removeCreatureById(uint32 id)
|
void Map::removeCreatureById(uint32 id)
|
||||||
{
|
{
|
||||||
if(id == 0)
|
if(id == 0)
|
||||||
return;
|
return;
|
||||||
if(CreaturePtr creature = m_knownCreatures[id])
|
|
||||||
creature->setRemoved(true);
|
auto it = m_knownCreatures.find(id);
|
||||||
m_knownCreatures.erase(id);
|
if(it != m_knownCreatures.end())
|
||||||
|
it->second->setRemoved(true);
|
||||||
|
|
||||||
|
m_knownCreatures.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::setCentralPosition(const Position& centralPosition)
|
void Map::setCentralPosition(const Position& centralPosition)
|
||||||
|
@ -288,14 +294,9 @@ void Map::setCentralPosition(const Position& centralPosition)
|
||||||
// remove creatures from tiles that we are not aware anymore
|
// remove creatures from tiles that we are not aware anymore
|
||||||
for(const auto& pair : m_knownCreatures) {
|
for(const auto& pair : m_knownCreatures) {
|
||||||
const CreaturePtr& creature = pair.second;
|
const CreaturePtr& creature = pair.second;
|
||||||
if(creature) {
|
if(!isAwareOfPosition(creature->getPosition()))
|
||||||
if(!isAwareOfPosition(creature->getPosition())) {
|
|
||||||
removeThing(creature);
|
removeThing(creature);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
logTraceError("invalid creature");
|
|
||||||
}
|
|
||||||
|
|
||||||
// this fixes local player position when the local player is removed from the map,
|
// this fixes local player position when the local player is removed from the map,
|
||||||
// the local player is removed from the map when there are too many creatures on his tile,
|
// the local player is removed from the map when there are too many creatures on his tile,
|
||||||
|
|
|
@ -24,21 +24,24 @@
|
||||||
#include "spritemanager.h"
|
#include "spritemanager.h"
|
||||||
#include "thing.h"
|
#include "thing.h"
|
||||||
#include <framework/core/resourcemanager.h>
|
#include <framework/core/resourcemanager.h>
|
||||||
|
#include <framework/core/filestream.h>
|
||||||
|
|
||||||
ThingsType g_thingsType;
|
ThingsType g_thingsType;
|
||||||
ThingType ThingsType::m_emptyThingType;
|
ThingType ThingsType::m_emptyThingType;
|
||||||
|
|
||||||
bool ThingsType::load(const std::string& file)
|
bool ThingsType::load(const std::string& file)
|
||||||
{
|
{
|
||||||
try {
|
FileStreamPtr fin = g_resources.openFile(file);
|
||||||
std::stringstream fin;
|
if(!fin) {
|
||||||
g_resources.loadFile(file, fin);
|
logError("unable to open dat file '", file, "'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
m_signature = Fw::getU32(fin);
|
m_signature = fin->getU32();
|
||||||
|
|
||||||
int numThings[LastCategory];
|
int numThings[LastCategory];
|
||||||
for(int i = 0; i < LastCategory; ++i)
|
for(int i = 0; i < LastCategory; ++i)
|
||||||
numThings[i] = Fw::getU16(fin);
|
numThings[i] = fin->getU16();
|
||||||
|
|
||||||
numThings[Item] -= 99;
|
numThings[Item] -= 99;
|
||||||
|
|
||||||
|
@ -50,10 +53,6 @@ bool ThingsType::load(const std::string& file)
|
||||||
|
|
||||||
m_loaded = true;
|
m_loaded = true;
|
||||||
return true;
|
return true;
|
||||||
} catch(Exception& e) {
|
|
||||||
logError("Failed to load dat from '", file, "': ", e.what());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThingsType::unload()
|
void ThingsType::unload()
|
||||||
|
@ -62,37 +61,39 @@ void ThingsType::unload()
|
||||||
m_things[i].clear();
|
m_things[i].clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThingsType::parseThingType(std::stringstream& fin, ThingType& thingType)
|
void ThingsType::parseThingType(const FileStreamPtr& fin, ThingType& thingType)
|
||||||
{
|
{
|
||||||
assert(fin.good());
|
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
int property = Fw::getU8(fin);
|
int property = fin->getU8();
|
||||||
if(property == ThingType::LastPropertyValue)
|
if(property == ThingType::LastPropertyValue)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
thingType.m_properties[property] = true;
|
thingType.m_properties[property] = true;
|
||||||
|
|
||||||
if(property == ThingType::IsGround)
|
if(property == ThingType::IsGround)
|
||||||
thingType.m_parameters[ThingType::GroundSpeed] = Fw::getU16(fin);
|
thingType.m_parameters[ThingType::GroundSpeed] = fin->getU16();
|
||||||
else if(property == ThingType::IsWritable || property == ThingType::IsWritableOnce)
|
else if(property == ThingType::IsWritable || property == ThingType::IsWritableOnce)
|
||||||
thingType.m_parameters[ThingType::MaxTextLenght] = Fw::getU16(fin);
|
thingType.m_parameters[ThingType::MaxTextLenght] = fin->getU16();
|
||||||
else if(property == ThingType::HasLight) {
|
else if(property == ThingType::HasLight) {
|
||||||
thingType.m_parameters[ThingType::LightLevel] = Fw::getU16(fin);
|
thingType.m_parameters[ThingType::LightLevel] = fin->getU16();
|
||||||
thingType.m_parameters[ThingType::LightColor] = Fw::getU16(fin);
|
thingType.m_parameters[ThingType::LightColor] = fin->getU16();
|
||||||
}
|
}
|
||||||
else if(property == ThingType::HasDisplacement) {
|
else if(property == ThingType::HasDisplacement) {
|
||||||
thingType.m_parameters[ThingType::DisplacementX] = Fw::getU16(fin);
|
thingType.m_parameters[ThingType::DisplacementX] = fin->getU16();
|
||||||
thingType.m_parameters[ThingType::DisplacementY] = Fw::getU16(fin);
|
thingType.m_parameters[ThingType::DisplacementY] = fin->getU16();
|
||||||
}
|
}
|
||||||
else if(property == ThingType::HasElevation)
|
else if(property == ThingType::HasElevation)
|
||||||
thingType.m_parameters[ThingType::Elevation] = Fw::getU16(fin);
|
thingType.m_parameters[ThingType::Elevation] = fin->getU16();
|
||||||
else if(property == ThingType::MiniMap)
|
else if(property == ThingType::MiniMap)
|
||||||
thingType.m_parameters[ThingType::MiniMapColor] = Fw::getU16(fin);
|
thingType.m_parameters[ThingType::MiniMapColor] = fin->getU16();
|
||||||
else if(property == ThingType::LensHelp)
|
else if(property == ThingType::LensHelp)
|
||||||
thingType.m_parameters[ThingType::LensHelpParameter] = Fw::getU16(fin);
|
thingType.m_parameters[ThingType::LensHelpParameter] = fin->getU16();
|
||||||
else if(property == ThingType::Cloth)
|
else if(property == ThingType::Cloth)
|
||||||
thingType.m_parameters[ThingType::ClothSlot] = Fw::getU16(fin);
|
thingType.m_parameters[ThingType::ClothSlot] = fin->getU16();
|
||||||
|
#if PROTOCOL<=810
|
||||||
|
else if(property == ThingType::IsRune)
|
||||||
|
thingType.m_properties[ThingType::IsStackable] = true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int totalSprites = 1;
|
int totalSprites = 1;
|
||||||
|
@ -102,7 +103,7 @@ void ThingsType::parseThingType(std::stringstream& fin, ThingType& thingType)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
thingType.m_dimensions[i] = Fw::getU8(fin);
|
thingType.m_dimensions[i] = fin->getU8();
|
||||||
|
|
||||||
if(i != ThingType::ExactSize)
|
if(i != ThingType::ExactSize)
|
||||||
totalSprites *= thingType.m_dimensions[i];
|
totalSprites *= thingType.m_dimensions[i];
|
||||||
|
@ -111,7 +112,7 @@ void ThingsType::parseThingType(std::stringstream& fin, ThingType& thingType)
|
||||||
thingType.m_spritesIndex.resize(totalSprites);
|
thingType.m_spritesIndex.resize(totalSprites);
|
||||||
thingType.m_sprites.resize(totalSprites);
|
thingType.m_sprites.resize(totalSprites);
|
||||||
for(int i = 0; i < totalSprites; i++)
|
for(int i = 0; i < totalSprites; i++)
|
||||||
thingType.m_spritesIndex[i] = Fw::getU16(fin);
|
thingType.m_spritesIndex[i] = fin->getU16();
|
||||||
}
|
}
|
||||||
|
|
||||||
ThingType *ThingsType::getThingType(uint16 id, Categories category)
|
ThingType *ThingsType::getThingType(uint16 id, Categories category)
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#define DATMANAGER_H
|
#define DATMANAGER_H
|
||||||
|
|
||||||
#include <framework/global.h>
|
#include <framework/global.h>
|
||||||
|
#include <framework/core/declarations.h>
|
||||||
#include "thingtype.h"
|
#include "thingtype.h"
|
||||||
|
|
||||||
class ThingsType
|
class ThingsType
|
||||||
|
@ -41,7 +42,7 @@ public:
|
||||||
bool load(const std::string& file);
|
bool load(const std::string& file);
|
||||||
void unload();
|
void unload();
|
||||||
|
|
||||||
void parseThingType(std::stringstream& fin, ThingType& thingType);
|
void parseThingType(const FileStreamPtr& fin, ThingType& thingType);
|
||||||
|
|
||||||
ThingType *getEmptyThingType() { return &m_emptyThingType; }
|
ThingType *getEmptyThingType() { return &m_emptyThingType; }
|
||||||
ThingType *getThingType(uint16 id, Categories category);
|
ThingType *getThingType(uint16 id, Categories category);
|
||||||
|
|
|
@ -50,6 +50,9 @@ struct ThingType
|
||||||
IsStackable,
|
IsStackable,
|
||||||
IsForceUse,
|
IsForceUse,
|
||||||
IsMultiUse,
|
IsMultiUse,
|
||||||
|
#if PROTOCOL<=810
|
||||||
|
IsRune,
|
||||||
|
#endif
|
||||||
IsWritable,
|
IsWritable,
|
||||||
IsWritableOnce,
|
IsWritableOnce,
|
||||||
IsFluidContainer,
|
IsFluidContainer,
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
#include <otclient/global.h>
|
#include <otclient/global.h>
|
||||||
|
|
||||||
#if PROTOCOL != 860 && PROTOCOL != 861 && PROTOCOL != 862 && PROTOCOL != 870
|
#if PROTOCOL != 860 && PROTOCOL != 861 && PROTOCOL != 862 && PROTOCOL != 870 && PROTOCOL != 810
|
||||||
#error "the supplied protocol version is not supported"
|
#error "the supplied protocol version is not supported"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -51,6 +51,8 @@ namespace Proto {
|
||||||
constexpr int NumViolationReasons = 19;
|
constexpr int NumViolationReasons = 19;
|
||||||
#elif PROTOCOL>=860
|
#elif PROTOCOL>=860
|
||||||
constexpr int NumViolationReasons = 20;
|
constexpr int NumViolationReasons = 20;
|
||||||
|
#elif PROTOCOL>=810
|
||||||
|
constexpr int NumViolationReasons = 32;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum OsTypes {
|
enum OsTypes {
|
||||||
|
@ -210,9 +212,7 @@ namespace Proto {
|
||||||
ClientRefreshContainer = 202,
|
ClientRefreshContainer = 202,
|
||||||
ClientRequestOutfit = 210,
|
ClientRequestOutfit = 210,
|
||||||
ClientChangeOutfit = 211,
|
ClientChangeOutfit = 211,
|
||||||
#if PROTOCOL>=870
|
ClientMount = 212, // 870
|
||||||
ClientMount = 212,
|
|
||||||
#endif
|
|
||||||
ClientAddVip = 220,
|
ClientAddVip = 220,
|
||||||
ClientRemoveVip = 221,
|
ClientRemoveVip = 221,
|
||||||
ClientBugReport = 230,
|
ClientBugReport = 230,
|
||||||
|
@ -242,7 +242,7 @@ namespace Proto {
|
||||||
ServerSpeakMonsterSay,
|
ServerSpeakMonsterSay,
|
||||||
ServerSpeakMonsterYell,
|
ServerSpeakMonsterYell,
|
||||||
|
|
||||||
// removed
|
// unsupported
|
||||||
ServerSpeakRVRChannel = 255,
|
ServerSpeakRVRChannel = 255,
|
||||||
ServerSpeakRVRAnswer,
|
ServerSpeakRVRAnswer,
|
||||||
ServerSpeakRVRContinue,
|
ServerSpeakRVRContinue,
|
||||||
|
@ -266,6 +266,29 @@ namespace Proto {
|
||||||
ServerSpeakChannelRed2 = 17,
|
ServerSpeakChannelRed2 = 17,
|
||||||
ServerSpeakMonsterSay = 19,
|
ServerSpeakMonsterSay = 19,
|
||||||
ServerSpeakMonsterYell
|
ServerSpeakMonsterYell
|
||||||
|
#elif PROTOCOL>=810
|
||||||
|
ServerSpeakSay = 1,
|
||||||
|
ServerSpeakWhisper,
|
||||||
|
ServerSpeakYell,
|
||||||
|
ServerSpeakPrivate,
|
||||||
|
ServerSpeakChannelYellow,
|
||||||
|
ServerSpeakRVRChannel,
|
||||||
|
ServerSpeakRVRAnswer,
|
||||||
|
ServerSpeakRVRContinue,
|
||||||
|
ServerSpeakBroadcast,
|
||||||
|
ServerSpeakChannelRed,
|
||||||
|
ServerSpeakPrivateRed,
|
||||||
|
ServerSpeakChannelOrange,
|
||||||
|
// 13 ??
|
||||||
|
ServerSpeakChannelRed2 = 14,
|
||||||
|
// 15 ??
|
||||||
|
ServerSpeakMonsterSay = 16,
|
||||||
|
ServerSpeakMonsterYell,
|
||||||
|
|
||||||
|
// unsupported
|
||||||
|
ServerSpeakPrivatePlayerToNpc = 255,
|
||||||
|
ServerSpeakPrivateNpcToPlayer,
|
||||||
|
ServerSpeakChannelWhite
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -289,9 +312,22 @@ namespace Proto {
|
||||||
MessageEventAdvance,
|
MessageEventAdvance,
|
||||||
MessageEventDefault,
|
MessageEventDefault,
|
||||||
MessageStatusDefault,
|
MessageStatusDefault,
|
||||||
MessageInfoDescription ,
|
MessageInfoDescription,
|
||||||
MessageStatusSmall,
|
MessageStatusSmall,
|
||||||
MessageConsoleBlue
|
MessageConsoleBlue
|
||||||
|
#elif PROTOCOL>=810
|
||||||
|
MessageWarning = 18,
|
||||||
|
MessageEventAdvance,
|
||||||
|
MessageEventDefault,
|
||||||
|
MessageStatusDefault,
|
||||||
|
MessageInfoDescription,
|
||||||
|
MessageStatusSmall,
|
||||||
|
MessageConsoleBlue,
|
||||||
|
MessageConsoleRed,
|
||||||
|
|
||||||
|
// unsupported
|
||||||
|
MessageConsoleOrange = 255,
|
||||||
|
MessageConsoleOrange2,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,6 @@ void ProtocolGame::login(const std::string& accountName, const std::string& acco
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_waitingLoginPacket = true;
|
|
||||||
m_accountName = accountName;
|
m_accountName = accountName;
|
||||||
m_accountPassword = accountPassword;
|
m_accountPassword = accountPassword;
|
||||||
m_characterName = characterName;
|
m_characterName = characterName;
|
||||||
|
@ -43,17 +42,26 @@ void ProtocolGame::login(const std::string& accountName, const std::string& acco
|
||||||
void ProtocolGame::onConnect()
|
void ProtocolGame::onConnect()
|
||||||
{
|
{
|
||||||
recv();
|
recv();
|
||||||
|
|
||||||
|
#if PROTOCOL>=860
|
||||||
|
m_waitingLoginPacket = true;
|
||||||
|
#else
|
||||||
|
sendLoginPacket(0, 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolGame::onRecv(InputMessage& inputMessage)
|
void ProtocolGame::onRecv(InputMessage& inputMessage)
|
||||||
{
|
{
|
||||||
|
// only for protocol >= 860
|
||||||
if(m_waitingLoginPacket) {
|
if(m_waitingLoginPacket) {
|
||||||
inputMessage.skipBytes(3);
|
inputMessage.skipBytes(3);
|
||||||
uint32 timestamp = inputMessage.getU32();
|
uint32 timestamp = inputMessage.getU32();
|
||||||
uint8 unknown = inputMessage.getU8();
|
uint8 unknown = inputMessage.getU8();
|
||||||
|
|
||||||
m_waitingLoginPacket = false;
|
m_waitingLoginPacket = false;
|
||||||
|
|
||||||
enableChecksum();
|
enableChecksum();
|
||||||
|
|
||||||
sendLoginPacket(timestamp, unknown);
|
sendLoginPacket(timestamp, unknown);
|
||||||
recv();
|
recv();
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,9 +35,12 @@
|
||||||
|
|
||||||
void ProtocolGame::parseMessage(InputMessage& msg)
|
void ProtocolGame::parseMessage(InputMessage& msg)
|
||||||
{
|
{
|
||||||
|
int opcode = 0;
|
||||||
|
int prevOpcode = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while(!msg.eof()) {
|
while(!msg.eof()) {
|
||||||
int opcode = msg.getU8();
|
opcode = msg.getU8();
|
||||||
|
|
||||||
switch(opcode) {
|
switch(opcode) {
|
||||||
case Proto::GameServerInitGame:
|
case Proto::GameServerInitGame:
|
||||||
|
@ -268,12 +271,13 @@ void ProtocolGame::parseMessage(InputMessage& msg)
|
||||||
parseExtendedOpcode(msg);
|
parseExtendedOpcode(msg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Fw::throwException("unknown opcode ", opcode);
|
Fw::throwException("unknown opcode ", opcode, ", previous opcode is ", prevOpcode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
prevOpcode = opcode;
|
||||||
}
|
}
|
||||||
} catch(Exception& e) {
|
} catch(Exception& e) {
|
||||||
logTraceError(e.what());
|
logError("Network exception (", msg.getUnreadSize(), " bytes unread, last opcode is ", opcode, ", prev opcode is ", prevOpcode, "): ", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,7 +396,11 @@ void ProtocolGame::parseUpdateTile(InputMessage& msg)
|
||||||
void ProtocolGame::parseTileAddThing(InputMessage& msg)
|
void ProtocolGame::parseTileAddThing(InputMessage& msg)
|
||||||
{
|
{
|
||||||
Position pos = parsePosition(msg);
|
Position pos = parsePosition(msg);
|
||||||
int stackPos = msg.getU8();
|
int stackPos = -1;
|
||||||
|
|
||||||
|
#if PROTOCOL>=860
|
||||||
|
stackPos = msg.getU8();
|
||||||
|
#endif
|
||||||
|
|
||||||
ThingPtr thing = internalGetThing(msg);
|
ThingPtr thing = internalGetThing(msg);
|
||||||
g_map.addThing(thing, pos, stackPos);
|
g_map.addThing(thing, pos, stackPos);
|
||||||
|
@ -754,8 +762,12 @@ void ProtocolGame::parsePlayerStats(InputMessage& msg)
|
||||||
{
|
{
|
||||||
double health = msg.getU16();
|
double health = msg.getU16();
|
||||||
double maxHealth = msg.getU16();
|
double maxHealth = msg.getU16();
|
||||||
|
#if PROTOCOL>=860
|
||||||
double freeCapacity = msg.getU32() / 100.0;
|
double freeCapacity = msg.getU32() / 100.0;
|
||||||
#if PROTOCOL >= 870
|
#else
|
||||||
|
double freeCapacity = msg.getU16() / 100.0;
|
||||||
|
#endif
|
||||||
|
#if PROTOCOL>=870
|
||||||
double experience = msg.getU64();
|
double experience = msg.getU64();
|
||||||
#else
|
#else
|
||||||
double experience = msg.getU32();
|
double experience = msg.getU32();
|
||||||
|
@ -805,7 +817,9 @@ void ProtocolGame::parsePlayerState(InputMessage& msg)
|
||||||
|
|
||||||
void ProtocolGame::parsePlayerCancelAttack(InputMessage& msg)
|
void ProtocolGame::parsePlayerCancelAttack(InputMessage& msg)
|
||||||
{
|
{
|
||||||
|
#if PROTOCOL>=860
|
||||||
msg.getU32(); // unknown
|
msg.getU32(); // unknown
|
||||||
|
#endif
|
||||||
g_game.processAttackCancel();
|
g_game.processAttackCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -830,11 +844,11 @@ void ProtocolGame::parseCreatureSpeak(InputMessage& msg)
|
||||||
|
|
||||||
std::string name = msg.getString();
|
std::string name = msg.getString();
|
||||||
int level = msg.getU16();
|
int level = msg.getU16();
|
||||||
int serverType = msg.getU8();
|
int speakType = msg.getU8();
|
||||||
int channelId = 0;
|
int channelId = 0;
|
||||||
Position creaturePos;
|
Position creaturePos;
|
||||||
|
|
||||||
switch(serverType) {
|
switch(speakType) {
|
||||||
case Proto::ServerSpeakSay:
|
case Proto::ServerSpeakSay:
|
||||||
case Proto::ServerSpeakWhisper:
|
case Proto::ServerSpeakWhisper:
|
||||||
case Proto::ServerSpeakYell:
|
case Proto::ServerSpeakYell:
|
||||||
|
@ -859,12 +873,12 @@ void ProtocolGame::parseCreatureSpeak(InputMessage& msg)
|
||||||
msg.getU32();
|
msg.getU32();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logTraceError("unknown speak type ", serverType);
|
logTraceError("unknown speak type ", speakType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string message = msg.getString();
|
std::string message = msg.getString();
|
||||||
Otc::SpeakType type = Proto::translateSpeakTypeFromServer(serverType);
|
Otc::SpeakType type = Proto::translateSpeakTypeFromServer(speakType);
|
||||||
|
|
||||||
g_game.processCreatureSpeak(name, level, type, message, channelId, creaturePos);
|
g_game.processCreatureSpeak(name, level, type, message, channelId, creaturePos);
|
||||||
}
|
}
|
||||||
|
@ -1140,8 +1154,8 @@ void ProtocolGame::setTileDescription(InputMessage& msg, Position position)
|
||||||
|
|
||||||
int stackPos = 0;
|
int stackPos = 0;
|
||||||
while(true) {
|
while(true) {
|
||||||
int inspectTileId = msg.getU16(true);
|
int inspectItemId = msg.getU16(true);
|
||||||
if(inspectTileId >= 0xFF00)
|
if(inspectItemId >= 0xFF00)
|
||||||
return;
|
return;
|
||||||
else {
|
else {
|
||||||
if(stackPos >= 10)
|
if(stackPos >= 10)
|
||||||
|
@ -1159,8 +1173,8 @@ Outfit ProtocolGame::internalGetOutfit(InputMessage& msg)
|
||||||
{
|
{
|
||||||
Outfit outfit;
|
Outfit outfit;
|
||||||
|
|
||||||
int id = msg.getU16();
|
int lookType = msg.getU16();
|
||||||
if(id != 0) {
|
if(lookType != 0) {
|
||||||
outfit.setCategory(ThingsType::Creature);
|
outfit.setCategory(ThingsType::Creature);
|
||||||
int head = msg.getU8();
|
int head = msg.getU8();
|
||||||
int body = msg.getU8();
|
int body = msg.getU8();
|
||||||
|
@ -1171,7 +1185,7 @@ Outfit ProtocolGame::internalGetOutfit(InputMessage& msg)
|
||||||
msg.getU16(); // mount
|
msg.getU16(); // mount
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
outfit.setId(id);
|
outfit.setId(lookType);
|
||||||
outfit.setHead(head);
|
outfit.setHead(head);
|
||||||
outfit.setBody(body);
|
outfit.setBody(body);
|
||||||
outfit.setLegs(legs);
|
outfit.setLegs(legs);
|
||||||
|
@ -1179,14 +1193,14 @@ Outfit ProtocolGame::internalGetOutfit(InputMessage& msg)
|
||||||
outfit.setAddons(addons);
|
outfit.setAddons(addons);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int id = msg.getU16();
|
int lookTypeEx = msg.getU16();
|
||||||
if(id == 0) {
|
if(lookTypeEx == 0) {
|
||||||
outfit.setCategory(ThingsType::Effect);
|
outfit.setCategory(ThingsType::Effect);
|
||||||
outfit.setId(13);
|
outfit.setId(13);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
outfit.setCategory(ThingsType::Item);
|
outfit.setCategory(ThingsType::Item);
|
||||||
outfit.setId(id);
|
outfit.setId(lookTypeEx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1198,7 +1212,10 @@ ThingPtr ProtocolGame::internalGetThing(InputMessage& msg)
|
||||||
ThingPtr thing;
|
ThingPtr thing;
|
||||||
|
|
||||||
int thingId = msg.getU16();
|
int thingId = msg.getU16();
|
||||||
assert(thingId != 0);
|
if(thingId == 0) {
|
||||||
|
Fw::throwException("[ProtocolGame::internalGetThing] thingId == 0");
|
||||||
|
}
|
||||||
|
|
||||||
if(thingId == 0x0061 || thingId == 0x0062) { // add new creature
|
if(thingId == 0x0061 || thingId == 0x0062) { // add new creature
|
||||||
CreaturePtr creature;
|
CreaturePtr creature;
|
||||||
|
|
||||||
|
@ -1253,10 +1270,14 @@ ThingPtr ProtocolGame::internalGetThing(InputMessage& msg)
|
||||||
|
|
||||||
// emblem is sent only when the creature is not known
|
// emblem is sent only when the creature is not known
|
||||||
int emblem = -1;
|
int emblem = -1;
|
||||||
|
bool passable = false;
|
||||||
|
|
||||||
|
#if PROTOCOL>=860
|
||||||
if(thingId == 0x0061)
|
if(thingId == 0x0061)
|
||||||
emblem = msg.getU8();
|
emblem = msg.getU8();
|
||||||
|
|
||||||
bool passable = (msg.getU8() == 0);
|
passable = (msg.getU8() == 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
if(creature) {
|
if(creature) {
|
||||||
creature->setHealthPercent(healthPercent);
|
creature->setHealthPercent(healthPercent);
|
||||||
|
@ -1277,8 +1298,9 @@ ThingPtr ProtocolGame::internalGetThing(InputMessage& msg)
|
||||||
thing = creature;
|
thing = creature;
|
||||||
} else if(thingId == 0x0063) { // creature turn
|
} else if(thingId == 0x0063) { // creature turn
|
||||||
parseCreatureTurn(msg);
|
parseCreatureTurn(msg);
|
||||||
} else // item
|
} else { // item
|
||||||
thing = internalGetItem(msg, thingId);
|
thing = internalGetItem(msg, thingId);
|
||||||
|
}
|
||||||
|
|
||||||
return thing;
|
return thing;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,9 @@ void ProtocolGame::sendLoginPacket(uint timestamp, uint8 unknown)
|
||||||
|
|
||||||
msg.addU16(Proto::ClientVersion);
|
msg.addU16(Proto::ClientVersion);
|
||||||
|
|
||||||
|
int paddingBytes = 128;
|
||||||
msg.addU8(0); // first RSA byte must be 0
|
msg.addU8(0); // first RSA byte must be 0
|
||||||
|
paddingBytes -= 1;
|
||||||
|
|
||||||
// xtea key
|
// xtea key
|
||||||
generateXteaKey();
|
generateXteaKey();
|
||||||
|
@ -45,20 +47,32 @@ void ProtocolGame::sendLoginPacket(uint timestamp, uint8 unknown)
|
||||||
msg.addU32(m_xteaKey[1]);
|
msg.addU32(m_xteaKey[1]);
|
||||||
msg.addU32(m_xteaKey[2]);
|
msg.addU32(m_xteaKey[2]);
|
||||||
msg.addU32(m_xteaKey[3]);
|
msg.addU32(m_xteaKey[3]);
|
||||||
|
|
||||||
msg.addU8(0); // is gm set?
|
msg.addU8(0); // is gm set?
|
||||||
|
paddingBytes -= 17;
|
||||||
|
|
||||||
|
#if PROTOCOL>=860
|
||||||
|
enableChecksum();
|
||||||
|
|
||||||
msg.addString(m_accountName);
|
msg.addString(m_accountName);
|
||||||
msg.addString(m_characterName);
|
msg.addString(m_characterName);
|
||||||
msg.addString(m_accountPassword);
|
msg.addString(m_accountPassword);
|
||||||
|
|
||||||
msg.addU32(timestamp);
|
msg.addU32(timestamp);
|
||||||
msg.addU8(unknown);
|
msg.addU8(unknown);
|
||||||
|
paddingBytes -= 11 + m_accountName.length() + m_characterName.length() + m_accountPassword.length();
|
||||||
|
#elif PROTOCOL>=810
|
||||||
|
msg.addU32(Fw::fromstring<uint32>(m_accountName));
|
||||||
|
msg.addString(m_characterName);
|
||||||
|
msg.addString(m_accountPassword);
|
||||||
|
|
||||||
|
paddingBytes -= 8 + m_characterName.length() + m_accountPassword.length();
|
||||||
|
#endif
|
||||||
|
|
||||||
// complete the 128 bytes for rsa encryption with zeros
|
// complete the 128 bytes for rsa encryption with zeros
|
||||||
msg.addPaddingBytes(128 - (29 + m_accountName.length() + m_characterName.length() + m_accountPassword.length()));
|
msg.addPaddingBytes(paddingBytes);
|
||||||
|
|
||||||
// encrypt with RSA
|
// encrypt with RSA
|
||||||
Rsa::encrypt((char*)msg.getBuffer() + 6 + msg.getMessageSize() - 128, 128, Proto::RSA);
|
Rsa::encrypt((char*)msg.getWriteBuffer() - 128, 128, Proto::RSA);
|
||||||
|
|
||||||
send(msg);
|
send(msg);
|
||||||
|
|
||||||
|
|
|
@ -28,11 +28,6 @@
|
||||||
#include <otclient/core/thingstype.h>
|
#include <otclient/core/thingstype.h>
|
||||||
#include <otclient/core/spritemanager.h>
|
#include <otclient/core/spritemanager.h>
|
||||||
|
|
||||||
ProtocolLogin::ProtocolLogin()
|
|
||||||
{
|
|
||||||
enableChecksum();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProtocolLogin::login(const std::string& host, int port, const std::string& accountName, const std::string& accountPassword)
|
void ProtocolLogin::login(const std::string& host, int port, const std::string& accountName, const std::string& accountPassword)
|
||||||
{
|
{
|
||||||
if(accountName.empty() || accountPassword.empty()) {
|
if(accountName.empty() || accountPassword.empty()) {
|
||||||
|
@ -88,33 +83,49 @@ void ProtocolLogin::onError(const boost::system::error_code& error)
|
||||||
|
|
||||||
void ProtocolLogin::sendLoginPacket()
|
void ProtocolLogin::sendLoginPacket()
|
||||||
{
|
{
|
||||||
OutputMessage oMsg;
|
OutputMessage msg;
|
||||||
|
|
||||||
oMsg.addU8(Proto::ClientEnterAccount);
|
msg.addU8(Proto::ClientEnterAccount);
|
||||||
oMsg.addU16(Proto::OsLinux);
|
#ifdef WIN32
|
||||||
oMsg.addU16(Proto::ClientVersion);
|
msg.addU16(Proto::OsWindows);
|
||||||
|
#else
|
||||||
|
msg.addU16(Proto::OsLinux);
|
||||||
|
#endif
|
||||||
|
msg.addU16(Proto::ClientVersion);
|
||||||
|
|
||||||
oMsg.addU32(g_thingsType.getSignature()); // data signature
|
msg.addU32(g_thingsType.getSignature()); // data signature
|
||||||
oMsg.addU32(g_sprites.getSignature()); // sprite signature
|
msg.addU32(g_sprites.getSignature()); // sprite signature
|
||||||
oMsg.addU32(Proto::PicSignature); // pic signature
|
msg.addU32(Proto::PicSignature); // pic signature
|
||||||
|
|
||||||
oMsg.addU8(0); // first RSA byte must be 0
|
int paddingBytes = 128;
|
||||||
|
msg.addU8(0); // first RSA byte must be 0
|
||||||
|
paddingBytes -= 1;
|
||||||
|
|
||||||
// xtea key
|
// xtea key
|
||||||
generateXteaKey();
|
generateXteaKey();
|
||||||
oMsg.addU32(m_xteaKey[0]);
|
|
||||||
oMsg.addU32(m_xteaKey[1]);
|
|
||||||
oMsg.addU32(m_xteaKey[2]);
|
|
||||||
oMsg.addU32(m_xteaKey[3]);
|
|
||||||
|
|
||||||
oMsg.addString(m_accountName);
|
msg.addU32(m_xteaKey[0]);
|
||||||
oMsg.addString(m_accountPassword);
|
msg.addU32(m_xteaKey[1]);
|
||||||
|
msg.addU32(m_xteaKey[2]);
|
||||||
|
msg.addU32(m_xteaKey[3]);
|
||||||
|
paddingBytes -= 16;
|
||||||
|
|
||||||
// complete the 128 bytes for rsa encryption with zeros
|
#if PROTOCOL>=860
|
||||||
oMsg.addPaddingBytes(128 - (21 + m_accountName.length() + m_accountPassword.length()));
|
enableChecksum();
|
||||||
Rsa::encrypt((char*)oMsg.getBuffer() + InputMessage::DATA_POS + oMsg.getMessageSize() - 128, 128, Proto::RSA);
|
|
||||||
|
|
||||||
send(oMsg);
|
msg.addString(m_accountName);
|
||||||
|
msg.addString(m_accountPassword);
|
||||||
|
paddingBytes -= 4 + m_accountName.length() + m_accountPassword.length();
|
||||||
|
#elif PROTOCOL>=810
|
||||||
|
msg.addU32(Fw::fromstring<uint32>(m_accountName));
|
||||||
|
msg.addString(m_accountPassword);
|
||||||
|
paddingBytes -= 6 + m_accountPassword.length();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
msg.addPaddingBytes(paddingBytes); // complete the 128 bytes for rsa encryption with zeros
|
||||||
|
Rsa::encrypt((char*)msg.getWriteBuffer() - 128, 128, Proto::RSA);
|
||||||
|
|
||||||
|
send(msg);
|
||||||
enableXteaEncryption();
|
enableXteaEncryption();
|
||||||
recv();
|
recv();
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,6 @@ typedef std::shared_ptr<ProtocolLogin> ProtocolLoginPtr;
|
||||||
class ProtocolLogin : public Protocol
|
class ProtocolLogin : public Protocol
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ProtocolLogin();
|
|
||||||
|
|
||||||
static ProtocolLoginPtr create() { return ProtocolLoginPtr(new ProtocolLogin); }
|
static ProtocolLoginPtr create() { return ProtocolLoginPtr(new ProtocolLogin); }
|
||||||
|
|
||||||
void login(const std::string& host, int port, const std::string& accountName, const std::string& accountPassword);
|
void login(const std::string& host, int port, const std::string& accountName, const std::string& accountPassword);
|
||||||
|
|
Loading…
Reference in New Issue