> ## Documentation Index
> Fetch the complete documentation index at: https://mythicframework.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Component System

> Understanding component-based architecture in Mythic Framework

Components are self-contained units of functionality that encapsulate related methods and data. They register with the framework via `RegisterComponent`, expose a public API, and can depend on or extend other components.

## Component Structure

A typical component looks like this:

```lua theme={null}
local MyComponent = {
    -- Private data (underscore convention)
    _data = {},

    -- Public methods (always use self parameter)
    DoSomething = function(self, param)
        -- Method implementation
        return result
    end,

    -- Internal helper (underscore = private by convention)
    _helperMethod = function(self)
        -- Not intended for external use
    end,

    -- Component metadata
    _protected = false,  -- Prevent other resources from overriding?
    _required = {},      -- Method names that must exist
    _name = 'mycomponent' -- Name used in logging
}

-- Register with framework
exports['mythic-base']:RegisterComponent('MyComponent', MyComponent)
```

<Note>
  All public methods use `function(self, ...)` and are called with colon syntax: `Component:Method(args)`. The `self` parameter is automatic with `:` calls.
</Note>

## Core Components

Provided by `mythic-base`, these are the essential components every resource depends on:

<CardGroup cols={2}>
  <Card title="Callbacks" icon="phone">
    Client-server callback system (request-response)
  </Card>

  <Card title="Logger" icon="file-lines">
    Centralized logging with levels and Discord webhooks
  </Card>

  <Card title="Database" icon="database">
    MongoDB and MySQL database operations
  </Card>

  <Card title="Middleware" icon="filter">
    Event middleware for pre/post processing
  </Card>

  <Card title="Fetch" icon="download">
    Player and character data access
  </Card>

  <Card title="DataStore" icon="hard-drive">
    Key-value persistent data storage
  </Card>
</CardGroup>

**Usage:**

```lua theme={null}
-- Logging
Logger:Info('MyResource', 'Something happened', { data = 'value' })
Logger:Error('MyResource', 'Error occurred', { console = true })

-- Database (async with callbacks)
Database.Game:findOne({
    collection = 'characters',
    query = { SID = 1 }
}, function(success, character)
    if success and character then
        print('Found character:', character.First)
    end
end)

-- Callbacks (server-side)
Callbacks:RegisterServerCallback('myresource:GetData', function(source, data, cb)
    cb({ success = true, data = someData })
end)
```

## Feature Components

Registered by feature resources (`mythic-inventory`, `mythic-jobs`, etc.) to expose their APIs:

```lua theme={null}
-- These are accessed via COMPONENTS after RetrieveComponents()
Inventory:AddItem(owner, 'water', 5)
Jobs.Permissions:HasJob(source, 'police')
Vehicles.Owned:GetPlayerVehicles(source)
Phone.Notification:Add(source, 'Title', 'Description', os.time(), 5000, 'phone')
```

Components use namespacing with dots to organize related functionality:

```lua theme={null}
-- Inventory sub-components
Inventory.Items:Has(source, 'lockpick', 1)
Inventory.Items:Remove(source, 'lockpick', 1)
Inventory.Items:GetCount(source, 'water')

-- Jobs sub-components
Jobs.Permissions:HasJob(source, 'police')
Jobs.Duty:On(source, 'police')

-- Vehicles sub-components
Vehicles.Owned:Spawn(source, vehicleData)
Vehicles.Keys:Has(source, vehicleNet)
```

## Creating Components

### Basic Component

```lua theme={null}
-- mythic-myresource/server/component.lua

exports['mythic-base']:RegisterComponent('MyFeature', {
    _protected = true,
    _name = 'myfeature',

    DoAction = function(self, player, data)
        Logger:Info('MyFeature', 'Action performed', {
            player = player,
            data = data
        })
        return true
    end,

    GetData = function(self, id, callback)
        Database.Game:findOne({
            collection = 'myfeature',
            query = { _id = id }
        }, function(success, result)
            if callback then
                callback(success, result)
            end
        end)
    end
})
```

### Component with Dependencies

Use `RequestDependencies` to ensure required components are loaded first:

```lua theme={null}
-- mythic-shop/server/component.lua

AddEventHandler('Core:Shared:Ready', function()
    exports['mythic-base']:RequestDependencies('Shop', {
        'Inventory',
        'Fetch',
        'Logger'
    }, function(errors)
        if #errors > 0 then
            return
        end

        -- All dependencies loaded, safe to use
        RetrieveComponents()
        RegisterCallbacks()
        Startup()
    end)
end)

-- After RetrieveComponents(), components are available as locals
function RegisterCallbacks()
    Callbacks:RegisterServerCallback('mythic-shop:Purchase', function(source, data, cb)
        local char = Fetch:Source(source):GetData('Character')
        -- Purchase logic...
        cb({ success = true })
    end)
end
```

## The `RetrieveComponents` Pattern

Most resources use a standard pattern where `RetrieveComponents()` pulls all needed components into local variables:

