⚙ Settings Configuration

Understand the two-layer settings system: global defaults and per-player overrides. Learn when to use each and how to modify them at runtime.

The Two Layers

Global defaults vs per-player overrides

Stoway uses a two-layer settings system to provide flexibility:

🌎

Global Settings

File: Settings.luau

Default values applied to all players. Set once, affects everyone.

  • Game-wide defaults
  • Static configuration
  • Changed in code
  • Requires server restart to apply
👤

Per-Player Settings

Property: state.Settings

Individual overrides per player. Can change at runtime.

  • Player-specific values
  • Runtime modifiable
  • Synced to client automatically
  • VIP, permissions, game modes

Global Settings

Configuration in src/shared/Settings.luau

Settings.luau Structure Luau
-- src/shared/Settings.luau

-- Hotbar Configuration
Settings.Hotbar = {
    Type = "Static",      -- Static or Dynamic
    MaxSlots = 10,            -- Number of hotbar slots
}

-- Storage/Backpack Configuration
Settings.Storage = {
    Limit = 15,              -- Weight limit (0 = infinite)
    CanStack = true,         -- Enable stacking
    Sorting = true,          -- Enable sorting
    MaxStackSize = 5,        -- Max items per stack
    SortOrder = "None"        -- Name, Rarity, ItemType, None
}

-- Stacking Rules
Settings.Stacking = {
    RequiredFields = { "Rarity", "Type" },  -- Must match to stack
    Blacklist = {                          -- Never stack these
        ["Legendary"] = true,
        ["Mythic"] = true,
    },
    Rarity = true,            -- Show rarity colors
}

-- Gameplay Settings
Settings.Gameplay = {
    Droppable = true,        -- Can items be dropped
    DropDistance = 10,        -- Drop range
}

-- UI Configuration
Settings.DifferentUIs = {
    Default = {
        FolderName = "StowayGui",
        GuiName = "Stoway",
        HookPresetName = "DefaultHooks"
    },
    Admin = {
        FolderName = "StowayAdmin",
        GuiName = "AdminGui",
        HookPresetName = "AdminHooks"
    }
}
Setting Type Default Description
Hotbar.MaxSlots number 10 Number of fixed hotbar slots (1-9 standard)
Storage.Limit number 15 Weight limit, 0 = unlimited
Storage.CanStack boolean true Enable item stacking
Storage.MaxStackSize number 5 Max items per stack
Gameplay.Droppable boolean true Allow dropping items to world

Per-Player Settings

Runtime configuration per player

Each player has a state.Settings table that inherits from global defaults but can be overridden:

InventoryState.luau Luau
-- src/server/StowayServerV1_2/Core/InventoryState.luau

export type PlayerSettings = {
    Limit: number,             -- Weight limit (0 = infinite)
    CanStack: boolean,         -- Allow stacking
    MaxStackSize: number,      -- Max items per stack
    MaxHotbarSlots: number,   -- Number of hotbar slots
    Droppable: boolean,        -- Allow dropping
    UiType: string,            -- Interface version
}

-- Constructor applies defaults
function InventoryState.new(player: Player): InventoryStateType
    -- ...
    self.Settings = {
        Droppable = Settings.Gameplay.Droppable,
        Limit = Settings.Storage.Limit,
        CanStack = Settings.Storage.CanStack,
        MaxStackSize = Settings.Storage.MaxStackSize,
        MaxHotbarSlots = Settings.Hotbar.MaxSlots,
        UiType = "Default"
    }
    return self
end

Modifying Per-Player Settings

Change settings at runtime

1

Direct Modification

Modify state.Settings directly and sync:

Direct modification Luau
local state = InventoryService.GetState(player)

-- Give VIP players more inventory space
if player.GetRankInGroup(12345) > 254 then
    state.Settings.Limit = 50  -- VIP gets 50 slots
end

-- Disable dropping for new players
state.Settings.Droppable = false

-- Sync to client
InventoryService.SyncSettings(player)
2

Change UI Type

Switch a player's UI skin:

Reload client UI Luau
-- Switch to admin UI
InventoryService.ReloadClient(player, {
    configSettingName = "Admin"
})

-- The client will:
-- 1. Destroy old UI
-- 2. Load new GUI from DifferentUIs.Admin
-- 3. Load new hooks from DifferentUIs.Admin.HookPresetName
-- 4. Rebuild all slots

Adding More Hotbar Slots

Give players extra hotbar slots (e.g., admins get 12 slots)

Stoway supports up to 12 hotbar slots. The recommended maximum is 12 because:

Binds.luau - Hotbar Slots 11-12 Luau
-- src/shared/Binds.luau

-- Slot 11 (Minus key)
Binds.HotbarSlots[11] = {
    Display = "-",
    PC = { {Main = Enum.KeyCode.Minus} },
    Console = { {Main = Enum.KeyCode.ButtonX, Modifiers = {Enum.KeyCode.ButtonR2}} } -- R2 + X
}

-- Slot 12 (Equals key)
Binds.HotbarSlots[12] = {
    Display = "=",
    PC = { {Main = Enum.KeyCode.Equals} },
    Console = { {Main = Enum.KeyCode.ButtonY, Modifiers = {Enum.KeyCode.ButtonR2}} } -- R2 + Y
}
1

Modify Per-Player Settings

