Use DoesWorldExistAt() to speed up capturing

- Remove any delays
- Move UI rendering into capture coroutine, so wait(...) can be reduced
- Use wait(0) instead of wait(1) in coroutines
- Use default value of STREAMING_CHUNK_TARGET
- Don't suggest to change framerate to 600 Hz
- Don't suggest to disable mTrailerMode
- Add "Done!" screen
- Update README.md

fixes #1
fixes #5
This commit is contained in:
David Vogel 2020-06-01 22:39:00 +02:00
parent 8cf480dc37
commit 151d1d88bd
4 changed files with 161 additions and 158 deletions

View File

@ -4,16 +4,17 @@ Addon that captures the map and saves it as image.
![missing image](images/example1.png) ![missing image](images/example1.png)
A resulting image with 3.8 gigapixels can be [seen here](https://easyzoom.com/image/159431) (Warning: Spoilers). A resulting image with 3.8 gigapixels can be [seen here](https://easyzoom.com/image/203402) (Warning: Spoilers).
## System requirements ## System requirements
- Windows Vista, ..., 10 (64 bit version) - Windows Vista, ..., 10. (64 bit version)
- A few GB of free drive space - A few GB of free drive space.
- 16-32 GB of RAM (But works with less as long as the software doesn't run out of virtual memory) - 4 or more GB of RAM for gigapixel images. (But it works with less as long as the software doesn't run out of virtual memory)
- A processor - A processor.
- Optionally a monitor, keyboard and mouse to interact with the mod/software - Optionally a monitor, keyboard and mouse to interact with the mod/software.
- A sound card to listen to music while it's grabbing screenshots - A sound card to listen to music while it's grabbing screenshots.
Capturing and stitching will take about 180 minutes (160 + 20).
## Usage ## Usage
@ -30,6 +31,7 @@ A resulting image with 3.8 gigapixels can be [seen here](https://easyzoom.com/im
- Don't cover the game window. - Don't cover the game window.
- Don't move the game window outside of screen space. - Don't move the game window outside of screen space.
- If you need to pause, use the ESC menu. - If you need to pause, use the ESC menu.
- Also, make sure that the console window isn't selected, as you will end up with screenshots of the console instead of the game. You can select and use any other window while it's capturing screenshots, though.
8. When you think you are done, close noita. 8. When you think you are done, close noita.
9. Start `.../Noita/mods/noita-mapcap/bin/stitch/stitch.exe`. 9. Start `.../Noita/mods/noita-mapcap/bin/stitch/stitch.exe`.
- Use the default values to create a complete stitch. - Use the default values to create a complete stitch.
@ -50,14 +52,10 @@ Here is a step by step explanation how to do so:
<MagicNumbers <MagicNumbers
VIRTUAL_RESOLUTION_X="840" VIRTUAL_RESOLUTION_X="840"
VIRTUAL_RESOLUTION_Y="840" VIRTUAL_RESOLUTION_Y="840"
STREAMING_CHUNK_TARGET="22"
... ...
> >
``` ```
`STREAMING_CHUNK_TARGET` seems to have some influence on missing chunks while grabbing screenshots.
If you have problems with not generated (only background) areas, modify this value.
3. Change the following values inside of `.../Noita/save_shared/config.xml` (Not the one in AppData!) to 3. Change the following values inside of `.../Noita/save_shared/config.xml` (Not the one in AppData!) to
``` xml ``` xml
@ -70,7 +68,6 @@ Here is a step by step explanation how to do so:
window_h="840" window_h="840"
window_w="840" window_w="840"
fullscreen="0" fullscreen="0"
framerate="600"
... ...
> >
``` ```
@ -84,8 +81,6 @@ Here is a step by step explanation how to do so:
6. When the game is loaded (When you can control your character): 6. When the game is loaded (When you can control your character):
- Press `F5`, `F8` and `F12` (In that order). - Press `F5`, `F8` and `F12` (In that order).
- Press `F7`, and disable `mTrailerMode` in the menu. (This should reduce chunk loading problems)
- Press `F7` again to close the menu.
7. Press the `>> Start capturing full map <<` button. 7. Press the `>> Start capturing full map <<` button.
@ -95,10 +90,6 @@ Here is a step by step explanation how to do so:
## Advanced stuff ## Advanced stuff
You can increase the "countdown" time in `.../Noita/mods/noita-mapcap/files/capture.lua`.
`CAPTURE_DELAY` is the time in frames the script has to wait until it can take a screenshot.
Also, when a chunk is captured, which is not a neighbor of the previous chunk, `CAPTURE_BIGJUMP_DELAY` gets added to the countdown.
If you use `noita_dev.exe`, you can enable the debug mode by pressing `F5`. Once in debug mode, you can use `F8` to toggle shaders (Includes fog of war), and you can use `F12` to disable the UI. There are some more options in the `F7` and `Shift + F7` menu. If you use `noita_dev.exe`, you can enable the debug mode by pressing `F5`. Once in debug mode, you can use `F8` to toggle shaders (Includes fog of war), and you can use `F12` to disable the UI. There are some more options in the `F7` and `Shift + F7` menu.
You can capture in a different resolution if you want or need to. If you do so, you have to adjust some values inside of the mod. You can capture in a different resolution if you want or need to. If you do so, you have to adjust some values inside of the mod.

View File

@ -5,8 +5,6 @@
CAPTURE_PIXEL_SIZE = 1 -- Screen to virtual pixel ratio CAPTURE_PIXEL_SIZE = 1 -- Screen to virtual pixel ratio
CAPTURE_GRID_SIZE = 420 -- in ingame pixels. There will always be 3 to 6 images overlapping CAPTURE_GRID_SIZE = 420 -- in ingame pixels. There will always be 3 to 6 images overlapping
CAPTURE_DELAY = 8 -- in frames
CAPTURE_BIGJUMP_DELAY = 20 -- in frames. Additional delay after doing a "larger than grid jump"
CAPTURE_FORCE_HP = 4 -- * 25HP CAPTURE_FORCE_HP = 4 -- * 25HP
CAPTURE_LEFT = -25000 -- in ingame pixels. Left edge of the full map capture rectangle CAPTURE_LEFT = -25000 -- in ingame pixels. Left edge of the full map capture rectangle
@ -26,31 +24,37 @@ local function preparePlayer()
setPlayerHP(CAPTURE_FORCE_HP) setPlayerHP(CAPTURE_FORCE_HP)
end end
local xOld, yOld = 0, 0
local function captureScreenshot(x, y, rx, ry) local function captureScreenshot(x, y, rx, ry)
-- "Larger than grid jump" delay local virtualWidth, virtualHeight =
local delay = CAPTURE_DELAY - 1 tonumber(MagicNumbersGetValue("VIRTUAL_RESOLUTION_X")),
if math.abs(x - xOld) > CAPTURE_GRID_SIZE or math.abs(y - yOld) > CAPTURE_GRID_SIZE then tonumber(MagicNumbersGetValue("VIRTUAL_RESOLUTION_Y"))
delay = delay + CAPTURE_BIGJUMP_DELAY
end
xOld, yOld = x, y
-- Set pos several times, so that chunks will load even if nothing happens in the surrounding local virtualHalfWidth, virtualHalfHeight = math.floor(virtualWidth / 2), math.floor(virtualHeight / 2)
-- This prevents black blocks in areas without entites local xMin, yMin = x - virtualHalfWidth, y - virtualHalfHeight
UiHideCountdown = delay local xMax, yMax = xMin + virtualWidth, yMin + virtualHeight
for i = 1, delay, 1 do
GameSetCameraPos(x, y)
wait(1)
UiHideCountdown = UiHideCountdown - 1
end
GameSetCameraPos(x, y)
UiHide = true -- Hide UI while capturing the screenshot UiCaptureDelay = 0
wait(1) GameSetCameraPos(x, y)
repeat
if UiCaptureDelay > 100 then
-- Wiggle the screen a bit, as chunks sometimes don't want to load
GameSetCameraPos(x+math.random(-100, 100), y+math.random(-100, 100))
DrawUI()
wait(0)
UiCaptureDelay = UiCaptureDelay + 1
GameSetCameraPos(x, y)
end
DrawUI()
wait(0)
UiCaptureDelay = UiCaptureDelay + 1
until DoesWorldExistAt(xMin, yMin, xMax, yMax) -- Chunks will be drawn on the *next* frame
wait(0) -- Without this line empty chunks may still appear, also it's needed for the UI to disappear
if not TriggerCapture(rx, ry) then if not TriggerCapture(rx, ry) then
UiCaptureProblem = "Screen capture failed. Please restart Noita." UiCaptureProblem = "Screen capture failed. Please restart Noita."
end end
UiHide = false
-- Reset monitor and PC standby each screenshot -- Reset monitor and PC standby each screenshot
ResetStandbyTimer() ResetStandbyTimer()
@ -161,6 +165,8 @@ function startCapturingHilbert()
t = t + 1 t = t + 1
end end
UiProgress.Done = true
end end
) )
end end

