TBL to Strings, Oh my!

I'm going around in circles trying to get a units mesh from blue print and then apply to another entity. In this case I'm using a projectile to simulate part of a unit by applying the mesh to it, then hiding the unneeded bones.

Typically most units mesh's appear like so from the blue print...

Display= {
	Mesh = {
		IconFadeInZoom = 130,
		LODs = {
				AlbedoName = 'MyUnit01_Albedo.dds',
				LODCutoff = 100,
				LookupName = '/effects/entities/PhaseShield/PhaseShieldLookup.dds',
				MeshName = '/mods/haha/units/MyUnit01/MyUnit01_lod0.scm',
				NormalsName = '/mods/haha/units/MyUnit01/MyUnit01_normalsTS.dds',
				Scrolling = true,
				ShaderName = 'PhaseShield',
				SpecularName = '/mods/haha/units/MyUnit01/MyUnit01_SpecTeam.dds',
				AlbedoName = '/mods/haha/units/MyUnit01/MyUnit01_Albedo.dds',
				LODCutoff = 215,
				LookupName = '/effects/entities/PhaseShield/PhaseShieldLookup.dds',
				MeshName = '/mods/haha/units/MyUnit01/MyUnit01_lod1.scm',
				NormalsName = '/mods/haha/units/MyUnit01/MyUnit01_normalsTS.dds',
				ShaderName = 'PhaseShield',
				SpecularName = '/mods/haha/units/MyUnit01/MyUnit01_SpecTeam.dds',

So later on I try using...

        local stringMesh = table.concat(bp.Display.Mesh.LODs)
        WARN('stringMesh = '..repr(stringMesh))

And see " bad argument #1 to `concat' (table contains non-strings)"

Am i just misusing the concat or is there a better way of doing this?

Edit: SetMesh requires a string, not a table. Which is strange cause the whole game is setup as a bunch of tables.

Ok so progress, however slow is still progress...

Managed to use the following to change one units model to that of another unit.

local bp = self:GetBlueprint()
local meshId = bp.Display.MeshBlueprint
WARN('meshId: '..repr(meshId))

Though getting this to apply to a projectile is proving to be rather difficult.


While there are no errors shown, the projectile isn't showing either, nor can I apply a SetScale to it without it freaking out with Lua errors. Maybe I'll change to another projectile as there could be hidden Lua changing the outcome I'm after.

I have used the SetMesh Function on one of my UEF Aircraft Carriers in CSK Units to add some Decorations on it.
You need to Create an small Blueprint File for the SetMesh Function.

MeshBlueprint {
    LODs = {
    MeshName = '/units/uea0102/uea0102_lod0.scm',
    ShaderName = 'Unit',
    AlbedoName = '/units/uea0102/uea0102_Albedo.dds',
    NormalsName = '/units/uea0102/uea0102_Normals.dds',
    SpecularName = '/units/uea0102/uea0102_Specteam.dds',
    LODCutoff = 300,
    SortOrder = 999,

This needs to be added to the Unit_Script.lua Code:

self.Plane01 = import('/lua/sim/Entity.lua').Entity()
PlaneMesh1 = '/mods/Commander Survival Kit Units/Decorations/Plane02_mesh',
self.Plane01:AttachBoneTo( -1, self, 'AttachPoint01' )

The Result is this:

Do you See the Models of some UEF Air Units on the Aircraft Carrier?
These are the Decorations.

@cdrmv Setting up an external file and directing a path to it is badicly how personal shields get added. What I'm after is the local ability to pull a unit mesh, modify it (example: change a shader) then apply it to another entity on the fly.

The key is being able to take the mesh table and convert it to a string. Far as I know of, SetMesh only works with strings, not tables.

That is actually what I want to try Out as Well.
But for an single Unit in Detail.
For example a Unit which charges Up an Weapon and some Model Parts start to glow. And If the Unit has Fire the Weapon it Switch Back to the Default Model/Shader.
Would be nice but its difficult to Release.

These are a few Examples how the SetMesh Function is used by the Game on GitHub from FAF

StartBeingBuiltEffects = function(self, builder, layer)
local BuildMeshBp = self.Blueprint.Display.BuildMeshBlueprint
        if BuildMeshBp then
            self:SetMesh(BuildMeshBp, true)

StopBeingBuiltEffects = function(self, builder, layer)
        local bp = self.Blueprint.Display
        local useTerrainType = false
        if bp then
            if bp.TerrainMeshes then
                local bpTM = bp.TerrainMeshes
                local pos = self:GetPosition()
                local terrainType = GetTerrainType(pos[1], pos[3])
                if bpTM[terrainType.Style] then
                    self:SetMesh(bpTM[terrainType.Style], true)
                    useTerrainType = true
            if not useTerrainType then
                self:SetMesh(bp.MeshBlueprint, true)

These are the two Default Calls of the SetMesh Function, which I have Seen several times.
However BuildMeshBP and MeshBlueprint is Not really clear to me where this is Declared. Both doesn't Show Up in an Blueprint File of an Unit.

self:SetMesh(BuildMeshBp, true)
self:SetMesh(bp.MeshBlueprint, true)

@cdrmv Problem comes done to the SetMesh requiring a string that points to the new mesh (table) your wanting to use.

Only two proven methods of making this work is to manually create a mesh blueprint for each unit your you intend or could possible want to change.


Abuse Blueprint.lua so that when it compiles all of the units (at startup) it makes extra Blueprints for the unit variations that could be possible. DMS does this, though its not compatible with FAF, so I'm looking for alternatives.


MeshBlueprint is seen in MohoData\system\Blueprints.lua line 149, under the following function:

function ExtractMeshBlueprint(bp)
    local disp = bp.Display or {}
    bp.Display = disp

    if disp.MeshBlueprint=='' then
        LOG('Warning: ',bp.Source,': MeshBlueprint should not be an empty string')
        disp.MeshBlueprint = nil

    if type(disp.MeshBlueprint)=='string' then
        if disp.MeshBlueprint!=lower(disp.MeshBlueprint) then
            #Should we allow mixed-case blueprint names?
            #LOG('Warning: ',bp.Source,' (MeshBlueprint): ','Blueprint IDs must be all lowercase')
            disp.MeshBlueprint = lower(disp.MeshBlueprint)

        # strip trailing .bp
        disp.MeshBlueprint = gsub(disp.MeshBlueprint, "%.bp$", "")

        if disp.Mesh then
            LOG('Warning: ',bp.Source,' has mesh defined both inline and by reference')

    if disp.MeshBlueprint==nil then
        # For a blueprint file "/units/uel0001/uel0001_unit.bp", the default
        # mesh blueprint is "/units/uel0001/uel0001_mesh"
        local meshname,subcount = gsub(bp.Source, "_[a-z]+%.bp$", "_mesh")
        if subcount==1 then
            disp.MeshBlueprint = meshname

        if type(disp.Mesh)=='table' then
            local meshbp = disp.Mesh
            meshbp.Source = meshbp.Source or bp.Source
            meshbp.BlueprintId = disp.MeshBlueprint
            # roates:  Commented out so the info would stay in the unit BP and I could use it to precache by unit.
            # disp.Mesh = nil

BuildMeshBP is seen in MohoData\system\Blueprints.lua line 223, under the following function:

function ExtractBuildMeshBlueprint(bp)
	local FactionName = bp.General.FactionName

	if FactionName == 'Aeon' or FactionName == 'UEF' or FactionName == 'Cybran' or FactionName == 'Seraphim' then 
		local meshid = bp.Display.MeshBlueprint
		if not meshid then return end

		local meshbp = original_blueprints.Mesh[meshid]
		if not meshbp then return end

		local shadername = FactionName .. 'Build'
		local secondaryname = '/textures/effects/' .. FactionName .. 'BuildSpecular.dds'

		local buildmeshbp = table.deepcopy(meshbp)
		if buildmeshbp.LODs then
			for i,lod in buildmeshbp.LODs do
				lod.ShaderName = shadername
				lod.SecondaryName = secondaryname
				if FactionName == 'Seraphim' then
				    lod.LookupName = '/textures/environment/Falloff_seraphim_lookup.dds'
		buildmeshbp.BlueprintId = meshid .. '_build'
		bp.Display.BuildMeshBlueprint = buildmeshbp.BlueprintId

It looks like ExtractBuildMeshBlueprint is applying BuildSpecular for when a unit is being constructed at a factory. This could indicate a way to create your own custom blueprints during the game load-up. Then later be able to reference them and call them up as needed.

Further up Blueprint.lua check out the following function:

function ExtractAllMeshBlueprints()

    for id,bp in original_blueprints.Unit do

    for id,bp in original_blueprints.Prop do

    for id,bp in original_blueprints.Projectile do

This appears to kick off each of the Mesh build-ups in sequence. Could simply create your own function via /hook then reference it here towards the end of the file. Far as I can tell, doing so wouldn't change the game or how it behaves as your just adding in your own Mesh variants that are being saved as a global.

Please note: I pulled the above snippets from vanilla FA as not all files are always represented in the FAF Client. In this case, I've confirmed that FAF client does not have a Blueprint.lua as it's using the original vanilla version.


DMS uses a custom Blueprint.lua via /hook that looks very promising. Goto line 384 to see DMS_ExtractPersonalShieldMeshBlueprint.

DMS Blueprints.zip

Edit: Just added it to 4DFAF and it appears to run correctly.

INFO: Hooked /lua/system/Blueprints.lua with /mods/4dfaf/hook/lua/system/Blueprints.lua
INFO: Blueprints Loading... '*.bp' files
INFO: Blueprints Loading: original files from /effects directory
INFO: Blueprints Loading: original files from /env directory
INFO: Blueprints Loading: original files from /meshes directory
INFO: Blueprints Loading: original files from /projectiles directory
INFO: Blueprints Loading: original files from /props directory
INFO: Blueprints Loading: original files from /units directory
INFO: Blueprints Loading: modded files from "4D-FAF (4th-Dimension for FAF) v2, UEF Units" mod
INFO: Blueprints Extracting mesh...
INFO: Blueprints Modding...
INFO: Blueprints Loading... completed: 604 original, 18 modded, and 74 preset units
INFO: Blueprints Loading... completed: 392 original and 11 modded projectiles
INFO: Blueprints Registering...

OMG! Just did a quick WARN('Self blueprint: '..repr(self:GetBlueprint())) on one of my units and saw this for the units Display / Mesh section:

WARNING:  - Display: table: 1B5AF7A8
WARNING:  -    Abilities: table: 1B5AF4B0
WARNING:  -       1: Transforming
WARNING:  -       2: 35% Phasing in Air Mode
WARNING:  -       3: Shield Piercing Missile
WARNING:  -       4: Chain Lightning
WARNING:  -    AnimationDeath: table: 1B5AF528
WARNING:  -       1: table: 1B5AF550
WARNING:  -          Animation: /mods/4DFAF/units/xsl0310/xsl0310_Death01.sca
WARNING:  -          AnimationRateMax: 1.75
WARNING:  -          AnimationRateMin: 1.1499999761581
WARNING:  -          Weight: 50
WARNING:  -       2: table: 1B5AF578
WARNING:  -          Animation: /mods/4DFAF/units/xsl0310/xsl0310_death02.sca
WARNING:  -          AnimationRateMax: 1.75
WARNING:  -          AnimationRateMin: 1.1499999761581
WARNING:  -          Weight: 33
WARNING:  -    AnimationWalk: /mods/4DFAF/units/xsl0310/xsl0310_Awalk.sca
WARNING:  -    AnimationWalkRate: 0.64399999380112
WARNING:  -    BuildMeshBlueprint: /mods/4dfaf/units/xsl0310/xsl0310_mesh_build
WARNING:  -    CloakMeshBlueprint: /mods/4dfaf/units/xsl0310/xsl0310_mesh_cloak
WARNING:  -    DisplayName: 
WARNING:  -    HideLifebars: false
WARNING:  -    IconName: xsl0310
WARNING:  -    Mesh: table: 1B5AF438
WARNING:  -       BlueprintId: /mods/4dfaf/units/xsl0310/xsl0310_mesh
WARNING:  -       BlueprintOrdinal: 1297
WARNING:  -       Description: 
WARNING:  -       IconFadeInZoom: 130
WARNING:  -       LODs: table: 1B5AF460
WARNING:  -          1: table: 1B5AF488
WARNING:  -             AlbedoName: /mods/4dfaf/units/xsl0310/xsl0310_albedo.dds
WARNING:  -             LODCutoff: 225.20259094238
WARNING:  -             LookupName: /textures/environment/Falloff_seraphim_lookup.dds
WARNING:  -             MeshName: /mods/4dfaf/units/xsl0310/xsl0310_lod0.scm
WARNING:  -             NormalsName: /mods/4dfaf/units/xsl0310/xsl0310_normalsTS.dds
WARNING:  -             Occlude: false
WARNING:  -             Scrolling: true
WARNING:  -             SecondaryName: 
WARNING:  -             ShaderName: Seraphim
WARNING:  -             Silhouette: false
WARNING:  -             SpecularName: /mods/4dfaf/units/xsl0310/xsl0310_SpecTeam.dds
WARNING:  -       SortOrder: 0
WARNING:  -       Source: /mods/4dfaf/units/xsl0310/xsl0310_unit.bp
WARNING:  -       StraddleWater: false
WARNING:  -       UniformScale: 1
WARNING:  -    MeshBlueprint: /mods/4dfaf/units/xsl0310/xsl0310_mesh
WARNING:  -    MeshBlueprintWrecked: /mods/4dfaf/units/xsl0310/xsl0310_mesh_wreck
WARNING:  -    MovementEffects: table: 1B5AF7D0
WARNING:  -       Land: table: 1B5AF7F8
WARNING:  -          Effects: table: 1B5AF320
WARNING:  -             1: table: 1B5AF348
WARNING:  -                Bones: table: 1B5AF370
WARNING:  -                   1: LeftExhaust
WARNING:  -                   2: RightExhaust
WARNING:  -                Offset: table: 1B5AF3C0
WARNING:  -                   1: 0
WARNING:  -                   2: -0.40000000596046
WARNING:  -                   3: 0
WARNING:  -                Type: GroundKickup01
WARNING:  -    PersonalShieldMeshBlueprint: /mods/4dfaf/units/xsl0310/xsl0310_mesh_personalshield

BuildMeshBlueprint: /mods/4dfaf/units/xsl0310/xsl0310_mesh_build

CloakMeshBlueprint: /mods/4dfaf/units/xsl0310/xsl0310_mesh_cloak

MeshBlueprint: /mods/4dfaf/units/xsl0310/xsl0310_mesh

MeshBlueprintWrecked: /mods/4dfaf/units/xsl0310/xsl0310_mesh_wreck

PersonalShieldMeshBlueprint: /mods/4dfaf/units/xsl0310/xsl0310_mesh_personalshield

Domino is the F'n man!

YES !!!! I got the shield drone to work !

Video link (If it first doesn't work, then YouTube may still be processing it): https://youtu.be/IV39URap11s

Added a copy of this unit to the FAF server unit the name "4D-FAF (4th-Dimension for FAF), UEF & Seraphim Units".