In OnPlayerAdded, override state.Settings.MaxHotbarSlots:

Give admins 12 slots Luau
-- src/server/StowayServerV1_2/init.luau

local ADMIN_GROUP_ID = 12345
local ADMIN_RANK = 255

local OnPlayerAdded = function(player)
    local state = InventoryState.new(player)
    PlayerInventories[player] = state

    -- Give admins 12 slots
    local rank = player:GetRankInGroup(ADMIN_GROUP_ID)
    if rank >= ADMIN_RANK then
        state.Settings.MaxHotbarSlots = 12
    end

    InventoryService.SyncSettings(player)
end
2

Check Client Hotbar Binds

Ensure your client code reads the correct number of binds from Binds.HotbarSlots based on state.Settings.MaxHotbarSlots.

⚠ Important:
  • Maximum supported slots: 12
  • Slots 11-12 use - and = keys on keyboard
  • Console uses R2 modifier (left trigger) for slots 11-12
  • Always sync settings after modifying: InventoryService.SyncSettings(player)
🎯

Global Settings For:

  • Game balance constants
  • Default stacking rules
  • Standard hotbar size
  • Base weight limits
👤

Per-Player Settings For:

  • VIP/member bonuses
  • Permission-based limits
  • Game mode restrictions
  • Temporary effects

Example: VIP Inventory Bonus

Complete example with global and per-player settings

VIP Configuration Luau
-- src/server/StowayServerV1_2/init.luau

local VIP_GROUP_ID = 12345
local VIP_RANK = 255
local VIP_LIMIT = 50     -- VIPs get 50 slots
local NORMAL_LIMIT = 15  -- Normal players get 15

local OnPlayerAdded = function(player)
    local state = InventoryState.new(player)
    PlayerInventories[player] = state

    -- Apply VIP bonus
    local rank = player:GetRankInGroup(VIP_GROUP_ID)
    if rank >= VIP_RANK then
        print("[Stoway] " .. player.Name .. " is a VIP!")
        state.Settings.Limit = VIP_LIMIT
        state.Settings.MaxStackSize = 10  -- VIPs stack higher
    else
        state.Settings.Limit = NORMAL_LIMIT
    end

    -- Sync settings to client
    InventoryService.SyncSettings(player)
end

Example: Restricted Slots (Disabled Backpack)

Block specific hotbar slots globally when backpack is disabled

This example shows how to prevent items from entering specific slots (e.g., 7 and 8) when the backpack is disabled. We implement this as a Global Setting that applies to all players.

1

Configure Settings

Define which slots are limited in src/shared/Settings.luau.

Settings.luau Luau
Settings.Hotbar = {
    MaxSlots = 10,
    -- Custom table of restricted slots (Global)
    LimitedSlots = {
        [7] = true,
        [8] = true,
    }
}
2

Modify AddOperation (Server)

In src/server/StowayServerV1_2/Operations/AddOperation.luau, require the global settings and check limits.

AddOperation.luau Luau
local Settings = require(game:GetService("ReplicatedStorage").Shared.Settings)

-- Inside the BackpackDisabled block
if Settings.Storage.BackpackEnabled == false then
    local emptySlot = SlotManager.FindEmptyHotbarSlot(state)

    if emptySlot then
        -- CHECK: Is this slot limited?
        local limited = Settings.Hotbar.LimitedSlots
        if limited and limited[emptySlot] then
            return {
                success = false,
                reason = emptySlot .. " is limited"
            }
        end
        -- ... Standard add logic ...
    end
end
3

Modify SwapOperation (Server)

In src/server/StowayServerV1_2/Operations/SwapOperation.luau, prevent swapping into limited slots.

SwapOperation.luau Luau
local Settings = require(game:GetService("ReplicatedStorage").Shared.Settings)

-- Inside ValidateSwap function
if not Settings.Storage.BackpackEnabled then
    local limited = Settings.Hotbar.LimitedSlots
    if limited then
        if from.type == "Hotbar" and limited[from.slot] then
            return false, from.slot .. " is limited"
        end
        if to.type == "Hotbar" and limited[to.slot] then
            return false, to.slot .. " is limited"
        end
    end
end
4

Modify Client Controller

In src/client/StowayClientv1_2/Operations/InventoryController.luau, check global settings to block dragging.

InventoryController.luau Luau
local GlobalSettings = require(ReplicatedStorage.Shared.Settings)

-- Inside Swap function
if not GlobalSettings.Storage.BackpackEnabled then
    local limited = GlobalSettings.Hotbar.LimitedSlots
    if limited then
        if fromType == "Hotbar" and limited[fromSlot] then
            warn(fromSlot .. " is limited")
            return "Slot is limited"
        end
        if toType == "Hotbar" and limited[toSlot] then
            warn(toSlot .. " is limited")
            return "Slot is limited"
        end
    end
end

Settings Reference

Quick reference for all settings

Setting Layer Type Default Syncs to Client
Limit Both number 15 ✔ Yes
CanStack Both boolean true ✔ Yes
MaxStackSize Both number 5 ✔ Yes
MaxHotbarSlots Both number 10 ✔ Yes
Droppable Both boolean true ✔ Yes
UiType Player only string "Default" ✔ Yes
Hotbar.Type Global only string "Static" ✔ Yes
Storage.Sorting Global only boolean true ✖ No

Use Cases

When to use each settings layer