Differing Entity ID's

02/23/2011 22:24 shitboi#1
I just came to realize that the entity ID in spawn packets and the target ID in action packet.

I am not sure if the ID decode has outdated or what; i qouted prog4never's code for decoding coordinates and targetID
02/23/2011 23:11 Ian*#2
People give these identifiers different names obviously but there should be an Entity ID and Entity UID.

The Entity UID is what you use for your target parameter. ID is generic, it's like 1080001 is for a DB but 3923442 might be the UID for that specific ID.

UID is an int starting at byte 8.
02/24/2011 00:05 pro4never#3
Also fyi...

Monster uids are 300k-500k
Player uids are 1million++
Tnps are I THINK 100k-200k but I could be wrong. (been a while since I saw)

But yah. UID identifies the target and is used in almost all packets.

IE: their movement, actions, despawn packet, trade/team stuff, etc.
02/24/2011 00:21 CptSky#4
Can be usefull if you don't want that the client think that your monsters are NPC... From Eudemon Online, but the same on CO2.

Code:
/////////////////////////////////////////////////////////////////////
// ID空间
const OBJID	SCENEID_FIRST		= 000001;			// SCENE的第一个ID
const OBJID	SYSNPCID_FIRST		= 00001;			// SYSNPC的第一个ID
const OBJID	SYSNPCID_LAST		= 99999;			// SYSNPC的最后一个ID
const OBJID	DYNANPCID_FIRST		= 100001;			// DYNANPC的第一个ID
const OBJID	DYNANPCID_LAST		= 199999;			// DYNANPC的最后一个ID
const OBJID	SCENEID_LAST		= 299999;			// SCENE的最后一个ID

const OBJID	NPCSERVERID_FIRST	= 400001;			// NPC的第一个ID
const OBJID	MONSTERID_FIRST		= 400001;			// MONSTER的第一个ID
const OBJID	MONSTERID_LAST		= 499999;			// MONSTER的最后一个ID
const OBJID	PETID_FIRST			= 500001;			// PET的第一个ID
const OBJID	PETID_LAST			= 599999;			// PET的最后一个ID
const OBJID	NPCSERVERID_LAST	= 899999;			// NPC的最后一个ID

const OBJID TRAPID_FIRST		= 900001;			// 魔法陷阱的第一个ID
const OBJID MAGICTRAPID_FIRST	= 900001;			// 玩家魔法的第一个ID
const OBJID MAGICTRAPID_LAST	= 989999;			// 玩家魔法的最后一个ID
const OBJID SYSTRAPID_FIRST		= 990001;			// 系统陷阱的第一个ID
const OBJID SYSTRAPID_LAST		= 999999;			// 系统陷阱的最后一个ID
const OBJID TRAPID_LAST			= 999999;			// 魔法陷阱的最后一个ID

const OBJID PLAYER_ID_FIRST		= 1000000;			// Player的第一个ID
const OBJID PLAYER_ID_LAST		= 1999999999;		// Player的最后一个ID
const OBJID	CALLPETID_FIRST		= 2000000000;		// CALLPET的第一个ID
const OBJID	CALLPETID_LAST		= 3999999999;		// CALLPET的最后一个ID

const OBJID CLIENT_ID_FIRST		= 4000000000;		// 为客户端保留的ID空间
const OBJID MOUSE_PLAYER_ID		= 4000000001;		// 放NPC时在鼠标上显示

const OBJID _IDMAX_NPC	=999999;
02/24/2011 00:43 IAmHawtness#5
Quote:
Originally Posted by CptSky View Post
Can be usefull if you don't want that the client think that your monsters are NPC... From Eudemon Online, but the same on CO2.

Code:
const OBJID	PETID_FIRST			= 500001;			// PET的第一个ID
const OBJID	PETID_LAST			= 599999;			// PET的最后一个ID

