Skip to content

get-wrecked/fivem

Repository files navigation

Medal for FiveM

A FiveM/GTA V server resource that integrates with the Medal.tv desktop client to capture gameplay clips and screenshots. It supports manual capture and optional automatic capture based on ingame events, configurable via an ingame menu.

Features

  • Auto-Clipping UI: Toggle auto-clipping, configure clip length, and enable/disable specific events.
  • Custom Event Signals: Dynamically register your own clipping events at runtime via the registerSignal export.
  • SuperSoaker Screenshots: Drop-in replacement for screenshot-basic, with both local capture, and HTTP upload. Features automatic fallback from Medal.tv to WebGL, if some unforeseen issue with the Medal connection occurs. Medal availability is monitored continuously (configurable interval), adapting in real-time, if Medal starts, stops, or crashes.
  • GameVein Data Pipeline: Allows the Medal client to get game context and server info when clipping.
  • Framework-Aware: The server detects framework (ESX → QBX → QB → ND → OX → TMC → unknown) and provides safe export helpers to avoid errors, without loading any framework resource files directly.

Requirements

  • FiveM server (FX Server from after 2020-05)
  • Medal.tv client installed, and running on the player’s PC (to use the full features)
  • Node.js LTS with pnpm installed (just to build the UI, one time, or avoid this with a Github release).

Installation

  1. Place this resource folder into your server's resources/ directory.

  2. In your server's server.cfg (or whatever config file your server uses to load resources), add the line below (replace with your actual folder name for this resource):

    ensure medal--fivem-resource
  3. Start (or restart) your server.

Usage

  • Ensure the Medal.tv desktop client is running before joining the server.
  • Toggle the Medal UI in-game:
    • Chat command: /medal (from Config.Command)
    • Default keybind: Page Up (from Config.Keybind)
    • The keybind is shown in the UI using FiveM's current binding for the command (resolved via GetHashKey + GetControlInstructionalButton), so if a player rebinds the key in FiveM, the UI label follows their current binding.
    • Send the command again, press the keybind again, press ESC, or click the X button to close the UI. The UI listens for the same key that opened it and closes on key press (keydown).
  • In the UI, you can:
    • Toggle auto-clipping on/off
    • Set clip length
    • Enable/disable individual events

Settings persist via resource KVPs; toggles and clip length are remembered per player.

Auto-Capture Configuration

You can configure automatic capture triggers through the ingame menu. Common examples include:

  • Player deaths/downs
  • Kills or headshots

Your server can enable/disable specific events to fit its gameplay style.

Building

This resource uses a pnpm workspace to manage builds for both the UI and the SuperSoaker HTTP server.

Prerequisites

  • Node.js LTS (v18+)

  • pnpm installed globally:

    npm i -g pnpm

Build Steps

From the root of the resource:

  1. Install dependencies:

    pnpm install
  2. Build everything:

    pnpm build

This builds:

  • UI: ui/srcui/dist (Vite build for the NUI)
  • SuperSoaker Server: superSoaker/src/server/server.tssuperSoaker/dist/server.js (TypeScript → CommonJS)

Individual Builds

  • pnpm build:server - Build only the SuperSoaker HTTP server
  • pnpm build:ui - Build only the React UI
  • pnpm dev:ui - Start Vite dev server for UI development

Note: The compiled superSoaker/dist/server.js must exist before starting the resource.

Release

To create a production-ready release package for deployment to FiveM servers:

pnpm release

To build a fresh release and immediately verify the output in one step, run:

pnpm release:verify

If you only need to run the verification checks against an existing release folder, use:

pnpm verify-release

