Repository navigation
Releases: Nextinel/Roblox_Framework
Releases · Nextinel/Roblox_Framework
Release list
Nextinel Builder & Type Safety
Added
- Nextinel Builder Plugin: Auto-generates folder structure and typed boilerplate modules. Download here
- Full Type Support: Added
Types.ServerModuleandTypes.ClientModule. You can now use:: Types.ServerModulefor full IntelliSense on lifecycle hooks
Improved
- Error Tracebacks: Switched from
pcalltoxpcallacross the entire framework. When an error occurs in any hook (not justinit), the stack trace is filtered to remove internal framework calls. You now see exactly which line in your module caused the crash - Logger: Cleaned up internal warnings and added better filtering for stack traces
Notes
- No breaking changes. Existing modules work as-is
- Highly recommend updating to get the new Plugin and Type safety features
HangWatcher, Priorities & Profile Methods
Added
- HangWatcher - warns if a module's
inittakes longer than 10 seconds. Configurable per module withskipHangWatch = 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 negativeaddprofile:observe(key, callback)/profile:observe(path, key, callback)- subscribe to field changes. Onlynumber,string,booleantypes 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 warningsshouldCheckExtrafields- optional flag innetworktable for the validator. Default istrue. Set tofalseto allow extra fields in the payload
Fixed
DependencyResolvernow uses Kahn's algorithm with priority as a tie-breaker
Notes
asyncInitruns in parallel viatask.spawnand 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)
endDataStore Module Rework
Breaking Changes
- Now you can get profile type from
dataStoreService.profile(exported type) - Reworked methods:
profile:add(key, delta)andprofile:set(key, value)instead ofdataStoreService.add(player, key, delta)anddataStoreService.set(player, key, value) - Added paths for
IN_PLAYERentries instead ofparent getProfile(player)now returns a wrapped profile object, notprofile.Data. Access raw data viaprofile.Data.<key>or useprofile:add()/profile:set()- And a few little fixes
Examples
Before:
local dataStoreService = require("./../Global/DataStoreService")
return {
update = function()
for _, plr in game:GetService("Players"):GetPlayers() do
local profile = dataStoreService.getProfile(plr)
if not profile then continue end
profile.Coins += 1
dataStoreService.updateData(plr) -- to update leaderstats and other folders in player Instance
end
end,
playerDataLoaded = function(plr: Player, profile: any)
dataStoreService.set(plr, "Coins", 100)
dataStoreService.add(plr, "Coins", math.random(-100, 100))
end,
}After:
local dataStoreService = require("./../Global/DataStoreService")
return {
update = function()
for _, plr in game:GetService("Players"):GetPlayers() do
local profile = dataStoreService.getProfile(plr)
if not profile then continue end
profile.Data.Coins += 1
profile:updateFolders() -- to update leaderstats and other folders in player Instance
end
end,
playerDataLoaded = function(plr: Player, profile: dataStoreService.profile)
profile:set("Coins", 100)
profile:add("Coins", math.random(-100, 100))
end,
}Logger & Types
New Shared Modules in ReplicatedStorage
- Logger -
logger.register(src),this:info(),this:warn(),this:error() - Types - Shared type definitions for
ClientandServermodules
Notes
No breaking changes. Existing code continues to work as-is
Network changes
Breaking changes:
network.remote->network.channelsetupFireServer.remoteNames->setupFireServer.channelsNames- Removed
RemotesFolder inReplicatedStorage - Network now uses Jolt (bundled with the framework at
ReplicatedStorage.Modules.Global.Jolt)
Not changed:
contractonEvent
How to use on server
Instead of getting remotes from Remotes Folder, now Jolt module is required to fire client:
local replicatedStorage = game:GetService("ReplicatedStorage")
local jolt = require(replicatedStorage.Modules.Global.Jolt)
local inventoryChannel = jolt.Server("Inventory")
return {
playerAdded = function(player)
-- Fire to a specific player (server -> client)
inventoryChannel:Fire(player, "hello", 123)
end,
update = function(dt)
-- Fire to all clients
inventoryChannel:FireAll("tick", dt)
end,
}Initial release
Structure
- ReplicatedStorage
- Assets
- Modules
- Remotes
- HUD
- ServerScriptService
- Modules
- Server
- StarterPlayerScripts
- Client
Modules folder branch
- Global
- Initialize
Features
- Network Handlers - Client & server handlers with built-in rate limits and validators
- Loading Screen - Built-in loading screen
- DataStoreService - Module with Migrator, built on ProfileStore
- Version - Built-in version checker that checks for updates on server start