Skip to main content
The mythic-base resource is the foundation of Mythic Framework, providing the component proxy system, logging, database access, and essential utilities that all other resources depend on.

Core Exports

These are the four fundamental exports that power the entire framework:

RegisterComponent

Register a new component or override existing

FetchComponent

Retrieve a registered component

ExtendComponent

Add methods to existing component

RequestDependencies

Asynchronously wait for dependencies

RegisterComponent

Register a new component or override an existing protected component.

Syntax

exports['mythic-base']:RegisterComponent(componentName, componentData)

Parameters

componentName
string
required
Name of the component to register (e.g., ‘Inventory’, ‘Jobs’, ‘MyComponent’)
componentData
table
required
Table containing component methods and propertiesSpecial Properties:
  • _protected (boolean) - If true, component cannot be overridden
  • _required (table) - Array of method names that must exist
  • _name (string) - Internal name for logging

Returns

success
boolean
Returns true if component was registered successfully

Examples

Basic Component:
-- mythic-example/server/component.lua

exports['mythic-base']:RegisterComponent('Example', {
    DoSomething = function(self, param)
        print('Doing something with:', param)
        return true
    end,

    GetData = function(self, id)
        return { id = id, name = 'Example Data' }
    end
})
Protected Component with Required Methods:
-- mythic-inventory/server/component.lua

exports['mythic-base']:RegisterComponent('Inventory', {
    -- Metadata
    _protected = true,  -- Cannot be overridden
    _required = { 'Get', 'AddItem', 'RemoveItem' },  -- Must have these methods
    _name = 'inventory',

    -- Required methods
    Get = function(self, characterId)
        return COMPONENTS.Database:findOne('inventory', {
            owner = characterId
        })
    end,

    AddItem = function(self, characterId, item, count, metadata)
        -- Add item logic
        COMPONENTS.Logger:Info('Inventory', 'Item added', {
            character = characterId,
            item = item,
            count = count
        })
        return true
    end,

    RemoveItem = function(self, characterId, slot, count)
        -- Remove item logic
        return true
    end,

    -- Additional methods
    HasItem = function(self, characterId, item, count)
        local inventory = self:Get(characterId)
        -- Check logic
        return false
    end
})
Component with State:
exports['mythic-base']:RegisterComponent('VehicleManager', {
    -- Private state
    _vehicles = {},

    Register = function(self, vehicleId, data)
        self._vehicles[vehicleId] = data
    end,

    Unregister = function(self, vehicleId)
        self._vehicles[vehicleId] = nil
    end,

    Get = function(self, vehicleId)
        return self._vehicles[vehicleId]
    end,

    GetAll = function(self)
        return self._vehicles
    end
})

Notes

Component Naming: Use PascalCase for component names (e.g., ‘Inventory’, ‘VehicleManager’, ‘MyFeature’)
Protected Components: Attempting to override a protected component will fail with an error. Use ExtendComponent to add methods to protected components.

FetchComponent

Retrieve a registered component for use.

Syntax

local component = exports['mythic-base']:FetchComponent(componentName)

Parameters

componentName
string
required
Name of the component to fetch

Returns

component
table|nil
The component table if found, nil if not registered

Examples

Basic Fetch:
-- Fetch a component
local Inventory = exports['mythic-base']:FetchComponent('Inventory')

if Inventory then
    -- Use the component
    local items = Inventory:Get(characterId)
else
    print('[ERROR] Inventory component not found!')
end
Using COMPONENTS Global:
-- COMPONENTS is a global table populated by FetchComponent
-- More convenient than repeated exports calls

AddEventHandler('Core:Shared:Ready', function()
    -- Components are now available in COMPONENTS global
    COMPONENTS.Logger:Info('MyResource', 'Starting up')

    local character = COMPONENTS.Characters:GetCharacter(source)
    local inventory = COMPONENTS.Inventory:Get(character.SID)
end)
Fetch Multiple Components:
-- Fetch multiple components at once
local Logger = exports['mythic-base']:FetchComponent('Logger')
local Database = exports['mythic-base']:FetchComponent('Database')
local Characters = exports['mythic-base']:FetchComponent('Characters')

-- Or use COMPONENTS global
local Logger = COMPONENTS.Logger
local Database = COMPONENTS.Database
local Characters = COMPONENTS.Characters

Notes

COMPONENTS Global: After Core:Shared:Ready event, all components are available in the COMPONENTS global table. Use COMPONENTS.ComponentName instead of repeatedly calling FetchComponent.
Timing: Don’t fetch components at the top level of your script! They may not be registered yet. Wait for Core:Shared:Ready or use RequestDependencies.

ExtendComponent

Add new methods to an existing component without overriding it.

Syntax

exports['mythic-base']:ExtendComponent(componentName, extensionData)

Parameters