These commands:

  1. Automatically builds the entire project (UI and TypeScript)
  2. Creates a release/medal/ directory
  3. Packages only production files (~60 files, ~2.3 MB):
    • Core resource files (fxmanifest.lua, config.lua)
    • All Lua scripts (client/server/shared)
    • Built JavaScript (superSoaker/dist/server.js)
    • Built UI (ui/dist/*)
    • Documentation (all README files, LICENSE)

The release script:

  • Dynamically excludes files from .gitignore and .git/info/exclude
  • Preserves built dist folders (overriding gitignore) as they contain production code
  • Works on Windows, Linux, and macOS
  • Verifies the release contents to ensure required files ship and unwanted files stay excluded (release:verify or verify-release)

The resulting release/medal/ folder can be directly copied to your FiveM server's resources directory.

Configuration Highlights

  • config.lua
    • Config.Command and Config.Keybind control how players open the UI.
    • Config.ClippingEvents pre-registers events visible in the Auto-Clipping UI.
    • Config.Screenshots
      • MedalPreferred: Prefer Medal.tv for screenshots when available. If Medal is unable to respond (network errors, timeouts, etc.), the resource automatically falls back to WebGL/Three.js capture. Medal availability is checked periodically (default: 3 seconds, configurable via Config.Medal.CheckIntervalMs), allowing automatic adaptation if Medal starts, stops, or crashes during gameplay.
      • ScreenshotBasicOverride: Provides compatibility for screenshot-basic exports.

Exports

Client Exports

  • fillSoaker(options?: SoakerOptions, cb: fun(data:string))

    • Capture a screenshot and return a Data URI to the callback.

    • Example:

      --//=-- Local screenshot as Data URI
      exports['medal--fivem-resource']:fillSoaker({ encoding = 'jpg', quality = 0.92 }, function(data)
        TriggerEvent('chat:addMessage', { template = '<img src="{0}" style="max-width: 300px;" />', args = { data } })
      end)
  • shootWater(url: string, field: string, options?: SoakerOptions, cb: fun(result:string))

    • Capture a screenshot and upload as multipart/form-data to url, invoking the callback with the HTTP response text.

    • Example:

      --//=-- Upload screenshot
      exports['medal--fivem-resource']:shootWater('https://your-upload/endpoint', 'file', {
        encoding = 'jpg', quality = 0.9, headers = { Authorization = 'Bearer XYZ' }
      }, function(resp)
        print('upload result', resp)
      end)
  • registerSignal(event: string, options: EventConfig)

    • Dynamically register a custom auto-clipping event with the UI and handler.

    • Example:

      --//=-- Register a custom event; when `my:custom:event` is triggered, a clip request is sent
      exports['medal--fivem-resource']:registerSignal('my:custom:event', {
        id = 'my_custom_event',
        title = 'My Custom Event',
        desc = 'Triggers on my custom event',
        enabled = true,
        tags = { 'custom' }
      })

EventConfig shape

Event configs define how an auto-clipping event appears and behaves in the UI. See clipping/__types.lua.

EventConfig = {
  id: string,           -- unique id used internally and for persistence
  title: string,        -- display name in the UI
  desc?: string,        -- optional description shown in the UI
  enabled?: boolean,    -- whether the event is enabled by default
  tags?: string[],      -- optional tags passed along with clip requests
}

Server Exports

  • requestPlayerWater(player: number, options: SoakerOptions, cb: fun(err:any|false, data:string, src:number))
    • Ask a specific player to capture a screenshot; the callback receives a Data URI.

    • Example:

      --//=-- Request a screenshot from a player
      exports['medal--fivem-resource']:requestPlayerWater(source, { encoding = 'png' }, function(err, data, src)
        if err then print('screenshot error', err) return end
        print(('player %s returned %d bytes'):format(src, #data))
      end)

Notes on Compatibility

  • When Config.Screenshots.ScreenshotBasicOverride = true, the resource provides handlers compatible with screenshot-basic client/server exports (fill/upload and request client screenshot). Prefer the fillSoaker/shootWater/requestPlayerWater exports shown above for consistent behavior.

Additional READMEs for Features

Primary Contributors

View All Contributors (Click Here)


If you encounter issues, or want to suggest new auto-clipping events, please open an issue or PR.

About

The Offical Medal FiveM Resource

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 6