DirectPlay Emulation Project

DirectPlay Emulation Project; support/discussion/questions

Moderator: thunderchero

User avatar
Flocke
BORG Trouble Maker
BORG Trouble Maker
Posts: 2546
Joined: Sun Apr 27, 2008 2:00 am
Location: Hamburg, Germany
Contact:

DirectPlay Emulation Project

Post by Flocke » Thu Sep 25, 2008 6:22 pm

Edit: DirectPlay Protocol-Layer Release Candidate 1 is out
Edit: This project for now is discontinued. You might still ask for the files if interested. Not sure when I find time for this again.. :(

About:
This version is the finished Layer of DirectPlay, still using DirectPlay without of any changes to the connection.
It is fully multiplayer compatible to unchanged versions and should work with any mod or BotF version.
(Of course without of solving the well known mod incompatibilities and version conflicts)
The only thing it is doing, is protocoling every DirectPlay call to a file named "MP DPNetworkEmulation-Log.txt" in same path as trek.exe.
There may occure false positive errors in the log, cause BotF often behaves in a try and error manner.
Anyway, there should not occure more or less crashes to BotF without of this Protocol-Layer.
This version is just intended to show that it is working and for beginning work on analysing the messages sent and received by BotF!!
A new Networkengine is to be expected, but I can't tell when. :)


Attention:
This version doesn't improve gameplay in any way yet, and even though it shouldn't, it may cause additional crashes.
Also, as you might have expected, I don't give any assurances or guarantees on it's behavior.
Its use is on your own risk and will ever be.

Anyway, as you trust me, I'm absolutely sure that it wouldn't cause any damage and there is no spyware, malware, trojan or anything the like included. (Well, you have to trust any modder that changes executable binary files like trek.exe or dlls or has it's own installer. Just prefer to make things clear in this bureaucratic country.)
If people are interested in the sourcecode, you may ask me. ;)


Install Instructions:
This version doesn't have an installer and you need to alter trek.exe with an hexeditor like HxD ( http://mh-nexus.de/en/hxd/ )!
But it's an easy task everyone is able to do, even if knowing nothing about hexediting and stuff.
First store your current version of trek.exe so you have a backup before hexediting anything and can always change back easily!
Then, after having created the backup, you just need to open trek.exe with the hexeditor, search for "ole32.dll", replace it with "dpemu.dll" and afterwards replace "dplayx.dll" with "dplemu.dll", that's it.
They should only be found once in trek.exe so with HxD you can just use the "Replace..." or in german "Ersetzen..." function in the "Search"/"Suchen" tab of HxD. Just a matter of some few seconds.
Of course you need to place the new dlls in the BotF execution path.

Now BotF should work as normal but log every DirectPlay message to the log file in mp.


Preview:
Progress now will concentrate on wrapping DirectPlay and supporting an Interface that can be used by the upcoming Networkengine as well.
Additonally, some of the initialisation calls of BotF will be handled internally and some protocol entries will get removed or deactivated.
Serial- and modem as well as IPX connections will get disabled.

Afterwards, RakNet is to be expected as the new Networkengine, being supported through the wrapper-class of DirectPlay.
RakNet will allow NAT punch through and bypass, so most or even all connection troubles should get solved without of additional NAT or modem or firewall configuration.
Firewalls shouldn't ask more but once for the game to pass through.
Cause RakNet doesn't seem to support changing its sleep duration after initialisation and for NAT punch through every millisecond counts when establishing a connection, it's not sure by now how much performance will get lost.
A server for establishing NAT punch through and bypass connections is already available and tested.
All multiplayer games except LAN games using the new Networkengine are thought to automatically try to establish the connection first with NAT punch through and afterwards with bypass.
It shouldn't matter if you use the network configuraion menus of BotF or a lobby system like WarZone to establish the connection.
All players will have to use the same Networkengine.
There might be an option added to stbof.ini to swap between Directplay and RakNet.

That's it for now. :)





Old stuff:
--------------------------------------------------------
First, I still can't assure that it will be possible to develope a new networkengine for botf.
But I've done some deeper research on it in the last few days (after getting shocked by the recent WarZone downtime).
And I've already had some promising success as well as some damn setbacks.
So, next comes the goals I'm aiming at.

Goals
:arrow: Solving most connection problems by supporting NAT punch-through as well as a stable bypass:
This would of cause require our own server, but I already know some people that are willing to provide us and we would find more for sure. :)
But it will also require adopting and wrapping a complete new networkengine for botf as well as supporting some kind of userinterface like a lobby-client.
So this would need alot of work and isn't to be expected in near future.

