Skip to content

Object

At a high level, Core Lua types can be divided into two groups: data structures and Objects. Data structures are owned by Lua, while Objects are owned by the engine and could be destroyed while still referenced by Lua. Any such object will inherit from this type. These include CoreObject, Player, and Projectile.

Properties

Property Name Return Type Description Tags
serverUserData table Table in which users can store any data they want on the server. Read-Write, Server-Only
clientUserData table Table in which users can store any data they want on the client. Read-Write, Client-Only

Class Functions

Class Function Name Return Type Description Tags
Object.IsValid(Object object) boolean Returns true if object is still a valid Object, or false if it has been destroyed. Also returns false if passed a nil value or something that's not an Object, such as a Vector3 or a string. None

Examples

Example using:

IsValid

The example below shows the importance of using Object.IsValid() instead of a simple nil check (that is if object then). An object can be in a situation where it's invalid, but not yet nil. This can happen if a script is retaining a reference to it or it began the destroy process but hasn't completed it yet.

In this example, the script has a cube child that it finds with the GetChildren() call. It then prints information about the cube as it progresses through the steps of being destroyed and its variable reference cleared.

local CUBE = script:GetChildren()[1]

function PrintCubeInfo()
    print(".:.:. Information about CUBE object .:.:.")

    if CUBE then
        print("CUBE is NOT nil")
    else
        print("CUBE is nil")
    end

    if Object.IsValid(CUBE) then
        print("CUBE is valid")
    else
        print("CUBE is NOT valid")
    end

    local childrenCount = #script:GetChildren()
    print("Number of children of this script: " .. tostring(childrenCount))
    print("")
end

PrintCubeInfo()

-- The cube is destroyed, but we still have a variable pointing to it.
CUBE:Destroy()

PrintCubeInfo()

-- Variable reference is cleared, releasing the cube.
CUBE = nil

PrintCubeInfo()

See also: CoreObject.Destroy | CoreLua.print | Object.IsValid


Example using:

clientUserData

In this example, multiple copies of the same script are placed into the scene. At startup, they search for each other and build a follow chain. The last script that can't find another script to follow is set to follow the local player. As the player moves around the chain of objects follows along in a smooth motion. The clientUserData property is leveraged in building the chain of object references.

For this to work all scripts should be in a client context. In order to visualize the effect, objects (for example a Cube) can be added as children of the scripts.

As the name implies, clientUserData is a non-dynamic property on the client only.

local allScripts = World.FindObjectsByName(script.name)

for _, otherScript in ipairs(allScripts) do
    if otherScript ~= script
    and otherScript.clientUserData.target == nil then
        script.clientUserData.target = otherScript
        break
    end
end

if script.clientUserData.target == nil then
    script.clientUserData.target = Game.GetLocalPlayer()
end

local velocity = Vector3.ZERO
local DRAG = 0.96
local ACCELERATION = 0.5

function Tick()
    if not script.clientUserData.target then return end

    local myPos = script:GetWorldPosition()

    myPos = myPos + velocity
    velocity = velocity * DRAG

    local targetPos = script.clientUserData.target:GetWorldPosition()
    local direction = (targetPos - myPos):GetNormalized()
    velocity = velocity + direction * ACCELERATION

    script:SetWorldPosition(myPos)
end

See also: World.FindObjectsByName | Game.GetLocalPlayer | CoreObject.GetWorldPosition | Vector3:GetNormalized() | CoreLua.Tick


Example using:

serverUserData

In this example we are trying to figure out which player was the first to join the game and promote them with some gameplay advantage. That's easy for the first player joining, but because players can join and leave at any moment, the first player to join might leave, at which point we need to promote the next (oldest) player. To accomplish this, we keep count of how many players have joined and save that number onto each player's serverUserData--a kind of waiting list.

As the name implies, serverUserData is a non-dynamic property on the server only.

local primaryPlayer = nil
local joinCounter = 0

function OnPlayerJoined(player)
    joinCounter = joinCounter + 1
    -- Save the waiting number onto the player itself
    player.serverUserData.joinNumber = joinCounter
end

function PromotePlayer(player)
    -- Give some gameplay advantage or leadership ability
    print("PROMOTING: " .. player.name)
end

function Tick()
    if (not Object.IsValid(primaryPlayer)) then
        -- Find the oldest player
        local oldestPlayer = nil
        local oldestJoinNumber = 999999

        local allConnectedPlayers = Game.GetPlayers()

        for _, player in ipairs(allConnectedPlayers) do
            local joinNumber = player.serverUserData.joinNumber
            if joinNumber < oldestJoinNumber then
                oldestJoinNumber = joinNumber
                oldestPlayer = player
            end
        end

        -- If we found a player, promote them
        if oldestPlayer then
            primaryPlayer = oldestPlayer

            PromotePlayer(oldestPlayer)
        end
    end
end

Game.playerJoinedEvent:Connect(OnPlayerJoined)

See also: CoreLua.print | Player.name | Object.IsValid | Game.GetPlayers | Event.Connect



Last update: February 2, 2022