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) | ||||
| sometimes minimap desync Z pos | ||||
| 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: | ||||
| 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 | ||||
| clean sprites cache periodically | ||||
| handle corrupt errors in dat/spr | ||||
| throw exceptions when fail to read a file | ||||
| 
 | ||||
| * framework | ||||
| rework Settings/g_configs | ||||
|  |  | |||
|  | @ -29,8 +29,28 @@ InputMessage::InputMessage() | |||
| 
 | ||||
| void InputMessage::reset() | ||||
| { | ||||
|     m_readPos = 0; | ||||
|     m_messageSize = 2; | ||||
|     m_messageSize = 0; | ||||
|     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) | ||||
|  | @ -88,7 +108,7 @@ std::string InputMessage::getString() | |||
| 
 | ||||
| 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 true; | ||||
| } | ||||
|  |  | |||
|  | @ -31,34 +31,43 @@ class InputMessage | |||
| public: | ||||
|     enum { | ||||
|         BUFFER_MAXSIZE = 16384, | ||||
|         HEADER_POS = 0, | ||||
|         HEADER_LENGTH = 2, | ||||
|         CHECKSUM_POS = 2, | ||||
|         CHECKSUM_LENGTH = 4, | ||||
|         DATA_POS = 6, | ||||
|         UNENCRYPTED_DATA_POS = 8 | ||||
|         MAX_HEADER_SIZE = 8, | ||||
|     }; | ||||
| 
 | ||||
|     InputMessage(); | ||||
| 
 | ||||
|     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); | ||||
|     uint16 getU16(bool peek = false); | ||||
|     uint32 getU32(bool peek = false); | ||||
|     uint64 getU64(bool peek = false); | ||||
|     std::string getString(); | ||||
| 
 | ||||
|     void skipBytes(uint16 bytes) { m_readPos += bytes; } | ||||
|     uint8* getBuffer() { return m_buffer; } | ||||
|     uint8* getReadBuffer() { return m_buffer + m_readPos; } | ||||
|     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; } | ||||
|     void setMessageSize(uint16 messageSize) { m_messageSize = messageSize; } | ||||
|     bool eof() { return m_readPos >= m_messageSize; } | ||||
|     int getReadSize() { return m_readPos - m_headerPos; } | ||||
|     int getUnreadSize() { return m_messageSize - (m_readPos - m_headerPos); } | ||||
| 
 | ||||
|     bool eof() { return (m_readPos - m_headerPos) >= m_messageSize; } | ||||
| 
 | ||||
| private: | ||||
|     bool canRead(int bytes); | ||||
|     void checkRead(int bytes); | ||||
| 
 | ||||
|     uint16 m_headerPos; | ||||
|     uint16 m_readPos; | ||||
|     uint16 m_messageSize; | ||||
|     uint8 m_buffer[BUFFER_MAXSIZE]; | ||||
|  |  | |||
|  | @ -29,7 +29,8 @@ OutputMessage::OutputMessage() | |||
| 
 | ||||
| void OutputMessage::reset() | ||||
| { | ||||
|     m_writePos = DATA_POS; | ||||
|     m_writePos = MAX_HEADER_SIZE; | ||||
|     m_headerPos = MAX_HEADER_SIZE; | ||||
|     m_messageSize = 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -91,6 +92,23 @@ void OutputMessage::addPaddingBytes(int bytes, uint8 byte) | |||
|     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) | ||||
| { | ||||
|     if(m_writePos + bytes > BUFFER_MAXSIZE) | ||||
|  |  | |||
|  | @ -34,11 +34,7 @@ class OutputMessage : public LuaObject | |||
| public: | ||||
|     enum { | ||||
|         BUFFER_MAXSIZE = 1024, | ||||
|         HEADER_POS = 0, | ||||
|         HEADER_LENGTH = 2, | ||||
|         CHECKSUM_POS = 2, | ||||
|         CHECKSUM_LENGTH = 4, | ||||
|         DATA_POS = 6 | ||||
|         MAX_HEADER_SIZE = 8 | ||||
|     }; | ||||
| 
 | ||||
|     OutputMessage(); | ||||
|  | @ -53,15 +49,19 @@ public: | |||
|     void addString(const std::string& value); | ||||
|     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; } | ||||
|     void setMessageSize(uint16 messageSize) { m_messageSize = messageSize; } | ||||
|     void setWritePos(uint16 writePos) { m_writePos = writePos; } | ||||
| 
 | ||||
|     void writeChecksum(); | ||||
|     void writeMessageSize(); | ||||
| 
 | ||||