View File

@ -1,6 +1,5 @@
<MagicNumbers VIRTUAL_RESOLUTION_X="1280" <MagicNumbers VIRTUAL_RESOLUTION_X="1280"
VIRTUAL_RESOLUTION_Y="720" VIRTUAL_RESOLUTION_Y="720"
STREAMING_CHUNK_TARGET="22"
DRAW_PARALLAX_BACKGROUND="0" DRAW_PARALLAX_BACKGROUND="0"
DEBUG_FREE_CAMERA_SPEED="10" DEBUG_FREE_CAMERA_SPEED="10"
DEBUG_NO_LOGO_SPLASHES="1" DEBUG_NO_LOGO_SPLASHES="1"

View File

@ -3,19 +3,17 @@
-- This software is released under the MIT License. -- This software is released under the MIT License.
-- https://opensource.org/licenses/MIT -- https://opensource.org/licenses/MIT
UiHide = false UiCaptureDelay = 0 -- Waiting time in frames
UiHideCountdown = 0
local UiReduce = false
UiProgress = nil UiProgress = nil
UiCaptureProblem = nil UiCaptureProblem = nil
async_loop( function DrawUI()
function()
if modGUI ~= nil then if modGUI ~= nil then
GuiStartFrame(modGUI) GuiStartFrame(modGUI)
GuiLayoutBeginVertical(modGUI, 50, 50) GuiLayoutBeginVertical(modGUI, 50, 50)
if not UiReduce then if not UiProgress then
-- Show informations
local problem local problem
local rect = GetRect() local rect = GetRect()
@ -61,6 +59,7 @@ async_loop(
if math.abs(ratioX - ratioY) < 0.0001 then if math.abs(ratioX - ratioY) < 0.0001 then
GuiTextCentered(modGUI, 0, 0, string.format("- Change the CAPTURE_PIXEL_SIZE in the mod to %f", ratioX)) GuiTextCentered(modGUI, 0, 0, string.format("- Change the CAPTURE_PIXEL_SIZE in the mod to %f", ratioX))
end end
GuiTextCentered(modGUI, 0, 0, '- Make sure that the console is not selected')
GuiTextCentered(modGUI, 0, 0, " ") GuiTextCentered(modGUI, 0, 0, " ")
problem = true problem = true
end end
@ -106,20 +105,20 @@ async_loop(
) )
GuiTextCentered(modGUI, 0, 0, " ") GuiTextCentered(modGUI, 0, 0, " ")
if GuiButton(modGUI, 0, 0, ">> Start capturing map around view <<", 1) then if GuiButton(modGUI, 0, 0, ">> Start capturing map around view <<", 1) then
UiProgress = {}
startCapturingSpiral() startCapturingSpiral()
UiReduce = true
end end
if GuiButton(modGUI, 0, 0, ">> Start capturing full map <<", 1) then if GuiButton(modGUI, 0, 0, ">> Start capturing full map <<", 1) then
UiProgress = {}
startCapturingHilbert() startCapturingHilbert()
UiReduce = true
end end
GuiTextCentered(modGUI, 0, 0, " ") GuiTextCentered(modGUI, 0, 0, " ")
end elseif not UiProgress.Done then
if not UiHide then -- Show progress
local x, y = GameGetCameraPos() local x, y = GameGetCameraPos()
GuiTextCentered(modGUI, 0, 0, string.format("Coordinates: %d, %d", x, y)) GuiTextCentered(modGUI, 0, 0, string.format("Coordinates: %d, %d", x, y))
GuiTextCentered(modGUI, 0, 0, string.format("Countdown: %d", UiHideCountdown)) GuiTextCentered(modGUI, 0, 0, string.format("Waiting %d frames...", UiCaptureDelay))
if UiProgress then if UiProgress.Progress then
GuiTextCentered( GuiTextCentered(
modGUI, modGUI,
0, 0,
@ -133,10 +132,18 @@ async_loop(
if UiCaptureProblem then if UiCaptureProblem then
GuiTextCentered(modGUI, 0, 0, string.format("A problem occurred while capturing: %s", UiCaptureProblem)) GuiTextCentered(modGUI, 0, 0, string.format("A problem occurred while capturing: %s", UiCaptureProblem))
end end
else
GuiTextCentered(modGUI, 0, 0, "Done!")
end end
GuiLayoutEnd(modGUI) GuiLayoutEnd(modGUI)
end end
end
async_loop(
function()
-- When capturing is active, DrawUI is called from a different coroutine
-- This ensures that the text is drawn *after* a screenshot has been grabbed
if not UiProgress or UiProgress.Done then DrawUI() end
wait(0) wait(0)
end end
) )