:arrow: Solving crashes and freezings on chat:
This might be (but doesn't have to be) more easy, cause it's just happening due to a wrong order of received messages.
For reordering, a layer between DirectPlay and botf as well as some analysis of the messages and data getting sent would be necessary.

:arrow: Speeding up the loading progress:
I'm sure that loading just takes so long cause of the big distance we all have to each other (and fiberglass cables already relativate the far distances through ocean). A savegame is very, very tiny, just a few kilobyte. As we know, it depends on the number of players, so it unnecessarily must get sent one by one. But it's still much too long!
I think they've implemented it by a loop of sending a few bytes, waiting on reply, sending next few bytes, waiting on reply and so on.
It should be possible to drastically shorten this and just tell botf it got received, temporarily buffer the content and send it to every player at once as a whole. That shouldn't have a much bigger delay than receiving a chat message.
It would require some analysis of the data getting sent, maybe some checks for requesting missing/corrupted (internally buffered) packages again, as far as not already covered by TCP/IP and Networkengine, and at least need a layer between botf and DirectPlay.

:arrow: Solving most of the mp specific crashes and allowing a stable timer:
This should be achievable by implementing a better synchronisation algorithm. It would at least require a layer between botf and DirectPlay as well as alot of research on the messages getting sent by botf between the computers. The timer currently is quite buggy, cause it's more likely that you'll do something just in time with the end of the turn and messages may loose order in the web.

:idea: Allowing additional people watching an active game:
This would at least need a layer between DirectPlay and botf, a complete new userinterface (cause botf probably can't be used for this without getting a Sync Error nearly every turn for the watching person) and it would require having analysed most of the data getting sent by botf so it can get parsed.
This goal is out of my personal intention, cause it would take lots and lots of work.

:idea: Allow developing a complete new AI:
Yes, I think this goal should become POSSIBLE, after having analysed every single bit botf sends and receives on mp. Possible, nothing more. :lol:
It's simply unexpectable if all data will ever be analysed so botf won't crash, but with implementing the AI as MP opponents, and with analysing 5 player games (so current AI won't disturb that much) or better games without of minors and all AI killed as well as no random events, it might become possible one time and I simply love that idea, although it's not part of my intention. :)

Maybe someone finds more goals but these seem to be more than enough for me. 8)

Analysing progress
So, what I've done so far is reading alot about DirectPlay, finding the old DirectX 7 SDK on http://www.vbgamer.de/vb/index.htm including the whole documentation of DirectPlay (just unpacked, didn't install)!
And I've been using Dependancy Walker from http://www.dependencywalker.com/ and HxD from http://mh-nexus.de/en/hxd/ to analyse trek.exe as well as dplayx.dll and ole32.dll that get used by botf.
The good: thing is, that with profiling trek.exe (so all dynamically loaded functions get logged by Dependancy Walker) it kept being DirectPlayCreate, DirectPlayLobbyCreateA in dplayx.dll and CoCreateInstance, CoInitialize, CoUninitialize in ole32.dll that are used by trek.exe. I've not tested this yet in really playing mp, but it should keep being just these five functions, with refering to the DirectPlay documentation and a tutorial found on web: http://www.gamedev.net/reference/articl ... cle764.asp
And these functions are well documented, including their function parameters and even headerfiles are available in SDK. :D
The bad: All my attempts to develope a layer so far failed and caused crashes. :(
The good: I'm still not out of ideas and I've already been able to compile my own first dll with http://www.codeblocks.org/ (MinGW distribution) that really got loaded and called by botf. ;)
And it's even enough to add the dlls to the botf folder, cause it always will look up in the installationpath first cause botf doesn't explicitly call the system dlls.
The bad: With reusing dplayx.dll or ole32.dll as names, these libs seem to be accessed by other libs being loaded by botf as well, cause of the same name, not forgetting about my layer needing the real dplayx.dll or ole32.dll. :cry:
The good: It's really easy to change the dll names that get loaded and used by botf. Just search the Hexcode of trek.exe for them and give them another name of same length. You may even be able to change the function names/adresses getting called by botf. :o
Anyway, it will require an edited trek.exe. :P
The bad: With using MinGW and GCC, the corresponding headerfiles dplay.h and dplobby.h, ole2.h->objbase.h already declare the functionnames used by botf with '__stdcall', not a problem for compilation but causing @[parametersize] appendancies to the names in the dll. Additionally DirectPlayEnumerate gets an ordinal of 1 instead of 8 like it has in the real dplayx.dll cause gcc automatically orders exports alphabetically by functionnames and isn't configurable on this. Not enough does hexediting the ordinal after compilation result still in wrong order for calls of trek.exe, not for Dependancy Walker. :x
The good: trek.exe always will just ask for a function by its name, or it's ordinal or its hint (another ordering number), and it's just using the ordinals for dplayx.dll and the hints or functionnames for ole32.dll as can be seen by Dependancy Walker. For debugging purposes it doesn't even matter if the right one with right parameterlist got called - trek.exe will crash after return. :mrgreen:
The bad: There will be lots of work to completely separate DirectPlay, including ole32 with it's com interfaces, cause they pass many functionpointers that may all be used by botf (luckily documented), and seperating DirectPlay requires replacing two libraries for botf, not one. But developing a layer or wrapper should not be split to two libraries! So there has to be a third library getting called by the two replacements and calling itself the real libs. Damn! :evil:


I think I'm not the onlyone interested in this, and as a documentation to myself I found starting a thread about would be a good idea.
Not to mention, well, yeah I'm sorry my approches in developing a savegamegenerator didn't find it's time yet! :roll:
And a new graphic engine, damn, when shall I do this? :oops:
What's about all my other projects and uni and other work?
Could anyone rent me some time please? 8O

cheers, Flocke

p.s. have I missed any smiley :?: oh yeah, this one :twisted: :!:

Edit: Oh, I've forgotten to tell about the -L parameter trek.exe gets called with by the WarZone client on launching. I tested this with a little trek.exe replacement and by calling trek.exe with this parameter (like -Mudd) by myself. You'll see that it works and the singleplayer button is deactivated.
BotF will then initialize DirectPlay, create a Lobby instance and determine all needed information for Direct IP connection (which are hold by DirectPlay, being initialized through and used by the LobbyClient itself), and even interact through DirectPlay with the LobbyClient in a way (the lobby client itself will query DirectPlay to determine the status, nothing more). I read about this in some of the documentations and it's always better to know how things are working before touching them! ^^
Last edited by Flocke on Wed Jul 10, 2013 5:44 am, edited 5 times in total.

User avatar
Spocks-cuddly-tribble
Code Master
Code Master
Posts: 723
Joined: Sun Apr 27, 2008 2:00 am

Post by Spocks-cuddly-tribble » Thu Sep 25, 2008 7:54 pm

An ambitious and praiseworthy project. I hope you'll find a way and assistance for that.
But since most of AFC members aren't programmers, all we can do is crossing fingers.
Is freibier's tentative appraisal of three years realistic?
On the verge of a nervous breakdown? Try the relaxing tribble sounds.

User avatar
thunderchero
Site Administrator aka Fleet Admiral
Site  Administrator aka Fleet Admiral
Posts: 6073
Joined: Fri Apr 25, 2008 2:00 am
Location: On a three month training mission, in command of the USS Valiant.
Contact:

Post by thunderchero » Thu Sep 25, 2008 11:52 pm

This sounds very promising I hope all the problems can be worked out.

this could be very useful :wink:

thunderchero

User avatar
Flocke
BORG Trouble Maker
BORG Trouble Maker
Posts: 2546
Joined: Sun Apr 27, 2008 2:00 am
Location: Hamburg, Germany
Contact:

Post by Flocke » Fri Sep 26, 2008 3:28 am

Spocks-cuddly-tribble wrote:Is freibier's tentative appraisal of three years realistic?
I feared someone would ask about a deadline. :roll:
Freibier has just been guessing, and that's ok but doesn't mean anything.
If I would think I'll need three years to get any improvement, I may better wait on Supremacy! :lol:

No, I don't think three years are realistic. He knows about my long time project of developing my own audioengine, that I've begun a few years ago, rebegun, and rewritten alot of times and it's still not finished, although I got it to play wave, ogg vorbis and mp3 in the recent weeks (and have nearly completely rewritten it in the last few months with a current total of some more than 10000 codelines). This project is and was my learning project for achieving better programming skills. I wouldn't have needed to reprogram it a single time and I won't do that again. I've learned alot about programming and now reached a state of it that I'm lucky with. It's using OpenAL for audiooutput and mpg123 for mp3 input and is now designed very flexible in an objectoriented and plugin-based manner. I aspire to finish this soundengine project in the next few month beside working on the networkengine project.
I've had many troubles at home and much to do for universaty - quite a hard time. :roll:
But with having my goals, I won't give up.
In real, sometime I want to become a professional gamedeveloper, maybe even independant, but currently that's just a long time dream.
What I've been aiming with my audioengine or soundengine or what to call, is creating my own gameengine - and I didn't found any good and already existing soundlibrary besides FMOD which is all but cheep for at least commercial use - so it should be well programmed, providing all I might need or may become needing lateron. Many people think, why developing your own? There are already free complete gameengines! Yes, there are, but I prefer a more flexible design, based upon a selection of task specific libraries, like Ogre for graphics and OpenAL for sound, etc.
And an own audioengine seemed to be a good starting to learn all I might need about programming and building my own base of a gameengine.

Now, that you know about this, you might understand a little better why Freibier came up with this 3 year appraisal. 8O
When developing a networkengine, eventually wrapping RakNet, I'll of course encapsulate it in a way that will allow me to easily reuse it for other tasks as well, maybe for my own gameengine lateron. But now I can fall back upon all my knowledge I gained by my audioengine project the first real project I ever started - all the programming before was just learning basics of alot of stuff, never designed for being reusable, remembering me on the attempts of BOTE (sorry, couldn't stop me *laugh*, I really love the BOTE project and I hate it on the other side, it's a great project and I don't really like a single peace of it :cry: call this envy, I dunno).

