Ability Damage/Heals in Client Log

Discuss the development of the server, emulator, and related services.
Get the latest updates on new features and upcoming changes to Return of Reckoning.
Forum rules
Before posting on this forum, be sure to read the Terms of Service, Privacy Policy and Code of Conduct
Londo
Posts: 217

Ability Damage/Heals in Client Log

Post#1 » Thu Jan 15, 2015 11:09 am

After days and day of decyphering packets I have finally derived the algorithm used by mythic to encode damage information in packets.

The damage/heal information is packed into array of integers that expands with larger data (Supposedly to save bandwidth, as this is a very common packet). Original server emulator code done by Dyox does not have correct algorithm to encode damage information.

(Here is example of each field controlled individually)
Image

Here is the algorithm (Can be improved for speed).

Code: Select all

public static List<byte> Pack(List<int> values)
        {
            List<byte> bytes = new List<byte>();
            foreach (int val in values)
            {
                if (val == 0)
                {
                    bytes.Add(0);
                    continue;
                }
                else if (val == 1)
                {
                    bytes.Add(1);
                    continue;
                }
                else if (val == -1)
                {
                    bytes.Add(2);
                    continue;
                }

                int signedValue = val;
                if (val != 1)
                {
                    if (val > 0)
                        signedValue = signedValue - 1;
                    else
                        signedValue = -signedValue;
                }

                int bitCount = BitCount(signedValue);
                int bitCountRemaning = bitCount;
                int octetCount = 0;
                int c = 0;
                while (bitCountRemaning > 0)
                {
                    if (c == 0)
                        bitCountRemaning -= 6;
                    else
                        bitCountRemaning -= 7;
                    octetCount++;
                }

                int offset = 0;
                int shift = 6;
                for (int i = 0; i < octetCount; i++)
                {
                    int mask = CreateMask(offset, offset + shift);
                    int octet = (mask & signedValue) >> offset;

                    if (i == 0)
                    {
                        octet = octet << 1; //LSB is the sign bit on first octet

                        if (val > 0)//if value was positive, we need to set sign flag
                            octet |= 1 << 0; //1 for positive
                        else
                            octet &= ~(1 << 0); //0 for negative
                    }

                    if (i != (octetCount - 1)) //if not on last octet, set expansion bit
                        octet |= 0x80;

                    bytes.Add((byte)octet);
                    offset += shift;

                    if (i == 0) //first octet we write 6 bits, then 7 bits on rest
                        shift = 7;
                }
            }
            return bytes;
        }
public void SendAbilityEffect(Client client, Ability ability, AbilityResult abilityResult, Character from, Character target,
            int? hitAmount, int? absorbedAmount, int? mitigatedAmount, int? overhealedAmount)
        {
            MemoryStream stream = client.GetWriteBuffer();
            PacketUtil.WriteByte(stream, (byte)Opcode.F_CAST_PLAYER_EFFECT);
            PacketUtil.WriteUInt16(stream, (ushort)from.Client.CharacterID);
            PacketUtil.WriteUInt16(stream, (ushort)target.Client.CharacterID);
            PacketUtil.WriteUInt16(stream, (ushort)ability.ID);


            if (ability.IsHeal)
                PacketUtil.WriteByte(stream, (byte)0);
            else
                PacketUtil.WriteByte(stream, (byte)6);


            PacketUtil.WriteByte(stream, (byte)abilityResult); //  BLOCK = 4,  PARRY = 5,  EVADE = 6,  DISRUPT = 7,  MISS = 8,   CRITICAL = 9


            if (ability.IsHeal)
                PacketUtil.WriteByte(stream, (byte)2);
            else
            {
                if (absorbedAmount.HasValue && mitigatedAmount.HasValue)
                    if (hitAmount.Value == 0)
                        PacketUtil.WriteByte(stream, (byte)50);
                    else
                        PacketUtil.WriteByte(stream, (byte)43);
                else if (absorbedAmount.HasValue && !mitigatedAmount.HasValue)
                    PacketUtil.WriteByte(stream, (byte)111);
                else if (!absorbedAmount.HasValue && mitigatedAmount.HasValue)
                    PacketUtil.WriteByte(stream, (byte)122);
                else
                    PacketUtil.WriteByte(stream, (byte)195);
            }

            List<int> numsToSend = new List<int>();

            if (hitAmount.HasValue)
            {
                if (ability.IsHeal)
                    numsToSend.Add(-hitAmount.Value);
                else
                    numsToSend.Add(hitAmount.Value);

                if (ability.IsHeal && overhealedAmount.HasValue)
                    numsToSend.Add(-overhealedAmount.Value);
                else
                {
                    if (mitigatedAmount.HasValue && absorbedAmount.HasValue)
                    {
                        numsToSend.Add(-mitigatedAmount.Value);
                        numsToSend.Add(-absorbedAmount.Value);
                    }
                    else if (mitigatedAmount.HasValue && !absorbedAmount.HasValue)
                    {
                        numsToSend.Add(-mitigatedAmount.Value);
                    }
                    else if (!mitigatedAmount.HasValue && absorbedAmount.HasValue)
                    {
                        numsToSend.Add(0);
                        numsToSend.Add(-absorbedAmount.Value);
                    }
                }
            }

            foreach (byte octet in PacketUtil.Pack(numsToSend))
                PacketUtil.WriteByte(stream, octet);

            PacketUtil.WriteByte(stream, 0x00);
            client.SendPacket("F_CAST_PLAYER_EFFECT", stream, false, false);
        }
        private static int BitCount(int value)
        {
            int bitCount = 0;
            int r = value;
            while (r > 0)
            {
                r /= 2;
                bitCount++;
            }
            return bitCount;
        }

        private static int CreateMask(int a, int b)
        {
            int r = 0;
            for (int i = a; i <= b; i++)
                r |= 1 << i;

            return r;
        }


Last edited by Londo on Thu Jan 15, 2015 11:15 am, edited 2 times in total.

Ads
User avatar
Elven
Former Staff
Posts: 5161

Re: Ability Damage/Heals in Client Log

Post#2 » Thu Jan 15, 2015 11:10 am

Once again, amazing work! :D

User avatar
chaoscode
Posts: 202

Re: Ability Damage/Heals in Client Log

Post#3 » Thu Jan 15, 2015 5:28 pm

good work!

User avatar
Tesq
Posts: 5713

Re: Ability Damage/Heals in Client Log

Post#4 » Thu Jan 15, 2015 6:16 pm

sweept londo !! :D
Image

User avatar
Morf
Posts: 1247

Re: Ability Damage/Heals in Client Log

Post#5 » Thu Jan 15, 2015 7:36 pm

Great stuff Londo.
Morfee - Shaman / Mynnos - Kotbs / Grubod - Black Orc / Snubz - Squig Herder

Who is online

Users browsing this forum: Bing [Bot] and 2 guests