{"id":18425817,"url":"https://github.com/faforever/java-ice-adapter","last_synced_at":"2026-03-17T09:38:17.133Z","repository":{"id":45179519,"uuid":"152485350","full_name":"FAForever/java-ice-adapter","owner":"FAForever","description":"A P2P connection proxy for Supreme Commander: Forged Alliance using ICE ","archived":false,"fork":false,"pushed_at":"2025-08-11T21:09:55.000Z","size":4076,"stargazers_count":6,"open_issues_count":13,"forks_count":14,"subscribers_count":5,"default_branch":"master","last_synced_at":"2026-01-11T15:16:51.375Z","etag":null,"topics":["frontend"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FAForever.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-10T20:25:55.000Z","updated_at":"2025-12-19T13:53:49.000Z","dependencies_parsed_at":"2023-11-10T23:23:19.837Z","dependency_job_id":"23d3f6cf-c52c-433b-8e54-cbb491fe965e","html_url":"https://github.com/FAForever/java-ice-adapter","commit_stats":null,"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"purl":"pkg:github/FAForever/java-ice-adapter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FAForever%2Fjava-ice-adapter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FAForever%2Fjava-ice-adapter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FAForever%2Fjava-ice-adapter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FAForever%2Fjava-ice-adapter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FAForever","download_url":"https://codeload.github.com/FAForever/java-ice-adapter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FAForever%2Fjava-ice-adapter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30620752,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-17T08:10:05.930Z","status":"ssl_error","status_checked_at":"2026-03-17T08:10:04.972Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["frontend"],"created_at":"2024-11-06T05:05:54.109Z","updated_at":"2026-03-17T09:38:17.119Z","avatar_url":"https://github.com/FAForever.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ❆ faf-ice-adapter ❆\n\n A P2P connection proxy for Supreme Commander: Forged Alliance using [ICE](https://en.wikipedia.org/wiki/Interactive_Connectivity_Establishment).\n\n## Building\nBuild the project using gradle from the provided wrapper (Java 21 required).\n\n## JSONRPC Protocol\nThe `faf-ice-adapter` is controlled using a bi-directional [JSON-RPC](http://www.jsonrpc.org/specification) interface over TCP.\n\n### Methods (client ➠ faf-ice-adapter)\n\n| Name | Parameters | Returns | Description |\n| --- | --- | --- | --- |\n| quit | | | Gracefully shuts down the `faf-ice-adapter`. |\n| hostGame | mapName (string) | | Tell the game to create the lobby and host game on Lobby-State. |\n| joinGame | remotePlayerLogin (string), remotePlayerId (int) | | Tell the game to create the Lobby, create a PeerRelay in answer mode and join the remote game. |\n| connectToPeer | remotePlayerLogin (string), remotePlayerId (int), offer (bool)| | Create a PeerRelay and tell the game to connect to the remote peer with offer/answer mode. |\n| disconnectFromPeer | remotePlayerId (int)| | Destroy PeerRelay and tell the game to disconnect from the remote peer. |\n| 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). |\n| iceMsg | remotePlayerId (int), msg (object) | | Add the remote ICE message to the PeerRelay to establish a connection. |\n| sendToGpgNet | header (string), chunks (array) | | Send an arbitrary message to the game. |\n| 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 |\n| status | | [status structure](#status-structure) | Polls the current status of the `faf-ice-adapter`. |\n\n### Notifications (faf-ice-adapter ➠ client )\n| Name | Parameters | Description |\n| --- | --- | --- |\n| onConnectionStateChanged | \"Connected\"/\"Disconnected\" (string) | The game connected to the internal GPGNetServer. |\n| onGpgNetMessageReceived | header (string), chunks (array) | The game sent a message to the `faf-ice-adapter` via the internal GPGNetServer. |\n| 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. |\n| onIceConnectionStateChanged | localPlayerId (int), remotePlayerId (int), state (string) | See https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceConnectionState |\n| onConnected | localPlayerId (int), remotePlayerId (int), connected (bool) | Informs the client that ICE connectivity to the peer is established or unestablished. |\n\n#### Status structure\n```\n{\n\"version\" : /* string: faf-ice-adapter version */\n\"ice_servers_size\" : /* the number of ICE servers set using `setIceServers` */\n\"lobby_port\" : /* the actual game lobby UDP port. Should match --lobby-port option if non-zero port is specified. */\n\"init_mode\" : /* the current init mode. See setLobbyInitMode */\n\"options\" : /* The specified commandline options */\n\"gpgnet\" : { /* The GPGNet state */\n  \"local_port\" : /* int: The port the game should connect to via /gpgnet 127.0.0.1:port */\n  \"connected\" : /* boolean: Is the game connected? */\n  \"game_state\" : /* string: The last received \"GameState\" */\n  \"task_string\" : /* string: A string describing the task/role of the game (joining/hosting)*/\n  }\n\"relays\" : [/* An array of relay information for each peer */\n  {\n    \"remote_player_id\" : /* int: The ID of the remote player */\n    \"remote_player_login\" : /* string: The name of the remote player */\n    \"local_game_udp_port\" : /* int: The UDP port opened for the game to connect to */\n    \"ice\": {/* ICE state information for this peer */\n      \"offerer\": /* bool: one peer is always offerer, one answerer */\n      \"state\": /* string: The connection state https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceConnectionState */\n      \"gathering_state\": /* string: The gathering state https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceGatheringState */\n      \"datachannel_state\": /* string: The state of the https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel */\n      \"connected\": /* bool: Is the peer connected? Needs to be in sync with the remote peer. */\n      \"loc_cand_addr\": /* string: The local address used for the connection */\n      \"rem_cand_addr\": /* string: The remote address used for the connection */\n      \"loc_cand_type\": /* string: The type of the local candidate 'local'/'stun'/'relay' */\n      \"rem_cand_type\": /* string: The type of the remote candidate 'local'/'stun'/'relay' */\n      \"time_to_connected\": /* double: The time it took to connect to the peer in seconds */\n      }\n    },\n  ...\n  ]\n}\n```\n\n## Commandline invocation\nThe first two commandline arguments `--id` and `--login` must be specified like this: `faf-ice-adapter -i 3 -l \"Rhiza\"`\nThe full commandline help text is:\n```\nfaf-ice-adapter usage:\n--help                               produce help message\n--id arg                             set the ID of the local player\n--login arg                          set the login of the local player, e.g. \"Rhiza\"\n--rpc-port arg (=7236)               set the port of internal JSON-RPC server\n--gpgnet-port arg (=0)               set the port of internal GPGNet server\n--lobby-port arg (=0)                set the port the game lobby should use for incoming UDP packets from the PeerRelay\n--log-directory arg                  (DEPRECATED, use env variable LOG_DIR)set a log directory to write ice_adapter_0 log files\n--force-relay                        force the usage of relay candidates only\n--debug-window                       activate the debug window if JavaFX is available\n--info-window                        activate the info window if JavaFX is available (allows access at the debug window)\n--delay-ui arg                       delays the launch of the info and debug window by arg ms\n```\n\n## Example usage sequence\n\n| Step | Player 1 \"Alice\" | Player 2 \"Bob\" |\n| --- | --- | --- |\n| 1 | Start the client |  |\n| 2 | The client starts `faf-ice-adapter` and connects to the JSONRPC server |  |\n| 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` |  |\n| 3.1 | The game sends `GameState Idle` | |\n| 3.2 | The client sends `CreateLobby ...` | |\n| 3.3 | The game sends `GameState Lobby` | |\n| 4 | The client sends `hostGame('monument_valley.v0001')`||\n| 5 | The game should now wait in the lobby and the client receives a lot of `onGpgNetMessageReceived` notifications from `faf-ice-adapter`||\n| 6 |  | Now Bob want to join Alices game, starts the client, the client starts `faf-ice-adapter` and the game like Alice did. |\n| 6.1 | | The game sends `GameState Idle` |\n| 6.2 | | The client sends `CreateLobby ...` |\n| 6.3 | | The game sends `GameState Lobby` |\n| 7 | The client sends `connectToPeer('Bob', 2, true)` | The client sends `joinGame('Alice', 1)` |\n| 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. |\n| 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. |\n| 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)`. |\n| 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. |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffaforever%2Fjava-ice-adapter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffaforever%2Fjava-ice-adapter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffaforever%2Fjava-ice-adapter/lists"}