Skip to content

Using The Library — Mod Launcher

Proddy edited this page May 10, 2023 · 2 revisions

This is the most common use case for the library, and the main reason it was built.

All the tutorials on this page assume that your mod has the library loaded, as explained in Getting Started.

Adding a chunk to an existing file

A big reason for the library is to help reduce mod size. If you want to add a change a couple of chunks to a L1_TERRA.p3d, you don't need to include a 1.32MB file, where 99% of it is the base game's file.

1) Configuring the Path Handler

If you don't already have one, create a file called CustomFiles.ini in the root of your mod's folder. This file contains all the path handling for files that Custom Files handles.

In the PathHandlers header, create a handler for L1_TERRA.

[PathHandlers]
art\\L1_TERRA.p3d=Resources/HandleL1Terra.lua

2) Writing the Path Handler

Create a file in your Resources folder, with the same name as you put in CustomFiles.ini.

This file will be called every time L1_TERRA is loaded. What we need to do is load the file, modify it, then Output it back to the game.

-- Get the path - we know this is L1_TERRA, but it's good practice to make a path handler dynamically get the path
local Path = GetPath()

-- Print to console that we're starting the path handler for this file
print("LuaP3DLib path handler started", Path)

-- To read a game file, we need to get the path in the virtual file system. See the docs for more details: https://docs.donutteam.com/docs/lucasmodlauncher/hacks/cf/virtual-file-system
local GamePath = "/GameData/" .. Path

-- Create the P3DFile
local P3DFile = P3D.P3DFile(GamePath)

-- Create the Locator chunk - We'll using a type 14 to create a coin, and we'll place it at 0,0,0
local Locator = P3D.LocatorP3DChunk("Custom Coin", P3D.Vector3(0, 0, 0), 14)

-- Add the locator to the P3DFile
P3DFile:AddChunk(Locator)

-- Output the P3DFile to the game
P3DFile:Output()

Modifying an existing chunk

Similar to adding a chunk, including an entire Pure3D file to modify a single chunk makes your mod needlessly large.

Doing it dynamically also allows for Pure3D edits based on mod settings.

For this example, we'll allow the end user to dynamically choose a colour for the radar.

1) Creating the mod setting

As we're allowing the end user to pick the colour, we need to add a mod setting. This is done by adding a [Setting] block to the Meta.ini.

To add a colour setting, you can append the below to the end of Meta.ini. More documentation can be found on the Configuring Mods page on the docs.

[Setting]
Name=RadarColour
Type=Colour
Title=Radar Colour
Default=0xFF00FF00
Alpha=0

2) Reading the mod setting

As mod settings cannot be changed whilst the game is launched, we only need to read them once. To do this, we can create a global variable in CustomFiles.lua.

-- Colour settings are provided as a 32bit int. We can use bitshifting to get the individual A, R, G, B values.
local function ColourToARGB(col)
	return (col >> 24) & 0xFF, (col >> 16) & 0xFF, (col >> 8) & 0xFF, col & 0xFF
end

-- Create the colour table
RadarColour = {}
-- Assign the values from the setting
RadarColour.A, RadarColour.R, RadarColour.G, RadarColour.B = ColourToARGB(GetSetting("RadarColour"))

3) Configuring the Path Handler

If you don't already have one, create a file called CustomFiles.ini in the root of your mod's folder. This file contains all the path handling for files that Custom Files handles.

In the PathHandlers header, create a handler for ingame.

[PathHandlers]
art\\frontend\\scrooby\\ingame.p3d=Resources/HandleIngame.lua

4) Writing the Path Handler

Create a file in your Resources folder, with the same name as you put in CustomFiles.ini.

This file will be called every time ingame is loaded. What we need to do is load the file, modify it, then Output it back to the game.

Note: For this example, we have a file called radar.p3d in the Resources folder that contains a single Sprite chunk.

-- Get the path - we know this is L1_TERRA, but it's good practice to make a path handler dynamically get the path
local Path = GetPath()

-- Print to console that we're starting the path handler for this file
print("LuaP3DLib path handler started", Path)

-- To read a game file, we need to get the path in the virtual file system. See the docs for more details: https://docs.donutteam.com/docs/lucasmodlauncher/hacks/cf/virtual-file-system
local GamePath = "/GameData/" .. Path

-- Create the P3DFile
local P3DFile = P3D.P3DFile(GamePath)

-- Load the P3D file from Resources
local RadarP3D = P3D.P3DFile(Paths.Resources .. "/radar.p3d")
-- Get the sprite chunk from the file
local RadarSprite = RadarP3D:GetChunk(P3D.Identifiers.Sprite)

-- Loop the P3DFile to find the original `radar.png` sprite, and replace it with the one from Resources
for ChunkIndex, Chunk in P3DFile:GetChunks(P3D.Identifiers.Sprite) do
	if Chunk.Name == "radar.png" then
		P3DFile.Chunks[ChunkIndex] = RadarSprite

		-- Break out of the loop - there's only one `radar.png` Sprite
		break
	end
end

-- Get the Frontend Project chunk from the original file
local ProjectChunk = P3DFile:GetChunk(P3D.Identifiers.Frontend_Project)
-- Create a variable to store the Hud in
local Hud
-- Loop each Frontend Page in the Frontend Project, looking for `Hud.pag`
for chunk in ProjectChunk:GetChunks(P3D.Identifiers.Frontend_Page) do
	if chunk.Name == "Hud.pag" then
		-- Assign it to the Hud variable and break from the loop
		Hud = chunk
		break
	end
end

-- Check we actually found the Hud
if Hud then
	-- Go down the chunk hierarchy to get the Frontend Multi Sprite that displays the radar
	local LayerChunk = Hud:GetChunk(P3D.Identifiers.Frontend_Layer)
	local PlayerGroupChunk = LayerChunk:GetChunk(P3D.Identifiers.Frontend_Group)
	local HudMapGroupChunk = PlayerGroupChunk:GetChunk(P3D.Identifiers.Frontend_Group)
	local RadarGroupChunk = HudMapGroupChunk:GetChunk(P3D.Identifiers.Frontend_Group)
	local RadarSprite = RadarGroupChunk:GetChunk(P3D.Identifiers.Frontend_Multi_Sprite)
	
	-- Set the radar colour to be the global variable in `CustomFiles.lua`
	RadarSprite.Colour = RadarColour
	
	-- Output the modified file
	P3DFile:Output()
end