Willkommen in der offiziellen Entwickler- und Betreiber-Dokumentation von Ancomox. Hier findest du zu jedem FiveM-Script die vollständige Anleitung: Installation, Voraussetzungen, Datenbank- und Panel-Sync, jede Config-Option und jeden Export mit Code-Beispiel.
Das Ökosystem
Ancomox ist die Dachmarke für alle hier dokumentierten FiveM-Ressourcen. Die Produkte teilen sich in zwei Gruppen:
Panel-gebundene Produkte — EmergencyOS und LicenseOS sind Web-Anwendungen. Akten, Fahndungen, Tickets, LiveMap und Statistiken werden im Browser unter emergencyos.de verwaltet, unabhängig von FiveM. Die zugehörigen FiveM-Ressourcen sind kostenlos und bringen das Panel als Tablet ins Spiel — dazu Funktionen, die nur dort möglich sind. Die Synchronisation läuft über eine gesicherte HTTP-Bridge. Für EmergencyOS gibt es zusätzlich einen Client für Garry’s Mod. Für die Nutzung wird ein kostenloses Panel-Konto mit API-Key benötigt.
Eigenständige Ressourcen — DispatchOS, Ancomox Garage, Vehicle Shop, Ancomox Warehouse, Ancomox Airdrop, Ancomox Fishing, DriveOS, Ancomox Admin Suite, Ancomox Activity Suite, Architect, die Börse, das HUD, GPS + Job + Admin Blips, Ancomox Banking und Ancomox Crafting laufen ohne Panel-Konto direkt auf deinem Server und binden sich nur an Framework, Datenbank und Inventar. Bei DispatchOS gibt es zusätzlich eine optionale Web-Leitstelle — sie erweitert den Funktionsumfang, wird aber für den Betrieb nicht benötigt.
Produkte im Überblick
Produkt
Zweck
Exports
EmergencyOS
Hauptsystem: Tablet/MDT für Polizei, Medic, Justiz & Feuerwehr
19
DispatchOS
Leitstelle / Dispatch / MDT mit umfangreicher Export-API
23
LicenseOS
Führerschein- & Fahrschulsystem
4
Ancomox Garage
Multi-Framework-Garagensystem
2
Vehicle Shop
Fahrzeug-Shop / Autohaus
Events
Ancomox Warehouse
Private Lagerhallen: kaufen, mieten, ausbauen, im Team teilen
4
Ancomox Airdrop
Versorgungsabwürfe mit Flugzeug, Fallschirm und Loot-Container
3
Ancomox Fishing
Angeln mit 3D-Showcase, Minigame, Markt, Turnieren & Bootsverleih
9
DriveOS
Automatische Fahrschule — Theorie & Praxis ohne Fahrlehrer
2
Ancomox Admin Suite
Admin-Panel im Spiel und im Browser, mit feingranularem Rechtesystem
—
Ancomox Activity Suite
Player-Analytics, Reports, Bans & Spielerakten
—
Architect
Bauwerkzeug mit Live-3D-Vorschau, Blueprints & Job-Rechten
Wähle links in der Sidebar ein Produkt — jede Seite ist gleich aufgebaut: Überblick → Voraussetzungen → Installation → Datenbank & Sync → Konfiguration → Exports → Events & Commands → Troubleshooting.
Allgemeine Voraussetzungen
Aktueller FiveM-Server (Artifacts)
oxmysql als Datenbank-Layer
Framework: ESX, QBCore / Qbox oder Standalone (je nach Script frei wählbar)
Ein kostenloses EmergencyOS-Panel-Konto mit API-Key — nur für die panel-gebundenen Scripts EmergencyOS und LicenseOS. Alle übrigen Ressourcen laufen ohne Konto.
So funktioniert die Panel-Anbindung
Jedes panel-gebundene Script verbindet sich beim Start automatisch mit dem Web-Panel — Server-IP und Port müssen nirgendwo eingetragen werden:
Im Panel unter Einstellungen → Datenbank Sync (bzw. FiveM-Bridge) einen API-Key erzeugen.
Den Key in die jeweilige config.lua / api_config.lua eintragen (SVConfig.API.key bzw. Config.ApiKey).
Ressource neu starten — der Server registriert sich selbst am Panel (IP/Port automatisch). Fertig.
Tipp: Die genauen Schritte, Endpunkte und Fehlerbilder stehen bei jedem Produkt in den Abschnitten „Installation" und „Datenbank & Panel-Sync".
Konventionen in dieser Doku
Code in dieser Schrift = exakte Datei-, Config- oder Exportnamen aus dem Quellcode.
Tabellen listen Key · Standard · Beschreibung — die Standardwerte sind die echten Defaults aus dem ausgelieferten Code.
Store
Alle hier dokumentierten Ressourcen findest du im offiziellen Ancomox-Store. Jede Produktseite in dieser Doku verlinkt oben direkt auf den passenden Artikel.
EmergencyOS ist die Ingame-Extension (Tablet/MDT) zum EmergencyOS-Web-Panel (emergencyos.de). Das Tablet ist die Bedienoberfläche im Spiel; die eigentliche Fach-App (Akten, Fahndungen, Tickets, LiveMap, Statistiken) läuft als Web-Panel, mit dem sich der Spielserver über eine HTTP-Bridge synchronisiert.
Zielgruppe / Fraktionen: Polizei/Behörden (LSPD, FIB, LSSD/Sheriff), Justiz (DOJ), Rettungsdienst (LSMD/Medic) und Feuerwehr (LSFD). Die Abteilungs-Sichtbarkeit ist strikt getrennt. Standard-Whitelist im Code: police, ambulance, fib, justiz, admin.
Kernfeatures (aus CHANGELOG/README):
- MDT/Tablet mit Multi-Window, freiem Resizing, Dark-Design, Rich-Text-Editor (Quill, Auto-Save), Aktenvorlagen.
- Personen- & Fahrzeugakten, Fahndungssystem (Wanted/BOLO) — intern & öffentlich; öffentliche Fahndungen laufen als DUI-Carousel auf Welt-Bildschirmen (Config.WantedBillboards).
- Digital Citation / Ticketsystem — inszeniertes Strafzettel-Ausstellen mit Beweisfoto (Evidence Cam → Discord), animiertem Beleg, Bürgerportal /strafzettel zum Einsehen & Bezahlen.
- Bußgeldrechner mit dynamischen Modifikatoren (Geständig −20 %, Wiederholungstäter +50 %).
- Sofort-Halterabfrage (F9 / /runplate) mit HUD und BOLO-Treffer.
- App „Dienst & Statistik" — automatische Dienstzeit-Erfassung nach Job, Live-Dienststand, Leaderboard, Team-Übersicht, Dienstpflicht/Wochen-Soll, AFK-Schutz, optionaler Discord-Wochenbericht.
- Verhaftungs-Anbindung für eigene Jail-Scripts (RecordArrest), Dispatch-Anbindung (Vanguard Dispatch Gateway).
- Panic Button (10-13), interner Monitor (Atlas-Feed auf Wachen-Screens), KI-gestützte Tatberichte, Beweismittel-Verwaltung, FIB „Nexus Netzwerk".
- Framework-agnostisch: ESX, QBCore oder STANDALONE (Custom) über die Data-Provider-API.
Voraussetzungen
Aus fxmanifest.lua (fx_version 'bodacious', game 'gta5', lua54 'yes'):
Voraussetzung
Pflicht
Hinweis
oxmysql
Ja (harte Abhängigkeit)
Muss vor EmergencyOS starten.
EmergencyOS-Panel-Konto
Ja
Instanz + API-Key auf emergencyos.de (ab Free-Version kostenlos).
Framework
Optional
es_extended (ESX) oderqb-core (QBCore) für Auto-Integration; sonst STANDALONE + Data Provider.
ox_lib
Optional
Standard-Benachrichtigungen (ox_lib:notify).
screenshot-basic
Optional
Nötig für Panel-Screenshots + Evidence Cam der Ticket-Zeremonie.
Es gibt keine expliziten dependency-Zeilen im Manifest außer @oxmysql.
Installation
Ordnername: Die Resource muss exakt EmergencyOS heißen (Groß-/Kleinschreibung beachten — der Code nutzt durchgängig exports['EmergencyOS'] und GetCurrentResourceName()).
API-Key erstellen: Im Panel unter Einstellungen → Datenbank Sync → API-Key — diesen Button sieht nur der Besitzer-Account. Neue Keys tragen das Präfix eos_.
Key eintragen: In config/api_config.lua → SVConfig.API.key (Details im nächsten Abschnitt).
Framework wählen: In config/config.luaConfig.Framework auf "ESX", "QBCORE" oder "STANDALONE" setzen; bei STANDALONE zusätzlich Data Provider registrieren (siehe README_CUSTOM_FRAMEWORK).
Server starten — fertig. Server-IP und Port müssen nirgendwo eingetragen werden: Der Server registriert sich beim Start selbst am Panel und schickt beim Handshake Resource-Name und Server-Port (GetConvar('netPort', '30120')) mit; das Panel hinterlegt IP, Port und Resource-Name automatisch als Push-Rückkanal. Erfolg: [EmergencyOS] v… bereit | Panel verbunden (Instanz <id>) — Sync aktiv.
Datenbank & Panel-Sync
Die Synchronisation läuft über eine bidirektionale HTTP-Bridge (server/api_endpoint.lua, server/sync_bridge.lua). Der Spielserver ruft das Panel unter https://emergencyos.de/api/… auf; das Panel ruft umgekehrt den FiveM-HTTP-Endpoint des Servers auf (SetHttpHandler, Autorisierung per Api-Key).
Einrichtung (neuer Weg, ab v3-Handshake)
Key erstellen: Panel → Einstellungen → Datenbank Sync → API-Key (nur Besitzer-Account). Neue Keys tragen das Präfix eos_.
Key eintragen in config/api_config.lua → SVConfig.API.key.
Resource neu starten — fertig. Server-IP/Port müssen nirgendwo eingetragen werden: der Server registriert sich beim Start selbst am Panel und schickt beim Handshake Resource-Name und Server-Port (GetConvar('netPort', '30120')) mit; das Panel registriert IP/Port/Resource-Name automatisch als Push-Rückkanal.
Handshake-Logik (api_endpoint.lua)
Self-Service-Key (eos_…): Anmeldung nur mit dem Key. Header: Api-Key, Resource-Name, Server-Port, optional Server-Ip (nur wenn SVConfig.API.serverIp gesetzt). Ziel: GET https://emergencyos.de/api/getInstance → liefert die numerische Instance-ID (GlobalInstanceId).
Legacy-Key (ohne eos_, Ancomox-Bestandskunden): zusätzlich Instance-Username + Instance-Password (aus SVConfig.API.username/password) erforderlich. Fehlen sie, bricht der Handshake mit klarer Konsolenmeldung ab (kein weiterer Versuch bis Neustart).
Retry/Backoff: Bei nicht erreichbarem Panel automatische Wiederholung 10s → 30s → 60s → 2min → 5min. HTTP 400 (unvollständige Daten) stoppt dauerhaft mit Anleitung; 401/403 (Key falsch/abgelaufen) zeigt einmal einen Hinweis und versucht danach leise alle 10 min erneut.
Re-Handshake: Nach Erst-Erfolg meldet sich der Server stündlich erneut an (registriert IP/Port bei Server-Umzug automatisch neu).
Nach Verbindung wird nach 5 s die animierte Fahndungs-Rotation gestartet (api/wantedCarousel.php?instance=<id>).
Sicherheit des eingehenden Endpoints
Nur POST mit gültigem Key (Header Authorization: Bearer <key> oder Api-Key), Vergleich in konstanter Zeit (SecureCompare).
U. a. syncWanteds (BOLO-Push), getDispatchState, dispatchCreateCall, dispatchAssign, dispatchClose, createBill, liveConsoleLog sowie die Data-Provider-Actions (getVehicle, searchPlayers, getPlayer, searchVehicles, trackPhone, getJobPlayerPositions).
BOLO/Fahndungs-Cache (sync_bridge.lua)
RAM-Cache mit 3 Quellen (Priorität absteigend): 1) Push (Actions['syncWanteds']), 2) Pull (api/getWanteds.php, Intervall SVConfig.BoloPullInterval, Default 300000 ms), 3) DEV-Fallback (direkte DB app_wanteds/app_vehicleRegister, nur wenn SVConfig.BoloDevFallback == true). MDT-Lookups werden SVConfig.MdtCacheTTL ms (Default 90000) gecacht, mit Live-Fallback auf die Data-Provider-Actions.
Konfiguration
config/config.lua (Client & Shared)
Key
Standard
Beschreibung
Config.Framework
"ESX"
Framework: "ESX", "QBCORE" oder "STANDALONE" (Custom, via Data Provider).
Config.TargetSystem
"none"
Target-System für Interaktionen; unterstützt "ox_target", sonst eigene Marker-/Tasten-Logik.
Config.Locale
"en"
Sprache der Tablet-Meldungen: "en" oder "de" (siehe locales.lua).
Config.ScreenshotWebhook
"https://discord.com/api/webhooks/"
Discord-Webhook für Panel-Screenshots + Evidence Cam. Leer/Platzhalter = deaktiviert.
Config.Prop
"prop_cs_tablet"
Handobjekt beim geöffneten Tablet.
Config.Animation.dict
"amb@world_human_tourist_map@male@base"
Anim-Dictionary der Haltung (auch für Ticket-Zeremonie).
Config.Animation.anim
"base"
Anim-Name.
Config.EnablePanicButton
true
Panic Button (10-13) aktivieren.
Config.PanicButtonCommand
"panicbutton"
Command-Name (/panicbutton).
Config.PanicButtonKey
"P"
Standard-Taste (GTA-Settings, frei belegbar).
Config.ServerPraefix
"TestServerInstance346"
Präfix für lokal gespeicherte Zugangsdaten (KVP). Pro Instanz eindeutig wählen!
Config.AutoFill.AutoFillPW
true
Gespeicherte Zugangsdaten ins Login eintragen.
Config.AutoFill.AutoLogin
true
Zusätzlich automatisch einloggen.
Config.AutoFill.AutoFillLogout
true
Daten auch nach Logout wieder eintragen.
Config.EnableParallax
true
Parallax-/Tiefeneffekt der Oberfläche (kosmetisch).
ShouldPadBeLocked()
return false
Funktion: eigene Zusatzbedingung; true = Tablet gesperrt.
Config.LockPadWhileDead
true
Tablet sperren, solange der Spieler tot ist.
Config.PlayerDeadEvent
"esx:onPlayerDeath"
Framework-Event Tod (bei Custom anpassen).
Config.PlayerReviveEvent
"esx_ambulancejob:revive"
Framework-Event Wiederbelebung.
Config.PlayerSpawnedEvent
"playerSpawned"
Framework-Event Spawn.
Config.EnableJobLock
true
true = nur Whitelist-Jobs dürfen das Tablet öffnen.
Config.WhitelistedJobs
{"police","ambulance","fib","justiz","admin"}
Jobs mit Tablet-Zugriff; steuert auch F9-Halterabfrage, Atlas-LiveLog-Empfang, Beamtenerkennung, serverseitige Event-Prüfung.
Config.UseKeyMapping
true
Tablet per Taste/Command öffnen (RegisterKeyMapping).
Config.DefaultKeybind
"MULTIPLY"
Standard-Taste (GTA-Bezeichner, hier Numpad *).
Config.KeyBindText
"Open EmergencyOS Tablet"
Beschriftung in den GTA-Tastatureinstellungen.
Config.NeedItem
false
true = Item im Inventar nötig.
Config.PadItems
{"tablet","othertablet"}
Item-Namen, die als Tablet gelten.
Config.UsePadOnFoot
true
Tablet zu Fuß nutzbar.
Config.OnFootFullscreen
false
Zu Fuß im Vollbild öffnen.
Config.UsePadInCar
true
Tablet im Fahrzeug nutzbar.
Config.PadInCarFullscreen
true
Im Fahrzeug im Vollbild öffnen.
Config.OpenKey
"E"
Interaktionstaste an Positionen/Props (Anzeige-Text).
Config.PlayerJobChange
"esx:setJob"
Framework-Event bei Jobwechsel (aktualisiert Whitelist live).
Config.EnablePositions
true
Feste Terminal-Positionen aktivieren.
Config.OpenDistance
2.0
Interaktionsdistanz zur Position (m).
Config.MarkerDrawDistance
5.0
Ab dieser Distanz wird der Marker gezeichnet (m).
Config.Positions
1 Beispiel (position01, Mission Row)
Terminal-Liste. Pro Eintrag: position (vector3), jobs, helpnotify, fullscreen, marker{enabled,type,moveUpDown,rotate,color{r,g,b,t},size{x,y,z}}.
Bürgerbüro-Punkte. Pro Eintrag: coords (vector4), ped (Model oder false), scenario, label, blip{enabled,sprite,color,scale,label}. NPCs spawnen ab 45 m, despawnen ab 65 m.
Config.DutyStats.enabled
true
App „Dienst & Statistik" aktivieren.
Config.DutyStats.onDutyJobs
{'police','fib','ambulance'}
Jobs, die als „im Dienst" zählen (getrennt von WhitelistedJobs; Off-Duty-Jobs weglassen).
Config.DutyStats.jobCheckInterval
15
Sek.: wie oft der Server den Job prüft (min. 5).
Config.DutyStats.flushInterval
120
Sek. bis zur Persistierung in die Spiel-DB (min. 30).
Config.DutyStats.trackActivity
true
Festnahmen/Panic/Scans/Halterabfragen mitzählen.
Config.DutyStats.leaderboardLimit
25
Leaderboard-Länge (min. 5).
Config.DutyStats.notifyOnChange
true
Kurze Info + Atlas-Log bei Dienstwechsel.
Config.DutyStats.hud
false
Dezentes Live-HUD (IM DIENST + Schichtzeit).
Config.DutyStats.hudPosition
{x=0.015, y=0.62}
HUD-Position.
Weitere Config.DutyStats-Optionen (im Code unterstützt, in der Default-Config nicht ausgeschrieben — bei Bedarf ergänzen):
Key
Standard
Beschreibung
Config.DutyStats.afkPause
true
AFK-Schutz aktiv (keine Dienstzeit bei Untätigkeit).
Diese Datei enthält Stub-Funktionen, die bei Custom-Frameworks überschrieben werden können. Standardwerte:
Funktion
Standard-Verhalten
Beschreibung
FrameworkGetPlayerJob()
return playerJobName
Liefert den aktuellen Client-Jobnamen.
FrameworkDoesPlayerHaveItem(item)
return true
Item-Besitzprüfung (Standard: immer true).
EMOSHelpNotify()
leer
Hook für eigene Help-Notify-Anzeige.
HelpNotifyClose()
leer
Hook zum Schließen der Help-Notify.
Exports
exports['EmergencyOS']:<Name>(...). Insgesamt 19 registrierte Exports (5 Client, 14 Server).
Client-Exports (client/client.lua)
LockEmergencyOS() — Client. Schließt das Tablet und sperrt das Öffnen (IsPadLocked = true). Keine Rückgabe.
exports['EmergencyOS']:LockEmergencyOS()
UnlockEmergencyOS() — Client. Hebt die Sperre auf. Keine Rückgabe.
exports['EmergencyOS']:UnlockEmergencyOS()
CloseEmergencyOS() — Client. Schließt das Tablet (ohne Sperre).
exports['EmergencyOS']:CloseEmergencyOS()
OpenTablet([fullscreen]) — Client. Öffnet das Tablet; fullscreen (bool) erzwingt Vollbild.
exports['EmergencyOS']:OpenTablet(true)
SetPlayerJob(jobName) — Client. Setzt den lokal bekannten Job (Bridge.PlayerJob) für Whitelist/UI. Bei STANDALONE/Custom bei Charwahl, Spawn und Jobwechsel aufrufen.
exports['EmergencyOS']:SetPlayerJob("police")
Server-Exports
SetPlayerJob(source, jobName) — Server (server.lua). Setzt global den Job eines Online-Spielers (Bridge.PlayerJobs[src]) für Whitelist-Prüfung, LiveMap-Gruppen und Panic-Broadcast.
local src = exports['EmergencyOS']:ResolveIdentifierToSource(ident)
RecordArrest(officerSrc) — Server (sv_duty.lua). Schreibt dem Beamten eine Verhaftung gut (erscheint in Team-Übersicht/Detailansicht/Settings). Rückgabe: true/false (false bei ungültiger/offline Source).
exports['EmergencyOS']:RecordArrest(officerSource) -- aus dem eigenen Jail-Script
AddOfficerActivity(officerSrc, column, amount) — Server (sv_duty.lua). Erhöht einen beliebigen Aktivitäts-Zähler (z. B. 'arrests', 'scans', 'plate_checks', 'panics').
IsPlateWanted(plate) — Server (sync_bridge.lua). true, wenn das (normalisierte) Kennzeichen im BOLO-RAM-Cache steht. Nicht-blockierend.
if exports['EmergencyOS']:IsPlateWanted("LS12345") then ... end
GetWanteds() — Server (sync_bridge.lua). Gibt wanteds (Tabelle) und version (Zahl) des aktuellen BOLO-Cache zurück.
local wanteds, version = exports['EmergencyOS']:GetWanteds()
MdtLookup(payload, cb) — Server (sync_bridge.lua). Asynchrone MDT-Abfrage ans Panel (mit Live-Fallback + Cache). payload z. B. { action="personDetail", id="emergencyos__LIVE:..." } bzw. { action=..., query=... }. Ergebnis kommt über cb(result).
EmergencyOS:ScanClosestPlayer — TriggerServerEvent. Payload: targetServerId (number). Serverseitige Distanzprüfung (≤ 6 m), öffnet die Personenakte des Ziels beim scannenden Beamten (ForceOpenRecord). Zählt als Aktivität scans.
EmergencyOS:CheckALPR — TriggerServerEvent. Payload: plate (string, ≤ 12 Zeichen). Prüft BOLO-Status, Cooldown 10 s pro Spieler/Kennzeichen; bei Treffer ALPRResult an den Absender.
Sofort-Halterabfrage (Standard-Keybind F9, aus Config.PlateCheck.defaultKey).
/panicbutton
Client
Panic Button 10-13 (Standard-Taste P; aus Config.PanicButtonCommand/PanicButtonKey).
/scanid
Client
Scannt den nächsten Spieler im Radius 3,0 m (nur Whitelist-Jobs) → öffnet dessen Akte.
/toggleterminal
Client
Schaltet die eingebaute System-Konsole (Terminal) im Tablet um.
/emos_fix
Client
Rettungsanker: setzt festgefahrene Anzeigen/NUI sofort zurück.
/emos_ticketfx <targetId> [betrag] [grund…] bzw. emos_ticketfx demo …
Server/Konsole
Test der Ticket-Zeremonie (keine echte Rechnung). Konsole oder Whitelist-Beamter.
/emos_dutydebug
Server/Konsole
Diagnose: zeigt pro Online-Spieler den erkannten Job, On-Duty-Status, Identifier, emos_duty_stats-Zeilen — zum Ermitteln der exakten Jobnamen für onDutyJobs.
HTTP 400 → Anmeldedaten unvollständig: bei eos_…-Key darf nur der Key gesetzt sein; bei Legacy-Key müssen username+password gesetzt sein. Danach Resource neu starten.
HTTP 401/403 → Key falsch/abgelaufen. Nach „Key neu generieren" im Panel den neuen Key eintragen. Weitere Versuche laufen leise alle 10 min.
„Panel nicht erreichbar" → Netzwerk/Firewall; Retry-Backoff greift automatisch.
Multi-IP-Server: Schlägt der Verbindungstest im Panel trotz laufendem Server fehl, die erreichbare FiveM-IP in SVConfig.API.serverIp eintragen (überschreibt die Auto-Erkennung).
BOLO-Pull-Warnung (api/getWanteds.php HTTP ≠ 200) → Panel-Dateien nicht/veraltet deployed. Für Dev ohne deployte PHP: SVConfig.BoloDevFallback = true (nur bei geteilter DB).
Framework-Bridge / Custom Framework: Bei Config.Framework="STANDALONE" liefern nur registrierte Data-Provider-Hooks Daten; ein Hook, der nil liefert, gilt als „nicht gefunden" (kein Fallback auf ESX/QB). Hooks müssen synchron sein (oxmysql:executeSync). Jobs zusätzlich über SetPlayerJob (Server und Client) setzen. getIdentifier muss Reconnects überleben (Server-IDs ungeeignet); ohne Provider wird die FiveM-License genutzt.
Dienstzeiten falscher/kein Job erkannt:/emos_dutydebug zeigt den exakt erkannten Jobnamen → in Config.DutyStats.onDutyJobs bzw. jobFaction eintragen; Off-Duty-Jobs nicht auflisten.
Ticket-Zeremonie ohne Beweisfoto:screenshot-basic fehlt oder Config.ScreenshotWebhook ist leer/Platzhalter → Evidence Cam deaktiviert.
Tickets vor dem Update lassen sich nicht nachträglich Beamten zuordnen (Zählung ab Einspielen).
Update-Check meldet dauerhaft „neue Version":version.json auf dem Webserver an die tatsächliche Resource-Version 3.9.6 anpassen.
Leitstellen-, Dispatch- und MDT-System für FiveM. Quelle: [ANCOMOX]/dispatchos · Version 2.22.0.
Überblick
Zweck: DispatchOS ist das zentrale Notruf-, Einsatz- und Leitstellensystem. Es nimmt Alarme (automatisch erkannt oder per API) entgegen, legt Einsätze („Calls") mit Priorität, Blip, Zone und Timeline an, verteilt sie an die zuständigen Fraktionsgruppen und stellt eine Vollbild-Leitstelle mit Taktikkarte bereit. Architektur laut Manifest: „RAM-first, Push statt Polling, serverseitig validiert".
Kernfeatures (aus README.md und Code verifiziert):
- Automatische Einsätze (Detektoren): Schüsse, Drive-by, Fahrzeugraub, Schlägerei, Unfall, Raser, Person am Boden, ALPR-Treffer, Panik, Zivil-Notrufe — mit Merge naher Mehrfachmeldungen (MergeRadius/MergeTime).
- Leitstelle / Dispatch Center (F6): Taktikkarte mit Live-Einheiten, Icon-Marker je Code, Einsatzliste + Filter, Detail-Dock mit Timeline & Notizen, Zuweisung, Fahndungs-Ticker (BOLO), Ø-Reaktionszeit-KPI, 7-Tage-Statistik-Cockpit, Panic-Auto-Fokus.
- MDT (F7): Kennzeichen-/Personenabfrage aus der Spieldatenbank (DirectDB) oder über EmergencyOS-Gateway; Fahndungsabgleich, Live-Online-Status.
- ALPR (F10/F11): Kennzeichenscanner im Einsatzfahrzeug per Raycast mit 3D-Holo-Marker und Fahndungstreffer.
- Schnellfunk (F5): konfigurierbare 10-Codes + Freitext + Position.
- Panic Button, Smart-3D-Ping, Eskalation (P3→P2→P1), Zonen-Routing, Rechte-System, Auto-Zuweisung bei Panik/Backup.
- Notruf-Integration: lb-phone (Nachricht + Anruf + Handy-Alerts) und generische Export-API für andere Telefon-Scripts.
- Optionale Web-Leitstelle (dispatchos.de) und EmergencyOS-Panel-Anbindung über FiveM-Events.
- Zweisprachig (de/en), Discord-Webhook-Feed integriert.
Voraussetzungen
Das fxmanifest.lua deklariert keinedependencies — alle Abhängigkeiten werden zur Laufzeit per GetResourceState(...) weich erkannt. Manifest-Eckdaten:
Manifest-Feld
Wert
fx_version
cerulean
game
gta5
lua54
yes
ui_page
html/index.html
Abhängigkeiten (alle laufzeit-erkannt, keine harte Pflicht):
Komponente
Pflicht
Zweck
FiveM-Server (aktuelle Artifacts)
ja
Basis
oxmysql
empfohlen
Persistenz (dispatchos_calls), Statistik/Heatmap, MDT-DirectDB. Ohne → alles läuft RAM-only, keine DB-Statistik.
In server.cfgnach oxmysql, Framework und (optional) EmergencyOS starten:
cfg
ensure oxmysql
ensure es_extended # bzw. qb-core / qbx_core
ensure EmergencyOS # optional
ensure dispatchos
Tabelle dispatchos_calls wird beim ersten Start automatisch angelegt bzw. migriert (fehlende Spalten werden ergänzt; einmalige Übernahme einer alten vanguard_calls-Tabelle).
config.lua anpassen — v. a. VConfig.JobGroups an die eigenen Fraktions-Jobs.
Panel-Bezug: Zwei optionale Anbindungen (beide ohne Ingame-Paywall): die gehostete Web-Leitstelle (VConfig.WebLink, Modul web_link) und das EmergencyOS-Panel (rein über FiveM-Events, siehe nächster Abschnitt).
Datenbank
Nur bei VConfig.PersistCalls = trueund gestartetem oxmysql. Eine Tabelle:
dispatchos_calls — angelegt via CREATE TABLE IF NOT EXISTS, danach Auto-Migration der Spalten (SHOW COLUMNS → fehlende per ALTER TABLE ADD COLUMN).
Spalte
Typ
Bemerkung
id
INT AUTO_INCREMENT PK
code
VARCHAR(16)
z. B. 10-71
label
VARCHAR(120)
street
VARCHAR(96)
priority
TINYINT DEFAULT 3
1–3
x, y, z
FLOAT DEFAULT 0
z per Migration ergänzt
responded_at
TIMESTAMP NULL
erste Zuweisung → Reaktionszeit-KPI
arrived_at
TIMESTAMP NULL
Auto-„Angekommen"
zone
VARCHAR(48)
Zuständigkeitszone
reports
INT DEFAULT 1
Anzahl gemergter Meldungen
units
INT DEFAULT 0
zugewiesene Einheiten (bei Close)
created_at
TIMESTAMP DEFAULT CURRENT_TIMESTAMP
Index idx_created
closed_at
TIMESTAMP NULL
Engine InnoDB, Charset utf8mb4. Retention: Zeilen älter als VConfig.DBRetentionDays werden periodisch gelöscht (Batch LIMIT 5000; 0 = nie). Einmal-Rename beim Start: falls vanguard_calls existiert und dispatchos_calls nicht, wird umbenannt (Bestandsdaten-Übernahme).
Die MDT-DirectDB liest zusätzlich fremde Tabellen (nur SELECT, keine eigene Anlage): ESX users/owned_vehicles, QBCore players/player_vehicles sowie optional eine lb-phone-Tabelle (Default phone_phones). Tabellennamen über VConfig.MDT.DirectDB überschreibbar.
Sync / Panel-Anbindung
A) EmergencyOS-Panel (Event-basiert, keine Webserver-Last)
Wird automatisch aktiv, sobald GetResourceState('EmergencyOS') == 'started':
- BOLO/Fahndung: DispatchOS ruft per pcall einen der Exports exports.EmergencyOS:GetWanteds/GetBolos/GetWantedPlates/GetWantedList ab (erster funktionierender wird gemerkt) und exports.EmergencyOS:IsPlateWanted(plate). Push-Refresh über Listener EmergencyOS:WantedsUpdated.
- Panic: Kompatibilitäts-Listener RegisterNetEvent('EmergencyOS:PanicButton', ...) — Tablet-Panik landet direkt als Einsatz (Dedupe über Cooldown).
- Atlas-Feed: internes Event dispatchos:dispatch:broadcast transportiert alle Dispatch-/Funk-/Status-Ereignisse (auch Discord/Phone/WebLink hängen hier dran).
- MDT-Gateway:exports.EmergencyOS:MdtLookup(payload, cb) (Panel-Akten + Live-Fallback), genutzt wenn DirectDB aus ist bzw. für Panel-Anreicherung (PanelEnrich/PanelFileLookup).
- Akte öffnen: NUI-Callback mdtOpenRecord → TriggerEvent('EmergencyOS:ForceOpenRecord', id).
- Externer Fokus:AddEventHandler('dispatchos:client:FocusCall', callId) öffnet die Leitstelle und fliegt per Kamera auf den Einsatz (für Atlas-Terminal-Klick).
- Statistik/Heatmap: gemeinsame Tabelle dispatchos_calls.
Für vollen Umfang liegen dem EmergencyOS-Paket 3 aktualisierte Dateien bei (html/app.js, Panel-Terminal.php, kleine client.lua-Ergänzungen). MDT.PanelFileLookup erst nach verbundener Panel-API (gültiger API-Key) aktivieren.
B) Web-Leitstelle (modules/web_link/server.lua, optional)
Nur aktiv, wenn VConfig.WebLink.Token gesetzt und kein Platzhalter ist (Platzhalter-Liste im Code: '', HIER_DEN_TOKEN_EINFUEGEN, los_HIER_DEN_KEY_EINFUEGEN). Ohne gültigen Token: Modul kehrt sofort zurück → reines Standalone.
Nur ausgehendes HTTPS (PerformHttpRequest), kein offener Port. Auth per Authorization: Bearer <Token>undApi-Key: <Token> (Apache/PHP-FPM-Kompatibilität).
Handshake:GET {BridgeUrl}/v1/hello → prüft Token; Klartext-Feedback in der Konsole (gültig / abgelaufen / unerreichbar / ungültig).
Alle Optionen aus config.lua (VConfig = {}). Zusätzlich am Ende die hartcodierten Blöcke aus server/main.lua (Discord/Auto-Panik) und Config-Keys, die der Code liest, aber die shipped config.luanicht enthält (mit „(nicht in config.lua)").
Verhindert Öffnen, wenn anderes NUI den Focus hält.
DispatchCenter.PanicFocus
true
Auto-Kameraflug bei Panik (10-13).
DispatchCenter.MapIcons
Tabelle
FontAwesome-Icon je Code, z. B. ["10-71"]="fa-gun", default="fa-location-dot".
DispatchCenter.Map.Image
"map/atlas.jpg"
Kartenbild.
DispatchCenter.Map.Width/Height
4096 / 4096
Bildmaße.
DispatchCenter.Map.MinX/MaxX
-5661.196911 / 6694.015444
Weltkoordinaten-Mapping X.
DispatchCenter.Map.MinY/MaxY
-4058.536586 / 8429.268293
Weltkoordinaten-Mapping Y.
DispatchCenter.Map.PosInterval
2500
Positions-Broadcast-Takt (ms; min. 1000 erzwungen).
Statuscodes, Eskalation, Funk
Key
Standard
Beschreibung
Statuses
{"10-8","10-6","10-7","10-11","10-15","10-97"}
Gültige Unit-Status-Codes.
Escalation.Enabled
true
Auto-Höherstufung wartender Einsätze.
Escalation.Steps
{[3]=120, [2]=180}
Sekunden ohne Einheit je Stufe (P3→P2 nach 120 s, P2→P1 nach 180 s).
Radio.Enabled
true
Schnellfunk-Modul.
Radio.Keybind
"F5"
Funk-Panel.
Radio.Cooldown
2000
Anti-Spam (ms) pro Sender.
Radio.Codes
Liste
10-Codes; je Eintrag code, label, optional pos=true (Position anhängen), priority=true (roter Alarmton). Codes, die auch in Statuses stehen, setzen den Unit-Status mit.
Basisgruppe, die auf Zonengruppen aufgefächert wird.
Zones.FallbackToAll
true
Wenn niemand in der Zonengruppe online: an Basisgruppe zurückfallen (keine unversorgten Einsätze).
Zones.List
Liste
Von oben nach unten geprüft: name, groups, optional poly (Polygon {x,y}) oder center+radius; Eintrag ohne Shape = Rest der Karte. Default: „Los Santos" (Polygon → leo_city), „Blaine County" (→ leo_county).
Auto-Panik-Zuweisung (local AUTO_PANIC): enabled=true, onlyIfUnassigned=true, notifyUnit=true. Weist bei neuem Panik-Einsatz automatisch die nächste freie On-Duty-Einheit derselben Abteilung zu.
Exports
Insgesamt 23 Exports (README nennt „~21"): 18 Server in server/main.lua, 1 Server in modules/phone/server.lua, 4 Client in client/main.lua. Namen SetPlayerJob und CreateCall existieren doppelt (client- und serverseitig, unterschiedliche Signatur/Wirkung — Kontext beachten).
Aufruf serverseitig: exports.dispatchos:Name(...) bzw. exports['dispatchos']:Name(...). Ressourcenname = Ordnername (dispatchos).
Server-Exports (server/main.lua)
1. CreateCall(data) — Seite: server
- Signatur: exports.dispatchos:CreateCall(data) — data muss data.coords = {x,y,z} enthalten.
- Felder (alle optional außer coords): code (≤16, Default "CALL"), label (≤120, Default "Einsatz"), priority (1–3, Default 3), groups (Default {"leo"}, danach Zonen-Routing), street (≤96), plate (≤12), vehName (≤40), details (≤200), sender (≤40), panic (bool), mergeKey, blip = {sprite,color,scale}.
- Rückgabe: Call-id (number) — oder bei Merge die bestehende id; nil bei ungültigen Daten.
- Beschreibung: Kern-Funktion zum Anlegen eines Einsatzes; führt Merge (gleicher mergeKey im Radius/Zeitfenster), Zonen-Routing, Broadcast an passende Gruppen und DB-Insert aus.
local id = exports.dispatchos:CreateCall({
code='10-90', label='Fahrzeugraub', priority=2,
groups={'leo'}, coords={x=215.3,y=-810.1,z=30.0},
street='Legion Square', mergeKey='mycustom'
})
3. AttachUnit(id, src) — server · (callId, playerSrc) → bool. Weist Einheit zu (setzt Waypoint, Status active, responded_at). Nur wenn Einheit die Gruppe teilt.
4. DetachUnit(id, src) — server · (callId, playerSrc) → bool. Entfernt Einheit; ohne verbleibende Einheiten → Status pending.
5. AddDispatchCall(code, label, details, coords, priority, groups, blip, mergeKey, plate, vehName, sender) — server · Positionsargumente-Wrapper um CreateCall → gibt id zurück. priority Default 3, groups Default {"leo"}, sender Default "System".
local id = exports.dispatchos:AddDispatchCall(
'10-31','Alarm',nil,{x=1.0,y=2.0,z=3.0},1,{'leo'},60)
6. Alarm(a) — server · Öffentliche Alarm-API → id oder nil. a.type: 'ladenraub' (10-90, P2), 'bankraub' (10-90, P1), 'gefaengnisausbruch' (10-98, P1) oder 'custom'. Weitere Felder: coords, code, label, details, priority, groups (Default {'leo'}), blip, mergeKey, sender. Auch via Event TriggerEvent('dispatchos:alarm', a).
local id = exports.dispatchos:Alarm({
type='custom', code='10-31', label='Juwelier-Alarm',
coords=coords, priority=1, groups={'leo'}, blip=617 })
7. GetCall(id) — server · → öffentliche Call-Tabelle (id, code, label, priority, coords, street, units, history, …) oder nil.
8. GetActiveCalls() — server · → Array aller aktiven Einsätze (öffentliche Form), nach id absteigend sortiert.
9. GetUnits() — server · → Array aller On-Duty-Einheiten {src, name, callsign, status, job}.
10. AddWantedPlate(p, reason) — server · Setzt lokale Fahndung (BOLO) für Kennzeichen; reason ≤90. Pusht an Leitstellen-Viewer. Keine Rückgabe.
11. RemoveWantedPlate(p) — server · Entfernt lokale Fahndung. Keine Rückgabe.
12. SetPlayerJob(src, job) — server · Setzt Job im STANDALONE-Tracker (StandaloneJobs[src]). Für Server ohne ESX/QBCore.
exports.dispatchos:SetPlayerJob(source, 'police')
13. SetPlayerDuty(src, state) — server · Setzt Duty-Flag (DutyStates[src]). Wirkt mit UseDuty=true.
14. LstSetStatus(src, st) — server · Web-Leitstand-Wrapper → bool. Setzt Unit-Status (validiert gegen Statuses).
15. LstSetCallsign(src, cs) — server · → true. Setzt Funkrufname.
16. LstGps(src, x, y) — server · → bool. Sendet Waypoint an Einheit.
17. LstAddNote(id, who, text) — server · → bool. Fügt Notiz (≤140) an Einsatz-Timeline.
18. LstRadio(who, code, text) — server · → bool. Sendet Funkspruch an alle Einheiten.
14–18 („Lst…") sind bewusst schlanke Wrapper für das Web-Link-Modul, funktionieren aber auch direkt.
Server-Export (modules/phone/server.lua)
19. PhoneEmergencyCall(data) — server · Generische Notruf-API für beliebige Telefon-Scripts → callId oder nil.
- Felder: x, y (Pflicht), z, code, label, details (≤140), priority (1–3), group ('leo'|'ems'|'both') oder groups, sender (≤24) oder anonymous=true. Eingebauter Cooldown pro Sender (VConfig.Phone.Cooldown), automatischer mergeKey='phone:<sender>'.
local id = exports.dispatchos:PhoneEmergencyCall({
x=215.3, y=-810.1, details='Bewaffneter Überfall',
sender='555-0123', group='leo', priority=2, code='911', label='Notruf' })
Client-Exports (client/main.lua)
20. CreateCall(data) — client · Third-Party-Integration. Ergänzt fehlende data.coords mit der Spielerposition und feuert TriggerServerEvent('dispatchos:server:CreateExternalCall', data). Keine Rückgabe (asynchron). Serverseitig gilt für echte Spieler: On-Duty-Pflicht, Rate-Limit, panic wird verworfen.
TriggerEvent('dispatchos:server:CreateExternalCall', data) — serverseitig (source 0 erlaubt) Einsatz anlegen; von Spieler-Clients gesendet gilt On-Duty + Rate-Limit, panic entfernt.
dispatchos:dispatch:broadcast — internes Feed-Event ({action='new'|'closed'|'update'|'unit'|'radio', …}); Anknüpfpunkt für Discord, lb-phone-Push, Web-Link, EmergencyOS-Atlas und Auto-Panik. Nicht von Clients auslösbar.
dispatchos:client:FocusCall(callId) — clientlokal, öffnet Leitstelle mit Kamera-Flug (Atlas-Integration).
Gehörte Fremd-Events:EmergencyOS:PanicButton, EmergencyOS:WantedsUpdated, lb-phone:newCompanyMessage, lb-phone:callEnded. Ausgelöst:EmergencyOS:ForceOpenRecord.
Client-seitige Server-Events (Auszug, spielergebunden, mit IsUnit/Cooldown/Permission-Guards)
Leitstellen-Selbsttest (warum F6 ggf. nicht öffnet)
* Alle Tasten in config.luaund pro Spieler unter GTA-Einstellungen → Tastenbelegung → FiveM änderbar.
Hinweise / Troubleshooting
Einsatzkräfte lösen keine Auto-Alarme aus → Absicht: ignoreUnits = true (Produktions-Default). Zum Testen im jeweiligen AutoCalls-Eintrag auf false.
fight ist standardmäßig aus (enabled=false) — bei Bedarf aktivieren.
Kein Blip/keine Karte für einen Job → Job in JobGroups eintragen und Zonengruppen (leo_city/leo_county) prüfen.
F6 öffnet nicht → anderes NUI hält den Focus (FocusGuard). /dcdiag zeigt Job/Unit/Focus-Status; notfalls DispatchCenter.FocusGuard = false.
„Panel nicht erreichbar" im MDT → MDT.PanelFileLookup erst nach eingerichteter EmergencyOS-Panel-API aktivieren; ohne DirectDB und ohne EmergencyOS liefert das MDT nur BOLO-Fahndung.
Diagnose-Schalter → VConfig.DetectorDebug = true (Detektoren) bzw. VConfig.MDT.Debug = true (MDT-Kette; Default bereits „an", da Debug ~= false).
Ohne oxmysql → Konsolenhinweis „Calls werden nicht persistiert (Heatmap bleibt leer)"; Statistik fällt auf In-Memory (seit Serverstart) zurück, Kern bleibt voll funktionsfähig.
Standalone-Job setzen → ohne ESX/QBCore Job/Duty über die Exports SetPlayerJob/SetPlayerDuty (Server) bzw. SetPlayerJob/SetDuty (Client) pflegen, sonst zählt niemand als Einheit.
Discord-Feed ist im Code aktiviert (enabled=true), postet aber nur mit gültiger webhook-URL (sonst still verworfen).
Sounds reminder/arrived werden clientseitig abgespielt, sind aber in VConfig.Sounds nicht definiert → bleiben stumm, bis ergänzt.
LicenseOS ist ein Führerschein- und Fahrschulsystem für FiveM. Die eigentliche Fach-Logik (Lizenzkatalog, Prüfungsbögen, Preise, Fahrstunden-Vorgaben) läuft in einem externen Web-Panel (https://licenseos.app). Die hier dokumentierte FiveM-Ressource ist die Server-Bridge + NUI-Anbindung zu diesem Panel — sie enthält selbst keine Prüfungsinhalte, sondern verbindet Spielserver und Panel.
Die Ressource leistet vier Dinge:
Panel ingame öffnen — das Web-Panel wird als NUI-iframe geladen (Muster: EmergencyOS-Tablet). Fahrlehrer arbeiten ingame mit demselben Panel wie im Browser, per Web-Login. Die Berechtigung wird serverseitig geprüft.
Server-Bridge — Handshake ans Panel, plus ein eingehender Push-Endpunkt, über den das Panel Lizenz-Änderungen live an den Spielserver meldet.
Exports — Lizenz-Checks (HasLicense, GetLicenses, …) für eigene Scripts, mit RAM-Cache und optionalem lokalem DB-Cache.
Framework-Sync — Lizenz-Änderungen aus dem Panel werden live ins Framework gespiegelt (ESX user_licenses, QB/Qbox metadata.licences, ox_core Charakter-Metadaten).
Lizenzarten (aus Config.LicenseMapping)
Panel-Klasse
Bedeutung
Framework-Lizenz
A1, A
Motorrad
drive_bike
B, BE
Auto (PKW / mit Anhänger)
drive
C, CE, D
LKW / Bus
drive_truck
BOOT
Boot
boat
FLUG
Flugzeug / Pilot
pilot
WS
Waffenschein
weapon
Die Klassen-Namen (A1, B, FLUG …) stammen aus dem Panel; die Mapping-Tabelle ist frei erweiterbar (siehe Konfiguration).
Prüfungen & Vorgänge
Theorieprüfung — Fahrlehrer starten per /theorie <klasse> eine Gruppenprüfung; alle Spieler im Umkreis (Config.TheoryRadius) bekommen den Prüfungsbogen automatisch als Panel-Overlay eingeblendet.
Fahrstunde — Fahrlehrer tragen per /fahrstunde <id> <minuten> [notiz] Fahrstunden ein; das Panel zählt Richtung eines Soll-Werts (totalMinutes/required).
Praktische Prüfung / Lizenzvergabe / Gebühren — werden im Web-Panel abgewickelt.
Bürger-Abfrage — Spieler rufen per /lizenzen ihre Lizenzen, Punkte, Gültigkeit und offenen Gebühren im Chat ab.
Lizenz-Status
aktiv · gesperrt · entzogen · abgelaufen (werden in Benachrichtigungen und im licenseos:licenseUpdate-Event verwendet).
Voraussetzungen
fxmanifest.lua:
Element
Wert
fx_version
cerulean
game
gta5
lua54
yes
ui_page
html/wrapper.html
dependency
/assetpacks
Harte Abhängigkeit: nur /assetpacks.
Framework: ESX (es_extended), QBCore (qb-core), Qbox (qbx_core) oder ox_core (ox_core) — automatisch erkannt, keine Anpassung nötig. Auch Standalone (ohne Framework) läuft; dann Identifier license:….
Datenbank / oxmysql:optional, aber empfohlen. Wird per GetResourceState('oxmysql') erkannt. Ohne oxmysql schaltet sich der lokale Lizenz-Cache automatisch ab (dann nur RAM-Cache + Live-API); die Offline-Spielersuche entfällt ebenfalls.
Web-Panel-Account mit erzeugtem API-Key (Panel → Einstellungen → FiveM-Bridge).
Netzwerk: Der Spielserver-HTTP-Port (Convar netPort, Standard 30120) muss vom Webserver aus per HTTP erreichbar sein, damit Panel-Pushes ankommen. Exports & Befehle (Richtung Spiel → Panel) funktionieren auch ohne eingehende Erreichbarkeit.
Optionale Notify-Ressourcen: okokNotify oder ox_lib (sonst Chat-Fallback).
Installation
Ordner als licenseos in resources/ ablegen.
Im Web-Panel einen API-Key erzeugen (Einstellungen → FiveM-Bridge, als Inhaber/Admin) und in config.lua eintragen:
lua
Config.PanelURL = 'https://licenseos.app' -- OHNE abschließenden /
Config.ApiKey = 'los_...'
In die server.cfg eintragen:
cfg
ensure licenseos
Server starten. Beim Start meldet sich der Server am Panel an (/bridge/getInstance.php) und registriert automatisch den Push-Rückkanal (IP/Port/Resource) — es muss keine Server-IP im Panel eingetragen werden.
Reihenfolge:oxmysql und das genutzte Framework sollten vor licenseos gestartet sein. Die Ressource wartet aber nach: bei Config.Framework = 'auto' bis zu 10 s auf ein Framework, bei erzwungenem Framework bis zu 30 s (und weicht dann nie still auf ein anderes aus, sondern auf Standalone).
Panel-Bezug: Das Panel wird ingame über /licenseos bzw. Taste F7 geöffnet und als iframe von Config.PanelURL geladen. Login-Daten werden nur lokal auf dem PC des Spielers gecacht (SetResourceKvp), nie auf dem Server.
Datenbank
Die Ressource legt eine eigene Tabelle an, sofern Config.LocalLicenseCache = trueund oxmysql läuft. Die Tabelle wird automatisch beim ersten erfolgreichen Handshake erstellt (kein manuelles SQL-Import nötig):
CREATE TABLE IF NOT EXISTS licenseos_licenses (
license_no VARCHAR(32) PRIMARY KEY,
identifier VARCHAR(80) NOT NULL,
owner_name VARCHAR(60) NOT NULL DEFAULT '',
class VARCHAR(6) NOT NULL,
status VARCHAR(12) NOT NULL,
points INT NOT NULL DEFAULT 0,
expires_at DATE DEFAULT NULL,
INDEX idx_lic_ident (identifier, status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Master bleibt das Panel. Diese Tabelle ist nur ein lokaler Spiegel: Voll-Sync beim Start (DELETE + Neu-Einfügen), Delta-Sync alle 15 Min (?since=…), plus Live-Pushes. Datenquelle: PanelURL/bridge/export.php.
Vorteil: HasLicense/GetLicenses laufen ohne Internet-Roundtrip; der Server bleibt bei Panel-Wartung spielbar.
Zusätzlich genutzte (Framework-)Tabellen — nur lesend für die Spielersuche bzw. schreibend für den Sync, werden nicht von dieser Ressource angelegt:
Die Bridge kommuniziert in beide Richtungen über HTTP-Endpunkte unterhalb von Config.PanelURL. Authentifizierung durchgehend per Api-Key-Header (bzw. Authorization beim eingehenden Endpunkt), zeitkonstant verglichen.
Datenschutz by Design: Es gibt keinen automatischen Bürger-Sync beim Joinen. Spieler werden nie pauschal ans Panel übertragen; die Suche läuft live, gespeichert wird ein Spieler erst bei einem echten Vorgang (Lizenz, Prüfung, Fahrstunde).
Lizenz vergeben/entziehen erfolgt im Panel (bzw. wird per licenseUpdate an den Server gepusht) — dafür gibt es bewusst keinen Export. Die Ressourcen-Exports sind lesend (siehe unten).
Konfiguration
Vollständige config.lua. Alle Werte sind die echten Defaults.
Key
Standard
Beschreibung
Config.PanelURL
'https://licenseos.app'
Basis-URL des Web-Panels, ohne abschließenden /. Grundlage aller Bridge-Endpunkte und des iframe.
Config.ApiKey
'los_HIER_DEN_KEY_EINFUEGEN'
API-Key aus dem Panel (Einstellungen → FiveM-Bridge). Solange der Platzhalter oder leer bleibt, ist die Bridge inaktiv.
Config.Command
'licenseos'
Chat-Befehl zum Öffnen des Panels ingame.
Config.Keybind
'F7'
Standard-Tastenbelegung (RegisterKeyMapping). '' = kein Keybind.
Config.AllowedJobs
{ ['fahrschule']=0, ['police']=1 }
Job/Gruppe → Mindest-Grade, ab dem das Panel geöffnet werden darf. Bei ox_core sind das Gruppennamen.
Config.AcePermission
'licenseos.open'
Ace-Permission, die das Öffnen immer erlaubt (zusätzlich zu AllowedJobs).
Mehrere Panel-Klassen dürfen auf dieselbe Framework-Lizenz zeigen (z. B. B und BE → drive). Beim Entzug entfernt die Bridge die Framework-Lizenz nur, wenn keine andere aktive Panel-Klasse dasselbe Mapping benötigt.
Was wo konfiguriert wird — wichtig
Lizenzarten (Katalog), Prüfungsinhalte, Preise/Gebühren werden im Web-Panel gepflegt, nicht in config.lua. In der Ressource legt man nur fest, wie diese ins Spiel wirken:
Lizenzen: über Config.LicenseMapping (welche Panel-Klasse welche Framework-Lizenz setzt) und Config.SyncFramework.
Prüfungen: über Config.TheoryCommand und Config.TheoryRadius (Start & Einladungsradius der Theorieprüfung); Bögen/Bestehensgrenzen/praktische Prüfung liegen im Panel.
Preise/Gebühren: rein im Panel; die Ressource zeigt nur die vom Panel gelieferten openFees (/lizenzen) an.
Exports
Alle vier Exports sind serverseitig (in server/main.lua). Aufruf aus Server-Scripts über exports.licenseos:…. Als identifier ist der Framework-Identifier zu übergeben: ESX identifier, QBCore/Qbox citizenid, ox_core stateId, Standalone license:….
1. GetCommunityId
Seite: Server
Signatur:exports.licenseos:GetCommunityId()
Parameter: keine
Rückgabe:number | nil — die Community-ID nach erfolgreichem Handshake, sonst nil (noch nicht verbunden).
Beschreibung: Liefert die vom Panel vergebene Community-ID. Nützlich für Support-Anfragen und zur Prüfung, ob die Bridge verbunden ist.
local id = exports.licenseos:GetCommunityId()
print(id and ('Verbunden, Community ' .. id) or 'Bridge noch nicht verbunden')
Beschreibung: Holt die aktiven Lizenzen eines Spielers. Reihenfolge der Quellen: lokale Tabelle (falls Cache aktiv & bereit) → RAM-Cache (< CacheTTL) → Live-API (/bridge/licenses.php). Kein Callback-Typ = No-Op.
exports.licenseos:GetLicenses(identifier, function(licenses)
for _, l in ipairs(licenses) do
print(l.class, l.license_no, l.points, l.expires_at)
end
end)
Parameter:identifier (string), class (string, z. B. 'B'), cb (function(has)).
Rückgabe (via Callback):boolean — ob eine aktive Lizenz der Klasse existiert.
Beschreibung: Async-Check (empfohlen für normale Wege). Nutzt intern GetLicenses und damit denselben Cache.
-- Beispiel: Fahrzeug nur bei gültiger PKW-Lizenz freigeben
exports.licenseos:HasLicense(identifier, 'B', function(has)
if not has then
-- z. B. Motor sperren, Strafe, Hinweis ...
TriggerClientEvent('ox_lib:notify', src, { description = 'Kein Führerschein Klasse B!' })
end
end)
4. HasLicenseCached
Seite: Server
Signatur:local has = exports.licenseos:HasLicenseCached(identifier, class)
Parameter:identifier (string), class (string).
Rückgabe:boolean — synchron, nur aus dem RAM-Cache. false, wenn für den Spieler noch kein HasLicense/GetLicenses lief (Cache leer).
Beschreibung: Kein HTTP, für Hot-Paths (z. B. jeden Frame / beim Einsteigen). Voraussetzung: der Spieler wurde vorher einmal geladen.
-- Hot-Path: vorher einmal HasLicense/GetLicenses aufrufen, um den Cache zu füllen
if not exports.licenseos:HasLicenseCached(identifier, 'C') then
-- LKW-Lizenz fehlt (nach Cache-Stand)
end
Lizenz geben/entziehen: dafür existiert kein Export. Das geschieht im Panel und wird per licenseUpdate-Push an den Server übernommen — koppelbar über das Event licenseos:licenseUpdate (siehe unten).
Events & Commands
Events
Event
Seite / Typ
Signatur
Beschreibung
licenseos:licenseUpdate
Server / AddEventHandler
(identifier, class, status, data)
Feuert bei jeder vom Panel gepushten Lizenz-Änderung. status: 'aktiv' / 'gesperrt' / 'entzogen' / 'abgelaufen'. Zum Koppeln eigener Systeme.
licenseos:requestOpen
Server / RegisterNetEvent
()
Vom Client ausgelöst; prüft serverseitig HasAccess und öffnet bei Erfolg das Panel. Intern — nicht manuell missbrauchen.
licenseos:openPanel
Client / RegisterNetEvent
(url)
Öffnet das NUI-iframe mit der übergebenen URL (auch für Theorie-Einladungen).
licenseos:denied
Client / RegisterNetEvent
(reason)
Wird bei fehlender Berechtigung gefeuert (Print im Client).
-- Eigene Systeme an Lizenz-Änderungen koppeln:
AddEventHandler('licenseos:licenseUpdate', function(identifier, class, status, data)
if status == 'entzogen' and class == 'B' then
-- z. B. Fahrzeugschlüssel sperren
end
end)
NUI-Callbacks (Client, intern): close, saveLogin, getLogin, clearLogin — verwalten den lokalen Login-Cache (KVP) und das Schließen.
Commands
Befehl (Default)
Config-Key
Wer
Nutzung / Wirkung
/licenseos
Config.Command
Jobs aus AllowedJobsoder Ace licenseos.open
Öffnet das Panel ingame (Berechtigung serverseitig). Auch per Keybind F7.
/fahrstunde
Config.LessonCommand
Ace licenseos.instructor
/fahrstunde <spieler-id> <minuten> [notiz] — trägt eine Fahrstunde ans Panel ein; Ziel-Spieler muss online sein.
/theorie
Config.TheoryCommand
Ace licenseos.instructor
/theorie <klasse> — startet eine Gruppen-Theorieprüfung; alle Spieler im Umkreis (TheoryRadius) bekommen den Bogen als Overlay; Fahrlehrer erhält Prüfungs-Code.
/lizenzen
Config.CitizenCommand
alle Spieler
Zeigt eigene Lizenzen, Punkte, Gültigkeit und offene Gebühren im Chat (5 s Cooldown).
Hinweise / Troubleshooting
„Kein API-Key in config.lua hinterlegt — Bridge inaktiv." → Config.ApiKey ist leer oder noch der Platzhalter los_HIER_DEN_KEY_EINFUEGEN. Echten Key aus Panel → Einstellungen → FiveM-Bridge eintragen.
HTTP 401 beim Handshake → falscher/abgelaufener API-Key. Panel-Key prüfen bzw. neu erzeugen.
Panel-Pushes kommen nicht an (Lizenzänderungen erscheinen ingame nicht sofort) → der Spielserver-Port (netPort, Standard 30120) ist vom Webserver aus nicht erreichbar. Firewall/Portfreigabe prüfen. Exports/Befehle (Spiel → Panel) laufen davon unabhängig.
Lokaler Cache bleibt aus („oxmysql nicht gestartet") → oxmysql wird nicht vor licenseos gestartet. ensure oxmysql vor ensure licenseos setzen. Ohne oxmysql läuft die Ressource mit RAM-Cache + Live-API weiter, aber ohne Offline-Suche.
Falsches Framework erkannt → Config.Framework explizit setzen. Erzwungenes Framework wartet bis zu 30 s auf die Ressource und weicht nie still auf ein anderes aus (fällt sonst auf Standalone). Bei 'auto' wird qbx_core vor qb-core geprüft (Qbox liefert eine qb-core-Bridge mit).
HasLicenseCached liefert false, obwohl Lizenz vorhanden → RAM-Cache für den Spieler noch leer. Vorher einmal HasLicense/GetLicenses aufrufen (oder lokalen Cache aktiv lassen).
Panel öffnet nicht / „keine Berechtigung" → weder passender Job-Grade in AllowedJobs noch Ace licenseos.open. Berechtigung wird ausschließlich serverseitig geprüft.
Fahrlehrer-Befehle reagieren nicht → Ace licenseos.instructor fehlt (add_ace + add_principal in server.cfg).
Datenschutz: Kein automatischer Bürger-Sync beim Join — gewollt. Spieler werden erst bei einem echten Vorgang im Panel gespeichert.
ancomox_garage (Handelsname „Zenith Glass Edition Garage") ist ein premium Multi-Framework-Garagensystem für FiveM. Es verwaltet das Ein- und Ausparken von Fahrzeugen über ein modernes Glass-NUI mit 3D-Fahrzeugvorschau und deckt weit mehr als eine klassische Garage ab.
Kernfunktionen
- Öffentliche & Job-Garagen (statisch aus Config oder dynamisch per In-Game-Creator in der DB)
- Fahrzeug einparken/ausparken, umbenennen, Schlüssel teilen (2 Stufen: Drive / Drive & Park)
- Impound (job-basiert, Gebühr, Sperrzeit) + Verwahrstelle/Impound-Lot (Auslösung) + Schrottplatz für „verlorene" Fahrzeuge
- Private, kaufbare Garagen in 3 Vanilla-GTA-Interiors (2/6/10 Stellplätze, kein MLO nötig, eigene Routing-Bucket-Instanz)
- Vehicle Transfer (Besitzübertragung zwischen Spielern, optional gegen Bezahlung)
- Valet (eingelagertes Fahrzeug liefern lassen), Admin-Fahrzeug-Panel, Housing-Bridge
- Fahrzeug-Lock (Keymapping), GPS-Tracking, Fuel-Bridges, optionale ox_target/qb-target-Integration
- Discord-Webhook-Logs für alle relevanten Aktionen
Autor:Ancomox | Emergency OS
Voraussetzungen
Anforderung
Wert / Beschreibung
fx_version
cerulean
game
gta5
Lua
lua54 'yes' (Lua 5.4 erforderlich)
Pflicht-Dependency
oxmysql (dependency 'oxmysql' in fxmanifest)
Framework
ESX (es_extended), QBCore (qb-core), QBox (qbx_core) oder Custom/Standalone — Auswahl über Config.Framework (Default "auto" erkennt die drei Standard-Frameworks selbst)
Datenbank
MySQL/MariaDB via oxmysql (Tabellen werden automatisch angelegt/migriert, siehe unten)
OneSync
Nur nötig, wenn Config.ServerSpawn.Enabled = true (server-autoritatives Spawnen, Anti-Dupe)
Optional
ox_lib (empfohlen für Menüs/TextUI), ox_target/qb-target (Targeting), Fuel-Script (ox_fuel/legacyfuel/ps-fuel/rcore_fuel), Vehiclekeys-Script
Installation
Ordner ancomox_garage nach resources/ (bzw. [ANCOMOX]/) kopieren.
In der server.cfgensure oxmysql VOR ensure ancomox_garage setzen (Reihenfolge ist wichtig).
In config/config.luaConfig.Framework auf "auto" lassen (erkennt ESX/QBCore/QBox) oder fest auf "esx", "qb" bzw. "custom" setzen.
Server starten — es muss KEINE SQL-Datei importiert werden, das Script legt seine Tabellen beim ersten Start selbst an und ergänzt fehlende Fahrzeug-Spalten automatisch.
Es ist kein manueller SQL-Import nötig. Bei MySQL.ready werden folgende Tabellen per CREATE TABLE IF NOT EXISTS angelegt und bestehende Fahrzeugtabellen migriert (EnsureColumnExists):
Tabelle
Zweck
Wichtige Spalten
ancomox_garages
Creator-/DB-Garagen (nur bei UseDatabaseGarages = true)
id, name, type (public/job), job_name (JSON-Array), loc_x/y/z/w, spawn_x/y/z/w, npc_hash, blip_sprite, blip_color, vehicle_types (CSV), vehicle_classes (CSV), society (0/1), min_grade
Instanz-ID = Base + DB-ID der Garage (bei Bucket-Kollision erhöhen)
Blips.ForSale
{sprite=374,color=2,scale=0.7,name="Garage For Sale"}
Blip für kaufbare Garagen
Blips.Owned
{sprite=357,color=5,scale=0.7,name="My Garage"}
Blip für eigene Garagen
Interiors
{small, medium, large}
Die 3 Vanilla-Interiors (siehe unten)
Locations
{legion_small, grove_medium, sandy_large}
Kaufbare Standorte (siehe unten)
Interiors-Eintrag (je small/medium/large): label, capacity (2/6/10), playerEnter (vector4), exitPoint (vector3), menuPoint (vector3), slots (Liste von vector4-Stellplätzen). Z-Höhe der drei Vanilla-Garagen ist bewusst -99.60 (knapp über dem Interior-Boden).
Locations-Eintrag (Table-Key = eindeutige DB-ID):
Feld
Beispiel
Beschreibung
label
"Legion Square Garage"
Anzeigename
interior
"small"
Verweist auf Interiors (small/medium/large)
price
65000
Kaufpreis
entrance
vector4(193.50,-831.60,30.73,340.0)
Kauf-/Betreten-Punkt (im Auto: [E] parkt ein und betritt)
vehicleSpawn
vector4(200.80,-838.60,30.62,340.0)
Außen-Punkt: hier spawnen Autos & alternativer [E]-Einlagerpunkt
Standard-Benachrichtigungen. NotifyClient(msg, type) und NotifyServer(source, msg, type) verzweigen intern nach ESX (ShowNotification / esx:showNotification) bzw. QB (Functions.Notify / QBCore:Notify). Für Custom-Frameworks hier anpassen.
Config.ScrapYard (Schrottplatz für „verlorene" Fahrzeuge):
Key
Standard
Beschreibung
location
vector4(101.34,-1071.60,29.23,338.30)
Schrottplatz-Punkt
fee
1000
Gebühr zum Wiederherstellen
spawnNPC
true
NPC spawnen
npcHash
"s_m_y_garbage"
NPC-Modell
Config.ImpoundLot (physische Verwahrstelle/Depot zum Auslösen):
Key
Standard
Beschreibung
Enabled
true
Verwahrstelle aktiv
location
vector4(409.79,-1622.92,29.29,231.0)
Büro (Davis Impound)
spawn
vector4(407.44,-1645.31,29.31,142.0)
Fahrzeug-Ausgabepunkt
releaseFee
800
Auslösegebühr nach Ablauf der Sperrzeit
blip
{sprite=68,color=1,scale=0.75,name="Impound Lot"}
Blip der Verwahrstelle
Config.Garages — statische Garagen (nur bei UseDatabaseGarages = false)
Enthält rund zwei Dutzend vordefinierte Standard-Garagen (öffentliche + Job-Garagen für police, ambulance, mechanic, merryweather, admin sowie Boots-/Air-Garagen). Struktur eines Garagen-Eintrags:
Feld
Typ
Pflicht
Beschreibung
location
vector4
ja
NPC-/Interaktionspunkt (Garage öffnen)
spawnPos
vector4
ja
Punkt, an dem ausgeparkte Fahrzeuge erscheinen / eingeparkt wird
job
nil | string | table
nein
Job-Bindung: nil = für alle, 'police' oder {'admin'}
spawnNPC
boolean
nein
NPC an der Garage spawnen
npcHash
string
nein
NPC-Modell (Default 'a_m_y_business_02')
blip
table
nein
{ sprite, color, scale, name }
markerSettings
table
nein
{ id, size = {x,y,z}, color = {r,g,b,a} } (optional; DB-Garagen nutzen Default-Marker id 36, Farbe hellblau)
vehicleTypes
table
nein
Erlaubte Typen, z. B. {"car","air","boat","bike"}
vehicleClasses
table
nein
Erlaubte GTA-Fahrzeugklassen, z. B. {0,1,2,...,20}
Neue Garage anlegen — Variante A (statisch, in Config.Garages)
Neuen Eintrag in die Config.Garages-Liste ergänzen. Beispiel öffentliche PKW-Garage:
{
location = vector4(-1985.00, 3065.13, 32.81, 102.20), -- Garage öffnen
spawnPos = vector4(-1993.00, 3067.41, 32.81, 57.95), -- Fahrzeug-Ausgabe
job = nil, -- nil = für alle
spawnNPC = true,
npcHash = 'a_m_y_business_02',
blip = { sprite = 357, color = 3, scale = 0.75, name = "Garage" },
markerSettings = { id = 25, size = {x = 5.0, y = 5.0, z = 1.0}, color = {r = 0, g = 255, b = 0, a = 100} },
vehicleTypes = {"car"},
vehicleClasses = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 19, 20}
}
Neue Garage anlegen — Variante B (dynamisch, empfohlen bei UseDatabaseGarages = true)
Im Spiel als Admin /creategarage → Platzierung per Raycast, Job-Bindung, Fahrzeugtyp-/Klassenfilter, Blip-Einstellungen, optional Company fleet (society) + Mindest-Job-Rang. Speicherung in ancomox_garages, sofortiger Sync an alle Clients. Private Standorte im selben Creator unter Tab „Private Garages" (Name, Interior small/medium/large, Preis, Entrance + Vehicle Exit Point) → Speicherung in ancomox_private_locations.
config/locales.lua — Sprachdatei
Locales enthält vollständige en- und de-Blöcke. Sprache über Config.Locale wählen; eigene Sprache = Block kopieren, Kürzel ändern, übersetzen. Strings mit %s/%d sind Format-Platzhalter (nicht entfernen). Übersicht der Schlüsselgruppen:
(Beide Sprachblöcke enthalten jeweils dieselbe Schlüsselmenge; Standardwerte sind die englischen bzw. deutschen Klartexte oben in config.lua-Nähe zitiert.)
Ein Log wird nur gesendet, wenn LogSettings[typ] = trueund die passende Webhook-URL gesetzt ist. Ein leerer String oder eine Demo-Webhook (interner Guard api/webhooks/119887…) unterdrückt den Versand.
Exports
Beide Exports liegen client-seitig in client/client.lua und dienen der Housing-Bridge. Sie sind nur aktiv, wenn Config.HousingBridge.Enabled = true. Beide geben keinen Wert zurück (kein Rückgabewert / nil).
label (string) — Anzeigename der Garage (Default "House Garage")
spawn (vector4/{x,y,z,w}) — wo ausgeparkte Fahrzeuge erscheinen (Default: aktuelle Ped-Position)
vehicleTypes (table, optional) — Typ-Filter
vehicleClasses (table, optional) — Klassen-Filter
Rückgabe: keine
Beschreibung: Öffnet das volle Garagen-Menü für eine an ein Haus gebundene Garage. Fahrzeuge, die hier eingelagert werden, erscheinen nur in dieser Haus-Garage. Auch als Event ancomox_garage:openHouseGarage verfügbar.
Beispiel:
exports.ancomox_garage:OpenHouseGarage(houseId, {
label = "Mein Haus",
spawn = vector4(x, y, z, w), -- wo Autos rauskommen
vehicleTypes = {"car"},
vehicleClasses = nil
})
-- alternativ per Event:
TriggerEvent('ancomox_garage:openHouseGarage', houseId, data)
houseId (string|number) — Haus-ID (Zuordnung über garage_id = "house:<hausId>")
vehicle (entity handle, optional) — zu lagerndes Fahrzeug. Wird nichts/0 übergeben, nutzt der Export das Fahrzeug, in dem der Spieler sitzt, sonst das nächste Fahrzeug im Umkreis < 5.0 m.
Rückgabe: keine
Beschreibung: Lagert das angegebene (oder automatisch ermittelte) Fahrzeug in die Haus-Garage ein (ruft intern AttemptToStoreVehicle). Ist kein Fahrzeug in Reichweite, erscheint die Notify no_vehicle_nearby.
Server-Callbacks laufen über eine eigene Bridge (ancomox_garage:cbRequest / cbResponse, Custom_RegisterServerCallback), z. B. garage:getVehicles, garage:fetchDBGarages, garage:saveCreatorGarage, garage:getPrivateGarageStates.
Discord-Logs
Zentrale Funktion: SendWebhookLog(type, title, message, color) (server/server.lua, Zeile ~8583). Sie prüft Config_Logs.LogSettings[type], holt Config_Logs.Webhooks[type], überspringt leere/Demo-Webhooks und postet dann per PerformHttpRequest ein Discord-Embed:
Benutzername:"Garage Logs"
Embed:title, description (Markdown mit Spielername, Identifier, Kennzeichen [PLATE], Beträgen), footer = "Garage System | <YYYY-MM-DD HH:MM:SS>", color = dezimaler Farbwert (z. B. grün 5763719 Store/Kauf, blau 3447003 ParkOut/Info, rot 15548997 Impound/Löschung, gelb 16776960 Update/Verkauf)
Welche Aktionen loggen in welchen Typ:
Typ
Geloggte Aktionen (Embed-Titel)
Store
„Vehicle Stored" (Fahrzeug eingeparkt; inkl. Hinweis auf private Garage)
„Vehicle Transferred" (Besitzübergabe zwischen Spielern)
Property
„Private Garage Purchased/Sold", „Garage Member Added", „Garage Upgraded"
Webhook-Setup:
1. In Discord: Servereinstellungen → Integrationen → Webhooks → Neuer Webhook, Kanal wählen, URL kopieren.
2. URL in config_logs.lua beim gewünschten Typ eintragen, z. B. Store = "https://discord.com/api/webhooks/…". Für mehrere Kategorien im selben Kanal dieselbe URL mehrfach eintragen.
3. Einzelne Kategorien über LogSettings.<Typ> = false deaktivieren (spart HTTP-Requests).
Hinweise / Troubleshooting
Reihenfolge in server.cfg:oxmysql muss vorancomox_garage starten, sonst schlagen die MySQL.ready-Migrationen fehl.
Kein SQL-Import nötig: Alle Tabellen und fehlende Fahrzeug-Spalten werden beim ersten Start automatisch angelegt/ergänzt.
„Garage server did not respond" (dbg_no_response):/garagedebug ausführen und die Ressource neu starten; meist ein DB-/Callback-Timing-Problem.
Falscher identifier: Bei Custom-Frameworks muss der von Custom_GetPlayer gelieferte identifier exakt zur Owner-Spalte (Config.CustomFramework.Columns.Owner) passen, sonst tauchen keine Fahrzeuge auf. addMoney ist Pflicht für Transfer-/Garagenverkauf, jobGrade für Fleet-Garagen.
DBStyle korrekt wählen:"esx" (getrennte stored/pound-Spalten) vs. "qb" (eine state-Spalte). Falsche Wahl → Fahrzeuge gelten als draußen/beschlagnahmt.
Private Garagen — Routing Buckets:RoutingBucketBase (Default 5000) darf nicht mit anderen Instanz-Systemen kollidieren; bei Bedarf erhöhen. Slot-Positionen bei „Auto klebt in der Wand" einfach als vector4 in Config.PrivateGarages.Interiors verschieben — Z wird per SetVehicleOnGroundProperly abgesichert (Z = -99.60 nicht unter -100.0 setzen, sonst fällt man durchs Interior).
Logout in privater Garage: Wird über ancomox_private_garage_presence abgefangen (v2.11-Fix) — Tabelle nicht manuell leeren, während Spieler online sind.
ServerSpawn (Anti-Dupe):Config.ServerSpawn.Enabled = true benötigt OneSync (Infinity) und ändert die Spawn-Architektur — vorher auf einem Testserver prüfen. Passt zu Config.OnRestart = "return".
AdvancedParking:fixDeleteVehicle.lua ist ein Kompatibilitäts-Shim; die Datei nicht in AdvancedParking selbst starten (sie bricht dort bewusst ab).
Discord-Logs kommen nicht an: Prüfen, ob (a) LogSettings[typ] = true, (b) die Webhook-URL gesetzt und gültig ist und (c) keine Demo-Webhook (…api/webhooks/119887…) verwendet wird — diese wird bewusst blockiert.
Fahrzeugbilder: Eigene PNGs (Modellname, klein) nach html/images/vehicles/ legen; fehlt ein Bild, lädt das UI das offizielle FiveM-Docs-Bild und danach default.png.
Ancomox Premium Vehicle Shop — Fahrzeug-Shop/Autohaus-Script für FiveM mit NUI-Oberfläche, permanenten Vorschaufahrzeugen, Probefahrt, kinematischer Kamera, Job-beschränkten Shops und Discord-Logging.
Überblick
ancomox_vehicleshop stellt beliebig viele Autohäuser (Standard: 14 Shops) an frei konfigurierbaren Orten bereit. Der Spieler interagiert über einen Verkäufer-Ped (via ox_target/qb-target) oder über einen klassischen 3D-Marker und öffnet eine NUI, in der Fahrzeuge nach Kategorien durchgeblättert, in einer Live-3D-Vorschau betrachtet (Farbe/Türen/Licht/Motor umschaltbar), probegefahren und gekauft werden können.
Kernmerkmale (aus dem Code bestätigt):
- Multi-Framework: esx, qbcore oder custom (Config.Framework).
- Wiederverwendbare Fahrzeug-Pools (Config.GlobalVehicles), pro Shop über useGlobal referenziert, oder Inline-Fahrzeuglisten pro Kategorie (vehicles).
- Job-beschränkte Shops (restrictedJob), z. B. Police/Ambulance/Mechanic.
- Permanente Zufalls-Vorschaufahrzeuge vor dem Shop (Config.UseRandomPreview, pro Shop via DisablePermanentPreview abschaltbar).
- Ghost-Car-Schutz (Preview-Fahrzeuge tragen das Kennzeichen SHOPPREV* und werden aggressiv aufgeräumt).
- Discord-Logs für Kauf und Probefahrt (config_logs.lua).
Wichtig: Die Ressource besitzt keineexports() und keineRegisterCommand. Der Shop wird ausschließlich über Ped-Target oder Marker geöffnet. Integriert wird ausschließlich über Config, Events und die entkapselten Dateien client/open.lua / server/open.lua.
Voraussetzungen
Abhängigkeit
Pflicht
Zweck / Quelle
es_extended
Ja (siehe Hinweis)
client/shop_fix.lua ruft exports['es_extended']:getSharedObject()unbedingt auf. → Auch im qbcore/custom-Betrieb aktuell erforderlich, sofern nicht editiert.
oxmysql
Ja
Fahrzeug-Speicherung.
qb-core
Alternativ
Nur wenn Config.Framework = "qbcore".
ox_target oder qb-target
Optional
Nur wenn Config.InteractionType = "ox_target" bzw. "qb-target". Andernfalls klassische Marker.
Keys-Ressource
Optional
Für Fahrzeugschlüssel nach Kauf: ESX → Event vehicles_keys:selfGiveVehicleKeys, QB → vehiclekeys:client:SetOwner, custom → custom_keys:give.
AdvancedParking
Optional
fixDeleteVehicle.lua bietet Kompatibilität; darf laut Datei nicht in AdvancedParking selbst gestartet werden.
Framework-Runtime (aus dem Code):
- ESX: exports["es_extended"]:getSharedObject()
- QBCore: exports["qb-core"]:GetCoreObject()
- custom: keine Core-Anbindung; die relevante Logik (Geld, Speichern, Job, Notify) muss in client/open.lua / server/open.lua selbst implementiert werden.
Installation
Ordner ancomox_vehicleshop in das resources-Verzeichnis kopieren.
In der server.cfg ergänzen:
cfg
ensure ancomox_vehicleshop
Reihenfolge: nach Framework (es_extended/qb-core), nachoxmysql und (falls genutzt) nachox_target/qb-target sowie der Keys-Ressource.
config/config.lua: Framework, Interaktionsart, Shops und Fahrzeuge einrichten.
config/locales.lua: Sprache über Config.Locale ('en' oder 'de') wählen.
Fahrzeugbilder unter html/images/vehicles/<model>.png ablegen (Kleinschreibung; fehlt das Bild, wird images/vehicles/default.png genutzt).
Custom-Framework:Config.Framework = "custom" setzen und die entkapselte Logik in client/open.lua / server/open.lua ausfüllen. Achtung: In server/open.lua gibt ProcessPayment im custom-Modus immer true zurück (kein Geldabzug) und SaveVehicleToDatabase speichert nichts (cb(true)) — beides selbst implementieren.
Datenbank
Die Ressource bringt keine eigene .sql-Datei mit. Es werden die Standard-Tabellen des jeweiligen Frameworks verwendet (Speicherung nur wenn Config.Use_ESX_Owned_Vehicles = true).
ESX → Tabelle owned_vehicles:
Spalte
Wert im Code
owner
Spieler-Identifier (xPlayer.identifier)
plate
generiertes 8-stelliges Kennzeichen (A–Z, 0–9)
vehicle
json.encode(props) inkl. model (Hash) und plate
type
'car' (fest)
QBCore → Tabelle player_vehicles:
Spalte
Wert im Code
license
GetPlayerLicense(src)
citizenid
Player.PlayerData.citizenid
vehicle
Modellname (String)
hash
GetHashKey(model)
mods
json.encode(props)
plate
generiertes Kennzeichen
state
0 (fest)
Beide Tabellen müssen aus dem jeweiligen Framework bereits existieren. Der Fahrzeug-type ist bei ESX fest 'car' — für Boote/Helis/Flugzeuge ggf. anpassen, sonst erscheint das Fahrzeug evtl. nicht im korrekten Garagentyp.
Konfiguration
Globale Optionen — config/config.lua
Key
Standard
Beschreibung
Config.Framework
"esx"
Framework: "esx", "qbcore" oder "custom". Steuert Geld-, Job-, Notify- und Speicherlogik.
Config.InteractionType
"ox_target"
Interaktion am Ped: "ox_target", "qb-target" oder "marker" (3D-Marker + Taste E).
Config.TargetPedModel
"a_m_y_business_02"
Ped-Modell des Verkäufers, das an jedem Shop gespawnt wird.
Config.Use_ESX_Owned_Vehicles
true
true = Kauf wird in DB gespeichert + Kennzeichen generiert. false = keine Speicherung, Kennzeichen "NOPLATE".
Config.UseRandomPreview
true
true = permanentes Zufalls-Vorschaufahrzeug vor jedem Shop (sofern Shop DisablePermanentPreview nicht setzt).
Config.TestDriveCoords
vector3(-891.3095, -3205.846, 13.94)
Globaler Spawnort für alle Probefahrten.
Config.TestDriveHeading
58.0
Blickrichtung beim Probefahrt-Spawn.
Config.TestDriveTime
40
Probefahrt-Dauer in Sekunden.
Config.ShopMarker
36
Marker-Typ (nur bei InteractionType = "marker").
Config.ShopMarkerColor
{ r = 0, g = 255, b = 0, a = 100 }
Marker-Farbe (RGBA).
Config.ShopMarkerScale
1.0
Marker-Größe.
Config.ShopDrawDistance
30.0
Distanz (m), ab der der Marker gezeichnet wird.
Config.ShopInteractDistance
2.5
Distanz (m) für „Drücke E"-Hinweis und Interaktion (Marker-Modus).
Config.BlipSprite
225
Standard-Blip-Icon aller Shops.
Config.BlipColor
5
Standard-Blip-Farbe.
Config.BlipScale
0.8
Standard-Blip-Größe.
Config.Shops
Tabelle (14 Einträge)
Liste aller Autohäuser (siehe Shop-Struktur).
Config.GlobalVehicles
Tabelle (16 Kategorien)
Wiederverwendbare Fahrzeug-Pools, referenziert über useGlobal.
Config.DefaultScale
1.0
Im gelieferten Code nicht referenziert — vermutlich reserviert/Legacy.
Config.MinScale
0.5
Im gelieferten Code nicht referenziert.
Config.MaxScale
3.0
Im gelieferten Code nicht referenziert.
Hinweis: Im ox_target/qb-target-Modus ist die Interaktionsdistanz in der Target-Option fest 2.5 hinterlegt (nicht aus Config.ShopInteractDistance).
Struktur eines Shop-Eintrags (Config.Shops[i])
Feld
Pflicht
Beispiel
Beschreibung
Name
Ja
"Premium Deluxe Motorsport"
Anzeigename im UI und am Blip.
ShopCoords
Ja
vector3(-46.82244, -1095.814, 27.67)
Position von Ped, Blip und Marker.
ShopHeading
Ja
135.0
Blickrichtung des Verkäufer-Peds.
PreviewCoords
Ja
vector3(-47.5914, -1091.934, 27.3023)
Standort des Vorschaufahrzeugs (permanent + im Menü).
PreviewHeading
Ja
137.0
Ausrichtung des Vorschaufahrzeugs.
ReturnCoords
Ja
vector3(-46.6705, -1095.858, 27.274)
Rückkehrposition nach Ende der Probefahrt.
PurchaseSpawnCoords
Ja
vector3(-21.51374, -1084.052, 27.04)
Spawnort des gekauften Fahrzeugs.
PurchaseSpawnHeading
Ja
68.0
Ausrichtung des gekauften Fahrzeugs (auch Heading bei Probefahrt-Rückkehr).
Categories
Ja
Tabelle
Kategorien/Fahrzeuglisten des Shops.
restrictedJob
Nein
"police"
Nur Spieler mit diesem Job sehen Blip/Ped/Marker und dürfen kaufen.
DisablePermanentPreview
Nein
true
Deaktiviert das dauerhafte Vorschaufahrzeug vor diesem Shop.
BlipSprite / BlipColor / BlipScale
Nein
43 / 3 / 0.8
Pro-Shop-Override der globalen Blip-Werte.
MarkerType / MarkerScale / MarkerColor
Nein
—
Pro-Shop-Override der Marker-Werte (im Code unterstützt, in der Default-Config nicht gesetzt).
Struktur einer Kategorie (Categories[j])
Feld
Pflicht
Beschreibung
name
Ja
Anzeigename des Kategorie-Tabs im UI (z. B. "Super Cars").
useGlobal
Entweder/oder
Schlüssel in Config.GlobalVehicles (z. B. "Super").
Ist useGlobal gesetzt, wird Config.GlobalVehicles[useGlobal] geladen; sonst vehicles. Ist keins vorhanden, ist die Kategorie leer.
Struktur eines Fahrzeug-Eintrags
Feld
Pflicht
Beispiel
Beschreibung
name
Ja
"Adder"
Anzeigename im UI.
model
Ja
"adder"
Spawnname des Fahrzeugs (muss serverseitig vorhanden sein; bestimmt auch das Bild images/vehicles/adder.png).
price
Ja
1540000
Kaufpreis (Rohwert; 1540000 = $1.540.000).
maxSpeed
Optional
200
Im gelieferten Code nicht ausgewertet. Die UI-Stats (Speed/Beschleunigung/Bremse/Handling) werden live aus den Handling-Daten des gespawnten Fahrzeugs berechnet. Feld dekorativ/reserviert.
Config.GlobalVehicles — verfügbare Pools
16 Pools mit fertigen Vanilla-Fahrzeuglisten, per useGlobal referenzierbar:
Zwei Stolperfallen:
- Bikes = Motorräder, Bike = Fahrräder (BMX, Cruiser …). Nicht verwechseln.
- Vans ist definiert, wird aber von keinem Default-Shop referenziert — bei Bedarf einer Kategorie über useGlobal = "Vans" zuweisen.
Beispiel: neuen Shop mit globaler und eigener Kategorie anlegen
Fahrzeug zu bestehendem Pool hinzufügen: neuen { name, model, price }-Eintrag in Config.GlobalVehicles.<Pool> einfügen — erscheint automatisch in jedem Shop, der diesen Pool via useGlobal nutzt.
Preis ändern:price des jeweiligen Eintrags anpassen.
Standardwerte (de): u. a. press_to_open = "Drücke ~INPUT_PICKUP~ um %s zu betreten", vehicle_bought = "Gekauft: ~b~%s~s~ für ~g~$%d~s~ (Kennz.: ~y~%s~s~)".
Events & Commands
Commands: Keine (RegisterCommand existiert nicht). Der Shop öffnet ausschließlich über Ped-Target oder Marker.
Netz-Events der Ressource:
Richtung
Event
Parameter
Zweck
Client → Server
ancomox_vehicleshop:buyVehicle
shopIndex, model, price, vehicleProps
Kaufanfrage. Server prüft Geld (ProcessPayment), speichert Fahrzeug, sendet purchaseSuccess.
Client → Server
ancomox_vehicleshop:logTestDrive
model
Meldet Probefahrt-Start für Discord-Log.
Server → Client
ancomox_vehicleshop:purchaseSuccess
shopIndex, model, price, plate, vehicleProps
Spawnt gekauftes Fahrzeug am PurchaseSpawnCoords, setzt Kennzeichen, gibt Schlüssel.
Betreiber-Warnung (Anti-Cheat):price wird vom Client an buyVehicle übergeben und serverseitig ungeprüft an ProcessPayment/Discord-Log durchgereicht. Es findet keine serverseitige Preis-/Modell-Validierung gegen die Config statt — ein manipulierter Client könnte Preis 0 senden. Bei Bedarf serverseitige Validierung in server/open.lua ergänzen.
Extern erwartete Events (Kompatibilität / selbst bereitzustellen):
Lösen FullShopRefresh() aus (Blips/Previews/Job-Rechte neu aufbauen).
Interne NUI-Callbacks (nur zur Info, keine Integrationspunkte): closeUI, toggleAutoRotate, changeColor, toggleDoor, toggleLights, toggleEngine, selectVehicle, buyVehicle, startTestDrive, hoverVehicleList.
Discord-Logs
Konfiguration in config_logs.lua (globale Tabelle Config_Logs):
Key
Standard
Beschreibung
Config_Logs.Webhooks.VehicleSale
""
Webhook-URL für Fahrzeugkäufe. Leer = kein Versand.
Config_Logs.Webhooks.TestDrive
""
Webhook-URL für Probefahrten. Leer = kein Versand.
Config_Logs.LogSettings.VehicleSale
true
Kauf-Logging aktivieren/deaktivieren.
Config_Logs.LogSettings.TestDrive
true
Probefahrt-Logging aktivieren/deaktivieren.
Versand über PerformHttpRequest als Embed (Username „Vehicle Shop", Footer „Ancomox Premium Vehicle Shop"). Kauf-Embed enthält Spielername, Identifier, Modell, Preis, Kennzeichen; Probefahrt-Embed Spielername, Identifier, Modell. Bei Use_ESX_Owned_Vehicles = false wird der Kauf als „(No DB Save)" geloggt.
Hinweise / Troubleshooting
es_extended trotz qbcore/custom nötig:client/shop_fix.lua ruft exports['es_extended']:getSharedObject() unbedingt auf. Ohne es_extended bricht der Client-Start. Für reinen QB-/Custom-Betrieb muss diese Stelle editiert werden.
Kein Geldabzug im custom-Modus:ProcessPayment gibt bei Config.Framework = "custom" immer true zurück und SaveVehicleToDatabase speichert nichts — eigene Logik in server/open.lua einbauen.
Ghost-Cars / Preview-Reste: Vorschaufahrzeuge tragen das Kennzeichen SHOPPREV*. client/shop_fix.lua und ClearGhostCars/SafeDeleteEntity räumen sie beim Start, Öffnen und Ressourcen-Stopp auf. Manuell platzierte Fahrzeuge mit diesem Kennzeichenmuster werden ebenfalls gelöscht.
fixDeleteVehicle.lua: überschreibt DeleteEntity/DeleteVehicle für AdvancedParking-Kompatibilität. Die Datei darf nicht innerhalb von AdvancedParking gestartet werden (bricht sonst mit Hinweismeldung ab).
Fahrzeug erscheint nicht in Garage: Bei ESX wird type = 'car' fest gespeichert — für Boote/Helis/Flugzeuge ggf. Speicher-Typ in server/open.lua anpassen.
Kein Schlüssel nach Kauf: Passende Keys-Ressource muss laufen und das jeweilige Event (vehicles_keys:selfGiveVehicleKeys bei ESX, vehiclekeys bei QB) bereitstellen.
maxSpeed/DefaultScale/MinScale/MaxScale: in der Config vorhanden, aber im ausgelieferten Code nicht ausgewertet (ggf. Legacy).
Vans-Pool ungenutzt, Bikes ≠ Bike — siehe Abschnitt GlobalVehicles.
Preis-Manipulation: siehe Betreiber-Warnung unter „Events" — serverseitig kein Preisabgleich mit der Config.
Ancomox Warehouse — private Lagerhallen für FiveM: kaufen oder mieten, in vier Stufen ausbauen, über mehrere Eingänge betreten und per Zugangs-Key mit dem Team teilen. ESX · QBCore · QBox mit Auto-Erkennung, eigene NUI, vollständig serverseitig abgesichert.
Überblick
ancomox_warehouse stellt beliebig viele Lagertypen bereit (ausgeliefert: Kleines, Mittleres und Großes Lager). Jeder Lagertyp hat mehrere Eingänge auf der Map, die der Spieler einzeln freischaltet. Betreten wird über ox_target, qb-target oder klassische Marker — je nachdem, was auf dem Server läuft.
Kernmerkmale:
Kaufen oder mieten — pro Server konfigurierbar; der Spieler entscheidet beim Erwerb. Der Miet-Modus umfasst Intervalle, automatischen Einzug, Kulanzzeit, Sperrung und optionale Zwangsauflösung.
Private Instanzen — jedes Lager läuft in einem eigenen Routing Bucket. Besitzer und alle Key-Inhaber teilen sich automatisch dieselbe Instanz; freigewordene Buckets werden wiederverwendet.
Vier Ausbaustufen je Lagertyp mit eigenen Werten für Slots, Traglast und Preis. Nach dem Kauf wird der Stash sofort mit neuer Kapazität registriert — ohne Neustart.
Zugangs-Keys mit Einzelrechten — Inventar, Zugänge kaufen, Ausbauen, Keys vergeben.
Verwaltung am Eingang — das komplette Verwaltungsmenü öffnet sich auch vor der Tür. Das ist der einzige praktikable Weg, einem Spieler einen Key zu geben, der noch keinen Zutritt hat, und der einzige Weg, ein wegen Mietrückstand gesperrtes Lager wieder freizukaufen.
Serverautoritativ — Preise, Besitz, Rechte und Distanzen werden ausschließlich serverseitig geprüft. Dazu Rate-Limit pro Aktion und ein Strike-System mit Auto-Kick.
Offene Bridge — bridge/client.lua und bridge/server.lua sind unverschlüsselt und dienen der Anbindung eigener Frameworks oder Inventare.
Wichtig: Ohne OneSync funktioniert die Instanzierung nicht — mehrere Spieler würden sich dann im selben Interior sehen. Setze in dem Fall Config.Instancing.enabled = false und sei dir bewusst, dass Lager dann nicht privat sind.
Voraussetzungen
Abhängigkeit
Pflicht
Zweck / Hinweis
oxmysql
Ja
Datenbank-Layer. Muss vor der Ressource starten.
es_extendedoderqb-coreoderqbx_core
Ja (eines)
Wird über Config.Framework = 'auto' selbst erkannt. QBox läuft über den Wert 'qb'.
ox_inventory, qb-inventory oder qs-inventory
Ja (eines)
Alternativ eigenes Inventar über Config.Inventory = 'custom' und die Bridge. ox_inventory wird empfohlen, weil nur dort Slots und Gewicht pro Stash gesetzt werden können.
OneSync
Ja
Für Routing Buckets (private Interiors).
ox_target oder qb-target
Optional
Ohne Target-Script greift automatisch der Marker-Modus mit Tastendruck.
ox_lib
Optional
Alternative Notifications und TextUI (Config.Notify = 'ox_lib').
Installation
Ordner ancomox_warehouse in das resources-Verzeichnis kopieren (z. B. resources/[ANCOMOX]/ancomox_warehouse).
In der server.cfg eintragen — nach Framework, oxmysql und Inventar:
Die Tabelle wird beim ersten Start automatisch angelegt. Fehlen dem MySQL-Benutzer die CREATE-Rechte, importiere install/ancomox_warehouse.sql von Hand.
config/config.lua und config/warehouses.lua anpassen.
Server neu starten und die Konsole prüfen:
[ANC-WH] Framework: esx · Inventar: ox_inventory · Version 2.1.1
[ANC-WH] 0 Lager aus der Datenbank geladen.
[ANC-WH] Interaktion: ox_target
Startreihenfolge: Erscheint „Kein unterstütztes Framework gefunden!", startet die Ressource vor dem Framework. Die Erkennung versucht es zwar bis zu 10 Sekunden lang, die server.cfg sollte aber trotzdem korrekt sortiert sein.
Datenbank
Die Ressource legt genau eine Tabelle an: anc_warehouses. Es wird nichts an Framework-Tabellen verändert.
Spalte
Typ
Bedeutung
id
INT UNSIGNED AI
Primärschlüssel.
owner
VARCHAR(64)
ESX-Identifier bzw. QB-citizenid.
warehouse
VARCHAR(32)
id aus Config.Warehouses — nachträglich nie ändern.
custom_name
VARCHAR(32)
Vom Spieler vergebener Lagername (leer = Standardlabel).
tier
TINYINT UNSIGNED
Ausbaustufe, 1 = Basis.
entries
TEXT
JSON-Array der freigeschalteten Zugangs-Indizes, z. B. [1,3].
Unix-Timestamp des Mietendes, 0 = kein Mietvertrag.
locked
TINYINT(1)
Gesperrt wegen Mietrückstand.
inside
TINYINT(1)
Besitzer war beim letzten Logout im Lager (für restoreOnRelog).
last_entry
TINYINT UNSIGNED
Zuletzt genutzter Eingang.
created_at
INT UNSIGNED
Unix-Timestamp des Erwerbs.
Ein UNIQUE KEY auf (owner, warehouse) stellt sicher, dass ein Spieler jeden Lagertyp nur einmal besitzen kann.
Performance: Alle Datensätze liegen nach dem Start im RAM. Die Datenbank wird ausschließlich bei echten Änderungen beschrieben — nicht bei jeder Interaktion.
Konfiguration
Alles Relevante liegt in config/ und bleibt auch bei Escrow-Schutz editierbar.
Kompatibilität — config/config.lua
Key
Standard
Beschreibung
Config.Debug
false
Ausführliche Konsolenausgaben inkl. gemessener Distanzen. Nur zum Testen.
Config.Locale
'de'
'de' oder 'en'. Weitere Sprachen als Datei in config/locales/.
Config.Framework
'auto'
'auto' · 'esx' · 'qb' (QBox nutzt ebenfalls 'qb').
Config.Inventory
'auto'
'auto' · 'ox_inventory' · 'qb-inventory' · 'qs-inventory' · 'custom'. 'custom' wird nie automatisch erkannt.
Config.Target
'auto'
'auto' · 'ox_target' · 'qb-target' · 'marker'.
Config.Notify
'anc'
'anc' (eigene Toasts) · 'ox_lib' · 'framework'.
Geld — Config.Money
Key
Standard
Beschreibung
purchaseAccount
'bank'
Konto für Kauf, Zugänge und Ausbau. 'bank' oder 'cash'.
rentAccount
'bank'
Konto für Mietzahlungen und automatischen Einzug.
symbol
'$'
Währungssymbol in der UI.
symbolBefore
true
Symbol vor (true) oder hinter (false) dem Betrag.
thousandsSep
'.'
Tausendertrennzeichen. Leerstring = keine Gruppierung.
Interface — Config.UI
Key
Standard
Beschreibung
accent
'#00E5A0'
Akzentfarbe des gesamten Interfaces. Färbt auch die Ingame-Marker, sofern useAccentColor aktiv ist.
accentAlt
'#22D3EE'
Zweite Farbe für Verläufe.
danger
'#FF4D6D'
Warnfarbe (Verkauf, abgelaufene Miete).
backdropDim
0.55
Abdunklung des Spielbilds hinter der UI. 0.0 bis 0.95.
panelOpacity
0.92
Deckkraft des Fensters. Sinnvoll zwischen 0.80 und 1.00.
gameBlur
true
Ingame-Weichzeichner hinter der UI (TriggerScreenblurFadeIn).
Synthetisches Sound-Feedback der UI (benötigt keine Audiodateien).
brand / brandSub
'ANCOMOX' / 'Storage Division'
Beschriftung im Kopfbereich der NUI.
Kein backdrop-filter ergänzen. FiveMs CEF-Schicht kennt das Spielbild nicht und füllt eine so gestaltete Fläche komplett schwarz — genau daher stammen die typischen schwarzen Kästen hinter Dialogen. Die UI arbeitet deshalb durchgehend mit echter Transparenz über rgba(...); der Weichzeichner kommt vom Spiel selbst.
Interaktion — Config.Interaction
Key
Standard
Beschreibung
key
38
Taste im Marker-Modus (38 = E).
keyLabel
'E'
Beschriftung in der TextUI. Muss zu key passen.
manageAtEntrance
true
Verwaltung auch am Eingang öffnen. Dringend aktiviert lassen — ohne diese Option lässt sich niemandem ein Key geben, der noch keinen Zutritt hat.
keyManage
47
Zweittaste dafür im Marker-Modus (47 = G). Im Target-Modus erscheint stattdessen ein eigener Menüeintrag.
keyManageLabel
'G'
Beschriftung der Zweittaste.
drawDistance
12.0
Ab welcher Entfernung Marker gezeichnet werden.
interactDistance
1.6
Ab welcher Entfernung interagiert werden kann.
showMarkers
true
Marker auch im Target-Modus zeichnen. Empfohlen: Target-Zonen sind unsichtbar.
targetRadius
1.6
Radius der Zonen im Interior (Stash, Verwaltung, Ausgang).
targetRadiusEntry
2.0
Radius der Eingänge draußen — Türen brauchen etwas mehr Spiel.
targetDistance
2.5
Maximale Distanz, aus der eine Option angezeigt wird. Zieht automatisch mit dem Zonenradius mit.
markerType, markerScale, markerBob, markerRotate
21, vector3(.35,.35,.25), true, true
Aussehen und Animation der Marker.
useAccentColor
true
Marker übernehmen Config.UI.accent. Bei false gelten colorEntry, colorStash, colorManage und colorExit.
Instanzierung — Config.Instancing
Key
Standard
Beschreibung
enabled
true
Private Interiors über Routing Buckets.
baseBucket
51000
Startwert der Bucket-IDs. Ab hier wird aufsteigend so viel belegt, wie gleichzeitig Lager betreten sind.
Bucket-Konflikte: Nutzt ein anderes Script (Housing, Gangs, MLOs) denselben Bereich, „verschwinden" Spieler gegenseitig von der Map. In dem Fall baseBucket auf einen freien Wert setzen.
Limits — Config.Limits
Key
Standard
Beschreibung
maxWarehousesPerPlayer
3
Maximale Anzahl gleichzeitig besessener Lager. 0 = unbegrenzt.
maxKeysPerWarehouse
8
Maximale Anzahl Zugangs-Keys pro Lager.
allowCustomName
true
Individueller Lagername erlaubt.
customNameMaxLength
24
Maximale Länge in Zeichen (UTF-8-sicher gekürzt, keine zerschnittenen Umlaute).
Verkauf — Config.Sell
Key
Standard
Beschreibung
enabled
true
Verkauf grundsätzlich erlauben.
refundPercent
0.60
Anteil des investierten Werts, den der Spieler zurückbekommt.
refundEntries / refundUpgrades
true / true
Ob gekaufte Zugänge bzw. Ausbaustufen in den Wert einfließen.
requireEmptyStash
true
Lager muss leer sein. Kann das Inventar den Inhalt nicht melden, wird die Prüfung übersprungen statt den Verkauf zu blockieren.
wipeStash
true
Stash beim Verkauf leeren, damit ein Neukauf keine alten Items enthält.
requireTypeConfirm
true
Spieler muss den Lagernamen zur Bestätigung eintippen.
payoutAccount
'bank'
Konto für die Erstattung.
Gemietete Lager können nicht verkauft werden — der Spieler besitzt sie nicht. Der Verkaufsbereich verschwindet in dem Fall aus der UI.
Zugangs-Keys — Config.Keys
Key
Standard
Beschreibung
enabled
true
Key-System aktiv. Bei false verschwindet der Team-Tab.
giveDistance
3.0
Maximale Entfernung zum Empfänger. Serverseitig mit kleinem Puffer geprüft.
defaultPermissions
{ stash = true, … }
Vorauswahl beim Hinzufügen einer Person.
accessWhileOwnerOffline
true
Dürfen Key-Inhaber das Lager auch betreten, wenn der Besitzer offline ist?
Verfügbare Rechte:
Recht
Erlaubt
stash
Lagerinventar öffnen.
entry
Weitere Zugänge freischalten (zahlt selbst).
upgrade
Ausbaustufen kaufen (zahlt selbst).
keys
Weitere Keys vergeben und entziehen.
Rechteausweitung ist ausgeschlossen: Nur der Besitzer kann das Recht keys weitergeben, und ein Key-Inhaber kann seine eigenen Rechte nicht bearbeiten. Beide Versuche werden serverseitig abgelehnt und als Strike gewertet.
Miete — Config.Rent
Key
Standard
Beschreibung
enabled
true
Miet-Modus aktiv. Bei false verschwindet der Mieten-Button aus der UI.
pricePercent
0.04
Miete pro Intervall als Anteil des Kaufpreises (4 %).
intervalDays
7
Länge eines Intervalls in Tagen.
graceHours
48
Kulanzzeit nach Ablauf, bevor gesperrt wird.
autoDebit
true
Automatischer Einzug, sofern der Besitzer online ist und genug Guthaben hat.
maxPrepaid
8
Maximal im Voraus zahlbare Intervalle.
deleteAfterDays
14
Tage nach der Sperrung bis zur Zwangsauflösung. 0 = nie löschen.
wipeStashOnDelete
false
Ob der Stash bei der Auflösung geleert wird.
checkIntervalMin
15
Prüfzyklus in Minuten.
Ablauf eines überfälligen Mietvertrags: Erinnerung (letzte 24 h) → automatischer Einzug → Kulanzzeit → Sperrung (alle Spieler werden aus der Instanz entfernt) → optional Auflösung. Ein gesperrtes Lager lässt sich am Eingang über die Verwaltung wieder freikaufen; alternativ per /warehouse unlock.
Sicherheit — Config.Security
Key
Standard
Beschreibung
validateDistance
true
Serverseitige Distanzprüfung bei jeder Aktion.
distanceTolerance
12.0
Erlaubte Abweichung in Metern. Puffer für Lag und für Türen, die je Lagergröße auseinanderliegen.
strikeDistance
100.0
Ab dieser Entfernung gilt eine Aktion als Exploit-Versuch. Darunter wird nur abgelehnt, ohne Strafpunkt.
eventCooldown
750
Mindestabstand zweier Events derselben Aktion in ms. Kauf, Keys und UI haben getrennte Kontingente.
strikeWarn / strikeKick
5 / 12
Schwellen für Log-Eintrag bzw. automatischen Kick.
kickReason
'[ANC Warehouse] …'
Kick-Nachricht.
Admin, Blips & Sonstiges
Key
Standard
Beschreibung
Config.Admin.groups
{ 'admin', 'superadmin', 'god', 'mod' }
ESX-Gruppen bzw. QB-Permissions mit Adminrechten.
Config.Admin.useAce
true
Zusätzlich die ACE-Permission ancomox_warehouse.admin akzeptieren.
Config.Admin.command
'warehouse'
Name des Admin-Befehls.
Config.Blips.enabled
true
Blips für Lagereingänge anzeigen.
Config.Blips.onlyOwned
false
Blips nur für bereits freigeschaltete Zugänge.
Config.Misc.restoreOnRelog
true
Spieler landet nach dem Relog wieder im Lager.
Config.Misc.fadeTime
500
Bildschirm-Fade beim Betreten und Verlassen in ms. 0 = aus.
Config.Misc.loadInteriors
true
IPLs beim Start anfordern.
Lager definieren — config/warehouses.lua
Jeder Eintrag in Config.Warehouses beschreibt einen Lagertyp:
{
id = 'bunker', -- eindeutig, NIE nachträglich ändern
label = 'Bunker',
tagline = 'Tief unter der Erde.', -- Werbetext im Kaufdialog
price = 2500000,
order = 4, -- Sortierung im Kaufdialog
theme = { from = '#10B981', to = '#059669' },
icon = 'warehouse', -- box | warehouse | crown
ipl = nil, -- optionales IPL
interior = {
spawn = vector4(x, y, z, heading), -- Ankunftspunkt
stash = vector3(x, y, z), -- Lagerbestand
manage = vector3(x, y, z), -- Verwaltungspult
exit = vector3(x, y, z), -- Ausgang
},
perks = { 'Feature 1', 'Feature 2' }, -- Bullet-Points im Kaufdialog
tiers = { -- Index 1 ist IMMER die Basis und kostet nichts
{ label = 'Basis', slots = 100, weight = 500000, price = 0 },
{ label = 'Ausbau I', slots = 150, weight = 900000, price = 1500000 },
},
entries = {
{
index = 1,
label = 'Sandy Shores',
price = 200000,
coords = vector4(x, y, z, heading),
blip = { sprite = 473, color = 2, scale = 0.75, label = 'Bunker' },
},
},
}
Feld
Hinweis
id
Wird als Fremdschlüssel in der Datenbank gespeichert. Eine spätere Änderung macht alle vorhandenen Lager dieses Typs unerreichbar.
weight
Angabe in Gramm (ox_inventory-Standard): 500000 = 500 kg.
tiers
Beliebig viele Stufen. Wird die Liste nachträglich verkürzt, werden vorhandene Lager beim Laden automatisch auf die höchste noch existierende Stufe begrenzt.
entries[].index
Muss eindeutig und stabil sein — er wird in anc_warehouses.entries gespeichert.
blip
Optional. Fehlt der Block, greifen Standardwerte.
Koordinaten übernehmen: An die gewünschte Stelle stellen, /warehouse pos ausführen und die Zeile aus der F8-Konsole in die Config kopieren. Der Befehl gibt sowohl vector3 als auch vector4 aus.
Eigenes Framework oder Inventar anbinden
Setze Config.Inventory = 'custom' und fülle die vier Funktionen in der Bridge aus. Mehr braucht das Script nicht.
Server — bridge/server.lua:
-- Stash anlegen bzw. Kapazität aktualisieren.
-- Aufruf: beim Serverstart, beim Kauf und nach jedem Ausbau.
function CustomInventory.RegisterStash(id, label, slots, weight, owner) return false end
-- Items zurückgeben. Wird nur für die Leer-Prüfung beim Verkauf gebraucht.
-- nil = nicht ermittelbar; das Script überspringt die Prüfung dann.
function CustomInventory.GetItems(id) return nil end
-- Stash vollständig leeren (Verkauf, Zwangsauflösung).
function CustomInventory.Clear(id) return false end
Client — bridge/client.lua:
-- Stash für den Spieler öffnen. true = geöffnet.
function CustomInventory.Open(stashId, label, slots, weight) return false end
Zu den Ausbaustufen: Das Script übergibt bei jeder Stufe die neuen Werte für Slots und Gewicht. Kann dein Inventar die Kapazität pro Stash nicht begrenzen — das gilt z. B. für esx_addoninventory — funktioniert das Lager zwar, der Ausbau hat aber keine spürbare Wirkung. Reduziere die Tiers in dem Fall lieber auf eine Stufe, statt Kapazität zu verkaufen, die nie greift.
Vollständige Config-Dateien
config/config.lua325 Zeilen · vollständige Datei
--[[
╔══════════════════════════════════════════════════════════════════════╗
║ ANC WAREHOUSE · HAUPT-KONFIGURATION ║
╚══════════════════════════════════════════════════════════════════════╝
]]
Config = {}
--──────────────────────────────────────────────────────────────────────────────
-- ALLGEMEIN
--──────────────────────────────────────────────────────────────────────────────
Config.Debug = false -- Ausführliche Konsolenausgaben (nur zum Testen!)
Config.Locale = 'de' -- 'de' | 'en' (weitere: config/locales/)
--──────────────────────────────────────────────────────────────────────────────
-- KOMPATIBILITÄT · 'auto' erkennt automatisch, was auf dem Server läuft
--──────────────────────────────────────────────────────────────────────────────
Config.Framework = 'auto' -- 'auto' | 'esx' | 'qb' (QBox läuft über 'qb')
-- 'custom' bindet dein eigenes Inventar über CustomInventory in
-- bridge/server.lua und bridge/client.lua an (wird nie automatisch erkannt).
Config.Inventory = 'auto' -- 'auto' | 'ox_inventory' | 'qb-inventory' | 'qs-inventory' | 'custom'
Config.Target = 'auto' -- 'auto' | 'ox_target' | 'qb-target' | 'marker'
-- 'anc' = eigenes Premium-Toast-Design (empfohlen, passt zur UI)
-- 'ox_lib' = ox_lib Notify
-- 'framework' = ESX/QBCore Standard-Notify
Config.Notify = 'anc' -- 'anc' | 'ox_lib' | 'framework' | 'auto'
--──────────────────────────────────────────────────────────────────────────────
-- GELD
--──────────────────────────────────────────────────────────────────────────────
Config.Money = {
-- Womit werden Lager bezahlt? 'bank' | 'cash'
purchaseAccount = 'bank',
-- Womit wird die Miete abgebucht? 'bank' | 'cash'
rentAccount = 'bank',
-- Währungssymbol in der UI
symbol = '$',
-- Symbol vor (true) oder hinter (false) dem Betrag
symbolBefore = true,
-- Tausendertrennzeichen für die UI
thousandsSep = '.',
}
--──────────────────────────────────────────────────────────────────────────────
-- UI · Dark-Glass Theme
--──────────────────────────────────────────────────────────────────────────────
Config.UI = {
-- Akzentfarbe des gesamten Interfaces (HEX). Beispiele:
-- Neon-Mint '#00E5A0' · Cyan '#22D3EE' · Violett '#8B5CF6' · Gold '#F5B301'
accent = '#00E5A0',
-- Zweite Akzentfarbe für Verläufe
accentAlt = '#22D3EE',
-- Warn-/Gefahrfarbe (Verkaufen, Miete abgelaufen)
danger = '#FF4D6D',
-- ── Durchsichtigkeit ────────────────────────────────────────────────
-- Wie stark wird das Spielbild hinter der UI abgedunkelt?
-- 0.0 = gar nicht · 0.55 = Standard · 1.0 = komplett schwarz
backdropDim = 0.55,
-- Deckkraft des Fensters selbst. Sinnvoll zwischen 0.80 und 1.00 —
-- niedriger = mehr Spielbild sichtbar, aber schlechter lesbar.
panelOpacity = 0.92,
-- Weichzeichner hinter der UI. Das ist ein ECHTER Ingame-Effekt
-- (kein CSS-Blur — den kann FiveM nicht über das Spielbild legen).
gameBlur = true,
-- Wo erscheinen die Benachrichtigungen? Falls deine HUD oben rechts
-- sitzt, stell hier z. B. 'top-center' oder 'bottom-right' ein.
-- 'top-right' | 'top-left' | 'top-center' | 'bottom-right' | 'bottom-left'
toastPosition = 'top-right',
-- Sound-Feedback in der UI
sounds = true,
-- Markenname im Header
brand = 'ANCOMOX',
-- Untertitel im Header
brandSub = 'Storage Division',
}
--──────────────────────────────────────────────────────────────────────────────
-- INTERAKTION
--──────────────────────────────────────────────────────────────────────────────
Config.Interaction = {
-- Taste bei Marker-Modus (38 = E)
key = 38,
-- Beschriftung der Taste in der TextUI. Muss zu `key` passen.
-- (GTA-Tokens wie ~INPUT_CONTEXT~ funktionieren NUR in der nativen
-- Hilfeanzeige — in ox_lib oder eigener NUI werden sie als Text
-- ausgegeben. Deshalb hier den Buchstaben eintragen.)
keyLabel = 'E',
-- Ab welcher Distanz wird der Marker gezeichnet
drawDistance = 12.0,
-- Ab welcher Distanz kann interagiert werden
interactDistance = 1.6,
-- ── Verwaltung am Eingang ──────────────────────────────────────────
-- Besitzer und Key-Inhaber können die Verwaltung direkt am Eingang
-- öffnen, ohne das Lager zu betreten. Das ist der einzige Weg, jemandem
-- einen Zugangs-Key zu geben: Wer noch keinen hat, kommt nicht in die
-- Instanz und wäre "nie in der Nähe". Ebenso lässt sich damit die Miete
-- eines bereits gesperrten Lagers nachzahlen.
manageAtEntrance = true,
-- Zweittaste dafür im Marker-Modus (47 = G).
-- Im Target-Modus erscheint stattdessen ein eigener Menüeintrag.
keyManage = 47,
keyManageLabel = 'G',
-- Marker auch dann anzeigen, wenn ox_target/qb-target aktiv ist.
-- Dringend empfohlen: Target-Zonen sind unsichtbar, und der Spieler
-- muss IN der Zone stehen. Ohne Marker sucht er den Punkt blind.
showMarkers = true,
-- Marker-Design
markerType = 21,
markerScale = vector3(0.35, 0.35, 0.25),
markerBob = true, -- schwebende Animation
markerRotate = true,
-- Farben (r,g,b,a) — werden bei UI.accent automatisch überschrieben,
-- wenn `useAccentColor = true`
useAccentColor = true,
colorEntry = { 0, 229, 160, 140 },
colorStash = { 245, 179, 1, 140 },
colorManage = { 34, 211, 238, 140 },
colorExit = { 255, 77, 109, 140 },
-- ── ox_target / qb-target ──────────────────────────────────────────
-- Radius der Interaktionszone in Metern.
-- WICHTIG: Bei ox_target muss der Spieler IN dieser Kugel stehen.
-- Zu klein = "ich sehe den Punkt, kann ihn aber nicht anvisieren".
-- 1.4–2.0 ist ein guter Bereich; kleiner nur, wenn zwei Punkte sehr
-- dicht beieinander liegen.
targetRadius = 1.6,
-- Radius für die Eingänge draußen (Türen brauchen etwas mehr Spiel)
targetRadiusEntry = 2.0,
-- Maximale Distanz, aus der eine Option angezeigt wird
targetDistance = 2.5,
}
--──────────────────────────────────────────────────────────────────────────────
-- INSTANZIERUNG · Jedes Lager ist privat (Routing Buckets)
--──────────────────────────────────────────────────────────────────────────────
Config.Instancing = {
enabled = true,
-- Startwert für Buckets. Muss frei von anderen Skripten sein!
-- Besitzer und alle Key-Inhaber teilen sich automatisch dieselbe Instanz.
baseBucket = 51000,
}
--──────────────────────────────────────────────────────────────────────────────
-- BESITZ-LIMITS
--──────────────────────────────────────────────────────────────────────────────
Config.Limits = {
-- Wie viele Lager darf ein Spieler gleichzeitig besitzen? (0 = unbegrenzt)
maxWarehousesPerPlayer = 3,
-- Maximale Anzahl Zugangs-Keys pro Lager
maxKeysPerWarehouse = 8,
-- Individueller Lagername erlaubt
allowCustomName = true,
customNameMaxLength = 24,
}
--──────────────────────────────────────────────────────────────────────────────
-- VERKAUFEN
--──────────────────────────────────────────────────────────────────────────────
Config.Sell = {
enabled = true,
-- Wie viel Prozent des Kaufpreises bekommt der Spieler zurück (0.0 – 1.0)
refundPercent = 0.60,
-- Werden gekaufte Eingänge mit erstattet?
refundEntries = true,
-- Werden gekaufte Upgrades mit erstattet?
refundUpgrades = true,
-- Lager muss leer sein bevor verkauft werden kann
requireEmptyStash = true,
-- Stash beim Verkauf leeren (verhindert, dass alte Items nach einem
-- Neukauf desselben Lagers wieder auftauchen)
wipeStash = true,
-- Sicherheitsabfrage: Spieler muss den Lagernamen eintippen
requireTypeConfirm = true,
-- Auf welches Konto geht die Erstattung
payoutAccount = 'bank',
}
--──────────────────────────────────────────────────────────────────────────────
-- ZUGANGS-KEYS · Mitbesitzer / Mitarbeiter
--──────────────────────────────────────────────────────────────────────────────
Config.Keys = {
enabled = true,
-- Maximale Distanz zum Spieler, dem ein Key gegeben wird
giveDistance = 3.0,
-- Rechte, die beim Vergeben standardmäßig aktiv sind
defaultPermissions = { stash = true, entry = false, upgrade = false, keys = false },
-- Dürfen Key-Inhaber das Lager auch betreten, wenn der Besitzer offline ist?
accessWhileOwnerOffline = true,
}
--──────────────────────────────────────────────────────────────────────────────
-- MIET-MODUS (optional)
--──────────────────────────────────────────────────────────────────────────────
Config.Rent = {
enabled = true,
-- Miete pro Intervall = Kaufpreis * pricePercent
pricePercent = 0.04,
-- Länge eines Miet-Intervalls in Tagen
intervalDays = 7,
-- Kulanzzeit in Stunden nach Ablauf, bevor das Lager gesperrt wird
graceHours = 48,
-- Automatischer Einzug vom Bankkonto, wenn genug Guthaben da ist
autoDebit = true,
-- Wie viele Intervalle darf man im Voraus zahlen
maxPrepaid = 8,
-- Wird ein gesperrtes Lager nach X Tagen komplett gelöscht? (0 = nie)
deleteAfterDays = 14,
-- Beim Löschen: Items in den Besitz des Servers (true) oder Stash behalten (false)
wipeStashOnDelete = false,
-- Wie oft prüft der Server die Mietverträge (Minuten)
checkIntervalMin = 15,
}
--──────────────────────────────────────────────────────────────────────────────
-- SICHERHEIT · Anti-Cheat / Anti-Exploit
--──────────────────────────────────────────────────────────────────────────────
Config.Security = {
-- Serverseitige Distanzprüfung bei jedem Kauf/Interaktion
validateDistance = true,
-- Erlaubte Abweichung in Metern (Puffer für Lag und für Standorte,
-- an denen die Türen der einzelnen Lagergrößen auseinanderliegen).
-- Zu klein gewählt = Spieler bekommen beim Kauf "Du bist zu weit entfernt".
distanceTolerance = 12.0,
-- Ab dieser Entfernung (in Metern) gilt eine Aktion als Exploit-Versuch
-- und zählt als Strike. Darunter wird nur abgelehnt, ohne Strafpunkt —
-- damit ehrliche Spieler nicht wegen Lag oder Türabständen auffallen.
strikeDistance = 100.0,
-- Minimaler Abstand zwischen zwei Events desselben Spielers (ms)
eventCooldown = 750,
-- Ab wie vielen geblockten Events wird geloggt / gekickt
strikeWarn = 5,
strikeKick = 12,
kickReason = '[ANC Warehouse] Ungültige Aktionen erkannt.',
-- Spieler bei Verlassen des Servers automatisch aus der Instanz nehmen
forceLeaveOnDrop = true,
}
--──────────────────────────────────────────────────────────────────────────────
-- DISCORD LOGS
--──────────────────────────────────────────────────────────────────────────────
Config.Logs = {
enabled = false,
webhook = '', -- https://discord.com/api/webhooks/...
botName = 'ANC Warehouse',
avatar = '', -- optionale Bild-URL
footer = 'ANCOMOX · Warehouse System',
-- Welche Ereignisse geloggt werden
events = {
purchase = true,
entry = true,
upgrade = true,
sell = true,
rent = true,
key = true,
stash = false, -- kann sehr gesprächig werden
admin = true,
security = true,
},
colors = {
purchase = 3066993, -- grün
entry = 3447003, -- blau
upgrade = 10181046, -- violett
sell = 15158332, -- rot
rent = 15844367, -- gold
key = 1752220, -- türkis
stash = 9807270, -- grau
admin = 15105570, -- orange
security = 10038562, -- dunkelrot
},
}
--──────────────────────────────────────────────────────────────────────────────
-- ADMIN
--──────────────────────────────────────────────────────────────────────────────
Config.Admin = {
-- ESX-Gruppen / QB-Permissions die als Admin gelten
groups = { 'admin', 'superadmin', 'god', 'mod' },
-- Zusätzlich: ACE-Permission "ancomox_warehouse.admin"
useAce = true,
command = 'warehouse',
}
--──────────────────────────────────────────────────────────────────────────────
-- BLIPS
--──────────────────────────────────────────────────────────────────────────────
Config.Blips = {
enabled = true,
-- Blips nur anzeigen, wenn der Spieler das Lager besitzt
onlyOwned = false,
-- Besitzte Lager bekommen einen anderen Farbton
ownedColor = 2,
shortRange = true,
}
--──────────────────────────────────────────────────────────────────────────────
-- SONSTIGES
--──────────────────────────────────────────────────────────────────────────────
Config.Misc = {
-- Spieler wird nach Relog automatisch zurück ins Lager gesetzt
restoreOnRelog = true,
-- Bildschirm-Fade beim Betreten/Verlassen (ms, 0 = aus)
fadeTime = 500,
-- IPLs beim Start laden (bei manchen Servern schon durch andere Skripte geladen)
loadInteriors = true,
}
HasWarehouse(source, warehouseId) — gibt true zurück, wenn der Spieler diesen Lagertyp besitzt.
local has = exports.ancomox_warehouse:HasWarehouse(source, 'medium')
GetPlayerWarehouses(source) — liefert alle Lager des Spielers als Tabelle { [warehouseId] = record }. Der Datensatz enthält u. a. tier, entries, keys, tenure, rentUntil und locked.
local list = exports.ancomox_warehouse:GetPlayerWarehouses(source)
for warehouseId, rec in pairs(list) do
print(warehouseId, rec.tier, rec.tenure)
end
GetStashId(ownerIdentifier, warehouseId) — liefert die Stash-ID für eigene Inventar-Zugriffe, oder nil. Erwartet den Identifier, nicht die Server-ID.
local stash = exports.ancomox_warehouse:GetStashId(identifier, 'large')
GiveWarehouse(source, warehouseId, entryIndex) — vergibt ein Lager per Script (Belohnung, Whitelist-Job, …). Gibt false zurück, wenn die ID unbekannt ist oder der Spieler das Lager bereits besitzt. Das Limit aus Config.Limits wird dabei nicht geprüft.
Berechtigung: Gruppe aus Config.Admin.groupsoder ACE ancomox_warehouse.admin. Alle Befehle funktionieren auch aus der Serverkonsole.
Befehl
Wirkung
/warehouse list
Alle konfigurierten Lager-IDs mit Preis, Zugängen und Stufen anzeigen.
/warehouse info <id>
Lager eines Spielers inklusive Keys anzeigen.
/warehouse give <id> <lagerId> [entry]
Lager vergeben. entry ist optional, Standard ist Zugang 1.
/warehouse remove <id> <lagerId>
Lager entziehen. Anwesende Spieler werden zuvor aus der Instanz entfernt.
/warehouse tier <id> <lagerId> <stufe>
Ausbaustufe setzen. Der Stash wird sofort neu registriert.
/warehouse unlock <id> <lagerId>
Gesperrtes Mietlager entsperren und die Laufzeit verlängern.
/warehouse pos [notiz]
Aktuelle Position im Config-Format in die F8-Konsole schreiben.
/warehouse reload
Cache aus der Datenbank neu laden und alle Stashes neu registrieren.
Spieler-Befehl
Befehl
Wirkung
/warehouseui
Notfall: gibt Maus und Tastatur frei, falls das Interface hängen bleibt.
Netz-Events sind intern. Alle ancomox_warehouse:*-Events erwarten einen validierten Spielerkontext und prüfen Besitz, Rechte und Distanz selbst. Für die Anbindung eigener Scripts sind ausschließlich die oben genannten Exports vorgesehen.
Discord-Logs
Konfiguration in Config.Logs. Die Embeds werden in Paketen zu maximal zehn Stück gesendet und bei Bedarf zwischengespeichert, damit ein voller Server den Webhook nicht überlastet.
Jedes Embed enthält Spielername, Server-ID und die verfügbaren Identifier (license, discord, steam). Farben je Kategorie lassen sich über Config.Logs.colors anpassen.
Hinweise / Troubleshooting
Symptom
Ursache und Lösung
„Kein unterstütztes Framework gefunden!"
Die Ressource startet vor dem Framework. Reihenfolge in der server.cfg prüfen — ancomox_warehouse muss nach es_extended bzw. qb-core stehen.
Stash öffnet nicht oder ist leer
Config.Inventory hart auf das tatsächlich genutzte System setzen statt 'auto'. Bei ox_inventory muss die Ressource vorher starten.
Spieler sehen sich gegenseitig im Lager
Config.Instancing.enabled = true setzen und sicherstellen, dass OneSync aktiv ist.
Andere Spieler „verschwinden" auf der Map
Ein anderes Script nutzt denselben Bucket-Bereich. Config.Instancing.baseBucket auf einen freien Wert setzen.
Interior leer oder man fällt durch die Map
Das IPL wurde nicht geladen. Config.Misc.loadInteriors prüfen und sicherstellen, dass kein anderes Script dieselben IPLs entfernt.
Marker statt ox_target
Config.Target = 'ox_target' hart setzen. 'auto' wartet beim Start bis zu 5 Sekunden auf das Target-Script; startet es später, greift der Marker-Modus.
Punkt sichtbar, aber nicht anvisierbar
Bei ox_target muss der Spieler in der unsichtbaren Kugelzone stehen. targetRadius bzw. targetRadiusEntry erhöhen. Hilft das nicht, liegt die Koordinate in einer Wand — mit /warehouse pos neu setzen.
„Du bist zu weit entfernt" beim Kaufen
Jede Lagergröße hat an einem Standort ihre eigene Tür; diese können weit auseinanderliegen. Der Server akzeptiert sowohl die Tür des gewählten Lagers als auch die, an der der Dialog geöffnet wurde. Tritt die Meldung trotzdem auf, Config.Security.distanceTolerance erhöhen. Mit Config.Debug = true wird die gemessene Entfernung ausgegeben.
Kein Key vergebbar
Der Empfänger muss in derselben Instanz und in Reichweite stehen. Am Eingang funktioniert das immer, im Interior nur, wenn die Person bereits Zutritt hat. Config.Interaction.manageAtEntrance muss aktiv sein.
Schwarze Kästen hinter Dialog oder Toast
Stammt von backdrop-filter im CSS. Im Auslieferungszustand ist keines enthalten — eigene Ergänzungen entfernen und stattdessen rgba(...) verwenden.
Hilfetext zeigt „INPUT_CONTEXT"
~INPUT_CONTEXT~ löst nur die native Hilfeanzeige auf. In eigenen Locale-Texten keine ~…~-Tokens verwenden; die Taste kommt aus Config.Interaction.keyLabel.
Ausbau ohne Wirkung
Das genutzte Inventar kann die Kapazität pro Stash nicht begrenzen. Siehe den Hinweis unter „Eigenes Framework oder Inventar anbinden".
Nichts passiert beim Kaufen
Config.Debug = true setzen und die Serverkonsole prüfen. Distanzprüfungen werden mit gemessener Entfernung geloggt.
Ancomox Airdrop — server-autoritatives Versorgungsabwurf-System für FiveM. Ein Transportflugzeug fliegt an, wirft eine Kiste am Fallschirm ab, der Inhalt landet in einem echten Inventar-Container. ESX · QBCore · QBox · Standalone.
Überblick
ancomox_airdrop lässt in konfigurierbaren Intervallen — oder per Admin-Befehl oder per Leuchtfackel eines Spielers — einen Airdrop niedergehen. Der Ablauf ist eine echte Szene: Ankündigung, Zonenradius auf der Karte, anfliegendes Transportflugzeug, Abwurf, Fallschirm mit Pendelbewegung und Rauchfahne, Aufschlag.
Kernmerkmale:
Kein Host-Client. Der Server berechnet einen deterministischen Flugplan (Start, Abwurfpunkt, Ende, Geschwindigkeit, Zeitstempel). Jeder Client rechnet daraus dieselbe Flugbahn und rendert Flugzeug und Kiste lokal. Alle sehen dasselbe, ohne Netzwerk-Entities — und kein Spieler kann den Ablauf beeinflussen, weil er während der gesamten Szene kein einziges Event sendet.
Flugzeug als Karten-Event. Der Blip bewegt sich für jeden Spieler über die Karte, unabhängig von der Entfernung.
Container statt Instant-Loot. Die Kiste öffnet ein echtes Inventar — Spieler können teilen, sich darum streiten und mehrfach zugreifen.
Loot-Engine mit gewichteten Pools, garantierten Einträgen, unique-Flag, Stapelung und Geld-Einträgen über account.
Boden-Auflösung mit Konsens. Der Server kann nicht raycasten; die Bodenhöhe liefern mehrere Clients unabhängig, der Median gewinnt. Ein manipulierter Client kann die Kiste nicht unerreichbar machen.
Läuft ohne alles. Framework, Inventar, Target, Notify, Progress und TextUI werden zur Laufzeit erkannt; fehlt etwas, greift ein eingebauter Fallback. Das Script startet auch auf einem nackten Server.
Zeitlicher Ablauf mit Standardwerten: Ankündigung → 27 s Anflug → Abwurf → 36 s Fall → Aufschlag → Kiste bleibt 25 Minuten liegen. Wird sie komplett leergeräumt, verschwindet sie 6 Sekunden später.
Voraussetzungen
Es gibt keine harten Abhängigkeiten. Alles unten ist optional und wird zur Laufzeit erkannt.
Abhängigkeit
Pflicht
Zweck / Hinweis
es_extended, qb-core oder qbx_core
Optional
Ohne Framework läuft das Script im Standalone-Modus mit eingebautem Loot-Fenster.
ox_inventory, qb-inventory oder qs-inventory
Optional
Ohne Inventarsystem übernimmt das eingebaute NUI-Loot-Fenster. Bei ox_inventory wird ein temporärer Stash mit Positionsbindung erzeugt.
oxmysql
Optional
Nur für Statistiken und persistente Flare-Cooldowns. Config.Database.enabled = false deaktiviert SQL vollständig.
ox_target oder qb-target
Optional
Ohne Target-Script greift ein performanter 3D-Text-Fallback mit Tastendruck.
ox_lib
Optional
Notifications, Progressbar und TextUI.
ps-dispatch, cd_dispatch, qs-dispatch
Optional
Polizei-Meldungen. Ohne Dispatch-System werden Job-Spieler direkt benachrichtigt.
Umbenannte Ressourcen: Heißt bei dir eine Abhängigkeit anders, trag den echten Namen in Config.ResourceNames ein — die Erkennung greift dann trotzdem.
Installation
Ordner ancomox_airdrop nach resources/[ancomox]/ kopieren.
In der server.cfg eintragen — nach Framework, Inventar und oxmysql:
ensure ancomox_airdrop
Admin-Rechte setzen. Über ACE funktioniert das in jedem Framework:
add_ace group.admin ancomox.airdrop allow
Flare-Items anlegen (nur nötig, wenn Spieler Airdrops selbst auslösen sollen). Bei ox_inventory den fertigen Block aus items/ox_inventory.lua in ox_inventory/data/items.lua kopieren — die Einträge enthalten bereits die nötige server.export-Verknüpfung.
config/loot.lua an die eigenen Item-Namen anpassen (siehe unten).
config/zones.lua prüfen und eigene Abwurfpunkte setzen.
Startet eine Abhängigkeit später als das Script, erkennt es sie automatisch nach und meldet das in der Konsole. Ein zu früher Start führt also nicht dauerhaft zu standalone.
Flare-Items ohne ox_inventory
QBCore / QBox: Einträge aus items/qb_core.lua in qb-core/shared/items.lua kopieren, Bilder nach qb-inventory/html/images/.
Standalone: Flares lassen sich per Befehl auslösen (/use_airdrop_flare), oder du setzt Config.Flares.enabled = false.
Datenbank
Die Datenbank ist optional. Ohne oxmysql läuft alles weiter — es fehlen nur Statistiken, und Flare-Cooldowns überleben keinen Serverneustart. Die Tabellen werden beim Start automatisch angelegt; sql/install.sql liegt für die manuelle Installation bei.
Tabelle
Inhalt
ancomox_airdrop_drops
Jeder Airdrop mit Typ, Zone, Koordinaten, Auslöser, Start- und Endzeit sowie Endgrund.
ancomox_airdrop_loot
Jede Item-Entnahme mit Identifier, Spielername, Item und Menge.
ancomox_airdrop_cooldowns
Flare-Cooldown pro Identifier — überlebt dadurch einen Neustart.
Abwurfzonen, Blacklist-Bereiche, Regeln zur Punktauflösung
config/loot.lua
Airdrop-Typen und Loot-Tabellen
Die wichtigsten Schalter
Key
Standard
Beschreibung
Config.Automatic.intervalMin / intervalMax
45 / 90
Zufälliger Abstand zwischen automatischen Airdrops in Minuten.
Config.Automatic.minPlayers
4
Darunter wird kein automatischer Drop gestartet.
Config.Automatic.maxConcurrent
2
Gleichzeitig aktive Airdrops. Gilt auch für Flares und Admin-Drops.
Config.Scene.enabled
true
false = die Kiste erscheint ohne Flugzeug.
Config.Scene.approachDistance
2200.0
Anflugstrecke in Metern. Bei 80 m/s ergibt das rund 27 Sekunden.
Config.Scene.renderDistance
800.0
Ab hier wird das Flugzeug als Objekt erzeugt. Der Karten-Blip ist davon unabhängig immer sichtbar.
Config.Crate.despawnAfter
25
Minuten, bis eine unangetastete Kiste verschwindet.
Config.Crate.despawnWhenEmpty
true
Leergeräumte Kiste nach emptyGrace Sekunden entfernen.
Config.Interaction.unlock.duration
6000
Dauer der Aufbruch-Animation in ms. Pro Airdrop-Typ über unlockTime überschreibbar.
Config.Interaction.unlock.item
nil
Optionales Werkzeug, z. B. 'lockpick'. consume steuert, ob es verbraucht wird.
Config.Container.maxOpenDistance
4.0
Ab dieser Entfernung wird der geöffnete Container zwangsweise geschlossen.
Config.Flares.playerCooldown
30
Minuten Sperre pro Spieler nach einer Fackel.
Config.Security.rateLimit
30
Maximale Aufrufe pro Spieler, pro Event-Typ, pro 10 Sekunden.
Zonen — zwei Modi
Der Modus entscheidet, wie zuverlässig der Abwurfpunkt sitzt:
Modus
Verhalten
preferPoints = true(empfohlen)
Es wird ausschließlich einer der hinterlegten Punkte genutzt. Die Höhe gilt als vermessen: keine Boden-Abfrage, kein Wasser-Risiko, kein Höhenfehler.
preferPoints = false
Zufälliger Punkt im Radius. Die Bodenhöhe wird zur Laufzeit von bis zu drei Clients abgefragt (Median). Gut in flachem Gelände, kann in Bergen und an Küsten danebenliegen.
So kommst du an gute Punkte: im Spiel an die Stelle gehen, Koordinaten abgreifen, als vector3(x, y, z) in points eintragen und preferPoints = true setzen. Die mitgelieferten Koordinaten sind Startwerte und sollten auf der eigenen Map geprüft werden — Küsten- und Gebirgszonen sind bewusst auf feste Punkte gestellt bzw. deaktiviert.
Loot-Regeln
guaranteed landet immer in der Kiste.
pool wird rolls-mal gewichtet gezogen. weight ist ein relatives Gewicht, keine Prozentangabe — die Summe muss nichts Bestimmtes ergeben.
unique = true — der Eintrag kann pro Kiste nur einmal gezogen werden.
account = 'money' | 'bank' | 'black_money' wird als Geld gutgeschrieben statt als Item. Bei QB/QBox gibt es kein Schwarzgeld-Konto; das System legt dort markedbills an, sonst Bargeld.
Waffen einfach als weapon_pistol schreiben — die Bridge normalisiert bei ox_inventory automatisch auf WEAPON_PISTOL.
Nur Items belegen Slots, Geld nicht. Passen garantierte Einträge nicht in container.slots, warnt die Konsole.
Eigenen Airdrop-Typ anlegen:
Config.AirdropTypes['military'] = {
label = 'Militär-Airdrop',
weight = 8, -- relative Wahrscheinlichkeit
plane = 'titan',
crateModel = 'prop_mil_crate_01',
blipColour = 1,
smokeColour = { r = 255, g = 40, b = 40 },
container = { slots = 20, maxWeight = 150000 },
unlockTime = 15000, -- ms bis die Kiste offen ist
announce = true,
loot = {
rolls = { min = 6, max = 9 },
guaranteed = {
{ item = 'armor', min = 3, max = 5 },
},
pool = {
{ item = 'weapon_assaultrifle', min = 1, max = 1, weight = 20,
unique = true, metadata = { ammo = 150 } },
{ item = 'rifle_ammo', min = 100, max = 300, weight = 80 },
{ account = 'black_money', min = 30000, max = 70000, weight = 50,
label = 'Schwarzgeld' },
},
},
}
Vollständige Config-Dateien
config/config.lua300 Zeilen · vollständige Datei
--[[--------------------------------------------------------------------------
ancomox_airdrop · Hauptkonfiguration
------------------------------------------------------------------------
Alle Werte hier sind sicher editierbar (escrow_ignore).
Loot -> config/loot.lua
Zonen -> config/zones.lua
----------------------------------------------------------------------------]]
Config = {}
-- =========================================================================
-- ALLGEMEIN
-- =========================================================================
Config.Debug = false -- Ausführliche Konsolenausgabe
Config.Locale = 'de' -- de | en | fr | es
-- Versionsprüfung beim Start (leere URL = aus).
-- Erwartet eine Textantwort, die NUR die Versionsnummer enthält, z.B. "2.0.1"
Config.VersionCheck = false
Config.VersionCheckUrl = ''
-- =========================================================================
-- AUTO-DETECTION
-- 'auto' erkennt automatisch, was auf dem Server läuft.
-- Nur überschreiben, wenn die Erkennung fehlschlägt.
-- =========================================================================
Config.Framework = 'auto' -- auto | esx | qb | qbx | standalone
Config.Inventory = 'auto' -- auto | ox | qb | qs | core | builtin
Config.Target = 'auto' -- auto | ox_target | qb-target | none
Config.Notify = 'auto' -- auto | ox_lib | esx | qb | builtin
Config.Progress = 'auto' -- auto | ox_lib | qb | builtin
Config.TextUI = 'auto' -- auto | ox_lib | qb | builtin
-- Ressourcen-Namen überschreiben (falls umbenannt)
Config.ResourceNames = {
esx = 'es_extended',
qb = 'qb-core',
qbx = 'qbx_core',
oxInv = 'ox_inventory',
qbInv = 'qb-inventory',
qsInv = 'qs-inventory',
oxLib = 'ox_lib',
oxTarget = 'ox_target',
qbTarget = 'qb-target',
oxmysql = 'oxmysql',
}
-- =========================================================================
-- DATENBANK (optional – nur für Statistiken & Crash-Recovery)
-- =========================================================================
Config.Database = {
enabled = true, -- false = komplett ohne SQL lauffähig
logDrops = true, -- Jeden Airdrop in DB schreiben
logLoot = true, -- Jede Item-Entnahme loggen
}
-- =========================================================================
-- AUTOMATISCHE AIRDROPS
-- =========================================================================
Config.Automatic = {
enabled = true,
intervalMin = 45, -- Minuten (untere Grenze)
intervalMax = 90, -- Minuten (obere Grenze)
minPlayers = 4, -- Erst ab so vielen Spielern online
maxConcurrent = 2, -- Gleichzeitig aktive Airdrops
firstDropDelay = 10, -- Minuten nach Serverstart bis zum ersten Drop
announce = true, -- Globale Ankündigung
}
-- =========================================================================
-- ADMIN / BERECHTIGUNGEN
-- =========================================================================
Config.Permissions = {
command = 'airdrop', -- /airdrop [typ]
cancelCmd = 'airdropcancel', -- /airdropcancel [id]
listCmd = 'airdroplist',
-- ACE-Permission (empfohlen, funktioniert in JEDEM Framework)
ace = 'ancomox.airdrop',
-- Zusätzlich akzeptierte Framework-Gruppen
groups = { 'admin', 'superadmin', 'god', 'owner' },
allowConsole = true,
}
-- =========================================================================
-- FLUGZEUG / SZENE
-- =========================================================================
-- Der Flug ist vollständig deterministisch: der Server berechnet Start,
-- Abwurfpunkt und Endpunkt, jeder Client rechnet daraus dieselbe Position.
-- Dadurch sehen ALLE Spieler dasselbe Flugzeug – auch quer über die Karte,
-- und es gibt keinen "Host"-Client mehr, der ausfallen könnte.
Config.Scene = {
enabled = true, -- false = Kiste erscheint ohne Flugzeug
-- Entfernung, in der das Flugzeug relativ zum Abwurfpunkt startet
approachDistance = 2200.0, -- ergibt bei 80 m/s ca. 27 s Anflug
exitDistance = 1500.0, -- wie weit es danach weiterfliegt
altitude = 320.0, -- Abwurfhöhe über dem Boden
speed = 80.0, -- m/s
-- Ab dieser Entfernung wird das Flugzeug als Objekt erzeugt.
-- GTA zeichnet Fahrzeuge darüber hinaus ohnehin kaum noch – höhere Werte
-- kosten nur Leistung. Der Karten-Blip ist IMMER für alle sichtbar.
renderDistance = 800.0,
planeBlip = true, -- Flugzeug als Event-Blip auf der Karte
planeLights = true,
}
-- =========================================================================
-- KISTE
-- =========================================================================
Config.Crate = {
defaultModel = 'prop_mil_crate_01',
chuteModel = 'p_cargo_chute_s',
descentSpeed = 9.0, -- m/s Sinkgeschwindigkeit am Fallschirm
swayStrength = 0.9, -- Seitliches Pendeln
spinSpeed = 12.0, -- Grad/Sekunde Eigendrehung
landingImpact = true, -- Staubwolke + Sound beim Aufsetzen
-- Rauchfahne an der Kiste. Es wird der erste Eintrag verwendet, dessen
-- Partikel-Dictionary sich laden lässt (Robustheit über GTA-Builds hinweg).
smoke = {
enabled = true,
scale = 2.5,
zOffset = 0.35,
variants = {
{ dict = 'scr_ba_bb', name = 'scr_ba_bb_package_flare' },
{ dict = 'scr_xm_ht', name = 'scr_xm_ht_package_flare' },
{ dict = 'scr_ie_export', name = 'scr_ie_export_package_flare' },
{ dict = 'core', name = 'exp_grd_flare' },
},
},
-- Sound beim Aufsetzen (leerer Name = aus)
landSound = { name = 'Crate_Land', set = 'FBI_05_SOUNDS' },
-- Ab dieser Entfernung wird die Kiste beim Spieler erzeugt
streamDistance = 400.0,
despawnAfter = 25, -- Minuten nach der Landung -> Kiste verschwindet
despawnWarn = 3, -- Minuten vorher warnen
-- Kiste verschwindet, sobald sie komplett leergeräumt ist
despawnWhenEmpty = true,
emptyGrace = 6, -- Sekunden Verzögerung, damit man es noch sieht
}
-- =========================================================================
-- BLIPS
-- =========================================================================
Config.Blips = {
-- Ungefähre Landezone. Wird ab der Ankündigung angezeigt und beim
-- Aufsetzen durch den exakten Kisten-Blip ersetzt.
zone = {
enabled = true,
radius = 200.0,
colour = 1, -- rote Fläche
alpha = 80,
fuzzy = true, -- Mittelpunkt zufällig versetzen
fuzzyOffset = 70.0,
showMarker = true, -- zusätzlicher Symbol-Blip in der Zonenmitte
},
crate = {
enabled = true,
sprite = 478,
colour = 5,
scale = 0.9,
shortRange = false,
flash = false,
},
-- Flugzeug-Blip: an/aus über Config.Scene.planeBlip
plane = {
sprite = 423,
colour = 4,
scale = 0.8,
},
}
-- =========================================================================
-- INTERAKTION
-- =========================================================================
Config.Interaction = {
distance = 2.2,
key = 38, -- E (nur bei Fallback ohne Target)
useTarget = true, -- ox_target / qb-target verwenden wenn vorhanden
-- Kiste muss erst "geknackt" werden
unlock = {
enabled = true,
duration = 6000, -- ms
item = nil, -- z.B. 'lockpick' – nil = kein Item nötig
itemLabel = 'Brecheisen', -- Anzeigename für die Fehlermeldung
consume = false, -- Item verbrauchen?
anim = { dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', clip = 'machinic_loop_mechandplayer' },
prop = nil,
cancelOnMove = true,
},
-- Nur bestimmte Jobs dürfen looten (leer = alle)
restrictJobs = {},
-- Loot nur außerhalb von Fahrzeugen
denyInVehicle = true,
denyWhenDead = true,
}
-- =========================================================================
-- CONTAINER (Loot-Kiste)
-- =========================================================================
Config.Container = {
prefix = 'ancomox_airdrop_',
slots = 18,
maxWeight = 120000,
-- Sicherheit: max. Distanz, in der der Container geöffnet bleiben darf
maxOpenDistance = 4.0,
}
-- =========================================================================
-- POLIZEI / DISPATCH
-- =========================================================================
Config.Dispatch = {
enabled = true,
system = 'auto', -- auto | ps-dispatch | cd_dispatch | qs-dispatch | core | none
onSpawn = true, -- Meldung wenn Airdrop startet
onLoot = true, -- Meldung wenn jemand plündert
lootChance = 65, -- % Wahrscheinlichkeit für Loot-Meldung
jobs = { 'police', 'sheriff', 'sast', 'bcso' },
blipTime = 120, -- Sekunden
}
-- =========================================================================
-- FLARES (Spieler löst Airdrop mit Item aus)
-- =========================================================================
Config.Flares = {
enabled = true,
-- Cooldown pro Spieler in Minuten
playerCooldown = 30,
-- Globaler Cooldown in Minuten (0 = aus)
globalCooldown = 5,
-- Verzögerung zwischen Flare-Wurf und Flugzeug (Sekunden)
callDelay = 25,
-- Flare darf nur in diesen Zonen benutzt werden (leer = überall erlaubt)
restrictToZones = false,
-- Verbotene Bereiche (Safezone, Stadt etc.)
blacklistZones = {
{ coords = vector3(-1037.0, -2737.0, 20.0), radius = 400.0, label = 'Flughafen' },
},
items = {
['airdrop_flare'] = {
label = 'Leuchtfackel',
airdropType = 'standard',
prop = 'prop_flare_01',
smokeColour = { r = 255, g = 60, b = 40 },
},
['airdrop_flare_rare'] = {
label = 'Signalfackel (Selten)',
airdropType = 'rare',
prop = 'prop_flare_01',
smokeColour = { r = 80, g = 140, b = 255 },
},
},
}
-- =========================================================================
-- SICHERHEIT / ANTI-CHEAT
-- =========================================================================
Config.Security = {
-- Max. Aufrufe pro Spieler, pro Event-Typ, pro 10 Sekunden
rateLimit = 30,
-- Nach wie vielen Verstößen gekickt wird
violationsToKick = 4,
-- Spieler bei Überschreitung kicken
kickOnAbuse = true,
kickMessage = 'Ancomox Airdrop: verdächtige Netzwerkaktivität erkannt.',
-- Loot nur wenn Spieler wirklich in Reichweite (Server-seitige Prüfung)
enforceDistance = true,
distanceTolerance = 6.0,
-- Höhentoleranz für den Loot-Zugriff. Verhindert Looten aus dem
-- Stockwerk darüber, lässt aber kleine Boden-Z-Abweichungen zu.
verticalTolerance = 10.0,
-- Verdächtige Vorgänge an Discord melden
logViolations = true,
}
-- =========================================================================
-- DISCORD WEBHOOKS
-- =========================================================================
Config.Webhook = {
enabled = false,
botName = 'ANCOMOX Airdrop',
avatar = '',
colour = 3447003,
urls = {
spawn = '',
loot = '',
collected = '',
admin = '',
security = '',
},
}
-- =========================================================================
-- HUD / NUI
-- =========================================================================
Config.HUD = {
enabled = true,
showDistance = true,
showDespawn = true, -- Verbleibende Zeit bis Despawn
position = 'right', -- right | left
soundOnSpawn = true,
}
config/zones.lua147 Zeilen · vollständige Datei
--[[--------------------------------------------------------------------------
ancomox_airdrop · Abwurfzonen
------------------------------------------------------------------------
ZWEI MODI PRO ZONE
1) preferPoints = true (EMPFOHLEN)
Es wird ausschließlich einer der hinterlegten Punkte verwendet.
Die Höhe gilt als vermessen: keine Boden-Abfrage, kein Wasser-Risiko,
kein Höhenfehler. Das ist der zuverlässigste Modus.
2) preferPoints = false
Zufälliger Punkt im Radius. Die Boden-Höhe wird zur Laufzeit von
mehreren Clients abgefragt (Median). Funktioniert gut in flachem
Gelände, kann in Bergen und an Küsten danebenliegen.
==> Für einen Verkaufs-fertigen Server: eigene Punkte im Spiel abgreifen
und preferPoints = true setzen. Die hier hinterlegten Koordinaten
sind Startwerte und sollten auf deiner Map geprüft werden.
----------------------------------------------------------------------------]]
Config.Zones = {
{
name = 'Sandy Shores / Grapeseed',
enabled = true,
weight = 25,
center = vector3(1900.0, 3700.0, 32.0),
radius = 850.0,
preferPoints = false, -- flaches Wüstengelände, Radius ist unkritisch
points = {
vector3(2431.87, 4968.25, 45.31),
vector3(1690.44, 3272.11, 40.14),
vector3(2140.19, 4780.55, 40.97),
},
hours = {},
allowFlare = true,
},
{
name = 'Grand Senora Desert',
enabled = true,
weight = 20,
center = vector3(1100.0, 2700.0, 38.0),
radius = 700.0,
preferPoints = false, -- sehr flach, ideal für Radius-Modus
points = {
vector3(1207.11, 2660.44, 37.85),
vector3(880.55, 2380.19, 51.66),
},
hours = {},
allowFlare = true,
},
{
name = 'Mount Chiliad / Raton Canyon',
enabled = true,
weight = 15,
center = vector3(500.0, 5600.0, 780.0),
radius = 700.0,
preferPoints = true, -- Gebirge: NUR feste Punkte verwenden
points = {
vector3(501.28, 5604.51, 797.91),
vector3(-70.66, 6432.11, 31.49),
vector3(1310.11, 6520.44, 19.32),
},
hours = {},
allowFlare = true,
},
{
name = 'Fort Zancudo Umland',
enabled = true,
weight = 15,
center = vector3(-2200.0, 3100.0, 32.0),
radius = 450.0, -- klein gehalten, damit nichts im Meer landet
preferPoints = false,
points = {},
hours = {},
allowFlare = true,
},
{
name = 'Alamo Sea · Ufer',
enabled = true,
weight = 15,
center = vector3(1300.0, 4200.0, 33.0),
radius = 800.0,
-- Der See selbst ist Wasser -> ausschließlich Uferpunkte verwenden
preferPoints = true,
points = {
vector3(1531.11, 3789.44, 34.32),
vector3(908.66, 3609.19, 32.60),
vector3(1728.55, 4681.11, 42.16),
vector3(1129.44, 4630.88, 30.85),
},
hours = {},
allowFlare = true,
},
{
name = 'Chumash / Küste West',
enabled = false, -- Küstenzone: erst mit eigenen Punkten aktivieren
weight = 10,
center = vector3(-2100.0, 2200.0, 20.0),
radius = 700.0,
preferPoints = true,
points = {
vector3(-1602.44, 2100.11, 75.28),
vector3(-2288.10, 3000.47, 32.81),
},
hours = {},
allowFlare = true,
},
{
name = 'Cayo Perico',
enabled = false, -- nur mit geladenem Cayo-DLC aktivieren
weight = 10,
center = vector3(5055.72, -4524.91, 7.27),
radius = 350.0,
preferPoints = true,
points = {
vector3(5055.72, -4524.91, 2.27),
vector3(4885.33, -5165.98, 2.11),
},
hours = {},
allowFlare = false,
},
}
--[[ Bereiche, in denen NIEMALS gedroppt wird (Safezones, Stadt, PD, …) ]]
Config.ZoneBlacklist = {
{ coords = vector3(441.0, -982.0, 30.0), radius = 250.0, label = 'Mission Row PD' },
{ coords = vector3(-1037.0, -2737.0, 20.0), radius = 350.0, label = 'LSIA' },
{ coords = vector3(295.0, -1446.0, 29.0), radius = 200.0, label = 'Pillbox Hospital' },
}
--[[ Regeln für die Auflösung des Abwurfpunkts ]]
Config.ZoneRules = {
-- Landet der gewählte Punkt im Wasser, wird ein neuer Punkt gesucht.
-- Greift nur im Radius-Modus; feste Punkte gelten als vermessen.
denyWater = true,
waterRetries = 4,
-- Plausibilitätsgrenzen für die vom Client gemeldete Boden-Höhe
minGroundZ = -50.0,
maxGroundZ = 1200.0,
-- Maximale Abweichung von der Zonenhöhe, wenn nur EIN Client geantwortet
-- hat. Sind sich mehrere Clients einig, gilt deren Wert ohne diese Grenze.
maxGroundDeviation = 260.0,
-- Wie viele Clients unabhängig befragt werden (Median gewinnt).
-- 1 = aus. Höhere Werte kosten nichts und verhindern Manipulation.
groundProbers = 3,
}
config/loot.lua168 Zeilen · vollständige Datei
--[[--------------------------------------------------------------------------
ancomox_airdrop · Airdrop-Typen & Loot-Tabellen
------------------------------------------------------------------------
LOOT-SYSTEM
guaranteed : wird IMMER in die Kiste gelegt
pool : gewichtete Zufallsauswahl ("weight" = relatives Gewicht)
rolls : wie viele Einträge aus dem Pool gezogen werden
unique : true = Eintrag kann pro Kiste nur einmal gezogen werden
GELD
Für Bargeld/Schwarzgeld statt Item: account = 'money' | 'black_money' | 'bank'
Wird beim Aufnehmen direkt gutgeschrieben (ohne Item).
WAFFEN
ox_inventory : 'WEAPON_PISTOL' (Großschreibung, metadata für Munition)
ESX/QB : 'weapon_pistol'
-> Die Bridge normalisiert das automatisch, schreibe einfach 'weapon_pistol'.
TYP-AUSWAHL
weight = relatives Gewicht bei automatischen Airdrops.
Es müssen KEINE 100 % ergeben – das System normalisiert selbst.
----------------------------------------------------------------------------]]
Config.AirdropTypes = {
---------------------------------------------------------------------
standard = {
label = 'Standard Airdrop',
weight = 55,
plane = 'titan',
crateModel = 'prop_mil_crate_01',
blipColour = 5,
smokeColour = { r = 240, g = 240, b = 240 },
container = { slots = 12, maxWeight = 60000 },
unlockTime = 5000,
announce = true,
loot = {
rolls = { min = 4, max = 6 },
guaranteed = {
{ item = 'bandage', min = 2, max = 4 },
},
pool = {
{ item = 'water', min = 2, max = 5, weight = 120 },
{ item = 'bread', min = 2, max = 5, weight = 120 },
{ item = 'bandage', min = 1, max = 3, weight = 90 },
{ item = 'lockpick', min = 1, max = 2, weight = 60 },
{ item = 'repairkit', min = 1, max = 1, weight = 45 },
{ item = 'armor', min = 1, max = 1, weight = 40 },
{ item = 'weapon_pistol', min = 1, max = 1, weight = 25, unique = true,
metadata = { ammo = 40 } },
{ item = 'pistol_ammo', min = 20, max = 60, weight = 55 },
{ account = 'money', min = 1500, max = 4000, weight = 70,
label = 'Bargeld' },
{ account = 'black_money', min = 2000, max = 6000, weight = 45,
label = 'Schwarzgeld' },
},
},
},
---------------------------------------------------------------------
rare = {
label = 'Seltener Airdrop',
weight = 28,
plane = 'titan',
crateModel = 'prop_mil_crate_01',
blipColour = 3,
smokeColour = { r = 60, g = 140, b = 255 },
container = { slots = 16, maxWeight = 90000 },
unlockTime = 8000,
announce = true,
loot = {
rolls = { min = 5, max = 7 },
guaranteed = {
{ item = 'armor', min = 1, max = 2 },
{ item = 'bandage', min = 3, max = 6 },
},
pool = {
{ item = 'weapon_smg', min = 1, max = 1, weight = 30, unique = true,
metadata = { ammo = 60 } },
{ item = 'weapon_pumpshotgun',min = 1, max = 1, weight = 30, unique = true,
metadata = { ammo = 24 } },
{ item = 'weapon_carbinerifle',min = 1, max = 1, weight = 12, unique = true,
metadata = { ammo = 90 } },
{ item = 'smg_ammo', min = 40, max = 120, weight = 70 },
{ item = 'rifle_ammo', min = 40, max = 120, weight = 50 },
{ item = 'medikit', min = 1, max = 2, weight = 55 },
{ item = 'advancedlockpick', min = 1, max = 2, weight = 45 },
{ item = 'thermite', min = 1, max = 1, weight = 20, unique = true },
{ account = 'black_money', min = 8000, max = 20000, weight = 60,
label = 'Schwarzgeld' },
{ item = 'goldbar', min = 1, max = 3, weight = 25 },
},
},
},
---------------------------------------------------------------------
exotic = {
label = 'Exotischer Airdrop',
weight = 12,
plane = 'velum',
crateModel = 'prop_mil_crate_01',
blipColour = 46,
smokeColour = { r = 190, g = 60, b = 255 },
container = { slots = 18, maxWeight = 120000 },
unlockTime = 12000,
announce = true,
loot = {
rolls = { min = 6, max = 8 },
guaranteed = {
{ item = 'armor', min = 2, max = 3 },
{ item = 'medikit', min = 2, max = 3 },
},
pool = {
{ item = 'weapon_specialcarbine', min = 1, max = 1, weight = 18, unique = true,
metadata = { ammo = 120 } },
{ item = 'weapon_heavysniper', min = 1, max = 1, weight = 6, unique = true,
metadata = { ammo = 20 } },
{ item = 'weapon_assaultrifle', min = 1, max = 1, weight = 22, unique = true,
metadata = { ammo = 120 } },
{ item = 'rifle_ammo', min = 90, max = 250, weight = 80 },
{ item = 'sniper_ammo', min = 10, max = 30, weight = 35 },
{ item = 'thermite', min = 1, max = 2, weight = 35 },
{ item = 'goldbar', min = 3, max = 8, weight = 45 },
{ item = 'diamond', min = 1, max = 3, weight = 25 },
{ account = 'black_money', min = 25000, max = 60000, weight = 55,
label = 'Schwarzgeld' },
},
},
},
---------------------------------------------------------------------
medical = {
label = 'Sanitäts-Airdrop',
weight = 5,
plane = 'titan',
crateModel = 'prop_mil_crate_01',
blipColour = 2,
smokeColour = { r = 60, g = 230, b = 90 },
container = { slots = 10, maxWeight = 50000 },
unlockTime = 3000,
announce = false,
loot = {
rolls = { min = 3, max = 4 },
guaranteed = {
{ item = 'medikit', min = 4, max = 8 },
{ item = 'bandage', min = 8, max = 15 },
},
pool = {
{ item = 'water', min = 5, max = 10, weight = 100 },
{ item = 'bread', min = 5, max = 10, weight = 100 },
{ item = 'painkillers',min = 2, max = 5, weight = 70 },
{ item = 'armor', min = 1, max = 2, weight = 40 },
},
},
},
}
--[[--------------------------------------------------------------------------
ITEM-METADATEN für das eingebaute Loot-Fenster (nur relevant, wenn KEIN
unterstütztes Inventar erkannt wird). Bild-Pfade sind optional.
----------------------------------------------------------------------------]]
Config.ItemDisplay = {
imagePath = 'nui://ox_inventory/web/images/%s.png', -- %s = Itemname
labels = {
-- ['goldbar'] = 'Goldbarren',
},
}
Exports
Alle Exports sind serverseitig.
StartAirdrop(typeKey, coords, sourceType, triggeredBy) — startet einen Airdrop. Gibt die ID zurück, oder nil plus Fehlergrund.
typeKey — Schlüssel aus Config.AirdropTypes, oder nil für gewichteten Zufall
coords — vector3 für eine feste Position, oder nil für Zonenwahl
GetActiveAirdrops() — liefert alle aktiven Airdrops als Tabelle { [id] = state } mit Typ, Zustand, Zone, Koordinaten und Despawn-Zeit.
for id, drop in pairs(exports.ancomox_airdrop:GetActiveAirdrops()) do
print(id, drop.type, drop.state, drop.zoneName)
end
Events & Commands
Admin-Befehle
Berechtigung über ACE ancomox.airdrop oder eine Gruppe aus Config.Permissions.groups. Alle Befehle funktionieren auch aus der Serverkonsole.
Befehl
Wirkung
/airdrop [typ] [hier]
Airdrop starten. Ohne Typ: gewichteter Zufall. hier setzt ihn an die eigene Position (nicht aus der Konsole).
/airdropcancel <id> · /airdropcancel all
Einzelnen Airdrop oder alle beenden.
/airdroplist
Aktive Airdrops mit Zustand, Zone und Restlaufzeit.
Item-Export für ox_inventory
Flares werden bei ox_inventory nicht über RegisterUsableItem ausgelöst, sondern über das Export-Feld in der Item-Definition. Ohne diesen Eintrag passiert beim Benutzen nichts:
server = { export = 'ancomox_airdrop.useFlareItem' },
Discord-Logs
Fünf getrennte Webhooks, jeder einzeln aktivierbar. Ist eine URL leer, wird für diese Kategorie nichts gesendet.
Kategorie
Wird ausgelöst bei
spawn
Start eines Airdrops inklusive Typ, Zone, Koordinaten und Auslöser.
loot
Erstes Öffnen der Kiste mit Spielername und Identifier.
collected
Ende eines Airdrops mit Grund und Laufzeit.
admin
Admin-gestartete Drops und benutzte Flares.
security
Sicherheitsverstöße: Rate-Limit, fehlendes Unlock-Ticket, zu schnelles Aufbrechen, Distanzprüfung.
Koordinaten fälschen — die Position kommt immer aus GetEntityCoords(GetPlayerPed(src)) auf dem Server.
Aus der Ferne looten — jede Entnahme prüft Distanz und Höhenkorridor serverseitig neu.
Die Fortschrittsleiste überspringen — der Server vergibt ein einmaliges Unlock-Ticket mit Zeitstempel und lehnt zu schnelle Abschlüsse ab.
Ohne geöffneten Container Items nehmen — wer nicht regulär geöffnet hat, steht nicht in der Betrachterliste.
Items duplizieren — Mengen werden gegen NaN, ±inf und den Restbestand geprüft.
Cooldowns umgehen — Flare-Cooldowns liegen serverseitig und überleben mit SQL einen Neustart.
Events spammen — Rate-Limits gelten pro Spieler und pro Event-Typ; pro Zeitfenster wird höchstens ein Verstoß gemeldet.
Faire Behandlung bei unklarer Bodenhöhe: Solange die Höhe der Kiste noch nicht bestätigt ist, gilt eine stark erweiterte Höhentoleranz und es wird kein Sicherheitsverstoß protokolliert. Der Fehler läge dann beim Server, nicht beim Spieler.
Hinweise / Troubleshooting
Symptom
Ursache und Lösung
„Framework: standalone" obwohl ESX läuft
Config.ResourceNames.esx prüfen (umbenannte Ressource) oder Config.Framework fest setzen.
Kiste schwebt oder steckt im Boden
Zone auf preferPoints = true mit exakten Koordinaten umstellen. Die Bodensetzung wird zwar wiederholt, bis die Collision geladen ist — feste Punkte sind aber immer zuverlässiger.
Kein Flugzeug, Kiste erscheint sofort
Config.Scene.enabled prüfen. Fehlt das Flugzeugmodell, steht eine Warnung in der Konsole.
Flugzeug auf der Karte, aber nicht am Himmel
Normal, solange du weiter als Config.Scene.renderDistance (800 m) entfernt bist.
Kiste ist leer oder verschwindet direkt
Die Item-Namen aus config/loot.lua existieren nicht in deinem Inventar. Das Script erkennt das, warnt in der Konsole und lässt die Kiste stehen, statt sie zu löschen.
Kein Rauch sichtbar
Eines der Partikel-Dictionaries aus Config.Crate.smoke.variants muss ladbar sein. Die Liste wird der Reihe nach durchprobiert.
Flare tut nichts
Bei ox_inventory fehlt server = { export = 'ancomox_airdrop.useFlareItem' } in der Item-Definition.
Spieler werden gekickt
Config.Security.rateLimit erhöhen oder kickOnAbuse = false setzen.
Schwarzer Kasten hinter dem HUD
Kommt von backdrop-filter — das rendert FiveMs CEF nicht transparent. Im Auslieferungszustand ist keines enthalten; eigene Ergänzungen entfernen und rgba(...) verwenden.
Ancomox Fishing — server-autoritatives Angelsystem mit eigenem Drill-Minigame, XP- und Levelsystem, dynamischem Markt, Turnieren und einem vollwertigen Bootsverleih. Das Markenzeichen: jeder Fang wird als echtes 3D-Modell präsentiert. ESX · QBCore · QBox.
Überblick
ancomox_fishing ist eine komplette Angel-Wirtschaft. Der Spieler kauft Rute und Köder, angelt am Wasser, kämpft im Drill-Minigame gegen den Fisch und verkauft den Fang legal am Fischmarkt oder illegal am Schwarzmarkt. Level, Zonen und Köder steuern, was überhaupt anbeißt.
Kernmerkmale:
3D-Fang-Showcase — jeder gefangene Fisch erscheint als echtes Modell. Kleine Fische liegen neben dem Spieler am Boden, große Fänge wälzen sich im Wasser davor. Bei epischen und legendären Fängen fährt eine kurze Trophäen-Kamera darum herum.
Eigenes Drill-Minigame — der Fisch zieht in unregelmäßigen Fluchten, der Spieler hält mit der Leertaste dagegen und muss die Nadel in der grünen Zone halten. Rutenqualität und Fischstärke gehen direkt in die Physik ein; bei Überspannung reißt die Schnur.
14 Arten in 5 Raritäten mit Gewichtsspannen, Tag-/Nachtzeiten, Wetter-Boni und Level-Anforderungen. Dazu Beifang wie Schrott, Perlen und eine Flaschenpost.
Einzigartige Fänge — der Buckelwal „Moby" kann pro Spieler nur ein einziges Mal gefangen werden.
XP und Level 1–50, persistent in der Datenbank, mit gebündelten Schreibvorgängen statt DB-Spam pro Fang.
Dynamischer Markt — Preise schwanken, Massenverkäufe drücken über die Marktsättigung den Preis, Gewicht und Qualität fließen ein.
Bootsverleih, komplett server-autoritativ, relog- und restartfest, mit drei Rückgabewegen.
Automatische Turniere nach schwerstem Gesamtgewicht, mit Zeitplan, Ankündigung, Mindestspielerzahl und Preisgeldern.
Voraussetzungen
Abhängigkeit
Pflicht
Zweck / Hinweis
oxmysql
Ja
XP, Statistiken und Bootsmieten. Als dependency im Manifest eingetragen.
es_extended, qb-core oder qbx_core
Ja (eines)
Wird über Config.Framework = 'auto' erkannt.
ox_inventory
Empfohlen
Nur dort gibt es echte Metadaten: individuelles Gewicht und Qualität pro Fisch sowie Ruten-Haltbarkeit. Alternativ qb-inventory oder das ESX-Inventar.
ox_target oder qb-target
Optional
Ohne Target-Script greift ein Marker-Fallback mit Tastendruck.
3D-Modelle: Das Script referenziert Basisspiel-Peds (a_c_fish, a_c_dolphin, a_c_sharkhammer, a_c_humpback …) ausschließlich per Modellname zur Laufzeit. Es wird keine Spieldatei mitgeliefert — geladen wird aus der GTA-V-Installation des Spielers.
Installation
Ordner ancomox_fishing nach resources/ kopieren.
ensure oxmysql und ensure ancomox_fishing in die server.cfg — nach dem Framework.
Datenbank: nichts zu tun, beide Tabellen werden beim ersten Start automatisch angelegt.
Items registrieren (siehe unten).
Icons kopieren: die 28 Icons aus install/ox_inventory_images/ nach ox_inventory/web/images/ und dieselben Dateien zusätzlich nach html/images/ für die eigenen Menüs, plus boat.png.
Admin-Rechte setzen:
add_ace group.admin ancomox_fishing.admin allow
Items registrieren
ox_inventory (empfohlen): Den kompletten Inhalt von install/ox_inventory_items.lua in ox_inventory/data/items.lua einfügen und ox_inventory neu starten. Die Definitionen enthalten bereits die server.export-Verknüpfungen — Ruten und Köder funktionieren sofort.
['fishing_rod_wood'] = {
label = 'Holzrute',
weight = 1500,
stack = false,
close = true,
consume = 0, -- das Script verwaltet den Verbrauch selbst
description = 'Eine einfache Angelrute aus Holz.',
server = { export = 'ancomox_fishing.fishing_rod_wood' },
},
QBCore: dieselben Items im QB-Format in qb-core/shared/items.lua.
ESX mit Datenbank-Items: die INSERT-Anweisungen am Ende von sql/ancomox_fishing.sql ausführen.
Warum stack = false bei Fischen? Jeder Fang trägt eigenes Gewicht und eigene Qualität als Metadata — beides fließt in den Verkaufspreis ein. Gestapelt ginge diese Information verloren.
Ingame-Zeit
Zeitgebundene Arten wie Wels und Schwertfisch brauchen die Ingame-Stunde. Der Server kennt sie nicht von sich aus — GetClockHours() ist ein reines Client-Native. Deshalb gibt es drei Quellen über Config.Time.source:
Wert
Verhalten
'client'(Standard)
Ein Spieler meldet die Ingame-Zeit periodisch. Autorität ist die niedrigste Server-ID, damit niemand dauerhaft „Nacht" faken kann. Zwischen zwei Meldungen läuft die Uhr serverseitig weiter.
'real'
Echte Serverzeit über os.date.
'fixed'
Immer Config.Time.fixedHour — zum Testen.
Wer einen Weather-Sync betreibt, kann Zeit und Regen auch direkt setzen:
Beide Tabellen werden beim Start automatisch angelegt. sql/ancomox_fishing.sql liegt für die manuelle Installation bei.
Tabelle
Spalten
Inhalt
ancomox_fishing
identifier, xp, stats
XP-Stand und Statistiken als JSON: Anzahl Fänge, schwerster Fang, Fänge pro Art und die Liste bereits gefangener Unikate.
ancomox_boat_rentals
identifier, model, point, price, deposit, started_at, pending_refund
Laufende Bootsmieten und offene Kautionen.
Kautionen können nicht verloren gehen. Nach einem Resource-Restart existiert kein Boot mehr; alle offenen Mieten werden in pending_refund umgewandelt und beim nächsten Login des Spielers automatisch ausgezahlt.
Bootsverleih
Das Boot wird vom Server erzeugt; der Client bekommt nur eine NetID. Kein Client kann ein fremdes Fahrzeug als Mietboot registrieren.
Vorgang
Verhalten
Rückgabe am Dock
Große grüne Zone auf dem Wasser (Standard 50 m). Funktioniert im Boot sitzend und daneben stehend. Volle Kaution zurück, abzüglich Schaden und Überziehung.
Fernrückgabe
/bootabgeben von überall oder per Button im Menü. Das Boot wird abgeholt, es gibt die Kaution minus Abholgebühr (Standard 35 %).
Boot verloren
Zerstört, gesunken oder verschwunden: die Miete wird automatisch geschlossen. Der Spieler hängt nie fest und kann sofort neu mieten.
Zurückholen
Am Verleih gegen Gebühr — holt ein festgefahrenes Boot ans Dock zurück.
Schlüssel
Nur der Mieter fährt (Statebag-basiert). Mitfahren dürfen alle.
Zeit & Schaden
Nach maxRentalMinutes läuft eine Gebühr pro Minute — das Boot wird dem Spieler aber nie unter dem Hintern weggenommen, solange er darin sitzt. Verlassene Boote sammelt der Verleih nach despawnEmptyAfter Minuten ein.
Fünf Standorte sind vorkonfiguriert: Puerto Del Sol, Chumash Pier, Paleto Bay, Sonar Collections Dock und der Alamo-See. Die Platzierung korrigiert sich zur Laufzeit selbst — die Z-Höhe des NPCs wird auf den echten Boden gesetzt, der Wasser-Spawn per GetWaterHeight bestimmt und bei Bedarf spiralförmig bis 40 m weiter außen gesucht.
Turnier sofort starten. Beide Befehle sind identisch.
Discord-Logs
Vier getrennte Webhooks in Config.Webhooks. Leere URL bedeutet, dass für diese Kategorie nichts gesendet wird.
Kategorie
Wird ausgelöst bei
catches
Fänge der Raritäten episch und legendär, mit Art, Gewicht und Spieler.
sales
Jeder Verkauf mit Summe und Art des Verkaufspunkts (legal / illegal).
boats
Anmietung und Rückgabe inklusive Modus, Kaution, Schadensanteil und Gebühren.
admin
Turnierergebnisse und Cheat-Verdachtsfälle: zu schnelles Minigame, zu kurzes Fangintervall, Rate-Limit.
Hinweise / Troubleshooting
Symptom
Ursache und Lösung
Rute oder Köder reagiert nicht
Bei ox_inventory fehlt server = { export = 'ancomox_fishing.<itemname>' } in der Item-Definition. Nur darüber löst ox_inventory das Item aus.
Nachtaktive Fische beißen nie
Config.Time.source prüfen. Bei 'client' muss mindestens ein Spieler online sein, der die Zeit meldet. Zum Testen 'fixed' mit fixedHour = 23 setzen.
Minigame ist unschaffbar
Config.Minigame.playerPull erhöhen. Der Spielerzug muss über dem maximalen Fischzug liegen, sonst wandert die Nadel zwangsläufig in den roten Bereich.
Ruten zerbrechen ständig
Ohne Metadata-Inventar greift fallbackBreakChance. Wert senken oder auf ox_inventory wechseln.
Schwarzmarkt zahlt nichts aus
Kein black_money-Item vorhanden. Im 'auto'-Modus wird automatisch Bargeld gezahlt und ein Hinweis in die Konsole geschrieben; alternativ Config.BlackMoney.mode fest setzen.
„Diese Zone erreichst du nur mit einem Boot"
Die Position liegt in einer Zone mit requiresBoat = true. Der Spieler muss auf einem stehenden Boot sitzen oder darauf stehen.
Bilder fehlen im Verkaufs- oder Shop-Menü
Die Menüs laden aus html/images/. Fehlt eine Datei, blendet das UI das Bild aus — funktionsfähig bleibt es.
Boot ist weg, Kaution scheinbar verloren
Kann nicht passieren: Nach Restart oder Verlust landet der Betrag als pending_refund in der Datenbank und wird beim nächsten Login ausgezahlt.
Turnier startet nicht
Config.Tournament.minPlayers prüfen. Die Serverkonsole schreibt bei jedem Versuch, wie viele Spieler online waren und warum abgebrochen wurde.
Peds oder Blips bleiben nach Restart liegen
Sollte nicht auftreten — beim onResourceStop werden alle Peds und Blips entfernt. Tritt es doch auf, läuft eine alte Version.
DriveOS — vollautomatische Fahrschule für FiveM. Theorie- und Praxisprüfung laufen ohne Fahrlehrer, rund um die Uhr. ESX · QBCore · Qbox · ox_core · Standalone, ohne Pflicht-Framework und ohne Pflicht-Datenbank.
Überblick
Auf den meisten Servern scheitert der Führerschein daran, dass kein Fahrlehrer online ist. DriveOS ersetzt den menschlichen Prüfer: Der Spieler geht zur Fahrschule, wählt seine Klasse, absolviert die Theorie, fährt die Prüfungsstrecke und bekommt am Ende die Lizenz im Framework eingetragen.
Vier Führerscheinklassen sind fertig konfiguriert:
Klasse
Fahrzeug
Theorie
Praxis
Voraussetzung
A — Motorrad
pcj
12 Fragen · 80 %
70 Punkte
—
B — PKW
asterope
15 Fragen · 80 %
70 Punkte
—
C — LKW
mule
12 Fragen · 85 %
75 Punkte
Klasse B
D — Bus
coach
12 Fragen · 85 %
75 Punkte
Klasse B
Fahrzeuge, Gebühren, Fragenzahl, Bestehensgrenzen und Voraussetzungen stehen alle in der config.lua. Eine neue Klasse entsteht durch Kopieren eines Blocks.
Theorieprüfung
Die Lösungen liegen ausschließlich auf dem Server. Der Client erhält Frage und Antwortmöglichkeiten, nie die richtige Antwort — weder auslesbar noch über einen NUI-Trick manipulierbar.
Zufälliger Fragenbogen pro Versuch. Zwei Prüfungen sind nie identisch.
Über 60 deutsche Fragen sind hinterlegt, thematisch nach Klasse sortiert.
Zeitlimit mit Server-Watchdog: Läuft die Zeit ab, wertet der Server aus — auch wenn der Spieler das Spiel schließt.
Fenster schließen zählt als nicht bestanden (abschaltbar), danach greift eine Sperrzeit.
Eine bestandene Theorie verfällt nach X Tagen (Standard 14) und wird nach bestandener Praxis verbraucht.
Praktische Prüfung
Jeder startet mit 100 Punkten:
Ereignis
Abzug
Leichter Tempoverstoß (ab 8 km/h über Limit)
−5
Grober Tempoverstoß (ab 21 km/h über Limit)
−15
Kollision
−10
Schwere Kollision
−25
Sofort durchgefallen bei zerstörtem oder brennendem Fahrzeug, Fahndungslevel während der Prüfung, Verlassen der Route (Standard: mehr als 200 m zum nächsten Checkpoint), mehr als 20 Sekunden außerhalb des Fahrzeugs oder überschrittenem Zeitlimit.
Für alle vier Klassen sind Checkpoint-Routen hinterlegt — mit GPS-Route, Restzeit, Tempolimit je Abschnitt und Hinweistexten. Die Busprüfung enthält Haltestellen-Checkpoints, an denen wirklich vollständig angehalten werden muss. Checkpoints werden automatisch auf die Straße gesnappt, ungenaue Koordinaten sind also unkritisch.
Voraussetzungen
Pflicht: keine. DriveOS läuft standalone. Alles Folgende wird automatisch erkannt, wenn es vorhanden ist.
Ressource
Wofür
oxmysql
Fortschritt in der Datenbank statt in einer JSON-Datei.
Gebühren ohne Framework: Auf ESX, QBCore und Qbox werden Prüfungsgebühren abgebucht. Auf ox_core und Standalone gibt es keine einheitliche Geld-API — dort sind die Prüfungen kostenlos, bis eine eigene Geldanbindung eingehängt wird.
Installation
Ordner driveos nach resources/ kopieren.
In die server.cfg eintragen:
ensure driveos
ACE-Recht für den Routen-Recorder setzen:
add_ace group.admin driveos.admin allow
Fertig. Mit oxmysql wird die Tabelle beim Start selbst angelegt, ohne oxmysql speichert DriveOS in einer JSON-Datei — beides ohne Handarbeit.
Datenbank
DriveOS nutzt genau eine Tabelle: driveos_progress. Sie wird beim Start automatisch angelegt, fehlende Spalten werden per Migration ergänzt.
Ohne oxmysql läuft der komplette Fortschritt über eine JSON-Datei — voll standalone, ohne jede Einrichtung.
Die Framework-Lizenz wird zusätzlich dort gesetzt, wo dein Framework sie erwartet:
Framework
Ablage
ESX
user_licenses
QBCore / Qbox
metadata.licences
ox_core
Charakter-Metadaten
Konfiguration
Trotz Escrow-Schutz bleiben diese Dateien offen und frei editierbar:
Theoriefragen — eine Zeile je Frage: Frage, drei Antworten, Nummer der richtigen Antwort
server/routes.lua
Prüfungsstrecken mit Checkpoints, Tempolimits und Haltestellen
README.md
Installation und Anpassung
Eigene Routen aufnehmen
Der eingebaute Recorder nimmt eine Strecke auf, während du sie abfährst. Abgesichert über die ACE-Berechtigung driveos.admin — kein Spieler kann das auslösen.
Befehl
Wirkung
/dsroute start
Aufnahme starten, Checkpoints werden automatisch gesetzt.
/dsroute point 30
Manueller Checkpoint mit Tempolimit 30.
/dsroute stophere
Haltestelle setzen — hier muss vollständig angehalten werden.
/dsroute stop
Fertiges Lua-Snippet in der Serverkonsole ausgeben.
Snippet kopieren, in server/routes.lua einfügen, fertig.
LicenseOS-Anbindung
DriveOS ist eine reine Ingame-Ressource ohne eigenes Panel. Läuft zusätzlich LicenseOS auf dem Server, übergibt DriveOS jede Prüfung dorthin — die Lizenz wird dann über LicenseOS inklusive Lizenznummer ausgestellt, und auf Wunsch werden die dort hinterlegten Pflicht-Fahrstunden auch für die Selbstbedienung durchgesetzt.
Die Anbindung ist ein Bonus, keine Voraussetzung — DriveOS funktioniert vollständig ohne LicenseOS.
Der Client entscheidet nichts. Checkpoints gelten erst als erreicht, wenn der Server sie bestätigt — kein Vorspulen, kein Desync-Trick.
Der Server misst unabhängig mit. Position und Geschwindigkeit werden serverseitig gegengeprüft.
Plausibilitätsprüfung der Fahrzeit. Wer die Strecke schneller abschließt, als sie physikalisch fahrbar ist, bekommt die Prüfung als ungültig gewertet.
Reason-Whitelist — gefälschte Fail-Events vom Client werden abgefangen.
Doppelstart-Schutz verhindert eine doppelte Abbuchung.
Automatische Erstattung, wenn eine Prüfung technisch nicht starten konnte — eng abgesichert gegen Missbrauch.
Die Theoriebewertung passiert zu 100 % serverseitig.
Discord-Logs
Ein Webhook protokolliert jede bestandene und nicht bestandene Prüfung. Die URL wird in der config.lua eingetragen; ohne Eintrag wird nichts gesendet.
Hinweise / Troubleshooting
Symptom
Ursache und Lösung
Framework wird nicht erkannt
Config.Framework von Hand setzen. Auf Standalone funktioniert alles außer den Framework-Funktionen.
Gebühren werden nicht abgebucht
Auf ox_core und Standalone gibt es keine einheitliche Geld-API — dort sind Prüfungen kostenlos, bis eine eigene Anbindung eingehängt ist. Siehe README.
Kein Target am Fahrschul-Ped
Ohne ox_target greift automatisch die E-Taste mit Marker. Das ist kein Fehler.
Checkpoints liegen neben der Straße
Unkritisch — Checkpoints werden automatisch auf die Straße gesnappt.
Prüfung wird als ungültig gewertet
Die Plausibilitätsprüfung der Fahrzeit hat angeschlagen. Bei sehr kurzen eigenen Routen die Streckenlänge prüfen.
Theorie ist plötzlich weg
Eine bestandene Theorie verfällt nach der eingestellten Frist (Standard 14 Tage) und wird nach bestandener Praxis verbraucht.
Einzelne Anzeigen bleiben leer
Sehr alte FXServer-Artefakte kennen einzelne Natives nicht. Das Script fängt das ab, statt abzustürzen — Artefakt aktualisieren.
Leistungsaufnahme: Im Leerlauf läuft ein Thread mit 800 ms Intervall; das Marker-Rendering startet erst im Umkreis von 15 m um die Fahrschule. Während einer Prüfung läuft die Bewertungsschleife alle 150 ms auf dem Client des Prüflings und alle 2,5 Sekunden serverseitig — nur für diesen einen Spieler.
Ancomox Admin Suite — vollständiges Admin-Panel für FiveM, bedienbar im Spiel per Tastendruck und im Browser über das mitgelieferte Web-Panel. Framework und Inventar werden selbst erkannt. ESX · QBCore · Qbox · Standalone.
Überblick
ancomox_adminsuite bündelt Spielerverwaltung, Sanktionen, Wirtschaft, Live-Werkzeuge und Datenschutz in einem Panel. Jede Aktion wird serverseitig gegen das Rechtesystem geprüft und protokolliert — das Interface entscheidet nie über Berechtigungen.
Funktionsumfang
Spielerverwaltung
Live-Liste mit Ping, Leben, Weste, Dimension und Statusmarkern, Aktualisierung im Sekundentakt
Vollständige Spielerakte: Kennungen, Beruf, Gang, Bargeld, Bank, Inventar, Position
Massenaktionen: alle heilen, alle wiederbeleben, alle herholen, alle Fahrzeuge reparieren
Support-Modus: Admin und Spieler in eine isolierte Dimension und zurück
Sanktionen
Kick, Ban mit Stundenangabe oder permanent, Offline-Ban über jede beliebige Kennung
Ban-Prüfung beim Verbinden über license, license2, Discord, Steam, FiveM und Hardware-Token
Ban-Manager mit Suche, Ablaufdatum und Entsperren
Verwarnungen mit Auto-Ban nach frei wählbarer Anzahl
Gefängnis mit Zonenüberwachung und automatischer Entlassung — übersteht Serverneustarts
Vorgefertigte Ban-Gründe, Einspruchs-Link im Kick-Screen, Begründungspflicht
Wirtschaft, Fahrzeuge, Welt
Geld und Items geben oder entziehen, Waffen verwalten, Inventar leeren, Job und Gang setzen
Item-Bilder aus dem eigenen Inventar — ox_inventory, qs-inventory, codem-inventory, qb-inventory und Framework-HUDs werden automatisch erkannt
Fahrzeug-Verwaltung in der Spielerakte: alle Fahrzeuge des Charakters aus der Datenbank mit Kennzeichen, Modell und Garagen-Status — herbeirufen, ein- und ausparken, vergeben oder löschen
Wetter, Zeit, Blackout, Lockdown, Ankündigungen, NPCs und Objekte aufräumen
Live-Werkzeuge
Live-Karte mit allen Spielern, Zoom, Verschieben und Schnellzielen
Live-Stream des Spielerbildschirms mit Beweisbildern samt Zeitstempel und Wasserzeichen
Verdeckte Kamerabeobachtung über die Engine, ohne den eigenen Charakter zu bewegen
Nicht nötig — kein CDN, keine Webfonts, kein Phone-Home. Vue liegt lokal im Paket.
Ohne Datenbank läuft das Panel im KVP-Modus: Alles funktioniert, aber Protokoll und Historie überleben keinen Neustart. Für einen ernsthaft betriebenen Server ist der Datenbankmodus die richtige Wahl.
Fertig. Die Tabellen legt das Skript beim ersten Start selbst an; die .sql-Datei liegt für die manuelle Einrichtung bei.
Rechteprobleme in einer Minute geklärt:/ancomoxperms zeigt für jeden Spieler, welcher ACE-Eintrag greift und welches Level dabei herauskommt.
Datenbank
Alle Tabellen werden beim ersten Start automatisch angelegt. Die passende .sql-Datei liegt bei, falls du sie lieber von Hand einspielst.
Ohne oxmysql arbeitet das Panel im KVP-Modus — vollständig funktionsfähig, aber Protokoll und Historie gehen beim Neustart verloren.
Rechte-System
Das ist der Kern des Panels. Die meisten Admin-Menüs lassen dich festlegen, dass ein Moderator nicht bannen darf. Hier bestimmst du zusätzlich, welches Feld der Spielerakte ein Rang überhaupt zu sehen bekommt.
Ein gesperrtes Feld wird nicht ausgeblendet — es verlässt den Server nicht. Ein manipulierter Client sieht es deshalb ebenfalls nicht. Dasselbe gilt für ganze Bereiche über Config.ViewPermissions; auch Befehlspalette und Tastenkürzel laufen durch dieselbe Sperre.
Abschalten und Beschränken funktioniert auf vier Ebenen:
Schalter
Umfang
Config.Features
16 Module einzeln an- und abschaltbar
Config.ActionPermissions
67 Aktionen, je mit Mindest-Level
Config.ViewPermissions
12 Bereiche — wer welchen Tab öffnen darf
Config.DataPermissions
13 Datenfelder — wer welches Feld der Akte sieht
Konfiguration
config.lua, die vier Sprachdateien, die SQL-Datei und die gesamte Dokumentation sind über escrow_ignore von der Verschlüsselung ausgenommen und bleiben dauerhaft offen.
Bereich
Inhalt
Config.Framework
Automatische Erkennung; bei Bedarf fest vorgeben.
Config.Features
16 Module.
Config.ActionPermissions
67 Aktionen mit Mindest-Level.
Config.ViewPermissions / Config.DataPermissions
12 Bereiche, 13 Datenfelder.
Config.Theme
Anzeigename, Untertitel, Icon, drei Presets, alle Akzentfarben, Eckenradius und Animationen.
Web-Panel
Port, Passwort, IP-Allowlist. Ab Werk abgeschaltet.
Web-Panel
Dasselbe Interface im Browser — moderieren ohne laufendes Spiel, auch vom Handy. Absicherung über Session-Token, Login-Sperre nach Fehlversuchen, IP-Bindung der Sitzung und IP-Allowlist.
Ab Werk deaktiviert und ohne gesetztes Passwort gar nicht erreichbar. Für den Betrieb im offenen Internet brauchst du einen TLS-Reverse-Proxy — der FiveM-HTTP-Endpunkt selbst ist unverschlüsselt.
Datenschutz
Ein eigener Tab bündelt, was auf einem EU-Server früher oder später gebraucht wird:
IP-Anzeige abschaltbar — bei showIP = false verlässt die IP den Server gar nicht erst
Automatische Löschfristen für Protokoll, Verwarnungen, Notizen, Tickets, Gefängnisdaten und abgelaufene Sperren — jede Frist einzeln einstellbar
Kennungen im Protokoll pseudonymisiert (PBKDF2 mit serverindividuellem Salt)
Discord-Webhooks maskieren Kennungen und IP-Adressen vor dem Versand
Export- und Löschfunktion für Anfragen einzelner Spieler, mit Pflichtbegründung und Protokoll
Spielerbefehle /meinedaten und /datenloeschung, Namen frei wählbar
Datenbank-Scan
Ein Spieler ist gelöscht, aber sein Auto steht noch in der Garage. Oder jemand fragt, was über ihn gespeichert ist. Das Panel liest information_schema, findet jede Spalte, die nach einer Spielerkennung aussieht, und zählt die Treffer:
Erkannt werden die License mit und ohne license:-Präfix sowie die QBCore-citizenid. Gefunden werden auch Tabellen von Skripten, an die niemand mehr denkt — ohne Konfiguration.
Der Scan zählt nur. Keine Inhalte im Export, kein DELETE, kein UPDATE. Außerhalb der Panel-Tabellen wird nichts gelöscht: Wer die users-Zeile eines Spielers entfernt, zerstört seinen Charakter.
Kein Ersatz für Rechtsberatung. Die mitgelieferte PRIVACY.md ist eine technische Beschreibung und Orientierungshilfe. Das Script macht einen Server nicht automatisch DSGVO-konform.
Events & Commands
Befehl
Wer
Wirkung
/ancomoxperms
Admin
Zeigt für jeden Spieler, welcher ACE-Eintrag greift und welches Level dabei herauskommt.
/meinedaten
Spieler
Datenauskunft anfordern. Name frei wählbar.
/datenloeschung
Spieler
Löschung der eigenen Daten beantragen. Name frei wählbar.
Hinweise / Troubleshooting
Symptom
Ursache und Lösung
Panel öffnet nicht / Rechte greifen nicht
/ancomoxperms ausführen — der Befehl zeigt den greifenden ACE-Eintrag und das resultierende Level.
Framework wird nicht erkannt
Config.Framework von Hand setzen. Auf Standalone funktioniert alles außer Geld, Job und Inventar.
Protokoll ist nach dem Neustart leer
Das Panel läuft im KVP-Modus. oxmysql installieren und vor dem Panel starten lassen.
Live-Stream und Beweisbilder fehlen
screenshot-basic nachinstallieren. Alle anderen Funktionen sind davon nicht betroffen.
Keine Item-Bilder
Das Inventar wurde nicht erkannt. Unterstützt sind ox_inventory, qs-inventory, codem-inventory, qb-inventory und Framework-nativ.
Web-Panel nicht erreichbar
Es ist ab Werk deaktiviert und ohne gesetztes Passwort gar nicht erreichbar. Port freigeben, Passwort setzen — im offenen Internet zwingend hinter einen TLS-Reverse-Proxy.
Einzelne Anzeigen bleiben leer
Sehr alte FXServer-Artefakte kennen einzelne Natives nicht. Das Panel fängt das ab, statt abzustürzen — Artefakt aktualisieren.
Ancomox Activity Suite — Player Analytics und Moderations-Zentrale. Trackt Spielzeiten, Serverauslastung und Wirtschaft automatisch und legt Reports, Bans, Verwarnungen und Spielerakten daneben. ESX · QBCore · Qbox · Standalone.
Überblick
ancomox_activitysuite beantwortet die Fragen, die ein Serverbetrieb wirklich stellt: Wann ist der Server voll? Wer sind die Stammspieler? Kippt gerade die Wirtschaft? Welche Fraktion stirbt? Die passenden Moderationswerkzeuge liegen direkt daneben.
Abgrenzung zur Admin Suite: Die Ancomox Admin Suite ist das klassische Admin-Panel für den Eingriff im laufenden Betrieb. Die Activity Suite ist das Analytics-Gegenstück — Auswertung, Verläufe und Spielerakten. Beide laufen unabhängig voneinander.
Analytics
Server-Auslastung — automatisches Population-Tracking mit 24-Stunden- und 7-Tage-Verlauf
Aktivitäts-Heatmap — 7×24-Raster der letzten 30 Tage, für Event- und Teamplanung
Spielzeit-Analytics — pro Spieler und pro Fraktion, mit Datumsfilter, Leaderboard und CSV-Export
Fraktions-Radar — Spielzeit, Mitglieder und Live-Online-Zahlen aller Jobs im Vergleich
Economy Watch
Gesamt-Geldmenge, Bargeld gegen Bank, durchschnittliches Vermögen — live aus der Datenbank
Vermögensverteilung nach Klassen (unter 10.000 bis über 10 Mio.) — Money-Glitches werden sichtbar, bevor sie die Wirtschaft kippen
Top 25 der Reichsten mit Direktsprung in die Akte, dazu eine Konzentrationsanzeige („Top 10 halten X %")
Vermögensverlauf pro Spieler über 30 Tage oder den gesamten Zeitraum
Spielerakte
Ein Klick auf einen Spieler öffnet Finanzen, Inventar und Waffen, den kompletten Fuhrpark mit Bildern, Verwarnungen, Aktivitäts-Chart, Admin-Notizen und Strafregister. Dazu ein Trust-Score aus echten Verwarnungen, Dossier-Export und eine Funktion zum Kopieren aller Kennungen. Geld geben, nehmen und wipen funktioniert online wie offline.
Moderation
Report-/Ticket-System — Spieler tippen /report, Admins bekommen einen Live-Push: annehmen, antworten, hinteleportieren, abschließen
Internes Ban-System — Zeit-Bans von 1 Stunde bis 30 Tage, Offline-Bans und Unban direkt im Panel, Ban-Prüfung beim Verbinden
Vollbild-Verwarnungen — die Warnung erscheint unübersehbar auf dem Bildschirm des Spielers
Live-Screenshot direkt in den Discord (über screenshot-basic)
Lückenlose Admin-Logs und drei getrennte Discord-Webhooks
Kick, Heal, Freeze, Spectate, TP und Bring, Massenaktionen, Server-Ankündigungen, Nuke und Soft-Wipe
Voraussetzungen
Punkt
Anforderung
Pflicht
oxmysql
Framework
ESX, QBCore oder Qbox (automatisch erkannt) — oder keines (Standalone über Ace-Permissions)
Optional
ox_inventory für Item-Labels, screenshot-basic für Live-Screenshots
Ordnername
Muss ancomox_activitysuite bleiben (Escrow-Auslieferung).
Server
Aktuelles FXServer-Artefakt.
Installation
Ordner nach resources/ kopieren — der Name muss ancomox_activitysuite bleiben.
In die server.cfg eintragen:
ensure oxmysql
ensure ancomox_activitysuite
Rechte vergeben. Bei ESX über users.group, bei QBCore/Qbox über das Permission-Level, im Standalone-Betrieb über ACE:
add_ace group.admin ancomox.admin allow
Fertig — alle neun Datenbanktabellen legt das Script beim ersten Start selbst an.
Wichtig zum ACE-Betrieb: Der Gruppenname hinter ancomox. muss in Config.Permissions als Schlüssel existieren. ancomox.admin greift also nur, wenn es dort einen Eintrag ['admin'] gibt.
Datenbank
Das Script legt beim ersten Start neun Tabellen selbst an — SQL-Kenntnisse sind nicht nötig. Der Ban-Check beim Verbinden läuft über die Tabelle panel_bans.
Zwei Aufbewahrungsfristen sind einstellbar:
Option
Standard
Wirkung
Config.PopulationInterval
10
Alle X Minuten wird die aktuelle Spielerzahl gespeichert.
Config.PopulationRetentionDays
14
So viele Tage werden die Populationsdaten aufbewahrt.
Rechte-System
Zwölf granulare Rechte je Gruppe. Jede einzelne Aktion wird serverseitig geprüft — das Interface blendet Verbotenes komplett aus, statt es nur zu deaktivieren.
Recht
Erlaubt
view_panel
Das Panel überhaupt öffnen.
view_team
Den Reiter „Team & Staff" sehen.
view_logs
Die Admin-Logs lesen.
mass_actions
Alle heilen, Chat leeren, Autos löschen.
announce
Server-Ankündigungen senden.
nuke
Spieler-Accounts komplett vernichten.
eco
Geld geben, abziehen, wipen und den Wirtschafts-Tab öffnen.
inv
Items spawnen und gezielt löschen.
set_job
Fraktionen ändern.
kick_ban
Kicken, Bannen, Heilen und Verwarnen.
spectate
Live-Spectate und Teleports.
reports
Spieler-Reports sehen und bearbeiten.
Fünf Gruppen sind vorkonfiguriert: superadmin und god (alles erlaubt), admin (alles außer nuke), mod (keine Wirtschafts- und Item-Rechte, kein Team-Reiter, keine Logs) sowie support (darf verwarnen, aber nicht kicken).
Konfiguration
Key
Standard
Beschreibung
Config.Framework
'auto'
'auto' · 'esx' · 'qb' · 'standalone'
Config.CommandName
"activitysuite"
Befehl zum Öffnen des Panels.
Config.Keybind
"F10"
Taste zum Öffnen. Leerstring = nur per Befehl.
Config.ServerName
"Ancomox Roleplay"
Anzeigename im Panel.
Config.ReportCommand
"report"
Befehl, mit dem Spieler einen Report erstellen.
Config.ReportCooldown
60
Sekunden zwischen zwei Reports pro Spieler (Spam-Schutz).
Config.NotifyAdminsOnReport
true
Admins mit reports-Recht im Chat benachrichtigen.
Config.UseInternalBans
true
Internes Ban-System: Offline-Bans, Zeit-Bans und Unban direkt im Panel.
Config.UseTxAdminBans
false
Permanente Online-Bans zusätzlich über txAdmin. Experimentell — der txAdmin-Export ist nicht offiziell; Fallback ist immer das interne System.
Config.WebhookURL
""
Admin-Aktionen. Wird auch für den Live-Screenshot-Upload verwendet.
Config.EcoWebhookURL
""
Economy-Logs. Leer lassen, wenn alles in denselben Channel soll.
Config.ReportWebhookURL
""
Report-Logs. Leer lassen, wenn alles in denselben Channel soll.
Escrow — was offen bleibt
Ausgeliefert wird über das offizielle FiveM Asset Escrow. Diese Dateien bleiben unverschlüsselt und frei editierbar:
Datei
Anpassbar
config.lua
Alle Einstellungen — Framework, Rechtesystem, Webhooks, Commands, Keybind
bridge/server.lua
Komplette Framework-Anbindung serverseitig — eigene Frameworks und Inventare andocken
bridge/client.lua
Framework-Anbindung clientseitig — Notifications, Revive, Status
html/ (komplett)
Das gesamte Interface — Farben, Texte, Logo, Branding
Verschlüsselt ist ausschließlich der Logik-Kern (server.lua, aggregator.lua, client.lua). Für ein Custom-Framework musst du also nie in eine verschlüsselte Datei — die offene Bridge ist die einzige Schnittstelle.
Vollständige Config-Datei
config.lua156 Zeilen · vollständige Datei
Config = {}
-- ------------------------------------------------------------------
-- FRAMEWORK
-- ------------------------------------------------------------------
-- 'auto' = Framework wird automatisch erkannt (empfohlen)
-- 'esx' = ESX Legacy (es_extended)
-- 'qb' = QBCore / Qbox (qb-core / qbx_core)
-- 'standalone' = Kein Framework (Session-Tracking + Ace-Permissions)
Config.Framework = 'auto'
-- ------------------------------------------------------------------
-- ALLGEMEIN
-- ------------------------------------------------------------------
-- Mit welchem Befehl wird das Panel im Spiel geöffnet?
Config.CommandName = "activitysuite"
-- Mit welcher Taste soll die Activity Suite geöffnet werden? (z.B. F10, F9, K)
-- Lass es leer (""), falls du ausschließlich den Command verwenden möchtest.
Config.Keybind = "F10"
Config.ServerName = "Ancomox Roleplay"
-- ------------------------------------------------------------------
-- REPORT / TICKET SYSTEM
-- ------------------------------------------------------------------
-- Command mit dem Spieler einen Report erstellen (z.B. /report Spieler XY rammt mich)
Config.ReportCommand = "report"
-- Cooldown in Sekunden zwischen zwei Reports pro Spieler (Spam-Schutz)
Config.ReportCooldown = 60
-- Sollen Admins (mit reports-Recht) im Chat benachrichtigt werden, wenn ein neuer Report eingeht?
Config.NotifyAdminsOnReport = true
-- ------------------------------------------------------------------
-- POPULATION TRACKING (Spieler-Verlauf Chart)
-- ------------------------------------------------------------------
-- Alle wieviel Minuten soll die aktuelle Spielerzahl gespeichert werden?
Config.PopulationInterval = 10
-- Wieviele Tage sollen die Populations-Daten aufbewahrt werden?
Config.PopulationRetentionDays = 14
-- ------------------------------------------------------------------
-- BAN SYSTEM
-- ------------------------------------------------------------------
-- Soll das Skript für PERMANENTE Online-Banns zusätzlich txAdmin verwenden?
-- (Experimentell - der txAdmin-Export ist nicht offiziell. Fallback ist immer das interne System.)
Config.UseTxAdminBans = false
-- Internes Ban-System aktivieren? (Ermöglicht Offline-Bans, Zeit-Bans & Unban direkt im Panel)
-- Der Ban-Check läuft beim Verbinden über die panel_bans Tabelle.
Config.UseInternalBans = true
-- ------------------------------------------------------------------
-- WEBHOOKS FÜR DISCORD LOGGING
-- ------------------------------------------------------------------
-- Standard Admin Aktionen (Bans, Kicks, Teleports, Nuke, Warns)
-- Wird auch für den Live-Screenshot-Upload verwendet!
Config.WebhookURL = ""
-- Economy Logs (Geld geben/nehmen, Items spawnen/löschen, Account Wipes)
-- Leer lassen, wenn alles in den gleichen Channel soll.
Config.EcoWebhookURL = ""
-- Report Logs (Neue Reports, Claims, Abschlüsse)
-- Leer lassen, wenn alles in den gleichen Channel soll.
Config.ReportWebhookURL = ""
-- ------------------------------------------------------------------
-- GRANULARES RECHTE-SYSTEM (RBAC)
-- Definiere hier exakt, welche Gruppe was im Panel darf.
--
-- ESX: Gruppen aus users.`group` (superadmin, admin, mod, ...)
-- QBCore/Qbox: Permission-Level (god, admin, mod) - unten bereits enthalten
-- Standalone: Ace-Permissions - vergib z.B.: add_ace group.admin ancomox.admin allow
-- Der Gruppenname hinter "ancomox." muss hier als Key existieren.
-- ------------------------------------------------------------------
Config.Permissions = {
-- HÖCHSTE STUFE: Darf absolut alles
['superadmin'] = {
view_panel = true, -- Darf das Panel überhaupt öffnen?
view_team = true, -- Darf den "Team & Staff" Tab sehen?
view_logs = true, -- Darf die Admin-Logs lesen?
mass_actions = true, -- Darf Alle heilen, Chat leeren, Autos löschen?
announce = true, -- Darf rote Server-Ankündigungen senden?
nuke = true, -- Darf Spieler-Accounts komplett vernichten?
eco = true, -- Darf Geld geben / abziehen / wipen + Wirtschafts-Tab?
inv = true, -- Darf Items spawnen & gezielt löschen?
set_job = true, -- Darf Fraktionen ändern?
kick_ban = true, -- Darf Spieler Kicken, Bannen, Heilen & Verwarnen?
spectate = true, -- Darf das Live-Spectate Auge nutzen & TPs?
reports = true -- Darf Spieler-Reports sehen & bearbeiten?
},
-- QBCore/Qbox Äquivalent zu superadmin
['god'] = {
view_panel = true, view_team = true, view_logs = true, mass_actions = true,
announce = true, nuke = true, eco = true, inv = true, set_job = true,
kick_ban = true, spectate = true, reports = true
},
-- MITTLERE STUFE: Admin
['admin'] = {
view_panel = true,
view_team = true,
view_logs = true,
mass_actions = true,
announce = true,
nuke = false, -- Admin darf keinen Nuke nutzen
eco = true,
inv = true,
set_job = true,
kick_ban = true,
spectate = true,
reports = true
},
-- UNTERSTE STUFE: Moderator / Supporter
['mod'] = {
view_panel = true,
view_team = false, -- Sieht den Team-Reiter nicht
view_logs = false, -- Darf andere Admins nicht überwachen
mass_actions = false,
announce = false,
nuke = false,
eco = false, -- Mod darf kein Geld manipulieren
inv = false, -- Mod darf keine Items manipulieren
set_job = false,
kick_ban = true,
spectate = true,
reports = true
},
['support'] = {
view_panel = true,
view_team = false,
view_logs = false,
mass_actions = false,
announce = false,
nuke = false,
eco = false,
inv = false,
set_job = false,
kick_ban = false, -- Darf nur verwarnen, nicht kicken
spectate = true,
reports = true
}
}
Events & Commands
Befehl
Wer
Wirkung
/activitysuite
Team
Panel öffnen. Name über Config.CommandName frei wählbar.
F10
Team
Panel per Tastendruck öffnen. Über Config.Keybind änderbar, Leerstring deaktiviert die Taste.
/report <Text>
Spieler
Report erstellen. Name über Config.ReportCommand frei wählbar.
STRG + K
Team
Command-Palette im Panel.
Discord-Logs
Drei getrennte Webhooks. Bleibt einer leer, landet nichts in diesem Kanal — sollen alle Meldungen in denselben Channel, trägst du dieselbe URL mehrfach ein.
Webhook
Inhalt
Config.WebhookURL
Bans, Kicks, Teleports, Nuke, Warns — und der Upload der Live-Screenshots.
Config.EcoWebhookURL
Geld geben und nehmen, Items spawnen und löschen, Account-Wipes.
Config.ReportWebhookURL
Neue Reports, Claims, Abschlüsse.
Hinweise / Troubleshooting
Symptom
Ursache und Lösung
Panel öffnet nicht
Die Gruppe fehlt in Config.Permissions oder view_panel steht auf false. Im ACE-Betrieb muss der Name hinter ancomox. exakt einem Schlüssel in Config.Permissions entsprechen.
Taste F10 reagiert nicht
Config.Keybind prüfen. Belegt eine andere Ressource dieselbe Taste, eine freie wählen oder den Leerstring setzen und nur den Befehl verwenden.
Reiter fehlen im Panel
Kein Fehler — das Interface blendet Bereiche ohne Recht vollständig aus, statt sie ausgegraut anzuzeigen.
Live-Screenshot funktioniert nicht
screenshot-basic muss installiert sein, und Config.WebhookURL darf nicht leer sein — der Upload läuft über diesen Webhook.
Keine Item-Labels
ox_inventory nicht erkannt. Ohne diese Ressource wird das Framework-Inventar genutzt.
Bans greifen nicht
Config.UseInternalBans prüfen. Der Ban-Check läuft beim Verbinden über panel_bans.
Kollision mit txAdmin
Keine. Das interne Ban-System arbeitet unabhängig; die txAdmin-Anbindung ist optional und ausdrücklich experimentell.
Populations-Chart bleibt leer
Die erste Messung erfolgt erst nach Config.PopulationInterval Minuten. Aussagekräftig wird der Verlauf nach einigen Stunden.
Ancomox Börse — dynamisches Börsen-, Kauf- und Verkaufssystem. Jedes Item hat einen eigenen Kurs, der sich alle fünf Minuten bewegt. Kein SQL, keine Pflicht-Abhängigkeiten. ESX · QBCore · Qbox · Standalone.
Überblick
ancomox_boerse ersetzt den üblichen Verkaufsautomaten durch einen echten Markt. Statt eines festen Betrags pro Item bewegt sich jeder Kurs aus vier Kräften, die zusammenspielen:
ein Gummiband zum Basispreis, damit nichts entgleist
ein eigener Zyklus je Item, mit eigener Phase und Geschwindigkeit
Rauschen, damit kein Verlauf vorhersehbar wird
der Verkaufsdruck der Spieler — wer 500 Stück auf einmal abstößt, drückt den Preis für die nächsten Einheiten
Das Ergebnis sind Kurse mit Trends, Einbrüchen und Erholungen. Wer den Markt liest, verdient mehr als wer blind ablädt.
Marktereignisse
Ereignis
Wirkung
Markt-Event
Zufällig wird ein Rohstoff um ±30 % nach oben oder unten geschleudert. Alle Spieler bekommen die Meldung mit Item-Icon.
Heißer Markt
Stündlich fragt ein Abnehmer einen zufälligen Rohstoff mit bis zu +50 % nach. Über dem Börsen-NPC steht, welcher gerade gefragt ist.
Live-Charts
Jede Zeile der Kursübersicht hat eine Sparkline; ein Klick öffnet den großen Chart mit vollem Verlauf, Hoch/Tief, Trendanzeige und Fortschreibung.
Handelspunkte
Jeder Handelspunkt ist ein Config-Block. Festgelegt wird dort, ob dort gekauft, verkauft oder beides wird, welche Items gehandelt werden, welche Jobs Zugriff haben und welcher Anteil jedes Trades in eine Fraktionskasse fließt.
Ein Schwarzmarkt nur für Mafia und Kartell ist damit eine Zeile. Fraktionskassen funktionieren mit esx_addonaccount, qb-management, qbx_management und Renewed-Banking.
Voraussetzungen
Keine Pflicht-Abhängigkeiten. Alles wird automatisch erkannt und ist in der Config überschreibbar.
Server starten. Die Konsole zeigt, was erkannt wurde:
[ancomox_boerse] Framework: esx | Inventar: ox | Target: ox | Notify: ox
[ancomox_boerse] Markt initialisiert: 0 wiederhergestellt, 45 neu erzeugt.
[ancomox_boerse] Bereit. 45 Items · Tick alle 5 Min · Bonus alle 60 Min
In der config.lua die eigenen Item-Namen und NPC-Positionen eintragen. Rechne mit etwa 10 Minuten.
Die Config wird beim Start geprüft. Fehlende Items, leere Shops und riskante Preis-Einstellungen werden namentlich in der Konsole gemeldet, bevor sie auf dem Live-Server auffallen.
Datenbank
Keine Datenbank, kein SQL-Import. Die Kurse überleben Neustarts über den KVP-Store von FiveM.
Änderst du später einen Basispreis, rechnet das Script den gespeicherten Kurs automatisch proportional um — der Markt springt also nicht zurück auf null.
Konfiguration
Eine einzige durchkommentierte config.lua — keine andere Datei muss angefasst werden. Mitgeliefert sind 45+ vorkonfigurierte Items und 4 fertige Handelspunkte als Startpunkt.
Bereich
Inhalt
Erkennung
Framework, Inventar, Interaktion, Notify, Banking — jeweils auto oder fest.
Marktmechanik
Tick-Intervall (Standard 5 Minuten), Kurshistorie, Ober- und Untergrenzen, Speicherintervall.
Ränge und Prozentsätze, Erkennung über ACE-Permission oder Framework-Gruppe.
Steuern & Spanne
Abgaben je Handelspunkt und die garantierte Mindest-Spanne.
Webhooks
Discord-Logging.
VIP-Ränge
Donatoren kaufen günstiger und verkaufen teurer. Ränge und Prozentsätze legst du selbst fest, die Erkennung läuft wahlweise über ACE-Permissions oder die Framework-Gruppe — ein Mehrwert für den eigenen Store, ohne Pay-to-Win.
Eigenes Inventar anbinden
Steht dein Inventar nicht auf der Liste, reichen fünf Funktionen in bridge/custom_server.lua. Fertige, kommentierte Beispiele liegen bei:
function ANC.Bridge.GetItemCount(src, item)
return exports['mein_inventar']:GetItemCount(src, item) or 0
end
Dasselbe gilt für Geld-Systeme, Fraktionskassen, VIP-Erkennung, Notifications und die Interaktion.
Die komplette Oberfläche: HTML, CSS und JavaScript
Geschützt sind die Bridge, die Marktlogik, die Handelsabwicklung und die Admin-Commands.
Wirtschaftssicherheit
Ein Script mit Kauf und Verkauf ist genau dann gefährlich, wenn sich die beiden Preise überkreuzen — dann kaufen Spieler und verkaufen sofort zurück und drucken Geld. Das ist hier ausgeschlossen:
Der Kaufpreis liegt immer über dem Verkaufspreis desselben Spielers. Auch bei aktivem Bonus, auch mit VIP-Rang, auch wenn Kauf und Verkauf auf zwei verschiedene Shops verteilt werden.
Eine garantierte Mindest-Spanne verhindert, dass sich VIP-Boni zu reibungslosem Hin- und Herhandeln addieren.
Rollback bei jedem Fehlschlag. Scheitert die Auszahlung, bekommt der Spieler seine Items zurück; scheitert die Item-Übergabe, sein Geld.
Alles wird am Server entschieden — Distanz, Job, Shop, Item, Menge und Preis. Der Client schickt nur, was er möchte.
Exports
Sieben Exports, um den Markt aus eigenen Scripts anzusprechen:
Damit kann ein Mining-Script den Kupferpreis fallen lassen, wenn eine ganze Fraktion gleichzeitig abbaut — oder ein Heist-Script den Diamantmarkt crashen lassen, sobald die Beute auf den Markt kommt.
Auf jeden abgeschlossenen Handel gibt es zusätzlich ein Event, an das sich eigene Statistiken oder Achievements hängen lassen.
Events & Commands
Berechtigung über ACE-Permission oder Framework-Gruppe.
Befehl
Wirkung
/boerse price <item> <preis>
Kurs setzen.
/boerse reset
Alle Kurse auf den Basiswert zurücksetzen.
/boerse event <item> <boom|crash>
Kurssprung auslösen.
/boerse bonus <item> [prozent]
Heißen Markt setzen.
/boerse list [suche]
Alle Kurse in der Konsole ausgeben.
/boerse tick
Einen Markt-Tick sofort auslösen.
/boerse save
Kurse sofort speichern.
/boerse debug
Debug-Modus umschalten.
Hinweise / Troubleshooting
Symptom
Ursache und Lösung
Konsole meldet fehlende Items beim Start
Genau dafür ist die Prüfung da: Die Item-Namen in config.lua existieren nicht in deinem Inventar. Namen angleichen.
Kurse stehen nach dem Neustart auf Basiswert
Der KVP-Store wurde geleert, oder es ist der erste Start. Danach bleiben die Kurse erhalten.
Kurse springen nach einer Preisänderung
Kein Fehler — bei geändertem Basispreis wird der gespeicherte Kurs proportional umgerechnet.
Falsches Inventar erkannt
Erkennung in der config.lua fest überschreiben. Für nicht gelistete Inventare fünf Funktionen in bridge/custom_server.lua ausfüllen.
Fraktionskasse bekommt nichts
Die Banking-Ressource wurde nicht erkannt. Unterstützt sind esx_addonaccount, qb-management, qbx_management und Renewed-Banking.
Spieler handeln Geld hin und her
Kann durch die garantierte Mindest-Spanne nicht auftreten. Tritt es doch auf, ist die Spanne in der Config zu niedrig gesetzt.
NPC oder Blip bleibt nach Restart stehen
Sollte nicht auftreten — NPCs, Blips und Target-Einträge werden beim Stoppen sauber entfernt.
Leistungsaufnahme: 0.00 ms im Leerlauf, keine Dauerschleifen mit Wait(0). Der Interaktions-Loop schläft, sobald kein NPC in Reichweite ist. Markt-Updates werden gebündelt verschickt, gespeichert wird nur bei echten Änderungen.
Ancomox Architect — Bauwerkzeug mit Live-3D-Vorschau, Blueprints, Undo/Redo, Job-Rechten und MySQL-Persistenz. Objekte werden lokal gestreamt statt genetzwerkt. Standalone · ESX · QBCore · Qbox.
Überblick
ancomox_architect ist ein Platzierungswerkzeug, das drei typische Probleme dieser Script-Gattung vermeidet: Objekte liegen nicht in einer JSON-Datei, die beim FTP-Upload verschwindet, sie werden nicht genetzwerkt (und stehen deshalb bei jedem Spieler in derselben Rotation), und es gibt keine Grenze bei 200 Objekten.
Das Event-Team stellt die Bühne selbst, die Polizei sperrt eine Straße in dreißig Sekunden ab, der Mechaniker richtet seine Werkstatt ein — jeder mit genau den Rechten, die er haben soll.
Live-3D-Vorschau
Neben dem Katalog steht ein Fenster, dessen Fläche vollständig durchsichtig ist — dahinter rendert das Spiel das tatsächliche Prop.
Kein hinterlegtes Bild nötig. Neue Props tauchen sofort mit korrekter Ansicht auf, ohne dass irgendwo eine Grafik nachgepflegt werden muss.
Drehen und zoomen wie in einem 3D-Programm. Wer nichts anfasst, sieht das Objekt langsam rotieren.
Stabil in jeder Drehung. Die Ausrichtung läuft über Quaternionen um die Kameraachse statt über Euler-Winkel um die Objektachse — das Prop taumelt nicht und liegt nie plötzlich auf dem Rücken.
Die Ausrichtung wird übernommen: Wie das Objekt in der Vorschau gedreht wurde, so beginnt die Platzierung.
Vorschaubilder auf Knopfdruck
/builder thumbs fährt den Katalog selbst ab: Jedes Prop wird vor einer Studio-Kamera fotografiert, zugeschnitten und gespeichert. Von jedem Prop entstehen zwei Aufnahmen aus derselben Position — eine mit und eine ohne das Objekt. Was auf beiden gleich ist, ist Hintergrund und wird transparent. Das funktioniert unabhängig von Farbe, Wolken oder Horizont, auch ein pechschwarzes Prop wird sauber freigestellt.
Die Bilder liegen als PNG mit Alphakanal in einer JSON-Datei im Resource-Ordner — kein externer Dienst, kein CDN. Clients halten sie lokal vor und laden erst nach, wenn sie neu erzeugt wurden.
Erkennt der Freisteller kein sinnvolles Ergebnis, behält er das Originalbild, statt eine leere Fläche abzulegen.
Bauen und Verwalten
Zwei Modi:Frei am Fadenkreuz oder ped-relativ, und Präzision mit Feinbewegung über die Pfeiltasten samt Achsenkreuz.
Drei Snap-Hilfen: Raster (frei von 0,05 bis 2 m), Wand-Snap richtet an der Hausfassade aus, Boden-Snap setzt das Objekt physikalisch korrekt auf den Untergrund.
Undo und Redo mit 30 Schritten pro Spieler — auch das Einfügen eines kompletten Blueprints ist ein einziger Schritt.
Klonen mit übernommener Rotation. Zwölf gleiche Absperrungen in einer Reihe sind zwölf Klicks, nicht zwölf Ausrichtungen.
X-Ray-Markierung: Beim Anfahren eines Listeneintrags zieht eine Linie durch die Welt zum Objekt — auch durch Wände.
Edit-in-Place: Beim Bearbeiten bleibt das Original serverseitig bestehen, bis du bestätigst. Crash oder Disconnect mittendrin gehen nicht verloren, die ID bleibt dieselbe.
Koordinaten kopieren: Ein Klick legt vec3(...) in die Zwischenablage, mit SHIFT als vec4(...) inklusive Drehwinkel.
Dauerhaft oder nur fürs Event: Ein Schalter entscheidet, ob ein Objekt in die Datenbank wandert oder beim nächsten Wipe verschwindet.
Blueprints
Ganze Bauwerke im Radius speichern — Marktplatz, Unfallstelle, Straßensperre, Bühne. Bis zu 300 Objekte pro Blueprint, Radius bis 150 Meter. Beim Einfügen dreht sich das Bauwerk mit der Blickrichtung mit, kein Objekt muss nachjustiert werden. Ein Blueprint mit 93 Objekten falsch platziert? Ein Tastendruck, alles weg.
Voraussetzungen
Punkt
Anforderung
Zwingend
FiveM-Server ab Build 5848 (fx_version 'cerulean', lua54) mit aktivem OneSync. Sonst nichts — kein ox_lib, kein Framework, keine Datenbank.
oxmysql
Empfohlen. Ohne läuft der JSON-Modus, dessen Daten ein FTP-Update überschreiben kann.
screenshot-basic
Nur für /builder thumbs. Liegt jedem FiveM-Server bereits bei.
ox_lib
Optional, nur für Benachrichtigungen. Sonst läuft das über das Framework oder GTA-Natives.
Framework
ESX (legacy und modern), QBCore und Qbox werden automatisch erkannt, per Config überschreibbar. Oder Standalone mit reinen ACE-Rechten.
Installation
Ordner nach resources/[local]/ancomox_architect legen.
In die server.cfg eintragen:
ensure ancomox_architect
Rechte vergeben:
add_ace group.admin ancomox_architect.admin allow
Ingame /builder eingeben — das war's.
Optional einmalig /builder thumbs laufen lassen, damit der Katalog echte Objektbilder statt Platzhalter zeigt.
Umstieg von einem anderen Placement-Script: Eine vorhandene objects.json wird beim ersten Start eingelesen, ins neue Format übersetzt und in die Datenbank übernommen — mit Backup der alten Datei. Ein Migrations-Handbuch liegt bei.
Datenbank
Objekte landen in MySQL und überleben jedes Resource-Update, jeden Re-Deploy und jeden FTP-Upload. Die Tabellen legt Architect beim ersten Start selbst an; sql/ancomox_architect.sql liegt für Datenbanken ohne CREATE-Recht bei.
Fehlt oxmysql, arbeitet Architect im JSON-Modus weiter und schreibt in die Konsole, was das bedeutet.
Streaming und Performance
Lokales Streaming: Der Server ist reine Datenquelle und erzeugt keine Entities. Jeder Client rendert selbst — mit exakt derselben Rotation für alle, ohne Ownership-Probleme und ohne den Netzwerk-Entity-Pool zu verbrauchen.
Raster-Streaming mit Zellen: Geladen wird nur, was in der Nähe ist, mit Hysterese gegen Flackern und einer Obergrenze neuer Objekte pro Zyklus gegen Ruckler.
Standardlimit 5.000 Objekte — eine Config-Zeile. Die Last hängt an der Sichtweite, nicht an der Gesamtzahl.
Routing-Bucket-Support: Objekte erscheinen nur in der Dimension, in der sie gebaut wurden — passend für Housing und Instanzen.
Rechte & Sicherheit
Kein Modell, keine Koordinate und keine Berechtigung wird dem Client geglaubt.
Rechte nach deinem System: ACE-Rechte, klassische ACE-Gruppen, ESX- und QBCore-Gruppen oder Jobs.
Job-Rechte bis ins Detail: pro Job erlaubte Kategorien, Mindestrang, eigenes Objektlimit und die Frage, ob dauerhaft gebaut werden darf. Beispiel: Polizei ab Rang 2 darf nur Absperrungen setzen, maximal 60 Stück, nie dauerhaft.
Der Server validiert alles: Modellname, Koordinaten, Rotation, Platzierungsdistanz, Kategorie-Rechte, globales und persönliches Objektlimit.
Rate-Limits gegen Event-Spam: Mindestabstand zwischen Aktionen und eine harte Obergrenze pro Minute und Spieler.
Gesperrte und Admin-Modelle: Modelle, die auf dem Server nichts zu suchen haben, sind gesperrt. Freie Modellnamen sind für Nicht-Admins abschaltbar.
Kein Datenleck über das Menü: Die Objektliste bekommt nur, wer sie öffnen darf — wer keine Rechte hat, bekommt keine Daten, nicht nur keinen Knopf.
Konfiguration
Die Kernlogik ist verschlüsselt, alles zum Anpassen bleibt offen:
Der komplette Katalog: 9 Kategorien, 122 Props, beliebig erweiterbar.
locales/
Alle Sprachdateien. Deutsch und Englisch vollständig, je 130 Texte; Französisch und Spanisch liegen als Bonus bei. Fehlt ein Schlüssel, greift automatisch Englisch statt eines leeren Feldes.
html/
Die gesamte Oberfläche inklusive Styles.
sql/, docs/, README
SQL-Datei, API-Dokumentation und Migrationshandbuch.
Eigene Props ergänzt du in config/categories.lua — neue Kategorie oder neuer Eintrag, eine Zeile pro Prop. Der Blickwinkel für die Vorschaubilder ist global einstellbar, mit Ausnahmen für einzelne Modelle, falls ein Prop anders herum modelliert ist.
Exports
Zwölf serverseitige und acht clientseitige Exports — Objekte anlegen, ändern, löschen, im Radius suchen, Blueprints einfügen, Rechte abfragen sowie Entity zu einer ID holen und umgekehrt.
Target-Anbindung: Fertige Beispiele für ox_target und qb-target liegen der API-Dokumentation bei. Gestreamte Objekte lassen sich sauber ansprechen, weil du zu jeder Entity die Objekt-ID bekommst — ein Target-Script ist aber keine Voraussetzung.
Events & Commands
Befehl
Wirkung
/builder
Bau-Menü öffnen.
/builder thumbs
Vorschaubilder für den kompletten Katalog erzeugen (einmalig).
Dazu Konsolenbefehle für Statistik, sofortiges Speichern und Bild-Verwaltung. Beim Start meldet Architect, welches Framework erkannt wurde, wo gespeichert wird und wie viele Objekte geladen sind.
Discord-Logs
Platzieren, Löschen, Bearbeiten, Wipe, Blueprints und abgelehnte Zugriffsversuche — jede Kategorie einzeln schaltbar.
Hinweise / Troubleshooting
Symptom
Ursache und Lösung
Objekte sind nach einem Update weg
Der JSON-Modus lief ohne Datenbank, und ein FTP-Upload hat die Datei überschrieben. oxmysql installieren — nur dort überleben Objekte ein Resource-Update.
Katalog zeigt nur Platzhalter
/builder thumbs einmalig laufen lassen. Dafür wird screenshot-basic benötigt.
Freisteller liefert unsaubere Bilder
Blickwinkel in der Config anpassen oder eine Ausnahme für das betroffene Modell setzen. Erkennt der Freisteller kein sinnvolles Ergebnis, behält er automatisch das Original.
Spieler sehen Objekte unterschiedlich
Kann bauartbedingt nicht auftreten: Jeder Client rendert dieselben Daten lokal, die Rotation ist deshalb überall identisch. Genau das geht bei genetzwerkten Objekten regelmäßig schief.
Ruckler beim Betreten eines Bereichs
Die Obergrenze neuer Objekte pro Streaming-Zyklus in der Config senken.
Objekte fehlen in einer Instanz
Objekte erscheinen nur in der Dimension, in der sie gebaut wurden (Routing-Bucket-Support).
Ein Job darf zu viel oder zu wenig
Job-Rechte prüfen: erlaubte Kategorien, Mindestrang, Objektlimit und die Erlaubnis für dauerhafte Objekte werden je Job einzeln gesetzt.
Alte objects.json wurde nicht übernommen
Die Migration läuft nur beim ersten Start mit erkannter Datei. Die Konsolenausgabe beim Start zeigt, was passiert ist; das Backup der Originaldatei bleibt erhalten.
Testabdeckung: Server-Logik, Datenbankpfad, Vorschau-Mathematik und Freisteller laufen gegen eine Suite aus 310 automatischen Prüfungen, die dem Paket beiliegt und selbst gestartet werden kann.
Ancomox HUD — ein HUD für alle Frameworks, bei dem jeder Spieler sein eigenes Layout bekommt: drei Themes, freies Drag & Drop, eigene Farben, Skalierung und eigene Tick-Raten. Ohne Abhängigkeiten. ESX · QBCore · QBox · Standalone.
Überblick
Der Kerngedanke: 200 Spieler müssen nicht mit demselben Layout leben. Jeder stellt sein HUD über /hud live im Spiel ein, alles wird pro Spieler gespeichert. Für den Serverbetreiber bleibt es bei Ordner rein, ensure, fertig — Framework, Tanksystem und Voice werden automatisch erkannt.
Drei Themes
Theme
Charakter
Apex Circles
Animierte Glass-Ringe.
Modern Bars
Balken mit Live-Werten.
Minimal
Ultraschlank, mit kompaktem Digital-Tacho.
Der Spieler wechselt das Theme selbst. Die Auswahl gilt automatisch auch für alle eigenen Status-Elemente, die du über die API registrierst — du musst also nichts pro Theme nachbauen.
Funktionsumfang
Vitals mit Smart-Fade und konfigurierbaren Warnschwellen
Geld-Animationen und Schwarzgeld, abschaltbar
Animierter RPM-Tacho in km/h oder mph, mit EV-Erkennung
Gurt mit realistischem Windschutzscheiben-Rauswurf, dazu eine Harness-API
Tempomat, Blinker, Warnblinker
Tank- und Motorwarnung, Flughöhe
Dynamische Minimap
Waffen-Widget mit Low-Ammo-Warnung
Linear-Kompass, Standort und Uhrzeit
Komplettes Notification-System mit ESX-/QB-Intercept und Redirect-Snippet
Progressbar
Voice: pma-voice und SaltyChat werden automatisch erkannt — mit Mute-Taste, Funk-Badge und Custom-Voice-API
Streamer-Modus über /streamermode und ein Kino-Modus
Deutsch und Englisch inklusive, auch im Einstellungsmenü
Voraussetzungen
Keine Abhängigkeiten. Das HUD läuft auf ESX, QBCore, QBox, einem eigenen Framework oder ganz ohne Framework. Die Erkennung passiert automatisch.
Bereich
Unterstützt
Framework
ESX Legacy (vollständig event-basiert) · QBCore · QBox (nativ, kein Workaround) · Standalone bzw. Custom über Events, Exports oder zwei Config-Getter
Tanksysteme
ox_fuel · LegacyFuel · ps-fuel · cdn-fuel · lj-fuel · okokGasStation · ti_fuel · lc_fuel · esx-sna-fuel — oder jede Ressource mit einem GetFuel(vehicle)-Export
Voice
pma-voice · SaltyChat — automatisch erkannt, dazu eine Custom-Voice-API
Speicherung
Einstellungen pro Spieler über den KVP-Store — keine Datenbank nötig
Sonstiges
OneSync-kompatibel
Bestehende Scripts müssen nicht angefasst werden. Legacy-Events wie hud:client:UpdateNeeds und hud:client:UpdateStress funktionieren weiter — vorhandene Consumable- und Stress-Scripts laufen unverändert.
Installation
Ordner nach resources/ kopieren.
In die server.cfg eintragen:
ensure ancomox_hud
Server starten. Framework, Tanksystem und Voice werden beim Start selbst erkannt.
Ingame /hud eingeben — das Einstellungsmenü öffnet sich, alles Weitere stellt jeder Spieler selbst ein.
Konfiguration
Trotz Escrow-Schutz bleibt alles offen, was zur Integration gebraucht wird:
Datei
Inhalt
config.lua
Sämtliche Servereinstellungen und Vorgaben.
Beide Sprachdateien
Deutsch und Englisch, jeder Text änderbar.
Notification- und API-Schicht
Vollständig offen.
Custom-Framework-Adapter
Anbindung eines eigenen Frameworks über zwei Config-Getter.
Ein eigenes Framework lässt sich damit vollständig integrieren, ohne verschlüsselten Code anzufassen.
Spielerseitige Einstellungen
Über /hud stellt jeder Spieler selbst ein: Theme, Position aller Elemente per Drag & Drop, Farben, Skalierung und die eigene Tick-Rate zwischen 16 und 1000 ms. Wer auf schwacher Hardware spielt, dreht die Update-Frequenz herunter, ohne dass der Serverbetreiber es für alle festlegen muss. Alles wird automatisch pro Spieler gespeichert.
Exports & Developer-API
Eigene Status-Anzeigen — Drogen-Level, Strahlung, Energie und Ähnliches — lassen sich in drei Zeilen registrieren. Die Theme-Anpassung passiert automatisch: Das neue Element erscheint in Apex Circles, Modern Bars und Minimal, ohne dass du es dreimal baust.
Dazu kommt eine vollständige Export-Suite auf Client und Server. Dokumentiert sind unter anderem:
Bereich
Zweck
Notify
Benachrichtigung über das HUD-eigene System ausgeben.
Progress
Fortschrittsleiste anzeigen.
SetPlayerInfo
Spielerdaten wie Job und Geld setzen — der Weg für Custom-Frameworks.
ForceHide
HUD vorübergehend ausblenden, etwa während einer Cutscene.
Seatbelt / Harness
Gurt- und Harness-Zustand setzen und abfragen.
VoiceState
Eigenes Voice-System anbinden.
Die genauen Signaturen aller Exports stehen in der mitgelieferten README. Sie ist vollständig dokumentiert und liegt unverschlüsselt bei.
Beide Events sind absichtlich beibehalten, damit bestehende Consumable- und Stress-Scripts ohne Anpassung weiterlaufen.
Performance
Event-getrieben statt Polling — Geld und Job werden über Events aktualisiert, nicht in einer Dauerschleife abgefragt.
Diff-basierte Updates — gesendet wird nur, was sich tatsächlich geändert hat.
Tick-Rate pro Spieler zwischen 16 und 1000 ms, vom Spieler selbst einstellbar.
Hinweise / Troubleshooting
Symptom
Ursache und Lösung
Tankanzeige bleibt leer
Das Tanksystem wurde nicht erkannt. Neun Systeme sind eingebaut; jede andere Ressource funktioniert, sobald sie einen GetFuel(vehicle)-Export anbietet.
Kein Voice-Badge
Erkannt werden pma-voice und SaltyChat. Ein anderes System bindest du über die Custom-Voice-API an.
Hunger und Durst bewegen sich nicht
Das Consumable-Script muss hud:client:UpdateNeeds auslösen. Bei ESX Legacy und QBCore passiert das in der Regel bereits.
Geld oder Job werden nicht angezeigt
Bei einem Custom-Framework müssen die beiden Config-Getter gefüllt oder SetPlayerInfo aufgerufen werden.
Doppelte Benachrichtigungen
Das HUD fängt ESX- und QB-Notifications ab. Läuft parallel ein weiteres Notify-Script, den Intercept in der config.lua abschalten oder das Redirect-Snippet verwenden.
Einstellungen sind nach dem Neustart weg
Die Einstellungen liegen im KVP-Store des Clients. Ein geleerter FiveM-Cache setzt sie zurück.
Element sitzt an einer unpassenden Stelle
Position, Skalierung und Farbe stellt jeder Spieler selbst über /hud ein — es gibt keine serverseitige Zwangsposition.
GPS + Job + Admin Blips — Blip-Verwaltung für ESX-Server: Kollegen desselben Jobs sehen sich gegenseitig auf der Karte, Admins sehen alle. Fahrzeugtyp, Sirenenstatus und Entfernung steuern Darstellung und Transparenz.
Überblick
Das Script verwaltet die Kartenblips aller Spieler nach Job-Zugehörigkeit. Wer im selben Job ist, sieht seine Kollegen in Echtzeit; Admins sehen unabhängig davon jeden. Aktiviert und deaktiviert wird automatisch anhand des Jobstatus und der Config.
Funktionsumfang
Bereich
Verhalten
Job-Tracking
Blips werden anhand von Jobstatus und Config-Einstellung automatisch an- und abgeschaltet. Die Positionen aktualisieren sich in Echtzeit.
Sichtbarkeit für Kollegen
Alle Spieler im selben Job sehen einander.
Admin-Sichtbarkeit
Admins sehen sämtliche Blips — auch ohne selbst einen Admin-Job zu haben. Die Erkennung läuft wahlweise über einen Admin-Job oder eine Admin-Benutzergruppe.
Fahrzeugunterstützung
Unterschiedliche Blip-Sprites und Farben je Fahrzeugtyp. Die Darstellung richtet sich zusätzlich nach dem Fahrzeugstatus und danach, ob die Sirene läuft.
Transparenz
Dynamisch nach Entfernung, über die Config einstellbar.
Spieler-Events
Blips werden bei Tod und Fahrzeugwechsel automatisch mitgeführt.
Manuelles Umschalten
Das GPS lässt sich per Befehl ein- und ausschalten.
Voraussetzungen
Abhängigkeit
Pflicht
Hinweis
es_extended
Ja
Das Script ist speziell für ESX-basierte Server gebaut. QBCore und Qbox werden nicht unterstützt.
Zur Leistungsaufnahme: Der Wert im Leerlauf steigt mit der Spielerzahl, weil für jeden sichtbaren Spieler ein Blip geführt und dessen Position aktualisiert wird. Auf einem vollen Server ist das spürbar mehr als bei drei Spielern — das ist bauartbedingt und betrifft jedes Blip-Script dieser Art.
Installation
Ordner nach resources/ kopieren.
Mit ensure in die server.cfg eintragen — naches_extended.
In der config.lua die Jobs eintragen, für die Blips geführt werden sollen, und festlegen, wie Admins erkannt werden (Job oder Benutzergruppe).
Server neu starten.
Konfiguration
Die gesamte Einrichtung passiert in der config.lua:
Bereich
Einstellbar
Jobs
Welche Jobs Blips bekommen und ob sie automatisch aktiviert werden.
Admin-Erkennung
Admin-Job oder Admin-Benutzergruppe. Beides ist möglich; Admins sehen alle Blips auch ohne passenden Job.
Fahrzeug-Blips
Sprite und Farbe je Fahrzeugtyp, dazu abweichende Darstellung bei aktiver Sirene.
Transparenz
Wie stark Blips mit zunehmender Entfernung ausblenden.
Events & Commands
Das GPS lässt sich manuell per Befehl umschalten. Den genauen Befehlsnamen legst du in der config.lua fest — dort steht auch die Standardbelegung.
Hinweise / Troubleshooting
Symptom
Ursache und Lösung
Keine Blips sichtbar
Der Job ist nicht in der config.lua eingetragen, oder das automatische Aktivieren ist für diesen Job abgeschaltet.
Admin sieht nicht alles
Prüfen, ob die Admin-Erkennung auf Job oder auf Benutzergruppe eingestellt ist und ob der Account zur gewählten Variante passt.
Blips verschwinden auf Distanz
Kein Fehler — die Transparenz nimmt mit der Entfernung ab. Der Verlauf ist in der Config einstellbar.
Falsches Symbol am Fahrzeug
Sprite und Farbe werden je Fahrzeugtyp gesetzt. Für ein neues Fahrzeugmodell den passenden Typ in der Config ergänzen.
Blip bleibt nach dem Tod stehen
Sollte nicht auftreten — Tod und Fahrzeugwechsel werden mitgeführt. Tritt es doch auf, läuft eine ältere Version.
Höhere Last bei vielen Spielern
Bauartbedingt: Je mehr sichtbare Spieler, desto mehr Blips werden geführt und aktualisiert. Über die Job-Auswahl lässt sich die Menge begrenzen.
Läuft nicht auf QBCore
Das Script setzt ESX voraus und bindet sich direkt an es_extended.
ancomox_banking stellt Filialen, Geldautomaten, Spar- und Firmenkonten, Kredite sowie übertragbare Bankkarten bereit. Das Girokonto spiegelt das Framework-Bankguthaben — es entsteht kein zweiter Geldbestand. Spar-, Firmen- und Kartenkonten führt das Script selbst.
Modul
Funktion
Girokonto
Spiegelt das Framework-Guthaben. Überweisung per IBAN, auch an offline Spieler.
Sparkonto
Eigenes Konto mit automatischer Verzinsung in einstellbaren Intervallen, wahlweise einfach oder mit Zinseszins, optional mit Höchstbetrag.
Kredite
Vermögensbasierte Bonitätsprüfung, wählbare Laufzeiten, automatischer Raten-Einzug in Echtzeit-Intervallen, Verzugsgebühren und Ausfall-Logik.
Firmen- & Gang-Konten
Drei Rollen (Inhaber, Verwalter, Mitglied) und vier einzeln schaltbare Rechte: einzahlen, abheben, überweisen, verwalten.
Bankkarten
Inventar-Item mit Metadaten, an genau ein Konto gebunden.
Kontakte
Adressbuch (bis 30 Einträge), zuletzt genutzt, Spieler in der Nähe, eigene IBAN teilen.
Bilanz
Wochenverlauf über 7, 14 oder 30 Tage, je Unternehmen und je Kategorie.
Überfall
ATM und Tresor, drei Modi.
Jedes Modul lässt sich einzeln abschalten und verschwindet dann vollständig aus der Oberfläche.
Neun Filialen sind vorkonfiguriert, davon eine große mit Tresor. Weitere werden in der Config angelegt: Koordinate, Name, Blip und Ped.
Bankkarten
Eine Karte ist ein Inventar-Item mit Metadaten, kein Datenbankeintrag:
Beim Bestellen wählt der Spieler das Konto (Giro, Spar oder Firma). Die Karte öffnet ausschließlich dieses Konto.
Wer Karte und PIN hat, kann am Automaten ein- und auszahlen — auch wenn der Kontoinhaber offline ist.
Die PIN wird mit einem Server-Secret gehasht, kein Klartext in der Datenbank. Fehlversuche werden gezählt, danach sperrt sich die Karte selbst.
Der Besitz wird bei jeder Transaktion neu geprüft — Weitergeben oder Diebstahl wirkt sofort.
Beim Kündigen ist die Karte sofort tot, laufende Automaten-Sitzungen werden beendet, der Kartenplatz wird frei. Das Item bleibt beim Halter.
Der Automat zieht tote Karten ein: gekündigte Karten, Karten auf gesperrten Konten und nicht mehr existierende Karten werden behalten und das Item vernichtet.
Überfall
Modus
Ablauf
Thermit (Standard)
Ladung wird an der Vorderseite des Automaten befestigt — die Seite wird aus der Bounding Box des Props ermittelt, funktioniert also unabhängig von der Drehung. Zündschnur brennt, Explosion, Feuer bleibt am Boden, Beute anschließend abholen.
ox_lib Skill-Check
Minispiel statt Sprengung.
Fortschrittsbalken
Reiner Timer.
Einstellbar sind Cooldowns, Polizei-Mindestanzahl, Alarm-Blips, Werkzeug-Verbrauch (beim Platzieren oder erst bei Erfolg) und ein Zeitfenster fürs Einsammeln.
Die Explosion nutzt den Parameter für kosmetische Detonationen — sichtbar und hörbar, aber ungefährlich. Auf Wunsch scharf schaltbar. Fehlt ein DLC-Prop auf deinem Build, läuft der Überfall mit Effekten weiter, statt abzubrechen.
Voraussetzungen
Abhängigkeit
Pflicht
Hinweis
FiveM-Server
Ja
Build 6683 oder neuer (fx_version 'cerulean', lua54).
oxmysql
Ja
MySQL 5.7+ oder MariaDB 10.2+.
ox_lib
Ja
Nicht optional — wird für Callbacks, Fortschrittsbalken, Kontextmenüs und Benachrichtigungen genutzt.
Framework
Nein
ox_core, es_extended, qb-core oder qbx_core — in dieser Erkennungsreihenfolge, per Config überschreibbar. Alternativ der mitgelieferte Standalone-Modus.
ox_inventory
Empfohlen
Ohne Item-Metadaten funktionieren Bankkarten nur beim eigenen Besitzer. Das Script meldet das beim Start in der Konsole.
ox_target / qb-target
Optional
Ohne beides schaltet das Script auf einen integrierten DrawText-Modus mit Tastendruck um.
OneSync
Optional
Nur für den Tab „In der Nähe" nötig, weil dort Positionen serverseitig gemessen werden.
Installation
Ordner nach resources/ legen und in die server.cfg eintragen:
ensure ancomox_banking
install.sqleinmalig importieren — sieben Tabellen. Alle späteren Änderungen migrieren sich selbst.
In der server.cfg ein eigenes Geheimnis für die Karten-PINs setzen. Das Script warnt beim Start, bis das erledigt ist.
Bei ox_inventory: das Item bank_card mit stack = false eintragen. Der fertige Ausschnitt liegt in der install.sql und im README.
Datenbank
Sieben Tabellen, angelegt über install.sql. Anders als bei den übrigen Ancomox-Ressourcen ist dieser Import Pflicht — nur die späteren Schema-Änderungen laufen automatisch als Migration beim Start.
Deutsch und Englisch, je 325 Texte. Fehlt ein Schlüssel, greift automatisch Englisch.
install.sql
Das Datenbankschema
README, CHANGELOG, LICENSE, docs/
Sechs Handbücher: Installation, Kompatibilitätsmatrix, Standalone-Betrieb, Überfall-Modi, Bilanz-Tab, Kontaktsystem
Verschlüsselt ist ausschließlich die Kernlogik.
Eigenes Framework anbinden
Die komplette Framework-Anbindung liegt in sechs lesbaren Bridge-Dateien mit dokumentierter Schnittstelle. Der Standalone-Modus bringt eine eigene Wirtschaft mit Bargeld, Bank und Job mit — inklusive atomarer Buchungen und Exports zur Anbindung eines eigenen Systems. Er greift auch automatisch als Fallback, wenn das Framework nicht startet.
Sicherheit
Positionsgeprüfte Sitzungen: Eine UI-Sitzung entsteht erst, wenn der Server bestätigt, dass der Spieler an der gemeldeten Filiale beziehungsweise genau an diesem Automaten steht. Jeder Geld-Callback verlangt eine gültige Sitzung.
Atomare Kontobuchungen: Abbuchungen laufen als bedingtes SQL-Update (WHERE balance >= ?). Zwei parallele Abhebungen können das Konto nicht ins Minus ziehen.
Reserviertes Tageslimit: Das Überweisungslimit wird vor der Buchung reserviert, damit zwei gleichzeitige Überweisungen nicht dasselbe Restkontingent verbrauchen.
Rate-Limits pro Aktionstyp — getrennt nach Einzahlen, Abheben, Überweisen und Kartenaktionen.
Karten-PINs gehasht mit dem Server-Secret aus der server.cfg, plus Fehlversuchs-Sperre auf der Karte und Brute-Force-Sperre pro Spieler.
Verdächtige Anfragen werden mit Name und Grund in der Konsole protokolliert, optional zusätzlich an Discord.
ancomox_crafting bindet Rezepte an Stationen statt an eine globale Liste. Jede Werkbank führt genau die Kategorien oder Rezepte, die ihr zugewiesen sind. Aufträge liegen in der Datenbank und laufen weiter, während der Spieler offline ist.
Ab Werk enthalten: 32 Rezepte in 9 Kategorien, 8 vorkonfigurierte Stationen (öffentliche Werkbank, gang-gesperrte Waffenbank, Chemielabor, Medizinlabor, Mechaniker-Werkbank, Elektronikwerkstatt, mobile Werkbank, Lagerfeuer) und 7 Baupläne.
Stationen
Betriebsart
Verhalten
active
Davorstehen und arbeiten.
queue
Auftrag abgeben und später abholen.
both
Beides, der Spieler entscheidet.
Zugriff wird nach Beruf und Gang mit Mindestrang geregelt — pro Station und pro Rezept. Ein leeres Feld bedeutet: jeder darf. Optional lässt sich ein Gegenstand verlangen, den der Spieler dabeihaben muss.
Drei Ausbaustufen je Station, jeweils mit Geld- und Materialkosten. Sie heben Tempo, Qualitätschance und die Zahl paralleler Warteschlangen-Plätze und schalten Rezepte frei, die eine ausgebaute Station voraussetzen.
Die Progression lässt sich pro Station und pro Kategorie abschalten — dort gibt es dann weder XP-Anforderungen noch XP-Gewinn.
Platzierbare Werkbänke
Als Item aus dem Inventar im Spiel ausrichten und abstellen. Übersteht Neustarts, hat eine eigene Kiste und eine eigene Ausbaustufe. Fünf Zugriffsmodi: nur der Besitzer, eine Freigabeliste, der eigene Beruf, der eigene Gang oder offen für alle.
Einstellbar sind Mindestabstand, Höchstzahl pro Charakter sowie Sperren im Fahrzeug und im Wasser. Beim Einpacken kommt das Item zurück ins Inventar.
Fertigkeiten & Qualität
Fertigkeiten pro Kategorie: 50 Stufen, 7 Ränge. Die XP-Kurve liegt offen; der Config-Prüfer meldet beim Start, wenn sie nicht mehr monoton steigt.
Fünf Qualitätsstufen von Grob bis Meisterwerk, ausgewürfelt aus Fertigkeit, Ausbaustufe der Station und Minispiel-Ergebnis. Die Stufe landet als Metadaten am Gegenstand: Rang, Punktzahl, Haltbarkeitsbonus, Name des Herstellers, Zeitstempel und ein Label-Zusatz.
Drei Fortschritts-Boni mit je eigener Startstufe und Deckel: Materialersparnis, Bonusausbeute und kürzere Herstellungszeit — alle als Zahlen in der Config.
Baupläne in drei Varianten: einmal lesen und dauerhaft freischalten, begrenzte Anzahl Nutzungen, oder schlicht dabeihaben müssen.
Zerlegen: Jedes Rezept läuft rückwärts. Die Rückgabequote hängt an der Fertigkeit — 35 % beim Neuling bis 80 % beim Meister.
Werkzeuge mit Verschleiß: Eine Zutat lässt sich als Werkzeug markieren — nötig, aber nicht verbraucht, dafür mit Abnutzung pro Herstellung.
Nebenprodukte mit eigener Chance je Rezept.
Vier Minispiel-Profile: drei fertige über ox_lib (ruhig, präzise, hektisch) plus ein dokumentierter Einhängepunkt für ein Fremd-Minispiel. Das Ergebnis beeinflusst Erfolgschance und Qualität, nie, ob überhaupt ein Gegenstand entsteht.
Warteschlange & Materialquellen
Zutaten kommen wahlweise aus dem Inventar des Spielers oder aus der Kiste der Werkbank. Welche Quelle zuerst durchsucht wird, ist einstellbar.
Aufträge liegen in der Datenbank, laufen offline weiter und überstehen Serverneustarts. Die Zahl paralleler Aufträge wächst mit der Ausbaustufe.
Überlauf-Kette bei vollem Inventar: Kiste der Station → persistentes Abholfach → Abruf über /craftclaim. Gelöscht wird nichts.
Kisten wahlweise gemeinsam für die ganze Station oder als eigenes Fach pro Charakter. Slots und Gewicht werden pro Station gesetzt.
qbx_core, qb-core, es_extended, ox_core, ND_Core oder Standalone.
Inventar
Ja
ox_inventory (empfohlen, vollständig integriert) · qb-inventory, ps-inventory, lj-inventory · qs-inventory, codem-inventory, origen_inventory, tgiann-inventory, core_inventory · ESX-Standardinventar · jedes andere über die Bridge.
Third-Eye
Optional
ox_target, sleepless_interact, qb-target oder interact. Ohne eines davon greift ein eingebauter Hinweis mit Tastendruck.
Erkennungsreihenfolge:qbx_core meldet sich gegenüber anderen Ressourcen als qb-core. QBox wird deshalb zuerst geprüft.
Inventar-Fähigkeiten: Fehlt die Kisten-Unterstützung, greift das Script still auf den Rucksack zurück. Fehlt die Metadaten-Unterstützung, lassen sich die Qualitätsstufen mit einem Schalter deaktivieren.
Installation
Ordner ancomox_crafting nach resources/ kopieren.
In der server.cfgnachox_lib, oxmysql und dem Framework eintragen:
ensure ancomox_crafting
Die neuen Items ins Inventar eintragen — fertige Copy-Paste-Blöcke für jedes unterstützte System stehen in docs/installation.md.
Server starten. Die acht Datenbanktabellen legt das Script beim ersten Start selbst an; die SQL-Datei liegt nur für Datenbankbenutzer ohne CREATE-Recht bei.
Ingame /craftbuilder öffnen und die erste Werkbank setzen.
Der Ordner darf umbenannt werden — die Oberfläche fragt ihren eigenen Ressourcennamen ab.
Datenbank
Acht Tabellen, beim ersten Start automatisch angelegt. Die beiliegende SQL-Datei wird nur gebraucht, wenn dem Datenbankbenutzer die Rechte zum Anlegen fehlen.
Fertigkeiten und Rezepte liegen im Arbeitsspeicher; geschrieben wird nur bei echten Änderungen.
Baukasten
Stationen, Rezepte, Zugriffsrechte und Werkbank-Positionen werden über /craftbuilder im laufenden Betrieb angelegt — ohne Neustart und ohne Config-Datei.
Stationen live platzieren: Ein durchscheinendes Geister-Prop erscheint vor dem Spieler. Linke Maustaste setzt, rechte bricht ab, das Mausrad dreht in 8-Grad-Schritten, die Pfeiltasten justieren die Höhe. Koordinaten und Ausrichtung landen ausgefüllt im Formular.
Item-Browser an jedem Item-Feld: das komplette Item-Verzeichnis als Raster mit Bild, Anzeigename und internem Namen, Suche filtert beim Tippen.
Die Config wird überlagert, nie überschrieben. Ein Baukasten-Eintrag mit derselben ID legt sich über den Config-Eintrag; wird er gelöscht, gilt wieder das Original. Datei-Anpassungen bleiben auch nach einem Update erhalten.
Übertragbar: Alles Gebaute wird zusätzlich als data/custom.json geschrieben. Datei kopieren, /ancoimport ausführen.
Rechte und Eingaben serverseitig: Zugang über ACE-Berechtigung, feste Identifier-Liste oder die Framework-Admins. Jedes Feld wird beim Speichern serverseitig geprüft und begrenzt.
6 Framework-, 8 Inventar- und 4 Target-Adapter mit identischer Schnittstelle
Komplette Oberfläche
HTML, CSS und JavaScript
Balancing-Mathematik
Qualitätsstufen und Boni
Vier Sprachdateien
Deutsch, Englisch, Französisch, Spanisch. Englisch ist immer der Rückfall.
SQL-Datei und Dokumentation
Über 4.500 Zeilen in neun Kapiteln
Ein eigenes Inventar anzubinden sind rund 60 Zeilen: zählen, hinzufügen, entfernen, Traglast prüfen. Fähigkeitsschalter am Dateianfang sagen dem Script, was das Inventar kann — fehlt eine Fähigkeit, schaltet sich genau diese Funktion ab, statt Fehler zu werfen.
Config-Prüfer
Beim Start werden unbekannte Kategorien, doppelte Rezept-IDs, nicht existierende Items, von keiner Station erreichbare Rezepte und eine nicht monoton steigende XP-Kurve gemeldet — jeweils mit Datei und Zeile.
Exports
24 Exports stehen bereit, unter anderem für: Fertigkeit abfragen, XP vergeben, ein Doppel-XP-Wochenende schalten, einen Bauplan als Beute verteilen, Rezepte und Stationen zur Laufzeit anlegen, vorab prüfen ob ein Spieler etwas bauen darf, sowie eine Herstellung aus einem anderen Script heraus starten.
Die vollständige Liste mit Signaturen steht im Exports-Kapitel der mitgelieferten Dokumentation.
Events & Commands
Insgesamt 13 Befehle. Die wichtigsten:
Befehl
Wirkung
/craftbuilder
Baukasten öffnen — Stationen und Rezepte im Spiel anlegen.
/craftclaim
Ergebnisse aus dem Abholfach holen.
/craftclose
Notausgang, falls die Oberfläche hängt.
/ancoreload
Config neu laden, nachdem an den Dateien gearbeitet wurde.
/ancoimport
data/custom.json von einem anderen Server einlesen.
Dazu Befehle zum XP-Vergeben, Baupläne verschenken, Statistik ausgeben, Werkbänke auflisten und Stationszonen sichtbar machen.
Ein Wächter gibt den NUI-Fokus automatisch zurück, falls die Oberfläche stehenbleibt.
Sicherheit
Material wird beim Start verbraucht, nie am Ende. Damit existiert das Zeitfenster nicht, aus dem die bekannten Crafting-Dupes entstehen.
Vollständiger Rollback: Schlägt das Abziehen mitten in einer Zutatenliste fehl, wird alles bereits Entnommene zurückgelegt und der Auftrag abgelehnt.
Speedhack-Sperre: Der Server merkt sich den Startzeitpunkt und lehnt zu frühe Fertigmeldungen ab — mit voller Rückerstattung und Eintrag im Sicherheitslog.
Distanzprüfung doppelt — beim Start und beim Abschluss, mit einstellbarer Toleranz. Bei Stationen mit mehreren Standorten wird gegen den nächstgelegenen gemessen.
Rate-Limit: Mindestabstand zwischen zwei Anfragen plus rollendes Minutenfenster.
Anti-Makro: optional erzwungenes Minispiel alle N Herstellungen, auch bei Rezepten ohne reguläres Minispiel.
Rechte werden zweimal geprüft — beim Öffnen der Oberfläche und bei jedem einzelnen Auftrag. Wer die Uniform mitten im Craft auszieht, produziert nicht weiter.
Dem Paket liegen 87 automatisierte Tests bei, die die echte Konfiguration und den Servercode mit nachgebildeten FiveM-Funktionen laden — darunter Anti-Dupe-Rollback, Speedhack-Sperre, Mehrfachnutzung eines Auftrags-Tokens, Bauplan-, Job- und Gang-Sperren, Stash-Sourcing und die Qualitätsmathematik.
Discord-Logs
Fünf Kanäle: Herstellung, Warteschlange, Verwertung, Baukasten und Auffälligkeiten. Gebündelt versendet, damit Discord nicht drosselt, wahlweise zusätzlich in die Datenbank.
Ein eigener Statistik-Tab wertet tagesgenau nach Rezept und Kategorie aus und zeigt meistgebaute Gegenstände sowie laufende Aufträge.
Hinweise / Troubleshooting
Symptom
Ursache und Lösung
Rezept taucht nirgends auf
Es ist keiner Station zugewiesen. Der Config-Prüfer meldet das beim Start mit Datei und Zeile.
Item wird nicht gefunden
Der interne Name stimmt nicht mit dem Inventar überein. Im Baukasten den Item-Browser statt manueller Eingabe verwenden.
Aufträge ziehen nicht aus der Kiste
Das Inventar unterstützt keinen Kistenzugriff. Das Script fällt still auf den Rucksack zurück.
Keine Qualitätsstufen am Gegenstand
Das Inventar unterstützt keine Metadaten. Die Stufen lassen sich per Schalter deaktivieren.
QBox wird als QBCore erkannt
Sollte nicht auftreten — qbx_core wird zuerst geprüft. Andernfalls das Framework in der Config erzwingen.
Ergebnis scheinbar verloren
Bei vollem Inventar wandert es in die Stationskiste, dann ins Abholfach. Abruf über /craftclaim.
Config-Änderung wirkt nicht
Ein Baukasten-Eintrag mit derselben ID überlagert die Config. Eintrag im Baukasten löschen, dann gilt wieder das Original.
Cursor bleibt sichtbar
/craftclose ausführen. Der eingebaute Wächter sollte den Fokus ohnehin zurückgeben.
Auftrag wird als ungültig abgelehnt
Die Speedhack-Sperre hat angeschlagen. Das Material wird vollständig erstattet, der Vorgang steht im Sicherheitslog.