Register for your free account! | Forgot your password?

Go Back   elitepvpers > MMORPGs > Conquer Online 2 > CO2 Private Server
You last visited: Today at 12:31

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



[Question]New way of packet handling?

Discussion on [Question]New way of packet handling? within the CO2 Private Server forum part of the Conquer Online 2 category.

Reply
 
Old   #1
 
stealarcher's Avatar
 
elite*gold: 0
Join Date: Apr 2006
Posts: 231
Received Thanks: 94
[Question]New way of packet handling?

I have been thinking, and to me it seems that a lot of the packet handlers (especially LOTF) are pretty large. Would it take up more resources to do something more dynamic such as the following? This is just an example obviously. But the main concept is there. The void would be your PacketID, the Arg1 would be your data[]. And it simply calls the method immediately rather then going through a case?

Code:
    class Program
    {
        static void Main(string[] args)
        {
            string Void = Convert.ToString(Console.ReadLine());
            string Arg1 = Convert.ToString(Console.ReadLine());
            object[] Args = new object[1];
            Args[0] = Arg1;
            try
            {
                typeof(Program).InvokeMember(Void, BindingFlags.InvokeMethod, null, null, Args);
            }
            catch
            {
                Console.WriteLine("Missing Packet Handler " + Void);
            }
            Console.ReadKey();
        }
        public static void Chat(string Arg1)
        {
            Console.WriteLine("Chat Handler " + Arg1);
        }
        public static void General()
        {
            Console.WriteLine("General Data Handler");
        }
    }
stealarcher is offline  
Old 01/25/2011, 03:54   #2
 
elite*gold: 21
Join Date: Jul 2005
Posts: 9,193
Received Thanks: 5,376
Not thought of that concept before... so basically you'd do something like an enum for packets and then just do a try/catch trying to invoke a member of that name?


IE:

Enum PacketTypes: ushort
{
ItemUsage = 1009,
}

public void ItemUsage(Client Sender, byte[] Data)
{
//handle ItemUsage
}

Then in your receive packet do something like...

ushort Type = ReadUInt16(Data, 2);

Try to invoke the enumerated method for the type read

catch

print unknown packet needing to be handled.
pro4never is offline  
Old 01/25/2011, 03:58   #3
 
stealarcher's Avatar
 
elite*gold: 0
Join Date: Apr 2006
Posts: 231
Received Thanks: 94
yupp pretty much was the idea xD, but i thought it may use too many resources.

#edit, now that i think about it, it would still be the first method it tries to call, so its not really doing much extra searching, so i dont really see it causing too big of an issue. It may actually save some considering it doesnt have to go through a case or if

#edit #2
Further Example. if ur trying it, u have to add the using System.Reflection; at the top to get the bindingflags.invokemethod. Also if you wanted the handler in a different class, you could replace the typeof(program) with something such as typeof(packethandler)

Code:
        enum PacketType : ushort
        {
            ItemUsage = 1009,
        }
        public static unsafe void Handle(GameClient GC, byte[] PData)
        {
            int Position = 0;
            while (Position < PData.Length)
            {
                ushort PacketLength = BitConverter.ToUInt16(PData, Position);
                ushort PacketID = BitConverter.ToUInt16(PData, Position + 2);
                byte[] Data = new byte[PacketLength + 8];
                Buffer.BlockCopy(PData, Position, Data, 0, PacketLength + 8);
                PacketType PT = (PacketType)PacketID;
                object[] args = new object[1];
                args[0] = Data;
                try
                {
                    typeof(Program).InvokeMember(PT.ToString(), BindingFlags.InvokeMethod, null, null, args);
                }
                catch
                {
                    Console.WriteLine("Missing Packet Handler " + PacketID);
                }
            }
        }
        public static void ItemUsage(byte[] Data)
        {
            //Handle Item Usage here
        }
stealarcher is offline  
Old 01/25/2011, 08:02   #4
 
elite*gold: 20
Join Date: Oct 2010
Posts: 451
Received Thanks: 259
Lol, it's better than the traditional LOTF way of handling packets. =]
Switch statements seem to be the way to go atm, but this is another interesting way of doing it. You're right though, it MIGHT take more resources (though I don't see how, you're still calling methods and redirecting packets by some kind of identification).
FuriousFang is offline  
Old 01/25/2011, 09:43   #5


 
Korvacs's Avatar
 
elite*gold: 20
Join Date: Mar 2006
Posts: 6,125
Received Thanks: 2,518
Invoking is slightly more expensive and time consuming than calling it directly.
Korvacs is offline  
Old 01/25/2011, 13:03   #6
 