const OBJID	CALLPETID_FIRST		= 2000000000;		// CALLPET的第一个ID
const OBJID	CALLPETID_LAST		= 3999999999;		// CALLPET的最后一个ID
Didn't know about these ids, that's kinda useful
02/24/2011 02:20 shitboi#6
ermmm, yes i noticed that UIDs are diffrent from IDs.

While i am storing char/mob spawn list, i did realize that mobs/guards' IDs are less than 999,999 while player IDs are more than 999,999. That is what helped me to build the 2 hashtables.

Anyways, my problem is that, when i look into the target UID in the action packet, Eg, thunder, The UID is a bit off as compared to the UID i have obtained through spawn packet.
02/24/2011 02:39 nTL3fTy#7
Quote:
Originally Posted by shitboi View Post
ermmm, yes i noticed that UIDs are diffrent from IDs.

While i am storing char/mob spawn list, i did realize that mobs/guards' IDs are less than 999,999 while player IDs are more than 999,999. That is what helped me to build the 2 hashtables.

Anyways, my problem is that, when i look into the target UID in the action packet, Eg, thunder, The UID is a bit off as compared to the UID i have obtained through spawn packet.
Are you decoding the magic attack information properly?
02/24/2011 02:51 Ian*#8
Quote:
Originally Posted by shitboi View Post
ermmm, yes i noticed that UIDs are diffrent from IDs.

While i am storing char/mob spawn list, i did realize that mobs/guards' IDs are less than 999,999 while player IDs are more than 999,999. That is what helped me to build the 2 hashtables.

Anyways, my problem is that, when i look into the target UID in the action packet, Eg, thunder, The UID is a bit off as compared to the UID i have obtained through spawn packet.

Thunder, and all magic attack packets are encrypted.
Regular melee attacks are not though.
02/24/2011 03:41 pro4never#9
Quote:
Originally Posted by shitboi View Post
ermmm, yes i noticed that UIDs are diffrent from IDs.

While i am storing char/mob spawn list, i did realize that mobs/guards' IDs are less than 999,999 while player IDs are more than 999,999. That is what helped me to build the 2 hashtables.

Anyways, my problem is that, when i look into the target UID in the action packet, Eg, thunder, The UID is a bit off as compared to the UID i have obtained through spawn packet.
As mentioned... skill usage is encrypted.


Here's some handy code from my proxy (pulled from tannels proxy)

Code:
 #region Encrypting
            Target += 0x746F4AE6;
            Target ^= User.UID;
            Target ^= 0x5F2D2463;
            Target = ((Target << 13) | (Target >> 19));

            ulong _X = X + 0xffff22ee;
            _X -= 0xffff0000;
            _X = ((_X << 15) | (_X >> 1));
            _X ^= 0x2ed6;
            _X ^= User.UID;
            X = (ushort)_X;

            ulong _Y = Y + 0xffff8922;
            _Y -= 0xffff0000;
            _Y = ((_Y << 11) | (_Y >> 5));
            _Y ^= 0xb99b;
            _Y ^= User.UID;
            Y = (ushort)_Y;
            ushort SkillId = S.ID;
            SkillId += 0xeb42;
            SkillId = (ushort)(SkillId << 13 | SkillId >> 0x3);
            SkillId = (ushort)(SkillId ^ User.UID);
            SkillId ^= 0x915d;
            #endregion
Simply reverse that for your decryption code.

Also...

Hashtables? Tannel much?
02/24/2011 11:53 shitboi#10
I actually reversed that and realized that the values are a bit off.
As for the hashtable part, that is a unsynchronised java direct access collection that do not give me too many exceptions, lol. I picked that only for simplicity's sake.

Anyways, i'll revisit my codes after i am done with my exam later. lol

EDIT:
i guess i'll stick this on before i leave; I do not think there is a problem with the decoding with skill at least. I am getting all the correct values for skills used.

@nTL3fTy: i believe i am decoding them properly.
@Ian : yes, i did realize that and had handled it

