// *************************************************************************** // // Reality - The Matrix Online Server Emulator // Copyright (C) 2006-2010 Rajko Stojadinovic // http://mxoemu.info // // --------------------------------------------------------------------------- // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . // // --------------------------------------------------------------------------- // // *************************************************************************** #ifndef MXOSIM_MESSAGETYPES_H #define MXOSIM_MESSAGETYPES_H #include "Common.h" #include "ByteBuffer.h" #include "Util.h" #include "Crypto.h" class MsgBaseClass { public: class PacketNoLongerValid {}; MsgBaseClass() {m_buf.clear();} virtual ~MsgBaseClass() {} virtual const ByteBuffer& toBuf() = 0; protected: ByteBuffer m_buf; }; typedef shared_ptr msgBaseClassPtr; class ObjectUpdateMsg : public MsgBaseClass { public: ObjectUpdateMsg(uint32 objectId); ~ObjectUpdateMsg(); virtual void setReceiver(class GameClient *toWho); protected: uint32 m_objectId; class GameClient *m_toWho; }; class DeletePlayerMsg : public ObjectUpdateMsg { public: DeletePlayerMsg(uint32 objectId); ~DeletePlayerMsg(); const ByteBuffer& toBuf(); void setReceiver(class GameClient *toWho); }; class CloseDoorMsg : public ObjectUpdateMsg { public: CloseDoorMsg(uint32 objectId ); ~CloseDoorMsg(); const ByteBuffer& toBuf(); void setReceiver(class GameClient *toWho); }; class PlayerSpawnMsg : public ObjectUpdateMsg { public: PlayerSpawnMsg(uint32 objectId); ~PlayerSpawnMsg(); const ByteBuffer& toBuf(); }; class PlayerAppearanceMsg : public ObjectUpdateMsg { public: PlayerAppearanceMsg(uint32 objectId); ~PlayerAppearanceMsg(); const ByteBuffer& toBuf(); }; class EmoteMsg : public ObjectUpdateMsg { public: EmoteMsg(uint32 objectId, uint32 emoteId, uint8 emoteCount); ~EmoteMsg(); const ByteBuffer& toBuf(); private: uint8 m_emoteCount; static map m_emotesMap; uint8 m_emoteAnimation; }; class AnimationStateMsg : public ObjectUpdateMsg { public: AnimationStateMsg(uint32 objectId); ~AnimationStateMsg(); const ByteBuffer& toBuf(); }; class PositionStateMsg : public ObjectUpdateMsg { public: PositionStateMsg(uint32 objectId); ~PositionStateMsg(); const ByteBuffer& toBuf(); }; class JackoutEffectMsg : public ObjectUpdateMsg { public: JackoutEffectMsg(uint32 objectId, bool jackout=true); ~JackoutEffectMsg(); const ByteBuffer& toBuf(); private: bool m_jackout; }; class StateUpdateMsg : public ObjectUpdateMsg { public: StateUpdateMsg(uint32 objectId, ByteBuffer stateData); ~StateUpdateMsg(); const ByteBuffer& toBuf(); private: ByteBuffer restOfData; }; class StaticMsg : public MsgBaseClass { public: StaticMsg() {} StaticMsg(const ByteBuffer &inputBuf) {m_buf = inputBuf;} ~StaticMsg() {} const ByteBuffer& toBuf() {return m_buf;} }; class EmptyMsg : public StaticMsg { public: EmptyMsg() {m_buf.clear();} ~EmptyMsg() {} }; class DoorAnimationMsg : public StaticMsg { public: DoorAnimationMsg(uint32 doorId, uint16 viewId, double X, double Y, double Z, double ROT, int doorType); ~DoorAnimationMsg(); }; class WhereAmIResponse : public StaticMsg { public: WhereAmIResponse(const class LocationVector &currPos); ~WhereAmIResponse(); }; class WhisperMsg : public StaticMsg { public: WhisperMsg(string sender, string message); ~WhisperMsg(); }; class SystemMsg : public StaticMsg { public: SystemMsg(uint16 opcode,string message) { m_buf.clear(); m_buf << uint16(swap16(opcode)); m_buf << uint8(0); m_buf << uint32(0); m_buf << uint32(0); //no sender size_t putMessageStrLenPosHere = m_buf.wpos(); m_buf << uint32(0); //we will overwrite this later //0x15 bytes of 0s for (int i=0;i<0x15;i++) m_buf << uint8(0); size_t messageStrLenPos = m_buf.wpos(); m_buf.writeString(message); //go back and put position there m_buf.put(putMessageStrLenPosHere,uint32(messageStrLenPos)); } ~SystemMsg() {} }; class BroadcastMsg : public SystemMsg { public: BroadcastMsg(string message) : SystemMsg(0x2EC7,message) {} ~BroadcastMsg() {} }; class ModalMsg : public SystemMsg { public: ModalMsg(string message) : SystemMsg(0x2ED7,message) {} ~ModalMsg() {} }; class SystemChatMsg : public SystemMsg { public: SystemChatMsg(string message) : SystemMsg(0x2E07,message) {} ~SystemChatMsg() {} }; class PlayerChatMsg : public StaticMsg { public: PlayerChatMsg(string charHandle,string theChatMsg) { m_buf.clear(); m_buf << swap16(0x2E10); m_buf << uint8(0); //could be 1 as well ? m_buf << uint32(swap32(0x12610200)); //some id, different, ill just use something size_t injectHandleLenPosHere = m_buf.wpos(); m_buf << uint32(0); //will come back here and overwrite later size_t injectMessageLenPosHere = m_buf.wpos(); m_buf << uint32(0); //also placeholder //0x15 0s vector fifteen(0x15,0); m_buf.append(fifteen); size_t handleLenPos=m_buf.wpos(); m_buf.writeString(charHandle); size_t messageLenPos = m_buf.wpos(); m_buf.writeString(theChatMsg); //overwrite the pos we didnt before m_buf.put(injectHandleLenPosHere,uint32(handleLenPos)); m_buf.put(injectMessageLenPosHere,uint32(messageLenPos)); } ~PlayerChatMsg() {} }; class BackgroundResponseMsg : public StaticMsg { public: BackgroundResponseMsg(string playerBackground) { m_buf.clear(); m_buf << uint16(swap16(0x8195)); size_t insertBackgroundStrLenPosHere = m_buf.wpos(); m_buf << uint16(0); //placeholder m_buf << uint8(0); size_t backgroundStrLenPos = m_buf.wpos(); m_buf.writeString(playerBackground); //go back and put position there m_buf.put(insertBackgroundStrLenPosHere,uint16(backgroundStrLenPos)); } ~BackgroundResponseMsg() {} }; class PlayerDetailsMsg : public StaticMsg { public: PlayerDetailsMsg(class PlayerObject *thePlayer); ~PlayerDetailsMsg(); }; class PlayerBackgroundMsg : public StaticMsg { public: PlayerBackgroundMsg(string playerBackground) { m_buf.clear(); m_buf << uint16(swap16(0x8198)); size_t insertBackgroundStrLenPosHere = m_buf.wpos(); m_buf << uint16(0); //placeholder m_buf << uint8(1); size_t backgroundStrLenPos = m_buf.wpos(); m_buf.writeString(playerBackground); //go back and put position there m_buf.put(insertBackgroundStrLenPosHere,uint16(backgroundStrLenPos)); } ~PlayerBackgroundMsg() {} }; class HexGenericMsg : public StaticMsg { public: HexGenericMsg(string hexadecimalData) { m_buf.clear(); string output; CryptoPP::HexDecoder decoder; decoder.Attach( new CryptoPP::StringSink( output ) ); decoder.Put( (const byte*)hexadecimalData.c_str(), hexadecimalData.length() ); decoder.MessageEnd(); m_buf.append(output); } ~HexGenericMsg() {} }; class LoadWorldCmd : public StaticMsg { public: typedef enum { TUTORIAL = 0x00, SLUMS = 0x01, DOWNTOWN = 0x02, INTERNATIONAL = 0x03, ARCHIVE01 = 0x04, ARCHIVE02 = 0x05, ASHENCOURT = 0x06, DATAMINE = 0x07, SAKURA = 0x08, SATI = 0x09, WIDOWSMOOR = 0x0A, YUKI = 0x0B, LARGE01 = 0x0C, LARGE02 = 0x0D, MEDIUM01 = 0x0E, MEDIUM02 = 0x0F, MEDIUM03 = 0x10, SMALL03 = 0x11, CAVES = 0x12, } mxoLocation; LoadWorldCmd(mxoLocation theLoc,string theSky); ~LoadWorldCmd(); private: map locs; }; class SetOptionCmd : public StaticMsg { public: SetOptionCmd(string optionName,bool booleanVal) { InitialSetUp(optionName,TYPE_BOOL); uint32 intermediaryVal = 2; if (booleanVal) intermediaryVal=1; m_buf << sizeof(intermediaryVal); m_buf << intermediaryVal; } SetOptionCmd(string optionName,uint16 shortIntVal) { InitialSetUp(optionName,TYPE_UINT16); m_buf << sizeof(shortIntVal); m_buf << shortIntVal; } SetOptionCmd(string optionName,uint32 intVal) { InitialSetUp(optionName,TYPE_UINT32); m_buf << sizeof(intVal); m_buf << intVal; } SetOptionCmd(string optionName,string stringVal) { InitialSetUp(optionName,TYPE_STRING); if (stringVal.length() < 1) m_buf << uint16(0); else m_buf.writeString(stringVal); } SetOptionCmd(string optionName,vector stringVals) { InitialSetUp(optionName,TYPE_STRING); stringstream cummulative; foreach(const string &theStr,stringVals) { if (cummulative.str().length() > 1) cummulative << ","; cummulative << theStr; } string stringVal = cummulative.str(); if (stringVal.length() < 1) m_buf << uint16(0); else m_buf.writeString(stringVal); } ~SetOptionCmd() {} private: typedef enum { TYPE_BOOL = 0x11, TYPE_UINT16 = 0x1B, TYPE_UINT32 = 0x17, TYPE_STRING = 0x19, TYPE_STRINGLIST = 0x14, } varType; void InitialSetUp(string optionName,varType theType) { m_buf.clear(); m_buf << uint16(swap16(0x3A05)); m_buf << uint8(0); m_buf << uint16(theType); m_buf.writeString(optionName); } }; class SetExperienceCmd : public StaticMsg { public: SetExperienceCmd(uint64 theExp) { m_buf.clear(); m_buf << uint16(swap16(0x80e5)) << uint64(theExp); } ~SetExperienceCmd() {} }; class SetInformationCmd : public StaticMsg { public: SetInformationCmd(uint64 theCash) { m_buf.clear(); m_buf << uint16(swap16(0x80e4)) << uint64(theCash); } ~SetInformationCmd() {} }; class EventURLCmd : public StaticMsg { public: EventURLCmd(string eventURL) { m_buf.clear(); //81 a5 00 00 07 00 05 m_buf << uint16(swap16(0x81a5)) // can also be 81a9 << uint16(0) << uint16(7) << uint8(5); m_buf.writeString(eventURL); } ~EventURLCmd() {} }; struct MsgBlock { uint16 sequenceId; list subPackets; bool FromBuffer(ByteBuffer &source) { { uint16 theId; if (source.remaining() < sizeof(theId)) return false; source >> theId; sequenceId = swap16(theId); } uint8 numSubPackets; if (source.remaining() < sizeof(numSubPackets)) return false; source >> numSubPackets; subPackets.clear(); for (uint8 i=0;i> firstTwoBytes[0]; int sizeOfPacketSize = 1; if (firstTwoBytes[0] > 0x7F) { sizeOfPacketSize = 2; firstTwoBytes[0] -= 0x80; if (source.remaining() < sizeof(uint8)) return false; source >> firstTwoBytes[1]; } uint16 subPacketSize = 0; if (sizeOfPacketSize == 1) { subPacketSize = firstTwoBytes[0]; } else if (sizeOfPacketSize == 2) { memcpy(&subPacketSize,firstTwoBytes,sizeof(subPacketSize)); subPacketSize = swap16(subPacketSize); } if (subPacketSize<1) return false; vector dataBuf(subPacketSize); if (source.remaining() < dataBuf.size()) return false; source.read(&dataBuf[0],dataBuf.size()); subPackets.push_back(ByteBuffer(&dataBuf[0],dataBuf.size())); } return true; } bool FromBuffer(const byte* buf,size_t size) { ByteBuffer derp; derp.append(buf,size); derp.wpos(0); derp.rpos(0); return FromBuffer(derp) && (derp.remaining() == 0); } void ToBuffer(ByteBuffer &destination) { destination << uint16(swap16(sequenceId)); destination << uint8(subPackets.size()); for (list::iterator it=subPackets.begin();it!=subPackets.end();++it) { uint16 packetSize = it->size(); if (packetSize > 0x7f) { packetSize = htons(packetSize | 0x8000); destination << uint16(packetSize); } else { destination << uint8(packetSize); } destination.append(it->contents(),it->size()); } } uint32 GetTotalSize() const { uint32 startSize = sizeof(uint16)+sizeof(uint8); for (list::const_iterator it=subPackets.begin();it!=subPackets.end();++it) { startSize += it->size(); } return startSize; } }; class OrderedPacket : public StaticMsg { public: OrderedPacket() {m_buf.clear();} OrderedPacket(ByteBuffer &source) { m_buf.clear(); FromBuffer(source); } OrderedPacket(const byte* buf,size_t size) { m_buf.clear(); FromBuffer(buf,size); } OrderedPacket(MsgBlock justOneBlock) { m_buf.clear(); msgBlocks.push_back(justOneBlock); } bool FromBuffer(ByteBuffer &source) { uint8 zeroFourId=0; if (source.remaining() < sizeof(zeroFourId)) return false; source >> zeroFourId; if (zeroFourId != 0x04) return false; uint8 numOrderPackets=0; if (source.remaining() < sizeof(numOrderPackets)) return false; source >> numOrderPackets; if (numOrderPackets < 1) return false; msgBlocks.clear(); for (uint8 i=0;i::iterator it=msgBlocks.begin();it!=msgBlocks.end();++it) { it->ToBuffer(destination); } } public: const ByteBuffer& toBuf() { m_buf.clear(); ToBuffer(m_buf); return m_buf; } uint32 GetTotalSize() const { uint32 startSize = sizeof(uint8)*2; for (list::const_iterator it=msgBlocks.begin();it!=msgBlocks.end();++it) { startSize += it->GetTotalSize(); } return startSize; } list msgBlocks; }; #endif