mirror of
				https://github.com/Dadido3/noita-mapcap.git
				synced 2025-11-04 07:19:34 +00:00 
			
		
		
		
	Compare commits
	
		
			No commits in common. "master" and "v2.20.0" have entirely different histories.
		
	
	
		
	
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -109,5 +109,3 @@ $RECYCLE.BIN/
 | 
				
			|||||||
/bin/stitch/*.dzi
 | 
					/bin/stitch/*.dzi
 | 
				
			||||||
/bin/stitch/*_files/
 | 
					/bin/stitch/*_files/
 | 
				
			||||||
/files/magic-numbers/generated.xml
 | 
					/files/magic-numbers/generated.xml
 | 
				
			||||||
 | 
					 | 
				
			||||||
/bin/stitch/captures/*
 | 
					 | 
				
			||||||
							
								
								
									
										5
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							@ -1,7 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "cSpell.words": [
 | 
					    "cSpell.words": [
 | 
				
			||||||
        "aabb",
 | 
					        "aabb",
 | 
				
			||||||
        "acidflow",
 | 
					 | 
				
			||||||
        "appdata",
 | 
					        "appdata",
 | 
				
			||||||
        "autosetup",
 | 
					        "autosetup",
 | 
				
			||||||
        "backbuffer",
 | 
					        "backbuffer",
 | 
				
			||||||
@ -41,24 +40,20 @@
 | 
				
			|||||||
        "nfnt",
 | 
					        "nfnt",
 | 
				
			||||||
        "Niccoli",
 | 
					        "Niccoli",
 | 
				
			||||||
        "noita",
 | 
					        "noita",
 | 
				
			||||||
        "noitamap",
 | 
					 | 
				
			||||||
        "Nolla",
 | 
					        "Nolla",
 | 
				
			||||||
        "NXML",
 | 
					        "NXML",
 | 
				
			||||||
        "openseadragon",
 | 
					 | 
				
			||||||
        "pixelated",
 | 
					        "pixelated",
 | 
				
			||||||
        "polymorphed",
 | 
					        "polymorphed",
 | 
				
			||||||
        "promptui",
 | 
					        "promptui",
 | 
				
			||||||
        "rasterizer",
 | 
					        "rasterizer",
 | 
				
			||||||
        "Regen",
 | 
					        "Regen",
 | 
				
			||||||
        "respawn",
 | 
					        "respawn",
 | 
				
			||||||
        "runfast",
 | 
					 | 
				
			||||||
        "savegames",
 | 
					        "savegames",
 | 
				
			||||||
        "schollz",
 | 
					        "schollz",
 | 
				
			||||||
        "screenshake",
 | 
					        "screenshake",
 | 
				
			||||||
        "svenstaro",
 | 
					        "svenstaro",
 | 
				
			||||||
        "tcnksm",
 | 
					        "tcnksm",
 | 
				
			||||||
        "tdewolff",
 | 
					        "tdewolff",
 | 
				
			||||||
        "unmodded",
 | 
					 | 
				
			||||||
        "unstitchable",
 | 
					        "unstitchable",
 | 
				
			||||||
        "upscaled",
 | 
					        "upscaled",
 | 
				
			||||||
        "Vogel",
 | 
					        "Vogel",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								AREAS.md
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								AREAS.md
									
									
									
									
									
								
							@ -1,10 +1,6 @@
 | 
				
			|||||||
# Capture areas
 | 
					# Capture areas
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A list of available capture areas.
 | 
					A list of available capture areas.
 | 
				
			||||||
Other game-modes or mods may use a different biome setup, and therefore the coordinates shown here are not valid for them.
 | 
					 | 
				
			||||||
The values shown are for an unmodded `New Game` world.
 | 
					 | 
				
			||||||
The noita-mapcap mod will always automatically determine the required coordinates so that it correctly captures the base layout or multiples of it.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Coordinates are in in-game "virtual" or "world" pixels.
 | 
					Coordinates are in in-game "virtual" or "world" pixels.
 | 
				
			||||||
`Right` and `Bottom` coordinates are not included in the rectangle.
 | 
					`Right` and `Bottom` coordinates are not included in the rectangle.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										29
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								README.md
									
									
									
									
									
								
							@ -5,10 +5,7 @@ It works with the regular Noita build and the dev build.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||

 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Map captures created with this mod can be viewed on [map.runfast.stream] (may contain spoilers).
 | 
					A resulting image with nearly 3.8 gigapixels can be [seen here](https://easyzoom.com/image/223556) (May contain spoilers).
 | 
				
			||||||
 | 
					 | 
				
			||||||
If you are interested in creating similar captures, or if you want to contribute your own captures to [map.runfast.stream], you can take a look at [github.com/acidflow-noita/noitamap].
 | 
					 | 
				
			||||||
There you'll find detailed step-by-step instructions on how to quickly capture large parts of the Noita world with as little visual glitches and other issues as possible.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
## System requirements
 | 
					## System requirements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -58,7 +55,8 @@ To the top left of the window are 3 buttons:
 | 
				
			|||||||
-  Reveals the output directory in your file browser.
 | 
					-  Reveals the output directory in your file browser.
 | 
				
			||||||
  This will contain raw screenshots and other recorded data that later can be stitched.
 | 
					  This will contain raw screenshots and other recorded data that later can be stitched.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-  Reveals the stitching tool directory in your file browser.
 | 
					-  Reveals the stitching tool 
 | 
				
			||||||
 | 
					directory in your file browser.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To stitch the final result, click  to open the directory of the stitching tool.
 | 
					To stitch the final result, click  to open the directory of the stitching tool.
 | 
				
			||||||
Start `stitch.exe` and proceed with the default values.
 | 
					Start `stitch.exe` and proceed with the default values.
 | 
				
			||||||
@ -81,10 +79,6 @@ After a few minutes the file `output.png` will be created.
 | 
				
			|||||||
  - `Spiral`: Will capture the world in a spiral.
 | 
					  - `Spiral`: Will capture the world in a spiral.
 | 
				
			||||||
    The center starting point of the spiral can either be your current viewport, the world center or some custom coordinates.
 | 
					    The center starting point of the spiral can either be your current viewport, the world center or some custom coordinates.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - `Animation`: Will capture an image sequence.
 | 
					 | 
				
			||||||
    This will capture whatever you see frame by frame and stores it in the output folder by frame number.
 | 
					 | 
				
			||||||
    You can't stitch the resulting images, but instead you can use something like ffmpeg to render the sequence into a video file.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Advanced mod settings
 | 
					### Advanced mod settings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- `World seed`: If non empty, this will set the next new game to this seed.
 | 
					- `World seed`: If non empty, this will set the next new game to this seed.
 | 
				
			||||||
@ -152,7 +146,7 @@ The sliders are at their default values:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
There is not a lot you can do about it:
 | 
					There is not a lot you can do about it:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- ~~You can try to increase the usable address space of your `.../Noita/noita_dev.exe` or `.../Noita/noita.exe` with [Large Address Aware] or a similar tool.
 | 
					- ~~You can try to increase the usable address space of your `.../Noita/noita_dev.exe` or `.../Noita/noita.exe` with [Large Address Aware](https://www.techpowerup.com/forums/threads/large-address-aware.112556/) or a similar tool.
 | 
				
			||||||
  This will help with any crashes that are related to out of memory exceptions.~~
 | 
					  This will help with any crashes that are related to out of memory exceptions.~~
 | 
				
			||||||
  `Large Address Aware` is already set in newer Noita builds.
 | 
					  `Large Address Aware` is already set in newer Noita builds.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -196,28 +190,17 @@ This will cause fast moving objects to completely disappear, and slow moving obj
 | 
				
			|||||||
To disable median blending, use the stitcher with `Blend tile limit` set to 1.
 | 
					To disable median blending, use the stitcher with `Blend tile limit` set to 1.
 | 
				
			||||||
This will cause the stitcher to only use the newest image tile for every resulting pixel.
 | 
					This will cause the stitcher to only use the newest image tile for every resulting pixel.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Viewing and hosting captures
 | 
					## Additional information
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The resulting stitched images are quite big.
 | 
					The resulting stitched images are quite big.
 | 
				
			||||||
You can read [this comment](https://github.com/Dadido3/noita-mapcap/issues/7#issuecomment-723591552) that addresses how you can view, convert or even self-host your images.
 | 
					You can read [this comment](https://github.com/Dadido3/noita-mapcap/issues/7#issuecomment-723591552) that addresses how you can view, convert or even self-host your images.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You can use [github.com/Dadido3/noita-mapcap-openseadragon] if you want to host a browser based viewer on your own web space.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
If you want to make your captures available to a wider audience, you should check out the [github.com/acidflow-noita/noitamap] project, which aims to make maps of all game modes (including mods) available to the public.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Acknowledgements
 | 
					## Acknowledgements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This mod uses the [LuaNXML] library by [Zatherz].
 | 
					This mod uses the [LuaNXML](https://github.com/zatherz/luanxml) library by [Zatherz](https://github.com/zatherz).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Thanks to [Daniel Niccoli](https://github.com/danielniccoli) for figuring out how to change some in-game options by manipulating process memory.
 | 
					Thanks to [Daniel Niccoli](https://github.com/danielniccoli) for figuring out how to change some in-game options by manipulating process memory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## License
 | 
					## License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[MIT](LICENSE)
 | 
					[MIT](LICENSE)
 | 
				
			||||||
 | 
					 | 
				
			||||||
[github.com/acidflow-noita/noitamap]: https://github.com/acidflow-noita/noitamap
 | 
					 | 
				
			||||||
[github.com/Dadido3/noita-mapcap-openseadragon]: https://github.com/Dadido3/noita-mapcap-openseadragon
 | 
					 | 
				
			||||||
[Large Address Aware]: https://www.techpowerup.com/forums/threads/large-address-aware.112556/
 | 
					 | 
				
			||||||
[LuaNXML]: https://github.com/zatherz/luanxml
 | 
					 | 
				
			||||||
[map.runfast.stream]: https://map.runfast.stream
 | 
					 | 
				
			||||||
[Zatherz]: https://github.com/zatherz
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -132,6 +132,8 @@ ProcedureDLL Capture(*capRect.RECT, x.l, y.l, sx.l, sy.l)
 | 
				
			|||||||
		ProcedureReturn #False
 | 
							ProcedureReturn #False
 | 
				
			||||||
	EndIf
 | 
						EndIf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						;Protected *pixelBuf = AllocateMemory(3 * width * height)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hDC = StartDrawing(ImageOutput(imageID))
 | 
						hDC = StartDrawing(ImageOutput(imageID))
 | 
				
			||||||
	If Not hDC
 | 
						If Not hDC
 | 
				
			||||||
		FreeImage(imageID)
 | 
							FreeImage(imageID)
 | 
				
			||||||
@ -140,11 +142,19 @@ ProcedureDLL Capture(*capRect.RECT, x.l, y.l, sx.l, sy.l)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	*pixelBuffer = DrawingBuffer()
 | 
						*pixelBuffer = DrawingBuffer()
 | 
				
			||||||
	glReadPixels_(*capRect\left, *capRect\top, capWidth, capHeight, #GL_BGR_EXT, #GL_UNSIGNED_BYTE, *pixelBuffer)
 | 
						glReadPixels_(*capRect\left, *capRect\top, capWidth, capHeight, #GL_BGR_EXT, #GL_UNSIGNED_BYTE, *pixelBuffer)
 | 
				
			||||||
	If glGetError_() <> #GL_NO_ERROR
 | 
					
 | 
				
			||||||
		StopDrawing()
 | 
					;	For y = 0 To *capRect\height - 1
 | 
				
			||||||
		FreeImage(imageID)
 | 
					;		*Line.Pixel = Buffer + Pitch * y
 | 
				
			||||||
		ProcedureReturn #False
 | 
					;
 | 
				
			||||||
	EndIf
 | 
					;		For x = 0 To *capRect\width - 1
 | 
				
			||||||
 | 
					;
 | 
				
			||||||
 | 
					;			*Line\Pixel = ColorTable(pos2) ; Write the pixel directly to the memory !
 | 
				
			||||||
 | 
					;			*Line+Offset
 | 
				
			||||||
 | 
					;
 | 
				
			||||||
 | 
					;			; You can try with regular plot to see the speed difference
 | 
				
			||||||
 | 
					;			; Plot(x, y, ColorTable(pos2))
 | 
				
			||||||
 | 
					;		Next
 | 
				
			||||||
 | 
					;	Next
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	StopDrawing()
 | 
						StopDrawing()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -178,8 +188,8 @@ EndProcedure
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
; IDE Options = PureBasic 6.04 LTS (Windows - x64)
 | 
					; IDE Options = PureBasic 6.04 LTS (Windows - x64)
 | 
				
			||||||
; ExecutableFormat = Shared dll
 | 
					; ExecutableFormat = Shared dll
 | 
				
			||||||
; CursorPosition = 99
 | 
					; CursorPosition = 116
 | 
				
			||||||
; FirstLine = 72
 | 
					; FirstLine = 99
 | 
				
			||||||
; Folding = -
 | 
					; Folding = -
 | 
				
			||||||
; Optimizer
 | 
					; Optimizer
 | 
				
			||||||
; EnableThread
 | 
					; EnableThread
 | 
				
			||||||
 | 
				
			|||||||
										
											Binary file not shown.
										
									
								
							@ -166,37 +166,6 @@ local function captureScreenshot(pos, ensureLoaded, dontOverwrite, ctx, outputPi
 | 
				
			|||||||
	MonitorStandby.ResetTimer()
 | 
						MonitorStandby.ResetTimer()
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---Captures a screenshot of the current viewport.
 | 
					 | 
				
			||||||
---This is used to capture animations, therefore the resulting image may not be suitable for stitching.
 | 
					 | 
				
			||||||
---@param outputPixelScale number? The resulting image pixel to world pixel ratio.
 | 
					 | 
				
			||||||
---@param frameNumber integer The frame number of the animation.
 | 
					 | 
				
			||||||
local function captureScreenshotAnimation(outputPixelScale, frameNumber)
 | 
					 | 
				
			||||||
	if outputPixelScale == 0 or outputPixelScale == nil then
 | 
					 | 
				
			||||||
		outputPixelScale = Coords:PixelScale()
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local rectTopLeft, rectBottomRight = ScreenCapture.GetRect()
 | 
					 | 
				
			||||||
	if not rectTopLeft or not rectBottomRight then
 | 
					 | 
				
			||||||
		error(string.format("couldn't determine capturing rectangle"))
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
	if Coords:InternalRectSize() ~= rectBottomRight - rectTopLeft then
 | 
					 | 
				
			||||||
		error(string.format("internal rectangle size seems to have changed from %s to %s", Coords:InternalRectSize(), rectBottomRight - rectTopLeft))
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	local topLeftWorld, bottomRightWorld = Coords:ToWorld(rectTopLeft), Coords:ToWorld(rectBottomRight)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	---We will use this to get our fame number into the filename.
 | 
					 | 
				
			||||||
	---@type Vec2
 | 
					 | 
				
			||||||
	local outputTopLeft = Vec2(frameNumber, 0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if not ScreenCapture.Capture(rectTopLeft, rectBottomRight, outputTopLeft, (bottomRightWorld - topLeftWorld) * outputPixelScale) then
 | 
					 | 
				
			||||||
		error(string.format("failed to capture screenshot"))
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	-- Reset monitor and PC standby every screenshot.
 | 
					 | 
				
			||||||
	MonitorStandby.ResetTimer()
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
---Map capture process runner context error handler callback. Just rolls off the tongue.
 | 
					---Map capture process runner context error handler callback. Just rolls off the tongue.
 | 
				
			||||||
---@param err string
 | 
					---@param err string
 | 
				
			||||||
---@param scope "init"|"do"|"end"
 | 
					---@param scope "init"|"do"|"end"
 | 
				
			||||||
@ -781,56 +750,6 @@ function Capture:StartCapturingPlayerPath(interval, outputPixelScale)
 | 
				
			|||||||
	self.PlayerPathCapturingCtx:Run(handleInit, handleDo, handleEnd, handleErr)
 | 
						self.PlayerPathCapturingCtx:Run(handleInit, handleDo, handleEnd, handleErr)
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---Starts to capture an animation.
 | 
					 | 
				
			||||||
---This stores sequences of images that can't be stitched, but can be rendered into a video instead.
 | 
					 | 
				
			||||||
---Use `Capture.MapCapturingCtx` to stop, control or view the process.
 | 
					 | 
				
			||||||
---@param outputPixelScale number? -- The resulting image pixel to world pixel ratio.
 | 
					 | 
				
			||||||
function Capture:StartCapturingAnimation(outputPixelScale)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	---Queries the mod settings for the live capture parameters.
 | 
					 | 
				
			||||||
	---@return integer interval -- The interval length in frames.
 | 
					 | 
				
			||||||
	local function querySettings()
 | 
					 | 
				
			||||||
		local interval = 1--tonumber(ModSettingGet("noita-mapcap.live-interval")) or 30
 | 
					 | 
				
			||||||
		return interval
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	-- Create file that signals that there are files in the output directory.
 | 
					 | 
				
			||||||
	local file = io.open("mods/noita-mapcap/output/nonempty", "a")
 | 
					 | 
				
			||||||
	if file ~= nil then file:close() end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	---Process main callback.
 | 
					 | 
				
			||||||
	---@param ctx ProcessRunnerCtx
 | 
					 | 
				
			||||||
	local function handleDo(ctx)
 | 
					 | 
				
			||||||
		Modification.SetCameraFree(false)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		local frame = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		repeat
 | 
					 | 
				
			||||||
			local interval = querySettings()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			-- Wait until we are allowed to take a new screenshot.
 | 
					 | 
				
			||||||
			local delayFrames = 0
 | 
					 | 
				
			||||||
			repeat
 | 
					 | 
				
			||||||
				wait(0)
 | 
					 | 
				
			||||||
				delayFrames = delayFrames + 1
 | 
					 | 
				
			||||||
			until ctx:IsStopping() or delayFrames >= interval
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			captureScreenshotAnimation(outputPixelScale, frame)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			frame = frame + 1
 | 
					 | 
				
			||||||
		until ctx:IsStopping()
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	---Process end callback.
 | 
					 | 
				
			||||||
	---@param ctx ProcessRunnerCtx
 | 
					 | 
				
			||||||
	local function handleEnd(ctx)
 | 
					 | 
				
			||||||
		Modification.SetCameraFree()
 | 
					 | 
				
			||||||
	end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	-- Run process, if there is no other running right now.
 | 
					 | 
				
			||||||
	self.MapCapturingCtx:Run(nil, handleDo, handleEnd, mapCapturingCtxErrHandler)
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
---Starts the capturing process based on user/mod settings.
 | 
					---Starts the capturing process based on user/mod settings.
 | 
				
			||||||
function Capture:StartCapturing()
 | 
					function Capture:StartCapturing()
 | 
				
			||||||
	Message:CatchException("Capture:StartCapturing", function()
 | 
						Message:CatchException("Capture:StartCapturing", function()
 | 
				
			||||||
@ -843,8 +762,6 @@ function Capture:StartCapturing()
 | 
				
			|||||||
		if mode == "live" then
 | 
							if mode == "live" then
 | 
				
			||||||
			self:StartCapturingLive(outputPixelScale)
 | 
								self:StartCapturingLive(outputPixelScale)
 | 
				
			||||||
			self:StartCapturingPlayerPath(5, outputPixelScale) -- Capture player path with an interval of 5 frames.
 | 
								self:StartCapturingPlayerPath(5, outputPixelScale) -- Capture player path with an interval of 5 frames.
 | 
				
			||||||
		elseif mode == "animation" then
 | 
					 | 
				
			||||||
			self:StartCapturingAnimation(outputPixelScale)
 | 
					 | 
				
			||||||
		elseif mode == "area" then
 | 
							elseif mode == "area" then
 | 
				
			||||||
			local area = ModSettingGet("noita-mapcap.area")
 | 
								local area = ModSettingGet("noita-mapcap.area")
 | 
				
			||||||
			if area == "custom" then
 | 
								if area == "custom" then
 | 
				
			||||||
@ -853,11 +770,9 @@ function Capture:StartCapturing()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				self:StartCapturingAreaScan(topLeft, bottomRight, captureGridSize, outputPixelScale, captureDelay)
 | 
									self:StartCapturingAreaScan(topLeft, bottomRight, captureGridSize, outputPixelScale, captureDelay)
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				---@type fun():Vec2, Vec2
 | 
									local predefinedArea = Config.CaptureArea[area]
 | 
				
			||||||
				local predefinedAreaFunction = Config.CaptureArea[area]
 | 
									if predefinedArea then
 | 
				
			||||||
				if predefinedAreaFunction then
 | 
										self:StartCapturingAreaScan(predefinedArea.TopLeft, predefinedArea.BottomRight, captureGridSize, outputPixelScale, captureDelay)
 | 
				
			||||||
					local topLeft, bottomRight = predefinedAreaFunction()
 | 
					 | 
				
			||||||
					self:StartCapturingAreaScan(topLeft, bottomRight, captureGridSize, outputPixelScale, captureDelay)
 | 
					 | 
				
			||||||
				else
 | 
									else
 | 
				
			||||||
					Message:ShowRuntimeError("PredefinedArea", string.format("Unknown predefined capturing area %q", tostring(area)))
 | 
										Message:ShowRuntimeError("PredefinedArea", string.format("Unknown predefined capturing area %q", tostring(area)))
 | 
				
			||||||
				end
 | 
									end
 | 
				
			||||||
 | 
				
			|||||||
@ -120,7 +120,7 @@ function Check:Regular(interval)
 | 
				
			|||||||
	-- This is not perfect, as it doesn't take rounding and cropping into account, so the actual captured area may be a few pixels smaller.
 | 
						-- This is not perfect, as it doesn't take rounding and cropping into account, so the actual captured area may be a few pixels smaller.
 | 
				
			||||||
	local mode = ModSettingGet("noita-mapcap.capture-mode")
 | 
						local mode = ModSettingGet("noita-mapcap.capture-mode")
 | 
				
			||||||
	local captureGridSize = tonumber(ModSettingGet("noita-mapcap.grid-size"))
 | 
						local captureGridSize = tonumber(ModSettingGet("noita-mapcap.grid-size"))
 | 
				
			||||||
	if (mode ~= "live" and mode ~= "animation") and (Coords.VirtualResolution.x < captureGridSize or Coords.VirtualResolution.y < captureGridSize) then
 | 
						if mode ~= "live" and (Coords.VirtualResolution.x < captureGridSize or Coords.VirtualResolution.y < captureGridSize) then
 | 
				
			||||||
		Message:ShowGeneralSettingsProblem(
 | 
							Message:ShowGeneralSettingsProblem(
 | 
				
			||||||
			"The virtual resolution is smaller than the capture grid size.",
 | 
								"The virtual resolution is smaller than the capture grid size.",
 | 
				
			||||||
			"This means that you will get black areas in your final stitched image.",
 | 
								"This means that you will get black areas in your final stitched image.",
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,6 @@
 | 
				
			|||||||
-- 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local NXML = require("luanxml.nxml")
 | 
					 | 
				
			||||||
local Vec2 = require("noita-api.vec2")
 | 
					local Vec2 = require("noita-api.vec2")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- List of components that will be disabled on every encountered entity.
 | 
					-- List of components that will be disabled on every encountered entity.
 | 
				
			||||||
@ -28,65 +27,40 @@ Config.ComponentsToDisable = {
 | 
				
			|||||||
	--"AudioComponent",
 | 
						--"AudioComponent",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local CHUNK_SIZE = 512
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
---Returns the rectangle of the base area as two vectors.
 | 
					 | 
				
			||||||
---@return Vec2 TopLeft Top left corner in world coordinates.
 | 
					 | 
				
			||||||
---@return Vec2 BottomRight Bottom right corner in world coordinates. This pixel is not included in the final rectangle.
 | 
					 | 
				
			||||||
local function getBaseArea()
 | 
					 | 
				
			||||||
	local xml = NXML.parse(ModTextFileGetContent("data/biome/_biomes_all.xml"))
 | 
					 | 
				
			||||||
	local width, height = BiomeMapGetSize()
 | 
					 | 
				
			||||||
	local offsetX, offsetY = math.floor(width/2), xml.attr.biome_offset_y -- TODO: This may not be right. Check what Noita is really doing when we have a biome map with an odd width.
 | 
					 | 
				
			||||||
	return Vec2(-offsetX, -offsetY)*CHUNK_SIZE, Vec2(-offsetX+width, -offsetY+height)*CHUNK_SIZE
 | 
					 | 
				
			||||||
	--return Vec2(-17920, -7168), Vec2(17920, 17408) -- Coordinates for a "New Game" without mods or anything.
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
---A list of capture areas.
 | 
					 | 
				
			||||||
---This contains functions that determine the capture area based on the biome size and other parameters.
 | 
					 | 
				
			||||||
---The returned vectors are the top left corner, and the bottom right corner of the capture area in world coordinates.
 | 
					 | 
				
			||||||
---The bottom right corner pixel is not included in the rectangle.
 | 
					 | 
				
			||||||
---@type table<string, fun():Vec2, Vec2>
 | 
					 | 
				
			||||||
Config.CaptureArea = {
 | 
					Config.CaptureArea = {
 | 
				
			||||||
	-- Base layout: Every part outside this is based on a similar layout, but uses different materials/seeds.
 | 
						-- Base layout: Every part outside this is based on a similar layout, but uses different materials/seeds.
 | 
				
			||||||
	["1x1"] = getBaseArea,
 | 
						["1x1"] = {
 | 
				
			||||||
 | 
							TopLeft = Vec2(-17920, -7168), -- in world coordinates.
 | 
				
			||||||
 | 
							BottomRight = Vec2(17920, 17408), -- in world coordinates. This pixel is not included in the rectangle.
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	-- Main world: The main world with 3 parts: sky, normal and hell.
 | 
						-- Main world: The main world with 3 parts: sky, normal and hell.
 | 
				
			||||||
	["1x3"] = function()
 | 
						["1x3"] = {
 | 
				
			||||||
		local width, height = BiomeMapGetSize()
 | 
							TopLeft = Vec2(-17920, -31744), -- in world coordinates.
 | 
				
			||||||
		local topLeft, bottomRight = getBaseArea()
 | 
							BottomRight = Vec2(17920, 41984), -- in world coordinates. This pixel is not included in the rectangle.
 | 
				
			||||||
		return topLeft + Vec2(0, -height)*CHUNK_SIZE, bottomRight + Vec2(0, height)*CHUNK_SIZE
 | 
						},
 | 
				
			||||||
		--return Vec2(-17920, -31744), Vec2(17920, 41984) -- Coordinates for a "New Game" without mods or anything.
 | 
					 | 
				
			||||||
	end,
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	-- -1 parallel world: The parallel world with 3 parts: sky, normal and hell.
 | 
						-- -1 parallel world: The parallel world with 3 parts: sky, normal and hell.
 | 
				
			||||||
	["1x3 -1"] = function()
 | 
						["1x3 -1"] = {
 | 
				
			||||||
		local width, height = BiomeMapGetSize()
 | 
							TopLeft = Vec2(-17920, -31744) + Vec2(-35840, 0), -- in world coordinates.
 | 
				
			||||||
		local topLeft, bottomRight = getBaseArea()
 | 
							BottomRight = Vec2(17920, 41984) + Vec2(-35840, 0), -- in world coordinates. This pixel is not included in the rectangle.
 | 
				
			||||||
		return topLeft + Vec2(-width, -height)*CHUNK_SIZE, bottomRight + Vec2(-width, height)*CHUNK_SIZE
 | 
						},
 | 
				
			||||||
		--return Vec2(-17920, -31744) + Vec2(-35840, 0), Vec2(17920, 41984) + Vec2(-35840, 0) -- Coordinates for a "New Game" without mods or anything.
 | 
					 | 
				
			||||||
	end,
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	-- +1 parallel world: The parallel world with 3 parts: sky, normal and hell.
 | 
						-- +1 parallel world: The parallel world with 3 parts: sky, normal and hell.
 | 
				
			||||||
	["1x3 +1"] = function()
 | 
						["1x3 +1"] = {
 | 
				
			||||||
		local width, height = BiomeMapGetSize()
 | 
							TopLeft = Vec2(-17920, -31744) + Vec2(35840, 0), -- in world coordinates.
 | 
				
			||||||
		local topLeft, bottomRight = getBaseArea()
 | 
							BottomRight = Vec2(17920, 41984) + Vec2(35840, 0), -- in world coordinates. This pixel is not included in the rectangle.
 | 
				
			||||||
		return topLeft + Vec2(width, -height)*CHUNK_SIZE, bottomRight + Vec2(width, height)*CHUNK_SIZE
 | 
						},
 | 
				
			||||||
		--return Vec2(-17920, -31744) + Vec2(35840, 0), Vec2(17920, 41984) + Vec2(35840, 0) -- Coordinates for a "New Game" without mods or anything.
 | 
					 | 
				
			||||||
	end,
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	-- Extended: Main world + a fraction of the parallel worlds to the left and right.
 | 
						-- Extended: Main world + a fraction of the parallel worlds to the left and right.
 | 
				
			||||||
	["1.5x3"] = function()
 | 
						["1.5x3"] = {
 | 
				
			||||||
		local width, height = BiomeMapGetSize()
 | 
							TopLeft = Vec2(-25600, -31744), -- in world coordinates.
 | 
				
			||||||
		local topLeft, bottomRight = getBaseArea()
 | 
							BottomRight = Vec2(25600, 41984), -- in world coordinates. This pixel is not included in the rectangle.
 | 
				
			||||||
		return topLeft + Vec2(-math.floor(0.25*width), -height)*CHUNK_SIZE, bottomRight + Vec2(math.floor(0.25*width), height)*CHUNK_SIZE
 | 
						},
 | 
				
			||||||
		--return Vec2(-25600, -31744), Vec2(25600, 41984) -- Coordinates for a "New Game" without mods or anything. These coordinates may not exactly be 1.5 of the base width for historic reasons.
 | 
					 | 
				
			||||||
	end,
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	-- Extended: Main world + each parallel world to the left and right.
 | 
						-- Extended: Main world + each parallel world to the left and right.
 | 
				
			||||||
	["3x3"] = function()
 | 
						["3x3"] = {
 | 
				
			||||||
		local width, height = BiomeMapGetSize()
 | 
							TopLeft = Vec2(-53760, -31744), -- in world coordinates.
 | 
				
			||||||
		local topLeft, bottomRight = getBaseArea()
 | 
							BottomRight = Vec2(53760, 41984), -- in world coordinates. This pixel is not included in the rectangle.
 | 
				
			||||||
		return topLeft + Vec2(-width, -height)*CHUNK_SIZE, bottomRight + Vec2(width, height)*CHUNK_SIZE
 | 
						},
 | 
				
			||||||
		--return Vec2(-53760, -31744), Vec2(53760, 41984) -- Coordinates for a "New Game" without mods or anything.
 | 
					 | 
				
			||||||
	end,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
-- Copyright (c) 2022-2025 David Vogel
 | 
					-- Copyright (c) 2022-2024 David Vogel
 | 
				
			||||||
--
 | 
					--
 | 
				
			||||||
-- 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
 | 
				
			||||||
@ -238,46 +238,6 @@ function Modification.SetMemoryOptions(memory)
 | 
				
			|||||||
					mPlayerNeverDies = function(value) ffi.cast("char*", 0x0131D89C+6)[0] = value end,
 | 
										mPlayerNeverDies = function(value) ffi.cast("char*", 0x0131D89C+6)[0] = value end,
 | 
				
			||||||
					mFreezeAI = function(value) ffi.cast("char*", 0x0131D89C+7)[0] = value end,
 | 
										mFreezeAI = function(value) ffi.cast("char*", 0x0131D89C+7)[0] = value end,
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				{_Offset = 0x0118718C, _BuildString = "Build Apr  8 2024 18:07:16", -- Steam dev build.
 | 
					 | 
				
			||||||
					mPostFxDisabled = function(value) ffi.cast("char*", 0x0131D8DC+0)[0] = value end,
 | 
					 | 
				
			||||||
					mGuiDisabled = function(value) ffi.cast("char*", 0x0131D8DC+1)[0] = value end,
 | 
					 | 
				
			||||||
					mGuiHalfSize = function(value) ffi.cast("char*", 0x0131D8DC+2)[0] = value end,
 | 
					 | 
				
			||||||
					mFogOfWarOpenEverywhere = function(value) ffi.cast("char*", 0x0131D8DC+3)[0] = value end,
 | 
					 | 
				
			||||||
					mTrailerMode = function(value) ffi.cast("char*", 0x0131D8DC+4)[0] = value end,
 | 
					 | 
				
			||||||
					mDayTimeRotationPause = function(value) ffi.cast("char*", 0x0131D8DC+5)[0] = value end,
 | 
					 | 
				
			||||||
					mPlayerNeverDies = function(value) ffi.cast("char*", 0x0131D8DC+6)[0] = value end,
 | 
					 | 
				
			||||||
					mFreezeAI = function(value) ffi.cast("char*", 0x0131D8DC+7)[0] = value end,
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{_Offset = 0x0118FD3C, _BuildString = "Build Aug 12 2024 21:10:13", -- Steam dev build.
 | 
					 | 
				
			||||||
					mPostFxDisabled = function(value) ffi.cast("char*", 0x01327D3C+0)[0] = value end,
 | 
					 | 
				
			||||||
					mGuiDisabled = function(value) ffi.cast("char*", 0x01327D3C+1)[0] = value end,
 | 
					 | 
				
			||||||
					mGuiHalfSize = function(value) ffi.cast("char*", 0x01327D3C+2)[0] = value end,
 | 
					 | 
				
			||||||
					mFogOfWarOpenEverywhere = function(value) ffi.cast("char*", 0x01327D3C+3)[0] = value end,
 | 
					 | 
				
			||||||
					mTrailerMode = function(value) ffi.cast("char*", 0x01327D3C+4)[0] = value end,
 | 
					 | 
				
			||||||
					mDayTimeRotationPause = function(value) ffi.cast("char*", 0x01327D3C+5)[0] = value end,
 | 
					 | 
				
			||||||
					mPlayerNeverDies = function(value) ffi.cast("char*", 0x01327D3C+6)[0] = value end,
 | 
					 | 
				
			||||||
					mFreezeAI = function(value) ffi.cast("char*", 0x01327D3C+7)[0] = value end,
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{_Offset = 0x0118FD3C, _BuildString = "Build Aug 12 2024 21:43:22", -- Steam dev build.
 | 
					 | 
				
			||||||
					mPostFxDisabled = function(value) ffi.cast("char*", 0x01327D3C+0)[0] = value end,
 | 
					 | 
				
			||||||
					mGuiDisabled = function(value) ffi.cast("char*", 0x01327D3C+1)[0] = value end,
 | 
					 | 
				
			||||||
					mGuiHalfSize = function(value) ffi.cast("char*", 0x01327D3C+2)[0] = value end,
 | 
					 | 
				
			||||||
					mFogOfWarOpenEverywhere = function(value) ffi.cast("char*", 0x01327D3C+3)[0] = value end,
 | 
					 | 
				
			||||||
					mTrailerMode = function(value) ffi.cast("char*", 0x01327D3C+4)[0] = value end,
 | 
					 | 
				
			||||||
					mDayTimeRotationPause = function(value) ffi.cast("char*", 0x01327D3C+5)[0] = value end,
 | 
					 | 
				
			||||||
					mPlayerNeverDies = function(value) ffi.cast("char*", 0x01327D3C+6)[0] = value end,
 | 
					 | 
				
			||||||
					mFreezeAI = function(value) ffi.cast("char*", 0x01327D3C+7)[0] = value end,
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{_Offset = 0x01191A34, _BuildString = "Build Jan 25 2025 15:51:09", -- Steam dev build.
 | 
					 | 
				
			||||||
					mPostFxDisabled = function(value) ffi.cast("char*", 0x0132ADDC+0)[0] = value end,
 | 
					 | 
				
			||||||
					mGuiDisabled = function(value) ffi.cast("char*", 0x0132ADDC+1)[0] = value end,
 | 
					 | 
				
			||||||
					mGuiHalfSize = function(value) ffi.cast("char*", 0x0132ADDC+2)[0] = value end,
 | 
					 | 
				
			||||||
					mFogOfWarOpenEverywhere = function(value) ffi.cast("char*", 0x0132ADDC+3)[0] = value end,
 | 
					 | 
				
			||||||
					mTrailerMode = function(value) ffi.cast("char*", 0x0132ADDC+4)[0] = value end,
 | 
					 | 
				
			||||||
					mDayTimeRotationPause = function(value) ffi.cast("char*", 0x0132ADDC+5)[0] = value end,
 | 
					 | 
				
			||||||
					mPlayerNeverDies = function(value) ffi.cast("char*", 0x0132ADDC+6)[0] = value end,
 | 
					 | 
				
			||||||
					mFreezeAI = function(value) ffi.cast("char*", 0x0132ADDC+7)[0] = value end,
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		[false] = {
 | 
							[false] = {
 | 
				
			||||||
@ -394,34 +354,6 @@ function Modification.SetMemoryOptions(memory)
 | 
				
			|||||||
						ptr[0] = value -- This basically just changes the value that Noita forces to the "mods_have_been_active_during_this_run" member of the WorldStateComponent when any mod is enabled.
 | 
											ptr[0] = value -- This basically just changes the value that Noita forces to the "mods_have_been_active_during_this_run" member of the WorldStateComponent when any mod is enabled.
 | 
				
			||||||
					end,
 | 
										end,
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				{_Offset = 0x01001DF4, _BuildString = "Build Apr  8 2024 18:11:27", -- Steam build.
 | 
					 | 
				
			||||||
					enableModDetection = function(value)
 | 
					 | 
				
			||||||
						local ptr = ffi.cast("char*", 0x006B3355+6)
 | 
					 | 
				
			||||||
						Memory.VirtualProtect(ptr, 1, Memory.PAGE_EXECUTE_READWRITE)
 | 
					 | 
				
			||||||
						ptr[0] = value -- This basically just changes the value that Noita forces to the "mods_have_been_active_during_this_run" member of the WorldStateComponent when any mod is enabled.
 | 
					 | 
				
			||||||
					end,
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{_Offset = 0x01007CA4, _BuildString = "Build Aug 12 2024 21:14:23", -- Steam build.
 | 
					 | 
				
			||||||
					enableModDetection = function(value)
 | 
					 | 
				
			||||||
						local ptr = ffi.cast("char*", 0x006B3925+6)
 | 
					 | 
				
			||||||
						Memory.VirtualProtect(ptr, 1, Memory.PAGE_EXECUTE_READWRITE)
 | 
					 | 
				
			||||||
						ptr[0] = value -- This basically just changes the value that Noita forces to the "mods_have_been_active_during_this_run" member of the WorldStateComponent when any mod is enabled.
 | 
					 | 
				
			||||||
					end,
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{_Offset = 0x01007CA4, _BuildString = "Build Aug 12 2024 21:48:01", -- Steam build.
 | 
					 | 
				
			||||||
					enableModDetection = function(value)
 | 
					 | 
				
			||||||
						local ptr = ffi.cast("char*", 0x006B3925+6)
 | 
					 | 
				
			||||||
						Memory.VirtualProtect(ptr, 1, Memory.PAGE_EXECUTE_READWRITE)
 | 
					 | 
				
			||||||
						ptr[0] = value -- This basically just changes the value that Noita forces to the "mods_have_been_active_during_this_run" member of the WorldStateComponent when any mod is enabled.
 | 
					 | 
				
			||||||
					end,
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				{_Offset = 0x01009D3C, _BuildString = "Build Jan 25 2025 15:55:41", -- Steam build.
 | 
					 | 
				
			||||||
					enableModDetection = function(value)
 | 
					 | 
				
			||||||
						local ptr = ffi.cast("char*", 0x006B3AD5+6)
 | 
					 | 
				
			||||||
						Memory.VirtualProtect(ptr, 1, Memory.PAGE_EXECUTE_READWRITE)
 | 
					 | 
				
			||||||
						ptr[0] = value -- This basically just changes the value that Noita forces to the "mods_have_been_active_during_this_run" member of the WorldStateComponent when any mod is enabled.
 | 
					 | 
				
			||||||
					end,
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										8
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								go.mod
									
									
									
									
									
								
							@ -35,9 +35,9 @@ require (
 | 
				
			|||||||
	github.com/rivo/uniseg v0.4.4 // indirect
 | 
						github.com/rivo/uniseg v0.4.4 // indirect
 | 
				
			||||||
	github.com/tdewolff/minify/v2 v2.20.10 // indirect
 | 
						github.com/tdewolff/minify/v2 v2.20.10 // indirect
 | 
				
			||||||
	github.com/tdewolff/parse/v2 v2.7.7 // indirect
 | 
						github.com/tdewolff/parse/v2 v2.7.7 // indirect
 | 
				
			||||||
	golang.org/x/image v0.18.0 // indirect
 | 
						golang.org/x/image v0.14.0 // indirect
 | 
				
			||||||
	golang.org/x/net v0.23.0 // indirect
 | 
						golang.org/x/net v0.19.0 // indirect
 | 
				
			||||||
	golang.org/x/sys v0.18.0 // indirect
 | 
						golang.org/x/sys v0.15.0 // indirect
 | 
				
			||||||
	golang.org/x/text v0.16.0 // indirect
 | 
						golang.org/x/text v0.14.0 // indirect
 | 
				
			||||||
	star-tex.org/x/tex v0.4.0 // indirect
 | 
						star-tex.org/x/tex v0.4.0 // indirect
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										20
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								go.sum
									
									
									
									
									
								
							@ -4,6 +4,10 @@ github.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1 h1:LejjvYg4tCW5HO
 | 
				
			|||||||
github.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1/go.mod h1:cnC/60IoLiDM0GhdKYJ6oO7AwpZe1IQfPnSKlAURgHw=
 | 
					github.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1/go.mod h1:cnC/60IoLiDM0GhdKYJ6oO7AwpZe1IQfPnSKlAURgHw=
 | 
				
			||||||
github.com/ByteArena/poly2tri-go v0.0.0-20170716161910-d102ad91854f h1:l7moT9o/v/9acCWA64Yz/HDLqjcRTvc0noQACi4MsJw=
 | 
					github.com/ByteArena/poly2tri-go v0.0.0-20170716161910-d102ad91854f h1:l7moT9o/v/9acCWA64Yz/HDLqjcRTvc0noQACi4MsJw=
 | 
				
			||||||
github.com/ByteArena/poly2tri-go v0.0.0-20170716161910-d102ad91854f/go.mod h1:vIOkSdX3NDCPwgu8FIuTat2zDF0FPXXQ0RYFRy+oQic=
 | 
					github.com/ByteArena/poly2tri-go v0.0.0-20170716161910-d102ad91854f/go.mod h1:vIOkSdX3NDCPwgu8FIuTat2zDF0FPXXQ0RYFRy+oQic=
 | 
				
			||||||
 | 
					github.com/Dadido3/go-libwebp v0.1.0 h1:aMM8wwOSyq8mk/xL9ze3vQHPygDU8TMXKH0TViwkBLE=
 | 
				
			||||||
 | 
					github.com/Dadido3/go-libwebp v0.1.0/go.mod h1:rYiWwlI58XRSMUFMw23nMezErbjX3Z5Xv0Kk3w6Mwwo=
 | 
				
			||||||
 | 
					github.com/Dadido3/go-libwebp v0.2.0 h1:SmssjSkrDkwSOGEpdultvneADGYaEqPbv6FcgausaK0=
 | 
				
			||||||
 | 
					github.com/Dadido3/go-libwebp v0.2.0/go.mod h1:rYiWwlI58XRSMUFMw23nMezErbjX3Z5Xv0Kk3w6Mwwo=
 | 
				
			||||||
github.com/Dadido3/go-libwebp v0.3.0 h1:Qr3Gt8Kn4qgemezDVnjAJffMB9C0QJhxP+9u0U5mC94=
 | 
					github.com/Dadido3/go-libwebp v0.3.0 h1:Qr3Gt8Kn4qgemezDVnjAJffMB9C0QJhxP+9u0U5mC94=
 | 
				
			||||||
github.com/Dadido3/go-libwebp v0.3.0/go.mod h1:rYiWwlI58XRSMUFMw23nMezErbjX3Z5Xv0Kk3w6Mwwo=
 | 
					github.com/Dadido3/go-libwebp v0.3.0/go.mod h1:rYiWwlI58XRSMUFMw23nMezErbjX3Z5Xv0Kk3w6Mwwo=
 | 
				
			||||||
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
 | 
					github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
 | 
				
			||||||
@ -87,11 +91,11 @@ github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4A
 | 
				
			|||||||
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 h1:+iq7lrkxmFNBM7xx+Rae2W6uyPfhPeDWD+n+JgppptE=
 | 
					golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 h1:+iq7lrkxmFNBM7xx+Rae2W6uyPfhPeDWD+n+JgppptE=
 | 
				
			||||||
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
 | 
					golang.org/x/exp v0.0.0-20231219180239-dc181d75b848/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
 | 
				
			||||||
golang.org/x/image v0.0.0-20210504121937-7319ad40d33e/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 | 
					golang.org/x/image v0.0.0-20210504121937-7319ad40d33e/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 | 
				
			||||||
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
 | 
					golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
 | 
				
			||||||
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
 | 
					golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
 | 
				
			||||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 | 
					golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 | 
				
			||||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
 | 
					golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
 | 
				
			||||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
 | 
					golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
					golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
@ -99,14 +103,14 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
 | 
				
			|||||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
 | 
					golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
 | 
				
			||||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 | 
					golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 | 
				
			||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
					golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
				
			||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
					golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
				
			||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
					golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
				
			||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 | 
					golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 | 
				
			||||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
 | 
					golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
 | 
				
			||||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
 | 
					golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 | 
				
			||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
					golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
				
			||||||
gonum.org/v1/plot v0.14.0 h1:+LBDVFYwFe4LHhdP8coW6296MBEY4nQ+Y4vuUpJopcE=
 | 
					gonum.org/v1/plot v0.14.0 h1:+LBDVFYwFe4LHhdP8coW6296MBEY4nQ+Y4vuUpJopcE=
 | 
				
			||||||
gonum.org/v1/plot v0.14.0/go.mod h1:MLdR9424SJed+5VqC6MsouEpig9pZX2VZ57H9ko2bXU=
 | 
					gonum.org/v1/plot v0.14.0/go.mod h1:MLdR9424SJed+5VqC6MsouEpig9pZX2VZ57H9ko2bXU=
 | 
				
			||||||
 | 
				
			|||||||
@ -67,9 +67,9 @@ modSettings = {
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		id = "capture-mode",
 | 
							id = "capture-mode",
 | 
				
			||||||
		ui_name = "Mode",
 | 
							ui_name = "Mode",
 | 
				
			||||||
		ui_description = "How the mod captures:\n- Live: Capture as you play along.\n- Area: Capture a defined area of the world.\n- Spiral: Capture in a spiral around a starting point indefinitely.\n- Animation: Capture the screen frame by frame.",
 | 
							ui_description = "How the mod captures:\n- Live: Capture as you play along.\n- Area: Capture a defined area of the world.\n- Spiral: Capture in a spiral around a starting point indefinitely.",
 | 
				
			||||||
		value_default = "live",
 | 
							value_default = "live",
 | 
				
			||||||
		values = { { "live", "Live" }, { "area", "Area" }, { "spiral", "Spiral" }, { "animation", "Animation"} },
 | 
							values = { { "live", "Live" }, { "area", "Area" }, { "spiral", "Spiral" } },
 | 
				
			||||||
		scope = MOD_SETTING_SCOPE_RUNTIME,
 | 
							scope = MOD_SETTING_SCOPE_RUNTIME,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -143,7 +143,7 @@ modSettings = {
 | 
				
			|||||||
				value_default = "512",
 | 
									value_default = "512",
 | 
				
			||||||
				allowed_characters = "0123456789",
 | 
									allowed_characters = "0123456789",
 | 
				
			||||||
				scope = MOD_SETTING_SCOPE_RUNTIME,
 | 
									scope = MOD_SETTING_SCOPE_RUNTIME,
 | 
				
			||||||
				show_fn = function() return modSettings:GetNextValue("capture-mode") == "area" or modSettings:GetNextValue("capture-mode") == "spiral" end,
 | 
									show_fn = function() return modSettings:GetNextValue("capture-mode") ~= "live" end,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				id = "pixel-scale",
 | 
									id = "pixel-scale",
 | 
				
			||||||
@ -167,7 +167,7 @@ modSettings = {
 | 
				
			|||||||
				value_display_multiplier = 1,
 | 
									value_display_multiplier = 1,
 | 
				
			||||||
				value_display_formatting = " $0 frames",
 | 
									value_display_formatting = " $0 frames",
 | 
				
			||||||
				scope = MOD_SETTING_SCOPE_RUNTIME,
 | 
									scope = MOD_SETTING_SCOPE_RUNTIME,
 | 
				
			||||||
				show_fn = function() return modSettings:GetNextValue("capture-mode") == "area" or modSettings:GetNextValue("capture-mode") == "spiral" end,
 | 
									show_fn = function() return modSettings:GetNextValue("capture-mode") ~= "live" end,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				id = "custom-resolution-live",
 | 
									id = "custom-resolution-live",
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user