Difference between revisions of "Loading Level Resources With Lua"

Jump to navigation Jump to search
added/updated methods for changing triggers, markers, decoration meshes; updated some info about rails, hulls; made wording more accurate about "level objects" vs "level resources" - those categories should probably be split into two pages
m (cat upd)
(added/updated methods for changing triggers, markers, decoration meshes; updated some info about rails, hulls; made wording more accurate about "level objects" vs "level resources" - those categories should probably be split into two pages)
Line 2: Line 2:
[[Category:Native Lua Functions]]
[[Category:Native Lua Functions]]
[[Category:Level Resources]]
[[Category:Level Resources]]
This is what has been found so far to add and/or modify level resource objects using a Lua script, along with brief descriptions of what these objects do.
[[Category:Level Objects]]
This is what has been found so far to add and/or modify level objects (during a level) and other level resources using a Lua script, along with brief descriptions of what these objects/resources do.
 
See [[Loading Level Objects When Level Starts]] for info on adding/modifying level objects "the normal way" right as the level begins, which is generally more stable.
 
(This page probably should be split into two pages about "Loading Level Resources" and "Modifying Level Objects During a Level" etc)
 
==Loading Resource Files==
==Loading Resource Files==
To make different sets of resources load at the start of a level, one way is to run code that alters the resTbl table used within the QueueResourcesForLoad() function. This function is initially defined in plain text in Journey.exe . (Research on this and the other functions in that ".lua" will probably reveal how to load completely customized resources from outside the .exe)
One way to change a level is to change what resources are loaded for the level; for example, loading a different "TriggerInstances" resource to load a different set of Triggers. One way to do this is to run code that alters the resTbl table used within the QueueResourcesForLoad() function. This function is initially defined in plain text in Journey.exe . (Research on this and the other functions in that ".lua" will probably reveal how to load completely customized resources from outside the .exe)


For example, if you inject this script, then whenever you define swapLevel as an internal level name ("Graveyard","Barrens",etc) the next level's resources will all be replaced with the ones from Level_''swapLevel''.
For example, if you execute this code, then whenever you define swapLevel as an internal level name ("Graveyard","Barrens",etc) the next level's resources will all be replaced with the ones from Level_''swapLevel'':
  swapLevel = ""
 
<div class="toccolours mw-collapsible mw-collapsed">
function QueueResourcesForLoad( resManager, resTbl, alloc )
<div style="font-weight:bold;line-height:1.6;">Example code mod for swapping resources between levels</div>
DebugPrint( "Loading: Queuing resources for load." )
<div class="mw-collapsible-content">
 
--this if/then block is the modded code, the rest is original
  <nowiki>swapLevel = ""
if swapLevel ~= "" then
 
for i,v in ipairs (resTbl) do
  function QueueResourcesForLoad( resManager, resTbl, alloc )
if v.class == "Script" then v.source = "Level_"..swapLevel.."/"..v.name..".lua"
  DebugPrint( "Loading: Queuing resources for load." )
elseif v.class == "Binary" then v.source = "Scripts/Level_"..swapLevel.."/"..v.name..".lua"
 
elseif v.name == "LvlMus" then v.source = swapLevel.."-MUS.bnk"
  --this if/then block is the modded code, the rest is original
elseif v.name == "LvlSfx" then v.source = swapLevel.."-SFX.bnk"
  if swapLevel ~= "" then
elseif v.class == "Texture" then v.source = "Level_"..swapLevel.."/DuneColorShadow.dds"
  for i,v in ipairs (resTbl) do
elseif v.class == "TerrainData" then  
  if v.class == "Script" then v.source = "Level_"..swapLevel.."/"..v.name..".lua"
v.outDir = "Level_"..swapLevel.."/"
  elseif v.class == "Binary" then v.source = "Scripts/Level_"..swapLevel.."/"..v.name..".lua"
v.srcGround = "Level_"..swapLevel.."/LandColor.dds"
  elseif v.name == "LvlMus" then v.source = swapLevel.."-MUS.bnk"
v.srcHeight = "Level_"..swapLevel.."/Heightmap.dds"
  elseif v.name == "LvlSfx" then v.source = swapLevel.."-SFX.bnk"
v.srcMask = "Level_"..swapLevel.."/MaskData.dds"
  elseif v.class == "Texture" then v.source = "Level_"..swapLevel.."/DuneColorShadow.dds"
end
  elseif v.class == "TerrainData" then  
end
  v.outDir = "Level_"..swapLevel.."/"
swapLevel = ""
  v.srcGround = "Level_"..swapLevel.."/LandColor.dds"