Oh, well, your question, when will it be finished? _No answer to that question_
So when? _hold on_
When?!? Men, you get nerving, I'm aiming different goals one by one, beginning with a layer between DirectPlay and trek.exe for logging purposes. If that's done, I may release the source to involve other people - programming isn't that hard and here are already people fluent speaking hexcode or reading assemblercode! I hope to get this done in the next few months or even more soon, then we'll see. It's not a project that has to be done in a whole!
With being able to log all the data and messages getting sent through the web or net, and maybe even supporting kind of a plugin system for altering the data just in time, there would be lots of work to do for all the modders being able or willing to read and analyse the logged hexcode of data that got sent and received by botf, allowing to achieve further goals. :)

User avatar
Flocke
BORG Trouble Maker
BORG Trouble Maker
Posts: 2546
Joined: Sun Apr 27, 2008 2:00 am
Location: Hamburg, Germany
Contact:

Post by Flocke » Fri Sep 26, 2008 4:27 am

Oh, two additional ideas I got:

:idea: Cheat protection:
With having analysed the data getting sent by botf, of course it would become possible to report on detected cheating! (With the exception of programmers that have the source to the new libraries, being able to alter the code and compile again.)
Although not intention, it might become useful.

:idea: Tournament-/League- Sytem:
With having a new client and our own server and having analysed the dataflow, it would become possible to implement a league-system with some additional tournament support.
A nice idea, but there are more worthy goals. ;)