Code:
    public static class Action {

        public int len, packetType, timer, charID, targetID, coordX, coordY, actionType, actionValue; //action value also known as skill ID
        byte[] trailer;
        byte[] pac; //the packet

        public Action(byte[] p) {
            pac = p;
            len = Utility.getUShort(p, 0);
            packetType = Utility.getUShort(p, 2);
            timer = Utility.getInt(p, 4);
            charID = Utility.getInt(p, 8);
            targetID = Utility.getUShort(p, 12);
            coordX = Utility.getUShort(p, 16);
            coordY = Utility.getUShort(p, 18);
            actionType = Utility.getInt(p, 20); //2=meelee, 24=skill/magic
            if (actionType != 2) {
                //decode skill id
                short aValue = (short) (((long) p[24] & 0xFF) | (((long) p[25] & 0xFF) << 8));
                aValue ^= (short) (0x915d & 0xffff);
                aValue ^= (short) (charID & 0xffff);
                aValue = (short) ((aValue << 0x3 | aValue >> 0xd) & 0xffff);
                aValue -= 0xeb42;
                actionValue = aValue;

                targetID = decodeTarget(targetID, charID);
                coordX = decodeXCord(coordX, charID);
                coordY = decodeYCord(coordY, charID);
            } else {
                actionValue = Utility.getInt(p, 24);
            }
            trailer = new byte[p.length - 28];
            System.arraycopy(p, 24, trailer, 0, p.length - 28);
        }

        @Override
        public String toString() {
            return "Packet Length :" + len + "\ntype :" + packetType + "\nTimer :" + timer + "\nChar ID :" + charID + "\nTarget ID :"
                    + targetID + "\nCoordX :" + coordX + "\nCoordY :" + coordY + "\nAction Type :" + actionType + "\nAction Value :"
                    + actionValue + "\n";
        }

        public static int decodeTarget(int target, int id){
            //decode target id
                target = ((target >> 13) | (target << 19));
                target ^= 0x5F2D2463;
                target ^= id;
                target -= 0x746F4AE6;
                return target;
        }

        public static int decodeXCord( int x, int id){
            //decode X coordinate
                long X = x;
                X ^= (id & 0xffff);
                X ^= 0x2ed6;
                X = ((X << 1) | ((X & 0x8000) >> 15)) & 0xffff;
                X |= 0xffff0000;
                X -= 0xffff22ee;
                return (int)X;
        }

        public static int decodeYCord(int y, int id){
            //decode Y coordinate
                long Y = y;
                Y = Y ^ (id & 0xffff) ^ 0xb99b;
                Y = ((Y << 5) | ((Y & 0xF800) >> 11)) & 0xffff;
                Y |= 0xffff0000;
                Y -= 0xffff8922;
                return (int)Y;
        }

        public static int encodeTarget(int Target, int id){
            Target += 0x746F4AE6;
            Target ^= id;
            Target ^= 0x5F2D2463;
            Target = ((Target << 13) | (Target >> 19));
            return Target;
        }

        public static int encodeXCord(int xcord, int id){
            long _X = xcord + 0xffff22ee;
            _X -= 0xffff0000;
            _X = ((_X << 15) | (_X >> 1));
            _X ^= 0x2ed6;
            _X ^= id;
            return (int)_X;
        }

        public static int encodeYCord(int ycord, int id){
            long _Y = ycord + 0xffff8922;
            _Y -= 0xffff0000;
            _Y = ((_Y << 11) | (_Y >> 5));
            _Y ^= 0xb99b;
            _Y ^= id;
            return (int)_Y;
        }

        public static int encodeSkill(int skill, int id){
            short SkillId = (short) (skill & 0xffff);
            SkillId += 0xeb42;
            SkillId = (short)(SkillId << 13 | SkillId >> 0x3);
            SkillId = (short)(SkillId ^ id);
            SkillId ^= 0x915d;
            return SkillId;
        }

        public static byte[] buildSkillPacket(int timer, int id, int targetid, int xcord, int ycord, int actionValue){
            byte[] packet = new byte[36];
            System.arraycopy(Utility.Int16ToBytes(28), 0, packet, 0, 2);
            System.arraycopy(Utility.Int16ToBytes(1022), 0, packet, 2, 2);
            System.arraycopy(Utility.Int32ToBytes(timer), 0, packet, 4, 4);
            System.arraycopy(Utility.Int32ToBytes(id), 0, packet, 8, 4);
            System.arraycopy(Utility.Int32ToBytes(targetid), 0, packet, 12, 4);
            System.arraycopy(Utility.Int16ToBytes(xcord), 0, packet, 16, 2);
            System.arraycopy(Utility.Int16ToBytes(ycord), 0, packet, 18, 2);
            System.arraycopy(Utility.Int32ToBytes(24), 0, packet, 20, 4);
            //encode actionValue
            short skill = (short) actionValue;
            skill += 0xeb42;
            skill = (short)(skill << 13 | skill >> 0x3);
            skill = (short)(skill ^ (id & 0xffff));
            skill ^= 0x915d;
            System.arraycopy(Utility.Int32ToBytes(skill), 0, packet, 24, 4);
            System.arraycopy("TQClient".getBytes(), 0, packet, 28, 8);
            return packet;
        }
    }