end
  v.srcHeight = "Level_"..swapLevel.."/Heightmap.dds"
  v.srcMask = "Level_"..swapLevel.."/MaskData.dds"
for i,resCons in ipairs( resTbl ) do
  end
DebugPrint( "Loading: Queuing "..resCons.name..", a "..resCons.class.."." )
  end
  swapLevel = ""
-- Allocate the resource object.
  end
local metatbl = _G[ resCons.class ]
 
local res = metatbl.new( alloc )
  for i,resCons in ipairs( resTbl ) do
  DebugPrint( "Loading: Queuing "..resCons.name..", a "..resCons.class.."." )
-- Initialize some values in the resource object based on the
 
-- construction table.
  -- Allocate the resource object.
resCons.class = nil
  local metatbl = _G[ resCons.class ]
for varName,varValue in pairs( resCons ) do
  local res = metatbl.new( alloc )
local varAccessor = res.__vars[ varName ]
 
if varAccessor then varAccessor( res, varValue ) end
  -- Initialize some values in the resource object based on the
end
  -- construction table.
  resCons.class = nil
-- Tell the C++ end this resource is ready to be loaded.
  for varName,varValue in pairs( resCons ) do
resManager:AddToLoadList( res )
  local varAccessor = res.__vars[ varName ]
end
  if varAccessor then varAccessor( res, varValue ) end
end
  end
"Script" resources are .lua's embedded in Journey.exe, but all other resources are loaded from the game folders.
 
  -- Tell the C++ end this resource is ready to be loaded.
  resManager:AddToLoadList( res )
  end
  end
  </nowiki>
</div></div>
 
"Script" resources are Lua files embedded in Journey.exe, but all other resources are loaded from the game folders.
 
 
Keep in mind that some types of level objects reference each other in a way that will cause the game to crash if something is wrong/missing, so some resources can only be safely replaced if you properly replace certain others as well.


Keep in mind that some resource types reference each other in a way that will cause the game to crash if something is wrong/missing, so some resource sets can only be safely replaced if you properly replace certain others as well.
If you try to load a resource that doesn't exist, some resource types will allow it and just use nothing for that resource, but other types will make the game crash.


If you try to load a set of resources that doesn't exist, some resource types will allow it and just load none of that resource, but other types will make the game crash.