trevtones
Commander
Commander
Posts: 347
Joined: Sat Apr 26, 2008 2:00 am
Location: The Canadian Union
Contact:

Post by trevtones » Fri Sep 26, 2008 6:38 am

Cant wait to try out BorgZone!!! :P
Don't let your reach exceed your grasp! :mad:

User avatar
Thunderchild
Ensign
Ensign
Posts: 28
Joined: Wed Apr 30, 2008 2:00 am

Post by Thunderchild » Fri Sep 26, 2008 8:23 am

What a about a function for viewing other battles if you don't have one? I think this would shorten the time for the uninvolved players.

User avatar
Flocke
BORG Trouble Maker
BORG Trouble Maker
Posts: 2546
Joined: Sun Apr 27, 2008 2:00 am
Location: Hamburg, Germany
Contact:

Post by Flocke » Fri Sep 26, 2008 8:43 am

Thunderchild wrote:What a about a function for viewing other battles if you don't have one? I think this would shorten the time for the uninvolved players.
Good point! Although it would partially fall under the "Allowing additional people watching an active game" category. It wouldn't need a gui, but it may require a new graphics engine so trek.exe can get workarounded and doesn't get messed up with batte events that didn't occure in real. As you know, moral get's affected by battles and may cause sync errors. But with letting the fight end in a draw, it may work without of a new graphicsengine.
That should be worth a try! :D
Edit: Wait, there's a problem with the host, I don't think this would work for the host without of workarounding by a new graphicsengine, cause he would start calculating the battle by real. So all would be able to watch with the exception of the host calculating the battles. Better workaround this by a new graphicsengine and allow everyone to watch the battles and probably even allow saving them as movies or making more screenshots or just store the parameters and let everyone rewatch the battles through the engine itself.

