> .net client framework for Eqemu
https://github.com/eqbrowser/unity-e...ient-framework
> README
.NET 3.5
No pinvokes
No use of Marshalling
100% managed eqemuauthcrypto implementation
- I had to override the default behavior of the DESCryptoServiceProvider. It has an internal check that is performed to
detect weak keys (aka, keys with terrible parity). By default, .NET won't let you use a crappy key (which is what the
emu uses prior to being patched). Put another way, I had to make DES even shittier to work with the emu!
- On this, more for information than anything else. I believe VI/Sony set the key to all 0s for dev and testing, and
then would patch in the encryption key whenever they pushed out patches. This wouldn't make it any more secure as
a hardcoded encryption key is totally worthless, but I think that was what they were doing.
ICSharpCodeSharpZipLib is being used for compression/decompression. As far as I know, it does not pinvoke so it should
be OK. You posted a link detailing a change that had to be made to work with Mono. I didn't make that change because I
don't have mono installed, so you'll have to do that part. Looked simple enough.
The current implementation uses asynchronous receives and sychronous sending. Receives currently have a single buffer, but this can be easily
expanded to multiple if the client starts dropping UDP packets. Sending is done synchronously on a separate thread to avoid impacting the UI
thread.
Receive operations are automatically assigned threads from the thread pool.
When a packet is received it goes through processing. This is where the CRC, decompression, fragment reconstruction, splitting
of opcombined packets, etc. is handled. The end result is either a packet that is handled by the core server code (e.g. an ACK)
or is transformed into an ApplicationPacket that is placed in an inbound queue. The application (e.g. the loginclient) will then
read from this queue, process the application packet, and do whatever it needs to do.
The application layer (e.g. the loginclient) has a thread that is responsible for reading inbound packets. This will prevent it from
locking the UI thread.
In my very awful test client I have a LoginClient and an EmuClient. This was a simple implementation of the steps for contacting the
Login Server and completing the login sequence. I am automatically selecting the first Emu server because it was simpler for testing
purposes. You'll want to use the event to populate the UI.
The current code to handle translation of hostname to IP is slow. IMO, this could do with a test to say, "Is this an IP already? If so, we're done"
instead of always trying to translate. Anyway, when the udp client shell test app starts, it'll take a bit before the menu displays.
The transition from Login Server to Emu is done as a manual step in the test client, again, because it was simpler. In practice, this handoff
is automatic (duh) and follows the steps I implemented (disconnect from login server, connect to emu, send sessionrequest, get sessionresponse,
send login)
- I haven't implemented the login packet due to time constraints, but the easiest way would be to look at the emu to see what the packet
should look like and what data is in it. My guess is you'll have to provide the 10 byte Session ID that is generated by the login server
and your login server player ID at a minimum.
- I may get to this part, but I'm not sure yet. If it has been implemented you'll know if I did or not. =P
I loaded all of the Titanium OpCodes already and wrote a couple of the struct types for the initial packets.
As a general rule, try to avoid creating new reference types unless you actually need them. The primary reason is to avoid periodic
bursts of lag due to GC. You can actually see this happening if you use windbg and sos. You can dump the heap and see how many types
are sitting on the heap, waiting for GC, etc. This doesn't mean you have to use object pools everywhere, just keep it in mind. If
performance becomes an issue, it'll be one area to examine (with windbg and sos.dll)
I haven't implemented opappcombined packets yet because I don't have any examples of them to work with. The emu looks like it can
receive them, but it doesn't appear to send them, so it shouldn't be a big deal for now. When I work out how to make them, I can
add that to the code.
I don't have a full grasp on the set session stats packets yet. I have a very minimal implementation so far (the first packet you send)
which should be OK for now. I did see that they get exchanged periodically, but I haven't analyzed them yet to learn how to set the
values correctly. I'll update them when I work that part out.
I implemented the OP_KeepAlive timer, so you shouldn't have to deal with that.
To send packets, just send an applicationpacket. The UDP client will do all of the necessary compression, fragmenting, opcombined,
sequencing, ACKing, etc. I tried to make it as fire and forget as possible.
Contributed by Daerath.