Here is a sample of the contents of resTbl as it gets passed to QueueResourcesForLoad:
Here is a sample of the contents of resTbl as it gets passed to QueueResourcesForLoad:
{  
<div class="toccolours mw-collapsible mw-collapsed">
<div style="font-weight:bold;line-height:1.6;">Format of resource tables loaded when level starts</div>
<div class="mw-collapsible-content">
<nowiki>{  
  {
  {
class = "ScreamBank",
  class = "ScreamBank",
name = "LvlSfx",
  name = "LvlSfx",
source = "Graveyard-SFX.bank"
  source = "Graveyard-SFX.bank"
  }, {
  }, {
class = "ScreamBank",
  class = "ScreamBank",
name = "LvlMus",
  name = "LvlMus",
source = "Graveyard-MUS.bank"
  source = "Graveyard-MUS.bank"
  }, {
  }, {
class = "TerrainData",
  class = "TerrainData",
name = "TerrainData",
  name = "TerrainData",
outDir = "Level_Graveyard/",
  outDir = "Level_Graveyard/",
srcGround = "Level_Graveyard/LandColor.dds",
  srcGround = "Level_Graveyard/LandColor.dds",
srcHeight = "Level_Graveyard/Heightmap.dds",
  srcHeight = "Level_Graveyard/Heightmap.dds",
srcMask = "Level_Graveyard/MaskData.dds"
  srcMask = "Level_Graveyard/MaskData.dds"
  }, {
  }, {
class = "Binary",
  class = "Binary",
name = "HullInstances",
  name = "HullInstances",
source = "Scripts/Level_Graveyard/HullInstances.lua",
  source = "Scripts/Level_Graveyard/HullInstances.lua",
type = "Hull"
  type = "Hull"
  }, {
  }, {
class = "Binary",
  class = "Binary",
name = "DecorationMeshInstances",
  name = "DecorationMeshInstances",
source = "Scripts/Level_Graveyard/DecorationMeshInstances.lua",
  source = "Scripts/Level_Graveyard/DecorationMeshInstances.lua",
type = "Decoration"
  type = "Decoration"
  }, {
  }, {
class = "Script",
  class = "Script",
name = "EnvNodeInstances",
  name = "EnvNodeInstances",
source = "Level_Graveyard/EnvNodeInstances.lua"
  source = "Level_Graveyard/EnvNodeInstances.lua"
  }, {
  }, {
class = "Script",
  class = "Script",
name = "MarkerInstances",
  name = "MarkerInstances",
source = "Level_Graveyard/MarkerInstances.lua"
  source = "Level_Graveyard/MarkerInstances.lua"
  }, {
  }, {
class = "Script",
  class = "Script",
name = "ParticleEmitterInstances",
  name = "ParticleEmitterInstances",
source = "Level_Graveyard/ParticleEmitterInstances.lua"
  source = "Level_Graveyard/ParticleEmitterInstances.lua"
  }, {
  }, {
class = "Script",
  class = "Script",
name = "SoundEmitterInstances",
  name = "SoundEmitterInstances",
source = "Level_Graveyard/SoundEmitterInstances.lua"
  source = "Level_Graveyard/SoundEmitterInstances.lua"
  }, {
  }, {
class = "Script",
  class = "Script",
name = "SignInstances",
  name = "SignInstances",
source = "Level_Graveyard/SignInstances.lua"
  source = "Level_Graveyard/SignInstances.lua"
  }, {
  }, {
class = "Script",
  class = "Script",
name = "SignData",
  name = "SignData",
source = "Level_Graveyard/SignData.lua"
  source = "Level_Graveyard/SignData.lua"
  }, {
  }, {
class = "Script",
  class = "Script",
name = "JetInstances",
  name = "JetInstances",
source = "Level_Graveyard/JetInstances.lua"
  source = "Level_Graveyard/JetInstances.lua"
  }, {
  }, {
class = "Script",
  class = "Script",
name = "DynamicNodeInstances",
  name = "DynamicNodeInstances",
source = "Level_Graveyard/DynamicNodeInstances.lua"
  source = "Level_Graveyard/DynamicNodeInstances.lua"
  }, {
  }, {
class = "Script",
  class = "Script",
name = "CameraKeyFrameInstances",
  name = "CameraKeyFrameInstances",
source = "Level_Graveyard/CameraKeyFrameInstances.lua"
  source = "Level_Graveyard/CameraKeyFrameInstances.lua"
  }, {
  }, {
class = "Script",
  class = "Script",
name = "StartLocation",
  name = "StartLocation",
source = "Level_Graveyard/StartLocation.lua"
  source = "Level_Graveyard/StartLocation.lua"
  }, {
  }, {
class = "Script",
  class = "Script",
name = "TimelineInstances",
  name = "TimelineInstances",
source = "Level_Graveyard/TimelineInstances.lua"
  source = "Level_Graveyard/TimelineInstances.lua"
  }, {
  }, {
class = "Script",
  class = "Script",
name = "TriggerInstances",
  name = "TriggerInstances",
source = "Level_Graveyard/TriggerInstances.lua"
  source = "Level_Graveyard/TriggerInstances.lua"
  }, {
  }, {
class = "Script",
  class = "Script",
name = "ClumpInstances",
  name = "ClumpInstances",
source = "Level_Graveyard/ClumpInstances.lua"
  source = "Level_Graveyard/ClumpInstances.lua"
  }, {
  }, {
class = "Script",
  class = "Script",
name = "RailInstances",
  name = "RailInstances",
source = "Level_Graveyard/RailInstances.lua"
  source = "Level_Graveyard/RailInstances.lua"
  }, {
  }, {
class = "Texture",
  class = "Texture",
gammaRemap = true,
  gammaRemap = true,
name = "DuneColorShadow",
  name = "DuneColorShadow",
source = "Level_Graveyard/DuneColorShadow.dds"
  source = "Level_Graveyard/DuneColorShadow.dds"
  }  
  }  
}
}</nowiki></div></div>
==Adding/Modifying Individual Resources==
==Adding/Modifying Individual Level Objects ==
'''Important things to remember'''
'''Important things to remember'''


Line 152: Line 171:
If you reference an ObjectName that exists in the Names table, but the associated object no longer exists in memory or is corrupted, your game will most likely crash. It also may crash if you reference an object that isn't in the Names table.  
If you reference an ObjectName that exists in the Names table, but the associated object no longer exists in memory or is corrupted, your game will most likely crash. It also may crash if you reference an object that isn't in the Names table.  


The ''Something''Instances/etc tables that you construct to load resources into the Names table are usually (but not always) cleared automatically after the functions run, to free up memory.
The ''Something''Instances/etc tables that you construct to load level objects into the Names table are usually (but not always) cleared automatically after the functions run, to free up memory.


