Updating Packet Structures

Sledmore

Chaturbate Livestreamer
Staff member
FindRetros Moderator
Jul 24, 2010
5,194
3,901
It's been a long time since I wrote the previous guide. So I guess it's time I write this guide. Hopefully this is written in good enough quality, although I've done it in quite a rush.

I will miss certain bits out, but for the most part the previous guide should cover it (AS3 Sorcerer and so on).
-

Updating packet structures is very easy, after 3-5 times of doing it you'll no longer require looking at this guide. Now, let's begin.

In this tutorial I'll be using the following revisions:
  • PRODUCTION-201601012205-226667486 (My original PlusEMU release).
  • PRODUCTION-201609221203-707282381
I'll go through a couple of packets that I know have since changed.
PHP:
    class AvailabilityStatusComposer : ServerPacket
    {
        public AvailabilityStatusComposer()
            : base(ServerPacketHeader.AvailabilityStatusMessageComposer)
        {
            base.WriteBoolean(true);
            base.WriteBoolean(false);
        }
    }
PHP:
    class MessengerInitComposer : ServerPacket
    {
        public MessengerInitComposer()
            : base(ServerPacketHeader.MessengerInitMessageComposer)
        {
            base.WriteInteger(PlusStaticGameSettings.MessengerFriendLimit);//Friends max.
            base.WriteInteger(300);
            base.WriteInteger(800);
            base.WriteInteger(1100);
            base.WriteInteger(0); // category count
        }
    }
PHP:
    class ModeratorInitComposer : ServerPacket
    {
        public ModeratorInitComposer(ICollection<string> UserPresets, ICollection<string> RoomPresets, Dictionary<string, List<ModerationPresetActionMessages>> UserActionPresets, ICollection<SupportTicket> Tickets)
            : base(ServerPacketHeader.ModeratorInitMessageComposer)
        {
            base.WriteInteger(Tickets.Count);
            foreach (SupportTicket ticket in Tickets.ToList())
            {
                base.WriteInteger(ticket.Id);
                base.WriteInteger(ticket.TabId);
                base.WriteInteger(1); // Type
                base.WriteInteger(114); // Category
                base.WriteInteger(((int)PlusEnvironment.GetUnixTimestamp() - Convert.ToInt32(ticket.Timestamp)) * 1000);
                base.WriteInteger(ticket.Score);
                base.WriteInteger(0);
                base.WriteInteger(ticket.SenderId);
                base.WriteString(ticket.SenderName);
                base.WriteInteger(ticket.ReportedId);
                base.WriteString(ticket.ReportedName);
                base.WriteInteger((ticket.Status == TicketStatus.PICKED) ? ticket.ModeratorId : 0);
                base.WriteString(ticket.ModName);
                base.WriteString(ticket.Message);
                base.WriteInteger(0);
                base.WriteInteger(0);
            }

            base.WriteInteger(UserPresets.Count);
            foreach (string pre in UserPresets)
            {
                base.WriteString(pre);
            }

            base.WriteInteger(UserActionPresets.Count);
            foreach (KeyValuePair<string, List<ModerationPresetActionMessages>> Cat in UserActionPresets.ToList())
            {
                base.WriteString(Cat.Key);
                base.WriteBoolean(true);
                base.WriteInteger(Cat.Value.Count);
                foreach (ModerationPresetActionMessages Preset in Cat.Value.ToList())
                {
                    base.WriteString(Preset.Caption);
                    base.WriteString(Preset.MessageText);
                    base.WriteInteger(Preset.BanTime); // Account Ban Hours
                    base.WriteInteger(Preset.IPBanTime); // IP Ban Hours
                    base.WriteInteger(Preset.MuteTime); // Mute in Hours
                    base.WriteInteger(0);//Trading lock duration
                    base.WriteString(Preset.Notice + "\n\nPlease Note: Avatar ban is an IP ban!");
                    base.WriteBoolean(false);//Show HabboWay
                }
            }

            base.WriteBoolean(true); // Ticket right
            base.WriteBoolean(true); // Chatlogs
            base.WriteBoolean(true); // User actions alert etc
            base.WriteBoolean(true); // Kick users
            base.WriteBoolean(true); // Ban users
            base.WriteBoolean(true); // Caution etc
            base.WriteBoolean(true); // Love you, Tom

            base.WriteInteger(RoomPresets.Count);
            foreach (string pre in RoomPresets)
            {
                base.WriteString(pre);
            }
        }
    }

