From 0.8.2 Stable
Maelstrom-3 is a preview release. It includes breaking changes that improve type quality, plugin extensibility, network safety, and runtime determinism.
Use this page when migrating from the 0.8.2 stable release.
Package Version
Section titled “Package Version”Update the package version to 0.9.0-maelstrom.3. The getting-started guide uses pesde init and pesde add for a new project.
[dependencies]Riptide = "riptide/core@0.9.0-maelstrom.3"Side-Specific API
Section titled “Side-Specific API”Entry scripts should import the side they launch. Modules then receive that same side-specific API in Init, Start, and player hooks.
The important change is the value passed into the module: server modules receive Riptide.Server, and client modules receive Riptide.Client. Inside a server service, register events and access state through that injected API:
function CoinsService:Init(Riptide) Riptide.Network.Register("Ping", callback) self.DataService = Riptide.GetService("DataService")end-- ServerScriptService/main.server.lualocal Riptide = require(ReplicatedStorage.Packages.Riptide).Server
Riptide.Launch({ ModulesFolder = ServerScriptService.Services,})Network Request/Response
Section titled “Network Request/Response”If your 0.8.x code used InvokeServer, InvokeClient, or RemoteFunction-style APIs, migrate to explicit request/response events. Maelstrom networking is RemoteEvent-based to avoid blocking server threads on clients.
-- ServerRiptide.Network.RegisterTyped("RequestCoins", {}, function(player) local coins = Riptide.State:Get("coins", player) or 0 Riptide.Network.FireClient(player, "CoinsResponse", coins)end)
-- ClientRiptide.Network.Register("CoinsResponse", function(coins) print("Coins:", coins)end)
Riptide.Network.FireServer("RequestCoins")Network Middleware
Section titled “Network Middleware”Middleware now receives the payload as a mutable args table. Return false to stop dispatch.
-- Server middlewareRiptide.Network.UseMiddleware("server", function(player, eventName, args) if eventName == "BuyItem" and typeof(args[2]) ~= "number" then return false end
return trueend)Typed Network
Section titled “Typed Network”Keep RegisterTyped for boundary validation. Add typed proxies when you want field autocomplete for known events.
local Network = Riptide.Network.TypedServer<NetworkEvents>()Network.PurchaseResult:FireClient(player, true, "ok")State Replication
Section titled “State Replication”State remains server-authoritative, but Maelstrom-3 hardens malformed payload handling and adds typed key proxies.
local State = Riptide.State.TypedServer<StateSchema>()State.coins:SetForPlayer(player, 100)On the client:
local State = Riptide.State.TypedClient<StateSchema>()State.coins:Subscribe(function(coins) print(coins or 0)end)Async.Parallel
Section titled “Async.Parallel”Async.Parallel now returns explicit result objects, so successful nil, thrown errors, and timeouts are distinguishable.
local results = Riptide.Async.Parallel({ function() return "loaded" end, function() return nil end,}, 5)
for _, result in ipairs(results) do if result.ok then print(result.value) elseif result.timedOut then warn("Timed out") else warn(result.error) endendPlugins
Section titled “Plugins”Plugins are new framework-layer extensions. They load and initialize before game modules, then reach Start readiness before player replay and module Start.
Riptide.Launch({ PluginsFolder = ServerScriptService.Plugins, ModulesFolder = ServerScriptService.Services,})Normal plugin sandboxes do not expose raw core event access such as OnCoreEvent. Use namespaced sandbox APIs like sandbox:OnNetworkEvent, sandbox:Emit, sandbox:On, sandbox:Once, and sandbox:GetPluginAPI.
Lifecycle Order
Section titled “Lifecycle Order”The server startup order is now:
1. Riptide bootstrap2. Plugin Load + Init3. Shared and server module Load4. ComponentService start5. Module Init6. Plugin Start readiness7. PlayerLifecycle replay8. Module StartMove code that must exist before services/controllers into plugin Init. Move bounded setup that must complete before gameplay into plugin Start.
Validation Checklist
Section titled “Validation Checklist”- Import
.Server/.Clientin entry scripts and use the injected side API in modules. - Replace any RemoteFunction request/response flow with event pairs.
- Update Network middleware signatures to args-table form.
- Update
Async.Parallelcallers to inspect result objects. - Move framework extensions into plugins when they should be available before game modules start.
- Start the game in Studio and check server/client startup and the migrated features.
- If you are already on Maelstrom-2, review the shorter Maelstrom-2 to Maelstrom-3 guide.