Synchronize world state across editor and room saves
This commit is contained in:
parent
1965e548b4
commit
ee7d36e72b
3 changed files with 75 additions and 13 deletions
|
|
@ -492,6 +492,7 @@ local function saveRoomFromEditor()
|
|||
gameWorld:invalidatePreview(name)
|
||||
if editorView == "world" then rebuildWorldRoomButtons() end
|
||||
currentRoom.name = name
|
||||
gameWorld:setLevel(currentRoom)
|
||||
editorRoomName = name
|
||||
roomNameField:editText(name)
|
||||
activeField = nil
|
||||
|
|
@ -520,6 +521,7 @@ local function clearRuntimeSaves()
|
|||
clearSaveConfirmationScope = nil
|
||||
if roomName then
|
||||
currentRoom = Room:new{ name = roomName }
|
||||
gameWorld:setLevel(currentRoom)
|
||||
setEditorRoomName(currentRoom.name)
|
||||
editorStatus = "Cleared " .. removed .. " runtime save item(s) and reloaded '" .. roomName .. ".'"
|
||||
else
|
||||
|
|
@ -905,6 +907,7 @@ local function openWorldRoom(cellX, cellY)
|
|||
currentRoom = Room:new{ name = name }
|
||||
editorStatus = "Editing '" .. name .. ".'"
|
||||
end
|
||||
gameWorld:setLevel(currentRoom)
|
||||
gameWorld:setLastRoom(currentRoom.name)
|
||||
setEditorRoomName(currentRoom.name)
|
||||
assetsView()
|
||||
|
|
|
|||
8
main.lua
8
main.lua
|
|
@ -66,8 +66,12 @@ function love.quit()
|
|||
-- An explicit editor save/clear removes the runtime copy intentionally;
|
||||
-- don't immediately recreate it while shutting down.
|
||||
if currentRoom and not suppressRuntimeAutosave then
|
||||
currentRoom:save()
|
||||
if gameWorld then gameWorld:setLastRoom(currentRoom.name) end
|
||||
if gameWorld then
|
||||
gameWorld:markDirty(currentRoom)
|
||||
gameWorld:flushRuntime()
|
||||
else
|
||||
currentRoom:save()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
77
world.lua
77
world.lua
|
|
@ -12,15 +12,54 @@ function World:initialize()
|
|||
self.previewCache = {}
|
||||
self.lastRoom = nil
|
||||
self:load()
|
||||
self:loadRuntimeState()
|
||||
self.levels = {}
|
||||
|
||||
end
|
||||
|
||||
function World:loadLevels()
|
||||
for _, placed in ipairs(self.rooms) do self.levels[placed.name] = Room:new{name = placed.name} end
|
||||
-- Gameplay saves go to LÖVE's runtime directory. Seed every world slice
|
||||
-- through the same runtime-first loader, not just the initially visible one.
|
||||
for _, placed in ipairs(self.rooms) do self.levels[placed.name] = Room:new{name = placed.name, runtime = true} end
|
||||
self:rebuildCollision()
|
||||
end
|
||||
|
||||
-- The editor can replace a level with a freshly loaded authored Room. Keep the
|
||||
-- global simulation pointing at that exact instance, not a stale preload.
|
||||
function World:setLevel(room)
|
||||
if not room or not room.name or not self:roomLocation(room.name) then return false end
|
||||
self.levels[room.name] = room
|
||||
self:rebuildCollision()
|
||||
return true
|
||||
end
|
||||
|
||||
-- Runtime state is one logical world snapshot: each level slice is written to
|
||||
-- LÖVE's save directory, and this companion file says which slice was active.
|
||||
-- The authored world layout remains source-only for the editor.
|
||||
function World:loadRuntimeState()
|
||||
local raw = love.filesystem.read("rooms/world.sav")
|
||||
if not raw then return end
|
||||
local ok, state = pcall(TSerial.unpack, raw)
|
||||
if ok and type(state) == "table" and state.lastRoom and self:roomLocation(state.lastRoom) then
|
||||
self.lastRoom = state.lastRoom
|
||||
end
|
||||
end
|
||||
|
||||
function World:saveRuntime(dirtyRooms)
|
||||
for room in pairs(dirtyRooms or {}) do room:save() end
|
||||
return love.filesystem.write("rooms/world.sav", TSerial.pack({lastRoom = currentRoom and currentRoom.name}, nil, true))
|
||||
end
|
||||
|
||||
function World:markDirty(room)
|
||||
self.dirtyRooms = self.dirtyRooms or {}
|
||||
self.dirtyRooms[room] = true
|
||||
end
|
||||
|
||||
function World:flushRuntime()
|
||||
self:saveRuntime(self.dirtyRooms)
|
||||
self.dirtyRooms = {}
|
||||
end
|
||||
|
||||
function World:listRoomNames()
|
||||
local names = {}
|
||||
for _, file in ipairs(love.filesystem.getDirectoryItems("rooms")) do
|
||||
|
|
@ -120,7 +159,6 @@ end
|
|||
function World:setLastRoom(name)
|
||||
if name and self.lastRoom ~= name then
|
||||
self.lastRoom = name
|
||||
return self:save()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
|
@ -310,8 +348,10 @@ function World:movePlayer(room, key)
|
|||
current[color] = player:getGridPos()
|
||||
end
|
||||
if moved then
|
||||
self:markDirty(room)
|
||||
self:playerJoinCheck(room, previous, current)
|
||||
self:tick(room)
|
||||
self:flushRuntime()
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -326,6 +366,7 @@ function World:switchPlayerColor(room, color)
|
|||
end
|
||||
end
|
||||
player:playSwitchSound(canSwitch)
|
||||
if canSwitch then self:markDirty(room); self:flushRuntime() end
|
||||
return canSwitch
|
||||
end
|
||||
|
||||
|
|
@ -353,19 +394,33 @@ function World:nextRoom(room, pos)
|
|||
elseif pos.y < 1 then exit, entry.y = "top", gridHeight end
|
||||
local nextName = self:getNeighbor(room.name, exit) or room.name
|
||||
local activeColors = room:getActiveColors()
|
||||
room:save()
|
||||
room.activeColors = {red = false, green = false, blue = false}
|
||||
currentRoom = self.levels[nextName]
|
||||
self:markDirty(room)
|
||||
local destination = self.levels[nextName]
|
||||
for _, color in ipairs(activeColors) do
|
||||
if currentRoom.player[color] then
|
||||
currentRoom.player[color].x, currentRoom.player[color].y = entry.x, entry.y
|
||||
else
|
||||
currentRoom:registerPlayer(Player:new(entry.x, entry.y, color), color)
|
||||
local player = room.player[color]
|
||||
-- Active copies travel with the player. Inactive copies are deliberately
|
||||
-- left in their room so World:playerJoinCheck can merge them later.
|
||||
room.player[color] = nil
|
||||
for i = #room.colorsPlayerHas, 1, -1 do
|
||||
if room.colorsPlayerHas[i] == color then table.remove(room.colorsPlayerHas, i) end
|
||||
end
|
||||
if destination.player[color] then
|
||||
for i = #destination.colorsPlayerHas, 1, -1 do
|
||||
if destination.colorsPlayerHas[i] == color then table.remove(destination.colorsPlayerHas, i) end
|
||||
end
|
||||
end
|
||||
destination.player[color] = player
|
||||
table.insert(destination.colorsPlayerHas, color)
|
||||
end
|
||||
room.activeColors = {red = false, green = false, blue = false}
|
||||
currentRoom = destination
|
||||
self:markDirty(currentRoom)
|
||||
for _, color in ipairs(activeColors) do
|
||||
currentRoom.player[color].x, currentRoom.player[color].y = entry.x, entry.y
|
||||
currentRoom:setActiveColor(color, true)
|
||||
end
|
||||
self:playerJoinCheck(currentRoom)
|
||||
self:setLastRoom(currentRoom.name)
|
||||
self.lastRoom = currentRoom.name
|
||||
setEditorRoomName(currentRoom.name)
|
||||
end
|
||||
|
||||
|
|
@ -397,7 +452,7 @@ function World:moveGroup(group, direction)
|
|||
self:rebuildCollision()
|
||||
for room in pairs(changed) do room:resolveSwitchesAndDoors() end
|
||||
self:rebuildCollision()
|
||||
for room in pairs(changed) do if room ~= currentRoom then room:save() end end
|
||||
for room in pairs(changed) do self:markDirty(room) end
|
||||
end
|
||||
|
||||
function World:drawOverlaps(room, color)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue