Skip to content

TypeScript multiplayer runtime framework targeting FiveM via an adapter.

License

Notifications You must be signed in to change notification settings

newcore-network/opencore

Repository files navigation

CI npm license typescript cli website

OpenCore Framework - Open Stable beta

OpenCore is a TypeScript multiplayer runtime framework targeting FiveM via an adapter.

It is not a gamemode or RP framework. It provides:

  • A stable execution model (server and client)
  • Dependency Injection and metadata-driven wiring
  • An event/command system
  • Security primitives (validation, access control, rate limiting)

License: MPL-2.0

Discord Community | Docs | OpenCore CLI

Installation

pnpm add @open-core/framework reflect-metadata tsyringe zod uuid

This framework uses TypeScript decorators. Ensure your project has decorators enabled.

Imports and entry points

The package exposes subpath entry points:

  • @open-core/framework (root)
  • @open-core/framework/server
  • @open-core/framework/client

Most projects will import the Server/Client namespaces:

import { Server } from '@open-core/framework/server'

Architecture

OpenCore follows a Ports & Adapters (Hexagonal) architecture.

  • Kernel (src/kernel): engine-agnostic infrastructure (DI, logger, metadata scanning)
  • Runtime (src/runtime): multiplayer execution model (controllers, processors, security, lifecycle)
  • Adapters (src/adapters): platform integration (FiveM, Node testing)

The runtime never auto-detects the platform. Adapters are selected explicitly at bootstrap time.

Operating modes

Each instance runs in exactly one mode configured via Server.init():

  • CORE: authoritative runtime. Typically provides identity/auth/players via exports.
  • RESOURCE: a normal FiveM resource using CORE as provider for some features.
  • STANDALONE: a self-contained runtime (useful for tooling, simulations, or small servers).

Server bootstrap

Initialize the server runtime:

import { Server } from '@open-core/framework/server'

await Server.init({
  mode: 'CORE'
})

Some features require providers (depending on your mode and configuration). Configure them before calling init():

import { Server } from '@open-core/framework/server'

Server.setPrincipalProvider(MyPrincipalProvider)
Server.setSecurityHandler(MySecurityHandler)
Server.setPersistenceProvider(MyPlayerPersistence)
Server.setNetEventSecurityObserver(MyNetEventSecurityObserver)

Controllers and decorators

OpenCore uses a decorator + processor pattern.

Decorators store metadata with Reflect.defineMetadata(). During bootstrap, the MetadataScanner reads metadata and processors register handlers.

Commands

import { Server } from '@open-core/framework/server'
import { z } from 'zod'

const TransferSchema = z.tuple([z.coerce.number().int().positive(), z.coerce.number().min(1)])

@Server.Controller()
export class BankController {
  @Server.Command({
    command: 'transfer',
    usage: '/transfer <id> <amount>',
    schema: TransferSchema,
  })
  @Server.Guard({ rank: 1 })
  @Server.Throttle(1, 2000)
  async transfer(player: Server.Player, args: z.infer<typeof TransferSchema>) {
    const [targetId, amount] = args
    player.emit('chat:message', `transfer -> ${targetId} (${amount})`)
  }
}

Network events

@OnNet() handlers always receive Player as the first parameter.

import { Server } from '@open-core/framework/server'
import { z } from 'zod'

const PayloadSchema = z.object({ action: z.string(), amount: z.number().int().positive() })

@Server.Controller()
export class ExampleNetController {
  @Server.OnNet('bank:action', { schema: PayloadSchema })
  async onBankAction(player: Server.Player, payload: z.infer<typeof PayloadSchema>) {
    player.emit('chat:message', `action=${payload.action} amount=${payload.amount}`)
  }
}

Security decorators

  • @Guard({ rank }) or @Guard({ permission })
  • @Throttle(limit, windowMs)
  • @RequiresState({ missing: [...] })

Testing

Tests run with Vitest.

pnpm test
pnpm test:unit
pnpm test:integration
pnpm test:coverage

Note: pnpm test does not run benchmarks.

Benchmarks

There are two benchmark suites:

  • Core benchmarks (Tinybench)
  • Load benchmarks (Vitest project benchmark)
pnpm bench:core
pnpm bench:load
pnpm bench:all

Snapshot (latest local run)

These values are a small extract from a recent local run (Dec 22, 2025). Results vary by machine.

  • Core
    • Decorators - Define metadata (Command): ~5.72M ops/sec (mean 0.17μs)
    • EventBus - Multiple event types: ~2.01M ops/sec (mean 0.50μs)
    • Dependency Injection (simple resolve): ~1.7M ops/sec
  • Load
    • Net Events - Simple (10 players): ~28.85K ops/sec (p95 0.25ms)
    • Net Events - Concurrent (500 players): ~1.18M ops/sec (p95 0.40ms)
    • Commands (validated, ~500 players): ~14M ops/sec

Full reports and methodology are available in benchmark/README.md.

Reports

Benchmark reports are generated under benchmark/reports/.

  • pnpm bench:all generates aggregated reports (text/json/html)
  • Load metrics used by load benchmarks are persisted in benchmark/reports/.load-metrics.json

For details about the benchmark system, see benchmark/README.md.

Development scripts

pnpm build
pnpm watch
pnpm lint
pnpm lint:fix
pnpm format

Ecosystem

OpenCore is designed to be extended via separate packages/resources.

  • @open-core/identity: identity and permission system

License

MPL-2.0. See LICENSE.

About

TypeScript multiplayer runtime framework targeting FiveM via an adapter.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •