# Multiplayer

VoxelWorld's multiplayer mode uses an authoritative dedicated server. The
server authenticates each player and decides gameplay outcomes; clients send
input-like intents and render the resulting state. Clients still generate the
deterministic base terrain locally from the seed provided by the server, so the
headless server does not render or mesh chunks.

## What the server owns

Protocol v4 makes the server authoritative for:

- each player's inventory, crafting cursor, selected hotbar slot, health, and
  hunger;
- dropped-item creation, motion, pickup, despawn, and persistence;
- arrow and boss projectiles, weapon/ammo use, PvP hits, and damage;
- shared pigs, chickens, fireflies, and crater-boss state;
- shared world time and weather; and
- persistent block edits and the world seed.

Players have independent inventory, health, and hunger records. Shared objects
such as a dropped item or projectile have one server identity and one outcome,
so two clients cannot legitimately pick up or resolve the same object in
different ways.

Clients send `GAME_ACTION` intents for actions such as inventory clicks, drops,
block interactions, bow use, melee attacks, and eating. The server validates
them against the authenticated player's current state, then sends each session
its own `GAME_STATE_SNAPSHOT` frames. A client cannot award itself an item,
report its own hit, choose its health, or replace shared entity state.

The headless simulation runs at 20 ticks per second. The current design sends
bounded full snapshots rather than spatially filtered deltas. That is a clear
and testable baseline for a few players on a LAN, but larger populations will
need interest management, delta compression, and more sophisticated
interpolation.

## Basic anti-cheat model

The server rejects malformed or impossible input before changing gameplay
state. Checks include:

- strictly increasing action request ids, which make duplicate/replayed
  mutations harmless;
- expected inventory revisions, so stale clicks cannot overwrite newer state;
- per-session pose and action rate limits;
- finite coordinates, world bounds, movement-speed limits, swept terrain
  collision, grounded jump/fall limits, and pitch limits;
- interaction reach and action-specific cooldown checks; and
- valid slot, item, block, face, count, and entity identifiers.

Those checks are defense in depth, not a promise that the alpha is
cheat-proof. The server remains the only authority even when a client predicts
movement or presentation locally. New gameplay messages should continue to
describe what the player tried to do, never the result the client wants.

## Local quick start

VoxelWorld requires JDK 25. Before the first start, initialize the database and
replace the bootstrap password:

```sh
./dev server --args='--change-password=admin'
```

The command prompts for the new password without putting it in shell history.
Then start the server:

```sh
./dev server
```

In another terminal, start the client:

```sh
./dev play
```

The defaults connect to `127.0.0.1:25565`. A brand-new server database creates
one bootstrap account:

```text
Username: admin
Password: admin
```

> **Security warning:** `admin` / `admin` is a temporary bootstrap credential.
> Change it with the command above before binding the server beyond localhost.

To test with another player, stop the server and create a distinct account:

```sh
./dev server --args='--create-user=friend'
```

The command prompts for a password and grants the account game access. Restart
the server afterward. One account cannot be connected from two clients at the
same time.

The server creates `server-data/world.seed` and
`server-data/voxelworld.db`. Keep that directory to preserve the world identity,
accounts, and block edits. Back it up while the server is stopped.

## Connection options

The `dev` helper aliases still accept normal Gradle options:

| Purpose | Development command | JVM system property |
| --- | --- | --- |
| Client host | `-PclientHost=HOST` | `voxelworld.client.host` |
| Client port | `-PclientPort=PORT` | `voxelworld.client.port` |
| Server bind address | `-PserverBind=ADDRESS` | `voxelworld.server.bind` |
| Server port | `-PserverPort=PORT` | `voxelworld.server.port` |
| Server data directory | `-PserverDataDir=PATH` | `voxelworld.server.dataDir` |

For example:

```sh
./dev server -PserverBind=127.0.0.1 -PserverPort=25565 \
  -PserverDataDir=server-data
./dev play -PclientHost=127.0.0.1 -PclientPort=25565
```

The packaged applications use command-line options instead:

```sh
bin/VoxelWorldServer --bind=127.0.0.1 --port=25565 \
  --data-dir=server-data
bin/VoxelWorld --server 127.0.0.1:25565
```

The multiplayer login screen also accepts `HOST[:PORT]` in its server field,
including bracketed IPv6 such as `[::1]:25565`. Command-line and environment
settings supply that field's initial value.

Packaged account-management commands use the same server executable:

