Otros recursos pueden añadir pantallas al mundo, abrirlas desde sus propias interacciones y añadir sus propias apps a Cuxial OS. La forma recomendada es Bridge.Screens de Cuxial Bridge: espera a que arranque Cuxial Screens y vuelve a registrarlo todo si se reinicia. Lo que no aparece en esta página es interno.
Bridge.Screens en el servidor
Incluye el bridge en tu recurso y declara la dependencia:
shared_scripts {
'@ox_lib/init.lua',
'@cuxial_bridge/init.lua',
}
dependencies { 'cuxial_bridge', 'cuxial_screens' }| Función | Devuelve | Qué hace |
|---|---|---|
registerScreen(def) | ok, err | Añade una pantalla. Mismos campos que data/screens.lua (ver Configuración). Devuelve true, 'pending' hasta que arranque Cuxial Screens. Registrar otra vez el mismo id la sustituye. |
removeScreen(id) | boolean | Quita una pantalla registrada por tu recurso. |
registerApp(def) | ok, err | Añade una app a Cuxial OS. Devuelve true, 'pending' si Cuxial Screens aún no ha arrancado: se registra cuando lo haga. |
unregisterApp(id) | boolean | Quita tu app. |
onCall(appId, method, fn) | — | Atiende una llamada de la página de tu app. |
push(src, appId, event, data) | boolean | Envía datos a tu app, si ese jugador la tiene abierta. |
notify(src, appId, title, body?) | boolean | Muestra una notificación del sistema con el icono de tu app. Título de hasta 64 caracteres, cuerpo de hasta 240. |
getSession(src) | table | nil | { screen, cid, unlocked, apps } de la sesión de pantalla del jugador. |
closeFor(src) | — | Cierra la pantalla que está usando el jugador. |
Las pantallas y apps que registra un recurso se borran cuando ese recurso se para.
Añadir una pantalla
Bridge.Screens.registerScreen({
id = 'office_pc',
label = 'Ordenador de la oficina',
model = 'cuxial_screens_test',
coords = vec3(-75.2, -818.4, 243.4),
heading = 90.0,
prop = true,
access = { jobs = { realestate = 2 }, boss = true },
tags = { 'office' },
})Añadir una app
| Campo | Tipo | Qué hace |
|---|---|---|
id | string | Id único: letras, números, _ y -, hasta 64 caracteres. |
label | string | Nombre de la app, ya traducido. |
icon | string | Ruta a un svg, png o webp de tu recurso, o el id de un icono del sistema (files, notes…). |
page | string | Página de tu recurso que se abre en la ventana, como 'web/dist/index.html'. |
size / minSize | table | { w, h } de la ventana a escala 1, de 320 × 200 a 1920 × 1080. |
access | table | { jobs = { [trabajo] = gradoMínimo }, gangs = { [banda] = gradoMínimo }, boss = true }. Sin él, todos. Basta un trabajo o una banda. Con boss = true además tiene que ser jefe. |
screens | string[] | Ids de pantalla donde aparece. |
tags | string[] | Etiquetas de pantalla donde aparece. Sin screens ni tags, en todas las pantallas. |
pinned | boolean | También anclada en la barra de tareas. |
desktop | boolean | También con icono en el escritorio. |
mirror | boolean | false muestra una tarjeta Contenido privado a quien mira el espejo en lugar de la app. Por defecto true. |
Bridge.Screens.registerApp({
id = 'office_sales',
label = locale('app_label'),
icon = 'web/dist/img/icon.svg',
page = 'web/dist/index.html',
size = { w = 900, h = 580 },
minSize = { w = 360, h = 320 },
access = { jobs = { realestate = 0 } },
tags = { 'office' },
desktop = true,
})
Bridge.Screens.onCall('office_sales', 'summary', function(src, payload, session)
-- session = { screen = id de la pantalla, cid = id del personaje, app = 'office_sales' }
local job = Bridge.GetJob(src)
if not job or job.name ~= 'realestate' then return nil, 'error_access' end
return { total = 12 }
end)El handler devuelve los datos para la página, o nil, 'clave_error', 'mensaje opcional'. Si lanza un error, la página recibe error_app_failed; un método sin handler devuelve error_method. El handler puede esperar consultas a la base de datos.
Cuxial Screens solo llama a tu handler con una sesión válida: personaje correcto, a distancia, app permitida en esa pantalla, límite de llamadas y tamaños. Tus propias reglas (trabajo, grado, dinero) se comprueban igualmente en el handler. No te fíes nunca de payload.
La lista de apps de una sesión se actualiza cuando el jugador cambia de trabajo o de banda, y las ventanas que ya no le corresponden se cierran.
Bridge.Screens en el cliente
| Función | Devuelve | Qué hace |
|---|---|---|
open(screenId) | boolean | Abre una pantalla sin la opción de interacción, por ejemplo cuando el jugador se sienta en un escritorio. Funciona con pantallas que tienen interact = false. |
close() | — | Cierra la pantalla en uso. |
isUsing() | boolean | Si el jugador está usando una pantalla. |
current() | string | nil | Id de la pantalla en uso. |
if Bridge.Screens.open('office_pc') then
-- el jugador está en la pantalla
endExports de Cuxial Screens
Las mismas funciones están disponibles como exports, para recursos que no usan el bridge.
| Lado | Export | Devuelve | Qué hace |
|---|---|---|---|
| Servidor | RegisterScreen(def) | ok, err | Añade una pantalla. |
| Servidor | RemoveScreen(id) | boolean | Quita una pantalla registrada por el recurso que llama. Las de data/screens.lua y /screensadmin no se pueden quitar desde fuera. |
| Servidor | GetSession(src) | string | nil | Id de la pantalla que usa el jugador. |
| Servidor | CloseFor(src) | — | Cierra la pantalla del jugador. |
| Cliente | Use(id) | boolean | Abre una pantalla. |
| Cliente | Close() | — | Cierra la pantalla en uso. |
| Cliente | IsUsing() | boolean | Si el jugador está usando una pantalla. |
| Cliente | Current() | string | nil | Id de la pantalla en uso. |
local id = exports.cuxial_screens:GetSession(source)Páginas de las apps: el kit
Una app es una página web de tu propio recurso que Cuxial OS abre en una ventana. Habla con su servidor solo a través de la sesión de pantalla, con el kit incluido en kit/ de Cuxial Screens.
Copia el kit
Copia kit/src de Cuxial Screens en tu proyecto web como src/lib/screens-app/, y añade @rrweb/record 2.1.7 a las dependencias de su package.json. El espejo lo usa para mostrar tu app a quien mira.
Úsalo en la página
import './lib/screens-app/app.css'
import { screens } from './lib/screens-app'
const info = await screens.ready() // { app, theme, user { name, initials, job }, screen { id, hostname } }
const res = await screens.call<{ total: number }>('summary', { day: 0 })
if (res.ok) total = res.data.total
else error = res.message ?? res.error
screens.on<{ total: number }>('total', d => (total = d.total))
screens.onTheme(t => (theme = t))Declara los archivos
Añade la página compilada a files de tu fxmanifest.lua, por ejemplo web/dist/index.html, web/dist/js/*.js, web/dist/css/*.css y web/dist/img/*.*.
| Kit | Qué hace |
|---|---|
screens.ready() | Espera la conexión con el sistema y devuelve la app, el tema, el usuario y la pantalla. |
screens.call(method, payload) | Llama a onCall en tu servidor. Devuelve { ok: true, data } o { ok: false, error, message? }. |
screens.on(event, fn) | Recibe los push de tu servidor. Devuelve una función para dejar de escuchar. |
screens.onTheme(fn) | Se llama al momento y en cada cambio de tema, acento o escala. |
screens.notify(title, body?) | Notificación del sistema. |
screens.setTitle(title) | Cambia el título de la ventana. null vuelve al nombre de la app. |
screens.wantEscape(on) | Con true, Esc va a tu app (para cerrar un modal) en vez de salir de la pantalla. |
screens.close() | Cierra la ventana. |
isDoubleUp(key, event) | Detecta el doble clic. Úsalo en onpointerup: las pantallas no lanzan dblclick. |
rem(theme, n) | Pasa rem a píxeles, para dibujar en canvas. |
app.css | Tokens del tema, maquetación base y las clases del sistema (os-card, os-btn, os-btn-accent, os-input, os-scroll…). |
Mide todo en rem y adapta con consultas @container app (…): las ventanas se redimensionan y las pantallas tienen resoluciones distintas.
En el espejo, data-private oculta un elemento, data-mask cambia su texto por asteriscos y los campos de contraseña siempre salen enmascarados. El título de la ventana siempre lo ven los espectadores.
No uses callbacks NUI de tu propio recurso desde la página de la app: se saltarían la sesión de pantalla. Toda petición va por screens.call.
Usar tus propios modelos
Un modelo sirve como pantalla cuando su pantalla es una malla con su propia textura incrustada, con UV completa de 0 a 1 y shader emisivo, y el modelo tiene su ytyp cargado. Añádelo a data/models.lua (ver Configuración) con su diccionario de texturas, el nombre de la textura y las cuatro esquinas de la pantalla en espacio local.
Eventos
Cuxial Screens no tiene eventos públicos. Usa las funciones de arriba.