| private: | ||||
|     bool canWrite(int bytes); | ||||
|     void checkWrite(int bytes); | ||||
| 
 | ||||
|     uint16 m_headerPos; | ||||
|     uint16 m_writePos; | ||||
|     uint16 m_messageSize; | ||||
|     uint8 m_buffer[BUFFER_MAXSIZE]; | ||||
|  |  | |||
|  | @ -69,40 +69,44 @@ void Protocol::send(OutputMessage& outputMessage) | |||
|     if(m_xteaEncryptionEnabled) | ||||
|         xteaEncrypt(outputMessage); | ||||
| 
 | ||||
|     // set checksum
 | ||||
|     uint32 checksum = getAdlerChecksum(outputMessage.getBuffer() + OutputMessage::DATA_POS, outputMessage.getMessageSize()); | ||||
|     outputMessage.setWritePos(OutputMessage::CHECKSUM_POS); | ||||
|     outputMessage.addU32(checksum); | ||||
|     // write checksum
 | ||||
|     if(m_checksumEnabled) | ||||
|         outputMessage.writeChecksum(); | ||||
| 
 | ||||
|     // set size
 | ||||
|     uint16 messageSize = outputMessage.getMessageSize(); | ||||
|     outputMessage.setWritePos(OutputMessage::HEADER_POS); | ||||
|     outputMessage.addU16(messageSize); | ||||
|     // wirte message size
 | ||||
|     outputMessage.writeMessageSize(); | ||||
| 
 | ||||
|     // send
 | ||||
|     if(m_connection) | ||||
|         m_connection->write(outputMessage.getBuffer(), outputMessage.getMessageSize()); | ||||
|         m_connection->write(outputMessage.getHeaderBuffer(), outputMessage.getMessageSize()); | ||||
| } | ||||
| 
 | ||||
| void Protocol::recv() | ||||
| { | ||||
|     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) | ||||
|         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) | ||||
| { | ||||
|     memcpy(m_inputMessage.getBuffer() + InputMessage::HEADER_POS, buffer, size); | ||||
| 
 | ||||
|     // read message size
 | ||||
|     uint16 dataSize = m_inputMessage.getU16(); | ||||
|     m_inputMessage.setMessageSize(dataSize); | ||||
|     m_inputMessage.fillBuffer(buffer, size); | ||||
|     uint16 remainingSize = m_inputMessage.readSize(); | ||||
| 
 | ||||
|     // schedule read for message data
 | ||||
|     // read remaining message data
 | ||||
|     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) | ||||
|  | @ -113,19 +117,16 @@ void Protocol::internalRecvData(uint8* buffer, uint16 size) | |||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     memcpy(m_inputMessage.getBuffer() + InputMessage::CHECKSUM_POS, buffer, size); | ||||
|     m_inputMessage.fillBuffer(buffer, size); | ||||
| 
 | ||||
