This page documents the tools to help with syncing NPCs online. NPC behaviour is handled in scripts/onlinePlay_npc.lua.
Every NPC is considered to be "owned" by a specific player. This player is responsible for sending everyone else updates about the NPC. NPCs only get an owner after spawning, and the owner can change at any time.
NPCs are also given "online UIDs". This number is used to identify the NPC, since using its index would not be reliable. Once an NPC has been assigned a UID, it will never change.
Most properties of an NPC - things like its position, speed, extra settings, and much more - will already be synced. However, the data table is not synced. In order to sync properties in the data table, you can use the "extra data" properties of the online NPC handling config.
NPCs IDs can have extra code and properties specified for them through the handling config. Most importantly, this allows for proper syncing of data tables. It also allows you to control things like when a player should steal ownership of an NPC from another player, or how often often the NPC should be updated.
The handling config can be used like so:
local onlinePlayNPC = require("scripts/onlinePlay_npc")
-- 751 is the ID of the NPC you want to affect here.
onlinePlayNPC.onlineHandlingConfig[751] = {
getExtraData = function(v)
-- The owner of the NPC will run getExtraData.
-- Its return value will then be received by everyone else in setExtraData.
local data = v.data
if not data.initialized then
return nil
end
return {
state = data.state,
timer = data.timer,
}
end,
setExtraData = function(v,receivedData)
-- The data from getExtraData will be used to change the NPC's state.
-- This is mainly for data table syncing, but it can also be used for any information about the NPC.
local data = v.data
if not data.initialized then
return nil
end
data.state = receivedData.state
data.timer = receivedData.timer
end,
}
The following fields are available for a handling config:
Field | Type | Description |
---|---|---|
getExtraData | function | A function to encode data about the NPC's state, which can then be passed into setExtraData on the other players' ends. Can return any encodable value. |
setExtraData | function | A function to take in the data from getExtraData and modify the NPC's state accordingly. |
shouldStealFunc | function | Runs every frame, if the NPC is owned by another player. If it returns true, it will try to take ownership of the NPC. If it returns false, then the NPC cannot be stolen at all. If it returns nil, standard logic for stealing NPCs applies. |
findSuitableOwnerFunc | function | Runs when an NPC initially spawns, to decide who should get ownership of it. If it returns a number, that player of that index will be given ownership. If it returns nil, standard logic for NPC ownership applies. |
canClaimHarmFunc | function | Normally, NPC harming is cancelled unless the player owns the NPC or is responsible for the harming. If this function returns true, harming will be allowed regardless of any other factors. |
canClaimKillFunc | function | Similar to canClaimHarmFunc, but for when an NPC dies. |
updateFrequency | number | How long, in seconds, is between each update of the NPC. The default is 1/10 (i.e., 10 updates per second). |
The following functions can be used for modifying the handling config per-NPC instead of per-ID. Note that the getExtraData and setExtraData functions cannot be changed through these methods.
Function | Returns | Description |
---|---|---|
onlinePlayNPC.getConfig​(​npc (NPC)​) | table or nil | Returns the handling config used by the NPC, if it has one. Respects per-NPC configs. |
onlinePlayNPC.overwriteConfig​(​npc (NPC), newConfig (table)​) | nil | Completely replaces the handling config of the NPC, ignoring the per-ID config entirely. |
onlinePlayNPC.mergeConfig​(​npc (NPC), newConfig (table)​) | nil | Merges the new config with the NPC's existing config (be it a per-NPC or per-ID one). If conflicts exist, then the new config takes priority. |
onlinePlayNPC.resetConfig​(​npc (NPC)​) | nil | Resets any per-NPC config, restoring the NPC to the per-ID config. |
Function | Returns | Description |
---|---|---|
onlinePlayNPC.getUIDFromNPC​(​npc (NPC)​) | number or nil | Returns the online UID of the NPC. If the NPC has not yet been assigned one, returns nil. |
onlinePlayNPC.getNPCFromUID​(​onlineUID (number)​) | NPC or nil | Returns the NPC with the given UID, if it exists. |
onlinePlayNPC.getOwner​(​npc (NPC)​) | number | Returns the index of the player that owns the NPC. If no owner has been assigned, returns 0. |
onlinePlayNPC.ownsNPC​(​npc (NPC)​) | boolean | Returns true if the NPC is owned by the player, or false otherwise. Always returns true when not online. |
onlinePlayNPC.tryClaimNPC​(​npc (NPC)​) | nil | Tries to claim ownership of the NPC, if it doesn't already have an owner. Does not guarantee that it will actually be claimed unless the player is the host. |
onlinePlayNPC.assignNPCToOwner​(​npc (NPC), playerIdx (number)​) | nil | Grants ownership of an NPC to a specific player. Can only be run as the host. |
For convenience, there is a version of the commands system specifically for NPCs. It acts almost exactly like the regular commands sytem, but each message is tied to a specific NPC.
local onlinePlay = require("scripts/onlinePlay")
local onlinePlayNPC = require("scripts/onlinePlay_npc")
-- NPC commands are created exactly like regular commands, just with a different function.
-- You should include the name of your NPC in the command name, to make it more unique.
local exampleCommand = onlinePlayNPC.createNPCCommand("myNPCName_example", onlinePlay.IMPORTANCE_MAJOR)
-- onReceive works almost the same, but there is an added argument: the NPC for the command.
function exampleCommand.onReceive(npc,sourcePlayerIdx, foo,bar)
-- Your code here.
end
-- Command:send is also mostly the same as a regular command, just with an NPC.
exampleCommand:send(npc,0, foo,bar)