|
You last visited: Today at 19:15
Advertisement
[D]Packet writer, reader and structures
Discussion on [D]Packet writer, reader and structures within the CO2 PServer Guides & Releases forum part of the CO2 Private Server category.
11/21/2014, 03:38
|
#1
|
elite*gold: 0
Join Date: Dec 2012
Posts: 1,761
Received Thanks: 950
|
[D]Packet writer, reader and structures
As I've decided to kinda write a new source in D, then I wanted to finish the packet structures before starting to write the server. I will be updating this thread with packet structures as I get further in development.
This could be used for people who might be interested in D, the packet structures (Although not offset based.) etc.
All packets will be based on patch 5515-5518 or any patches around there. In the future I might use the conditional compilation to have different versions for offsets. Gotta love D's version keyword.
Note: None of the packets has been tested in terms of server usage as of now, but they should be pretty much legit structures.
Packet writer/reader: (packet.d)
Code:
module packet;
import std.c.string;
version (Windows) {
private const string newLine = "\r\n";
}
else {
private const string newLine = "\n";
}
enum PacketType : ushort {
// Auth Packets ...
authrequest = 1086,
authresponse = 1055,
passwordseed = 1059,
// Game Packets ...
authmessage = 1052,
message = 1004
}
/**
* A data packet class.
*/
class DataPacket {
protected:
/**
* The data packet buffer.
*/
ubyte[] b;
/**
* The current read offset.
*/
size_t offset = 0;
/**
* Creates a new instance of DataPacket.
*/
this() { }
public:
/**
* Creates a new instance of DataPacket.
*/
this(ushort type, ushort size) {
assert(size < 1024);
write!ushort(size);
write!ushort(type);
}
/**
* Creates a new instance of DataPacket.
*/
this(ubyte[] buffer) {
assert(buffer !is null);
assert(buffer.length > 4);
b = buffer.dup;
}
/**
* Creates a new instance of DataPacket.
*/
this(DataPacket packet) {
assert(packet !is null);
assert(packet.plength > 4);
b = packet.b.dup;
}
/**
* Appends bytes to the buffer.
*/
void writeBuffer(ubyte[] buffer) {
b ~= buffer;
}
/**
* Writes an empty buffer until the specific offset.
*/
void writeEmpty(size_t toOffset) {
while (b.length < toOffset)
write!ubyte(0);
}
/**
* Writes a value to the buffer.
*/
void write(T)(T value) {
ubyte[] pBuffer = new ubyte[T.sizeof];
auto ptr = &value;
memcpy(pBuffer.ptr, ptr, T.sizeof);
writeBuffer(pBuffer);
}
/**
* Writes a string value to the buffer.
*/
void writeString(string value) {
writeBuffer(cast(ubyte[])value);
}
/**
* Reads a value from the buffer.
*/
auto read(T)() {
ubyte[] pBuffer = b[offset .. (offset + T.sizeof)];
T val;
memcpy(&val, pBuffer.ptr, T.sizeof);
offset += T.sizeof;
return val;
}
/**
* Reads a buffer value.
*/
ubyte[] readBuffer(size_t size) {
ubyte[] pBuffer = b[offset .. (offset + size)];
offset += size;
return pBuffer;
}
/**
* Reads a string value.
*/
string readString(size_t size) {
return cast(string)readBuffer(size);
}
/**
* Skips offsets for reading.
*/
void skip(size_t offsets = 1) {
offset += offsets;
}
/**
* Goes to a specific offset for reading.
*/
void go(size_t offset) {
this.offset = offset;
}
@property {
/**
* Gets the final buffer.
*/
ubyte[] buffer() {
ushort vlen = vlength;
while (b.length != vlen) {
write!ubyte(0);
}
return b;
}
/**
* Gets the physical length of the packet.
*/
size_t plength() {
return b.length;
}
/**
* Gets the virtual length of the packet.
*/
ushort vlength() {
size_t oldOffset = offset;
offset = 0;
ushort size = read!ushort;
offset = oldOffset;
return size;
}
/**
* Gets the packet type.
*/
ushort ptype() {
size_t oldOffset = offset;
offset = 2;
ushort p = read!ushort;
offset = oldOffset;
return p;
}
}
/**
* Gets the string of the packet.
*/
override string toString() {
import std.conv : to;
import std.string : format;
string s = format("Packet: %s P-Size: %s V-Size: %s", ptype, plength, vlength);
s ~= newLine;
s ~= "bytes[";
foreach (v; b) {
s ~= "0x" ~ to!string(v, 16) ~ ", ";
}
s.length -= 2;
s ~= "]";
s ~= newLine;
s ~= "text('";
foreach (v; b) {
s ~= (v >= 32 && v <= 126 ? cast(char)v : '.');
}
return s ~ "')";
}
}
/**
* A string packer class.
*/
class StringPacker {
public:
static:
/**
* Packs the strings into a packet.
*/
void pack(DataPacket packet, string[] strings) {
packet.write!ubyte(cast(ubyte)strings.length);
foreach (s; strings) {
if (s) {
packet.write!ubyte(cast(ubyte)s.length);
if (s.length)
packet.writeString(s);
}
else
packet.write!ubyte(0);
}
}
/**
* Unpacks strings from a packet.
*/
string[] unpack(DataPacket packet) {
string[] strings;
ubyte stringCount = packet.read!ubyte;
foreach (i; 0 .. stringCount) {
ubyte stringSize = packet.read!ubyte;
if (stringSize > 0) {
strings ~= packet.readString(stringSize);
}
else
strings ~= null;
}
return strings;
}
}
Auth packets:
authrequest.d
Code:
module authrequest;
import packet;
class AuthRequestPacket : DataPacket {
private:
string m_account;
string m_password;
public:
this(DataPacket packet) {
super(packet);
go(4);
m_account = readString(16);
go(132);
auto passbytes = readBuffer(16);
import std.array : replace;
string password = cast(string)passbytes; // DECRYPT THE BYTES ...
password = replace(password, "-", "0");
password = replace(password, "#", "1");
password = replace(password, "(", "2");
password = replace(password, "\"", "3");
password = replace(password, "%", "4");
password = replace(password, "\f", "5");
password = replace(password, "'", "6");
password = replace(password, "$", "7");
password = replace(password, "&", "8");
password = replace(password, "!", "9");
m_password = password;
}
@property {
string account() { return m_account; }
string password() { return m_password; }
}
}
authresponse.d
Code:
module authresponse;
import packet;
enum AccountStatus : uint {
banned,
invalidAccountOrPassword,
ready,
pointCardExpired = 6,
monthlyCardExpired = 7,
serverIsDown = 10,
pleaseTryAgainLater,
accountBanned,
serverIsBusy = 20,
serverIsBusyTryAgainLater,
accountLocked,
accountNotActivated = 30,
failedToActivateAccount = 31,
invalidInput = 40,
invalidInfo,
timedOut,
recheckSerialNumber,
unbound = 46,
used3LoginAttempts = 51,
failedToLogin,
databaseError = 54,
invalidAccountId = 57,
serversNotConfigured = 59,
serverLocked = 70,
accountLockedByPhone = 72
}
class AuthResponsePacket : DataPacket {
public:
this(uint entityUID, AccountStatus status, uint port, uint hash, string ip) {
assert(entityUID == 0 || entityUID >= 1000000);
assert(ip.length < 16);
super(PacketType.authresponse, 52);
write!uint(entityUID);
write!uint(status);
write!uint(port);
write!uint(hash);
writeString(ip);
}
}
passwordseed.d
Code:
module passwordseed;
import packet;
class PasswordSeedPacket : DataPacket {
public:
this(uint seed) {
super(PacketType.passwordseed, 8);
write!uint(seed);
}
}
Game packets:
authmessage.d
Code:
module authmessage;
import packet;
class AuthMessagePacket : DataPacket {
private:
uint m_entityUID;
uint m_key;
public:
this(DataPacket packet) {
super(packet);
go(4);
m_entityUID = read!uint;
m_key = read!uint;
}
@property {
uint entityUID() { return m_entityUID; }
uint key() { return m_key; }
}
}
message.d
Code:
module message;
import packet;
enum MessageType : uint {
talk = 2000,
whisper,
team,
guild,
clan,
friend = 2009,
center = 2011,
topleft,
ghost,
service,
tip,
world = 2021,
qualifier,
register = 2100,
entrance,
messageBox,
hawkMessage = 2104,
website,
guildWarFirst = 2108,
guildWarNext,
guildBullentin = 2111,
broadcast = 2500,
monster = 2600,
slideFromRight = 100000,
slideFromRightRedVib = 1000000,
whiteVibrate = 10000000
}
class MessagePacket : DataPacket {
private:
MessageType m_msgType;
uint m_color;
string m_from;
string m_to;
string m_msg;
uint m_time;
uint m_toMesh;
uint m_fromMesh;
public:
this(MessageType msgType, uint color, string fromMsg, string toMsg, string msg, uint time, uint toMesh, uint fromMesh) {
ushort size = cast(ushort)(fromMsg.length + toMsg.length + msg.length + 1 + 4 + 24);
super(PacketType.message, size);
write!uint(color);
write!uint(msgType);
write!uint(time);
write!uint(toMesh);
write!uint(fromMesh);
StringPacker.pack(this, [fromMsg, toMsg, null, msg]);
}
this(DataPacket packet) {
super(packet);
go(4);
m_color = read!uint;
m_msgType = cast(MessageType)read!uint;
m_time = read!uint;
m_toMesh = read!uint;
m_fromMesh = read!uint;
auto msgData = StringPacker.unpack(this);
m_from = msgData[0];
m_to = msgData[1];
m_msg = msgData[3];
}
@property {
MessageType messageType() { return m_msgType; }
uint color() { return m_color; }
uint time() { return m_time; }
uint toMesh() { return m_toMesh; }
uint fromMesh() { return m_fromMesh; }
string from() { return m_from; }
string to() { return m_to; }
string message() { return m_msg; }
}
}
That's all for now
|
|
|
11/21/2014, 04:25
|
#2
|
elite*gold: 21
Join Date: Jul 2005
Posts: 9,193
Received Thanks: 5,383
|
D gives me a headache... but gj?
|
|
|
11/21/2014, 12:59
|
#3
|
elite*gold: 0
Join Date: Dec 2012
Posts: 1,761
Received Thanks: 950
|
Quote:
Originally Posted by pro4never
D gives me a headache... but gj?
|
How does it give you a headache? It's pretty straight forward and has way better capability than C#.
|
|
|
11/21/2014, 16:23
|
#4
|
elite*gold: 0
Join Date: Mar 2008
Posts: 309
Received Thanks: 208
|
I fancied the idea of XML packet structures for versioning. A server, built once, could handle any client it has the structures for.
D is an interesting language.. what made you look into it?
I really like Haskell, but I fear it.. haha, I think I'm not smart enough to use the language. My professor knows the language and he explains it to be very robust for the sort of things I'm interested in.. Much more over C#, which is what I use now.
|
|
|
11/21/2014, 16:53
|
#5
|
elite*gold: 0
Join Date: Dec 2012
Posts: 1,761
Received Thanks: 950
|
Quote:
Originally Posted by .Ocularis
I fancied the idea of XML packet structures for versioning. A server, built once, could handle any client it has the structures for.
D is an interesting language.. what made you look into it?
I really like Haskell, but I fear it.. haha, I think I'm not smart enough to use the language. My professor knows the language and he explains it to be very robust for the sort of things I'm interested in.. Much more over C#, which is what I use now.
|
The only problem with the xml idea would be performance decrease and you really only want your server to run on specific patches and not a range of patches, because of feature changes between them.
I looked into D, because I wanted to learn a new language that I could use to build efficient thread-safe, concurrent applications such as web servers, so I dug into D with a focus on simple network programming and the structure of a webserver and really liked the language and its many features which most langauges today lack. Then I discovered vibe.d and got really hyped.
vibed.org
I started to use it as my main language and wrote a few interpreters and a simple language that compiled to C then to native, wrote an extension to the sfml library for D to support GUI programming and simplified event handling and interaction between gaming and GUI.
Such as this.
Code:
/**
MODULE: control.d
DESCRIPTION:
The control.d module wraps around the base control management.
*/
module dgui.control;
import dsfml.graphics : RenderWindow;
import dsfml.window;
import dgui.space;
import dgui.controlcontainer;
class EventHandler(T1,T2) {
private:
void function(T1,T2) F;
void delegate(T1,T2) D;
public:
this(void function(T1,T2) F) {
this.F = F;
}
this(void delegate(T1,T2) D) {
this.D = D;
}
void exec(T1 v1, T2 v2) {
if (F) F(v1,v2);
else if (D) D(v1,v2);
}
}
class Control {
private:
string m_name;
size_t m_layer;
bool m_enabled;
bool m_visible;
ControlContainer m_parent;
Rectangle m_rect;
protected:
@property {
void rect(Rectangle value) {
m_rect = value;
}
}
public:
this(string name) {
m_name = name;
m_layer = 0;
m_enabled = true;
m_visible = true;
m_rect = new Rectangle(0,0,0,0);
}
@property {
string name() { return m_name; }
size_t layer() { return m_layer; }
void layer(size_t value) {
m_layer = value;
if (m_parent)
m_parent.sortLayers();
}
bool enabled() { return m_enabled; }
void enabled(bool value) {
m_enabled = value;
}
bool visible() { return m_visible; }
void visible(bool value) {
m_visible = value;
if (m_parent)
m_parent.sortLayers();
}
ControlContainer parent() { return m_parent; }
void parent(ControlContainer value) {
if (m_parent)
m_parent.removeControl(this);
m_parent = value;
}
Rectangle rect() {
return m_rect;
}
}
void draw(RenderWindow window) { }
void boundPosition(Point p) { }
void unboundPosition(Point p) { }
void onKeyPressed(Keyboard.Key key) { }
void onKeyReleased(Keyboard.Key key) { }
void onMousePressed(Mouse.Button button) { }
void onMouseReleased(Mouse.Button button) { }
void onMouseMove(Point point) { }
Point getHorizontalPoint() {
return new Point(m_rect.x + m_rect.width, m_rect.y);
}
Point getVerticalPoint() {
return new Point(m_rect.x, m_rect.y + m_rect.height);
}
bool intersecting(Rectangle r) {
return intersect(m_rect, r);
}
}
Code:
module dgui.controls.label;
import std.conv;
import dsfml.system;
import dsfml.window;
import dsfml.graphics;
import dgui.control;
import dgui.image;
import dgui.space;
import dgui.color;
alias DGUIColor = dgui.color.Color;
alias DSFMLColor = dsfml.graphics.Color;
/**
A simple wrapper around the text class from dsfml.
This simplifies around text management, drawing, size and position.
*/
class Label : Control {
private:
/**
The text.
*/
Text m_text;
/**
The font.
*/
Font m_font;
/**
The character size.
*/
uint m_characterSize;
/**
The color.
*/
DGUIColor m_color;
public:
/**
Creates a new instance of Label.
*/
this(string name, string msg, Font font, uint characterSize = 14) {
super(name);
m_characterSize = characterSize;
m_font = font;
m_color = white;
text = msg;
}
@property {
/**
Gets the text.
*/
string text() {
return to!string(m_text.getString());
}
/**
Sets the text.
*/
void text(string value) {
m_text = new Text(to!dstring(value), m_font, m_characterSize);
m_text.position = Vector2f(rect.x, rect.y);
m_text.setColor(DSFMLColor(m_color.r, m_color.g, m_color.b, m_color.a));
auto size = m_text.getLocalBounds();
rect.size = new Capacity(cast(uint)size.width, cast(uint)size.height);
}
/**
Gets the position.
*/
Point position() {
return rect.position;
}
/**
Sets the position.
*/
void position(Point value) {
rect.position = value;
m_text.position = Vector2f(value.x, value.y);
}
/**
Gets the size.
*/
Capacity size() {
return rect.size;
}
/**
Gets the color.
*/
DGUIColor color() {
return m_color;
}
/**
Sets the color.
*/
void color(DGUIColor color) {
m_color = color;
m_text.setColor(DSFMLColor(color.r, color.g, color.b, color.a));
}
}
/**
Draws the label to a sfml RenderWindow.
*/
override void draw(RenderWindow window) {
window.draw(m_text);
}
/**
Sets bounding position.
*/
override void boundPosition(Point p) {
position = getBoundPosition(p.x, p.y, rect.x, rect.y);
}
private bool isIntersecting = false;
EventHandler!(Label,Mouse.Button) mousePressedEvent;
EventHandler!(Label,Mouse.Button) mouseReleasedEvent;
EventHandler!(Label,Point) mouseMoveEvent;
/**
Sets unbounding position.
*/
override void unboundPosition(Point p) {
position = getUnboundPosition(p.x, p.y, rect.x, rect.y);
}
override void onMousePressed(Mouse.Button button) {
if (!isIntersecting) return;
if (mousePressedEvent)
mousePressedEvent.exec(this,button);
}
override void onMouseReleased(Mouse.Button button) {
if (!isIntersecting) return;
if (mouseReleasedEvent)
mouseReleasedEvent.exec(this,button);
}
override void onMouseMove(Point point) {
isIntersecting = intersecting(new Rectangle(point, 1, 1));
if (mouseMoveEvent)
mouseMoveEvent.exec(this,point);
}
}
Code:
module main;
// D IMPORTS
import std.conv;
// DGUI Imports
import dgui.window;
import dgui.screen;
class MyScreen : Screen {
import dgui.color;
import dgui.controls.label;
import dgui.control : EventHandler;
import dsfml.window;
Label lblTest;
private:
void lblTest_mousePressed(Label lbl, Mouse.Button button) {
lbl.color = green;
}
void lblTest_mouseReleased(Label lbl, Mouse.Button button) {
lbl.color = red;
}
public:
this(string name) {
super(name);
string[] fontNames = ["verdana.ttf", "verdanab.ttf", "verdanai.ttf", "verdanaz.ttf"];
import dsfml.graphics.font;
import dgui.fonts;
Font font;
foreach (fname; fontNames) {
font = getFont(fname);
if (font)
break;
}
if (font) {
lblTest = new Label("lblTest", "Hello World!", font);
lblTest.mousePressedEvent = new EventHandler!(Label,Mouse.Button)(&lblTest_mousePressed);
lblTest.mouseReleasedEvent = new EventHandler!(Label,Mouse.Button)(&lblTest_mouseReleased);
addControl(lblTest);
}
}
}
/**
Entry point
*/
void main(string[] args)
{
auto window = new Window(800,600,"DGUI1");
// INIT GUI
window.addScreen(new MyScreen("MyScreen"));
window.open();
}
I have been looking at Rust and Go too, but didn't like their syntaxes as much.
|
|
|
11/22/2014, 06:45
|
#6
|
elite*gold: 0
Join Date: Feb 2014
Posts: 397
Received Thanks: 205
|
Quote:
Originally Posted by pro4never
D gives me a headache... but gj?
|
Ha.
|
|
|
11/23/2014, 12:04
|
#7
|
elite*gold: 20
Join Date: Mar 2006
Posts: 6,126
Received Thanks: 2,518
|
Why would there be a performance decrease when using XML packet structures? You just use the xml to build or populate a class you're not reading from them continually just when the server starts...
Also the whole multi patch support isn't very easy to implement there's a whole range of changes beyond just packet structures that you would need to account for, I dropped the concept in the end as the amount of changes would basically require you to build a base and then use plugins for handling the different changes in logic. It would be an exceptional amount of work, basically.
|
|
|
 |