```sh
bin/VoxelWorldServer --change-password=admin
bin/VoxelWorldServer --create-user=friend
```

Run `bin/VoxelWorldServer --help` for its accepted options. Client credentials
are entered in the login screen; never put passwords in command-line arguments
or JVM properties.

## Hosting on a LAN

Bind the server to all network interfaces:

```sh
./dev server -PserverBind=0.0.0.0 -PserverPort=25565
```

Other clients connect to the server computer's LAN address, for example:

```sh
./dev play -PclientHost=192.168.1.50 -PclientPort=25565
```

`0.0.0.0` is only a server bind address. It is not an address that clients can
connect to.

Allow inbound **TCP** traffic to port `25565` in the server computer's firewall.
For access across the internet, a router would also need a TCP port-forward to
the server's stable LAN address. Even with server-authoritative gameplay, direct
public exposure is not recommended: use localhost, a trusted LAN, or a private
VPN instead.

## Transport security

The current protocol is length-delimited, versioned TCP, but it is
**unencrypted**. Login credentials and game traffic cross the network in
plaintext. Passwords are hashed in the SQLite database, but hashing at rest
does not protect them in transit. Do not reuse an important password, and do
not forward the raw service port to the public internet. Put remote tests behind
a private VPN. TLS, certificate validation, and production-grade credential and
session management must be added before public hosting.

## Packaging

Build both player clients and the server archive:

```sh
./dev package
```

On an Apple Silicon Mac this produces:

```text
build/distributions/VoxelWorld-0.2.0-client-macos-arm64.zip
build/distributions/VoxelWorld-0.2.0-client-windows-x64.zip
build/distributions/VoxelWorld-0.2.0-server.zip
```

The normal client archive is labeled for the OS and CPU that ran Gradle because
it contains that host's LWJGL native libraries. The dedicated Windows x64 task
cross-packages Windows-only LWJGL libraries from macOS and verifies that no
macOS libraries or first-thread JVM option leaked into its launcher. The
server archive is platform-independent Java and intentionally contains no
LWJGL or native jars.

After extracting an archive, use `bin/VoxelWorld` (client) or
`bin/VoxelWorldServer` (server). On Windows, use the corresponding `.bat`
script; the Windows client also has the friendlier root launcher
`PLAY-VOXEL-SLOP.bat`. These portable alpha zips do not yet bundle Java, so
every target needs a 64-bit JDK 25. The Windows archive can be structurally
verified on macOS, but its first graphical smoke test should still run on a
Windows x64 machine.

To publish refreshed macOS and Windows clients to the companion website from
the Apple Silicon development Mac:

```sh
./dev release-site
```

This also regenerates the website's release manifest, displayed file sizes,
and SHA-256 checksums, then runs the website build and tests. Pass
`-PsiteDir=/absolute/path/to/VoxelSlopSite` if the site is not in its default
Documents/Github location.

## Current limitations

- There is no TLS, certificate handling, in-game registration/account
  management, or recovery flow. Account creation and password changes are
  server-console operations.
- Authority checks prevent basic forged inventory, duplicate-action,
  impossible-reach, speed/fly-through-wall, and client-reported-damage cheats.
  They do not yet provide lag compensation, anomaly scoring, automated
  sanctions, or a production moderation system.
- The 20 TPS server sends bounded full snapshots. There is no spatial interest
  management, entity delta stream, sharding, clustering, or large-population
  load balancing yet.
- A rejected gameplay intent is followed by canonical state and an on-screen
  notice. A disconnect returns the client to login so it cannot continue in an
  unsaved local fork.
- Shared campfire storage/cooking and the crater firewall, victory sequence, and
  crater-fire hazards still need dedicated protocol state. The online client
  keeps the campfire UI closed and the local firewall down rather than allowing
  either client to invent authoritative results.
- Player inventories, shared drops, chest contents, world state, and accepted
  block edits are committed as one SQLite checkpoint. A restart cannot restock
  the starter chest or expose both sides of an interrupted item transfer.
- Clients generate base terrain and chunk meshes locally from the server seed.
  The server distributes the seed and saved overrides rather than chunk mesh
  data.
- There is no production-grade reconnect/session-resume protocol. A reconnect
  receives a fresh authoritative snapshot.
- SQLite and the seed file are local to one server process. Schema migrations
  exist, but operational backup, replication, failover, monitoring, and abuse
  controls are not implemented.
