Skip to main content

Observer

A typed observer that notifies subscribers when its value changes. Observers can be created and subscribed to from any module. They are useful for decoupling modules and creating a more modular codebase. The Observer class is a singleton and should not be instantiated. The Observer class provides two methods for creating and getting observers. You can create an observer with a specific type and subscribe to it with a callback. When the observer's value changes, all subscribed callbacks are called with the new value.

One of my favorite explanations of the observer pattern is from Refactoring Guru.

Here's an example of how to use the Observer class: Firstly, Setup Event Module

local Observer = require(path.to.Observer)

local events = {
	["PlayerDamaged"] = Observer.Create("PlayerDamaged") :: Observer.Event<Player, number>,
	["MorningTime"] = Observer.Create("MorningTime") :: Observer.Event<string>,
}

return events

Secondly, Connect to an Event in any Module

local events = require(path.to.Events)

events.MorningTime:Connect(function(morningString: string)
	if morningString == "Good Morning" then
		print(`{morningString}! It's a awesome day!`)
	elseif morningString == "Bad Morning" then
		print(`{morningString}! It's what we get when it rains!`)
	end
end)

events.PlayerDamaged:Connect(function(player: Player, damage: number)
	print(`{player.Name} took {damage} damage!`)
	playerEffects:ShakeScreen() -- example function
	particleSystem:BloodSplatter(player.Position) -- example function
end)

Lastly, Fire the Event Value in any Module

local events = require(path.to.Events)

events.MorningTime:Fire("Good Morning")

while player:IsStandingInFire() do
	events.PlayerDamaged:Fire(10)
end
NOTE
Observers are client/server specific and cannot be shared between them.
You would need to create a separate observer for each side.
OR create some sort of networked event system to communicate between them.

Types

Connection

interface Connection {
Disconnect(selfConnection) → ()--

Disconnects the connection, removing the callback from the event.

}

Functions

Create

Observer.Create(namestring) → Event<T...>

Types

interface Event<T...> {
Connect(
selfEvent<T...>,
callback(...any) → ()
) → Connection--

Connects a callback to the event. The callback will be called with the event's parameters when the event is fired.

Fire(
selfEvent<T...>,
...T...
) → ()--

Fires the event with the given parameters. All connected callbacks will be called with these parameters.

}

Creates a new typed observer with the specified name.

local Observer = require(path.to.Observer)

local events = {
	["PlayerDamaged"] = Observer.Create("PlayerDamaged") :: Observer.Event<Player, number>,
	["MorningTime"] = Observer.Create("MorningTime") :: Observer.Event<string>,
}

return events
Show raw api
{
    "functions": [
        {
            "name": "Create",
            "desc": "Creates a new typed observer with the specified name.\n\n```lua\nlocal Observer = require(path.to.Observer)\n\nlocal events = {\n\t[\"PlayerDamaged\"] = Observer.Create(\"PlayerDamaged\") :: Observer.Event<Player, number>,\n\t[\"MorningTime\"] = Observer.Create(\"MorningTime\") :: Observer.Event<string>,\n}\n\nreturn events\n```",
            "params": [
                {
                    "name": "name",
                    "desc": "",
                    "lua_type": "string"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Event<T...>\n"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 147,
                "path": "libraries/observer/Source/init.lua"
            }
        }
    ],
    "properties": [],
    "types": [
        {
            "name": "Connection",
            "desc": "",
            "fields": [
                {
                    "name": "Disconnect",
                    "lua_type": "(self: Connection) -> ()",
                    "desc": "Disconnects the connection, removing the callback from the event."
                }
            ],
            "source": {
                "line": 16,
                "path": "libraries/observer/Source/init.lua"
            }
        },
        {
            "name": "Event<T...>",
            "desc": "",
            "fields": [
                {
                    "name": "Connect",
                    "lua_type": "(self: Event<T...>, callback: (...any) -> ()) -> Connection",
                    "desc": "Connects a callback to the event. The callback will be called with the event's parameters when the event is fired."
                },
                {
                    "name": "Fire",
                    "lua_type": "(self: Event<T...>, ...: T...) -> ()",
                    "desc": "Fires the event with the given parameters. All connected callbacks will be called with these parameters."
                }
            ],
            "source": {
                "line": 27,
                "path": "libraries/observer/Source/init.lua"
            }
        }
    ],
    "name": "Observer",
    "desc": "- Wally Package: [Observer](https://wally.run/package/naxious/observer)\n\nA typed observer that notifies subscribers when its value changes.\nObservers can be created and subscribed to from any module.\nThey are useful for decoupling modules and creating a more modular codebase.\nThe Observer class is a singleton and should not be instantiated.\nThe Observer class provides two methods for creating and getting observers.\nYou can create an observer with a specific type and subscribe to it with a callback.\nWhen the observer's value changes, all subscribed callbacks are called with the new value.\n\nOne of my favorite explanations of the observer pattern is from [Refactoring Guru](https://refactoring.guru/design-patterns/observer).\n\nHere's an example of how to use the Observer class:\n`Firstly, Setup Event Module`\n```lua\nlocal Observer = require(path.to.Observer)\n\nlocal events = {\n\t[\"PlayerDamaged\"] = Observer.Create(\"PlayerDamaged\") :: Observer.Event<Player, number>,\n\t[\"MorningTime\"] = Observer.Create(\"MorningTime\") :: Observer.Event<string>,\n}\n\nreturn events\n```\n`Secondly, Connect to an Event in any Module`\n```lua\nlocal events = require(path.to.Events)\n\nevents.MorningTime:Connect(function(morningString: string)\n\tif morningString == \"Good Morning\" then\n\t\tprint(`{morningString}! It's a awesome day!`)\n\telseif morningString == \"Bad Morning\" then\n\t\tprint(`{morningString}! It's what we get when it rains!`)\n\tend\nend)\n\nevents.PlayerDamaged:Connect(function(player: Player, damage: number)\n\tprint(`{player.Name} took {damage} damage!`)\n\tplayerEffects:ShakeScreen() -- example function\n\tparticleSystem:BloodSplatter(player.Position) -- example function\nend)\n```\n`Lastly, Fire the Event Value in any Module`\n```lua\nlocal events = require(path.to.Events)\n\nevents.MorningTime:Fire(\"Good Morning\")\n\nwhile player:IsStandingInFire() do\n\tevents.PlayerDamaged:Fire(10)\nend\n```\n\n:::note\n\tObservers are client/server specific and cannot be shared between them.\n\tYou would need to create a separate observer for each side.\n\tOR create some sort of networked event system to communicate between them.\n:::",
    "source": {
        "line": 100,
        "path": "libraries/observer/Source/init.lua"
    }
}