User avatar
Flocke
BORG Trouble Maker
BORG Trouble Maker
Posts: 2546
Joined: Sun Apr 27, 2008 2:00 am
Location: Hamburg, Germany
Contact:

Post by Flocke » Fri Sep 26, 2008 6:38 pm

Ok, I can tell now that BotF is using the IDirectPlay3A interface.
I've build a dll replacement for ole32.dll, implementing the three functions CoCreateInstance, CoInitialize and CoUninitialize.
Additionally I have build a replacement for dplayx.dll implementing the functions CreateDirectPlay and CreateDirectPlayLobby.

When launching through warzone, ole32.dll doesn't seem to get called but just CreateDirectPlayLobby, else CoInitialize will get called first, then CoCreateInterface followed by CreateDirectPlayLobby.

Currently it always crashes after the call to CreateDirectPlayLobby with a SEGFAULT, that means windows blocks accessing some memory. This might be caused by the functionpointers currently passed through the libs that I've not yet implemented.

But the functions that get called before crash get called right, containing expected data. By logging it to a textfile I already found out about the IDirectPlay3A interface being used.

Let's see what comes next...
I've a good feeling. :)

User avatar
Flocke
BORG Trouble Maker
BORG Trouble Maker
Posts: 2546
Joined: Sun Apr 27, 2008 2:00 am
Location: Hamburg, Germany
Contact:

Post by Flocke » Sat Sep 27, 2008 4:32 am

Strike!

I've build a first replacement for the DirectPlayLobby class, just letting popup some windows on getting called. I've passed it to botf instead of the instance I myself get by the real DirectPlay and yes, it's functionpointers got called without of a problem!
There was my main fear, now I'm quite sure it will be possible, I've just to implement some more stuff! :D

Hope to get first working prepreprealphatestversion.0001a soon.

User avatar
Flocke
BORG Trouble Maker
BORG Trouble Maker
Posts: 2546
Joined: Sun Apr 27, 2008 2:00 am
Location: Hamburg, Germany
Contact:

Post by Flocke » Sat Sep 27, 2008 10:00 am

Ok, another update.

I think I know now what has been causing the crashes. :?
As I've told, the access to DirectPlay is split to two libraries.
But different libraries, although if loaded by a single program, are recognized as different individual processes. And every process has it's own memory and if I try to access DirectPlay by two different libraries, splitting the initialisation, both will act on their own instances of DirectPlay.
So the second part of initialisation through the replaced dplayx.dll will miss the first part done by the replaced ole32.dll, that's why it always crashes there, now even within my own library before returning to botf.

This has something good and something bad.
It's good to know why it crashes and now I also know why DirectPlay is based upon the COM (Component Object Model) which is one solution to allow interprocess communication.
Having found out about this, now I'm very sure it will be possible to develope such an engine, with having explanations to all the strange behavior I've explored.
But, on the other hand, I've never needed interprocess communication before and that means I'll have to read a little about and learn how to do that before I can solve this. And I fear that's alot more work than expected...

Damn, couldn't it be just one dll? :?

User avatar
ketteringdave
Lieutenant-Junior Grade
Lieutenant-Junior Grade
Posts: 99
Joined: Sun Apr 27, 2008 2:00 am

Post by ketteringdave » Sat Sep 27, 2008 11:31 am

Flocke wrote:Hope to get first working prepreprealphatestversion.0001a soon.
I read this as "pre prep real phat test version" at first. :)

Seriously, impressive work. You lost me at "multiplayer."

User avatar
Flocke
BORG Trouble Maker
BORG Trouble Maker
Posts: 2546
Joined: Sun Apr 27, 2008 2:00 am
Location: Hamburg, Germany
Contact:

Post by Flocke » Sat Sep 27, 2008 7:23 pm

ketteringdave wrote:I read this as "pre prep real phat test version" at first. :)
LOL, that's a cool misread! :lol:

Ok, I've searched the web for the purpose of interprocess communication, in hope to find a better alternative to COM (that got depricated by .NET). But all I found were solutions based upon COM like OLE and ActiveX or the big damn .NET framework, which I don't want to use cause it's unnecessarily huge for this little purpose. I also found POSIX which can be ported from Linux to Windows, but seems to need some kind of emulation and who want's that? Me not.
So I'll stick with COM which is already needed to initialize DirectPlay anyway. I didn't like it that much, cause it is using registry keys for interprocess communication and I would prefer not to register anything to the registry!
But, then I've found Reg-Free COM.
Reg-Free COM is normal COM, the COM shipping since Windows XP, but first tries to obtain the necessary data by another file, a .manifest file, in the application directory before searching the registry. So with having a manifest file, there can't occure interferences within the registry. The only downcast of Reg-Free COM is that it doesn't ship with windows versions prior to Windows XP, but I think noone needs support for prior windows versions!

Here are two great links I've found about COM and Reg-Free COM:
http://www.codeguru.com/cpp/com-tech/ac ... php/c5567/
http://msdn.microsoft.com/en-us/magazine/cc188708.aspx

I can't tell how much time it'll take me to learn to use the COM model for our purposes, but I'll try to be fast. :)
If anyone has a better idea than using Reg-Free COM to link the two dlls together to another, single dll, please let me know about.

User avatar
Flocke
BORG Trouble Maker
BORG Trouble Maker
Posts: 2546
Joined: Sun Apr 27, 2008 2:00 am
Location: Hamburg, Germany
Contact:

Post by Flocke » Mon Sep 29, 2008 9:32 am

Ok, I've been wrong, I don't need COM, the fault is somewhere in my own code. It even crashes without of trek.exe in my own dplay test program.
And it's due to a specific class. I'll figure that out later. Just wanted to tell everyone about my stupidity :lol:
Ok, I really wasn't sure about multiple loads on a single dll being recognized as different instances or not. Now I know that they still are recognized as belonging to the single trek.exe process. Having put a global variable in the dll and incrementing it through both the other dlls did work as it should - both were acting on the same instance.

But having learned a little more about COM and dlls isn't bad anyway... :)

User avatar
Flocke
BORG Trouble Maker
BORG Trouble Maker
Posts: 2546
Joined: Sun Apr 27, 2008 2:00 am
Location: Hamburg, Germany
Contact:

Post by Flocke » Thu Oct 02, 2008 1:17 pm

Yesterday I had to give Dissy a good fight in MP, and well, these many connection problems told me again to continue work on the new networkengine project.
That many troubles really made me sick, we had to reload very often and always needed having a dozen attempts to get it loading...

Ok, it seem's as I've solved the bug that crashed my code. It always has been a corruped call stack and it seems as if it got corrupted by a directplay method in some way. DirectPlayLobbyCreateA to be exact. And I think I might know why. DirectPlayLobbyCreateA is giving a pointer to the new created LPDIRECTPLAYLOBBYA lobby-object but in real it's a polymorphism object of the type LPDIRECTPLAYLOBBY2A and has to be converted by calling the COM function QueryInterface on it. If having done this, the call stack doesn't seem to get corrupted anymore. I dunno why it get's currupted without calling it, but may have been some compiling issues without of it.

Now I'm progressing again and already am passing my own LPDIRECTPLAY3A class instance to botf as I've done with the LPDIRECTPLAYLOBBY2A class. And it get's called right as well, getting me a step forward.
But I've to solve method by method and this is still alot of work to get botf completely seperate from directplay and working again.

But it's just a matter of time now, I'm quite sure about...
If layer is done, it should be able to protocol every message and data send through directplay, besides eventually some registry keys that seem to get used by botf for connection info when launching through warzone, but that shouldn't matter and I could write/read them on my own or just ignore them.

Currently I'm just trying to get botf run again and actually often pass just the call parameters to directplay functions. :)

Post Reply

Return to “DirectPlay Emulation Project”

Who is online

Users browsing this forum: No registered users