02/24/2011 17:11 pro4never#11
Quote:
Originally Posted by shitboi View Post
I actually reversed that and realized that the values are a bit off.
As for the hashtable part, that is a unsynchronised java direct access collection that do not give me too many exceptions, lol. I picked that only for simplicity's sake.

Anyways, i'll revisit my codes after i am done with my exam later. lol

EDIT:
i guess i'll stick this on before i leave; I do not think there is a problem with the decoding with skill at least. I am getting all the correct values for skills used.

@nTL3fTy: i believe i am decoding them properly.
@Ian : yes, i did realize that and had handled it

Code:
    public static class Action {

        public int len, packetType, timer, charID, targetID, coordX, coordY, actionType, actionValue; //action value also known as skill ID
        byte[] trailer;
        byte[] pac; //the packet

        public Action(byte[] p) {
            pac = p;
            len = Utility.getUShort(p, 0);
            packetType = Utility.getUShort(p, 2);
            timer = Utility.getInt(p, 4);
            charID = Utility.getInt(p, 8);
            targetID = Utility.getUShort(p, 12);
            coordX = Utility.getUShort(p, 16);
            coordY = Utility.getUShort(p, 18);
            actionType = Utility.getInt(p, 20); //2=meelee, 24=skill/magic
            if (actionType != 2) {
                //decode skill id
                short aValue = (short) (((long) p[24] & 0xFF) | (((long) p[25] & 0xFF) << 8));
                aValue ^= (short) (0x915d & 0xffff);
                aValue ^= (short) (charID & 0xffff);
                aValue = (short) ((aValue << 0x3 | aValue >> 0xd) & 0xffff);
                aValue -= 0xeb42;
                actionValue = aValue;

                targetID = decodeTarget(targetID, charID);
                coordX = decodeXCord(coordX, charID);
                coordY = decodeYCord(coordY, charID);
            } else {
                actionValue = Utility.getInt(p, 24);
            }
            trailer = new byte[p.length - 28];
            System.arraycopy(p, 24, trailer, 0, p.length - 28);
        }

        @Override
        public String toString() {
            return "Packet Length :" + len + "\ntype :" + packetType + "\nTimer :" + timer + "\nChar ID :" + charID + "\nTarget ID :"
                    + targetID + "\nCoordX :" + coordX + "\nCoordY :" + coordY + "\nAction Type :" + actionType + "\nAction Value :"
                    + actionValue + "\n";
        }

        public static int decodeTarget(int target, int id){
            //decode target id
                target = ((target >> 13) | (target << 19));
                target ^= 0x5F2D2463;
                target ^= id;
                target -= 0x746F4AE6;
                return target;
        }

        public static int decodeXCord( int x, int id){
            //decode X coordinate
                long X = x;
                X ^= (id & 0xffff);
                X ^= 0x2ed6;
                X = ((X << 1) | ((X & 0x8000) >> 15)) & 0xffff;
                X |= 0xffff0000;
                X -= 0xffff22ee;
                return (int)X;
        }

        public static int decodeYCord(int y, int id){
            //decode Y coordinate
                long Y = y;
                Y = Y ^ (id & 0xffff) ^ 0xb99b;
                Y = ((Y << 5) | ((Y & 0xF800) >> 11)) & 0xffff;
                Y |= 0xffff0000;
                Y -= 0xffff8922;
                return (int)Y;
        }

        public static int encodeTarget(int Target, int id){
            Target += 0x746F4AE6;
            Target ^= id;
            Target ^= 0x5F2D2463;
            Target = ((Target << 13) | (Target >> 19));
            return Target;
        }

        public static int encodeXCord(int xcord, int id){
            long _X = xcord + 0xffff22ee;
            _X -= 0xffff0000;
            _X = ((_X << 15) | (_X >> 1));
            _X ^= 0x2ed6;
            _X ^= id;
            return (int)_X;
        }

        public static int encodeYCord(int ycord, int id){
            long _Y = ycord + 0xffff8922;
            _Y -= 0xffff0000;
            _Y = ((_Y << 11) | (_Y >> 5));
            _Y ^= 0xb99b;
            _Y ^= id;
            return (int)_Y;
        }

        public static int encodeSkill(int skill, int id){
            short SkillId = (short) (skill & 0xffff);
            SkillId += 0xeb42;
            SkillId = (short)(SkillId << 13 | SkillId >> 0x3);
            SkillId = (short)(SkillId ^ id);
            SkillId ^= 0x915d;
            return SkillId;
        }

        public static byte[] buildSkillPacket(int timer, int id, int targetid, int xcord, int ycord, int actionValue){
            byte[] packet = new byte[36];
            System.arraycopy(Utility.Int16ToBytes(28), 0, packet, 0, 2);
            System.arraycopy(Utility.Int16ToBytes(1022), 0, packet, 2, 2);
            System.arraycopy(Utility.Int32ToBytes(timer), 0, packet, 4, 4);
            System.arraycopy(Utility.Int32ToBytes(id), 0, packet, 8, 4);
            System.arraycopy(Utility.Int32ToBytes(targetid), 0, packet, 12, 4);
            System.arraycopy(Utility.Int16ToBytes(xcord), 0, packet, 16, 2);
            System.arraycopy(Utility.Int16ToBytes(ycord), 0, packet, 18, 2);
            System.arraycopy(Utility.Int32ToBytes(24), 0, packet, 20, 4);
            //encode actionValue
            short skill = (short) actionValue;
            skill += 0xeb42;
            skill = (short)(skill << 13 | skill >> 0x3);
            skill = (short)(skill ^ (id & 0xffff));
            skill ^= 0x915d;
            System.arraycopy(Utility.Int32ToBytes(skill), 0, packet, 24, 4);
            System.arraycopy("TQClient".getBytes(), 0, packet, 28, 8);
            return packet;
        }
    }
