local util = require("openmw.util") local world = require("openmw.world") local async = require("openmw.async") local core = require("openmw.core") local types = require("openmw.types") local visitedCells = {} local cellCount = #world.cells local i = cellCount local lastTimestamp = core.getRealTime() - 100 local timeFromLast = 100 local function getExCellId(gridX, gridY) return string.format("(%d,%d)", gridX, gridY) end local function getCellId(cell) if not cell then return end if cell.isExterior then return getExCellId(cell.gridX, cell.gridY) else return (cell.id or ""):gsub(":", "") end end local function processAndTeleport(skipExtraction) local pl = world.players[1] if not skipExtraction then world.extractLocalMaps() end local function func() if world.isMapExtractionActive() then async:newUnsavableSimulationTimer(0.05, func) return elseif skipExtraction then pl:sendEvent("builtin:map_extractor:updateMenu", { line1 = "Generating local maps...", }) end repeat if i % 50 == 0 then local currentTime = core.getRealTime() timeFromLast = (timeFromLast + currentTime - lastTimestamp) / 2 lastTimestamp = currentTime end local res, cell = pcall(function () return world.cells[i] end) if not res then cell = nil end i = i - 1 local pos local customCellId = getCellId(cell) if not cell or not customCellId or visitedCells[customCellId] then goto continue end visitedCells[customCellId] = true if cell.isExterior then for j = cell.gridX - 1, cell.gridX + 1 do for k = cell.gridY - 1, cell.gridY + 1 do visitedCells[getExCellId(j, k)] = true end end end if cell.isExterior then pos = util.vector3(cell.gridX * 8192 + 4096, cell.gridY * 8192 + 4096, 0) else pos = util.vector3(0, 0, 0) end do local estimatedTimeLeft = math.max(timeFromLast, 1) / 50 * i local hours = math.floor(estimatedTimeLeft / 3600) estimatedTimeLeft = estimatedTimeLeft % 3600 local minutes = math.floor(estimatedTimeLeft / 60) local seconds = estimatedTimeLeft % 60 pl:sendEvent("builtin:map_extractor:updateMenu", { line2 = string.format("Processed %d / %d cells", cellCount - i, cellCount), line3 = string.format("Estimated time left: %d:%02d:%02.0f", hours, minutes, seconds), }) print(string.format('Teleporting to cell #%d: "%s"', i, customCellId)) pl:teleport(cell, pos) break end ::continue:: until i <= 0 if i <= 0 then pl:sendEvent("builtin:map_extractor:updateMenu", { line1 = "Map extraction complete.", line2 = "", line3 = "", }) end end async:newUnsavableSimulationTimer(0.05, func) end async:newUnsavableSimulationTimer(0.1, function () local pl = world.players[1] pl:sendEvent("builtin:map_extractor:updateMenu", {line1 = "Generating world map..."}) world.enableExtractionMode() types.Player.setControlSwitch(pl, types.Player.CONTROL_SWITCH.Controls, false) types.Player.setControlSwitch(pl, types.Player.CONTROL_SWITCH.Fighting, false) types.Player.setControlSwitch(pl, types.Player.CONTROL_SWITCH.Jumping, false) types.Player.setControlSwitch(pl, types.Player.CONTROL_SWITCH.Looking, false) types.Player.setControlSwitch(pl, types.Player.CONTROL_SWITCH.Magic, false) types.Player.setControlSwitch(pl, types.Player.CONTROL_SWITCH.VanityMode, false) types.Player.setControlSwitch(pl, types.Player.CONTROL_SWITCH.ViewMode, false) async:newUnsavableSimulationTimer(0.1, function () world.extractWorldMap() if not world.getOverwriteFlag() then for _, cellId in pairs(world.getExistingLocalMapIds() or {}) do visitedCells[cellId] = true end end processAndTeleport(true) end) end) return { eventHandlers = { ["builtin:map_extractor:teleport"] = function (pl) processAndTeleport() end, } }