Der Killdot
Bei einem Kill blitzen in FiveM vier kleine Punkte um dein Fadenkreuz
auf. Sie sind gleich weit von der Mitte entfernt und liegen sich
paarweise gegenüber. Diese Figur ist eindeutig - sie entsteht im
normalen Spielgeschehen praktisch nie zufällig.
Andere Auto-Cutter raten über Lautstärke, Bewegung im Bild oder
Treffermarkierungen. Alles drei geht schief, sobald jemand danebenhält,
eine Granate hochgeht oder die Musik laut wird. Der Killdot ist ein
Signal des Spiels selbst: er ist da oder er ist nicht da.
Schritt 1 — nur die Bildmitte
Durchsucht wird nicht das ganze Bild, sondern ein Quadrat von etwa
68 × 68 Pixeln um die Mitte. Das ist der einzige Ort, an dem der
Killdot je auftaucht. Der Rest des Bildes wird nicht einmal angeschaut -
deshalb kostet ein Frame fast nichts, egal ob 1080p oder 4K.
| Größe | Wert bei 1080p | Wofür |
| half | 34 px | halbe Kantenlänge des Suchfensters |
| min_area / max_area | 6 – 260 px² | wie groß ein Punkt sein darf |
| r_min / r_max | 3 – 30 px | Abstand des Punkts zur Mitte |
Alle Werte skalieren mit der Bildhöhe. Bei 1440p oder 4K wird
derselbe Faktor angewendet — du musst nichts umstellen.
Schritt 2 — Farbe statt Helligkeit
Der Ausschnitt wird von RGB nach HSV umgerechnet. In HSV steht der
Farbton getrennt von Sättigung und Helligkeit — deshalb bleibt "rot"
dort auch rot, wenn die Szene dunkel ist oder das Spiel gerade eine
Explosion zeigt. In RGB wäre derselbe Punkt bei Nacht ein völlig
anderer Zahlenwert.
Die beiden Masken
// Rot liegt in HSV am Rand des Farbkreises -
// deshalb zwei Bereiche statt einem.
if ((h < 12 || h > 168) && s > 90 && v > 70) red[i] = 255;
// Weiße Marker: hell, aber ohne Farbe.
if (v > 200 && s < 60) white[i] = 255;
Danach läuft ein morphologisches Öffnen mit einem 2 × 2-Kernel
darüber: erst erodieren, dann dilatieren. Einzelne verrauschte Pixel
verschwinden dabei, echte Punkte bleiben stehen.
Schritt 3 — die Ringprüfung
Aus der Maske werden zusammenhängende Flächen gebildet. Flächen mit
passender Größe und passendem Abstand zur Mitte gelten als Kandidaten.
Dann kommen zwei Bedingungen, die zusammen die eigentliche Erkennung
ausmachen:
-
Gemeinsamer Ring
Alle Punkte müssen ungefähr gleich weit von der Mitte entfernt
sein — 40 % Abweichung sind erlaubt. Ein einzelner roter Fleck
irgendwo im Fenster fällt damit raus.
-
Paarweise gegenüber
Zwei Punkte gelten als Paar, wenn sich ihre Vektoren zur Mitte
aufheben: liegt einer bei (0, −8), muss der andere bei (0, +8)
liegen. Es braucht mindestens zwei solcher Paare. Genau das
unterscheidet einen Killdot von vier zufälligen roten Pixeln.
Schritt 4 — aus Treffern werden Clips
Abgetastet wird mit 10 Bildern pro Sekunde. Das reicht, weil der
Killdot über mehrere Frames sichtbar bleibt, und spart gegenüber
jedem einzelnen Frame das Neunfache an Rechenzeit.
2×
so oft muss der Killdot gesehen werden, bevor er zählt
1
Aussetzer wird verziehen — ein Frame Rauch beendet keinen Kill
2,5 s
Mindestabstand, damit eine Animation nicht drei Clips ergibt
Schritt 5 — schneiden
Geschnitten wird mit ffmpeg, das hier als WebAssembly direkt im
Browser läuft. Der Sprung an die Startzeit passiert vor dem Einlesen
(-ss vor -i), damit ffmpeg nicht das halbe
Video durchrechnen muss, um an Minute 12 zu kommen.
Im Standardfall wird dabei nichts neu berechnet.
-c copy übernimmt die Bilddaten unverändert aus dem
Original in die neue Datei. Der Clip ist damit bitgenau dasselbe Bild
wie deine Aufnahme, und der ganze Vorgang dauert Millisekunden statt
Minuten.
Warum das so wichtig ist: ffmpeg als WebAssembly
ist rund zehnmal langsamer als ein installiertes ffmpeg. Gemessen an
demselben Clip: 1481 ms mit Neuberechnung, 5 ms
ohne. Neu berechnet wird deshalb nur, wenn es einen echten Grund
gibt — einen exakten Schnittpunkt oder das 10-MB-Limit von Discord.
Der Preis des Kopierens: ein Video lässt sich nur an Keyframes
aufteilen. Der Anfang rutscht deshalb auf das Keyframe davor, der Clip
wird etwas länger. Gemessen an einer Aufnahme mit einem Keyframe pro
Sekunde: Schnitt bei 6,5 s ergab 2,5 s statt 2,0 s — er begann eine
halbe Sekunde früher, das Ende stimmte.
Schritt 6 — mehrere Decoder gleichzeitig
Der Flaschenhals ist nicht das Rechnen. Gemessen an einem
24-Sekunden-Video gingen 75 % der Zeit allein dafür
drauf, das Bild aus dem Video in den Arbeitsspeicher zu holen — und
nur 2,5 % für die eigentliche Killdot-Erkennung.
Zwei Dinge greifen deshalb ineinander. Erstens wird der Ausschnitt
schon beim Übertragen zugeschnitten, und zwar asynchron statt
blockierend. Zweitens wird das Video in bis zu vier Abschnitte
zerlegt, die gleichzeitig durchsucht werden.
| 24-s-Video | Zeit | Faktor Echtzeit |
| vorher, ein Abschnitt | 2083 ms | 11,5× |
| vorher, vier Abschnitte | 1759 ms | 13,6× |
| jetzt, ein Abschnitt | 1474 ms | 16,3× |
| jetzt, vier Abschnitte | 1017 ms | 23,6× |
Interessant daran: Die Aufteilung allein brachte fast nichts (1,18×).
Erst als das Übertragen den Hauptthread nicht mehr blockierte, konnten
sich die Abschnitte überhaupt überlappen.
Die Abschnitte überlappen sich um 2,5 Sekunden, damit ein Kill genau
auf einer Grenze nicht in beiden Hälften nur halb gesehen und dadurch
verworfen wird. Doppelfunde räumt dieselbe Mindestabstands-Regel auf,
die auch sonst greift.
Was hier bewusst fehlt
Motion Blur. Die Desktop-Version kann es, hier
fehlt es absichtlich. Echtes Motion Blur mittelt mehrere
Originalbilder — dafür muss das Video vollständig dekodiert
werden, statt nur an den Schnittstellen. Im Browser ist das
unbrauchbar langsam, und die schnelle Variante erzeugt
Doppelbilder statt Blur.
Regler für die Erkennung. Die Werte sind an
echtem FiveM-Material vermessen. Ein Regler daran wäre nur eine
Einladung, es kaputtzustellen.
Hochskalieren. 1080p auf 4K zu strecken erfindet
keine Details, sondern nur größere Dateien. Was hier passiert:
beim Schneiden gehen keine Details verloren.