extension

module
v5.0.0-alpha.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 23, 2026 License: MIT

README

OCAP Recorder (Go)

Coverage

About

A Go implementation of an ArmA 3 native extension that records gameplay to PostgreSQL, SQLite, or in-memory JSON. Captures unit positions, combat events, markers, and more for mission replay and analytics.

Architecture

Overview
ArmA 3 Game
    ↓ callExtension("ocap_recorder", [":COMMAND:", args])
RVExtensionArgs() [CGo boundary]
    ↓
Dispatcher.Dispatch(Event)
    ↓
    ├─ [Sync]     → Handler directly
    └─ [Buffered] → Channel → Goroutine → Handler
                                              ↓
                                   Parser (args → core types)
                                              ↓
                                   EntityCache (validate/enrich)
                                              ↓
                                   Storage Backend
                                     ├─ Memory → in-memory append → JSON export on save
                                     ├─ Postgres → Queue → DB writer (batch insert every 2s) → PostgreSQL
                                     └─ SQLite → Queue → DB writer (batch insert every 2s) → SQLite

Buffered handlers are gated on :STORAGE:INIT: — events queue in channels until the storage backend is ready.

DLL Entry Points

The extension exposes CGo-exported functions that ArmA 3 calls:

Function Purpose
RVExtensionArgs() Main entry point; receives command and arguments
RVExtension() Legacy simple command handler
RVExtensionVersion() Returns version string
Event Dispatcher

The dispatcher routes commands to handlers with optional buffering:

  • Sync handlers: Execute immediately (entity creation)
  • Buffered handlers: Queue events in channels for async processing (high-volume state updates)
  • Metrics: OpenTelemetry integration for queue sizes, events processed/dropped
Project Structure
cmd/ocap_recorder/main.go    Entry point, initialization, lifecycle commands
pkg/a3interface/             CGo exports (RVExtension*)
internal/
├── dispatcher/              Event routing with async buffering
├── parser/                  Command parsing (args → core types)
├── worker/                  Handler registration and DB writer loop
├── queue/                   Thread-safe queues for batch writes
├── cache/                   Entity lookup caching (ObjectID → model)
├── model/                   Database models + converters
├── storage/                 Storage backends (memory, postgres, sqlite)
└── geo/                     Coordinate/geometry utilities
Design Principles
  1. Low latency: Async buffered handlers don't block ArmA's game loop
  2. High throughput: Batch writes every 2 seconds instead of per-event
  3. Entity caching: Sync entity creation → cache → async state updates use cached FK
  4. Pluggable storage: Memory (JSON export), PostgreSQL, or SQLite (in-memory with periodic disk dump)
  5. Observability: OpenTelemetry metrics and structured logging (slog)

Building

Requires Docker with Linux containers.

Windows DLL
docker pull x1unix/go-mingw:1.24

docker run --rm -v ${PWD}:/go/work -w /go/work x1unix/go-mingw:1.24 \
  go build -buildvcs=false -o dist/ocap_recorder_x64.dll -buildmode=c-shared ./cmd/ocap_recorder
Linux .so
docker run --rm -v ${PWD}:/go/work -w /go/work golang:1.24-bullseye \
  go build -buildvcs=false -o dist/ocap_recorder_x64.so -buildmode=c-shared ./cmd/ocap_recorder

Uses Debian Bullseye (glibc 2.31) for broad compatibility with Linux game servers.

Configuration

Copy ocap_recorder.cfg.json.example to ocap_recorder.cfg.json alongside the DLL and edit as needed.

Supported Commands

All commands follow a :RESOURCE:ACTION: naming convention. New commands must use this pattern — resource noun first, then verb/qualifier (e.g., :SOLDIER:CREATE:, :EVENT:KILL:, :SYS:INIT:).

Entity Commands
Command Buffer Purpose
:SOLDIER:CREATE: Sync Register new unit
:VEHICLE:CREATE: Sync Register new vehicle
:SOLDIER:STATE: 10,000 Update unit position/state
:VEHICLE:STATE: 10,000 Update vehicle position/state
Combat Commands
Command Buffer Purpose
:EVENT:PROJECTILE: 5,000 Projectile tracking (positions + hits)
:EVENT:KILL: 2,000 Kill event
General Commands
Command Buffer Purpose
:EVENT:GENERAL: 1,000 General gameplay event
:EVENT:CHAT: 1,000 Chat message
:EVENT:RADIO: 1,000 Radio transmission
:TELEMETRY:FRAME: 100 Server telemetry (FPS, entity counts, weather, player network stats)
:TIME:STATE: 100 Mission time/date tracking
Marker Commands
Command Buffer Purpose
:MARKER:CREATE: Sync Create map marker (needs immediate DB ID)
:MARKER:STATE: 1,000 Update marker position/appearance
:MARKER:DELETE: 500 Delete marker
Placed Object Commands
Command Buffer Purpose
:PLACED:CREATE: Sync Register placed object (mine, explosive)
:PLACED:EVENT: 1,000 Placed object lifecycle event (detonated/deleted)
ACE3 Integration
Command Buffer Purpose
:ACE3:DEATH: 1,000 ACE3 death event
:ACE3:UNCONSCIOUS: 1,000 ACE3 unconscious event
Lifecycle Commands
Command Purpose
:SYS:INIT: Initialize extension, send :SYS:READY: callback
:STORAGE:INIT: Initialize storage backend, ungate buffered handlers
:MISSION:START: Start recording mission
:MISSION:SAVE: End recording, flush data, upload if configured
:SYS:VERSION: Get extension version

Directories

Path Synopsis
cmd
ocap_recorder command
internal
api
internal/api/client.go
internal/api/client.go
geo
model/convert
Package convert provides functions to convert between GORM models and core models
Package convert provides functions to convert between GORM models and core models
storage
internal/storage/storage.go
internal/storage/storage.go
storage/memory
internal/storage/memory/export.go
internal/storage/memory/export.go
storage/memory/export/v1
Package v1 contains the v1 export format for OCAP2 mission data.
Package v1 contains the v1 export format for OCAP2 mission data.
storage/postgres
Package postgres implements the storage.Backend interface using GORM/PostgreSQL with internal queues and a background DB writer goroutine.
Package postgres implements the storage.Backend interface using GORM/PostgreSQL with internal queues and a background DB writer goroutine.
storage/sqlite
Package sqlitestorage implements the storage.Backend interface using an in-memory SQLite database with periodic disk dumps via VACUUM INTO.
Package sqlitestorage implements the storage.Backend interface using an in-memory SQLite database with periodic disk dumps via VACUUM INTO.
util
Package util provides common utility functions used across the OCAP recorder.
Package util provides common utility functions used across the OCAP recorder.
pkg
core
pkg/core/events.go
pkg/core/events.go

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL