`World.Spawn()` with Custom Properties

In a system with two templates NPC and Spawner:

  • the NPC template has Custom Properties "Speed" (number) and "Lane" (CoreObjectReference)
  • the Spawner template also has these same Custom Properties, plus "Interval" (number of seconds between spawns)

The Spawner should copy its Speed and Lane values to the NPC. Ideally this would happen in the call to World.Spawn() but this seem to work.

As a workaround, I can copy the values using npc:SetCustomProperty(), then listen for those changes in the NPC implementation. This makes the implementation of NPC more complex.

Should this be a feature request? Or is there actually a way to spawn with Custom Properties?

-- Every INTERVAL seconds spawn template
while true do
  local npc = World.SpawnAsset(NPC_TEMPLATE, {
    transform = SPAWNER:GetWorldTransform(),
    Lane = SPAWN_LANE,
    Speed = SPAWN_SPEED,
  npc:SetCustomProperty("Lane", LANE)

I think it would be a nice idea (you can't do it at the moment) - although you get exactly that option when you AddItem() to an inventory.

However, it would be fairly simple to write your own wrapper function for SpawnAsset along the same lines as AddItem that added this functionality. e.g.

function SpawnAssetWithProps(assetID, tableParams, tableCustomProps)
    local asset = World.SpawnAsset(assetID, tableParams)
    for propName, propValue in pairs(tableCustomProps) do
        asset:SetCustomProperty(propName, propValue)
    return asset

Of course you would want to add some error traps etc.

You could then call the function with something like:

SpawnAssetWithProps(myTemplate, nil, {["TestString"] = "Something", ["TestInt"] = 1})

Instead of that rather ugly hand coded table you could build that separately using some other approach; perhaps based on GetCustomProperties(). Hopefully that gives you some ideas.

Edit: For general reference, be sure to make those properties dynamic for this to work.

Second Edit: Regarding getting the props into your NPC, I think listening for the change is likely to be the most robust.

The one issue I find with this approach is that any scripts running immediately after the asset is spawned will run before the calls to SetCustomProperty(). To handle those changes asynchronously while keeping the original functionality when in Hierarchy, the result scripts are more verbose.

I agree it's not nice. I have not tested if SetCustomProperty sequentially sets the property server side or queues it as an additional task. If it sets it when called then your server side scripts should be OK, or as a minimum require a Task.Wait() to get pushed down the list of tasks. Unfortunately, anything non-server is fully subject to race conditions. I guess you could use a data table and have the script wait for the data table property to not be nil.