Skip to content

Data Library

Data persistence, serialization, and management system for the Lilia framework.


Overview

The data library provides comprehensive functionality for data persistence, serialization, and management within the Lilia framework. It handles encoding and decoding of complex data types including vectors, angles, colors, and nested tables for database storage. The library manages both general data storage with gamemode and map-specific scoping, as well as entity persistence for maintaining spawned entities across server restarts. It includes automatic serialization/deserialization, database integration, and caching mechanisms to ensure efficient data access and storage operations.


encodetable

Purpose

Converts complex data types (vectors, angles, colors, tables) into database-storable formats

When Called

Automatically called during data serialization before database storage

Parameters

  • value (any): The value to encode (vector, angle, color table, or regular table)

Returns

  • table or any - Encoded representation suitable for JSON serialization

Realm

Shared

Example Usage

Low Complexity:

-- Simple: Encode a vector
local encoded = lia.data.encodetable(Vector(100, 200, 300))
-- Returns: {100, 200, 300}

Medium Complexity:

-- Medium: Encode a color with alpha
local color = Color(255, 128, 64, 200)
local encoded = lia.data.encodetable(color)
-- Returns: {255, 128, 64, 200}

High Complexity:

-- High: Encode nested table with mixed data types
local complexData = {
    position = Vector(0, 0, 0),
    rotation = Angle(0, 90, 0),
    color   = Color(255, 0, 0),
    settings = {enabled = true, count = 5}
}
local encoded = lia.data.encodetable(complexData)
-- Returns: {position = {0, 0, 0}, rotation = {0, 90, 0}, color = {255, 0, 0, 255}, settings = {enabled = true, count = 5}}


decode

Purpose

Converts encoded data back to original complex data types (vectors, angles, colors)

When Called

Automatically called during data deserialization after database retrieval

Parameters

  • value (any): The encoded value to decode (table, string, or raw data)

Returns

  • any - Decoded value with proper data types restored

Realm

Shared

Example Usage

Low Complexity:

-- Simple: Decode a vector from encoded format
local decoded = lia.data.decode({100, 200, 300})
-- Returns: Vector(100, 200, 300)

Medium Complexity:

-- Medium: Decode an angle from encoded format
local encodedAngle = {0, 90, 0}
local decoded = lia.data.decode(encodedAngle)
-- Returns: Angle(0, 90, 0)

High Complexity:

-- High: Decode complex nested data structure
local encodedData = {
    position = {100, 200, 300},
    rotation = {0, 90, 0},
    color    = {255, 0, 0, 255},
    settings = {enabled = true, count = 5}
}
local decoded = lia.data.decode(encodedData)
-- Returns: {position = Vector(100, 200, 300), rotation = Angle(0, 90, 0), color = Color(255, 0, 0, 255), settings = {enabled = true, count = 5}}


serialize

Purpose

Converts any data structure into a JSON string suitable for database storage

When Called

Called before storing data in the database to ensure proper serialization

Parameters

  • value (any): The data to serialize (tables, vectors, angles, colors, etc.)

Returns

  • string - JSON string representation of the encoded data

Realm

Shared

Example Usage

Low Complexity:

-- Simple: Serialize a basic table
local serialized = lia.data.serialize({name = "test", value = 42})
-- Returns: '{"name":"test","value":42}'

Medium Complexity:

-- Medium: Serialize a vector
local serialized = lia.data.serialize(Vector(100, 200, 300))
-- Returns: '{"value":[100,200,300]}'

High Complexity:

-- High: Serialize complex nested data with mixed types
local complexData = {
    position = Vector(0, 0, 0),
    rotation = Angle(0, 90, 0),
    color    = Color(255, 0, 0),
    settings = {enabled = true, count = 5}
}
local serialized = lia.data.serialize(complexData)
-- Returns: JSON string with all data properly encoded


deserialize

Purpose

Converts serialized data (JSON strings or tables) back to original data structures

When Called

Called after retrieving data from database to restore original data types

Parameters

  • raw (string|table): Serialized data from database (JSON string or table)

Returns

  • any - Deserialized data with proper types restored, or nil if invalid

Realm

Shared

Example Usage

Low Complexity:

-- Simple: Deserialize a JSON string
local deserialized = lia.data.deserialize('{"name":"test","value":42}')
-- Returns: {name = "test", value = 42}

Medium Complexity:

-- Medium: Deserialize encoded vector data
local jsonData = '{"value":[100,200,300]}'
local deserialized = lia.data.deserialize(jsonData)
-- Returns: Vector(100, 200, 300)

High Complexity:

-- High: Deserialize complex data with fallback handling
local complexJson = '{"position":[0,0,0],"rotation":[0,90,0],"color":[255,0,0,255],"settings":{"enabled":true,"count":5}}'
local deserialized = lia.data.deserialize(complexJson)
-- Returns: {position = Vector(0, 0, 0), rotation = Angle(0, 90, 0), color = Color(255, 0, 0, 255), settings = {enabled = true, count = 5}}


decodeVector

Purpose

Specifically decodes vector data from various formats (JSON, strings, tables)

