Help making a dungeon system

Hello, I am developing an RPG dungeon game that follows a storyline, similiar to PWNED: Aeternae Memori. I’m wondering what the best way to handle the dungeon system is.

My idea is that there is one default dungeon place and all the maps are stored in server storage, then when the player selects the stage and enters, loads the corresponding map and data then teleports the player over to the place. Each stage has a singleplayer only story mode with NPCs, dialogue and maybe cutscenes, and a multiplayer/gameplay mode that removes the story parts.

My problem is that I’m not sure how to create a new server of the place every time a player enters a dungeon, and how to efficiently update the scripts in the dungeon place in sync with the lobby as the combat system is also in the lobby area. There are also many chapters with each chapter having many stages, so the serverstorage of the dungeon place may end up taking a lot of storage.

1 Like

Im a little lost, making a new server?

you could just use ReservePrivateServerAsync() and teleport the player there

A few things here, taking your three problems separately — the server one is
the easy one and the other two are the ones that actually bite.

You don’t create servers, you reserve them. TeleportService:ReserveServer
gives you a private server for one dungeon run. It’s server-side only, and it
hands back two values — you want the first one:

local TeleportService = game:GetService("TeleportService")

local accessCode = TeleportService:ReserveServer(DUNGEON_PLACE_ID)

local options = Instance.new("TeleportOptions")
options.ReservedServerAccessCode = accessCode
options:SetTeleportData({
    chapter = 2,
    stage = 5,
    mode = "story",
})

TeleportService:TeleportAsync(DUNGEON_PLACE_ID, {player}, options)

On the other side, read it back with player:GetJoinData().TeleportData
not from a RemoteEvent, and not from a DataStore you wrote a second earlier.
If you need the dungeon place to know it’s a real dungeon run rather than
someone who joined it directly, check game.PrivateServerId ~= "" together
with game.PrivateServerOwnerId == 0. That pair means “reserved server”, as
opposed to a paid VIP server, where the owner id is non-zero.

Party of four goes in one TeleportAsync call with all four players in the
table — same access code, same server. Don’t loop and teleport them one at a
time, or you can race and get two servers.

The script-sync problem is the one I’d solve first, because it will cost you
months.
Two places with a copy of the combat system each is a fork, and it
will drift the first time you hotfix one at 2am. Use Packages: right-click the
combat ModuleScript folder → Convert to Package, then insert that same package
into the dungeon place. When you publish a new version, the other place shows
the update prompt instead of you diffing two copies by hand. It’s the one
Studio feature that’s actually built for exactly your situation.

Structure it so the shared package is pure logic — no assumptions about
workspace.Lobby existing — and each place passes in its own configuration at
startup. If the combat module has to know which place it’s running in, that’s
the seam where the fork comes back.

ServerStorage bloat: stop shipping the maps inside the place. Every map in
ServerStorage is in the place file, so it’s paid for at server start by every
run, including the runs that load one map and never touch the other forty.

Publish each map as its own Model asset and pull it in on demand:

local InsertService = game:GetService("InsertService")

local ok, result = pcall(function()
    return InsertService:LoadAsset(mapAssetId)
end)

if ok then
    result:GetChildren()[1].Parent = workspace
    result:Destroy()
end

Two constraints worth knowing before you commit: the assets have to be owned
by whoever owns the place (or the group), or LoadAsset refuses them, and it
yields — so load the map before you let the players in, not after. Keep a table
of {chapter, stage} -> assetId in the dungeon place and you can add a chapter
without republishing anything.

Once maps are assets, the “singleplayer story vs multiplayer” split is just
which extra models you load on top — NPCs, dialogue triggers and cutscene rigs
as separate assets layered onto the same base map, rather than two whole copies
of every stage.

Verification of every specific in it: ReserveServer, `TeleportOptions