Okay, so starting from easy to "hard". Again, it's important to select match case on your text editor. So first, we search for the header in the AS3 Sorcerer scripts.

To make it easier, we search for the header in the following format "[PACKET_ID]", so in out case "[2468]". This will (in most times) bring us straight to the HabboMessages class, with a bunch of other packet IDs.

Result:
Code:
_-09d[2468] = _-Dz;

Okay, so to break that down the first part (which will always change) identifies one of the hash maps/dictionaries at the top in our case:
Code:
private static const _-09d:Map = new _-5vF();
private static const _-5Ii:Map = new _-5vF();
In our case, knowing this is useless - but it may help you get somewhat more familiar.

We just need to know the value, which is "_-Dz". This is the class, exactly where our packet structure is. So the next step is to find that.

Search for "class _-Dz" in your text editor (again, remember to have match case enabled in your text editor).

Result:
Code:
//------------------------------------------------------------
//_-51J._-Dz

package _-51J
{
    import _-6Pm._-3gB;
    import _-4Ie._-4rz;
    import _-6Pm.*;

    public class _-Dz extends _-3gB implements _-4LU 
    {
        public function _-Dz(_arg1:Function)
        {
            super(_arg1, _-4rz);
        }
        public function _-1EC():_-4rz
        {
            return ((_-3LD as _-4rz));
        }
    }
}//package _-51J

Okay, so I don't really have much to explain here. I only know a select bits regarding the SWF, I haven't ever bothered to learn everything - I can make a pretty accurate guess about this class, but won't be explaining much.

There is two ways we can find the packet structure here, look at both the first and second methods - notice what sticks out the most?

This class: "_-4rz", now you can simply do it this way. However I typically prefer to use the namespaces - I've always done it that way for around 2 years or so.

So you can simply search "class _-4rz" to find the packet structure. But hold that thought for now. An alternative way is to use the namespaces.

So how do we do this? it's always the second to last namespace. In our case?

Code:
_-4Ie._-4rz

You may have to search a couple of times, but you'll soon hit the packet structure class - which you may forget by the time you search, so the way to identify that you're in the right place?

Result:
Code:
//_-4Ie._-4rz
Which the full class will read:
Code:
//------------------------------------------------------------
//_-4Ie._-4rz

package _-4Ie
{
    import _-6Pm._-402;
    import _-6Pm.*;

    public class _-4rz implements for 
    {

        private var _-4iW:Boolean;
        private var _-6gh:Boolean;

        public function get isOpen():Boolean
        {
            return (this._-4iW);
        }
        public function get _-4jg():Boolean
        {
            return (this._-6gh);
        }
        public function flush():Boolean
        {
            this._-4iW = false;
            this._-6gh = false;
            return (true);
        }
        public function parse(_arg1:_-402):Boolean
        {
            this._-4iW = _arg1.readBoolean();
            this._-6gh = _arg1.readBoolean();
            return (true);
        }

    }
}//package _-4Ie

So now we get down to business. You will always see a method in the class named "parse", in our case:

Code:
        public function parse(_arg1:_-402):Boolean
        {
            this._-4iW = _arg1.readBoolean();
            this._-6gh = _arg1.readBoolean();
            return (true);
        }

And bingo - our packet structure. We now know that this packet has two booleans, however this is for our old revision - so we have to do the exact same process again in the new revision. I'm not going to show that process, as it's the exact same - and our thread will be too long, instead I'll just include the class.

Code:
//------------------------------------------------------------
//_-6bS._-2dx