stealarcher's Avatar
 
elite*gold: 0
Join Date: Apr 2006
Posts: 231
Received Thanks: 94
Alrighty, thanks for the feedback guys.
stealarcher is offline  
Old 01/25/2011, 18:24   #7
 
_Emme_'s Avatar
 
elite*gold: 1142
Join Date: Aug 2006
Posts: 2,464
Received Thanks: 1,161
This is how I've always done it:

Kernel:
Code:
public delegate void PacketHandlerDelegate(BasePacket Packet, GameClient Client);
public static Dictionary<PacketType, PacketHandlerDelegate> PacketHandlerList = new Dictionary<PacketType, PacketHandlerDelegate>();
GameHandler:
Code:
RegisterPacketHandler(PacketType.GameConnectPacket, PacketHandler.HandleGameConnectPacket);

RegisterPacketHandler(PacketType.CreateCharacterPacket, PacketHandler.HandleCreateCharacterPacket);

RegisterPacketHandler(PacketType.DataPacket, PacketHandler.HandleDataPacket);


public static void RegisterPacket(PacketType Type, Kernel.PacketHandlerDelegate Handler)
        {
            Kernel.PacketHandlerList.Add(Type, Handler);
        }

GameReceive:
Code:
PacketBuffer Buffer = new PacketBuffer(Packet, Packet.Length);
                BasePacket NewBuffer;
                for (UInt16 i = 0; i < Buffer.Length; i += (UInt16)(NewBuffer.PacketLength + 8))
                {
                    UInt16 Length = Buffer.ReadUInt16(i);
                    if (Length <= Packet.Length - i)
                    {
                        NewBuffer = new BasePacket(Buffer.ReadSubPacket(i, Length));
                        PacketType Type = NewBuffer.PacketType;
                        if (Kernel.PacketHandlerList.ContainsKey(Type))
                            Kernel.PacketHandlerList[Type].Invoke(NewBuffer, Client);
                        else
                            IConsole.WriteLine(string.Format(HexDump("[Game] [Unknown Packet] {0}", NewBuffer.Buffer), Type), ConsoleColor.Red);
                    }
                    else
                        return;
                }

Then at the actual functions, all you need to do is:

Code:
public static void HandleGameConnectPacket(BasePacket Packet, GameClient Client)
{
}


Hope that helps!
_Emme_ is offline  
Old 01/25/2011, 19:10   #8
 
stealarcher's Avatar
 
elite*gold: 0
Join Date: Apr 2006
Posts: 231
Received Thanks: 94
nice, it seems to work better 4 u then switches then im assuming, since you have always done it that way. starting my own custom source just debating on the best way to do it. b4 I end up with something that cant hold 10 players lmao
stealarcher is offline  
Old 01/25/2011, 19:22   #9


 
Korvacs's Avatar
 
elite*gold: 20
Join Date: Mar 2006
Posts: 6,125
Received Thanks: 2,518
Invoking is a more expensive way of doing it theres no two ways about it, the performance gain is virtually none existant unless your switch is going to contain in excess of 60 or 70 statements.
Korvacs is offline  
Old 01/26/2011, 03:32   #10
 
stealarcher's Avatar
 
elite*gold: 0
Join Date: Apr 2006
Posts: 231
Received Thanks: 94
how many known packets are there that are received by the server now days, around 30-40?
stealarcher is offline  
Old 01/26/2011, 17:01   #11
 
_Emme_'s Avatar
 
elite*gold: 1142
Join Date: Aug 2006
Posts: 2,464
Received Thanks: 1,161
Quote:
Originally Posted by Korvacs View Post
Invoking is a more expensive way of doing it theres no two ways about it, the performance gain is virtually none existant unless your switch is going to contain in excess of 60 or 70 statements.
Again, if you're not planning on running a CO server for a living, but rather a way of learning how to program in a fun way, you don't always have to use the best way of doing it just for this case (in my opinion that is).

Sure, CO may not exceed ~70 packets, although if you're planning on bigger projects in the future you might want to learn other teqniques that can benefit for all kinds of solutions; because the way it is right now most of us know how to write a simple switch statement, so I defnitly think you should try different teqniques that may not benefit in this case, but will in the future.
_Emme_ is offline  
Old 01/26/2011, 17:07   #12


 
Korvacs's Avatar
 