|     if(m_checksumEnabled) { | ||||
|         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"); | ||||
|             return; | ||||
|         } | ||||
|     if(m_checksumEnabled && !m_inputMessage.readChecksum()) { | ||||
|         logTraceError("got a network message with invalid checksum"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if(m_xteaEncryptionEnabled) { | ||||
|         if(!xteaDecrypt(m_inputMessage)) | ||||
|             return; | ||||
|     if(m_xteaEncryptionEnabled && !xteaDecrypt(m_inputMessage)) { | ||||
|         logTraceError("failed to decrypt message"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     onRecv(m_inputMessage); | ||||
|  | @ -143,16 +144,16 @@ void Protocol::generateXteaKey() | |||
| 
 | ||||
| bool Protocol::xteaDecrypt(InputMessage& inputMessage) | ||||
| { | ||||
|     uint16 messageSize = inputMessage.getMessageSize() - InputMessage::CHECKSUM_LENGTH; | ||||
|     if(messageSize % 8 != 0) { | ||||
|     uint16 encryptedSize = inputMessage.getUnreadSize(); | ||||
|     if(encryptedSize % 8 != 0) { | ||||
|         logTraceError("invalid encrypted network message"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     uint32 *buffer = (uint32*)(inputMessage.getBuffer() + InputMessage::DATA_POS); | ||||
|     uint32 *buffer = (uint32*)(inputMessage.getReadBuffer()); | ||||
|     int readPos = 0; | ||||
| 
 | ||||
|     while(readPos < messageSize/4) { | ||||
|     while(readPos < encryptedSize/4) { | ||||
|         uint32 v0 = buffer[readPos], v1 = buffer[readPos + 1]; | ||||
|         uint32 delta = 0x61C88647; | ||||
|         uint32 sum = 0xC6EF3720; | ||||
|  | @ -166,37 +167,32 @@ bool Protocol::xteaDecrypt(InputMessage& inputMessage) | |||
|         readPos = readPos + 2; | ||||
|     } | ||||
| 
 | ||||
|     int tmp = inputMessage.getU16(); | ||||
|     if(tmp > inputMessage.getMessageSize() - 4) { | ||||
|     uint16 decryptedSize = inputMessage.getU16() + 2; | ||||
|     int sizeDelta = decryptedSize - encryptedSize; | ||||
|     if(sizeDelta > 0 || -sizeDelta > encryptedSize) { | ||||
|         logTraceError("invalid decrypted a network message"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     inputMessage.setMessageSize(tmp + InputMessage::UNENCRYPTED_DATA_POS); | ||||
|     inputMessage.setMessageSize(inputMessage.getMessageSize() + sizeDelta); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void Protocol::xteaEncrypt(OutputMessage& outputMessage) | ||||
| { | ||||
|     uint16 messageLength = 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); | ||||
|     outputMessage.writeMessageSize(); | ||||
|     uint16 encryptedSize = outputMessage.getMessageSize(); | ||||
| 
 | ||||
|     //add bytes until reach 8 multiple
 | ||||
|     if((messageLength % 8) != 0) { | ||||
|         uint16 n = 8 - (messageLength % 8); | ||||
|     if((encryptedSize % 8) != 0) { | ||||
|         uint16 n = 8 - (encryptedSize % 8); | ||||
|         outputMessage.addPaddingBytes(n); | ||||
|         messageLength += n; | ||||
|         encryptedSize += n; | ||||
|     } | ||||
| 
 | ||||
|     int readPos = 0; | ||||
|     uint32 *buffer = (uint32*)(outputMessage.getBuffer() + OutputMessage::DATA_POS); | ||||
|     while(readPos < messageLength / 4) { | ||||
|     uint32 *buffer = (uint32*)(outputMessage.getDataBuffer() - 2); | ||||
|     while(readPos < encryptedSize / 4) { | ||||
|         uint32 v0 = buffer[readPos], v1 = buffer[readPos + 1]; | ||||
|         uint32 delta = 0x61C88647; | ||||
|         uint32 sum = 0; | ||||
|  | @ -210,21 +206,3 @@ void Protocol::xteaEncrypt(OutputMessage& outputMessage) | |||
|         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: | ||||
|     bool xteaDecrypt(InputMessage& inputMessage); | ||||
|     void xteaEncrypt(OutputMessage& outputMessage); | ||||
|     uint32 getAdlerChecksum(uint8* buffer, uint16 size); | ||||
| 
 | ||||
|     bool m_checksumEnabled; | ||||
|     bool m_xteaEncryptionEnabled; | ||||
|  |  | |||
|  | @ -326,6 +326,22 @@ inline float randomRange<float>(float min, float max) { | |||
|     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
 | ||||
|  |  | |||
|  | @ -269,16 +269,22 @@ CreaturePtr Map::getCreatureById(uint32 id) | |||
|     LocalPlayerPtr localPlayer = g_game.getLocalPlayer(); | ||||
|     if(localPlayer && localPlayer->getId() == id) | ||||
|         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) | ||||
| { | ||||
|     if(id == 0) | ||||
|         return; | ||||
|     if(CreaturePtr creature = m_knownCreatures[id]) | ||||
|         creature->setRemoved(true); | ||||
|     m_knownCreatures.erase(id); | ||||
| 
 | ||||
|     auto it = m_knownCreatures.find(id); | ||||
|     if(it != m_knownCreatures.end()) | ||||
|         it->second->setRemoved(true); | ||||
| 
 | ||||
|     m_knownCreatures.erase(it); | ||||
| } | ||||
| 
 | ||||
| void Map::setCentralPosition(const Position& centralPosition) | ||||
|  | @ -288,13 +294,8 @@ void Map::setCentralPosition(const Position& centralPosition) | |||
|     // remove creatures from tiles that we are not aware anymore
 | ||||
|     for(const auto& pair : m_knownCreatures) { | ||||
|         const CreaturePtr& creature = pair.second; | ||||
|         if(creature) { | ||||
|             if(!isAwareOfPosition(creature->getPosition())) { | ||||
|                 removeThing(creature); | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|             logTraceError("invalid creature"); | ||||
|         if(!isAwareOfPosition(creature->getPosition())) | ||||
|             removeThing(creature); | ||||
|     } | ||||
| 
 | ||||
|     // this fixes local player position when the local player is removed from the map,
 | ||||
|  |  | |||
|  | @ -24,36 +24,35 @@ | |||
| #include "spritemanager.h" | ||||
| #include "thing.h" | ||||
| #include <framework/core/resourcemanager.h> | ||||
| #include <framework/core/filestream.h> | ||||
| 
 | ||||
| ThingsType g_thingsType; | ||||
| ThingType ThingsType::m_emptyThingType; | ||||
| 
 | ||||
| bool ThingsType::load(const std::string& file) | ||||
| { | ||||
|     try { | ||||
|         std::stringstream fin; | ||||
|         g_resources.loadFile(file, fin); | ||||
| 
 | ||||
|         m_signature = Fw::getU32(fin); | ||||
| 
 | ||||
|         int numThings[LastCategory]; | ||||
|         for(int i = 0; i < LastCategory; ++i) | ||||
|             numThings[i] = Fw::getU16(fin); | ||||
| 
 | ||||
|         numThings[Item] -= 99; | ||||
| 
 | ||||
|         for(int i = 0; i < LastCategory; ++i) { | ||||
|             m_things[i].resize(numThings[i]); | ||||
|             for(int id = 0; id < numThings[i]; ++id) | ||||
|                 parseThingType(fin, m_things[i][id]); | ||||
|         } | ||||
| 
 | ||||
|         m_loaded = true; | ||||
|         return true; | ||||
|     } catch(Exception& e) { | ||||
|         logError("Failed to load dat from '", file, "': ", e.what()); | ||||
|     FileStreamPtr fin = g_resources.openFile(file); | ||||
|     if(!fin) { | ||||
|         logError("unable to open dat file '", file, "'"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     m_signature = fin->getU32(); | ||||
| 
 | ||||
|     int numThings[LastCategory]; | ||||
|     for(int i = 0; i < LastCategory; ++i) | ||||
|         numThings[i] = fin->getU16(); | ||||
| 
 | ||||
|     numThings[Item] -= 99; | ||||
| 
 | ||||
|     for(int i = 0; i < LastCategory; ++i) { | ||||
|         m_things[i].resize(numThings[i]); | ||||
|         for(int id = 0; id < numThings[i]; ++id) | ||||
|             parseThingType(fin, m_things[i][id]); | ||||
|     } | ||||
| 
 | ||||
|     m_loaded = true; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void ThingsType::unload() | ||||
|  | @ -62,37 +61,39 @@ void ThingsType::unload() | |||
|         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) { | ||||
|         int property = Fw::getU8(fin); | ||||
|         int property = fin->getU8(); | ||||
|         if(property == ThingType::LastPropertyValue) | ||||
|             break; | ||||
| 
 | ||||
|         thingType.m_properties[property] = true; | ||||
| 
 | ||||
|         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) | ||||
|             thingType.m_parameters[ThingType::MaxTextLenght] = Fw::getU16(fin); | ||||
|             thingType.m_parameters[ThingType::MaxTextLenght] = fin->getU16(); | ||||
|         else if(property == ThingType::HasLight) { | ||||
|             thingType.m_parameters[ThingType::LightLevel] = Fw::getU16(fin); | ||||
|             thingType.m_parameters[ThingType::LightColor] = Fw::getU16(fin); | ||||
|             thingType.m_parameters[ThingType::LightLevel] = fin->getU16(); | ||||
|             thingType.m_parameters[ThingType::LightColor] = fin->getU16(); | ||||
|         } | ||||
|         else if(property == ThingType::HasDisplacement) { | ||||
|             thingType.m_parameters[ThingType::DisplacementX] = Fw::getU16(fin); | ||||
|             thingType.m_parameters[ThingType::DisplacementY] = Fw::getU16(fin); | ||||
|             thingType.m_parameters[ThingType::DisplacementX] = fin->getU16(); | ||||
|             thingType.m_parameters[ThingType::DisplacementY] = fin->getU16(); | ||||
|         } | ||||
|         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) | ||||
|             thingType.m_parameters[ThingType::MiniMapColor] = Fw::getU16(fin); | ||||
|             thingType.m_parameters[ThingType::MiniMapColor] = fin->getU16(); | ||||
|         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) | ||||
|             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; | ||||
|  | @ -102,7 +103,7 @@ void ThingsType::parseThingType(std::stringstream& fin, ThingType& thingType) | |||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         thingType.m_dimensions[i] = Fw::getU8(fin); | ||||
|         thingType.m_dimensions[i] = fin->getU8(); | ||||
| 
 | ||||
|         if(i != ThingType::ExactSize) | ||||
|             totalSprites *= thingType.m_dimensions[i]; | ||||
|  | @ -111,7 +112,7 @@ void ThingsType::parseThingType(std::stringstream& fin, ThingType& thingType) | |||
|     thingType.m_spritesIndex.resize(totalSprites); | ||||
|     thingType.m_sprites.resize(totalSprites); | ||||
|     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) | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ | |||
| #define DATMANAGER_H | ||||
| 
 | ||||
| #include <framework/global.h> | ||||
| #include <framework/core/declarations.h> | ||||
| #include "thingtype.h" | ||||
| 
 | ||||
| class ThingsType | ||||
|  | @ -41,7 +42,7 @@ public: | |||
|     bool load(const std::string& file); | ||||
|     void unload(); | ||||
| 
 | ||||
|     void parseThingType(std::stringstream& fin, ThingType& thingType); | ||||
|     void parseThingType(const FileStreamPtr& fin, ThingType& thingType); | ||||
| 
 | ||||
|     ThingType *getEmptyThingType() { return &m_emptyThingType; } | ||||
|     ThingType *getThingType(uint16 id, Categories category); | ||||
|  |  | |||
|  | @ -50,6 +50,9 @@ struct ThingType | |||
|         IsStackable, | ||||
|         IsForceUse, | ||||
|         IsMultiUse, | ||||
| #if PROTOCOL<=810 | ||||
|         IsRune, | ||||
| #endif | ||||
|         IsWritable, | ||||
|         IsWritableOnce, | ||||
|         IsFluidContainer, | ||||
|  |  | |||
|  | @ -25,7 +25,7 @@ | |||
| 
 | ||||
| #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" | ||||
| #endif | ||||
| 
 | ||||
|  | @ -51,6 +51,8 @@ namespace Proto { | |||
|     constexpr int NumViolationReasons = 19; | ||||
| #elif PROTOCOL>=860 | ||||
|     constexpr int NumViolationReasons = 20; | ||||
| #elif PROTOCOL>=810 | ||||
|     constexpr int NumViolationReasons = 32; | ||||
| #endif | ||||
| 
 | ||||
|     enum OsTypes { | ||||
|  | @ -210,9 +212,7 @@ namespace Proto { | |||
|         ClientRefreshContainer = 202, | ||||
|         ClientRequestOutfit = 210, | ||||
|         ClientChangeOutfit = 211, | ||||
| #if PROTOCOL>=870 | ||||
|         ClientMount = 212, | ||||
| #endif | ||||
|         ClientMount = 212, // 870
 | ||||
|         ClientAddVip = 220, | ||||
|         ClientRemoveVip = 221, | ||||
|         ClientBugReport = 230, | ||||
|  | @ -242,7 +242,7 @@ namespace Proto { | |||
|         ServerSpeakMonsterSay, | ||||
|         ServerSpeakMonsterYell, | ||||
| 
 | ||||
|         // removed
 | ||||
|         // unsupported
 | ||||
|         ServerSpeakRVRChannel = 255, | ||||
|         ServerSpeakRVRAnswer, | ||||
|         ServerSpeakRVRContinue, | ||||
|  | @ -266,6 +266,29 @@ namespace Proto { | |||
|         ServerSpeakChannelRed2 = 17, | ||||
|         ServerSpeakMonsterSay = 19, | ||||
|         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 | ||||
|     }; | ||||
| 
 | ||||
|  | @ -289,9 +312,22 @@ namespace Proto { | |||
|         MessageEventAdvance, | ||||
|         MessageEventDefault, | ||||
|         MessageStatusDefault, | ||||
|         MessageInfoDescription , | ||||
|         MessageInfoDescription, | ||||
|         MessageStatusSmall, | ||||
|         MessageConsoleBlue | ||||
| #elif PROTOCOL>=810 | ||||
|         MessageWarning = 18, | ||||
|         MessageEventAdvance, | ||||
|         MessageEventDefault, | ||||
|         MessageStatusDefault, | ||||
|         MessageInfoDescription, | ||||
|         MessageStatusSmall, | ||||
|         MessageConsoleBlue, | ||||
|         MessageConsoleRed, | ||||
| 
 | ||||
|         // unsupported
 | ||||
|         MessageConsoleOrange = 255, | ||||
|         MessageConsoleOrange2, | ||||
| #endif | ||||
|     }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -32,7 +32,6 @@ void ProtocolGame::login(const std::string& accountName, const std::string& acco | |||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     m_waitingLoginPacket = true; | ||||
|     m_accountName = accountName; | ||||
|     m_accountPassword = accountPassword; | ||||
|     m_characterName = characterName; | ||||
|  | @ -43,17 +42,26 @@ void ProtocolGame::login(const std::string& accountName, const std::string& acco | |||
| void ProtocolGame::onConnect() | ||||
| { | ||||
|     recv(); | ||||
| 
 | ||||
| #if PROTOCOL>=860 | ||||
|     m_waitingLoginPacket = true; | ||||
| #else | ||||
|     sendLoginPacket(0, 0); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void ProtocolGame::onRecv(InputMessage& inputMessage) | ||||
| { | ||||
|     // only for protocol >= 860
 | ||||
|     if(m_waitingLoginPacket) { | ||||
|         inputMessage.skipBytes(3); | ||||
|         uint32 timestamp = inputMessage.getU32(); | ||||
|         uint8 unknown = inputMessage.getU8(); | ||||
| 
 | ||||
|         m_waitingLoginPacket = false; | ||||
| 
 | ||||
|         enableChecksum(); | ||||
| 
 | ||||
|         sendLoginPacket(timestamp, unknown); | ||||
|         recv(); | ||||
|     } | ||||
|  |  | |||
|  | @ -35,9 +35,12 @@ | |||
| 
 | ||||
| void ProtocolGame::parseMessage(InputMessage& msg) | ||||
| { | ||||
|     int opcode = 0; | ||||
|     int prevOpcode = 0; | ||||
| 
 | ||||
|     try { | ||||
|         while(!msg.eof()) { | ||||
|             int opcode = msg.getU8(); | ||||
|             opcode = msg.getU8(); | ||||
| 
 | ||||
|             switch(opcode) { | ||||
|             case Proto::GameServerInitGame: | ||||
|  | @ -268,12 +271,13 @@ void ProtocolGame::parseMessage(InputMessage& msg) | |||
|                 parseExtendedOpcode(msg); | ||||
|                 break; | ||||
|             default: | ||||
|                 Fw::throwException("unknown opcode ", opcode); | ||||
|                 Fw::throwException("unknown opcode ", opcode, ", previous opcode is ", prevOpcode); | ||||
|                 break; | ||||
|             } | ||||
|             prevOpcode = opcode; | ||||
|         } | ||||
|     } 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) | ||||
| { | ||||
|     Position pos = parsePosition(msg); | ||||
|     int stackPos = msg.getU8(); | ||||
|     int stackPos = -1; | ||||
| 
 | ||||
| #if PROTOCOL>=860 | ||||
|     stackPos = msg.getU8(); | ||||
| #endif | ||||
| 
 | ||||
|     ThingPtr thing = internalGetThing(msg); | ||||
|     g_map.addThing(thing, pos, stackPos); | ||||
|  | @ -754,8 +762,12 @@ void ProtocolGame::parsePlayerStats(InputMessage& msg) | |||
| { | ||||
|     double health = msg.getU16(); | ||||
|     double maxHealth = msg.getU16(); | ||||
| #if PROTOCOL>=860 | ||||
|     double freeCapacity = msg.getU32() / 100.0; | ||||
| #if PROTOCOL >= 870 | ||||
| #else | ||||
|     double freeCapacity = msg.getU16() / 100.0; | ||||
| #endif | ||||
| #if PROTOCOL>=870 | ||||
|     double experience = msg.getU64(); | ||||
| #else | ||||
|     double experience = msg.getU32(); | ||||
|  | @ -805,7 +817,9 @@ void ProtocolGame::parsePlayerState(InputMessage& msg) | |||
| 
 | ||||
| void ProtocolGame::parsePlayerCancelAttack(InputMessage& msg) | ||||
| { | ||||
| #if PROTOCOL>=860 | ||||
|     msg.getU32(); // unknown
 | ||||
| #endif | ||||
|     g_game.processAttackCancel(); | ||||
| } | ||||
| 
 | ||||
|  | @ -830,11 +844,11 @@ void ProtocolGame::parseCreatureSpeak(InputMessage& msg) | |||
| 
 | ||||
|     std::string name = msg.getString(); | ||||
|     int level = msg.getU16(); | ||||
|     int serverType = msg.getU8(); | ||||
|     int speakType = msg.getU8(); | ||||
|     int channelId = 0; | ||||
|     Position creaturePos; | ||||
| 
 | ||||
|     switch(serverType) { | ||||
|     switch(speakType) { | ||||
|         case Proto::ServerSpeakSay: | ||||
|         case Proto::ServerSpeakWhisper: | ||||
|         case Proto::ServerSpeakYell: | ||||
|  | @ -859,12 +873,12 @@ void ProtocolGame::parseCreatureSpeak(InputMessage& msg) | |||
|             msg.getU32(); | ||||
|             break; | ||||
|         default: | ||||
|             logTraceError("unknown speak type ", serverType); | ||||
|             logTraceError("unknown speak type ", speakType); | ||||
|             break; | ||||
|     } | ||||
| 
 | ||||
|     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); | ||||
| } | ||||
|  | @ -1140,8 +1154,8 @@ void ProtocolGame::setTileDescription(InputMessage& msg, Position position) | |||
| 
 | ||||
|     int stackPos = 0; | ||||
|     while(true) { | ||||
|         int inspectTileId = msg.getU16(true); | ||||
|         if(inspectTileId >= 0xFF00) | ||||
|         int inspectItemId = msg.getU16(true); | ||||
|         if(inspectItemId >= 0xFF00) | ||||
|             return; | ||||
|         else { | ||||
|             if(stackPos >= 10) | ||||
|  | @ -1159,8 +1173,8 @@ Outfit ProtocolGame::internalGetOutfit(InputMessage& msg) | |||
| { | ||||
|     Outfit outfit; | ||||
| 
 | ||||
|     int id = msg.getU16(); | ||||
|     if(id != 0) { | ||||
|     int lookType = msg.getU16(); | ||||
|     if(lookType != 0) { | ||||
|         outfit.setCategory(ThingsType::Creature); | ||||
|         int head = msg.getU8(); | ||||
|         int body = msg.getU8(); | ||||
|  | @ -1171,7 +1185,7 @@ Outfit ProtocolGame::internalGetOutfit(InputMessage& msg) | |||
|         msg.getU16(); // mount
 | ||||
| #endif | ||||
| 
 | ||||
|         outfit.setId(id); | ||||
|         outfit.setId(lookType); | ||||
|         outfit.setHead(head); | ||||
|         outfit.setBody(body); | ||||
|         outfit.setLegs(legs); | ||||
|  | @ -1179,14 +1193,14 @@ Outfit ProtocolGame::internalGetOutfit(InputMessage& msg) | |||
|         outfit.setAddons(addons); | ||||
|     } | ||||
|     else { | ||||
|         int id = msg.getU16(); | ||||
|         if(id == 0) { | ||||
|         int lookTypeEx = msg.getU16(); | ||||
|         if(lookTypeEx == 0) { | ||||
|             outfit.setCategory(ThingsType::Effect); | ||||
|             outfit.setId(13); | ||||
|         } | ||||
|         else { | ||||
|             outfit.setCategory(ThingsType::Item); | ||||
|             outfit.setId(id); | ||||
|             outfit.setId(lookTypeEx); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -1198,7 +1212,10 @@ ThingPtr ProtocolGame::internalGetThing(InputMessage& msg) | |||
|     ThingPtr thing; | ||||
| 
 | ||||
|     int thingId = msg.getU16(); | ||||
|     assert(thingId != 0); | ||||
|     if(thingId == 0) { | ||||
|         Fw::throwException("[ProtocolGame::internalGetThing] thingId == 0"); | ||||
|     } | ||||
| 
 | ||||
|     if(thingId == 0x0061 || thingId == 0x0062) { // add new creature
 | ||||
|         CreaturePtr creature; | ||||
| 
 | ||||
|  | @ -1253,10 +1270,14 @@ ThingPtr ProtocolGame::internalGetThing(InputMessage& msg) | |||
| 
 | ||||
|         // emblem is sent only when the creature is not known
 | ||||
|         int emblem = -1; | ||||
|         bool passable = false; | ||||
| 
 | ||||
| #if PROTOCOL>=860 | ||||
|         if(thingId == 0x0061) | ||||
|             emblem = msg.getU8(); | ||||
| 
 | ||||
|         bool passable = (msg.getU8() == 0); | ||||
|         passable = (msg.getU8() == 0); | ||||
| #endif | ||||
| 
 | ||||
|         if(creature) { | ||||
|             creature->setHealthPercent(healthPercent); | ||||
|  | @ -1277,8 +1298,9 @@ ThingPtr ProtocolGame::internalGetThing(InputMessage& msg) | |||
|         thing = creature; | ||||
|     } else if(thingId == 0x0063) { // creature turn
 | ||||
|         parseCreatureTurn(msg); | ||||
|     } else // item
 | ||||
|     } else { // item
 | ||||
|         thing = internalGetItem(msg, thingId); | ||||
|     } | ||||
| 
 | ||||
|     return thing; | ||||
| } | ||||
|  |  | |||
|  | @ -37,7 +37,9 @@ void ProtocolGame::sendLoginPacket(uint timestamp, uint8 unknown) | |||
| 
 | ||||
|     msg.addU16(Proto::ClientVersion); | ||||
| 
 | ||||
|     int paddingBytes = 128; | ||||
|     msg.addU8(0); // first RSA byte must be 0
 | ||||
|     paddingBytes -= 1; | ||||
| 
 | ||||
|     // xtea key
 | ||||
|     generateXteaKey(); | ||||
|  | @ -45,20 +47,32 @@ void ProtocolGame::sendLoginPacket(uint timestamp, uint8 unknown) | |||
|     msg.addU32(m_xteaKey[1]); | ||||
|     msg.addU32(m_xteaKey[2]); | ||||
|     msg.addU32(m_xteaKey[3]); | ||||
| 
 | ||||
|     msg.addU8(0); // is gm set?
 | ||||
|     paddingBytes -= 17; | ||||
| 
 | ||||
| #if PROTOCOL>=860 | ||||
|     enableChecksum(); | ||||
| 
 | ||||
|     msg.addString(m_accountName); | ||||
|     msg.addString(m_characterName); | ||||
|     msg.addString(m_accountPassword); | ||||
| 
 | ||||
|     msg.addU32(timestamp); | ||||
|     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
 | ||||
|     msg.addPaddingBytes(128 - (29 + m_accountName.length() + m_characterName.length() + m_accountPassword.length())); | ||||
|     msg.addPaddingBytes(paddingBytes); | ||||
| 
 | ||||
|     // 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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -28,11 +28,6 @@ | |||
| #include <otclient/core/thingstype.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) | ||||
| { | ||||
|     if(accountName.empty() || accountPassword.empty()) { | ||||
|  | @ -88,33 +83,49 @@ void ProtocolLogin::onError(const boost::system::error_code& error) | |||
| 
 | ||||
| void ProtocolLogin::sendLoginPacket() | ||||
| { | ||||
|     OutputMessage oMsg; | ||||
|     OutputMessage msg; | ||||
| 
 | ||||
|     oMsg.addU8(Proto::ClientEnterAccount); | ||||
|     oMsg.addU16(Proto::OsLinux); | ||||
|     oMsg.addU16(Proto::ClientVersion); | ||||
|     msg.addU8(Proto::ClientEnterAccount); | ||||
| #ifdef WIN32 | ||||
|     msg.addU16(Proto::OsWindows); | ||||
| #else | ||||
|     msg.addU16(Proto::OsLinux); | ||||
| #endif | ||||
|     msg.addU16(Proto::ClientVersion); | ||||
| 
 | ||||
|     oMsg.addU32(g_thingsType.getSignature()); // data signature
 | ||||
|     oMsg.addU32(g_sprites.getSignature()); // sprite signature
 | ||||
|     oMsg.addU32(Proto::PicSignature); // pic signature
 | ||||
|     msg.addU32(g_thingsType.getSignature()); // data signature
 | ||||
|     msg.addU32(g_sprites.getSignature()); // sprite 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
 | ||||
|     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); | ||||
|     oMsg.addString(m_accountPassword); | ||||
|     msg.addU32(m_xteaKey[0]); | ||||
|     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
 | ||||
|     oMsg.addPaddingBytes(128 - (21 + m_accountName.length() + m_accountPassword.length())); | ||||
|     Rsa::encrypt((char*)oMsg.getBuffer() + InputMessage::DATA_POS + oMsg.getMessageSize() - 128, 128, Proto::RSA); | ||||
| #if PROTOCOL>=860 | ||||
|     enableChecksum(); | ||||
| 
 | ||||
|     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(); | ||||
|     recv(); | ||||
| } | ||||
|  |  | |||
|  | @ -32,8 +32,6 @@ typedef std::shared_ptr<ProtocolLogin> ProtocolLoginPtr; | |||
| class ProtocolLogin : public Protocol | ||||
| { | ||||
| public: | ||||
|     ProtocolLogin(); | ||||
| 
 | ||||
|     static ProtocolLoginPtr create() { return ProtocolLoginPtr(new ProtocolLogin); } | ||||
| 
 | ||||
|     void login(const std::string& host, int port, const std::string& accountName, const std::string& accountPassword); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Eduardo Bart
						Eduardo Bart