Excellia - Networking Part 2: Event Verification/Handling
by, 8 August 2011 at 02:01 AM (3865 Views)
In part 1 I've told you about the procedure of encoding Events into Packets and Packets into ChannelBuffers as well as decoding ChannelBuffers into Packets and Packets into Events. Now I want to tell you more about how the actual handling of a decoded Event takes place.
Before I started writing this network system, I thought to myself "how can I write a quality system, that allows me to encode, decode, verify and handle Events in a compact but still highly extensible manner?". It could not be like most network utilities provide it, because that disables a lot of the features I wanted to add. So it had to be just what a RuneScape emulator needs. More specifically, it had to be just what Excellia needs. The pattern I had in mind, was to let the encoding and decoding of Packets and Events be handled in Netty's thread pool, and the actual verifying and handling by the server engine.
After putting some thoughts into it, I figured it was best to make a separate method for encoding, and for decoding and handling. Yet still, it had to be small, compact context. That's when I came up with 2 new classes: MessageUpstreamHandlerContext and MessageDownsteamHandlerContext.
The contexts are the classes that are bound to opcodes upon startup. When decoding a Packet into an Event, it loads the configured upstream context and calls the decode(...) method. Same goes for the downstream context with the encode(...) method when encoding an Event into a Packet. The handling, however, had to be done by the server engine so that there's not too much pressure on Netty's thread pool. Therefore, there's a small handler which processes the decoded Event by submitting a so-called ChannelMessageTask to the engine. Upon execution, the task acquires the corresponding upstream context again and calls the special handle(...) method which will iterate through all configured handlers and let them handle the Event.
When processing an Event the way I just described, the possibilities are many. To make it easier, I've written some new classes which assist in verifying and handling the Event. Come to think of it, they do not differ so much from one another. The classes EventVerifier and EventHandler are used to verify the data of the Event and handle the actual actions respectively. I'm also making good use of extensible systems, and attempt to apply it in many other forms. Here is how the handling of Events that indicate an item option has been clicked, would go:
Decodes the GamePacket into an ItemEvent. ItemEvent is an abstract class which implements the Event interface. The inheritors of ItemEvent each have their own values more specific to the option type (e.g. the ItemPickedUpEvent contains an additional X and Y coordinate of the location where the item was picked up).
Verifies that the player actually has the item the client says it has. Clients should never be trusted, therefore you should always check all info you receive from clients. In this case, the verifier does the following:
- Check if the reported interface ID is actually currently displayed to the player, then;
- Check if the reported slot is valid, so not negative and no higher than the maximum amount of slots in the displayed interface, then;
- Check if the reported item ID matches the actual item that the server has at the reported slot.
Once these checks are all valid, the handling will proceed, otherwise the data is discarded. Naturally it is possible to add more than one verifier to the context for more cleaner code. For example, with the wield-item option you could just add a WieldSkillRequirementHandler and WieldQuestRequirementHandler, which check for skill and quest requirements to wield an item respectively, right between the ItemVerifier and specific WieldHandler.
Handles the actual actions that need to be taken for the ItemEvent. To keep it all clean, the handler of i.e. wield options and pick-up options would be different than this one. WieldHandler and ItemPickedUpHandler respectively.
Hopefully this clarifies what was described before. As you can see, it's all very scalable and convenient. You can basically do whatever you like with this system, as long as you think with common sense about what needs to be done.
This system, for example, seems rather large and honestly it kinda is. But because of the smart way it has been set up it still runs far smoother than the average server out there. And this is not bragging or anything, because it took me very very long to think of a system like this.
I'm currently writing some Event handlers on this new system, to support me in future developments of actual content. Aside of that I also noticed there's a small bug within player updating. These are main priorities because it's just about the last thing that was required before writing actual content.
I thank to kindly for reading, and do not hesitate to ask any questions you might have.