When Called

Called when specifically needing to decode vector data from database or serialized format

Parameters

  • raw (any): Raw data that should contain vector information

Returns

  • Vector or any - Decoded Vector object, or original data if not vector format

Realm

Shared

Example Usage

Low Complexity:

-- Simple: Decode vector from array format
local vector = lia.data.decodeVector({100, 200, 300})
-- Returns: Vector(100, 200, 300)

Medium Complexity:

-- Medium: Decode vector from JSON string
local jsonString = '[100,200,300]'
local vector = lia.data.decodeVector(jsonString)
-- Returns: Vector(100, 200, 300)

High Complexity:

-- High: Decode vector with multiple format fallbacks
local vectorData = "Vector(100, 200, 300)"
local vector = lia.data.decodeVector(vectorData)
-- Returns: Vector(100, 200, 300) - handles string parsing


decodeAngle

Purpose

Specifically decodes angle data from various formats (JSON, strings, tables)

When Called

Called when specifically needing to decode angle data from database or serialized format

Parameters

  • raw (any): Raw data that should contain angle information

Returns

  • Angle or any - Decoded Angle object, or original data if not angle format

Realm

Shared

Example Usage

Low Complexity:

-- Simple: Decode angle from array format
local angle = lia.data.decodeAngle({0, 90, 0})
-- Returns: Angle(0, 90, 0)

Medium Complexity:

-- Medium: Decode angle from JSON string
local jsonString = '[0,90,0]'
local angle = lia.data.decodeAngle(jsonString)
-- Returns: Angle(0, 90, 0)

High Complexity:

-- High: Decode angle with multiple format fallbacks
local angleData = "Angle(0, 90, 0)"
local angle = lia.data.decodeAngle(angleData)
-- Returns: Angle(0, 90, 0) - handles string parsing


set

Purpose

Stores data in the database with gamemode and map-specific scoping

When Called

Called when storing persistent data that should survive server restarts

Parameters

  • key (string): Unique identifier for the data, value (any) - Data to store, global (boolean, optional) - Store globally across all gamemodes/maps, ignoreMap (boolean, optional) - Store for all maps in current gamemode

Returns

  • string - Database path where data was stored

Realm

Server

Example Usage

Low Complexity:

-- Simple: Store basic data for current gamemode and map
lia.data.set("playerCount", 25)
-- Stores data scoped to current gamemode and map

Medium Complexity:

-- Medium: Store data globally across all gamemodes and maps
lia.data.set("serverVersion", "1.0.0", true)
-- Stores data globally, accessible from any gamemode/map

High Complexity:

-- High: Store complex data with custom scoping
local playerData = {
    position  = Vector(100, 200, 300),
    inventory = {weapon = "pistol", ammo = 50},
    settings  = {volume = 0.8, graphics = "high"}
}
lia.data.set("player_" .. player:SteamID64(), playerData, false, true)
-- Stores player data for current gamemode but all maps


delete

Purpose

Removes data from the database with gamemode and map-specific scoping

When Called

Called when removing persistent data that should no longer be stored

Parameters

  • key (string): Unique identifier for the data to delete, global (boolean, optional) - Delete from global scope, ignoreMap (boolean, optional) - Delete from all maps in current gamemode

Returns

  • boolean - Always returns true

Realm

Server

Example Usage

Low Complexity:

-- Simple: Delete data for current gamemode and map
lia.data.delete("playerCount")
-- Removes data scoped to current gamemode and map

Medium Complexity:

-- Medium: Delete data globally across all gamemodes and maps
lia.data.delete("serverVersion", true)
-- Removes data from global scope

High Complexity:

-- High: Delete player data with custom scoping
local playerID = "player_" .. player:SteamID64()
lia.data.delete(playerID, false, true)
-- Removes player data for current gamemode but all maps


loadTables

Purpose

Loads all stored data from database into memory with hierarchical scoping

When Called

Called during server startup to restore all persistent data

Returns

  • None

Realm

Server

Example Usage

Low Complexity:

-- Simple: Load all data tables
lia.data.loadTables()
-- Loads global, gamemode, and map-specific data

Medium Complexity:

-- Medium: Load data with custom initialization
lia.data.loadTables()
-- After loading, access specific data
local playerCount = lia.data.get("playerCount", 0)

High Complexity:

-- High: Load data with validation and error handling
lia.data.loadTables()
-- Data is loaded hierarchically: global -> gamemode -> map-specific
-- Later data overrides earlier data (map overrides gamemode overrides global)


loadPersistence

Purpose

Ensures persistence table has required columns for entity storage

When Called

Called during server startup to prepare database schema for entity persistence

Returns

  • Promise - Database operation promise

Realm

Server

Example Usage

Low Complexity:

-- Simple: Load persistence schema
lia.data.loadPersistence()
-- Ensures all required columns exist in persistence table

Medium Complexity:

-- Medium: Load persistence with error handling
lia.data.loadPersistence():next(function()
    print("Persistence schema loaded successfully")
end):catch(function(err)
    print("Failed to load persistence schema: " .. err)
end)

