A P2P connection proxy for Supreme Commander: Forged Alliance using ICE.
Build the project using gradle from the provided wrapper (Java 21 required).
The faf-ice-adapter
is controlled using a bi-directional JSON-RPC interface over TCP.
Name | Parameters | Returns | Description |
---|---|---|---|
quit | Gracefully shuts down the faf-ice-adapter . |
||
hostGame | mapName (string) | Tell the game to create the lobby and host game on Lobby-State. | |
joinGame | remotePlayerLogin (string), remotePlayerId (int) | Tell the game to create the Lobby, create a PeerRelay in answer mode and join the remote game. | |
connectToPeer | remotePlayerLogin (string), remotePlayerId (int), offer (bool) | Create a PeerRelay and tell the game to connect to the remote peer with offer/answer mode. | |
disconnectFromPeer | remotePlayerId (int) | Destroy PeerRelay and tell the game to disconnect from the remote peer. | |
setLobbyInitMode | lobbyInitMode (string): "normal" or "auto" | Set the lobby mode the game will use. Supported values are "normal" for normal lobby and "auto" for automatch lobby (aka ladder). | |
iceMsg | remotePlayerId (int), msg (object) | Add the remote ICE message to the PeerRelay to establish a connection. | |
sendToGpgNet | header (string), chunks (array) | Send an arbitrary message to the game. | |
setIceServers | iceServers (array) | ICE server array for use in webrtc. Must be called before joinGame/connectToPeer. See https://developer.mozilla.org/en-US/docs/Web/API/RTCIceServer | |
status | status structure | Polls the current status of the faf-ice-adapter . |
Name | Parameters | Description |
---|---|---|
onConnectionStateChanged | "Connected"/"Disconnected" (string) | The game connected to the internal GPGNetServer. |
onGpgNetMessageReceived | header (string), chunks (array) | The game sent a message to the faf-ice-adapter via the internal GPGNetServer. |
onIceMsg | localPlayerId (int), remotePlayerId (int), msg (object) | The PeerRelays gathered a local ICE message for connecting to the remote player. This message must be forwarded to the remote peer and set using the iceMsg command. |
onIceConnectionStateChanged | localPlayerId (int), remotePlayerId (int), state (string) | See https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceConnectionState |
onConnected | localPlayerId (int), remotePlayerId (int), connected (bool) | Informs the client that ICE connectivity to the peer is established or unestablished. |
{
"version" : /* string: faf-ice-adapter version */
"ice_servers_size" : /* the number of ICE servers set using `setIceServers` */
"lobby_port" : /* the actual game lobby UDP port. Should match --lobby-port option if non-zero port is specified. */
"init_mode" : /* the current init mode. See setLobbyInitMode */
"options" : /* The specified commandline options */
"gpgnet" : { /* The GPGNet state */
"local_port" : /* int: The port the game should connect to via /gpgnet 127.0.0.1:port */
"connected" : /* boolean: Is the game connected? */
"game_state" : /* string: The last received "GameState" */
"task_string" : /* string: A string describing the task/role of the game (joining/hosting)*/
}
"relays" : [/* An array of relay information for each peer */
{
"remote_player_id" : /* int: The ID of the remote player */
"remote_player_login" : /* string: The name of the remote player */
"local_game_udp_port" : /* int: The UDP port opened for the game to connect to */
"ice": {/* ICE state information for this peer */
"offerer": /* bool: one peer is always offerer, one answerer */
"state": /* string: The connection state https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceConnectionState */
"gathering_state": /* string: The gathering state https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceGatheringState */
"datachannel_state": /* string: The state of the https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel */
"connected": /* bool: Is the peer connected? Needs to be in sync with the remote peer. */
"loc_cand_addr": /* string: The local address used for the connection */
"rem_cand_addr": /* string: The remote address used for the connection */
"loc_cand_type": /* string: The type of the local candidate 'local'/'stun'/'relay' */
"rem_cand_type": /* string: The type of the remote candidate 'local'/'stun'/'relay' */
"time_to_connected": /* double: The time it took to connect to the peer in seconds */
}
},
...
]
}
The first two commandline arguments --id
and --login
must be specified like this: faf-ice-adapter -i 3 -l "Rhiza"
The full commandline help text is:
faf-ice-adapter usage:
--help produce help message
--id arg set the ID of the local player
--login arg set the login of the local player, e.g. "Rhiza"
--rpc-port arg (=7236) set the port of internal JSON-RPC server
--gpgnet-port arg (=0) set the port of internal GPGNet server
--lobby-port arg (=0) set the port the game lobby should use for incoming UDP packets from the PeerRelay
--log-directory arg (DEPRECATED, use env variable LOG_DIR)set a log directory to write ice_adapter_0 log files
--force-relay force the usage of relay candidates only
--debug-window activate the debug window if JavaFX is available
--info-window activate the info window if JavaFX is available (allows access at the debug window)
--delay-ui arg delays the launch of the info and debug window by arg ms
Step | Player 1 "Alice" | Player 2 "Bob" |
---|---|---|
1 | Start the client | |
2 | The client starts faf-ice-adapter and connects to the JSONRPC server |
|
3 | The client starts the game and makes it connect to the GPGNet server of the faf-ice-adapter using /gpgnet 127.0.0.1:7237 commandline argument for ForgedAlliance.exe |
|
3.1 | The game sends GameState Idle |
|
3.2 | The client sends CreateLobby ... |
|
3.3 | The game sends GameState Lobby |
|
4 | The client sends hostGame('monument_valley.v0001') |
|
5 | The game should now wait in the lobby and the client receives a lot of onGpgNetMessageReceived notifications from faf-ice-adapter |
|
6 | Now Bob want to join Alices game, starts the client, the client starts faf-ice-adapter and the game like Alice did. |
|
6.1 | The game sends GameState Idle |
|
6.2 | The client sends CreateLobby ... |
|
6.3 | The game sends GameState Lobby |
|
7 | The client sends connectToPeer('Bob', 2, true) |
The client sends joinGame('Alice', 1) |
8 | The game should connect to the internal PeerRelay, and shows that it's connecting to the peer. | The game should connect to the internal PeerRelay, and shows that it's connecting to the peer. |
9 | The client receives multiple onIceMsg(1, 2, someIceMsg) notifications and must now transfer these messages string ordered to the peer. |
The client receives multiple onIceMsg(1, 2, someIceMsg) notifications and must now transfer these messages string ordered to the peer. |
10 | The client must set the transferred ICE messages for the peer using iceMsg(2, someIceMsg) . |
The client must set the transferred ICE messages for the peer using iceMsg(1, someIceMsg) . |
11 | The client received multiple iceConnectionStateChanged(...) notifications which would finally show the 'Connected' or 'Complete' state, which should also let the game connect to the peer. Another indicator for a connection is the onDatachannelOpen notification. |
The client received multiple iceConnectionStateChanged(...) notifications which would finally show the 'Connected' or 'Complete' state, which should also let the game connect to the peer. |