Skip to content

HangWatcher, Priorities & Profile Methods

Choose a tag to compare

@Nextinel Nextinel released this 13 Oct 02:28
· 3 commits to main since this release
78399cf

Added

  • HangWatcher - warns if a module's init takes longer than 10 seconds. Configurable per module with skipHangWatch = true
  • Priorities - control init order with priority = -1 (lower = earlier). Dependencies always take precedence over priority
  • Profile methods:
    • profile:decrease(key, delta) / profile:decreaseAt(path, key, delta) - shorthand for negative add
    • profile:observe(key, callback) / profile:observe(path, key, callback) - subscribe to field changes. Only number, string, boolean types are supported. Triggers only on :add(), :addAt(), :set(), :setAt(), :decrease(), :decreaseAt()
    • profile:addAt(path, key, delta) / profile:setAt(path, key, value) - modify nested fields without leaving the Data table
  • DataStoreService functions:
    • .tryGetProfile(player) - non-yielding, returns nil if not loaded
    • .awaitProfile(player) - explicit yielding alias of .getProfile(player)
    • .getProfiles() - returns all loaded profiles
  • skipHangWatch - per-module field to disable hang warnings
  • shouldCheckExtrafields - optional flag in network table for the validator. Default is true. Set to false to allow extra fields in the payload

Fixed

  • DependencyResolver now uses Kahn's algorithm with priority as a tie-breaker

Notes

  • asyncInit runs in parallel via task.spawn and is not affected by priority or dependency order
  • No breaking changes. Existing modules work as-is

Demo

Try it: Wave Survival (Download) - a small showcase of Nextinel in action. Covers networking, module lifecycle, profiles, and data saving

Examples

HangWatcher

-- This module's init takes 15s -> HangWatcher warns after 10s
return {
    init = function()
        task.wait(15)
    end,
}

-- This module disables the warning
return {
    skipHangWatch = true,
    init = function()
        task.wait(15)
    end,
}

Priorities

-- Module: DataLoader
return {
    priority = -100, -- runs before everything else
    init = function() end,
}

-- Module: UI
return {
    priority = 100, -- runs last
    init = function() end,
}

Profile methods

local profile = dataStoreService:getProfile(plr)

-- top-level observe
local disconnectTop = profile:observe("Coins", function(new, old)
    print(`Coins: {old} -> {new}`)
end)

-- nested observe
local disconnectNested = profile:observe("values/entry1", "CurrencyName", function(new, old)
    print(`values.entry1.CurrencyName: {old} -> {new}`)
end)

-- nested add/set
profile:addAt("values/entry1", "CurrencyName", 50)
profile:setAt("values/entry1", "CurrencyName", 100)

-- shorthand
profile:decrease("Coins", 10) -- same as :add("Coins", -10)
profile:decreaseAt("values/entry1", "CurrencyName", 5)

-- unsubscribe
disconnectTop()
disconnectNested()

DataStoreService methods

-- non-yielding, returns nil if not loaded yet
local profile = dataStoreService:tryGetProfile(plr)
if profile then
    profile:add("Coins", 1)
end

-- explicit yielding
local profile = dataStoreService:awaitProfile(plr)

-- iterate over all loaded profiles
for plr, profile in dataStoreService:getProfiles() do
    profile:add("Coins", 10)
end