componentName
string
required
Name of the component to extend
extensionData
table
required
Table containing new methods to add to the component

Returns

success
boolean
Returns true if extension was successful

Examples

Add Helper Methods:
-- mythic-inventory-extras/server/component.lua

-- Extend Inventory component with new methods
exports['mythic-base']:ExtendComponent('Inventory', {
    -- Add weight calculation
    GetWeight = function(self, characterId)
        local inventory = self:Get(characterId)
        local totalWeight = 0

        for _, item in pairs(inventory.items) do
            totalWeight = totalWeight + (item.weight * item.count)
        end

        return totalWeight
    end,

    -- Add bulk operation
    AddMultipleItems = function(self, characterId, items)
        for _, itemData in ipairs(items) do
            self:AddItem(characterId, itemData.item, itemData.count)
        end
    end,

    -- Add search functionality
    FindItem = function(self, characterId, itemName)
        local inventory = self:Get(characterId)

        for slot, item in pairs(inventory.items) do
            if item.name == itemName then
                return slot, item
            end
        end

        return nil
    end
})
Override Method While Preserving Original:
-- Save reference to original method
local originalAddItem = COMPONENTS.Inventory.AddItem

-- Extend with wrapper that adds logging
exports['mythic-base']:ExtendComponent('Inventory', {
    AddItem = function(self, characterId, item, count, metadata)
        -- Log before
        COMPONENTS.Logger:Debug('Inventory', 'Adding item', {
            character = characterId,
            item = item,
            count = count
        })

        -- Call original method
        local success = originalAddItem(self, characterId, item, count, metadata)

        -- Log after
        if success then
            TriggerEvent('inventory:itemAdded', characterId, item, count)
        end

        return success
    end
})
Add Integration Methods:
-- mythic-crafting/server/component.lua

-- Extend Inventory with crafting-specific methods
exports['mythic-base']:ExtendComponent('Inventory', {
    CanCraft = function(self, characterId, recipe)
        for _, ingredient in ipairs(recipe.ingredients) do
            if not self:HasItem(characterId, ingredient.item, ingredient.count) then
                return false
            end
        end
        return true
    end,

    ConsumeRecipe = function(self, characterId, recipe)
        for _, ingredient in ipairs(recipe.ingredients) do
            self:RemoveItem(characterId, ingredient.item, ingredient.count)
        end
    end
})

Notes

Non-Destructive: ExtendComponent adds methods without removing existing ones. If a method already exists, it will be overridden.
Modular Extensions: Use ExtendComponent to add resource-specific functionality to core components without modifying the original resource.

RequestDependencies

Asynchronously wait for component dependencies to be registered before initializing your component.

Syntax

exports['mythic-base']:RequestDependencies(componentName, dependencies, callback)

Parameters

componentName
string
required
Name of your component (for error reporting)
dependencies
table
required
Array of component names that must be loaded before callback executes
callback
function
required
Function called when all dependencies are loaded or on timeoutCallback Parameters:
  • errors (table) - Array of error messages (empty if all dependencies loaded)

Returns

Nothing (callback-based)

Examples

Basic Dependency Management:
-- mythic-shops/server/component.lua

exports['mythic-base']:RequestDependencies('Shops', {
    'Inventory',
    'Finance',
    'Logger'
}, function(errors)
    if #errors > 0 then
        -- Dependencies failed to load
        print('[ERROR] Shops failed to load dependencies:')
        for _, err in ipairs(errors) do
            print('  - ' .. err)
        end
        return
    end

    -- All dependencies loaded, safe to register component
    exports['mythic-base']:RegisterComponent('Shops', {
        Purchase = function(self, player, item, price)
            -- Can safely use dependencies here
            if COMPONENTS.Finance:Charge(player, price) then
                COMPONENTS.Inventory:AddItem(player, item, 1)
                COMPONENTS.Logger:Info('Shops', 'Purchase complete')
                return true
            end
            return false
        end
    })
end)
Multiple Dependencies:
exports['mythic-base']:RequestDependencies('VehicleShop', {
    'Database',
    'Logger',
    'Vehicles',
    'Finance',
    'Inventory',
    'Characters'
}, function(errors)
    if #errors > 0 then
        error('[VehicleShop] Missing dependencies: ' .. json.encode(errors))
        return
    end

    -- All dependencies available
    exports['mythic-base']:RegisterComponent('VehicleShop', {
        -- Component implementation
    })
end)
Graceful Degradation:
exports['mythic-base']:RequestDependencies('MyFeature', {
    'Inventory',    -- Required
    'Phone'         -- Optional enhancement
}, function(errors)
    local hasPhone = true

    -- Check which dependencies failed
    for _, err in ipairs(errors) do
        if string.find(err, 'Phone') then
            print('[WARNING] Phone not available, notifications disabled')
            hasPhone = false
        else
            -- Other dependency failed, can't continue
            print('[ERROR]', err)
            return
        end
    end

    exports['mythic-base']:RegisterComponent('MyFeature', {
        Notify = function(self, player, message)
            if hasPhone then
                -- Use phone notifications
                COMPONENTS.Phone:SendNotification(player, message)
            else
                -- Fallback to chat
                TriggerClientEvent('chat:addMessage', player, {
                    args = { message }
                })
            end
        end
    })
end)