High Complexity:

-- High: Load persistence as part of initialization sequence
lia.data.loadPersistence():next(function()
    return lia.data.loadPersistenceData(function(entities)
        -- Process loaded entities
        for _, ent in ipairs(entities) do
            -- Spawn entities or process data
        end
    end)
end)


savePersistence

Purpose

Saves entity data to database for persistence across server restarts

When Called

Called during server shutdown or periodic saves to persist entity states

Parameters

  • entities (table): Array of entity data tables to save

Returns

  • None

Realm

Server

Example Usage

Low Complexity:

-- Simple: Save basic entity data
local entities = {
    {class = "prop_physics", pos = Vector(0, 0, 0), angles = Angle(0, 0, 0), model = "models/props_c17/FurnitureTable001a.mdl"}
}
lia.data.savePersistence(entities)

Medium Complexity:

-- Medium: Save entities with custom properties
local entities = {
    {
        class   = "lia_vendor",
        pos     = Vector(100, 200, 0),
        angles  = Angle(0, 90, 0),
        model   = "models/player.mdl",
        name    = "Weapon Vendor",
        items   = {"weapon_pistol", "weapon_shotgun"}
    }
}
lia.data.savePersistence(entities)

High Complexity:

-- High: Save complex entities with dynamic properties
local entities = {}
for _, ent in ipairs(ents.GetAll()) do
    if ent:GetClass() == "lia_item" then
        table.insert(entities, {
            class   = ent:GetClass(),
            pos     = ent:GetPos(),
            angles  = ent:GetAngles(),
            model   = ent:GetModel(),
            itemID  = ent:GetItemID(),
            amount  = ent:GetAmount(),
            data    = ent:GetData()
        })
    end
end
lia.data.savePersistence(entities)


loadPersistenceData

Purpose

Loads persisted entity data from database and optionally executes callback

When Called

Called during server startup to restore persisted entities

Parameters

  • callback (function, optional): Function to call with loaded entity data

Returns

  • Promise - Database operation promise

Realm

Server

Example Usage

Low Complexity:

-- Simple: Load persistence data
lia.data.loadPersistenceData()
-- Loads entity data into cache

Medium Complexity:

-- Medium: Load persistence data with callback
lia.data.loadPersistenceData(function(entities)
    print("Loaded " .. #entities .. " entities")
    for _, ent in ipairs(entities) do
        print("Entity: " .. ent.class .. " at " .. tostring(ent.pos))
    end
end)

High Complexity:

-- High: Load persistence data with entity spawning
lia.data.loadPersistenceData(function(entities)
    for _, entData in ipairs(entities) do
        local ent = ents.Create(entData.class)
        if IsValid(ent) then
            ent:SetPos(entData.pos)
            ent:SetAngles(entData.angles)
            ent:SetModel(entData.model)
            ent:Spawn()
            -- Restore custom properties
            for k, v in pairs(entData) do
                if not defaultCols[k] then
                    ent:SetNWVar(k, v)
                end
            end
        end
    end
end)


get

Purpose

Retrieves stored data from memory cache with automatic deserialization

When Called

Called when accessing stored persistent data

Parameters

  • key (string): Unique identifier for the data, default (any, optional) - Default value if key not found

Returns

  • any - Stored data or default value if not found

Realm

Shared

Example Usage

Low Complexity:

-- Simple: Get basic data
local playerCount = lia.data.get("playerCount", 0)
-- Returns stored player count or 0 if not found

Medium Complexity:

-- Medium: Get data with default fallback
local serverSettings = lia.data.get("serverSettings", {
    maxPlayers  = 32,
    mapRotation = {"gm_flatgrass", "gm_construct"}
})
-- Returns stored settings or default configuration

High Complexity:

-- High: Get complex data with validation
local playerData = lia.data.get("player_" .. player:SteamID64(), {})
if playerData.position then
    player:SetPos(playerData.position)
end
if playerData.inventory then
    player:GetInventory():LoadFromData(playerData.inventory)
end
-- Retrieves and processes complex player data


getPersistence

Purpose

Retrieves cached entity persistence data from memory

When Called

Called when accessing loaded entity persistence data

Returns

  • table - Array of entity data tables or empty table if none loaded

Realm

Shared

Example Usage

Low Complexity:

-- Simple: Get persistence data
local entities = lia.data.getPersistence()
print("Loaded " .. #entities .. " entities")

Medium Complexity:

-- Medium: Get persistence data with filtering
local entities = lia.data.getPersistence()
local vendors = {}
for _, ent in ipairs(entities) do
    if ent.class == "lia_vendor" then
        table.insert(vendors, ent)
    end
end
print("Found " .. #vendors .. " vendors")

High Complexity:

-- High: Get persistence data with processing
local entities = lia.data.getPersistence()
local entityStats = {}
for _, ent in ipairs(entities) do
    if not entityStats[ent.class] then
        entityStats[ent.class] = 0
    end
    entityStats[ent.class] = entityStats[ent.class] + 1
end
for class, count in pairs(entityStats) do
    print(class .. ": " .. count .. " entities")
end