```lua theme={null}
local Inventory, Callbacks, Fetch, Logger

function RetrieveComponents()
    Inventory = exports['mythic-base']:FetchComponent('Inventory')
    Callbacks = exports['mythic-base']:FetchComponent('Callbacks')
    Fetch = exports['mythic-base']:FetchComponent('Fetch')
    Logger = exports['mythic-base']:FetchComponent('Logger')
end

AddEventHandler('Core:Shared:Ready', function()
    exports['mythic-base']:RequestDependencies('MyResource', {
        'Inventory', 'Callbacks', 'Fetch', 'Logger'
    }, function(errors)
        if #errors == 0 then
            RetrieveComponents()
        end
    end)
end)
```

After `RetrieveComponents()`, you use the local variables directly instead of `X` everywhere.

## Component Patterns

### Service Pattern

Stateless components that provide services:

```lua theme={null}
exports['mythic-base']:RegisterComponent('Notifications', {
    Send = function(self, player, message, type)
        TriggerClientEvent('mythic-notifications:client:Send', player, {
            message = message,
            type = type or 'info',
            duration = 5000
        })
    end,

    SendError = function(self, player, message)
        self:Send(player, message, 'error')
    end,

    SendSuccess = function(self, player, message)
        self:Send(player, message, 'success')
    end
})
```

### Manager Pattern

Components that manage a collection of entities:

```lua theme={null}
exports['mythic-base']:RegisterComponent('VehicleManager', {
    _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
})
```

## Extending Components

Use `ExtendComponent` to add functionality to an existing component without modifying the original resource:

```lua theme={null}
-- Store reference to original method
local originalAddItem = Inventory.AddItem

-- Extend with additional behavior
exports['mythic-base']:ExtendComponent('Inventory', {
    AddItem = function(self, player, item, count)
        -- Log before
        Logger:Info('Inventory', 'Adding item', {
            player = player,
            item = item,
            count = count
        })

        -- Call original
        local success = originalAddItem(self, player, item, count)

        return success
    end
})
```

<Warning>
  `ExtendComponent` cannot modify protected components (`_protected = true`). It will fail with a warning.
</Warning>

## Component Communication

### Direct Method Calls

```lua theme={null}
-- Simple and fast
local inventory = Inventory:Get(characterId)
Notification:Send(source, 'Item received', 'success')
```

### Event-Based Communication

```lua theme={null}
-- Component triggers event for other systems to react
exports['mythic-base']:RegisterComponent('Shop', {
    Purchase = function(self, player, item, price)
        local success = self:_processPurchase(player, item, price)
        if success then
            TriggerEvent('Shop:PurchaseComplete', player, item, price)
        end
        return success
    end
})

-- Other components listen
AddEventHandler('Shop:PurchaseComplete', function(player, item, price)
    Logger:Info('Shop', 'Purchase complete', { player = player, item = item })
end)
```

## Best Practices

<AccordionGroup>
  <Accordion title="Single Responsibility" icon="bullseye">
    Each component should have one clear purpose:

    ```lua theme={null}
    -- Good: focused component
    Garage = {
        SpawnVehicle = function(self, ...) end,
        StoreVehicle = function(self, ...) end,
        GetVehicles = function(self, ...) end,
    }

    -- Bad: does too many unrelated things
    Everything = {
        SpawnVehicle = function(self, ...) end,
        GetInventory = function(self, ...) end,
        SendEmail = function(self, ...) end,
    }
    ```
  </Accordion>

  <Accordion title="Always Use RequestDependencies" icon="clock">
    Never assume components are available immediately:

    ```lua theme={null}
    -- Bad: may be nil if component hasn't loaded yet
    local Inventory = Inventory

    -- Good: wait for dependencies
    exports['mythic-base']:RequestDependencies('MyResource', { 'Inventory' }, function(errors)
        if #errors == 0 then
            RetrieveComponents()
        end
    end)
    ```
  </Accordion>

  <Accordion title="Error Handling" icon="triangle-exclamation">
    Always handle errors gracefully:

    ```lua theme={null}
    exports['mythic-base']:RegisterComponent('Payment', {
        Charge = function(self, player, amount)
            if not player or amount <= 0 then
                return false, 'Invalid parameters'
            end

            local balance = self:GetBalance(player)
            if balance < amount then
                return false, 'Insufficient funds'
            end

            local success = self:_deductBalance(player, amount)
            if not success then
                Logger:Error('Payment', 'Failed to deduct balance')
                return false, 'Transaction failed'
            end

            return true
        end
    })
    ```
  </Accordion>

  <Accordion title="Use Protected for Core Components" icon="shield">
    Prevent accidental overrides of critical components:

    ```lua theme={null}
    exports['mythic-base']:RegisterComponent('Inventory', {
        _protected = true,
        -- Methods cannot be overridden by other resources
    })
    ```
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Proxy Pattern" icon="circle-nodes" href="/concepts/proxy-pattern">
    Deep dive into RegisterComponent, FetchComponent, etc.
  </Card>

  <Card title="Event System" icon="bolt" href="/concepts/event-system">
    Complement components with events and callbacks
  </Card>

  <Card title="Resource Structure" icon="folder-tree" href="/concepts/resource-structure">
    How to organize resources using components
  </Card>

  <Card title="API Reference" icon="code" href="/api/core/base">
    Complete API documentation
  </Card>
</CardGroup>
