Helix Framework

repository·master·Indexed 42 days ago

https://github.com/nebulouscloud/helix

A stable, open-source, and DRM-free Garry's Mod framework derived from NutScript 1.1, designed for creating roleplay gamemodes. It provides a robust base for developers to implement gameplay mechanics, including systems for character management, inventories, factions, and plugins.

Tokens
4.8K
Snippets
19
Records
24
Agent score
52%

What's inside Helix

  1. Understand Helix Inventories and Item Instancing

    master

    In Helix, inventories are distinct objects belonging to a character, which in turn belongs to a player.

    Accessing a player's inventory: Use client:GetCharacter():GetInventory() to retrieve the main inventory object.

    Item Instancing: Helix uses an asynchronous instancing system to prevent server freezes. Instead of returning the instance immediately, ix.item.Instance uses a callback.

    ix.item.Instance(inventory, "item_id", data, x, y, callback)

    • inventory: The inventory object (use 0 for no inventory).
    • item_id: The ID of the item to instance.
    • data: (Optional) A table of custom data.
    • x, y: The grid position in the inventory. Use inventory:FindEmptySlot() to find available space.
    • callback: A function that receives the new item instance.
    -- Instancing an item manually
    local inventory = client:GetCharacter():GetInventory()
    local x, y = inventory:FindEmptySlot()
    
    ix.item.Instance(inventory, "test_item", { custom_data = true }, x, y, function(item)
        print("New item instance created: " .. item:GetID())
    end)
  2. How the Character object works in Helix

    master

    Helix uses a Character object to separate character data from the player object. This allows for managing characters even when they are not the active character for a player, or when the player is offline.

    • Accessing the active character: Use client:GetCharacter() (where client is the Helix term for the player object).
    • Accessing all loaded characters: Use the ix.char.loaded table.
    • Data Management: Instead of setting data directly on the player (as in Clockwork), set it on the character object.

    Comparison:

    • Clockwork: player:SetCharacterData("foo", "bar")
    • Helix: client:GetCharacter():SetData("foo", "bar")
    -- Accessing the character and setting data
    local char = client:GetCharacter()
    char:SetData("foo", "bar")
    
    -- Accessing all loaded characters
    for _, char in pairs(ix.char.loaded) do
        print(char:GetName())
    end
  3. Convert Clockwork plugins to Helix plugins

    master

    Helix plugins have a simplified structure compared to Clockwork.

    1. Flatten Structure: Move all contents from the Clockwork plugin subfolder into the main plugin folder.
    2. Replace plugin.ini: Delete plugin.ini and use sh_plugin.lua as the primary entry point. Define the following in sh_plugin.lua:
      • PLUGIN.name = "Plugin Name"
      • PLUGIN.author = "Plugin Author"
      • PLUGIN.description = "Plugin Description"
    3. Handle the PLUGIN table: The PLUGIN table is removed after loading. If you need to access it in other files (commands, entities, etc.), add local PLUGIN = PLUGIN at the top of those files.
    4. Global Aliases: If Clockwork used PLUGIN:SetGlobalAlias("cwMyPlugin"), change cwMyPlugin to PLUGIN in Helix.
    -- sh_plugin.lua
    PLUGIN.name = "My Plugin"
    PLUGIN.author = "Author"
    PLUGIN.description = "Description"
    
    -- In other files (e.g., a command)
    local PLUGIN = PLUGIN
  4. Install the Helix framework

    master

    To install Helix, download the framework from the official GitHub repository and place the contents into a folder named helix within your Garry's Mod gamemodes directory.

    Path: garrysmod/gamemodes/helix

    After installation, restart your server to apply the changes.

    mkdir -p garrysmod/gamemodes/helix
  5. Configure MySQL for Helix

    master

    By default, Helix uses SQLite. To use an external MySQL database (required for multi-server setups or website integration), follow these steps:

    1. Install MySQLOO: Ensure the gmsv_mysqloo_win32.dll (Windows) or gmsv_mysqloo_linux.dll (Linux) is located in garrysmod/lua/bin.
    2. Create Configuration: Create a helix.yml file in garrysmod/gamemodes/helix. You can copy helix.example.yml as a template.
    3. Update Adapter: Set the adapter key to "mysqloo".
    4. Set Connection Details: Provide your hostname, username, password, database name, and port (default is 3306).

    CRITICAL: You must use exactly two spaces for indentation in helix.yml. Do not use tabs or different spacing, or the configuration will fail to load.

    database:
      adapter: "mysqloo"
      hostname: "myexampledatabase.com"
      username: "myusername"
      password: "mypassword"
      database: "helix"
      port: 3306
  6. Migrate Clockwork schema to Helix

    master

    To convert a Clockwork schema to Helix, follow these structural and initialization steps:

    1. Set the Base Gamemode: In your schema's gamemode folder, open init.lua and cl_init.lua. Change DeriveGamemode("Clockwork") to DeriveGamemode("helix").
    2. Update Folder Structure:
      • Move schema/entities out of the schema folder.
      • Rename the libraries folder to libs.
      • Consolidate commands files; Helix does not use the Clockwork commands tab structure.
    3. Update Schema Entrypoint: The main schema file is sh_schema.lua located inside the schema folder.
    4. Update File Inclusion: Replace Clockwork's inclusion utility with Helix's utility.

    Conversion Mapping:

    • Clockwork: Clockwork.kernel:IncludePrefixed("sh_myfile.lua")
    • Helix: ix.util.Include("sh_myfile.lua")
    -- In init.lua and cl_init.lua
    DeriveGamemode("helix")
    
    -- In sh_schema.lua
    ix.util.Include("sh_myfile.lua")
  7. Migrate Schema and Plugin Hooks

    master

    When converting hooks from Clockwork to Helix, you must update both the function names and the argument signatures. Helix typically uses client instead of player and often flattens arguments.

    Example Hook Migration:

    • Clockwork: function Schema:PlayerPlayPainSound(player, gender, damageInfo, hitGroup)
    • Helix: function Schema:GetPlayerPainSound(client)
  8. Convert Clockwork Factions to Helix Factions

    master

    Factions in Helix follow a similar logic to Clockwork but with different property names and registration methods:

    • Definition: Instead of Clockwork.faction:New("Name"), the FACTION object is pre-defined; set the name via FACTION.name = "Name Here".
    • Whitelisting: Change FACTION.whitelist = true to FACTION.isDefault = false.
    • Models: Combine male and female models into a single list in FACTION.models (no separate parts required).
    • Naming: Change function FACTION:GetName(name) to function FACTION:GetDefaultName(name).
    • Description: Use FACTION.description = "...".
    • Registration: Use FACTION.index to get the registered faction instead of FACTION:Register().
    -- Helix Faction Example
    FACTION.name = "My Faction"
    FACTION.isDefault = false
    FACTION.models = {"models/player/group_a.mdl", "models/player/group_b.mdl"}
    FACTION.description = "A description of the faction"
    
    function FACTION:GetDefaultName(name)
        return name
    end
    
    local FACTION_MYFACTION = FACTION.index
  9. Migrate Flags from Clockwork to Helix

    master

    Flags are functionally equivalent but use different syntax for addition and character manipulation.

    Adding a flag: Use ix.flag.Add("id", "Description").

    Manipulating character flags: Access flags through the character object obtained from the client:

    • client:GetCharacter():GiveFlags(flags)
    • client:GetCharacter():TakeFlags(flags)
    • client:GetCharacter():HasFlags(flags)
    -- Adding a flag
    ix.flag.Add("x", "Description")
    
    -- Using flags on a character
    local character = client:GetCharacter()
    if character:HasFlags("x") then
        character:GiveFlags("y")
    end
  10. Define Helix Items and Item Functions

    master

    Helix items are defined in the items folder. Key differences from Clockwork include:

    • Registration: ITEM:Register() is no longer used.
    • Pricing: Use ITEM.price instead of ITEM.cost.
    • Capacity: Helix uses a grid system. Replace ITEM.weight with ITEM.width and ITEM.height (minimum 1x1).
    • Functions: All item functions (like Use) must be defined within the ITEM.functions table.

    Example Item Structure:

    ITEM.price = 100
    ITEM.width = 1
    ITEM.height = 1
    ITEM.functions.Use = {
        OnRun = function(item)
            print("Used by: " .. item.player)
        end
    }
    -- A complete item definition example
    ITEM.uniqueID = "water"
    ITEM.price = 10
    ITEM.width = 1
    ITEM.height = 1
    
    ITEM.functions.Use = {
        OnRun = function(item)
            print("Drinking water...")
            -- Logic here
        end,
        icon = "icon16/water.png"
    }