elite*gold: 20
Join Date: Mar 2006
Posts: 6,125
Received Thanks: 2,518
For testing/experimental/learning purposes try it out yes, but using it for the sake of it is bad practice, your just coding in inefficiencies if you believe that method is the best you clearly have never tested it against a switch of equal size nor read material on tests which demonstrate that it is inefficient when compared to a switch if the number of entries is less than around 60/70.
Korvacs is offline  
Old 01/26/2011, 17:12   #13
 
elite*gold: 0
Join Date: Feb 2006
Posts: 550
Received Thanks: 81
make an interface with the void handlepacket, create an array store the index as an instance to an implemented interface, call the void from the interface that you get using the packet id as the index.
ChingChong23 is offline  
Old 01/26/2011, 18:42   #14
 
elite*gold: 0
Join Date: Sep 2008
Posts: 1,683
Received Thanks: 505
This is no new concept.

Code:
        private delegate void Arguments();
 
        private readonly IDictionary<PacketType, Arguments> Processors;
 
        public Processor()
        {
            Processors = new Dictionary<PacketType, Arguments>
                             {
                                 {PacketType.DataPacket, DataPacket},
                                 {PacketType.GameConnectPacket, GameConnectPacket},
                                  etc..
                             };
        }
 
        public void Process(byte[] _input, Client _client)
        {
            Packet = new PacketBuffer(_input);
            PacketType Type = (PacketType)Packet.Type;
            Arguments Handler;
            Processors.TryGetValue(Type, out Handler);
            if (Handler != null)
                Handler.Invoke();
            else
                Invoke.WriteLine("Designated handler for " + Type + " was not found.");
        }
Basser is offline  
Old 01/26/2011, 20:21   #15
 
unknownone's Avatar
 
elite*gold: 20
Join Date: Jun 2005
Posts: 1,013
Received Thanks: 381
Korv is right that there's no performance gain to get from this, but there is absolutely a gain otherwise (in terms of code management).

I'll just make clear on Korv's mention of invoking being expensive. In the case of the OPs example where he is using reflection to invoke a method by name, there is a clear measurable difference in performance - however, in the example of Emme's, where he is invoking a delegate, the performance difference is completely negligible. (There is a difference, but it's a few nanoseconds compared to a direct method call, of no concern at all). A delegate is essentially a function pointer, and has around the same cost as a virtual method call.

The additional performance cost in Emme's example comes from searching the dictionary for a value though. It's a relatively small cost, hardly relevant. The cost of accessing a dictionary is approx O(1). The same isn't true for a switch, as it needs to (potentially) fall through each case, so at worst will be O(n). (irrelevant unless you have thousands of cases still though). The dictionary approach scales better, and even with a small number of cases is very much a non-issue.

On Emme's code being "bad practice" (ignoring the static fields, which IS bad practice), certainly true if you're using it "for the sake of it", but you don't just use it for the sake of it. You use it because it's a proper object oriented approach to the problem which allows you to completely decouple your packet processor from any implementation details - leading to code which is easier to test, maintain and extend. Being bad practice couldn't be further from the truth - loosely coupled code is good practice. (You can potentially decouple a switch from implementation if done right, but I've not seen that around here yet.)

In the "big switch" approach I've seen in many sources on here, everything is tightly coupled, because the packet processing class depends on just about everything else (which is why people end up resorting to using static fields, because their code doesn't follow established OOP practices). It's impossible to unit test the packet processor, because it depends on the entire server, and can only be tested as a whole. That's completely bad practice by any standard, and if your reason for doing it is to shave a fraction of a percent off the performance of your application, I'd question why you're writing in C#.
unknownone is offline  
Thanks
1 User
Reply


Similar Threads Similar Threads
Play sound via Packet Send?? [Question String Packet]
07/14/2010 - CO2 Private Server - 5 Replies
Yow im trying to figure out why i cant play music with the string packet What im doin is; MyChar.Client.SendPacket(Game.Packet.String(MyCha r.UID, 20, Splitter)); My Packet is: public byte String(long CharId, byte Type, string name)
[Question] Packet data , packet editing ??
10/13/2009 - 9Dragons - 2 Replies
I would like to know : What is packet data? How do i get the address for hacking a item in game? How to use it ??
packet bot [QUESTION]
08/11/2009 - Kal Online - 10 Replies
well...is packetbot written in c++ or c#? and if there is anyone who could help me with it pls post here....i will give somthing in exchange :D



All times are GMT +2. The time now is 12:31.


Powered by vBulletin®
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2024 elitepvpers All Rights Reserved.