Similar Threads
|
[Release] BTRF reader/writer source
01/24/2017 - Rappelz Private Server - 20 Replies
It was asked some time ago and Gr4ph0s asked too, for the source of the BTRF parser.
This project is a BTRF reader/writer that represent a model of these file. So it can write BTRF files, but you need to add data to blocks in order to write something in a file.
For more information about how to use it, see dll-client-cpp/main.cpp and dll-client-python/print-content.py for a python script.
The code is made using C++, so I don't expect so much contribution, but if someone want to...
|
Bin READER / WRITER [SOURCE]
04/06/2013 - WarRock - 7 Replies
Heyho,
Ich Release mal meine Decoder und Encoder Source für .bin Dateien.
Have fun :)
Multiupload.nl - upload your files to multiple file hosting sites!
Virustotal:
|
Packet Structures From XML
10/10/2011 - CO2 Private Server - 6 Replies
Not sure, if it works nor if I have done it right, but it looks correct to me.
However would it be a good thing to read packet structures from a xml file like this or is there better ways?
The reason I'm interested in it, it's because you do not need to open source to edit offsets nor build, if an offset is wrong or something.
The wrapper:
public class PacketStructure
{
|
[Q]Packet Structures
06/18/2010 - Kal Online - 10 Replies
any1 can help me with packet structures..? like
When I have packet like 0x11 or any other type.
Data is for example: 11 00 00 00 4A 58 9A 4A 32 ...
Where 4A 58 represents some WORD (coord, playerid, whatever)
etc.
thanks......
|
All times are GMT +1. The time now is 19:15.
|
|