Post by Paleologos on May 10, 2021 17:10:17 GMT
For all the help many thanks to: Alazar88, Qtzl3000, Rebishaz and OG DMI hackers: Alex and Noremacstew
Introduction
OK, so you want to modify objects placed in levels? Perhaps you want to replace secret flower with WM statue or make huge flying carpets? No problem. With this tutorial you'll learn how to create your own custom level arrangement.
What is DecorationMeshInstances.lua?
DecorationMeshInstances.lua (further referred to as DMI) is a lua script file used in Journey for defining the type, position, and other parameters of every object placed in a level. From the mountain on the horizon, through all structures to animated entities such as carpets or WMs. Inside DMI you can find visual settings for all of that.
However, DMI does not control collision meshes, meaning that changing objects will only have visual effect but the player's character will still bounce off previous object geometry. Collisions are stored in other script - HullInstances.lua.
Where is DMI located?
All DMI scripts are located inside Journey/Data/Scripts/Level_... folders. Every level has its own DMI script. On PC version they are not stored as plain .lua file but as .bin, which requires using hex editor to mod it. On iOS all DMI files are in .lua format that you can easily modify with any text editor.
What you'll need
On PC all you need to have is hex editor such as HxD, to open .bin DMI files.
Remember to ALWAYS KEEP A COPY of the original files!
Additional tools and utilities
• Here are deciphered plain DMI lua scripts used in iOS version of Journey. This can be very useful when compared with PC .bin file: mega.nz/file/8jJXTAhK#CbCFhr1rkFG2gSy3XIjU0-esL0M1Y8pp0VMNK4o2Ois
• Here's an excel table with all DMI from PC version [CS is not included], made by Qtzl3000. Useful for orientation and quick search: mega.nz/file/B6RhECDC#dKxZddiBOyKoNXCR7uIW3DXprUdoS-Yh0rGUtQlvWWs
• In case you want to convert float number to hex value, you can use this converter: gregstoll.com/~gregstoll/floattohex/ [remember to check "swap endianness" for PC modding].
What about online?
Changing DMI will usually only impact visual side of the game on your end. Since it doesn't change collisions you won't appear floating in the air or doing some weird actions for the other player. However changing the position of objects that you can activate (cloth creatures, HL stones, glyphs) may potentially result in gameplay changes that will look unusual for the other player. Be mindful when using modded DMI in multiplayer.
Can it potentially break the game?
Yes. If something goes wrong in your modded file and the game won't know what to do, you'll get a crash to desktop (CTD). In such a case just try to undo your latest change or replace your modded file with the original, vanilla one.
Getting to know DMI
As an example, let's use DMI from CS (Level_Graveyard). Navigate to Journey/Data/Scripts/Level_Graveyard and open your DecorationMeshInstances.lua.bin file with HxD. You'll see a bunch of hex codes and some decoded words on the right side. It might be a bit overwhelming but don't worry it's not as hard as it might look at first glance.
Hint: you can change your "byte group size" to 4 for clarity. In HxD it's in View->byte group size.
The script you see is what the game loads into the memory every time you enter new level. DMI and HullInstances are different from all the other scripts because they are not embedded in Journey.exe but instead loaded from game directory when the game needs them. This means you can change them on the fly while playing the game. To see changes you've made, you have to reload that level.
Since DMI is loaded into the memory from local directory and not from .exe you don't have to worry about its size. Adding new objects however seems to be useless. The game won't display them anyway, even if you add new random ObjectName.
Now let's take a look at the first gravestone object in CS DMI file. Hit ctrl+F and search for text-string: 74b504ccddcf3271.
You should see an object instance with P_GraveStone written somewhere around. That's a gravestone you can see on the right side of main menu dune, we'll use it as our test subject. You can also notice that every object data starts with hex value: 4857B033 F77F or HW°3÷. Remember that "HW°3÷". It looks like total gibberish but that's the start of every single object data in the script. After that header start all parameters that you can modify.
This is how the data in DMI is structured on PC:
And for comparison the same object from deciphered iOS DMI file:
{ ObjectName = "74b504ccddcf3271270ae91510824a9a"
, GardenerName = "|Cube2030|Cube2030Node"
, Mesh = "P_GraveStone"
, FadeMin = 200
, FadeMax = 220
, ShaderLODMin = 15
, ShaderLODMax = 20
, Brightness = 1
, Saturation = 1
, Hue = 0
, Transformation = { {0.241105, 0.0418987, -0.0662136, 0}, {-0.0431773, 0.228238, -0.0127973, 0}, {0.04962, 0.0202357, 0.193487, 0}, {243.277, 48.7436, 223.285, 1} }
, Shader = "MeshSandSide"
, RenderMode = "Solid"
, ShaderParams =
{ { ParamType = "float3"
, ParamName = "uvMlt"
, ParamVal = { 1, 1, 1 }
}
, { ParamType = "texture"
, ParamName = "texColor"
, ParamVal = "GraveStone"
}
, { ParamType = "texture"
, ParamName = "texDetail"
, ParamVal = "DesertRamp"
}
, { ParamType = "texture"
, ParamName = "texRamp"
, ParamVal = "DesertRampLight"
}
, { ParamType = "texture"
, ParamName = "texAo"
, ParamVal = "White"
}
, { ParamType = "texture"
, ParamName = "texEdgeMask"
, ParamVal = "SandMask"
}
, { ParamType = "float"
, ParamName = "inShadow"
, ParamVal = 0
}
, { ParamType = "float3"
, ParamName = "aoStepBiasInt"
, ParamVal = { 50, 0.2, -0.25 }
}
, { ParamType = "float2"
, ParamName = "uvOffset"
, ParamVal = { 0, 0 }
}
, { ParamType = "float"
, ParamName = "duneHeightOff"
, ParamVal = 0.8
}
}
}
Description:
ObjectName - This is unique object ID. If the object has attached other scripts (for example triggers) you can identify it by that name. Do not change it manually. If the game has attached script to a certain object ID but it can't be found in DMI you'll get CTD.
Mesh - Defines which mesh model should be applied on the object. The names of meshes can be found in Data/Meshes folder.
FadeMin & FadeMax - Define the distance at which object will appear.
ShaderLODMin & ShaderLODMax - Define the distance at which shader will appear.
Brightness, Saturation, Hue - Define the object brightness, saturation and hue. For brightness and saturation you can write even high values such as 50 or 100. For example: object with 100 brightness will glow, similar effect can be done with high saturation. Negative values work too but effects can vary. Try them yourself. Hue is a float value between 0-1. Usually default hue [0] is color yellow.
Transformation (position XYZ) - Defines the position of object. Values 0,0,0 are at south-east corner of the map [north is the mountain]. X axis is east-west direction, Y axis is height, Z axis is south-north direction. Fourth value has unknown function.
Transformation (3D rotation and scale matrix) - These values define rotation and scale of the object. They're stored as 3D rotation matrix. That’s probably the most difficult part of DMI to grasp.
Here's an online tool for 3D rotation matrixes: danceswithcode.net/engineeringnotes/rotations_in_3d/demo3D/rotations_in_3d_tool.html
The problem with that visualization tool is that Journey interprets axes differently:
Yaw is in-game roll (counter clockwise = 90° - left side roll; 270° - right side roll)
Pitch is in-game yaw (clockwise = 90° - facing east; 270° - facing west)
Roll is in-game pitch (clockwise = 90° - facing up; 270° - facing down)
The transform data affects other things:
- If you multiply all the coordinate values for one axis by some number, the mesh will be scaled by that number along the axis (so everything*2 = 2 times bigger in one direction, etc.)
- If the "math" for the different axes doesn't all equal the same number, then weird stuff can happen, like the mesh being stretched/squashed/skewed. If you change all the coordinate values for one axis to their reverse (1 to -1, etc.) then the mesh will be inside out.
Shader - Define which shader should be used for the object.
ShaderParams - Bunch of parameters that can include texture, texture UV offset, texture mask, ambient occlusion, lighting etc. In PC's DMI there's always a name of a parameter and its value. Value is always first followed by name. Offsets between values and parameter names name can differ. Values has to be placed in proper position or they may cause CTD (you can use similar ShaderParams as templates to find appropriate configuration).
Making a simple mod
Now that you know how DMI are structured and how they work, you can start experimenting with them. Let's change a few things about that gravestone.
1. Highlight values from rotation and scale matrix: 3BE4763E, 39B7693E, 7521463E and modify their value (look at "Single (float32)" in the HxD data inspector). Change values to respectably: 0,441105008125305, 0,42823800444603, 0,293487012386322. That will make the object 2x bigger.
2. How about a little colour change? Highlight hue sector (starts at offset 0x2178) and modify the value from 0 to 0,5.
3. Now change mesh model from "P_GraveStone" to "P_SecretFlower" [Do not use ctrl+V in HxD if you want to paste that! Use ctrl+B instead to overwrite existing code].
4. Next replace texture from "GraveStone" to "FlowerSecret".
5. Finally change "DesertRampLight" to "White". Otherwise the lighting will look strange. Remember to put zeros in place of “tRampLight” [in hex table not in decoded text!]. Do not leave any junk data. Keep your DMI just as clean as your room
6. Save the file.
Hint: You can always copy parameters from other objects for easier edit. Just remember to keep original ObjectName.
Launch the game and look at what appears on the top of the dune. If everything is done right this should be the result:
You can notice that the flower is not really a solid object. The collision around it is still the same as if there was invisible gravestone. As mentioned previously, DMI does not change collision meshes. This can be done with HullInstances but that's a story for another tutorial...
Introduction
OK, so you want to modify objects placed in levels? Perhaps you want to replace secret flower with WM statue or make huge flying carpets? No problem. With this tutorial you'll learn how to create your own custom level arrangement.
What is DecorationMeshInstances.lua?
DecorationMeshInstances.lua (further referred to as DMI) is a lua script file used in Journey for defining the type, position, and other parameters of every object placed in a level. From the mountain on the horizon, through all structures to animated entities such as carpets or WMs. Inside DMI you can find visual settings for all of that.
However, DMI does not control collision meshes, meaning that changing objects will only have visual effect but the player's character will still bounce off previous object geometry. Collisions are stored in other script - HullInstances.lua.
Where is DMI located?
All DMI scripts are located inside Journey/Data/Scripts/Level_... folders. Every level has its own DMI script. On PC version they are not stored as plain .lua file but as .bin, which requires using hex editor to mod it. On iOS all DMI files are in .lua format that you can easily modify with any text editor.
What you'll need
On PC all you need to have is hex editor such as HxD, to open .bin DMI files.
Remember to ALWAYS KEEP A COPY of the original files!
Additional tools and utilities
• Here are deciphered plain DMI lua scripts used in iOS version of Journey. This can be very useful when compared with PC .bin file: mega.nz/file/8jJXTAhK#CbCFhr1rkFG2gSy3XIjU0-esL0M1Y8pp0VMNK4o2Ois
• Here's an excel table with all DMI from PC version [CS is not included], made by Qtzl3000. Useful for orientation and quick search: mega.nz/file/B6RhECDC#dKxZddiBOyKoNXCR7uIW3DXprUdoS-Yh0rGUtQlvWWs
• In case you want to convert float number to hex value, you can use this converter: gregstoll.com/~gregstoll/floattohex/ [remember to check "swap endianness" for PC modding].
What about online?
Changing DMI will usually only impact visual side of the game on your end. Since it doesn't change collisions you won't appear floating in the air or doing some weird actions for the other player. However changing the position of objects that you can activate (cloth creatures, HL stones, glyphs) may potentially result in gameplay changes that will look unusual for the other player. Be mindful when using modded DMI in multiplayer.
Can it potentially break the game?
Yes. If something goes wrong in your modded file and the game won't know what to do, you'll get a crash to desktop (CTD). In such a case just try to undo your latest change or replace your modded file with the original, vanilla one.
Getting to know DMI
As an example, let's use DMI from CS (Level_Graveyard). Navigate to Journey/Data/Scripts/Level_Graveyard and open your DecorationMeshInstances.lua.bin file with HxD. You'll see a bunch of hex codes and some decoded words on the right side. It might be a bit overwhelming but don't worry it's not as hard as it might look at first glance.
Hint: you can change your "byte group size" to 4 for clarity. In HxD it's in View->byte group size.
The script you see is what the game loads into the memory every time you enter new level. DMI and HullInstances are different from all the other scripts because they are not embedded in Journey.exe but instead loaded from game directory when the game needs them. This means you can change them on the fly while playing the game. To see changes you've made, you have to reload that level.
Since DMI is loaded into the memory from local directory and not from .exe you don't have to worry about its size. Adding new objects however seems to be useless. The game won't display them anyway, even if you add new random ObjectName.
Now let's take a look at the first gravestone object in CS DMI file. Hit ctrl+F and search for text-string: 74b504ccddcf3271.
You should see an object instance with P_GraveStone written somewhere around. That's a gravestone you can see on the right side of main menu dune, we'll use it as our test subject. You can also notice that every object data starts with hex value: 4857B033 F77F or HW°3÷. Remember that "HW°3÷". It looks like total gibberish but that's the start of every single object data in the script. After that header start all parameters that you can modify.
This is how the data in DMI is structured on PC:
And for comparison the same object from deciphered iOS DMI file:
{ ObjectName = "74b504ccddcf3271270ae91510824a9a"
, GardenerName = "|Cube2030|Cube2030Node"
, Mesh = "P_GraveStone"
, FadeMin = 200
, FadeMax = 220
, ShaderLODMin = 15
, ShaderLODMax = 20
, Brightness = 1
, Saturation = 1
, Hue = 0
, Transformation = { {0.241105, 0.0418987, -0.0662136, 0}, {-0.0431773, 0.228238, -0.0127973, 0}, {0.04962, 0.0202357, 0.193487, 0}, {243.277, 48.7436, 223.285, 1} }
, Shader = "MeshSandSide"
, RenderMode = "Solid"
, ShaderParams =
{ { ParamType = "float3"
, ParamName = "uvMlt"
, ParamVal = { 1, 1, 1 }
}
, { ParamType = "texture"
, ParamName = "texColor"
, ParamVal = "GraveStone"
}
, { ParamType = "texture"
, ParamName = "texDetail"
, ParamVal = "DesertRamp"
}
, { ParamType = "texture"
, ParamName = "texRamp"
, ParamVal = "DesertRampLight"
}
, { ParamType = "texture"
, ParamName = "texAo"
, ParamVal = "White"
}
, { ParamType = "texture"
, ParamName = "texEdgeMask"
, ParamVal = "SandMask"
}
, { ParamType = "float"
, ParamName = "inShadow"
, ParamVal = 0
}
, { ParamType = "float3"
, ParamName = "aoStepBiasInt"
, ParamVal = { 50, 0.2, -0.25 }
}
, { ParamType = "float2"
, ParamName = "uvOffset"
, ParamVal = { 0, 0 }
}
, { ParamType = "float"
, ParamName = "duneHeightOff"
, ParamVal = 0.8
}
}
}
Description:
ObjectName - This is unique object ID. If the object has attached other scripts (for example triggers) you can identify it by that name. Do not change it manually. If the game has attached script to a certain object ID but it can't be found in DMI you'll get CTD.
Mesh - Defines which mesh model should be applied on the object. The names of meshes can be found in Data/Meshes folder.
FadeMin & FadeMax - Define the distance at which object will appear.
ShaderLODMin & ShaderLODMax - Define the distance at which shader will appear.
Brightness, Saturation, Hue - Define the object brightness, saturation and hue. For brightness and saturation you can write even high values such as 50 or 100. For example: object with 100 brightness will glow, similar effect can be done with high saturation. Negative values work too but effects can vary. Try them yourself. Hue is a float value between 0-1. Usually default hue [0] is color yellow.
Transformation (position XYZ) - Defines the position of object. Values 0,0,0 are at south-east corner of the map [north is the mountain]. X axis is east-west direction, Y axis is height, Z axis is south-north direction. Fourth value has unknown function.
Transformation (3D rotation and scale matrix) - These values define rotation and scale of the object. They're stored as 3D rotation matrix. That’s probably the most difficult part of DMI to grasp.
Here's an online tool for 3D rotation matrixes: danceswithcode.net/engineeringnotes/rotations_in_3d/demo3D/rotations_in_3d_tool.html
The problem with that visualization tool is that Journey interprets axes differently:
Yaw is in-game roll (counter clockwise = 90° - left side roll; 270° - right side roll)
Pitch is in-game yaw (clockwise = 90° - facing east; 270° - facing west)
Roll is in-game pitch (clockwise = 90° - facing up; 270° - facing down)
The transform data affects other things:
- If you multiply all the coordinate values for one axis by some number, the mesh will be scaled by that number along the axis (so everything*2 = 2 times bigger in one direction, etc.)
- If the "math" for the different axes doesn't all equal the same number, then weird stuff can happen, like the mesh being stretched/squashed/skewed. If you change all the coordinate values for one axis to their reverse (1 to -1, etc.) then the mesh will be inside out.
Shader - Define which shader should be used for the object.
ShaderParams - Bunch of parameters that can include texture, texture UV offset, texture mask, ambient occlusion, lighting etc. In PC's DMI there's always a name of a parameter and its value. Value is always first followed by name. Offsets between values and parameter names name can differ. Values has to be placed in proper position or they may cause CTD (you can use similar ShaderParams as templates to find appropriate configuration).
Making a simple mod
Now that you know how DMI are structured and how they work, you can start experimenting with them. Let's change a few things about that gravestone.
1. Highlight values from rotation and scale matrix: 3BE4763E, 39B7693E, 7521463E and modify their value (look at "Single (float32)" in the HxD data inspector). Change values to respectably: 0,441105008125305, 0,42823800444603, 0,293487012386322. That will make the object 2x bigger.
2. How about a little colour change? Highlight hue sector (starts at offset 0x2178) and modify the value from 0 to 0,5.
3. Now change mesh model from "P_GraveStone" to "P_SecretFlower" [Do not use ctrl+V in HxD if you want to paste that! Use ctrl+B instead to overwrite existing code].
4. Next replace texture from "GraveStone" to "FlowerSecret".
5. Finally change "DesertRampLight" to "White". Otherwise the lighting will look strange. Remember to put zeros in place of “tRampLight” [in hex table not in decoded text!]. Do not leave any junk data. Keep your DMI just as clean as your room
6. Save the file.
Hint: You can always copy parameters from other objects for easier edit. Just remember to keep original ObjectName.
Launch the game and look at what appears on the top of the dune. If everything is done right this should be the result:
You can notice that the flower is not really a solid object. The collision around it is still the same as if there was invisible gravestone. As mentioned previously, DMI does not change collision meshes. This can be done with HullInstances but that's a story for another tutorial...