Targets are 4 byte uints, not 2 byte ushorts.

For simplicity sake here's my olllddd decryption code from my packethandler

Code:
 ushort SkillId = Convert.ToUInt16(((long)Data[24] & 0xFF) | (((long)Data[25] & 0xFF) << 8));
                                        SkillId ^= (ushort)0x915d;
                                        SkillId ^= (ushort)Client.UID;
                                        SkillId = (ushort)(SkillId << 0x3 | SkillId >> 0xd);
                                        SkillId -= 0xeb42;
                                        if (!Client.Skills.ContainsKey(SkillId))
                                            return;
                                        Target = ((Target >> 13) | (Target << 19));
                                        Target ^= 0x5F2D2463;
                                        Target ^= Client.UID;
                                        Target -= 0x746F4AE6;
                                        ushort TargetX = 0;
                                        ushort TargetY = 0;
                                        long xx = (Data[16] & 0xFF) | ((Data[17] & 0xFF) << 8);
                                        long yy = (Data[18] & 0xFF) | ((Data[19] & 0xFF) << 8);
                                        xx = xx ^ (Client.UID & 0xffff) ^ 0x2ed6;
                                        xx = ((xx << 1) | ((xx & 0x8000) >> 15)) & 0xffff;
                                        xx |= 0xffff0000;
                                        xx -= 0xffff22ee;
                                        yy = yy ^ (Client.UID & 0xffff) ^ 0xb99b;
                                        yy = ((yy << 5) | ((yy & 0xF800) >> 11)) & 0xffff;
                                        yy |= 0xffff0000;
                                        yy -= 0xffff8922;
                                        TargetX = Convert.ToUInt16(xx);
                                        TargetY = Convert.ToUInt16(yy);
