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:
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:
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:
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:
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?
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:
Which the full class will read:
So now we get down to business. You will always see a method in the class named "parse", in our case:
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.
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:
New Revision:
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.
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:
Which means our final structure is:
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.
I will miss certain bits out, but for the most part the previous guide should cover it (AS3 Sorcerer and so on).
-
You must be registered for see links
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
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();
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
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.