From tests done by inserting logging code into the resource-loading functions, this appears to always be the order that resources get loaded into the Names table, in all levels. You should probably use the same order when adding/modifying different types of resources at the same time, it is not yet known if doing them in a different order can break anything.
From tests done by inserting logging code into the level-object-loading functions, this appears to always be the order that level objects get loaded into the Names table, in all levels. You should probably use the same order when adding/modifying different types of level objects at the same time, it is not yet known if doing them in a different order can break anything.
#Camera Key Frames
#Camera Key Frames
#Hulls
#Hulls
#Environment Nodes
# Environment Nodes
#Markers
# Markers
#Jets
# Jets
#Decoration Meshes
#Decoration Meshes
#Signs
#Signs
#Timelines
#Timelines
#Rails
# Rails
#Clumps
#Clumps
#Creatures
#Creatures
#Triggers
#Triggers
#PrintNameTableSize() from Helpers.lua is called - seems like a safe/good function to edit so it instead adds/modifies all the resources you want ready before the level actually "starts", mostly untested
# PrintNameTableSize() from Helpers.lua is called - seems like a safe/good function to edit so it instead adds/modifies all the level objects or other things you want ready before the level actually "starts"; though for level object mods that you want ever since the level starts, it's probably better to just [[Loading Level Objects When Level Starts|insert them directly into the initial object table that gets loaded]]
#Environment Nodes (apparently gets loaded twice)
#Environment Nodes (apparently gets loaded twice)
*Load order not yet known for Particle Emitters, Sound Emitters, Terrain Data, the SFX/Music Banks, or the DuneColorShadow texture.
*Load order not yet known for Particle Emitters, Sound Emitters, Terrain Data, the SFX/Music Banks, or the DuneColorShadow texture.
Line 181: Line 200:
  TriggerInstances = { ObjectType = "TriggerInstances", {ObjectName = "ed489eebe96121c9de7ccce1d25d6ced", GardenerName = "|PlaySFXTrigger270|PlaySFXTrigger270_G", Type = "PlaySFXTrigger", Shortcut = "", Vars = { bankName = "LvlMus", soundName = "M_0m1", vol = 1} } }
  TriggerInstances = { ObjectType = "TriggerInstances", {ObjectName = "ed489eebe96121c9de7ccce1d25d6ced", GardenerName = "|PlaySFXTrigger270|PlaySFXTrigger270_G", Type = "PlaySFXTrigger", Shortcut = "", Vars = { bankName = "LvlMus", soundName = "M_0m1", vol = 1} } }
  ResolveTriggerNames( game:eventBarn(), game:clumpBarn() )
  ResolveTriggerNames( game:eventBarn(), game:clumpBarn() )
With this method by itself, if you change the trigger type to a different one than the original, it seems to (sometimes?) not work due to it expecting different data types; it's not yet known how to completely change the trigger type. You might be able to at least change trigger types if the Vars would be the same data types/names - for example if two trigger types both use { var1 = float, var2 = string, var3 = a Clump of Hulls, var4 = boolean } you could possibly switch from one type to the other and change the Var values and it would work; not tested yet.
With this method by itself, if you change the trigger type to a different one than the original, it seems to (sometimes?) not work due to it expecting different data types; it's not yet known how to completely change the trigger type during a level, but it can be done at the start of a level. You might be able to at least change trigger types if the Vars would be the same data types/names - for example if two trigger types both use { var1 = float, var2 = string, var3 = a Clump of Hulls, var4 = boolean } you could possibly switch from one type to the other and change the Var values and it would work; not tested yet.
 
You can also change the values of individual Vars in a Trigger if they are basic data types (like a boolean, number, string, etc - not a Names["Something"] reference) by simply running:
Names["ObjectName"][ "VarName" ]( Names["ObjectName"], NewVarValue )
 
====Creating new Triggers====
====Creating new Triggers====
You can temporarily create new triggers basically the same way, by adding the CreateTriggers function:
You can temporarily create new triggers basically the same way, by adding the CreateTriggers function:
Line 195: Line 218:
  ActivateTriggerByName( "TextTrigger" )
  ActivateTriggerByName( "TextTrigger" )
  ActivateTriggerByName( "AnimTrigger" )
  ActivateTriggerByName( "AnimTrigger" )
With this method alone, new Trigger ObjectNames are added to the Names table for the rest of the level, but the actual data defining what the Trigger should do is '''not''' added to the section of memory where normal Trigger data is stored. Wherever the data is, the Trigger does exist at least until the end of the frame (maybe a few frames) and it can be activated for that short time, but then the data is overwritten and your game will crash if it tries to activate the nonexistent Trigger.  
With this method alone, new Trigger ObjectNames are apparently added to the Names table for the rest of the level, but the actual data defining what the Trigger should do is '''not''' added to the section of memory where normal Trigger data is stored. Wherever the data is, the Trigger does exist at least until the end of the frame (maybe a few frames) and it can be activated for that short time, but then the data is overwritten and your game will crash if it tries to activate the nonexistent Trigger. Based on other research, the triggers might be permanent if you run the same <code>TriggerInstances = { whatever }</code> code again before you run ResolveTriggerNames, but this hasn't been tested.  