package _-6bS
{
    import _-4vy._-3SP;
    import _-4vy.*;

    public class _-2dx implements _-5Jv 
    {

        private var _-0lw:Boolean;
        private var _-OK:Boolean;
        private var _-5iM:Boolean;

        public function get isOpen():Boolean
        {
            return (this._-0lw);
        }
        public function get _-0ZD():Boolean
        {
            return (this._-OK);
        }
        public function get _-2Ou():Boolean
        {
            return (this._-5iM);
        }
        public function flush():Boolean
        {
            this._-0lw = false;
            this._-OK = false;
            this._-5iM = false;
            return (true);
        }
        public function parse(_arg1:_-3SP):Boolean
        {
            this._-0lw = _arg1.readBoolean();
            this._-OK = _arg1.readBoolean();
            if (_arg1.bytesAvailable){
                this._-5iM = _arg1.readBoolean();
            };
            return (true);
        }

    }
}//package _-6bS

So again, all we need here is the parse method. We can see here that there are three booleans - need I say more? A new boolean needs adding to the bottom of your class. I'll have to go into finding the value etc another time.

Let's try the messenger.

Repeat the process. Here are both parse methods in the order of old revision to new revision.

Old Revision:
Code:
        public function parse(_arg1:_-402):Boolean
        {
            this._-O8 = _arg1._-4pl();
            this._-6I- = _arg1._-4pl();
            this._-1y0 = _arg1._-4pl();
            this._-0rL = _arg1._-4pl();
            var k:int = _arg1._-4pl();
            var k:int;
            while (k < k) {
                this._-0SH.push(new _-2h(_arg1));
                k++;
            };
            return (true);
        }

New Revision:
Code:
        public function parse(_arg1:_-3SP):Boolean
        {
            this._-8e = _arg1._-0qG();
            this._-4tz = _arg1._-0qG();
            this._-1QF = _arg1._-0qG();
            var k:int = _arg1._-0qG();
            var k:int;
            while (k < k) {
                this._-0X3.push(new _-3Bk(_arg1));
                k++;
            };
            return (true);
        }

So, we'll break down this one. I don't feel I need to explain how to identify a string, integer and boolean as it's straight forward (just look over the class, you can see within 5 seconds what is an integer or not).

The old structure is: INT, INT, INT, INT (count) { // }
The new structure is: INT, INT, INT, INT (count) { // }

So we simply need to remove one of the integers, again it's tricky to explain on how to find which one we need to remove - so we'll save that for now, just simply compare the classes to find out.

Another thing - we haven't completed the structure there, as we need to figure out what the structure inside the loop is.

Code:
while (k < k) {
                this._-0X3.push(new _-3Bk(_arg1));
                k++;
            };

Simply take the instance in the middle, where the argument is. "_-3Bk". It's pretty obvious that this is a class. So what do we do? Duh.

Search for "class _-3Bk" and bingo. The constructor contains the missing packet structure:
Code:
        public function _-3Bk(_arg1:_-3SP)
        {
            this._-6BE = _arg1._-0qG();
            this._name = _arg1.readString();
        }

Which means our final structure is:
Code:
INTEGER,
INTEGER,
INTEGER,
INTEGER (COUNT)
{
INTEGER,
STRING
}

And that about wraps it up. I was going to include the moderation packet, but I think this thread is already too long. If someone wants to do that and post it in the comments I'll happily answer if it's correct or not.

Thanks.
 

Seriosk

Programmer;
Oct 29, 2016
256
105
No... How i know the packets that changed, for after update it
Read the thread.. I don't think he can make it any clearer... seems to me your the kind of person who just wants to be told all in one sentence on how to do this..

P.S, Good thread.. you have just raised the community's independence to update packets by a lot..
 

Josemy

New Member
Apr 13, 2014
3
0
Read the thread.. I don't think he can make it any clearer... seems to me your the kind of person who just wants to be told all in one sentence on how to do this..

P.S, Good thread.. you have just raised the community's independence to update packets by a lot..
Your reading comprehension is not very good, I'm asking him, that to update structures, first you have to know what has changed (not explained) and then update them (if explained)
 

Seriosk

Programmer;
Oct 29, 2016
256
105
Your reading comprehension is not very good, I'm asking him, that to update structures, first you have to know what has changed (not explained) and then update them (if explained)
Hes given you an example of a few that have changed, the rest is down to you.. You should KNOW if a packet has been changed as it will be unhanded in your emulator if the ID is wrong..

Missing information can be found on this thread for as3sorcerer etc
 

Users who are viewing this thread

Top