예제 #1
0
        public void SendPing()
        {
            m_Ping = (int)m_PingStopwatch.ElapsedMilliseconds;

            OutputMessage message = new OutputMessage();

            message.AddU8(ClientServerOpCodes.Ping);
            WriteToOutput(message);

            m_PingSent++;
            m_PingStopwatch.Restart();
        }
예제 #2
0
        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));
            }
        }
예제 #3
0
        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);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
        }
예제 #6
0
        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);
        }
예제 #7
0
        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);
            }
        }
예제 #8
0
        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);
        }
예제 #9
0
        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);
        }
예제 #10
0
        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);
        }
예제 #11
0
        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);
        }
예제 #12
0
        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;
            }
        }
예제 #13
0
        // 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;
            }
        }