LLM Agent files

This commit is contained in:
yzinchuk
2026-07-05 18:14:54 -04:00
parent afeffc1b98
commit c1bd7eb045
6 changed files with 1000 additions and 0 deletions
+122
View File
@@ -0,0 +1,122 @@
# Architecture
How the 2009scape game server is put together. See [`../AGENTS.md`](../AGENTS.md) for
build/run instructions and the top-level rules, and [`CONTENT_GUIDE.md`](CONTENT_GUIDE.md)
for adding gameplay.
## The two halves: engine vs. content
The codebase is deliberately split:
- **`Server/src/main/core/`** — the **engine**. Networking, the RS cache reader, the game
loop/pulse scheduler, entities (players, NPCs), the world map, storage/auth, and the
**content API** (`core.api`). Engine code must not depend on any specific piece of
content.
- **`Server/src/main/content/`** — the **content**. Quests, NPC behavior, minigames,
skills, items, region-specific interactions. Content is built on top of `core.api` and
is discovered reflectively at startup.
Keeping this boundary clean is the main architectural discipline of the project.
## Startup and plugin discovery
Entry point: `core.Server` (`core.Server.main`). During boot the server:
1. Loads configuration from `worldprops/default.conf` (TOML) into `GameWorld.settings`.
2. Loads the RuneScape **cache** (map, item/npc/object definitions) via `core.cache`.
3. Runs **`core.plugin.ClassScanner`**, which uses the **classgraph** library to scan the
classpath and reflectively instantiate every class implementing a known
`ContentInterface` sub-type (see the table in `AGENTS.md`). This is how content
"registers" itself — there is no central manifest to edit.
4. Starts the world / game loop and opens the network listener(s).
Because discovery is reflective, **adding a new content class is enough to activate it**
just implement the right interface and put the file under `content/`.
`ClassScanner` also builds the registry of player-runnable bot scripts (see
[`BOT_SCRIPTING.md`](BOT_SCRIPTING.md)) by picking up classes annotated with
`@PlayerCompatible`.
## The game loop / pulse system
The world advances in discrete **ticks** (RuneScape's canonical tick is 600 ms). Timed
and repeating work is modeled as **`Pulse`** objects submitted to `GameWorld.Pulser`. A
`Pulse` overrides `pulse(): Boolean` and returns `true` when it is finished. Movement,
combat swings, skill actions, and bot scripts are all implemented as pulses.
`TickListener` content runs once per tick globally; `MovementPulse` handles walking a
player/NPC to a destination.
Coroutines (`kotlinx-coroutines`) back parts of the worker/pulse infrastructure.
## Entities and nodes
Everything interactable in the world is a **`Node`** (`core.game.node`):
- `Entity``Player` and `NPC` (living things with combat, skills, movement).
- `Player` also has an AI subclass, `AIPlayer`, used for bots.
- `Item` / `GroundItem` — items in containers or on the floor.
- `Scenery` — world objects (trees, doors, altars…).
Players carry a lot of linked state under `core.game.node.entity.player.link` (quests,
diaries, prayers, emotes, teleport manager, hint icons, etc.) and use `Container`s
(`inventory`, `equipment`, `bank`) for items.
## The content API (`core.api`)
`core.api.ContentAPI.kt` is a large file of **top-level helper functions** that form the
intended, stable surface for content code — e.g. `sendMessage`, `animate`, `addItem`,
`removeItem`, `getStatLevel`, `rewardXP`, `teleport`, `getVarp`/`setVarp`, `lock`,
`sendDialogue`. Content should call these rather than reaching into engine internals.
Key interfaces in `core.api` (all extend the `ContentInterface` marker so `ClassScanner`
finds them): `InteractionListener`, `InterfaceListener`, `Commands`, `LoginListener`,
`LogoutListener`, `TickListener`, `StartupListener`, `ShutdownListener`, `PersistPlayer`,
`PersistWorld`, `MapArea`.
## Networking
The server speaks the original RS2 build-530 binary protocol.
- **TCP** is the primary transport.
- An optional **WebSocket** listener (`org.java-websocket`) carries the *same* raw binary
protocol inside binary frames, enabling browser/PWA clients. It is off by default;
enable via `websocket_enabled`/`websocket_port` in `default.conf` (port defaults to
`53594 + world_id`). Plain `ws://` for local testing; `wss://` (with a PKCS12 keystore)
for production/PWA. See the README for keystore setup.
- Client and server must share `secret_key` or the connection is refused.
A separate **management** interface is defined via Protobuf (`Proto/Management.proto`,
`src/main/proto/`).
## Data, config, and storage
- **Configuration:** `worldprops/default.conf` (TOML), parsed by
`core.game.system.config.ServerConfigParser` into `GameWorld.settings`
(`core.game.world.GameSettings`). Paths (cache, saves, data, logs, scripts) are held in
`core.ServerConstants`.
- **Static game data** (npc spawns, shops, drop tables, item configs) lives in JSON files
loaded at runtime. Edit these with the **Thanos tool** (needs Java 11), *not* by hand.
- **Item/NPC/object/animation IDs** come from the external **`ConstLib`** dependency
(`org.rs09.consts.*`, bundled in `Server/libs/`) — reference them as `Items.FEATHER_314`,
`NPCs.CHICKEN_...`, etc.
- **Persistence:** player saves + account data via MySQL (`mysql-connector-java`) or
SQLite (`sqlite-jdbc`). Controlled by `use_auth` / `persist_accounts` in config; when
both are false, **no database is needed** (ideal for local content work). Both MUST be
`true` in production.
## Testing & static analysis
- **JUnit 5** tests in `Server/src/test/kotlin/` (e.g. `APITests`, `ExchangeTests`,
skill/region tests). Run with `./run -t` or `sh mvnw test`.
- **detekt** (`Server/detekt.yml`) runs in the Maven `verify` phase and in CI
(`.gitlab-ci.yml`); keep new Kotlin clean against it.
## Build specifics worth knowing
- Maven, JVM target **11** (JDK 11 required — not newer).
- `mvn clean` installs the bundled `ConstLib` and `PrimitiveExtensions` jars from
`Server/libs/` into the local Maven repo, so a fresh checkout won't compile until clean
has run once.
- The package build produces a fat jar (`…-with-dependencies.jar`) whose main class is
`core.Server`; the `build` script renames it to `builddir/server.jar`.