goto-bus-stop / aocmultiny Goto Github PK
View Code? Open in Web Editor NEW[wip] Tiny NAT-traversing Age of Empires 2 Multiplayer client.
License: GNU General Public License v3.0
[wip] Tiny NAT-traversing Age of Empires 2 Multiplayer client.
License: GNU General Public License v3.0
The DirectPlay library parts can be pretty useful for other apps too (especially because there is hardly any documentation for DirectPlay lobbying) so it could be published as a standalone library. It'd need a bit more work though because currently it only deals with the data structures necessary to start a lobbyable application, and not actually running a game and keeping it alive.
Currently dplib hardcodes TCP/IP or libnice service provider addresses, which is a bit restrictive (although you're unlikely to use anything other than TCP/IP from the defaults, but who knows).
Idea:
Shorthands for common stuff:
DPAddress::ip("164.145.25.145"); // โ tcp/ip address with a specific IP
DPAddress::ip(); // tcp/ip address with empty IP, for hosting sessions
Address builder for other stuff:
class DPAddress {
public:
DPAddress (GUID serviceProviderGuid);
DPAddress* add (GUID dataType, void* data, int dataSize);
DPAddress* add (GUID dataType, string str) {
return add(dataType, str.c_str(), str.length());
}
};
// tcp/ip address with an IP component
new DPAddress(DPSPGUID_TCPIP)
->add(DPAID_INet, "164.145.25.145");
// libnice service provider address with custom signaling and STUN servers, and a known host SDP
new DPAddress(DPSPGUID_NICE)
->add(DPAID_ICESignalingServer, "aocmultiny.net:7788")
->add(DPAID_ICETURN, "turn.l.google.com:6345")
->add(DPAID_ICESDP, hostSdp, hostSdpLen);
// or even, but not sure if this is doable with types and stuff:
new DPAddress(DPSPGUID_NICE, {
{ DPAID_ICESignalingServer, "aocmultiny.net:7788" },
{ DPAID_ICETURN, "turn.l.google.com:6345" },
{ DPAID_ICESDP, hostSdp, hostSdpLen },
});
So it's easy to access & not easy to accidentally make multiple
This would likely be a separate library, but documenting here so I don't forget:
A mod manager for AoC for data mods and visual mods. Existing data mods can be combined together by diffing the various mods with the original data files, and stacking the diffs.
(A new JSON-based data format could be nice too on top of that.)
Maybeee
A DPSession will represent a single game session, and the DPLobby class will map to DirectPlay's own lobby stuff with some sugar sprinkled on top.
Currently:
auto lobby = new DPLobby(new DPGameAoC(), "Player name");
lobby->host();
lobby->launch();
Maybe-future:
auto lobby = new DPLobby();
auto game = new DPGameAoC();
auto session = lobby->hostSession(game);
session->launch();
// maybe?
auto session = lobby->joinSession(game, address, sessionGuid);
session->launch();
I put an MIT thing on this first but I think I want to go a more copyleft direction. Probably GPL for the final application, and LGPL for the library bits (dplib, maaaybe nicesp?).
Will put GPL on the repo for now, the library bits could be switched to a more permissive license later.
To ensure that players all have the same game version, it'd be good to provide (optionally, ideally) a UserPatch installer. This shouldn't overwrite anything (eg. a Vooblyfied aoc should still work with voobly). I'm not sure if running the UP setup on a Vooblyfied aoc works or if it needs an original exe.
If UP setup works on Vooblyfied installs, aocmultiny can just ship a UP setup and run it, and revert to a backup when the game is finished.
Another option is to then move the UP executable to eg. age2_x1.aocmultiny.exe
and add a DirectPlay registry entry for it. That might also make switching game types easier in the future (eg. to support exe mods like Forgotten Empires)
New thing for dplib: a base class for DPlay service providers. DPServiceProvider would be a wrapper around IDirectPlaySP, minus the Get- and SetSPData methods (which will be used to associate the DPServiceProvider to IDirectPlaySP instances internally).
Implement Service Provider callbacks as virtual methods in the subclass.
class MyServiceProvider: public dplib::DPServiceProvider {
private:
SomeProxiedConnection connection;
public:
virtual HRESULT Open (DPSP_OPENDATA* data) {
// Can use `this` to store stuff, instead of SetSPData and GetSPData.
this->connection.open("http://myproxy.com");
return DP_OK;
}
virtual HRESULT Send (DPSP_SENDDATA* data) {
this->connection.send(data->idPlayerTo, data->lpMessage, data->dwMessageSize);
return DP_OK;
}
};
Then, SPInit
will be something like:
HRESULT WINAPI SPInit (SPINITDATA* data) {
auto sp = new MyServiceProvider(data);
return sp->init();
}
DPServiceProvider could also provide overloads for hooks. Eg, it could turn EnumSessions from EnumSessions (DPSP_ENUMSESSIONSDATA* data)
into EnumSessions (void* message, int size, bool returnStatus)
.
class DPServiceProvider {
public:
HRESULT EnumSessions (void* message, int size, bool returnStatus);
HRESULT EnumSessions (DPSP_ENUMSESSIONSDATA* data) {
this->EnumSessions(
data->lpMessage,
data->dwMessageSize,
data->bReturnStatus
);
}
};
And subclasses could choose to either use the simplified overloaded fn, or the raw DirectPlay-style struct parameter.
Likely methods:
EnumSessions
Reply
Send
CreatePlayer
DeletePlayer
GetAddress
GetCaps
Open
Close // actually DPlay's CloseEx hook
Shutdown // actually DPlay's ShutdownEx hook
GetAddressChoices
SendEx // could refer to the same Send() overload as Send() by default
SendToGroupEx // or just SendToGroup
Cancel
GetMessageQueue
DPlay's CloseEx and ShutdownEx would have to be used instead of its Close and Shutdown, because the standard Close and Shutdown hooks don't get the IDirectPlaySP interface passed in, so we couldn't use GetSPData to retrieve the DPServiceProvider instance.
That and wx Streams will simplify the thing a lot.
Mention things that need to be installed like
https://www.microsoft.com/en-us/download/details.aspx?id=13287
GET/PUT /rooms
GET/PUT /players
IRC channels are game rooms.
For now we'll need a max of 8 users per channel, but in the future we can +v
players, and -v
spectators, and allow up to 32 users per channel.
The first player to join a channel creates it and gets +o
. +o
is the host. Hosts can start a game.
When a game starts, a CTCP message should be sent to the channel. Like how IRC clients implement /me: CTCP #channel ACTION text
, we could use CTCP #room GAME_STARTING
. DirectPlay connection info needs to be sent to the players, which could either be a message to the room or to individual players: CTCP nick GAME_LAUNCH <host_ip> <dp_session_guid>
.
May prefer to use a slightly modified IRC server that doesn't allow you to fake CTCP messages as easily (perhaps by sending them from the server, and not the room host)
I'm a C++ noob so this thing leaks all over the place
Auto-install https://github.com/Tails8521/WololoKingdoms possibly.
So that it can also be compiled easily on Windows
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.