It is not yet known how to make the actual Trigger persist for the entire level. Until we figure that out, one solution to create new "persistent" Triggers might be to have this code running every frame - though you'd have to make it not run while the normal level load/unload stuff is happening. Haven't tested that yet.
If that doesn't work, one solution to create new "persistent" Triggers might be to have this code running every frame - though you'd have to make it not run while the normal level load/unload stuff is happening. Haven't tested that yet.


Once you have created a new Trigger, you only need to use ResolveTriggerNames() to re-create it after its data is deleted. However, there does not appear to be any harm in using CreateTriggers() for it again, it just won't do anything - the Names table will stay the same.
Once you have created a new Trigger, you only need to use ResolveTriggerNames() to re-create it after its data is deleted. However, there does not appear to be any harm in using CreateTriggers() for it again, it just won't do anything - the Names table will stay the same.
====Spawning instant one-time Triggers====
==== Spawning instant one-time Triggers ====
If you just want to make a new Trigger-like event that instantly happens and then disappears ( instead of being a "normal" Trigger that relies on other Triggers to make it happen and can be reused) you can use the SpawnEvent function from PWeb3.lua. It seems that SpawnEvent is not a global function, so you have to re-define it to use it globally.
If you just want to make a new Trigger that instantly activates and then is removed from memory by Lua garbage collection after it's done doing its stuff ( instead of being a "normal" Trigger that relies on other Triggers to make it happen and can be reused) you can use the SpawnEvent function from PWeb3.lua. It seems that SpawnEvent is not a global function, so you have to re-define it to use it globally.
  SpawnEvent { TriggerType = { var1 = x, var2 = y, var3 = z... basically the same kind of Vars table that would be used with that Trigger type }
  SpawnEvent { TriggerType = { var1 = x, var2 = y, var3 = z... basically the same kind of Vars table that would be used with that Trigger type }
===Clumps===
===Clumps===
Line 220: Line 243:
  SetClumpMembers( game:clumpBarn() )
  SetClumpMembers( game:clumpBarn() )
Demonstration of the new Clump:
Demonstration of the new Clump:
  SpawnEvent {EventAfterDelay = {delay = 0.01, effects = Names["NewGameStandUpEvents"]}}
  <nowiki>SpawnEvent {EventAfterDelay = {delay = 0.01, effects = Names["NewGameStandUpEvents"]}}</nowiki>
Demonstration of the Clump it's duplicating:
Demonstration of the Clump it's duplicating:
  SpawnEvent {EventAfterDelay = {delay = 0.01, effects = Names["e7fa07adac45a2fb9a369edcf5964ec7"]}}
  <nowiki>SpawnEvent {EventAfterDelay = {delay = 0.01, effects = Names["e7fa07adac45a2fb9a369edcf5964ec7"]}}</nowiki>
====Modifying Clumps====
====Modifying Clumps====
To modify existing Clumps, get them from ClumpInstances.lua and do basically the same code, but without the LoadClumps function:
To modify existing Clumps, get them from ClumpInstances.lua and do basically the same code, but without the LoadClumps function:
Line 231: Line 254:
  SetClumpMembers( game:clumpBarn() )
  SetClumpMembers( game:clumpBarn() )
Demonstration:
Demonstration:
  SpawnEvent {EventAfterDelay = {delay = 0.01, effects = Names["e7fa07adac45a2fb9a369edcf5964ec7"]}}
  <nowiki>SpawnEvent {EventAfterDelay = {delay = 0.01, effects = Names["e7fa07adac45a2fb9a369edcf5964ec7"]}}</nowiki>
===Timelines===
===Timelines===
Timelines are timed sequences of Trigger activations, used to organize cutscenes and other events where a bunch of Triggers get activated in a row.  
Timelines are timed sequences of Trigger activations, used to organize cutscenes and other events where a bunch of Triggers get activated in a row.  
Line 255: Line 278:
  LoadEnvFXParticles( game:envFXBarn(), game:particleBarn() )
  LoadEnvFXParticles( game:envFXBarn(), game:particleBarn() )
Based on tests where logging code was put in LoadEnvFXParticles() and ParticleEmitterInitialize() and nothing was logged, it seems this script doesn't actually run at level start, so Particle Emitters might be added to Names table by another Lua script or by inaccessible C code. But maybe this function could still add/modify Particle Emitters anyway.
Based on tests where logging code was put in LoadEnvFXParticles() and ParticleEmitterInitialize() and nothing was logged, it seems this script doesn't actually run at level start, so Particle Emitters might be added to Names table by another Lua script or by inaccessible C code. But maybe this function could still add/modify Particle Emitters anyway.
=== Sound Emitters===
===Sound Emitters===
Sound Emitters emit sounds. They can be stationary or attached to a moving object somehow. It seems that most looping music is played by Sound Emitters that are set to be audible at the same volume anywhere in the level.
Sound Emitters emit sounds. They can be stationary or attached to a moving object somehow. It seems that most looping music is played by Sound Emitters that are set to be audible at the same volume anywhere in the level.


Line 275: Line 298:
LoadEnvNodes does ''not'' clear the EnvNodeInstances table automatically upon completion, and the code comments say this causes a crash, so might be a bad idea to do it yourself.
LoadEnvNodes does ''not'' clear the EnvNodeInstances table automatically upon completion, and the code comments say this causes a crash, so might be a bad idea to do it yourself.
===Markers===
===Markers===
Markers seem to be locations, or regions of space around locations, which objects can be aimed or moved towards/away from by certain Triggers. Also, Markers can maybe be moved around or attached to moving objects by Triggers.
Markers are point locations, which objects can be aimed at/away from, moved towards/away from, or attached to by certain Triggers.


It has not yet been tested, but Markers can probably be added and/or modified in a similar way to Triggers and Clumps, based on MarkerInstances.lua's and the functions in Markers.lua:
Markers can be added and/or modified in a similar way to Triggers and Clumps, based on MarkerInstances.lua's and the functions in Markers.lua:
  MarkerInstances = { construct based on the format in MarkerInstances.lua }
  MarkerInstances = { construct based on the format in MarkerInstances.lua }
  LoadMarkers( game:markerBarn() )
  LoadMarkers( game:markerBarn() )
Doing the above works to modify Markers that already exist, but might clutter up memory by just replacing Names table entries with new Markers, and the old ones aren't garbage collected... not yet figured out.
Markers can also be modified by running this code:
<code>MarkerInitialize( Names["The Marker's ObjectName"], { an individual Marker constructor table })</code>
Or individual variables for Markers can be modified by running <code>Names["The Marker's ObjectName"]:function</code>  with functions:
* <code>SetPosition{X, Y, Z}</code> = set position at XYZ coordinates
* <code>SetQuat{a, b, c, d}</code> = set orientation/angle to that quaternion. Is used for certain Triggers/etc that do stuff like "set some other object's angle to the quaternion of this Marker".
* <code>SetScale{X, Y, Z}</code> = sets "scale" in XYZ axis. Markers are points so their actual size is always "infinitely small", in terms of anything that Triggers/etc check about whether the Marker is touching something/inside some area, etc;  the scale is just used for stuff like Triggers that say "set some object's scale to the scale of this Marker".
* <code>enabled(true or false)</code> = whether the Marker is enabled (assumedly if it's disabled, then any Triggers/etc that "do something" relating to the Marker will not do that thing; not tested)
===Decoration Meshes===
Decoration Meshes are any visible object other than terrain, fog, particle effects, Strands(?), and the basic "naked" player avatar. By themselves, they are not physical objects: most collision data comes from physical Hulls put in the same place as the mesh, and for cloth objects the collision/interaction mechanics are set by certain types of Triggers.
You can add/change Decoration Meshes loaded at start of level by editing DecorationMeshInstances.lua.bin in the folder for that level under Data/Scripts. See Paleologos's guide on Journey fan forum modding board.
Decoration Meshes that exist can probably be modified by running:
<code>DecorationInitialize( game:resources(), Names["The DM's ObjectName", {a table defining the DM, see below}] )</code>
They can definitely have individual variables modified by running <code>Names["The DM's ObjectName"]:function</code>  with the same kind of code found inside the DecorationInitialize function (found in DecorationMeshes.lua);
for example <code>Names["ObjectName"]:SetMatrix( Transformation, see below )</code> will change the rotation/scale/position of the mesh.
Here is basically how the Decoration Mesh constructor table is formatted (this is the Sphinx in Level_Graveyard):
<div class="toccolours mw-collapsible mw-collapsed">
<div style="font-weight:bold;line-height:1.6;">Example of non-binarized Decoration Mesh constructor</div>
<div class="mw-collapsible-content">
<nowiki>{
ObjectName = "ecd9205156899a8ad85b0dc3eb91313c"
  , GardenerName = "|Decoration549|Decoration549_G"
  , Mesh = "P_GraveyardGateRaySphinx"
  , FadeMin = 200
  , FadeMax = 220
  , ShaderLODMin = 15
  , ShaderLODMax = 30
  , Brightness = 1
  , Saturation = 1
  , Hue = 0
  , Transformation = { {4.44089e-016, 0, 1, 0}, {-0, 1, 0, 0}, {-1, -0, 4.44089e-016, 0}, {253.055, 6.07769, 491.756, 1} }
  , Shader = "MeshCham"
  , RenderMode = "Solid"
  , ShaderParams =
    { { ParamType = "float3"
      , ParamName = "uvMlt"
      , ParamVal = { 1, 1, 1 }
      }
    , { ParamType = "texture"
      , ParamName = "texColor"
      , ParamVal = "Sphinx"
      }
    , { ParamType = "texture"
      , ParamName = "texDetail"
      , ParamVal = "Warm"
      }
    , { ParamType = "texture"
      , ParamName = "texRamp"
      , ParamVal = "DesertShadowRamp"
      }
    , { ParamType = "texture"
      , ParamName = "texAo"
      , ParamVal = "White"
      }
    , { ParamType = "texture"
      , ParamName = "texEdgeMask"
      , ParamVal = "White"
      }
    , { ParamType = "float"
      , ParamName = "inShadow"
      , ParamVal = 0
      }
    , { ParamType = "float3"
      , ParamName = "aoStepBiasInt"
      , ParamVal = { 0, 0, 0 }
      }
    , { ParamType = "float"
      , ParamName = "chamLevel"
      , ParamVal = 11
      }
    , { ParamType = "float3"
      , ParamName = "chamDir"
      , ParamVal = { 0, 1, 0 }
      }
    , { ParamType = "texture"
      , ParamName = "texCham"
      , ParamVal = "SphinxSymbol"
      }
    , { ParamType = "texture"
      , ParamName = "texChamMask"
      , ParamVal = "BlurredNoise"
      }
    , { ParamType = "float3"
      , ParamName = "chamColor"
      , ParamVal = { 15, 15, 15 }
      }
    , { ParamType = "float3"
      , ParamName = "chamEdgeColor"
      , ParamVal = { 3.5, 2.21585, 1.3055 }
      }
    , { ParamType = "float2"
      , ParamName = "uvOffset"
      , ParamVal = { 0, 0 }
      }
    }
  }</nowiki></div></div>
<u>Stuff known so far about adding new objects during the level:</u>
The game loads Decoration Meshes into the Names table by calling AddDecoToNames() which is in DecorationMeshes.lua ; a Decoration class object gets passed to the function as "deco". It is not yet known if/how we could create a Decoration in Lua.
DecorationMeshes.lua includes a DecorationMeshes function (mostly commented out) and DecorationInitialize function, which seem like they could convert data in a DecorationMeshInstances table to Decorations and load them into the Names table, but there is no DecorationMeshInstances table ever created(?), plus the DecorationMeshes function needs to be passed a DecorationBarn as "decBarn" and there is nothing like a game:decBarn()/decorationBarn()/etc. It is not yet known if/how we could call a usable DecorationBarn in Lua.
===Rails===
===Rails===
Rails seem to be paths that objects can move along.
Rails are invisible lines drawn between a set of point locations, which may be "closed", as in the last point connects back to the first point. They seem to mostly be used as a path for an object/etc to move along, but are also used for other kinds of things that are based on a "2D" line in space - like some wind walls are an infinite flat plane stretching up and/or down from a Rail.


It has not yet been tested, but Rails can probably be added and/or modified in a similar way to Triggers and Clumps, based on RailInstances.lua's and the functions in RailBarn.lua:
It has not yet been tested, but Rails can probably be added and/or modified in a similar way to Triggers and Clumps, based on RailInstances.lua's and the functions in RailBarn.lua:
Line 310: Line 448:


<nowiki>**</nowiki> signData and signInstances don't seem to actually be referenced inside InitializeSignBarn, so they might not be required, but if required then maybe signData is the Credits table and signInstances is the SignInstances table. )
<nowiki>**</nowiki> signData and signInstances don't seem to actually be referenced inside InitializeSignBarn, so they might not be required, but if required then maybe signData is the Credits table and signInstances is the SignInstances table. )
=== TBD / Other===
===TBD / Other ===
These are the remaining types of level resources. They can *maybe* be manipulated in real time with Lua code, but it's not yet known if/how it can be done.
These are the remaining types of level objects/resources. They can *maybe* be manipulated in real time with Lua code, but it's not yet known if/how it can be done.
====Hulls====
==== Hulls====
Hulls are regions of space that never move(?), which are used as physical collision geometry and/or a way for Triggers to determine "if ''this thing'' is touching/inside ''this region'', do ''this event''".
Hulls are 3D regions of space, which are used as collision geometry and/or a way for Triggers to determine "if ''this thing'' is touching/inside ''this region'', do ''this event''", and also can have some built-in properties like being wind walls, etc.  
 
You can change the Hulls loaded at start of level by editing HullInstances.lua in the folder for that level under Data/Scripts.
====Decoration Meshes====
Decoration Meshes are any visible object other than terrain, fog, particle effects, Strands(?), and the basic "naked" player avatar. By themselves, they are not physical objects, their collision data comes from physical Hulls put in the same place.
 
You can change the Decoration Meshes loaded at start of level by editing DecorationMeshInstances.lua.bin in the folder for that level under Data/Scripts.
 
<u>Known so far:</u>


The game loads Decoration Meshes into the Names table by calling AddDecoToNames() which is in DecorationMeshes.lua ; a Decoration class object gets passed to the function as "deco". It is not yet known if/how we could create a Decoration in Lua.
You can change the Hulls loaded at start of level by editing HullInstances.lua.bin in the folder for that level under Data/Scripts.


DecorationMeshes.lua includes a DecorationMeshes function (mostly commented out) and DecorationInitialize function, which seem like they could convert data in the DecorationMeshInstances table to Decorations and load them into the Names table, but the DecorationMeshes function needs to be passed a DecorationBarn as "decBarn" and there is nothing like a game:decBarn()/decorationBarn()/etc. It is not yet known if/how we could call a usable DecorationBarn in Lua.
====Sound Banks====
====Sound Banks====
SFX Banks contain sounds, and references/mixing data for longer sounds streamed from the audio files in Data/Sounds/Streams.
SFX Banks contain sounds, and references/mixing data for longer sounds streamed from the audio files in Data/Sounds/Streams.
Line 331: Line 460:
Music Banks just contain references/mixing data for music audio files streamed in from Data/Sounds/Streams.
Music Banks just contain references/mixing data for music audio files streamed in from Data/Sounds/Streams.


These are LevelSfx''Somewhere''-SFX.bnk and LevelMus''Somewhere''-MUS.bnk in the Data/Sounds folder; not much is known yet about how to edit these at all, other than renaming files to swap one level for another.
These are LevelSfx''Somewhere''-SFX.bnk and LevelMus''Somewhere''-MUS.bnk in the Data/Sounds folder; not much is known yet about how to edit these at all, other than renaming files to swap one level for another, or editing the code for QueueResourcesForLoad() to change the sound bank resource in the resource table it receives at the start of the level.
====TerrainData ====
====TerrainData====
Terrain Data determines the terrain's Height Map and Land Color (the color of sand/snow added to the sides and/or top of some Decoration Meshes, and that collects on the player avatars). It also determines Mask Data which seems to be unused.
Terrain Data determines the terrain's Height Map and Land Color (the color of sand/snow added to the sides and/or top of some Decoration Meshes, and that collects on the player avatars). It also determines Mask Data which seems to be unused.


Line 342: Line 471:


==Using Functions With "Hidden" Barns/Managers==
==Using Functions With "Hidden" Barns/Managers==
Many of the functions for creating resources need a related "somethingBarn"/etc - many of them already have this as "game:somethingBarn()", but some don't appear to have any predefined global variable in Lua. For at least some of these, you can still access it and make your own global variable for it, and then use that variable whenever a function calls for a "somethingBarn". (This has only been tested with Creatures)
Many of the functions for creating level objects need a related "somethingBarn"/etc - many of them already have this as "game:somethingBarn()", but some don't appear to have any predefined global variable in Lua. For at least some of these, you can still access it and make your own global variable for it, and then use that variable whenever a function calls for a "somethingBarn". (This has only been tested with Creatures)


You do this by modifying/overwriting the function used with the Barn, to save the variable that it receives when the game calls it normally (whenever a level loads). For example, you could overwrite CreateCreatures with this:
You do this by modifying/overwriting the function used with the Barn, to save the variable that it receives when the game calls it normally (whenever a level loads). For example, you could overwrite CreateCreatures with this:
  function CreateCreatures( creatureBarn )
  function CreateCreatures( creatureBarn )
     Hack_CreatureBarn = creatureBarn -- this is the part that's been modded in
    --Mod
     Hack_CreatureBarn = creatureBarn
    --/Mod
     for i, v in ipairs( DynamicNodeInstances ) do
     for i, v in ipairs( DynamicNodeInstances ) do
         if v.Type == "Creature" then
         if v.Type == "Creature" then

Navigation menu