public void SendPing() { m_Ping = (int)m_PingStopwatch.ElapsedMilliseconds; OutputMessage message = new OutputMessage(); message.AddU8(ClientServerOpCodes.Ping); WriteToOutput(message); m_PingSent++; m_PingStopwatch.Restart(); }
void AddChecksum(OutputMessage message) { if (ChecksumEnabled) { uint checksum = Adler32(message.GetBuffer().ToArray(), (uint)message.GetBufferLength()); int pos = message.Tell(); message.Seek(0); message.AddU32(checksum); message.IncreaseHeaderLength(sizeof(uint)); message.Seek(pos + sizeof(uint)); } }
public void SendSetTactics() { var optionStorage = OpenTibiaUnity.OptionStorage; OutputMessage message = new OutputMessage(); message.AddU8(ClientServerOpCodes.SetTactics); message.AddU8((byte)optionStorage.CombatAttackMode); message.AddU8((byte)optionStorage.CombatChaseMode); message.AddU8(optionStorage.CombatSecureMode ? (byte)1 : (byte)0); message.AddU8((byte)optionStorage.CombatPvPMode); WriteToOutput(message); }
private void XteaEncrypt(OutputMessage message) { AddMessageLength(message); int encryptedSize = message.GetBufferLength(); if ((encryptedSize % 8) != 0) { int n = 8 - (encryptedSize % 8); message.AddPaddingBytes(n); encryptedSize += n; } int indexedSize = message.GetBufferLength(); byte[] buffer = message.GetIndexedBuffer(indexedSize); int readPos = 0; while (readPos < encryptedSize / 4) { uint v0 = BitConverter.ToUInt32(buffer, readPos * 4); uint v1 = BitConverter.ToUInt32(buffer, (readPos + 1) * 4); uint delta = 0x61C88647; uint sum = 0; for (int i = 0; i < 32; i++) { v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + m_XteaKey[sum & 3]); sum -= delta; v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + m_XteaKey[sum >> 11 & 3]); } int tmpReadPos = 0; byte[] v0Array = BitConverter.GetBytes(v0); byte[] v1Array = BitConverter.GetBytes(v1); foreach (byte v in v0Array) { buffer[readPos * 4 + tmpReadPos++] = v; } foreach (byte v in v1Array) { buffer[readPos * 4 + tmpReadPos++] = v; } readPos += 2; } message.ReplaceIndexedBuffer(buffer); }
public void SendFollow(uint creatureID) { if (creatureID != 0) { m_Player.StopAutowalk(false); } OutputMessage message = new OutputMessage(); message.AddU8(ClientServerOpCodes.Follow); message.AddU32(creatureID); message.AddU32(creatureID); // Sequence WriteToOutput(message); }
public void SendGo(List <int> pathSteps) { if (pathSteps == null) { return; } m_CreatureStorage.ClearTargets(); OutputMessage message = new OutputMessage(); if (pathSteps.Count == 1) { switch ((PathDirection)(pathSteps[0] & 65535)) { case PathDirection.East: message.AddU8(ClientServerOpCodes.GoEast); break; case PathDirection.NorthEast: message.AddU8(ClientServerOpCodes.GoNorthEast); break; case PathDirection.North: message.AddU8(ClientServerOpCodes.GoNorth); break; case PathDirection.NorthWest: message.AddU8(ClientServerOpCodes.GoNorthWest); break; case PathDirection.West: message.AddU8(ClientServerOpCodes.GoWest); break; case PathDirection.SouthWest: message.AddU8(ClientServerOpCodes.GoSouthWest); break; case PathDirection.South: message.AddU8(ClientServerOpCodes.GoSouth); break; case PathDirection.SouthEast: message.AddU8(ClientServerOpCodes.GoSouthEast); break; default: return; } } else { int pathMaxSteps = (byte)System.Math.Min(byte.MaxValue, pathSteps.Count); message.AddU8(ClientServerOpCodes.GoPath); message.AddU8((byte)pathMaxSteps); int i = 0; while (i < pathMaxSteps) { message.AddU8((byte)(pathSteps[i] & 65535)); i++; } } WriteToOutput(message); }
public void Send(OutputMessage message) { if (m_Socket?.Connected != true) { return; } bool empty = m_MessageQueue.Count == 0; m_MessageQueue.Enqueue(message); if (empty) { publicSend(message); } }
public void SendUseOnCreature(UnityEngine.Vector3Int position, uint typeID, int positionOrData, uint creatureID) { if (position.x != 65535) { m_Player.StopAutowalk(false); } OutputMessage message = new OutputMessage(); message.AddU8(ClientServerOpCodes.UseObject); message.AddPosition(position); message.AddU16((ushort)typeID); message.AddU8((byte)positionOrData); message.AddU32(creatureID); WriteToOutput(message); }
public void SendUseTwoObjects(UnityEngine.Vector3Int firstPosition, uint firstID, int firstData, UnityEngine.Vector3Int secondPosition, uint secondID, int secondData) { if (firstPosition.x != 65535 || secondPosition.x != 65535) { m_Player.StopAutowalk(false); } OutputMessage message = new OutputMessage(); message.AddU8(ClientServerOpCodes.UseTwoObject); message.AddPosition(firstPosition); message.AddU16((ushort)firstID); message.AddU8((byte)firstData); message.AddPosition(secondPosition); message.AddU16((ushort)secondID); message.AddU8((byte)secondData); WriteToOutput(message); }
private void SendWorldName() { var index = WorldName.IndexOf("\n"); if (index > 0 && index != WorldName.Length - 1) { throw new Exception(@"ProtocolGame.SendWorldName: World name can't contain \n or \r\n."); } if (!WorldName.EndsWith("\n")) { WorldName += "\n"; } OutputMessage message = new OutputMessage(); message.AddString(WorldName, true); WriteToOutput(message, true); }
public void WriteToOutput(OutputMessage message, bool raw = false) { // TODO: move this to the message pool if (!raw) { if (XteaEnabled) { XteaEncrypt(message); } if (OpenTibiaUnity.GameManager.GetFeature(GameFeatures.GameProtocolChecksum)) { AddChecksum(message); } else if (OpenTibiaUnity.GameManager.GetFeature(GameFeatures.GameProtocolSequenceNumber)) { AddSequenceNumber(message); } AddMessageLength(message); } m_Connection?.Send(message); }
protected void SendLogin() { OutputMessage message = new OutputMessage(); message.AddU8(ClientLoginOpCodes.EnterAccount); message.AddU16(Utility.OperatingSystem.GetCurrentOs()); var gameManager = OpenTibiaUnity.GameManager; message.AddU16((ushort)gameManager.ProtocolVersion); if (gameManager.GetFeature(GameFeatures.GameClientVersion)) { message.AddU32((uint)gameManager.ClientVersion); } if (gameManager.GetFeature(GameFeatures.GameContentRevision)) { message.AddU16(Constants.ContentRevision); message.AddU16(0); } else { message.AddU32(Constants.DatSignature); } message.AddU32(Constants.SprSignature); message.AddU32(Constants.PicSignature); if (gameManager.GetFeature(GameFeatures.GamePreviewState)) { message.AddU8(0x00); } int offset = message.Tell(); var random = new System.Random(); if (gameManager.GetFeature(GameFeatures.GameLoginPacketEncryption)) { message.AddU8(0); // first byte must be zero GenerateXteaKey(random); AddXteaKey(message); } if (gameManager.GetFeature(GameFeatures.GameAccountNames)) { message.AddString(AccountName); } else { message.AddU32(uint.Parse(AccountName)); } message.AddString(Password); int paddingBytes = Crypto.RSA.GetRsaSize() - (message.Tell() - offset); for (int i = 0; i < paddingBytes; i++) { message.AddU8((byte)random.Next(0xFF)); } if (gameManager.GetFeature(GameFeatures.GameLoginPacketEncryption)) { Crypto.RSA.EncryptMessage(message); } if (gameManager.GetFeature(GameFeatures.GameOGLInformation)) { message.AddU8(1); message.AddU8(1); if (gameManager.ClientVersion >= 1072) { message.AddString(string.Format("{0} {1}", OpenTibiaUnity.GraphicsVendor, OpenTibiaUnity.GraphicsDevice)); } else { message.AddString(OpenTibiaUnity.GraphicsDevice); } message.AddString(OpenTibiaUnity.GraphicsVersion); } if (gameManager.GetFeature(GameFeatures.GameAuthenticator)) { offset = message.Tell(); message.AddU8(0); message.AddString(string.Empty); // no auth-token message.AddU8(0); // stay logged-in for a while paddingBytes = Crypto.RSA.GetRsaSize() - (message.Tell() - offset); for (int i = 0; i < paddingBytes; i++) { message.AddU8((byte)random.Next(0xFF)); } Crypto.RSA.EncryptMessage(message); } if (gameManager.GetFeature(GameFeatures.GameProtocolChecksum)) { ChecksumEnabled = true; } WriteToOutput(message); if (gameManager.GetFeature(GameFeatures.GameLoginPacketEncryption)) { XteaEnabled = true; } }
// TODO: use a pool instead // and confirm the encryption of the packet ONLY on a successful sent // This is working, but using a pool is more of a robust public void SendLoginPacket(uint challengeTimestamp, byte challengeRandom) { OutputMessage message = new OutputMessage(); message.AddU8(ClientServerOpCodes.PendingGame); message.AddU16(Utility.OperatingSystem.GetCurrentOs()); var gameManager = OpenTibiaUnity.GameManager; message.AddU16((ushort)gameManager.ProtocolVersion); if (gameManager.GetFeature(GameFeatures.GameClientVersion)) { message.AddU32((uint)gameManager.ClientVersion); } if (gameManager.GetFeature(GameFeatures.GameContentRevision)) { message.AddU16(Constants.ContentRevision); } if (gameManager.GetFeature(GameFeatures.GamePreviewState)) { message.AddU8(0); } int offset = message.Tell(); message.AddU8(0); // first byte must be zero; var random = new System.Random(); if (gameManager.GetFeature(GameFeatures.GameLoginPacketEncryption)) { GenerateXteaKey(random); AddXteaKey(message); message.AddU8(0x00); // gm } if (gameManager.GetFeature(GameFeatures.GameSessionKey)) { message.AddString(SessionKey); message.AddString(CharacterName); } else { if (gameManager.GetFeature(GameFeatures.GameAccountNames)) { message.AddString(AccountName); } else { message.AddU32(uint.Parse(AccountName)); } message.AddString(CharacterName); message.AddString(Password); if (gameManager.GetFeature(GameFeatures.GameAuthenticator)) { message.AddString(AuthenticatorToken); } } if (gameManager.GetFeature(GameFeatures.GameChallengeOnLogin)) { message.AddU32(challengeTimestamp); message.AddU8(challengeRandom); } int paddingBytes = Crypto.RSA.GetRsaSize() - (message.Tell() - offset); for (int i = 0; i < paddingBytes; i++) { message.AddU8((byte)random.Next(0xFF)); } if (gameManager.GetFeature(GameFeatures.GameLoginPacketEncryption)) { Crypto.RSA.EncryptMessage(message); } if (gameManager.GetFeature(GameFeatures.GameProtocolChecksum)) { ChecksumEnabled = true; } WriteToOutput(message); if (gameManager.GetFeature(GameFeatures.GameLoginPacketEncryption)) { XteaEnabled = true; } }