211 lines
7.2 KiB
Markdown
211 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** | 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.
|