Such a complete mess but w/e.
02/24/2011 20:16 shitboi#12
Ohh !!!! ... thank you to pointing out my mistake. Now that you mentioned it, it's too obvious . I am too used to auto complete. lol

Will test it out later.
02/24/2011 20:57 ImFlamedCOD#13
Code:
private uint ror32(uint value, int amount)
        {
            return ((value >> amount) | (value << (32 - amount)));
        }

        private uint rol32(uint value, int amount)
        {
            return ((value << amount) | (value >> (32 - amount)));
        }

        private ushort ror16(ushort value, int amount)
        {
            return (ushort)((value >> amount) | (value << (16 - amount)));
        }

        private ushort rol16(ushort value, int amount)
        {
            return (ushort)((value << amount) | (value >> (16 - amount)));
        }

        public void Decrypt(uint Seed)
        {

            uint uID = this.UID;
            ushort x = this.X;
            ushort y = this.Y;
            ushort spellID = this.SpellID;
            this.X = (ushort)(this.rol16((ushort)((x ^ 11990) ^ ((ushort)uID)), 1) - 8942);
            this.Y = (ushort)(this.rol16((ushort)((y ^ 47515) ^ ((ushort)uID)), 5) - 35106);
            this.SpellID = (ushort)(this.rol16((ushort)((spellID ^ 37213) ^ ((ushort)uID)), 3) - 60226);
            OpponentUID = (uint)Assembler.RollRight(OpponentUID, 13, 32);
            OpponentUID = (OpponentUID ^ 0x5F2D2463 ^ Seed) - 0x746F4AE6;
        }

// Assembler Code

    public class Assembler
    {
        public static int RollLeft(uint Value, byte Roll, byte Size)
        {
            Roll = (byte)(Roll & 0x1F);
            return (int)((Value << Roll) | (Value >> (Size - Roll)));
        }

        public static int RollRight(uint Value, byte Roll, byte Size)
        {
            Roll = (byte)(Roll & 0x1F);
            return (int)((Value << (Size - Roll)) | (Value >> Roll));
        }
    }
If you change the Rolls from using the ones above you can use them and cut out rol6 and the other never got around to it tho.

One originally from my first proxy thanks to Grabola helped me with it. I have a much more capable neater,cleaner version now but this one will work just as good.:)
02/25/2011 18:20 shitboi#14
Thanks for everyone's help, I realized where my problem lies (besides the one p4n pointed out).


EDIT: problem solved...
need to use right shift unsigned operator >>>


Code:
public static int decodeTarget(int target, int id){
            //decode target id
                target = ( (target >>> 13) | (target << 19)); //&0xffffffff ;
                target ^= 0x5F2D2463;
                target ^= (id & 0xffffffff);
                target -= 0x746F4AE6;
                return target;
        }