# Download

You can get the latest version of Knight at <https://github.com/RAMPAGELLC/knight>


# Welcome

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2FYS4eTmHh5O4HOXuOx3C9%2Fwelcome.jpg?alt=media&amp;token=5a72007e-dfed-46fa-9fc4-4b5264ac39ea" alt=""><figcaption></figcaption></figure>

## About Knight

Knight is a comprehensive Luau-based framework for Roblox game development that allows for the structured creation of server-side, client-side, and shared code. This framework promotes clean code organization and scalable development practices, making it easier to manage complex game logic.

## Why choose Knight

Knight is made for everyone from professional game studios like RAMPAGE to independent developers. With the powerful & simple structure of Knight you can easily build a great codebase foundation for your game. With our powerful features such as our amazing networking system you can easily get a stable version of your game out quickly!

## Thank you for choosing Knight.

We hope this introduction phase helps you understand key points such as;

* How knight works.
* How to use knight.

{% hint style="danger" %}
Knight is an experimental framework actively being developed by Contributors and RAMPAGE Interactive. While bugs and issues may arise, we believe Knight is in a stable enough state for developers to start using.
{% endhint %}

{% hint style="warning" %}
V3 Documentation is actively worked on by vq9o and contributor(s); Please report any documentation issues via Issues tab on the main Knight GitHub (rampagellc/knight docs branch), or fix it yourself and submit a PR!
{% endhint %}


# Installation

{% hint style="danger" %}
In version `v1.0.5` the project structure has been drastically changed breaking tools like the Knight CLI, Git installation, etc.

You **must now use Wally** to install until we fix our tools. Add `knight = "vq9o/knight@1.0.5"` to `wally.toml` then run `wally install`.
{% endhint %}

Knight is a lightweight framework for organizing your Roblox game code using services and clean architecture.

There are **three ways** to install Knight in your project:

***

## Option 1: Clone via Git

If you're comfortable with Git, clone the Knight repository directly:

```bash
git clone https://github.com/RAMPAGELLC/knight.git
```

***

## Option 2: Use Knight CLI

If you have the **Knight CLI** installed globally via npm:

```bash
npm install -g @rampage/knight
```

### You can scaffold a new project with:

```bash
knight init
```

This creates a pre-structured Knight project with client, server, and shared folders ready to go. You can also use it to generate new services and controllers.

> ✅ Tip: Run `knight --help` to explore all CLI options.

***

## Option 3: Download RBXL Binary

Prefer a plug-and-play Studio file? Download the `.rbxl` place file from the GitHub Releases:

👉 [Knight GitHub Releases](https://github.com/RAMPAGELLC/knight/releases)

Choose the latest version and open it directly in Roblox Studio to explore or build on top of it.

***

### Next Steps

Once Knight is installed, you can:

* [Create Your First Service](/documentation/what-are-services)
* [Understand the Lifecycle](/execution-model)
* [Explore Client vs Server Organization](/services-vs-controllers)

For help or to report issues, visit the [Knight GitHub Repository](https://github.com/RAMPAGELLC/knight).


# What are folders

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2FgzzTZdXsqnl7Ntx2Emdh%2FWhat%20are%20folders.jpg?alt=media&amp;token=cfaf1ea8-92a9-43cf-9b7e-2bb7d43171c9" alt=""><figcaption></figcaption></figure>

## What are folders?

Folders contain Services, Objects, etc you may create within your codebase. Everything within the folders will be automatically loaded on game start.

{% hint style="info" %}
Parent **ModuleScript** is loaded, **it's descendants does not**. You can have a infinite amount of folders.\*
{% endhint %}

## Where are they located?

There is 3 locations where the folders are located.

### The Server

This is located in `root/ServerStorage/Knight`

### The Client

This is located in `root/PlayerScripts/StarterPlayerScripts/Knight`

### The Shared

This is located in `root/ReplicatedStorage/Knight`

## How to use?

In this screenshot this is the default layout for **0.0.3,** you can create new folders and delete them as you please.

![](https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2FWUCf5HjqCTveh0iYOVcR%2Fimage.png?alt=media\&token=9e5d7d09-47d3-4c7c-b90f-984a7d89b913)

Services folders are used to contain services. Go here to learn about here;

{% content-ref url="/pages/d0JHMP06d1ls7j3MalTK" %}
[What are services?](/documentation/what-are-services)
{% endcontent-ref %}

You can create as much folders as you please such as a Objects folder, asset folder, etc. Or even folders under folders. There is no limit & it can be indexed the same.

```lua
Knight.MyCustomFolder.AnotherCoolFolder.AndAnother.CoolModule.bar()
```

## How you utilize folders and stylize is up to you!

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2F9kvEn3ScYwxkUeUrHLCl%2Fimage.png?alt=media&amp;token=73096cea-5cfa-420b-9d58-a3b842756111" alt=""><figcaption><p>Style example</p></figcaption></figure>

> Article & Art by vq9o


# What are services?

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2FzZwM5EQKVQDk4oljfpp0%2Fwhat%20are%20services.jpg?alt=media&amp;token=2a731f56-ec5f-4f5a-ad0d-c051e0e57c46" alt=""><figcaption></figcaption></figure>

## What are services?

Services are module scripts that serve a specific purpose within your experience. For example, you might have services dedicated to handling the user interface (UI), managing player points, or controlling game-specific logic.

## **Creating a Service**

To create a service, you’ll need to place a new `ModuleScript` in one of the designated Knight service folders based on its purpose:

* **Server-side services**: `Server`
* **Client-side services**: `Client`
* **Shared services**: `Shared`

## Default Functions

* **`Init()`**: Called during the initialization phase of the service. This is optional and typically used for setting up any necessary data or connections before the service starts.

  ```lua
  function Knight:Init()
      -- Initialization logic here
  end
  ```
* **`Start()`**: Called when the service is ready to begin its main functionality. This is also optional and is typically used to start processes like event listeners, timers, etc.

  ```lua
  function Knight:Start()
      -- Start logic here
  end
  ```
* **`Update(deltaTime)`**: Called every frame. This function is optional and is used for tasks that need to be updated regularly, such as animations or game logic.

  ```lua
  function Knight:Update(deltaTime)
      -- Frame update logic here
  end
  ```

## Configuration Options

* **`CanStart`**, **`CanUpdate`**, **`CanInit`**:

  These booleans determine whether the `Start()`, `Update()`, and `Init()` functions will be called.

{% hint style="success" %}
If you're using a third-party module and don't want Knight to call its default start functions or inject the framework, set `Standalone`to `true`. This will disable the metatable inject and other framework features to ensure it remains Standalone.
{% endhint %}

### Priority Startup

Folders named **"Database"** will have the first priority during initialization, followed by manual **"Priority"** set within the modu**le**. This is useful for ensuring that core game systems, such as data management, are loaded before other services.

{% hint style="info" %}
The default priority levels are as follows:

* Internal Services: 4
* Objects: 3
* Services: 2

You can adjust the startup priority by setting `Knight.Priority` to a specific number in the script. Higher priority numbers indicate an earlier startup.
{% endhint %}

## Additional Configuration

Optionally, if you have the instance named "**Init**" or "**EnivornmentInit**" or it has the collection tag "**KNIGHT\_IGNORE**" it will be automatically ignored and not inited/imported into the framework.&#x20;

{% hint style="warning" %}
We recommend using the Collection Tag only to mark Modules as in-active/disabled.
{% endhint %}

## Template

Each service in Knight follows a standard template structure:

```lua
local Knight = {
    -- Optional variables
    ServiceName = script.Name,
    ServiceData = {
        Author = "YourName",
        Description = "Description of what this service does"
    },
    
    -- Defaults to true if not specified.
    CanStart = true,
    CanUpdate = true,
    CanInit = true,
    
    -- Automatic .Priority calculation; this forces the dependencies to start before
    -- this service/controller does.
    Dependencies = {
        "shared/someAPI",
        "PlayerData"
    }
}

Knight.__index = Knight;

-- Optional
function Knight:Init()
    warn(self.ServiceName .. " Service Initialized!")
    
    -- For client services only
    print(self.Player.Name)  -- self.Player is an reference to the LocalPlayer.
    
    -- Access shared modules and functions
    self.Shared.SomeSharedModule:DoSomething()
    
    -- Access server or client-specific functionality
    self.Services.SomeOtherService:DoSomethingElse()
end

-- Optional
function Knight:Start()
    warn(self.ServiceName .. " Service Started!")
end

-- Optional
function Knight:Update(deltaTime)
    -- This is ran every frame; this works on server & client!
end

return Knight

```

> Article & Art by vq9o


# Getting a service

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2F4Qn2TNrHRvydYtSwDFhD%2FGetting%20a%20service.jpg?alt=media&amp;token=4ade6a92-61fa-480c-a692-909779a2e24d" alt=""><figcaption></figcaption></figure>

## Getting a service

In Knight, services can be accessed in a few different ways depending on how your configuration is set up. A key setting that impacts how you fetch services is the `CYCLIC_INDEXING_ENABLED` flag, which controls whether cyclic dependencies between services are allowed. By default, this setting is enabled.

## Accessing Services

Services in Knight can be accessed using either the `Knight.Import` method or the newer, more memory-efficient `Knight.GetService` method (introduced in version 0.0.7). These methods allow you to retrieve and interact with other services in your game.

However, if you have `CYCLIC_INDEXING_ENABLED` set to `true` (the default setting), you can also access other services directly by indexing the `Knight.Services` table within a service. This allows services to reference one another cyclically.

### Accessing Services with Cyclic Indexing

When `CYCLIC_INDEXING_ENABLED` is `true`, you can access another service directly from within your current service without worrying about manual importing or memory overhead from excessive service loading. This is useful for cases where services need to call each other's functions during their execution.

Here’s an example of how you can use cyclic indexing to call a function from another service:

```lua
local Service = {}
Service.__index = Service

function Service:Start()
    -- Cyclic indexing allows you to access another service directly
    local result = self.Services.OtherService:CallFunction()
    warn("Result from OtherService: ", result)
end

return Service
```

In this example:

* `self.Services.OtherService` refers to another service called `OtherService` Running on the same context level (Server or Client), to reference a shared Service/Object use `self.Shared`.
* `CallFunction()` is a method defined within the `OtherService` service.

## How Cyclic Indexing Works

With `CYCLIC_INDEXING_ENABLED` set to `true`, Knight's internal service loader allows services to reference one another via the `Services` table. This is beneficial when services are interdependent, such as when one service needs to trigger an event or call a function in another service.

## Considerations When Using Cyclic Indexing

{% hint style="danger" %}
While cyclic indexing can be convenient, it's important to note that in complex projects, heavy reliance on cyclic dependencies can increase the difficulty of managing your services. This is especially true if the dependency chain grows large. To avoid memory issues and potential bugs, Knight introduced `GetService` as an alternative.

On large experiences such as the Rosource Project, the Emergency Response Series, etc we average around \~3GB Client Memory with Cyclic enabled. Please note this specifically with the large-coldebase with all gameplay features.
{% endhint %}

## Disabling Cyclic Indexing

If you prefer to avoid cyclic dependencies altogether, you can disable cyclic indexing by setting `CYCLIC_INDEXING_ENABLED` to `false` in your `KNIGHT_CONFIG.lua` file. When cyclic indexing is disabled, services must be explicitly retrieved using either `Knight.Import` or `Knight.GetService`, and attempts to access services via cyclic indexing will fail.

Here’s how you disable cyclic indexing:

```lua
return {
    CYCLIC_INDEXING_ENABLED = false
}
```

With cyclic indexing disabled, you would need to retrieve services like this:

```lua
local Knight = {}

function Knight:Start()
    local OtherService = Knight:GetService("OtherService")
    warn(OtherService:CallFunction())
end

return Knight
```

{% hint style="info" %}

#### When cyclic indexing is disabled you will still be able to index the following:

* Player
* Enum
* initStart
* Inited
* KnightCache
* GetService
* Remotes
  {% endhint %}

#### Best Practices

* **Use Cyclic Indexing Sparingly**: While convenient, cyclic indexing can lead to tightly coupled services. For better maintainability, consider using `GetService` or `Import` to explicitly manage dependencies.
* **Optimize for Memory Usage**: In large games with many services, consider disabling cyclic indexing and using `GetService` for a more memory-efficient approach.
* **Keep Dependencies Clear**: Regardless of whether cyclic indexing is enabled or disabled, ensure that your services have well-defined responsibilities to avoid confusion and unintended dependencies.

> Article & Art by vq9o


# Creating a library

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2Fzv3XnozR32kL7TBcATJs%2FCreating%20a%20library.jpg?alt=media&amp;token=b45f9049-0d0b-4f10-b544-e49ed41355cb" alt=""><figcaption></figcaption></figure>

{% hint style="danger" %}
Documentation for creating a internal Knight Library (Knight.{libraryname}) is coming soon. Contribution is welcomed!!
{% endhint %}


# AGF/Knit Transition to Knight

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2F9FLDYVW7JSib7DXqfuxc%2FAGFKnitTransition.jpg?alt=media&amp;token=9ce094cc-6470-46ba-b394-7cf765298040" alt=""><figcaption></figcaption></figure>

## **Introduction**

As Roblox developers, you may have been using frameworks like AeroGameFramework (AGF) or Knit to structure your projects. Both of these frameworks follow a modular approach, offering client-server communication patterns, service organization, and utilities that ease game development. Now, if you're transitioning to the **Knight framework**, this article will guide you through key differences, similarities, and how to adjust your workflow to fit the Knight framework’s approach.

## **Why Transition to Knight?**

The **Knight framework** offers a flexible, modular, and scalable structure tailored for Roblox development. It emphasizes strong typing, configuration through enums and types, and integrates easily with modern tools. Here are some reasons you might consider transitioning:

* **Enhanced modularity** with well-defined service and object separation.
* **Configurable behaviors** using `KNIGHT_CONFIG`, `KNIGHT_ENUM`, and `KNIGHT_TYPES`.
* **Improved organization** of shared, client, and server scripts across the game's services.

## **Key Concepts in Knight**

Before jumping into code, let’s go over some key concepts in the Knight framework:

1. **Services**: Just like in AGF or Knit, Knight uses **Services** to structure server-side and shared logic. Services are stored under `ReplicatedStorage/Knight/Services` for shared services and `ServerScriptService/Knight/Services` for server-only services.
2. **Objects**: These are reusable components, typically representing specific game logic that can be instantiated multiple times. Knight encourages storing these under `ReplicatedStorage/Knight/Objects`.
3. **Configurations and Types**: Knight makes heavy use of configuration files like `KNIGHT_CONFIG.lua` and `KNIGHT_TYPES.lua`, which define custom behaviors, types, and constants to be reused across the codebase.
4. **Packages**: Knight uses a `Packages` folder structure that contains utilities or third-party packages. This setup is similar to how AGF or Knit organizes third-party dependencies.

## **Transitioning from AGF/Knit to Knight**

Let’s break down the transition by focusing on core areas like **service management**, **client-server communication**, and **initialization logic**.

***

## **1. Service Management in Knight**

In AGF/Knit, services are organized in `ServerScriptService` or `ReplicatedStorage` (for shared services). Similarly, Knight organizes services across these locations, but with a focus on stronger separation between server-only and shared services.

**AGF/Knit Example:**

```lua
-- KnitService Example
local PointsService = Knit.CreateService {
    Name = "PointsService",
    Client = {},
}

function PointsService:AwardPoints(player, amount)
    -- Logic to award points to the player
end
```

**Knight Example:**

In Knight, services are also module-based and are organized under `Knight/Services`. Here's a transition example of how you would define a service in Knight:

```lua
-- KnightService
local PointsService = {}

function PointsService:AwardPoints(player, amount)
    -- Logic to award points to the player
end
```

## **2. Client-Server Communication**

In AGF/Knit, client-server communication is handled via `RemoteFunction` abstractions like `Client` tables within services. Knight, on the other hand, exposes **remote functions** dynamically through the `Knight.Remotes` API.

**AGF/Knit Example:**

```lua
-- Server-side Knit service with a remote method
PointsService.Client.GetPoints = function(self, player)
    return PointsService:GetPlayerPoints(player)
end

-- Client-side Knit Service
function ClientPointService:Start()
    local points = Knit.GetService("PointsService"):GetPoints()
end
```

**Knight Example:**

In Knight, you would dynamically expose server functions to the client using the **Exposed-Server Functions API**. Here’s how you would achieve the same functionality:

```lua
-- Server-side Knight Service
local PointsService = {}
PointsService.Client = {}

function PointsService.Client:GetPoints(player)
    return PointsService:GetPlayerPoints(player)
end

-- Client-side Knight Service
function ClientPointService:Start()
    local points = self.Server.PointsService:GetPoints()
end
```

## **3. Initialization and Configuration**

Both AGF and Knit have initialization flows, but in Knight, you have more configuration options using the `KNIGHT_CONFIG.lua` and `KNIGHT_TYPES.lua` files to specify game-wide settings and behaviors.

**AGF/Knit Example:**

```lua
Knit.Start():Then(function()
    print("Knit started")
end):Catch(warn)
```

**Knight Example:**

<pre class="language-lua"><code class="lang-lua"><strong>require(game:GetService("ReplicatedStorage").Packages.Knight).Core.Init()
</strong></code></pre>

***

## **Adapting to Knight’s Structure**

As you transition to Knight, it’s important to understand its directory structure and how services, objects, and configurations are separated:

* **Server-only services**: `src/ServerScriptService/Knight/Services`
* **Shared services**: `src/ReplicatedStorage/Knight/Services`
* **Objects (reusable game logic)**: `src/ReplicatedStorage/Knight/Objects`
* **Configuration files**: `src/ReplicatedStorage/KNIGHT_CONFIG.lua`, `KNIGHT_ENUM.lua`, `KNIGHT_TYPES.lua`

This clear separation of concerns allows for easier management of client-server logic and reusable components. We highly recommend going to [Welcome](/documentation/welcome)to read further about our framework!


# Exposed-Server Functions

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2FBgGsgZJmWHqnsiL6WVHi%2FExposed-server%20functions.jpg?alt=media&amp;token=f739f3f7-f319-49e5-a98b-970e84ceacec" alt=""><figcaption></figcaption></figure>

## **Overview**

In many modern Roblox frameworks, such as AeroGameFramework (AGF) or Knit, we expose server-side functions to the client through a structured and dynamic API. This pattern allows client scripts to access and invoke specific server functions seamlessly, mimicking the way you'd call local functions. These exposed server functions simplify client-server communication, ensuring that server-side logic can be invoked safely and efficiently from the client without manual remote event handling.

## **What Are Exposed-Server Functions?**

Exposed-server functions are server-side functions that are exposed to clients for remote invocation. These functions are wrapped around `RemoteFunction`s, allowing clients to call server-side logic just like they would call a local method.

### **Example Structure:**

```lua
-- Client-Side Example
local points = self.Server.PointsService:GetLocalPoints()
print("Received points:", points)
```

In this example, `PointsService` is a server-side service, and `GetLocalPoints` is a remote function exposed to the client. The client can directly call this function, and the server handles the logic.

## **How Exposed-Server Functions Work**

Exposed-server functions rely on a dynamic system that abstracts remote communication through a combination of **metatables**. This system allows developers to access server services and their exposed functions as if they were local.

### **Key Concepts:**

* **Service Name**: Represents the name of the service that contains the server logic (e.g., `PointsService`).
* **Event/Function Name**: Represents the name of the server function that you want to call remotely (e.g., `GetLocalPoints`).
* **Remote Function**: A `RemoteFunction` object on the server that handles requests from the client and returns a result.

## **Client-Side Usage**

On the client-side, you access these exposed functions via the `self.Server` object, which allows you to call server functions as if they were local.

### **Example:**

```lua
-- Client-side
local points = self.Server.PointsService:GetLocalPoints() -- Calling the exposed server function
print("Received points:", points) -- Output the result
```

## **Server-Side Implementation**

On the server, the functions that the client can call are registered and exposed through a dynamic API. These functions are typically defined within services and then registered as RemoteFunctions that the client can invoke.

### **Server-Side Example:**

```lua
local PointsService = {}
PointsService.Client = {}

-- Define a server-side function exposed to the client

-- Do note, everything ran inside this function is on the Server runtime.
-- Also do not worry, important variables like passwords are not exposed 
-- as we use roblox's networking solutions
function PointsService.Client:GetLocalPoints(Player: Player)
    -- This function is invoked by the client
    -- You can implement your logic here, such as fetching data from a database
    local points = 100 -- Example points logic
    return points -- Return the result to the client
end

return PointsService
```

In the example above:

* **PointsService** is the service.
* **GetLocalPoints** is the function within the service that the client can call.
* The function handles server-side logic, such as retrieving the player's points, and returns the result to the client.

#### **Why Use Exposed-Server Functions?**

1. **Simplified Client-Server Communication**:
   * The client doesn't need to manually handle RemoteFunction objects. Instead, they can call server functions as if they were local, making the code easier to read and manage.
2. **Dynamic and Flexible**:
   * Since service and function names are dynamically resolved using metatables, this system allows for easy scaling and customization. You can add new services and functions without changing much client-side code.

#### **Common Use Cases**

* **Fetching Player Data**:

  * Clients often need to request data stored on the server (e.g., player points, inventory, etc.).

  ```lua
  local points = self.Server.PointsService:GetLocalPoints()
  ```
* **Server-side Calculations**:

  * Sometimes the client may need to request complex calculations from the server.

  ```lua
  local result = self.Server.MathService:CalculateDistance(pointA, pointB)
  ```
* **Interacting with Game State**:

  * Clients can send requests to update the game state, such as interacting with NPCs or triggering server-side events.

  ```lua
  self.Server.NPCService:TriggerInteraction(npcId)
  ```


# Configuring Knight

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2F7EiucZgDRMPbrnqzmd9S%2FConfiguring%20Knight.jpg?alt=media&amp;token=84918a02-f7de-4228-8197-82087758f51b" alt=""><figcaption></figcaption></figure>

## Configuring Knight

The `KNIGHT_CONFIG.lua` file is the core configuration file for the Knight framework, allowing developers to customize Knight’s behavior and optimize it for specific project requirements. This configuration file is located in `src/ReplicatedStorage` and contains settings that affect how services and other aspects of Knight operate.

## Setting Up `KNIGHT_CONFIG.lua`

By default, the `KNIGHT_CONFIG.lua` file might look like this:

```lua
-- Get essential services for later use
local HttpService = game:GetService("HttpService")
local RunService = game:GetService("RunService")

-- Define the configuration table for the Knight framework
local config

config = {
    -- Specifies the time limit (in seconds) before considering a service to be taking too long to load
    TOO_LONG_LOAD_TIME = 20,

    -- Enables or disables cyclic indexing between services, allowing services to reference each other directly
    CYCLIC_INDEXING_ENABLED = true,

    -- Keeps shared resources accessible even if cyclic indexing is disabled
    KEEP_SHARED_ON_CYCLIC_DISABLE = true,

    -- Disables waiting for non-essential services to load during initialization
    DO_NOT_WAIT = true,

    -- Enables logging of startup information for debugging and diagnostics
    LOG_STARTUP_INFO = true,

    -- Enables tracking if startup is taking too long; false means no warnings or errors for long startups
    TRACKBACK_ON_STARTUP_TOOK_TOO_LONG = false,

    -- If true, the framework will automatically report any issues to a predefined external service
    AUTOMATIC_REPORT_FRAMEWORK_ISSUES = false,

    -- Function to report issues automatically when AUTOMATIC_REPORT_FRAMEWORK_ISSUES is enabled
    -- Only runs on the server to avoid unnecessary client requests
    REPORT_FUNC = function(Environment: string, Issue: string)
        -- Check if automatic issue reporting is enabled
        if not config.AUTOMATIC_REPORT_FRAMEWORK_ISSUES then
            return -- Exit if reporting is disabled
        end
        -- Ensure the code is running on the server before proceeding with the report
        if RunService:IsServer() then
            -- Attempt to send the issue report asynchronously using HTTP POST
            pcall(function()
                HttpService:PostAsync(
                    "https://api.vq9o.com/knight-issues.php",  -- Endpoint for reporting issues
                    HttpService:JSONEncode({ -- Encode the report as JSON
                        GAME_ID = game.GameId,  -- Include the game ID in the report
                        PLACE_ID = game.PlaceId, -- Include the specific place ID
                        ENVIRONMENT = Environment,  -- Include the environment (e.g., development/production)
                        ISSUE = Issue,  -- Include a description of the issue
                    })
                )
            end)
        end
    end,

    -- Specifies whether the game should shut down if the library initialization fails
    SHUTDOWN_ON_LIBRARY_FAIL = true,

    -- The delay (in seconds) before kicking players after a shutdown is triggered due to library failure
    SHUTDOWN_KICK_DELAY = 20,

    -- Defines the startup priorities for various Knight components
    -- Internal components have the highest priority, followed by objects, then services
    STARTUP_PRIORITY = {
        ["Internal"] = 4,  -- Priority level 4 (highest) for internal components
        ["Objects"] = 3,   -- Priority level 3 for objects
        ["Services"] = 2,  -- Priority level 2 for services
    },
}

-- Return the configuration table to be used throughout the Knight framework
return config

```

This configuration file returns a table containing various settings. These settings can be customized to control how Knight behaves within your project.

## Key Configuration Options

Let’s break down each of these configuration settings:

1. **`TOO_LONG_LOAD_TIME`**\
   This setting defines the maximum time (in seconds) that a service can take to load before it is flagged as taking too long. This is useful for identifying performance bottlenecks during game startup.
2. **`CYCLIC_INDEXING_ENABLED`**\
   This flag allows services to cyclically reference each other via the `Knight.Services.ServiceName` pattern. When enabled (the default), services can directly call other services within the framework, even if they depend on each other. Disabling this setting may improve performance in larger projects by reducing memory overhead.
3. **`KEEP_SHARED_ON_CYCLIC_DISABLE`**\
   This option retains shared services and data even if `CYCLIC_INDEXING_ENABLED` is disabled. This is particularly useful when you still want to allow shared resources to be accessible while preventing full cyclic dependencies between services.
4. **`DO_NOT_WAIT`**\
   When enabled, Knight will not wait for non-essential services to load during initialization. This can help speed up game startup times by skipping non-critical services that can be started later or asynchronously.
5. **`LOG_STARTUP_INFO`**\
   This flag enables logging of startup information. If set to `true`, Knight will log details about service startup, which can be useful for debugging and performance analysis.
6. **`TRACKBACK_ON_STARTUP_TOOK_TOO_LONG`**\
   When enabled, this setting tracks whether startup is taking too long and logs warnings or errors if necessary. This can help identify potential bottlenecks in the game’s loading process.
7. **`AUTOMATIC_REPORT_FRAMEWORK_ISSUES`**\
   If this option is set to `true`, Knight will automatically report any issues encountered by the framework to an external endpoint. This is useful for tracking bugs or problems in real time. Reporting only occurs on the server side to avoid unnecessary client requests.
8. **`REPORT_FUNC`**\
   This function is used to send issue reports to a predefined external service. The function collects environment-specific data (such as the game’s ID and the place’s ID) and sends a JSON-encoded report to the endpoint. This function only runs when `AUTOMATIC_REPORT_FRAMEWORK_ISSUES` is enabled, and only on the server to ensure efficiency.
9. **`SHUTDOWN_ON_LIBRARY_FAIL`**\
   This option ensures that the game will automatically shut down if the Knight framework fails to initialize. This prevents the game from running in an incomplete or broken state.
10. **`SHUTDOWN_KICK_DELAY`**\
    Defines the delay (in seconds) before kicking players after a shutdown is triggered due to a Knight library failure. This gives players a buffer period before being disconnected.
11. **`STARTUP_PRIORITY`**\
    This table defines the priority order for starting Knight’s components. Higher numbers indicate higher priority, meaning components with higher priority numbers are started first. This is useful when certain components (e.g., internal systems) need to be initialized before others (e.g., services).

### Example Usage Scenarios

#### **Debugging Startup**

To debug startup performance, you might want to enable both `LOG_STARTUP_INFO` and `TRACKBACK_ON_STARTUP_TOOK_TOO_LONG`. These settings will log all startup activities and notify you if any services are taking too long to load:

```lua
return {
    LOG_STARTUP_INFO = true,
    TRACKBACK_ON_STARTUP_TOOK_TOO_LONG = true,
}
```

#### **Reporting Framework Issues**

If you want to automatically report framework issues in production environments but not during development, you can use the following configuration:

```lua
local isDevelopment = false  -- Set this flag based on your environment

return {
    AUTOMATIC_REPORT_FRAMEWORK_ISSUES = not isDevelopment,  -- Only report in production
}
```

#### **Optimizing Startup Times**

To speed up startup times by only loading critical services immediately, you could enable `DO_NOT_WAIT`:

```lua
return {
    DO_NOT_WAIT = true,
}
```

## Configuring Knight to Match Your Game's Needs

Configuring Knight is essential for customizing the framework to match your game’s needs. By adjusting the `KNIGHT_CONFIG.lua` file, you can control core features like service initialization, debugging, and memory optimization.

Whether you’re working on a small-scale game or a massive online experience, the flexibility provided by Knight’s configuration allows you to fine-tune performance, control service behavior, and ensure your game operates smoothly under various conditions.

## Best Practices for Configuration

* **Start Simple**: When first starting out, it’s a good idea to keep the configuration simple with the default settings and then gradually introduce more advanced options like priority folders and environment-specific settings as your game grows.
* **Test Configurations**: If you disable `CYCLIC_INDEXING_ENABLED`, be sure to test all services thoroughly to ensure they still function correctly with `GetService`.
* **Use DebugMode Wisely**: Enable `DebugMode` during development to help identify any issues or service dependencies. Remember to disable it for production to reduce unnecessary logging.

> Article & Art by vq9o


# KPM Integration: Knight Package Manager CLI

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2FCqoViGytrrjS7nex1aC8%2Fkpm.jpg?alt=media&amp;token=c4405cc7-8a07-4d00-8c38-1c6df896665c" alt=""><figcaption></figcaption></figure>

## KPM Integration: Knight Package Manager CLI

KPM (Knight Package Manager) is a command-line tool developed in TypeScript and distributed as an npm package (`kpm.client`). Its purpose is to streamline the process of managing Knight packages, such as `Cmdr`, in a structure similar to npm. With KPM, you can install, update, and uninstall Knight packages from your desktop CLI, allowing for easy management of game development dependencies.

This article will guide you through setting up KPM and provide example usage for managing packages within your Knight framework projects.

## Installing KPM

To get started with KPM, you’ll need to install it globally via npm. Ensure you have Node.js and npm installed on your system.

```bash
npm install -g kpm.client
```

Once installed, you can access KPM through your command line using the `kpm` command.

## Example Usage of KPM

Let’s look at a basic example of using KPM in your desktop CLI.

```bash
C:\Users\administrator> kpm
  _  ______  __  __        _ _            _
 | |/ /  _ \|  \/  |   ___| (_) ___ _ __ | |_
 | ' /| |_) | |\/| |  / __| | |/ _ \ '_ \| __|
 | . \|  __/| |  | | | (__| | |  __/ | | | |_
 |_|\_\_|   |_|  |_|  \___|_|_|\___|_| |_|\__|

Copyright (c) 2024 RAMPAGE Interactive.
Written by vq9o and Contributor(s).

Knight Package Manager CLI
```

### Basic Commands

Here are some of the most commonly used commands in KPM, along with example usage.

#### **1. Installing a Package**

To install a Knight package (such as `Cmdr`), use the `install` command. You can specify the package and an optional version:

```bash
kpm install cmdr
```

This will install the latest version of the `Cmdr` package. You can also specify a version:

```bash
kpm install cmdr 1.2.3
```

This installs version `1.2.3` of the `Cmdr` package.

#### **2. Uninstalling a Package**

To uninstall a package, use the `uninstall` command:

```bash
kpm uninstall cmdr
```

This removes the `Cmdr` package from your Knight project.

#### **3. Updating Packages**

To update all installed packages to their latest versions, use the `update` command:

```bash
kpm update
```

You can also update a specific package by specifying its name:

```bash
kpm update cmdr
```

This updates only the `Cmdr` package to the latest version.

#### **4. Checking for Updates**

To check if a specific package has a new version available without installing the update, use the `check-update` command:

```bash
kpm check-update cmdr
```

This will display information about whether a new version of the `Cmdr` package is available.

#### **5. Outputting the Manifest of a Package**

To view the manifest (for example a NPM package.json) of a specific package, use the `output-manifest` command:

```bash
kpm output-manifest cmdr
```

This will print the package’s manifest to the console, showing details such as the version, dependencies, and other metadata.

#### **6. Publishing Packages**

KPM also allows you to publish packages. To open the KPM publish form in your default browser, use the `publish` command:

```bash
kpm publish
```

This will redirect you to the form where you can submit your package to the KPM repository.

#### **7. Package Count**

To get a count of all installed packages, use the `count` command:

```bash
kpm count
```

This will display the total number of packages installed in your project.

### Advanced Commands

KPM offers several advanced commands to help you further customize and manage your environment.

#### **1. Setting the Installation Path**

By default, KPM installs packages in the current running directory, but you can change this location using the `set-path` command:

```bash
kpm set-path C:/MyGame/KnightPackages
```

This sets the new path where packages will be installed.

To verify the current path, use:

```bash
kpm get-path
```

#### **2. Unsafe Mode**

KPM has a feature called "unsafe mode," which allows you to enable or disable certain operations that may pose risks to your game’s stability. You can toggle unsafe mode using the `unsafemode` command:

```bash
kpm unsafemode enable
```

To disable it:

```bash
kpm unsafemode disable
```

#### **3. Reinstalling KPM Client**

If you need to reinstall or update the KPM client to the latest version, you can use the `npm` command:

```bash
kpm npm
```

This command will uninstall and reinstall KPM to ensure you have the latest version of the CLI.

#### **4. Logging In**

To access certain features, such as downloading private packages, you need to be logged in. Use the `login` command to log in and save your authentication key:

```bash
bkpm login
```

Follow the prompts to log in securely.

## Example Workflow

Here’s an example of a typical workflow using KPM in a project:

1. **Install Cmdr**:

   ```bash
   kpm install cmdr
   ```
2. **Set a Custom Installation Path**:

   ```bash
   kpm set-path C:/MyGame/KnightPackages
   ```
3. **Check for Updates for Cmdr**:

   ```bash
   kpm check-update cmdr
   ```
4. **Update All Packages**:

   ```bash
   kpm update
   ```
5. **Output Manifest for Cmdr**:

   ```bash
   kpm output-manifest cmdr
   ```
6. **Log in to KPM**:

   ```bash
   kpm login
   ```

This workflow allows you to efficiently manage the packages used in your Knight framework project without leaving your desktop CLI.


# Framework Profiling

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2FOD1hAJlqM4tnx7tk7pAV%2FFramework%20Profiling.jpg?alt=media&amp;token=6ef6cc76-1ac3-4175-b033-3d5f67f8076f" alt=""><figcaption></figcaption></figure>

{% hint style="danger" %}
Article is not completed, and KnightProfiler is unreleased software currently under going rigorous internal testing.
{% endhint %}

## Framework Profiling

Profiling a complex framework like Knight can be challenging due to the way the framework initializes and manages its components. Traditional profiling methods may not provide the granularity or context needed to fully understand the performance characteristics of services and operations within the framework. However, there is a dedicated tool that makes this process much easier: `KnightProfiler`.

In this article, we’ll discuss the difficulties of profiling the Knight framework and introduce `KnightProfiler` as the solution to gather meaningful performance insights.

## The Challenge of Profiling Knight

The Knight framework is designed to initialize services, shared modules, and core components dynamically, based on the context in which it operates (server or client). Due to this dynamic nature, traditional profiling tools may struggle to pinpoint bottlenecks, particularly during the initialization phase.

### For example:

* **Service Initialization**: Services in Knight may depend on other services or shared modules, causing their initialization to be asynchronous and conditional.
* **Dynamic Imports**: The use of dynamic imports and cyclic dependencies makes it harder for profiling tools to capture performance metrics accurately at the exact moment they are required.
* **Contextual Execution**: The behavior of the framework may vary depending on whether it is running on the client or server, adding an additional layer of complexity to profiling efforts.

## Introducing KnightProfiler

To overcome these challenges, you can use **KnightProfiler**, a purpose-built tool designed to profile the Knight framework with minimal setup. `KnightProfiler` captures performance data during initialization, service execution, and other critical operations within the framework, providing you with the insights necessary to optimize your game.

You can get `KnightProfiler` at the following repository:

* **KnightProfiler**: <https://github.com/RAMPAGELLC/KnightProfiler>

### Features of KnightProfiler

* **Detailed Service Profiling**: Track the initialization time and execution performance of individual services within the Knight framework.
* **Granular Module Profiling**: Monitor how long specific shared modules or components take to load and execute, helping identify performance bottlenecks.
* **Contextualized Reports**: Get profiling data that is contextualized based on whether it’s running in the client, server, or shared environments, allowing you to optimize based on the specific context of your game.
* **Low Overhead**: Designed to work seamlessly with Knight without adding significant performance overhead, ensuring that your profiling data is accurate and your game remains performant.

### Installing and Using KnightProfiler

1. **Clone or Download KnightProfiler**: Start by cloning or downloading the repository from GitHub.
   * GitHub Repo: [KnightProfiler](https://github.com/RAMPAGELLC/KnightProfiler)
2. **Integrate with Knight**: Follow the instructions in the repository to integrate KnightProfiler into your existing Knight framework setup. The profiler is designed to hook into Knight’s initialization and service management process with minimal changes to your codebase.
3. **Run Your Game**: Once KnightProfiler is integrated, run your game as you normally would. KnightProfiler will automatically begin capturing performance data during the game’s initialization and as services execute.
4. **Analyze the Data**: After you’ve run your game with KnightProfiler, review the performance reports it generates. You can use this data to:
   * Identify services that are taking too long to initialize.
   * Track down shared modules that may be causing bottlenecks.
   * Analyze how different services interact with each other and pinpoint any inefficiencies.

### Example Usage of KnightProfiler

Here’s a quick example of how to set up and use KnightProfiler after integrating it into your game:

<pre class="language-lua"><code class="lang-lua">-- Copyright (c) 2024 RAMPAGE Interactive
-- Written by vq9o

local ReplicatedStorage= game:GetService("ReplicatedStorage")
local HttpService = game:GetService("HttpService")

local KnightProfiler= require(ReplicatedStorage.Packages.KnightProfiler)
local Knight = require(ReplicatedStorage.Packages.Knight)

-- Start profiling services
KnightProfiler:Start()

-- Initialize Knight Framework
local KnightInstance, KnightAPI = Knight.Core:Init()

task.wait(10)

-- Stop profiling after initialization is complete and 10 seconds has passed
KnightProfiler:Stop()

-- Output the profiling report to the console to save it for later analysis
local UUID: string = HttpService:GenerateGUID(false)

KnightProfiler:GenerateReport(UUID)

repeat
<strong>    task.wait()
</strong><strong>until KnightProfiler:ReportIsCompleted(UUID)
</strong>
-- Force any and all connected clients to quit game.
KnightProfiler:Quit()
</code></pre>

### Best Practices for Profiling with KnightProfiler

* **Profile Early and Often**: Start profiling your game as early as possible during development. This will help you catch performance issues before they become ingrained in your game’s architecture.
* **Focus on Bottlenecks**: Use KnightProfiler to focus on specific areas of your game that are underperforming, such as services that are slow to start or shared modules that are being loaded too frequently.
* **Adjust Based on Context**: Pay close attention to the differences in performance between the client and server environments, as bottlenecks may occur in one environment but not the other.


# Services vs Controllers

In the Knight Framework, the architecture is centered around **Services**. These are modules that encapsulate your game’s business logic, game state, and communication between the client and server.

While other frameworks often refer to client-side modules as **Controllers** for readability and clarity, under the hood, **everything is just a Service**.

***

## What is a Service?

A **Service** in Knight is any module placed in:

* `src/ServerStorage/Knight/Services` (server-side)
* `src/StarterPlayer/StarterPlayerScripts/Knight/Services` (client-side)
* `src/ReplicatedStorage/Knight/Shared/Services` (shared)

Services are automatically loaded and managed by the framework, and can depend on other Services via `self.Services`.

### Examples:

<pre class="language-lua"><code class="lang-lua">-- Server-side Service
local Players = game:GetService("Players")

local PlayerService= {}
PlayerService.__index = PlayerService;

function PlayerService:Start()
	Players.PlayerAdded:Connect(function(player)
		print("Player joined:", player.Name)
<strong>	end)
</strong>end

return PlayerService
</code></pre>

```lua
-- Client-side "Controller" (Still a Service under the hood)

local CameraController = {}
CameraController.__index = CameraController;

function CameraController:Start()
	print("Camera controller started")
end

return CameraController
```

***

## Why Call Them "Controllers" on the Client?

While technically still Services, developers often call client-side services **Controllers** because:

* They manage *input*, *UI*, *camera*, *audio*, and other *player-facing systems*
* It helps mentally separate **game logic** (server) from **player experience** (client)
* It mirrors common frontend/backend naming conventions

This naming convention is **optional** and purely for developer ergonomics.

***

## Best Practices

### 1. **Keep Logic Scoped to the Right Context**

* Server Services should **never** assume presence of GUI elements or player input.
* Client Services (aka Controllers) should **never** mutate global game state or kick players.

### 2. **Name Clearly and Consistently**

Use suffixes if it helps readability:

```lua
-- Server
PlayerService
InventoryService

-- Client
CameraController
HUDController
InputController
```

### 3. **Shared Services Are Powerful**

If you have logic that both client and server need (like data validation, math utilities, enum definitions), place them in `Knight/Shared/Services`.

Avoid placing business logic here — shared services should be **deterministic and stateless** when possible.

***

### Summary

| Concept        | Definition                                              |
| -------------- | ------------------------------------------------------- |
| Service        | A module that runs logic in the Knight Framework        |
| Controller     | A naming convention for client-side services            |
| Shared Service | A deterministic module usable by both client and server |

Ultimately, whether you call them Services or Controllers — **they all follow the same lifecycle** and are powered by the same Service system behind the scenes.

Stick to what makes sense for your team and stay consistent.


# Execution Model

## Execution Model

The execution model of Knight defines the flow of operations of the Knight framework.

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2Fmdh5bqWzlgHyZg4uN2ZW%2Fimage.png?alt=media&amp;token=cd4f7041-64a3-4034-bf73-5795b229b81c" alt=""><figcaption></figcaption></figure>


# Intellisense

{% hint style="success" %}
Documentation coming soon!
{% endhint %}


# Checking if the framework has loaded

You can check if the client or server has finished loading by checking the `ClientLoaded` and `ServerLoaded` attribute on `ReplicatedStorage`.


# Error Handling

## About

In knight error handling is handled by the framework with some basic logging. You can hook into this through the `OnError` event to log them externally to a API like [Sentry](https://sentry.io/welcome/).

#### We recommend using [sentry-roblox by devSparkle](https://devsparkle.me/sentry-roblox/) and integrating it with Knight.

## Examples

```lua
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Packages = ReplicatedStorage:WaitForChild("Packages")

local require = require(require(Packages:WaitForChild("knight")).import)
local errorHandler = require("core/class/ErrorHandler")

(errorHandler.OnError :: BindableEvent).Event:Connect(function(errorPayload: {
    runType: string;
    isShared: boolean;
    child: Instance;
    trace: string;
    message: string;
    timestamp: number;
})
    -- Your custom error handling here
end)
```


# Examples


# Example Service/Controller

```lua
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Packages = ReplicatedStorage:WaitForChild("Packages")

local KNIGHT_TYPES = require(ReplicatedStorage:WaitForChild("KNIGHT_TYPES"))
local require = require(require(Packages:WaitForChild("knight")).import)

local ClientPointsService = {} :: KNIGHT_TYPES.KnightClass

function ClientPointsService:Start()
    warn("ClientPointsService has started!")
    task.wait(1)
    warn("Got local points:", ClientPointsService.Server.PointService:GetLocalPoints())
    warn("Import test - GetService()", self:GetService("TestClientService"):foo())
    warn("Require test", require("TestClientService"):bar())
end

function ClientPointsService:Init()
    warn("ClientPointsService has inited!")
    warn("Starting error logger test 3000")
    
    local b = false
    assert(b == true, "expected b to be true")

    task.delay(0.25, function()
        warn("Starting error logger test 2")
        local b = false
        assert(b == true, "expected b to be true")
    end)
    
    warn(self)
end

return ClientPointsService

--------------------------------------------------------------------

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local KNIGHT_TYPES = require(ReplicatedStorage:WaitForChild("KNIGHT_TYPES"))

local TestClientService = {} :: KNIGHT_TYPES.KnightClass

function TestClientService:foo()
	warn("TestClientService has imported!")

    return self;
end

function TestClientService:bar()
    return "Hi mom from custom-require!";
end

return TestClientService
```


# Knight External API

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2FOaG9nmySRZlwdy4Eo8AP%2Fknight%20external%20api.jpg?alt=media&amp;token=251164b6-f18c-49b5-b1ec-cbc702017a98" alt=""><figcaption></figcaption></figure>

The `ReplicatedStorage.Packages.Knight` module is the core of the Knight framework. It provides essential functions for managing the framework's initialization, service access, logging, and module imports. This module is the backbone of the Knight system, handling both server-side and client-side logic depending on the environment/context in which it is run.

## Accessing the Knight API Module

To use the `Knight` module, you first need to require it:

```lua
local Knight = require(game.ReplicatedStorage.Packages.Knight)
```

Once you have access to the module, you can use its various core functions.

#### Functions Overview

***

### `Knight.Core.Log(Type: string, ...)`

**Description**:\
Logs messages to the console, with support for different log levels (`print`, `warn`, `error`). This function prefixes the log with the Knight framework version for easy identification.

**Usage**:

```lua
Knight.Core.Log("print", "Knight Framework has started.")
```

**Parameters**:

* `Type: string`: The type of log (`"print"`, `"warn"`, `"error"`).
* `...`: The message or messages to log.

***

### `Knight:PrintVersion()`

**Description**:\
Prints the current version of the Knight framework to the console. Useful for tracking which version of the framework is currently running.

**Usage**:

```lua
Knight:PrintVersion()
```

**Parameters**:\
None.

**Returns**:\
None.

***

### `Knight.Core.Import(Path: string)`

**Description**:\
Imports a module based on the specified path. This function handles importing from different parts of the framework (`Knight/Shared`, `Knight/Client`, `Knight/Server`, etc.) and external systems like KPM.

**Usage**:

```lua
local Module = Knight.Core.Import("Knight/Shared/MyModule")
```

**Parameters**:

* `Path: string`: The path to the module you want to import.

**Returns**:\
The module at the specified path, or throws an error if the path is invalid or not found.

***

### `Knight.Core:GetStorage(IsShared: boolean | nil)`

**Description**:\
Fetches the appropriate Knight storage context based on whether the request is for shared storage or not. This method is responsible for locating the storage in the server (`ServerStorage`) or client (`PlayerScripts`), or the shared space (`ReplicatedStorage`).

**Usage**:

```lua
local Storage = Knight.Core:GetStorage(true)  -- Fetch shared storage
```

**Parameters**:

* `IsShared: boolean | nil`: If `true`, fetches the shared storage from `ReplicatedStorage`. If `false` or `nil`, fetches the storage specific to the environment (server or client).

**Returns**:\
The storage context (`ServerStorage`, `PlayerScripts`, or `ReplicatedStorage`).

***

### `Knight.Core:GetShared()`

**Description**:\
Deprecated. Fetches shared storage. Use `Knight.Core:GetStorage(true)` instead.

**Usage**:

```lua
local SharedStorage = Knight.Core:GetShared()
```

**Parameters**:\
None.

**Returns**:\
The shared storage context (`ReplicatedStorage`).

{% hint style="danger" %}
This method is deprecated and will print a warning recommending the use of `Knight.Core:GetStorage(true)`.
{% endhint %}

***

### `Knight.Core:Init()`

**Description**:\
Initializes the Knight framework, setting up the internal environment and populating the `_G.Knight` global variable with the API and shared resources. This method also ensures that the required "Init" module is present in the storage context and loads it.

**Usage**:

```lua
Knight.Core:Init()
```

**Returns**:\
`Knight`: The Knight module itself.\
`_G.Knight.API`: The initialized API.

***

#### Example Usage

Below is an example of how you might use the Knight API module in your game:

```lua
local Knight = require(game.ReplicatedStorage.Packages.Knight)

-- Initialize the Knight framework
local KnightInstance, KnightAPI = Knight.Core:Init()

-- Import a shared module
local MySharedModule = Knight.Core.Import("Knight/Shared/MyModule")

-- Print the framework version
Knight:PrintVersion()

-- Log a message
Knight.Core.Log("print", "Knight framework initialized successfully!")

-- Fetch storage
local Storage = Knight.Core:GetStorage(true)
```

#### Best Practices

* **Use `Knight.Core.Import()`**: This method allows for clean and dynamic importing of modules based on their paths within the framework. Be sure to use correct paths to avoid import errors.
* **Initialize Once**: Always initialize the Knight framework at the start of your game using `Knight.Core:Init()`. This sets up the internal environment and ensures services are loaded correctly.
* **Log with Context**: Use `Knight.Core.Log()` to log important events, errors, or warnings during runtime, especially during initialization and service execution.

> Article & Art by vq9o


# Knight Remotes API

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2FTvRLIXO6VOszweHQ16Xv%2Fknightremotesapi.jpg?alt=media&amp;token=eed1bc69-2970-4f2c-be85-b2c6638c5ab8" alt=""><figcaption></figcaption></figure>

## KnightRemotes API Documentation - Version 1.0.4

The `KnightRemotes` module provides a robust framework for managing remote events and functions across the client and server in the Knight framework. This module handles remote creation, firing, middleware management, and connection, ensuring efficient, secure communication for your game.

## Overview

* **Get Remotes**: Synchronously or asynchronously retrieve `RemoteAPI` instances by name.
* **Fire Remotes**: Trigger remotes on specific players, all players, or players nearby a location.
* **Middleware**: Integrate middleware functions for security and validation checks on events.
* **Register/Unregister Remotes**: Add or remove remote functions/events dynamically.

## Functions

Here’s the revised documentation with the requested formatting changes:

***

### `Remotes:GetAsync(RemoteName: string) -> await RemoteAPI`

**Description:**\
Waits asynchronously to retrieve the `RemoteAPI` associated with the specified remote name.

**Usage:**

```lua
local remoteAPI = Remotes:GetAsync("ExampleRemote")
```

**Parameters:**

* **RemoteName** (string): The name of the remote event or function to retrieve.

**Returns:**

* **RemoteAPI**: The `RemoteAPI` associated with `RemoteName` (yields until available).

***

### `Remotes:Get(RemoteName: string) -> RemoteAPI | boolean`

**Description:**\
Fetches the `RemoteAPI` associated with the given remote name synchronously.

**Usage:**

```lua
local remoteAPI = Remotes:Get("ExampleRemote")
```

**Parameters:**

* **RemoteName** (string): The name of the remote.

**Returns:**

* **RemoteAPI**: The `RemoteAPI` if available, otherwise `false`.

***

### `Remotes:Fire(RemoteName: string, ...) -> (any...)`

**Description:**\
Triggers the specified remote event or function with the provided arguments.

**Usage:**

```lua
Remotes:Fire("ExampleRemote", arg1, arg2)
```

**Parameters:**

* **RemoteName** (string): The name of the remote.
* **...** (any): Arguments passed to the remote event.

***

### `Remotes:FireAllNearby(RemoteName: string, position: Vector3, maxDistance: number | boolean, ...) -> (any...)`

**Description:**\
Fires the remote to all players within the specified distance from a central position.

**Usage:**

```lua
Remotes:FireAllNearby("ExampleRemote", Vector3.new(0, 0, 0), 100, any...)
```

**Parameters:**

* **RemoteName** (string): The name of the remote.
* **position** (Vector3): Center position for nearby players.
* **maxDistance** (number | boolean): Maximum radius; if `true`, defaults to 50.
* **...** (any): Additional arguments passed to the remote.

***

### `Remotes:FireAll(RemoteName: string, ...) -> (any...)`

**Description:**\
Triggers the remote for all connected players.

**Usage:**

```lua
Remotes:FireAll("ExampleRemote", arg1, arg2)
```

**Parameters:**

* **RemoteName** (string): The remote’s name.
* **...** (any): Arguments passed to each connected player.

***

### `Remotes:Connect(RemoteName: string, callback: () -> void | nil | boolean) -> void`

**Description:**\
Attaches a callback to the specified remote. The callback executes each time the remote event is fired.

**Usage:**

```lua
Remotes:Connect("ExampleRemote", function()
    print("Remote triggered!") 
end)
```

**Parameters:**

* **RemoteName** (string): The name of the remote.
* **callback** (function): Function executed on the remote event firing.

***

### `Remotes:Register(RemoteName: string, RemoteClass: string, Callback: any) -> void`

**Description:**\
Registers a new remote with a specified class type and optional callback function.

**Usage:**

<pre class="language-lua"><code class="lang-lua">Remotes:Register("ExampleRemote", "RemoteFunction", function()
<strong>    print("Remote registered!")
</strong>end)
</code></pre>

**Parameters:**

* **RemoteName** (string): Name for the new remote.
* **RemoteClass** (string): Class type (e.g., RemoteFunction).
* **Callback** (function, optional): Function to associate with the remote.

***

### `Remotes:RegisterMiddleware(Target: string, Callback: (Player: Player, ...any) -> boolean): void`

**Description:**\
Adds middleware for validation or checks before a remote is triggered.

**Usage:**

```lua
Remotes:RegisterMiddleware("ExampleRemote", function(player) 
    return player:IsInGroup(1234567890) 
end)
```

**Parameters:**

* **Target** (string): The target remote or `*` for global middleware.
* **Callback** (function): Middleware function, returning `true` to proceed or `false` to block.

***

### `Remotes:UnregisterMiddleware(Target: string): void`

**Description:**\
Removes middleware associated with a specific remote.

**Usage:**

```lua
Remotes:UnregisterMiddleware("ExampleRemote")
```

**Parameters:**

* **Target** (string): The name of the remote from which to remove middleware.

***

### `RemoteAPI:Fire(...) -> (any...)`

**Description:**\
Triggers the associated remote event with the provided arguments.

**Usage:**

```lua
remoteAPI:Fire(arg1, arg2)
```

**Parameters:**

* **...** (any): Arguments passed to the remote event.

***

### `RemoteAPI:FireAll(...) -> (any...)`

**Description:**\
Fires the associated remote for all players.

**Usage:**

```lua
remoteAPI:FireAll(arg1, arg2)
```

**Parameters:**

* **...** (any): Arguments passed to each connected player.

***

### `RemoteAPI:FireAllNearby(position: Vector3, maxDistance: number | boolean, ...) -> (any...)`

**Description:**\
Triggers the remote for players within a specific range from a center position.

**Usage:**

```lua
remoteAPI:FireAllNearby(Vector3.new(0, 0, 0), 100, arg1, arg2)
```

**Parameters:**

* **position** (Vector3): The central position for nearby players.
* **maxDistance** (number | boolean): Maximum radius; defaults to 50 if `true`.
* **...** (any): Additional arguments for the remote.

***

### `RemoteAPI:Connect(callback: () -> void | nil | boolean) -> void`

**Description:**\
Attaches a callback to the remote event, executed when the event fires.

**Usage:**

```lua
remoteAPI:Connect(function() print("Remote event triggered!") end)
```

**Parameters:**

* **callback** (function): Function to execute on the event firing.

***

### `RemoteAPI:OnDestroying(callback: (RemoteName: string) -> void) -> void`

**Description:**\
Sets a callback function to be executed when the remote is destroyed.

**Usage:**

```lua
remoteAPI:OnDestroying(function(remoteName) print(remoteName, "is being destroyed.") end)
```

**Parameters:**

* **callback** (function): Function called with the `RemoteName` when destroyed.

***

### `RemoteAPI:Destroy()`

**Description:**\
Removes the remote from cache and triggers any attached `OnDestroying` callbacks.

**Usage:**

```lua
remoteAPI:Destroy()
```

## Examples / Code Samples

### Getting and Firing a Remote

Retrieve a remote using `Get` and fire it with some arguments.

```lua
local myRemote = Remotes:Get("ExampleRemote")

if myRemote then
    myRemote:Fire("Hello", 42)
end
```

Additionally you can fire an event via:

```lua
-- Server-side
Remotes:Fire("ExampleRemote", game.Players.vq9o, "Hello", 42)
Remotes:FireAll("ExampleRemote", "Hello", 42)

-- Client-side
Remotes:Fire("ExampleRemote", "Hello", 42)
```

### Registering a New Remote with a Callback

Register a new remote that will respond with a callback function.

```lua
Remotes:Register("PlayerData", "RemoteFunction", function(player, data)
    print(player.Name .. " sent data:", data)
    return "Acknowledged"
end)
```

### Using Middleware for Validation

Add middleware to restrict access or validate conditions before a remote is triggered.

```lua
Remotes:RegisterMiddleware("PlayerData", function(player, data)
    return player:IsInGroup(123456)  -- Only allow players in group 123456
end)
```

### Firing a Remote to Nearby Players

Fire a remote to all players within a 100-stud radius of a specific position.

```lua
local position = Vector3.new(0, 10, 0)
Remotes:FireAllNearby("AlertNearby", position, 100, "An event occurred nearby!")
```

### Connecting a Callback to an Existing Remote

Attach a callback function to run when a remote is fired.

```lua
Remotes:Connect("PlayerJoined", function(player)
    print(player.Name .. " joined the game.")
end)
```

### Destroying a Remote and Handling Cleanup

Destroy a remote when it's no longer needed and execute cleanup code.

```lua
local api = Remotes:Get("TemporaryEvent")

api:OnDestroying(function(name)
    print(name .. " is being destroyed.")
end)

api:Destroy()
```

### Using Grouped Event Names

You can organize events into "groups" by naming them with a prefix, separated by a colon (e.g., `PointsService:GetPoints`). This allows for structured and readable event names within your system.

```lua
-- Register an event under the "PointsService" group
Remotes:Register("PointsService:GetPoints", "RemoteFunction", function(player)
    -- Assume there's a function that retrieves points for a player
    local points = PointsService:GetPlayerPoints(player.UserId)
    return points
end)

-- Retrieve and use the grouped event
local pointsRemote = Remotes:Get("PointsService:GetPoints")

if pointsRemote then
    local playerPoints = pointsRemote:Fire(somePlayer)
    print("Player's points:", playerPoints)
end
```

In this example, `PointsService:GetPoints` is treated as a single, valid event name, enabling a structured namespace approach for grouping related events in the `KnightRemotes` module.


# Knight Import/require API

## About

Knight has a custom require/import implementaiton in v1.0.0.

## Aliases

Aliases are paths you can define to instances such as `@` points to `ReplicatedStorage.Packages`.

### Default Aliases

* core
  * Knight core
* @
  * ReplicatedStorage.Packages
* @s
  * ServerStorage.ServerPackages for server, and ReplicatedStorage.Packages for client.
* packages
  * same as @
* shared&#x20;
  * Knight Shared
* objects
  * Knight Objects of Runtime Context

## Examples

```lua
local require = require(path.to.src)

local module = require("shared/module")
local somePackage = require("package/module")
local somePackage2 = require("@/module")
local external = require(ReplicatedStorage.SomeModule)
```

```lua
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local KNIGHT_TYPES = require(ReplicatedStorage:WaitForChild("KNIGHT_TYPES"))

local GuiController = {} :: KNIGHT_TYPES.KnightClass

function GuiController:init()
   self.ui = require(script.Components.Main)(self)
end

function GuiController:start()
   return self.ui
end

---------- MainComponent ----------
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Packages = ReplicatedStorage:WaitForChild("Packages")

local require = require(require(Packages:WaitForChild("knight")).import)
local fusion = require("core/fusion")

return function(controller)
	local New, Children = fusion.New, fusion.Children;

	return New("Frame")({
		Name = "Frame",
		BackgroundTransparency = 1,
		Size = UDim2.fromScale(1, 1),
        Visible = state.enabled;

		[Children] = {
			New("TextLabel")({
				Name = "TextLabel",
				BackgroundColor3 = Color3.fromRGB(93, 34, 34),
				BackgroundTransparency = 0.15,
				RichText = true,
				Size = UDim2.fromScale(1, 1),
				TextColor3 = Color3.new(1, 1, 1),
				TextStrokeTransparency = 0.2,
				TextWrapped = true,
				ZIndex = 1,
			}),

			New("ImageLabel")({
				Name = "ImageLabel",
				AnchorPoint = Vector2.new(0.5, 0.5),
				BackgroundTransparency = 1,
				Image = "rbxassetid://11782559813",
				Position = UDim2.fromScale(0.5, 0.22),
				ScaleType = Enum.ScaleType.Fit,
				Size = UDim2.fromOffset(425, 425),
				ZIndex = 2,
			}),
		},
	})
end

```


# Documentation

## Contributing to the Knight Framework.

Thank you for being interested in contributing to the project.

### Code Of Conduct

* Refrain from using languages other than English.
* Refrain from discussing any politically charged or inflammatory topics.
* Uphold mature conversations and respect each other; excessive profanity, hate speech, or any kind of harassment will not be tolerated.
* No advertising.
* Do not mention members of GitHub unless a question is directed at them and can't be answered by anyone else.
* Do not mention any of the development team for any reason. We will read things as we get to them.

## Suggestions

Before posting makes sure:

* Clear & Understandable title
* Descriptive description
* **Make sure it doesn't exist already!**
* Explain the Pros & Cons of this addition and/or removal.

### Style Guidelines

Before you can push we have some requirements, make sure your commit message is:

* Under 72 characters.
* Start the commit message with specific emoji for the criteria:
* * 🎨 `:art:` when improving the format/structure of the code
* * 🐎 `:racehorse:` when improving performance
* * 📝 `:memo:` when writing docs
* * 🐛 `:bug:` when fixing a bug
* * 🔥 `:fire:` when removing code or files
* * ✅ `:white_check_mark:` when adding tests
* * 🔒 `:lock:` when dealing with security
* * ⬆️ `:arrow_up:` when upgrading dependencies
* * ⬇️ `:arrow_down:` when downgrading dependencies
* * 👕 `:shirt:` when removing linter warnings


# Framework

## Contributing to the Knight Framework.

Thank you for being interested in contributing to the project.

### Code Of Conduct

* Refrain from using languages other than English.
* Refrain from discussing any politically charged or inflammatory topics.
* Uphold mature conversations and respect each other; excessive profanity, hate speech, or any kind of harassment will not be tolerated.
* No advertising.
* Do not mention members of GitHub unless a question is directed at them and can't be answered by anyone else.
* Do not mention any of the development team for any reason. We will read things as we get to them.

## Reporting Bugs

> **Notice:** If an issue is closed and you experiencing the same issue, you are most likely doing something wrong, please request help instead.

Before posting make sure:

* Clear & Understandable title
* Descriptive description with images & error logs.
* Explain what's happening & reproduction steps.

Please include:

* Knight Version
* is any other framework installed?
* Is any other knight addons installed?
* Knight version
* Roblox Studio/Client version

## Suggestions

Before posting makes sure:

* Clear & Understandable title
* Descriptive description
* **Make sure it doesn't exist already!**
* Explain the Pros & Cons of this addition and/or removal.

### Style Guidelines

Before you can push we have some requirements, make sure your commit message is:

* Under 72 characters.
* Start the commit message with specific emoji for the criteria:
* * 🎨 `:art:` when improving the format/structure of the code
* * 🐎 `:racehorse:` when improving performance
* * 📝 `:memo:` when writing docs
* * 🐛 `:bug:` when fixing a bug
* * 🔥 `:fire:` when removing code or files
* * ✅ `:white_check_mark:` when adding tests
* * 🔒 `:lock:` when dealing with security
* * ⬆️ `:arrow_up:` when upgrading dependencies
* * ⬇️ `:arrow_down:` when downgrading dependencies
* * 👕 `:shirt:` when removing linter warnings

### Lua Styleguide

* Do not repeat yourself.
* Do not trust the client
* Balance security and optimizations
* [Consider this Lua Performance guide](https://springrts.com/wiki/Lua_Performance)
* Make use of `KNIGHT_CONFIG` where it makes sense making features optional or customizable


# Templates (RBXL)

Open-sourced project(s) made with Knight Framework.

## Basic Obby

> <https://www.roblox.com/games/115553297833591/Knight-Demos-Basic-obby>
>
> Programmed by RAMPAGE Interactive and the Roblox Corporation.


# Games who use Knight

### RoSource Project

{% embed url="<https://www.roblox.com/groups/5574738/RoSource-Project#!/about>" %}
Project group.
{% endembed %}

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2FPiGvkx7LGYUNz8iPQVFX%2Fimage.png?alt=media&amp;token=298633e3-b3f3-4e7f-97f5-a2966823e724" alt=""><figcaption></figcaption></figure>

### Apollo Bay

{% embed url="<https://www.roblox.com/groups/32462483/Apollo-Bay#!/about>" %}

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2Fb7Po7eDD9PRgMKAodr62%2Fimage.png?alt=media&amp;token=9cb1d183-49c2-4dc0-9e48-10504076fc43" alt=""><figcaption></figcaption></figure>

### Emergency Response: UK

{% embed url="<https://www.roblox.com/games/18903710138/Emergency-Response-UK>" %}

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2FUQI5OKsn0Tj7BylFhMx4%2Fimage.png?alt=media&amp;token=c86b246a-253d-4947-bcb8-b2e6a2d711b3" alt=""><figcaption></figcaption></figure>

### Skull Island

{% embed url="<https://www.roblox.com/games/16574913126/SEASON-1-Skull-Island>" %}

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2FxoxocD0mZoMPdHuOZRlM%2Fimage.png?alt=media&amp;token=0047135e-6627-4066-9c05-1b21f19c67a8" alt=""><figcaption></figcaption></figure>

### BATTLEFIELD Tech Demo

{% embed url="<https://www.roblox.com/groups/9640975/RAMPAGE-Interactive-LLC#!/about>" %}
Project Group
{% endembed %}

## Blacksite Omega

{% embed url="<https://www.roblox.com/games/15366364939/Early-Access-Blacksite-Omega>" %}

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2FBYY0TJ2UUeIMY7NzNLmr%2Fimage.png?alt=media&amp;token=7f4ee0f6-8248-42d2-8930-1b19626f5100" alt=""><figcaption></figcaption></figure>

## The Western Frontier

{% embed url="<https://www.roblox.com/games/12336113063/V2-The-Western-Frontier>" %}

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2FclImaySh3szZsst34rhV%2Fimage.png?alt=media&amp;token=5df39eac-2085-4075-8656-dc044941997f" alt=""><figcaption></figcaption></figure>

## Canadian Roleplay

{% embed url="<https://www.roblox.com/games/9820168729/City-Of-Hamilton>" %}

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2FI6mvg2YjnX0y1xQhCZ8S%2Fimage.png?alt=media&amp;token=68f193f8-dd46-49aa-9513-e7b60d941911" alt=""><figcaption></figcaption></figure>

## Garsha's Undead West

{% embed url="<https://www.roblox.com/groups/34143700/Undead-West-x-RAMPAGE#!/about>" %}

## Europaxc's CITY-22

{% embed url="<https://www.roblox.com/games/12434382005/CITY-22>" %}

<figure><img src="https://2460843234-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZVYkqtpa3etiCJsYeGLR%2Fuploads%2FF6lM8ZJVX0VT4Bm23eyY%2Fimage.png?alt=media&amp;token=8ff108d1-b37a-4224-954e-c64befe60f30" alt=""><figcaption></figcaption></figure>


# README.md

{% hint style="danger" %}
This documentation is outdated (v2 documentation) is subjected to contain wrong information.

Legacy documentation is temporarily archived here until v3 documentation is completed.
{% endhint %}


# Services

Services are module scripts that serve a specific purpose. For example a experience may have a service for GameUI, Points, etc.

### Creating a service <a href="#creating-a-service" id="creating-a-service"></a>

You can create a service by creating a new ModuleScript under one of Knights Services folders. Learn how to find knight service folders [Folders explanation](https://app.gitbook.com/s/ZVYkqtpa3etiCJsYeGLR/~/changes/YBDQiMUocThlJ09JRJ9Z/knight/folders-explanation).

### Template <a href="#template" id="template"></a>

Each service is structured with this template.

```lua
local Knight = {
	ServiceName = script.Name,
	ServiceData = {
		Author = "vq9o",
		Description = "Example Service example"
	},
	CanStart = true,
	CanUpdate = true,
}

function Knight.Init()
	warn("Example Service inited!")
end

function Knight.Start()
	warn("Example Service Started!")
end

function Knight.Update(DeltaFrame)
	warn("Example Service called for new frame!")
end

return Knight
```

### Default Functions <a href="#default-functions" id="default-functions"></a>

```lua
function Knight.Init() -- optional. Called on init
end
```

```lua
function Knight.Start() -- optional. Called on start
end
```

```lua
function Knight.Update(deltaTime) -- optional. Called on every frame.
end
```

### Init <a href="#init" id="init"></a>

<pre class="language-lua"><code class="lang-lua"><strong>local Knight = {
</strong>	ServiceName = script.Name,
	ServiceData = {
		Author = "vq9o",
		Description = "Example Service example"
	}
}

function Knight.Init()
	-- Client services only.
	print(Knight.Player.Name) -- Prints LocalPlayer name
	
	-- All services can access this.
	Knight.Shared -- indexs shared, you can access everything in it.
	Knight. -- indexs your current runtype (client or server)
	Knight.Knight -- returns knight internal functions
	
	-- Example you can call another function bar from service foo without need of using
	-- Roblox's require().
	Knight.Services.foo.bar()
end

return Knight
</code></pre>

## Config

CanStart, CanUpdate, CanInit variable allow execution of the .Update(), .Start(), and .Init(). Useful if your using a third-party module and you need to disable Knight from calling its default start function like CameraShaker.

Config is not required and will default to true.

## Priority Startup

Folders named as "Database" will have first priority to init, then folders named "Priority" will init. Useful to load core game backend first.


# Startup Priority

In version 0.0.7-prod we added startup priority. By default the following groups have the priority of;

Internal = 4

Objects = 3

Services = 2

A higher priority = startup first. Default priority is 1, if a module does not have a pre-defined priority one will be automatically assigned stated above or defaults to 1.


