448 lines
18 KiB
Lua
448 lines
18 KiB
Lua
|
|
-- ─────────────────────────────────────────────────────────────────────────────
|
|||
|
|
-- App Registry – manages registered apps, installation & export
|
|||
|
|
-- ─────────────────────────────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
AppRegistry = {}
|
|||
|
|
|
|||
|
|
local _registry = {} -- app_id -> manifest
|
|||
|
|
|
|||
|
|
--- Register an app with the system.
|
|||
|
|
---@param manifest table
|
|||
|
|
function AppRegistry.Register(manifest)
|
|||
|
|
if not manifest or not manifest.app_id then
|
|||
|
|
Utils.Warn("AppRegistry.Register: invalid manifest (missing app_id)")
|
|||
|
|
return false
|
|||
|
|
end
|
|||
|
|
if _registry[manifest.app_id] then
|
|||
|
|
Utils.Warn(("AppRegistry: app '%s' already registered, overwriting"):format(manifest.app_id))
|
|||
|
|
end
|
|||
|
|
_registry[manifest.app_id] = manifest
|
|||
|
|
Utils.Log(("Registered app: %s v%s"):format(manifest.app_id, manifest.version or "?"))
|
|||
|
|
return true
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
--- Get the full registry sorted (default/system first, then alphabetically).
|
|||
|
|
---@return table[]
|
|||
|
|
function AppRegistry.GetAll()
|
|||
|
|
local list = {}
|
|||
|
|
for _, m in pairs(_registry) do
|
|||
|
|
list[#list + 1] = m
|
|||
|
|
end
|
|||
|
|
table.sort(list, function(a, b)
|
|||
|
|
if (a.default or false) ~= (b.default or false) then
|
|||
|
|
return (a.default and true or false)
|
|||
|
|
end
|
|||
|
|
return (a.name or "") < (b.name or "")
|
|||
|
|
end)
|
|||
|
|
return list
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
--- Get a single app manifest by id.
|
|||
|
|
---@param appId string
|
|||
|
|
---@return table?
|
|||
|
|
function AppRegistry.Get(appId)
|
|||
|
|
return _registry[appId]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
--- Check if an app is registered.
|
|||
|
|
---@param appId string
|
|||
|
|
---@return boolean
|
|||
|
|
function AppRegistry.Exists(appId)
|
|||
|
|
return _registry[appId] ~= nil
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
--- Combine registry with per-user install data (for store listing).
|
|||
|
|
---@param installs table[] rows from pc_live_installs
|
|||
|
|
---@return table[]
|
|||
|
|
function AppRegistry.BuildStoreList(installs)
|
|||
|
|
local installedMap = {}
|
|||
|
|
for _, row in ipairs(installs) do
|
|||
|
|
installedMap[row.app_id] = row.version
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
local list = AppRegistry.GetAll()
|
|||
|
|
for _, app in ipairs(list) do
|
|||
|
|
app.installed = installedMap[app.app_id] ~= nil
|
|||
|
|
app.installed_version = installedMap[app.app_id]
|
|||
|
|
app.update_available = app.installed and (app.installed_version ~= app.version)
|
|||
|
|
end
|
|||
|
|
return list
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
--- Build list of currently installed apps for the desktop.
|
|||
|
|
---@param installs table[]
|
|||
|
|
---@return table[]
|
|||
|
|
function AppRegistry.BuildInstalledList(installs)
|
|||
|
|
local list = {}
|
|||
|
|
for _, row in ipairs(installs) do
|
|||
|
|
local manifest = _registry[row.app_id]
|
|||
|
|
if manifest then
|
|||
|
|
local entry = {}
|
|||
|
|
for k, v in pairs(manifest) do entry[k] = v end
|
|||
|
|
entry.installed_version = row.version
|
|||
|
|
list[#list + 1] = entry
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
return list
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
-- ── Export for external resources ──────────────────────────────────────────
|
|||
|
|
exports('RegisterApp', function(manifest)
|
|||
|
|
return AppRegistry.Register(manifest)
|
|||
|
|
end)
|
|||
|
|
|
|||
|
|
-- ── Register Built-In Apps ─────────────────────────────────────────────────
|
|||
|
|
-- NOTE: icon field uses the emoji directly so NUI can display it without a
|
|||
|
|
-- separate lookup table. Add dependencies = {} on every app.
|
|||
|
|
-- ──────────────────────────────────────────────────────────────────────────
|
|||
|
|
CreateThread(function()
|
|||
|
|
Wait(0) -- Let other resources load first
|
|||
|
|
|
|||
|
|
-- ┌─────────────────────────────────────────────┐
|
|||
|
|
-- │ SYSTEM (pre-installed, cannot remove) │
|
|||
|
|
-- └─────────────────────────────────────────────┘
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.browser",
|
|||
|
|
name = "Browser",
|
|||
|
|
icon = "🌐",
|
|||
|
|
version = "1.0.0",
|
|||
|
|
category = "system",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = true,
|
|||
|
|
description = "Browse internal IC websites.",
|
|||
|
|
price = 0,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.mail",
|
|||
|
|
name = "Mail",
|
|||
|
|
icon = "✉",
|
|||
|
|
version = "2.0.0",
|
|||
|
|
category = "system",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = true,
|
|||
|
|
description = "E-Mail, Ordner, Kalender – alles in einer App.",
|
|||
|
|
price = 0,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.addressbook",
|
|||
|
|
name = "Adressbuch",
|
|||
|
|
icon = "👤",
|
|||
|
|
version = "1.0.0",
|
|||
|
|
category = "system",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = true,
|
|||
|
|
description = "Kontakte verwalten – Name, E-Mail, Telefon. Direkt mit Mail verknüpft.",
|
|||
|
|
price = 0,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.store",
|
|||
|
|
name = "Software Store",
|
|||
|
|
icon = "🛒",
|
|||
|
|
version = "1.0.0",
|
|||
|
|
category = "system",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = true,
|
|||
|
|
description = "Browse and install software.",
|
|||
|
|
price = 0,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
-- Webhosting (ic-web). Vorinstalliert, weil die Anmeldung ohnehin
|
|||
|
|
-- entscheidet, wer hier etwas tun kann – ohne Zugang sieht man nur die
|
|||
|
|
-- Anmeldemaske.
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.webhosting",
|
|||
|
|
name = "Webhosting",
|
|||
|
|
icon = "🌍",
|
|||
|
|
version = "1.0.0",
|
|||
|
|
category = "system",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = true,
|
|||
|
|
description = "IC-Domänen und Webseiten verwalten. Anmeldung erforderlich.",
|
|||
|
|
price = 0,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
-- Bleeter selbst, eingebettet als Fenster im PC.
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.bleeter",
|
|||
|
|
name = "Bleeter",
|
|||
|
|
icon = "🐦",
|
|||
|
|
version = "1.0.0",
|
|||
|
|
category = "system",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = true,
|
|||
|
|
description = "Bleeter – Feed, Werbung, Gewerbe und Profil.",
|
|||
|
|
price = 0,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
-- Bleeter-Verwaltung. Ohne Anmeldung sieht man nur die Anmeldemaske,
|
|||
|
|
-- deshalb vorinstalliert wie das Webhosting.
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.bleeteradmin",
|
|||
|
|
name = "Bleeter-Verwaltung",
|
|||
|
|
icon = "🐦",
|
|||
|
|
version = "1.0.0",
|
|||
|
|
category = "system",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = true,
|
|||
|
|
description = "Unternehmensprofile auf Bleeter einrichten und Mitarbeiter freigeben.",
|
|||
|
|
price = 0,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
-- ┌─────────────────────────────────────────────┐
|
|||
|
|
-- │ UTILITY │
|
|||
|
|
-- └─────────────────────────────────────────────┘
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.terminal",
|
|||
|
|
name = "Terminal",
|
|||
|
|
icon = "⌨",
|
|||
|
|
version = "1.3.0",
|
|||
|
|
category = "utility",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = false,
|
|||
|
|
description = "Advanced command-line interface for power users.",
|
|||
|
|
price = 0,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.notes",
|
|||
|
|
name = "Notepad Pro",
|
|||
|
|
icon = "📝",
|
|||
|
|
version = "1.0.0",
|
|||
|
|
category = "utility",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = false,
|
|||
|
|
description = "Text editor with rich formatting and local storage.",
|
|||
|
|
price = 299,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.calculator",
|
|||
|
|
name = "Calculator",
|
|||
|
|
icon = "🔢",
|
|||
|
|
version = "1.0.0",
|
|||
|
|
category = "utility",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = false,
|
|||
|
|
description = "Scientific calculator with unit conversion.",
|
|||
|
|
price = 0,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
-- ┌─────────────────────────────────────────────┐
|
|||
|
|
-- │ COMMUNICATION │
|
|||
|
|
-- └─────────────────────────────────────────────┘
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.chat",
|
|||
|
|
name = "IC Chat",
|
|||
|
|
icon = "💬",
|
|||
|
|
version = "2.0.0",
|
|||
|
|
category = "communication",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = false,
|
|||
|
|
description = "In-character instant messaging platform.",
|
|||
|
|
price = 0,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.voip",
|
|||
|
|
name = "VoIP Client",
|
|||
|
|
icon = "📞",
|
|||
|
|
version = "1.1.0",
|
|||
|
|
category = "communication",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = false,
|
|||
|
|
description = "Encrypted voice-over-IP calls via IC network.",
|
|||
|
|
price = 499,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
-- ┌─────────────────────────────────────────────┐
|
|||
|
|
-- │ SECURITY │
|
|||
|
|
-- └─────────────────────────────────────────────┘
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.vpn",
|
|||
|
|
name = "SecureVPN",
|
|||
|
|
icon = "🔒",
|
|||
|
|
version = "2.0.0",
|
|||
|
|
category = "security",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = false,
|
|||
|
|
description = "Encrypt your connection and mask your IP on IC networks.",
|
|||
|
|
price = 1499,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.firewall",
|
|||
|
|
name = "Firewall Pro",
|
|||
|
|
icon = "🛡",
|
|||
|
|
version = "1.1.0",
|
|||
|
|
category = "security",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = false,
|
|||
|
|
description = "Block unauthorized access to your system.",
|
|||
|
|
price = 999,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
-- ┌─────────────────────────────────────────────┐
|
|||
|
|
-- │ BUSINESS │
|
|||
|
|
-- └─────────────────────────────────────────────┘
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.finance",
|
|||
|
|
name = "Finance Manager",
|
|||
|
|
icon = "💰",
|
|||
|
|
version = "1.0.0",
|
|||
|
|
category = "business",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = false,
|
|||
|
|
description = "Track income, expenses and bank account balances.",
|
|||
|
|
price = 4999,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
|
|||
|
|
-- ┌─────────────────────────────────────────────┐
|
|||
|
|
-- │ GOVERNMENT (job-locked) │
|
|||
|
|
-- └─────────────────────────────────────────────┘
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.police.mdw",
|
|||
|
|
name = "Police MDW",
|
|||
|
|
icon = "🔍",
|
|||
|
|
version = "3.0.1",
|
|||
|
|
category = "government",
|
|||
|
|
permissions = { job = "police" },
|
|||
|
|
dependencies = {},
|
|||
|
|
default = false,
|
|||
|
|
description = "Mobile Data Workstation: criminal records, warrants, BOLO alerts.",
|
|||
|
|
price = 0,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.police.dispatch",
|
|||
|
|
name = "Dispatch Board",
|
|||
|
|
icon = "🚔",
|
|||
|
|
version = "2.1.0",
|
|||
|
|
category = "government",
|
|||
|
|
permissions = { job = "police" },
|
|||
|
|
dependencies = {},
|
|||
|
|
default = false,
|
|||
|
|
description = "Live dispatch board for law enforcement units.",
|
|||
|
|
price = 0,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.ems",
|
|||
|
|
name = "EMS Dashboard",
|
|||
|
|
icon = "🏥",
|
|||
|
|
version = "1.2.0",
|
|||
|
|
category = "government",
|
|||
|
|
permissions = { job = "ambulance" },
|
|||
|
|
dependencies = {},
|
|||
|
|
default = false,
|
|||
|
|
description = "Patient management and ambulance dispatch system.",
|
|||
|
|
price = 0,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
-- ┌─────────────────────────────────────────────┐
|
|||
|
|
-- │ ENTERTAINMENT │
|
|||
|
|
-- └─────────────────────────────────────────────┘
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.music",
|
|||
|
|
name = "TuneStream",
|
|||
|
|
icon = "🎵",
|
|||
|
|
version = "1.0.0",
|
|||
|
|
category = "entertainment",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = false,
|
|||
|
|
description = "Stream in-character radio stations and playlists.",
|
|||
|
|
price = 999,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
|
|||
|
|
-- ┌─────────────────────────────────────────────┐
|
|||
|
|
-- │ PARKING JOB │
|
|||
|
|
-- └─────────────────────────────────────────────┘
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.parkuhr",
|
|||
|
|
name = "Parkuhr Dashboard",
|
|||
|
|
icon = "🅿",
|
|||
|
|
version = "1.0.0",
|
|||
|
|
category = "government",
|
|||
|
|
permissions = { job = "parking" },
|
|||
|
|
dependencies = {},
|
|||
|
|
default = false,
|
|||
|
|
description = "Parking management dashboard – device overview, revenue tracking and tariff management.",
|
|||
|
|
price = 0,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
-- ┌─────────────────────────────────────────────┐
|
|||
|
|
-- │ IC-VERWALTUNG (Behörden) │
|
|||
|
|
-- └─────────────────────────────────────────────┘
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.ic_verwaltung",
|
|||
|
|
name = "IC-Verwaltung",
|
|||
|
|
icon = "🏛",
|
|||
|
|
version = "1.0.0",
|
|||
|
|
category = "government",
|
|||
|
|
permissions = { jobs = { "police", "ambulance", "dpa", "fire", "doj" } },
|
|||
|
|
dependencies = {},
|
|||
|
|
default = false,
|
|||
|
|
description = "Zugang zum IC-Verwaltungsportal. Nur für Behörden: PD, MD, DPA, FD, DOJ.",
|
|||
|
|
price = 0,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
|
|||
|
|
-- ┌─────────────────────────────────────────────┐
|
|||
|
|
-- │ GESETZBUCH (öffentliche Gesetze-Übersicht) │
|
|||
|
|
-- └─────────────────────────────────────────────┘
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.gesetzbuch",
|
|||
|
|
name = "Gesetzbuch",
|
|||
|
|
icon = "📖",
|
|||
|
|
version = "1.0.0",
|
|||
|
|
category = "government",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = {},
|
|||
|
|
default = false,
|
|||
|
|
description = "Öffentliche Übersicht aller Gesetzbücher und Paragraphen des Bundesstaates San Andreas – ohne Login einsehbar.",
|
|||
|
|
price = 0,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
|
|||
|
|
-- ┌─────────────────────────────────────────────┐
|
|||
|
|
-- │ BLEETER │
|
|||
|
|
-- └─────────────────────────────────────────────┘
|
|||
|
|
|
|||
|
|
-- ┌─────────────────────────────────────────────┐
|
|||
|
|
-- │ DARKNET (requires VPN) │
|
|||
|
|
-- └─────────────────────────────────────────────┘
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.darkbrowser",
|
|||
|
|
name = "Dark Browser",
|
|||
|
|
icon = "🕵",
|
|||
|
|
version = "0.9.0",
|
|||
|
|
category = "darknet",
|
|||
|
|
permissions = {},
|
|||
|
|
dependencies = { "pc.vpn" },
|
|||
|
|
default = false,
|
|||
|
|
description = "Access the hidden IC darknet. Requires SecureVPN. Use at your own risk.",
|
|||
|
|
price = 2499,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
end)
|