Custom bridge

Implement the game-server-owned GameBridge used by the Forgeport connector core

Forgeport provides the connector core but no pack-specific adapter. The game server administrator or developer must implement GameBridge against the exact database schema and runtime API of the server source.

This page is for L2J sources

An L2Off server running retail binaries has no source to compile a bridge into. Its connector runs as a separate process and is configured, not written — see PTS / L2Off servers.

1. Install the connector core

Download these files from Admin → Game Servers:

  • portal-connector-core-<version>.jar
  • minimal-json-0.9.5.jar

Place both files in the game server's build and runtime classpath. Everything the core publishes lives in the package net.forgeport.connector.

Requirements

Java 17 or newer, and outbound HTTPS/WSS to wss.forgeport.net on port 443. The core has no other dependency: it uses the JDK's own WebSocket client plus minimal-json, and never touches your database.

2. Create an empty bridge

Create a class in your own package. This template implements the complete interface but advertises no capabilities and performs no game mutation:

MyGameBridge.java
package com.yourpack.gameserver.portal;

import com.eclipsesource.json.JsonArray;
import com.eclipsesource.json.JsonObject;

import net.forgeport.connector.GameBridge;
import net.forgeport.connector.GrantResult;

public final class MyGameBridge implements GameBridge
{
	@Override
	public String[] capabilities()
	{
		return new String[0];
	}

	@Override
	public int onlineCount()
	{
		return 0;
	}

	@Override
	public JsonArray listCharacters(String accountName)
	{
		return new JsonArray();
	}

	@Override
	public JsonArray listRankings(String metric, int limit)
	{
		return new JsonArray();
	}

	@Override
	public String verifyCredentials(String accountName, String password)
	{
		return "TEMPORARY_FAILURE";
	}

	@Override
	public String unstuck(String accountName, int characterId)
	{
		return "FAILED";
	}

	@Override
	public JsonArray searchCatalog(String term, int limit)
	{
		return new JsonArray();
	}

	@Override
	public JsonArray searchSkillCatalog(String term, int limit)
	{
		return new JsonArray();
	}

	@Override
	public GrantResult applyGrant(String commandId, JsonObject payload)
	{
		return GrantResult.permanent("NOT_IMPLEMENTED");
	}
}

Template only

Do not advertise or enable this template in production. Implement and test a function before adding its capability to capabilities().

A handshake must advertise at least one capability, or the gateway closes the connection and the connector loops on reconnect. To smoke-test connectivity before implementing anything real, advertise GET_SERVER_STATUS and GET_ONLINE_COUNT — both are honest as soon as onlineCount() reads the live world.

3. Adapt a working example

Read the complete bridge class closest to the target source:

The examples show the complete composition class, capability list, helper boundaries, online-count implementation, and replay-safe grant flow. They are models to adapt, not adapters supplied by Forgeport.

Verify these points in the exact source revision:

  • Account table, status columns, and password hashing
  • Character, clan, and identifier columns
  • Database connection-pool API
  • Live player lookup and account ownership
  • Item and skill template APIs
  • Inventory, skill, name, gender, and character persistence calls

4. Implement required capabilities

Implement these first:

CapabilityBridge method
VERIFY_GAME_CREDENTIALSverifyCredentials
LIST_ACCOUNT_CHARACTERSlistCharacters
DELIVER_ITEM_GRANTapplyGrant

Start with these three; PLAYER_ONLINE_EVENT and SEARCH_GAME_CATALOG complete the five required capabilities. Without them, Forgeport cannot link a game account, select a character, and deliver a purchase. Admin → Game Servers reports any missing required capability.

Implement optional methods only when the corresponding portal feature is required. applyGrant is reached by two capabilities: add DELIVER_SKILL_GRANT once the same method also handles the l2.grant_skill payload. Return only completed capabilities:

@Override
public String[] capabilities()
{
	return new String[]
	{
		"VERIFY_GAME_CREDENTIALS",
		"LIST_ACCOUNT_CHARACTERS",
		"SEARCH_GAME_CATALOG",
		"DELIVER_ITEM_GRANT",
		"PLAYER_ONLINE_EVENT"
	};
}

Install the pack-specific EnterWorld hook before advertising PLAYER_ONLINE_EVENT:

PortalConnector.getInstance().playerOnline(
	player.getAccountName(),
	player.getObjectId()
);

Call it after the character is fully present in the live world.

5. Add grant idempotency

applyGrant receives a stable commandId. Before changing game state:

  1. Return ALREADY_APPLIED when the command is already complete, and the stored PERMANENT_FAILURE when that is what was decided.
  2. Return RECONCILIATION_REQUIRED when a previous attempt remains APPLYING.
  3. Run every check that can decline. A decline is REFUSED, returned before anything is written — the journal included — and the portal releases the player's coins on it.
  4. Persist APPLYING.
  5. Apply the mutation.
  6. Persist APPLIED.

Use the schema and result rules in Deliver item grants. One journal covers both grant payloads, and the same journal is required for CHARACTER_SERVICES.

6. Start and stop the connector

Start the connector after the game world and data tables are loaded, passing your bridge instance:

import net.forgeport.connector.PortalConfig;
import net.forgeport.connector.PortalConnector;

PortalConfig.load();
PortalConnector.getInstance().start(new MyGameBridge());

Because the bridge is passed as an object, the compiler checks this wiring: renaming or removing the class breaks the build instead of leaving a running server with a disabled connector.

Add best-effort shutdown:

try
{
	PortalConnector.getInstance().shutdown();
}
catch (Exception ignored)
{
}

7. Configure portal.properties

Download the generated file from Admin → Game Servers and place it at config/portal.properties. It is complete as downloaded — nothing to fill in. The commented DeliveryWindow.* and Unstuck.X/Y/Z lines are optional tuning; the defaults are what both reference bridges do:

config/portal.properties
Enabled=True
GatewayUrl=wss://wss.forgeport.net/
Token=gps_<game-server-id>.<secret>

# Optional. The default is 15 seconds.
#HeartbeatSeconds=15

# When each capability actually reaches a character on YOUR pack.
#DeliveryWindow.DELIVER_ITEM_GRANT=online
#DeliveryWindow.DELIVER_SKILL_GRANT=online
#DeliveryWindow.CHARACTER_SERVICES=online
#DeliveryWindow.UNSTUCK_CHARACTER=offline

# Where an unstuck sends a character. Giran on retail coordinates by default.
#Unstuck.X=82698
#Unstuck.Y=148638
#Unstuck.Z=-3473

Keep this file out of version control because Token authenticates the game server.

server token

Regenerating the token from Admin → Game Servers revokes the previous token immediately and disconnects the active connector session. Replace the file on the game server and restart it, or the connector retries forever against a revoked credential.

8. Build and verify

  1. Rebuild and restart the game server.
  2. Confirm Connected in Admin → Game Servers.
  3. Run Connector check.
  4. Resolve every failed advertised capability before enabling portal features.

Grant and character-service checks require a designated online character. The grant check adds one Adena. The unstuck check updates the saved coordinates of an offline character.

Test the bridge against your own pack before you launch

A bridge is written against one pack's schema, revision and customisations, and none of that is visible to Forgeport. Connector check proves your bridge answers and that a command reaches it — it cannot prove a player ends up holding what they paid for, because a method that writes to the wrong table answers exactly like one that works.

Before opening the portal to players, run each advertised capability once for real and confirm the result in the game client: link an account, buy an item and see it in the inventory, buy a skill and see it on the character, run a rename and a gender change. Every capability you leave unverified is one your first paying player tests for you.

On this page