Notes

Always Use RequestDependencies: Even if dependencies are in fxmanifest.lua, use RequestDependencies to ensure components are registered before you use them.
Timeout: Dependencies have a timeout (default 30 seconds). If a dependency doesn’t load in time, it will error in the callback.
Load Order: Resources still need proper load order in resources.cfg. RequestDependencies handles component registration timing, not resource loading.

Core:Shared:Ready Event

The Core:Shared:Ready event fires when mythic-base has finished initializing and all core components are available.

Syntax

AddEventHandler('Core:Shared:Ready', function()
    -- Core components available
end)

When to Use

Use Core:Shared:Ready when you need to:
  • Access core components (Logger, Database, etc.)
  • Set up event handlers that use components
  • Initialize features that depend on the framework

Examples

Client-Side Initialization:
-- mythic-hud/client/main.lua

AddEventHandler('Core:Shared:Ready', function()
    -- Fetch client components
    local Logger = exports['mythic-base']:FetchComponent('Logger')
    local Callbacks = exports['mythic-base']:FetchComponent('Callback')

    Logger:Info('HUD', 'Initializing HUD')

    -- Register callbacks
    Callbacks:RegisterCallback('hud:getData', function(data, cb)
        cb({ status = 'ok' })
    end)

    -- Start HUD
    SendNUIMessage({ type = 'INIT' })
end)
Server-Side Initialization:
-- mythic-jobs/server/main.lua

AddEventHandler('Core:Shared:Ready', function()
    -- Components now available in COMPONENTS global
    COMPONENTS.Logger:Info('Jobs', 'Loading jobs system')

    -- Load jobs from database
    local jobs = COMPONENTS.Database:find('jobs', {})

    COMPONENTS.Logger:Info('Jobs', 'Loaded ' .. #jobs .. ' jobs')

    -- Set up event handlers
    RegisterNetEvent('jobs:server:clockIn', function(jobId)
        local char = COMPONENTS.Characters:GetCharacter(source)
        COMPONENTS.Jobs:ClockIn(char.SID, jobId)
    end)
end)

COMPONENTS Global

The COMPONENTS global table contains all registered components for easy access.

Usage

-- Instead of this:
local Logger = exports['mythic-base']:FetchComponent('Logger')
local Database = exports['mythic-base']:FetchComponent('Database')

-- Use this:
COMPONENTS.Logger:Info('MyResource', 'Message')
COMPONENTS.Database:findOne('collection', {})

Available After

COMPONENTS is populated after the Core:Shared:Ready event fires.

Common Components

-- Core components (always available)
COMPONENTS.Logger
COMPONENTS.Database
COMPONENTS.Middleware
COMPONENTS.Callback
COMPONENTS.Punishment

-- Feature components (if resources loaded)
COMPONENTS.Characters
COMPONENTS.Inventory
COMPONENTS.Finance
COMPONENTS.Jobs
COMPONENTS.Vehicles
COMPONENTS.Police
COMPONENTS.Properties

Best Practices

❌ Bad:
-- Top-level component access (may be nil!)
local Logger = COMPONENTS.Logger
Logger:Info('MyResource', 'Starting')  -- Error: attempt to index nil
✅ Good:
AddEventHandler('Core:Shared:Ready', function()
    COMPONENTS.Logger:Info('MyResource', 'Starting')
end)
❌ Bad:
-- Assume dependencies exist
exports['mythic-base']:RegisterComponent('MyFeature', {
    DoThing = function(self)
        COMPONENTS.Inventory:AddItem(...)  -- May be nil!
    end
})
✅ Good:
exports['mythic-base']:RequestDependencies('MyFeature', {
    'Inventory'
}, function(errors)
    if #errors == 0 then
        exports['mythic-base']:RegisterComponent('MyFeature', {
            DoThing = function(self)
                COMPONENTS.Inventory:AddItem(...)  -- Guaranteed to exist
            end
        })
    end
end)
exports['mythic-base']:RegisterComponent('MyFeature', {
    --- Add an item to player's inventory
    ---@param player number Player server ID
    ---@param item string Item name
    ---@param count number Quantity
    ---@return boolean success
    GiveItem = function(self, player, item, count)
        -- Implementation
    end
})
When to use _protected = true:
  • Core framework components
  • Components with complex internal state
  • Components where overriding would break other resources
When NOT to use:
  • Simple utility components
  • Components designed to be customizable
  • Resource-specific components

Next Steps