Der Callback openBleeter oeffnete Bleeters eigenes Fenster ueber dem PC. Das nahm dem PC den Fokus - SetNuiFocus gilt global fuer den Client, zwei Resources sperren sich dabei gegenseitig die Maus aus. Seit Bleeter als eigene App im PC laeuft (client/bleeter.lua), rief ihn niemand mehr auf.
210 lines
7.2 KiB
Markdown
210 lines
7.2 KiB
Markdown
# pc-live — IC-Computer
|
||
|
||
Ein Computer im Spiel: Schreibtisch, Fenster, Apps. Man tritt an ein
|
||
Terminal, drückt **E**, und bekommt eine Oberfläche mit Mail, Browser,
|
||
Adressbuch, Kalender und weiteren Anwendungen.
|
||
|
||
Andere Resources hängen sich als App ein — so laufen hier das IC-Webhosting
|
||
(`ic-web`) und Bleeter.
|
||
|
||
---
|
||
|
||
## Installation
|
||
|
||
### 1. Ordner
|
||
|
||
```
|
||
resources/[haleoe]/pc-live/
|
||
```
|
||
|
||
### 2. Datenbank
|
||
|
||
Reihenfolge einhalten, die Migrationen setzen auf dem Grundschema auf:
|
||
|
||
```bash
|
||
mysql -u BENUTZER -p DATENBANK < sql/pc_live.sql
|
||
mysql -u BENUTZER -p DATENBANK < sql/pc_live_devices.sql
|
||
mysql -u BENUTZER -p DATENBANK < sql/migration_postfach_ordner.sql
|
||
mysql -u BENUTZER -p DATENBANK < sql/migration_kalender.sql
|
||
```
|
||
|
||
| Datei | legt an |
|
||
|---|---|
|
||
| `pc_live.sql` | Benutzer, Apps, Mail, Ordner, Kalender, Kontakte |
|
||
| `pc_live_devices.sql` | **feste PC-Standorte** – fehlte im ursprünglichen Schema, ohne sie ist kein fester PC ansprechbar |
|
||
| `migration_postfach_ordner.sql` | Ordner je Postfach, Zustellungskennung |
|
||
| `migration_kalender.sql` | private, geteilte und öffentliche Kalender |
|
||
|
||
Alle wiederholt ausführbar.
|
||
|
||
### 3. server.cfg
|
||
|
||
```
|
||
ensure oxmysql
|
||
ensure es_extended
|
||
ensure pc-live
|
||
```
|
||
|
||
### 4. Einen PC in die Welt stellen
|
||
|
||
Ein fester PC braucht **zwei Einträge mit derselben Kennung** — das ist die
|
||
häufigste Stolperfalle:
|
||
|
||
**a) Datenbank** – Standort, Beschriftung, Jobsperre:
|
||
|
||
```sql
|
||
INSERT INTO pc_live_devices (id, label, x, y, z, heading, type, job, active)
|
||
VALUES ('mission_row_1', 'LSPD Terminal',
|
||
441.615, -979.645, 30.425, 195.0, 'public', NULL, 1);
|
||
```
|
||
|
||
**b) `config.lua`** – Kamerafahrt und Einfrieren beim Öffnen:
|
||
|
||
```lua
|
||
{
|
||
id = "mission_row_1", -- muss zur Datenbank passen
|
||
label = "LSPD Terminal",
|
||
coords = vector3(441.615, -979.645, 30.425),
|
||
heading = 195.0,
|
||
type = "public", -- oder: type = "job", job = "police"
|
||
}
|
||
```
|
||
|
||
Fehlt der Eintrag in `config.lua`, lässt sich der PC benutzen — aber ohne
|
||
Kamera und ohne dass die Spielfigur einfriert.
|
||
|
||
Zum `heading`: **nicht** die Ausrichtung des Props, sondern die Seite, von der
|
||
aus man auf den Bildschirm schaut. Am einfachsten: davorstellen, in die
|
||
gewünschte Richtung schauen, eigene Position und Blickrichtung ablesen — die
|
||
Blickrichtung plus 180° ist der Wert.
|
||
|
||
### 5. Apps anderer Resources einhängen
|
||
|
||
Eine App besteht aus vier Teilen. Beispiel `ic-web`:
|
||
|
||
| Teil | Ort |
|
||
|---|---|
|
||
| Brücke NUI → Server | `client/…lua`, eingetragen in `fxmanifest.lua` |
|
||
| Oberfläche | `nui/js/apps/….js`, eingetragen in `fxmanifest.lua` **und** `nui/index.html` |
|
||
| Schreibtischsymbol | `APP_META` in `nui/js/desktop.js` |
|
||
| Registrierung | `AppRegistry.Register` in `server/apps.lua` |
|
||
|
||
Antworten des Servers laufen über den Nachrichtenverteiler in `desktop.js`
|
||
(`window.addEventListener('message', …)`). Jede App bekommt dort ihren eigenen
|
||
`case`.
|
||
|
||
Resources können sich auch von außen eintragen:
|
||
|
||
```lua
|
||
exports['pc-live']:RegisterApp({ app_id = 'meine.app', name = 'Meine App', … })
|
||
```
|
||
|
||
Die Oberfläche muss trotzdem in `nui/` liegen — das NUI lädt nur Dateien der
|
||
eigenen Resource.
|
||
|
||
**Eigene App bauen: [PLUGINS.md](PLUGINS.md)** — vollständiges Beispiel von der
|
||
Tabelle bis zum Schreibtischsymbol, dazu die Fallen, die sonst Zeit kosten.
|
||
|
||
---
|
||
|
||
## Was drin ist
|
||
|
||
| App | |
|
||
|---|---|
|
||
| **Browser** | interne Seiten unter `ic://…`, externe über iframe |
|
||
| **Mail** | mehrere Postfächer, Ordner je Postfach, Signaturen, Kalender |
|
||
| **Adressbuch** | Kontakte, verknüpft mit Mail |
|
||
| **Webhosting** | Domänen und Webseiten (`ic-web`) |
|
||
| **Bleeter** | soziales Netz: Feed, Werbung, Markt, Kalender, Gewerbe, Profil |
|
||
| **Bleeter-Verwaltung** | Unternehmensprofile und Freigaben |
|
||
| **Software Store** | Apps nachinstallieren |
|
||
|
||
---
|
||
|
||
## Mail: was hier anders ist
|
||
|
||
**Postfächer hängen an einer Anmeldung, nicht an der Person.** Über *Postfächer
|
||
→ + Postfach hinzufügen* schaltet man ein Postfach mit Adresse und Passwort
|
||
frei (geprüft von `ic-web`). Mehrere Personen können dasselbe Postfach
|
||
gleichzeitig offen haben — ein Firmenpostfach gehört der Firma.
|
||
|
||
**Ordner gehören zum Postfach.** Legt jemand im Firmenpostfach einen Ordner an,
|
||
sehen ihn alle, die es bedienen. Sortiert jemand eine Mail ein, liegt sie für
|
||
alle im selben Ordner.
|
||
|
||
Das ist nicht selbstverständlich, denn eine Mail an ein geteiltes Postfach wird
|
||
**je Empfänger einmal** gespeichert. Damit das Einsortieren trotzdem für alle
|
||
gilt, tragen alle Kopien einer Zustellung dieselbe `delivery_id`
|
||
(`pc_live_mail.delivery_id`) — wird eine verschoben, wandern die anderen mit.
|
||
|
||
Gelesen und gelöscht bleibt dagegen persönlich. Das ist keine Eigenschaft der
|
||
Nachricht, sondern der Person.
|
||
|
||
**Signaturen** gehören ebenfalls zum Postfach (`ic_mail_accounts.signature`).
|
||
Wer es bedient, schreibt mit derselben Fußzeile.
|
||
|
||
---
|
||
|
||
## Kalender
|
||
|
||
| Sichtbarkeit | gehört | sieht | bearbeitet |
|
||
|---|---|---|---|
|
||
| privat | der Person | nur sie | nur sie |
|
||
| geteilt | einem Postfach | wer es bedient | wer es bedient |
|
||
| öffentlich | einem Postfach | jeder auf dem Server | wer es bedient |
|
||
|
||
Ein öffentlicher Termin hängt bewusst auch an einem Postfach — sonst gäbe es
|
||
niemanden, der ihn später ändern oder absagen könnte.
|
||
|
||
Änderungen erreichen alle Beteiligten sofort, sonst hätte jeder eine andere
|
||
Vorstellung vom Dienstplan, bis er den PC neu öffnet.
|
||
|
||
---
|
||
|
||
## Sicherheit
|
||
|
||
**Welches Postfach gemeint ist, schickt der Client mit.** Der Server prüft das
|
||
bei jeder Ordner- und Mailaktion über `ic-mail:CanAccessAddress` und fällt ohne
|
||
Zugriff auf das persönliche Postfach zurück, statt fremde Ordner herauszugeben.
|
||
Jede Ordneraktion hängt zusätzlich an einer Besitzprüfung, nicht an der
|
||
mitgeschickten Id allein.
|
||
|
||
**Keine eingebauten Browserdialoge.** `prompt()`, `confirm()` und `alert()`
|
||
haben in FiveMs CEF keinen Handler: der Aufruf öffnet nichts und lässt das NUI
|
||
stehen. Stattdessen `ICWebRender.promptText` und `ICWebRender.confirmBox` aus
|
||
`nui/js/apps/webhosting.js`.
|
||
|
||
**Spielerinhalte werden über `textContent` gesetzt, nie über `innerHTML`.**
|
||
Das NUI ist derselbe Kontext wie der PC — wer dort Markup einschleusen kann,
|
||
kann auch dessen Callbacks aufrufen.
|
||
|
||
---
|
||
|
||
## Voraussetzungen
|
||
|
||
| | |
|
||
|---|---|
|
||
| `oxmysql` | Datenbankzugriff |
|
||
| `es_extended` | Spieler, Jobs, Benachrichtigungen |
|
||
| `ic-mail` | optional – ohne sie gibt es keine Mailadressen |
|
||
| `ic-web` | optional – liefert Webhosting-App und Postfachanmeldung |
|
||
|
||
---
|
||
|
||
## Bekannte Fallstricke
|
||
|
||
**Der Fensterrahmen hat keine `id`.** `WindowManager.create` setzt
|
||
`data-wid`. Wer sein Fenster mit `document.getElementById(WIN_ID)` sucht,
|
||
findet nichts und schreibt ins Leere — das Fenster bleibt leer. Richtig ist
|
||
das von `create()` zurückgegebene Element oder
|
||
`document.querySelector('[data-wid="…"]')`.
|
||
|
||
**Ja/Nein-Spalten aus der Datenbank.** `TINYINT(1)` kommt je nach Treiberweg
|
||
als `1` oder als `true` an — `oxmysql` wandelt es bei `query`/`single` in einen
|
||
Boolean um, bei `prepare` nicht. Ein Vergleich mit `== 1` geht deshalb
|
||
irgendwann schief, und zwar still. Siehe `ICWeb.Bool` in `ic-web`.
|
||
|
||
**Keine Datenbankarbeit beim Herunterfahren.** Ein `await` in `onResourceStop`
|
||
wartet auf eine Antwort, die niemand mehr entgegennimmt — der Server meldet
|
||
„Execution of function reference in script host failed". Aufräumen gehört in
|
||
den Start.
|