Tool for finding creations in the Scrap Mechanic game.
Install node from https://nodejs.org/en/download/ This tool was developed with node version 14.8.0.
then clone the project, and run npm install from the project directory.
The tool will parse a save file (which is a sqlite database file) and will look for creations contain specified parts. So, if you've lost a creation and you know it contains (for example) one or more Level 5 Thrusters then you can use the tool to list the co-ordinates of all creations containing that part.
All Scrap Mechanic survival parts are defined in the game file: C:\Program Files (x86)\Steam\steamapps\common\Scrap Mechanic\Survival\Scripts\game\survival_items.lua
In that file, each part has a unique identified (UUID), e.g. a Level 5 Thruster is:
obj_interactive_thruster_05 = sm.uuid.new( "a736ffdf-22c1-40f2-8e40-988cab7c0559" )
You can run the tool specifying the part UUID, e.g.:
node sm_finder.js mygame.db a736ffdf-22c1-40f2-8e40-988cab7c0559
Here is an example of the output you can expect:
Total number of bodies in save file: 3462
Found creation with part. BodyId: 28042
Found 1 matching bodies
Co-ordinates for body 28042:
{"minX":-737,"maxX":-735,"minY":622,"maxY":625,"absZ":198}
Finished
The min and max values are the co-ordinates of the creation, and absZ is its altitude.
You'll need a mod or code change to display the co-ordinates on the HUD. There are many available. You might also want a mod to allow you to teleport to specific co-ordinates.
Currently I am using this change to show co-ordinates on the HUD:
File: C:\Program Files (x86)\Steam\steamapps\common\Scrap Mechanic\Survival\Scripts\game\SurvivalPlayer.lua, change the top of function SurvivalPlayer.cl_localPlayerUpdate as follows:
function SurvivalPlayer.cl_localPlayerUpdate( self, dt )
self:cl_updateCamera( dt )
if g_survivalHud then
g_survivalHud:setText( "TimePanel", getTimeOfDayString() )
local character = self.player:getCharacter()
if character then
local text = character.worldPosition.x ..", ".. character.worldPosition.y .. ", ".. character.worldPosition.z
local direction = character.direction
local yaw = math.atan2( direction.y, direction.x )
if math.abs( yaw ) < math.pi * 0.25 then
text = text.." E"
elseif math.abs( yaw ) > math.pi * 0.75 then
text = text.." W"
elseif yaw >= math.pi * 0.25 then
text = text.." N"
else
text = text.." S"
end
g_survivalHud:setText( "TimePanel", text )
end
end
and in File: C:\Program Files (x86)\Steam\steamapps\common\Scrap Mechanic\Data\Gui\Layouts\Hud\Hud_SurvivalHud.layout, add this line as part of the widget definitions:
<Widget type="TextBox" skin="TextBox" name="TimePanel" position_real="0 0 0.228125 0.0740741" />
Here's what I've discovered about the save file database tables:
This table contains an entry for each creation. It includes bodies that exist at the start of a new game (so your first creation won't have ID 1).
The ID seems to change e.g. when you put a creation on or off the lift.
I have not fully decoded it.
74|1|000201 0000004A 0001 C5217B5D C52185B1 C511CCCF C511D943 0001 3E6CF065 BF2ED471 3ED1FCDE 3F0EF633 C511BF12 C5215350 4122445E 00000000000000000000000000000000000000000000000000
0 3 9 13 17 21 27 31 35 39 43 47 51
ID (74) maxY minY maxX minX Z
Note that co-ordinates are stored in IEEE 754 floating point format, see e.g. https://gregstoll.com/~gregstoll/floattohex/
This table contains simple shapes. A single block would be represented with a single row in this table.
Contiguous identical blocks appear to only take up one row. For example, if you made a row of three 'Metal 1' blocks then only one row in the table would be created. If you coloured one of those blocks then you'd end up with 2 rows.
I have not fully decoded it.
591|72|011F01 0000024F 00000048 1E2F557C22A0D4890645E194C2F6ED8A 00000048 FFF6FFFF 000CFF 222222 00 0100010001
0 3 7 11 27 38
ID Blk Part UUID Blk again Clr
Note that UUIDs are stored in big-endian format so the bytes are reversed, e.g. the example above is the 'Metal 1' UUID:
blk_metal1 = sm.uuid.new( "8aedf6c2-94e1-4506-89d4-a0227c552f1e" )
The row includes a reference (Blk) to the containing RigidBody. That's how I am able to find parts: I scan ChildShape to find rows containing the part of interest, and then I can look up the co-ordinates of the containing body in the RigidBody table.
I'm not making use of this table in the tool, but it can be used to find harvestable items, e.g. I used it manually to find a plot of mature potatoes.
The parts are listed in file:
C:\Program Files (x86)\Steam\steamapps\common\Scrap Mechanic\Survival\Scripts\game\survival_harvestable.lua
and the partially decoded table format is:
05000100 014953 00FFFFFFE5FFFFFFE500010001 D62F47C69D6F9D8EE2487E9BAE4993B3 3C3439F0 C4D4AC00 C4D4E400 BF0000013EFFFFFF3EFFFFFFBF00000100000000EE9E28FF
ID UUID Z pos Y pos X pos