### Create a Simple Matter System (Lua) Source: https://github.com/matter-ecs/matter/blob/main/docs/GettingStarted.md A basic example of a Matter system function. This system prints 'Hello world!' to the output, demonstrating how systems are defined and executed by the loop. ```lua local function myFirstSystem() print("Hello world!") end return myFirstSystem ``` -------------------------------- ### Build Matter-ECS Example Game Source: https://github.com/matter-ecs/matter/blob/main/example/README.md Instructions to build the 'Attack of the Killer Roombas' example game using Wally and Rojo. This involves installing dependencies and generating the Roblox place file. ```shell wally install rojo build example.project.json --output example.rbxl ``` -------------------------------- ### Initialize Matter World and Loop (Lua) Source: https://github.com/matter-ecs/matter/blob/main/docs/GettingStarted.md This snippet demonstrates how to import the Matter library and create a new World and Loop instance. The Loop is essential for managing the game's update cycle and passing the world to systems. ```lua local Matter = require(ReplicatedStorage.Matter) local world = Matter.World.new() local loop = Matter.Loop.new(world) -- This makes Loop pass the world to all your systems. ``` -------------------------------- ### Add Matter ECS Dependency to Wally Configuration (wally.toml) Source: https://github.com/matter-ecs/matter/blob/main/docs/Installation.md This snippet demonstrates adding the Matter ECS package as a dependency in the `wally.toml` file. It specifies the package name and version required for the project, ensuring Matter ECS is available for installation via Wally. ```toml [dependencies] matter = "matter-ecs/matter@0.8.4" ``` -------------------------------- ### Start Matter Game Loop (Lua) Source: https://github.com/matter-ecs/matter/blob/main/docs/GettingStarted.md Initiates the Matter game loop, binding it to the Heartbeat event from Roblox's RunService. This ensures that the scheduled systems will execute on every frame. ```lua loop:begin({ default = RunService.Heartbeat }) ``` -------------------------------- ### Schedule Systems in Matter.js (Lua) Source: https://github.com/matter-ecs/matter/blob/main/docs/GettingStarted.md This code collects all ModuleScript children from a 'systems' folder and schedules them to run within the Matter game loop. Systems are the core logic units in Matter.js. ```lua local systems = {} for _, child in ipairs(script.systems:GetChildren()) do if child:IsA("ModuleScript") then table.insert(systems, require(child)) end end loop:scheduleSystems(systems) ``` -------------------------------- ### Define Components for Matter.js (Lua) Source: https://github.com/matter-ecs/matter/blob/main/docs/GettingStarted.md This snippet shows how to define custom components using Matter.component(). Components are data containers that can be attached to entities within the Matter world. ```lua local Matter = require(ReplicatedStorage.Matter) return { Health = Matter.component(), Poison = Matter.component(), } ``` -------------------------------- ### Set Up Replication System and Remote Event Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/Replication.md Initializes the replication system by creating a RemoteEvent in ReplicatedStorage and preparing a list of component references for replication. ```lua local ReplicatedStorage = game:GetService("ReplicatedStorage") local RemoteEvent = Instance.new("RemoteEvent") RemoteEvent.Name = "MatterRemote" RemoteEvent.Parent = ReplicatedStorage local replicatedComponents = {} for _, name in REPLICATED_COMPONENTS do replicatedComponents[Components[name]] = true end local function replication(world) -- todo! end return { system = replication, priority = math.huge, } ``` -------------------------------- ### Add Wally Tool to Aftman Configuration (aftman.toml) Source: https://github.com/matter-ecs/matter/blob/main/docs/Installation.md This snippet shows how to configure the `aftman.toml` file to include the Wally package manager as a tool. It specifies the repository and version of Wally to be managed by Aftman, enabling its use in the project. ```toml [tools] wally = "UpliftGames/wally@x.x.x" ``` -------------------------------- ### Implement Poison Damage System (Lua) Source: https://github.com/matter-ecs/matter/blob/main/docs/GettingStarted.md This system iterates over entities that have both Health and Poison components, applying a damage-over-time effect. It uses the `Component:patch` method to create an updated component. ```lua local Components = require(script.Parent.components) local Health = Components.Health local Poison = Components.Poison local function poisonHurts(world) for id, health in world:query(Health, Poison) do world:insert(id, health:patch({ value = health.value - 0.1 })) end end ``` -------------------------------- ### Install Matter with Wally Source: https://github.com/matter-ecs/matter/blob/main/README.md Add Matter ECS as a dependency in your project's `wally.toml` file to install the library. ```toml Matter = "matter-ecs/matter@0.8.4" ``` -------------------------------- ### Matter Debugger: Initialize and Setup Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/MatterDebugger.md Provides the essential Lua code for initializing the Matter debugger and integrating it with the Matter Loop. It involves creating the debugger instance, obtaining widgets, and passing them to the Loop. ```lua local ReplicatedStorage = game:GetService("ReplicatedStorage") local Packages = ReplicatedStorage.Packages local Matter = require(Packages.matter) local Plasma = require(Packages.plasma) -- Create the debugger instance, passing the Plasma library local debugger = Matter.Debugger.new(Plasma) -- Get the widget collection to pass to systems local widgets = debugger:getWidgets() -- Initialize the Matter Loop, passing the widgets local loop = Matter.Loop.new(world, state, widgets) -- Automatically set up the Loop middleware to invoke the debugger each frame debugger:autoInitialize(loop) ``` -------------------------------- ### Install Rewire using Wally Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/HotReloading.md Add the Rewire library as a dependency in your project's `wally.toml` file to enable hot reloading functionality. ```TOML [dependencies] rewire = "sayhisam1/rewire@0.3.0" ``` -------------------------------- ### Matter ECS API References Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/Replication.md Key API methods and services used in the replication system for querying changes, managing entities, and handling player events. ```APIDOC World: queryChanged(component: Component): iterator - Returns an iterator over entities that have had the specified component changed since the last query. - Parameters: - component: The component type to track changes for. - Returns: - An iterator yielding entityId and a record containing 'old' and 'new' component data. contains(entityId: number): boolean - Checks if an entity with the given ID exists in the world. - Parameters: - entityId: The ID of the entity to check. - Returns: - true if the entity exists, false otherwise. __iter(): iterator - Allows iteration over all entities in the world. - Returns: - An iterator yielding entityId and a table of the entity's components. Players: - A Roblox service that provides access to player-related information and events. useEvent(service, eventName): iterator - A utility function to subscribe to and iterate over events from a service. - Parameters: - service: The service object (e.g., Players). - eventName: The name of the event to listen for (e.g., "PlayerAdded"). - Returns: - An iterator that yields arguments passed to the event. RemoteEvent: FireAllClients(payload: any) - Sends a payload to all connected clients. - Parameters: - payload: The data to send, must be serializable. FireClient(player: Player, payload: any) - Sends a payload to a specific client. - Parameters: - player: The target player object. - payload: The data to send, must be serializable. ``` -------------------------------- ### Replicate World State to New Players Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/Replication.md Handles late-joining players by iterating through the current world state and sending relevant component data for each entity to the new player. ```lua -- Also inside our replication function for _, player in useEvent(Players, "PlayerAdded") do local payload = {} for entityId, entityData in world do local entityPayload = {} for component, componentData in entityData do if replicatedComponents[component] then entityPayload[tostring(component)] = { data = componentData } end end payload[tostring(entityId)] = entityPayload end RemoteEvent:FireClient(player, payload) end ``` -------------------------------- ### Replicate Component Changes to Clients Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/Replication.md Detects changes in replicated components using `world:queryChanged` and buffers them into a payload to be sent to all clients via a RemoteEvent. ```lua -- In the replication function local changes = {} for component in replicatedComponents do for entityId, record in world:queryChanged(component) do local key = tostring(entityId) local name = tostring(component) if changes[key] == nil then changes[key] = {} end if world:contains(entityId) then changes[key][name] = { data = record.new } end end end if next(changes) then RemoteEvent:FireAllClients(changes) end ``` -------------------------------- ### Matter Debugger: Install Plasma Dependency with Wally Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/MatterDebugger.md Shows how to add the Plasma library, a dependency for the Matter debugger, to your project using Wally, the Roblox open-source package manager. ```toml [dependencies] plasma = "matter-ecs/plasma@0.4.2" ``` -------------------------------- ### Define Replicated Components Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/Replication.md Specifies which components should be replicated across the network. This list determines which component data is synchronized. ```lua local REPLICATED_COMPONENTS = { "Roomba", "Model", "Health", "Target", "Mothership", "Spinner", } ``` -------------------------------- ### Handle Server Entity Replication Updates Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/Replication.md This Lua code snippet demonstrates how a client receives and processes entity replication data sent from a server. It connects to a RemoteEvent to listen for updates, managing entity creation, component synchronization (adding/removing), and despawning based on server messages. It relies on ReplicatedStorage for event access and a 'world' object for entity manipulation. ```lua local ReplicatedStorage = game:GetService("ReplicatedStorage") local Components = require(ReplicatedStorage.Game.components) -- example -- Get our remote event that we created on the server local RemoteEvent = ReplicatedStorage:WaitForChild("MatterRemote") -- A lookup table from server entity IDs to client entity IDs. They're different! local entityIdMap = {} RemoteEvent.OnClientEvent:Connect(function(entities) -- entities is the data sent from the server. Either the `payload` or `changes` from earlier! -- Loop over the entities the server is replicating for serverEntityId, componentMap in entities do -- Check if we've created this entity on the client before local clientEntityId = entityIdMap[serverEntityId] -- If we've created this entity before, and there are no components inside its list, that means -- the entity was despawned on the server. We despawn it here too. if clientEntityId and next(componentMap) == nil then world:despawn(clientEntityId) -- Remove it from our lookup table entityIdMap[serverEntityId] = nil continue end local componentsToInsert = {} local componentsToRemove = {} -- Loop over all the components in the entity for name, container in componentMap do -- If container.data exists, the component was either changed or added. if container.data then table.insert(componentsToInsert, Components[name](container.data)) else -- if it doesn't exist, it was removed! table.insert(componentsToRemove, Components[name]) end end -- We haven't created this entity on the client before. create it. if clientEntityId == nil then clientEntityId = world:spawn(unpack(componentsToInsert)) -- add the client-side entity id to our lookup table entityIdMap[serverEntityId] = clientEntityId else -- we've seen this entity before. -- Just insert or remove any necessary components. if #componentsToInsert > 0 then world:insert(clientEntityId, unpack(componentsToInsert)) end if #componentsToRemove > 0 then world:remove(clientEntityId, unpack(componentsToRemove)) end end end end) ``` -------------------------------- ### Health Regeneration System Source: https://github.com/matter-ecs/matter/blob/main/docs/Concepts.md An example of a system that iterates over entities possessing the 'Health' component. It regenerates health for entities whose current health is below their maximum health, applying a small percentage increase per frame. ```luau for id, health in world:query(Health) do if health.current < health.max then world:insert(id, health:patch({ -- Regenerate 0.1% of maximum health per frame current = math.min(health.max, health.current + (health.max * 0.001)) }) end end ``` -------------------------------- ### Migrate to Matter ECS Scope Source: https://github.com/matter-ecs/matter/blob/main/README.md Update your `wally.toml` file to use the `matter-ecs/matter` scope for migrating from previous versions or scopes. ```toml Matter = "matter-ecs/matter@0.8.4" ``` -------------------------------- ### Create Model Instance for Ships Source: https://github.com/matter-ecs/matter/blob/main/docs/BestPractices/Reconciliation.md This system iterates through entities with a 'Ship' component but without a 'Model' component. It clones a ship prefab, parents it to the workspace, and inserts a 'Model' component referencing the created instance. ```lua for id, ship in world:query(Ship):without(Model) do local model = prefabs.Ship:Clone() -- assuming prefabs is a place where you store pre-made models model.Parent = workspace world:insert(id, Model({ instance = model })) end ``` -------------------------------- ### Initialize HotReloader Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/HotReloading.md Set up a new `HotReloader` instance in your game's initialization code, typically where your Matter `Loop` object is created. ```Lua local ReplicatedStorage = game:GetService("ReplicatedStorage") local Packages = ReplicatedStorage.Packages local HotReloader = require(Packages.rewire).HotReloader local hotReloader = HotReloader.new() ``` -------------------------------- ### Update wally.toml Dependency Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/Migration.md This snippet shows the required change in the `wally.toml` file to point to the new `matter-ecs/matter` package. It specifies the new dependency name and version. ```toml [dependencies]\nmatter = "matter-ecs/matter@0.8.4" ``` -------------------------------- ### Define Car Component Destinations Source: https://github.com/matter-ecs/matter/blob/main/docs/BestPractices/StateMachines.md Initializes a `Car` component with an array of `Vector3` destinations for navigation. This sets up the initial state for a car entity that will move through a series of points. ```Lua world:spawn(Car({ destinations = {Vector3.new(0, 0, 0), Vector3.new(10, 0, 5), Vector3.new(-5, 2, 3)} })) ``` -------------------------------- ### Lua: Avoid `return` in Query Loops, Use `continue` Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/CommonMistakes.md Demonstrates a common Lua error where `return` is used instead of `continue` within a `world:query` loop. Using `return` prematurely exits the entire system, while `continue` should be used to skip to the next iteration. This prevents unintended system termination and ensures all entities are processed. ```lua function mySystem(world) for id, health, poison in world:query(Health, Poison) do if not poison.active then return -- Oops! After reaching the first inactive poison, -- we're going to stop running the entire system! -- Should have used `continue` here. end world:insert(id, health:patch({ current = health.current - 1 })) end end ``` -------------------------------- ### Spawn Entity with Components Source: https://github.com/matter-ecs/matter/blob/main/docs/Concepts.md Demonstrates how to create a new entity within the Matter World and attach multiple components to it simultaneously. Returns the unique identifier for the newly spawned entity. ```lua local newEntityId = world:spawn( Enemy(), Health({ current = 100, max = 100, }), Name({ name = "Evil Tree" }), Tree({ type = "oak" }) ) ``` -------------------------------- ### Matter ECS: Correctly Using Updated Component Reference Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/CommonMistakes.md Demonstrates the correct pattern in Matter ECS for updating immutable components. It shows how to reassign the component variable to the patched value before inserting it, ensuring subsequent logic uses the updated data. ```lua local health = world:get(id, Health) health = health:patch({ current = health.current - 10 }) world:insert(id, health) if health.current < 0 then -- ... end ``` -------------------------------- ### Implement Car Component Driving and Waiting Modes Source: https://github.com/matter-ecs/matter/blob/main/docs/BestPractices/StateMachines.md Extends the car navigation system by introducing a `mode` property to the `Car` component, allowing for 'driving' and 'waiting' states. The system handles transitions between these modes, including a timed wait at destinations. ```Lua world:spawn(Car({ destinations = {Vector3.new(0, 0, 0), Vector3.new(10, 0, 5), Vector3.new(-5, 2, 3)}, mode = "driving" })) ----- for id, car, model in world:query(Car, Model) do if car.mode == "waiting" then if os.clock() - car.startedWaiting > 5 then -- Wait 5 seconds world:insert(id, car:patch({ mode = "driving", startedWaiting = Matter.None })) end elseif car.mode == "driving" then if #car.destinations == 0 then world:despawn(id) continue end local currentPosition = model.model.PrimaryPart.Position if (currentPosition - car.destinations[1]).magnitude < 2 then -- Arrived table.remove(car.destinations, 1) world:insert(id, car:patch({ mode = "waiting", startedWaiting = os.clock() })) continue end model.model.PrimaryPart.BodyPosition.Position = car.destinations[1] --example end end ``` -------------------------------- ### Matter World API Methods Source: https://github.com/matter-ecs/matter/blob/main/docs/Concepts.md Provides a reference for core methods available on the Matter World object, used for managing entities and their components. These methods facilitate entity creation, component manipulation, and querying. ```APIDOC World: spawn(component1, component2, ...) - Spawns a new entity with the provided components. - Parameters: - component1, component2, ...: Instances of components to attach to the new entity. - Returns: The unique numeric ID of the newly created entity. insert(entityId, component) - Adds a new component to an existing entity or replaces an existing component of the same type. - Parameters: - entityId: The numeric ID of the entity. - component: The component instance to insert. get(entityId, componentType) - Retrieves a specific component instance from an entity. - Parameters: - entityId: The numeric ID of the entity. - componentType: The class/type of the component to retrieve. - Returns: The component instance, or nil if not found. remove(entityId, componentType) - Removes a specific component from an entity. - Parameters: - entityId: The numeric ID of the entity. - componentType: The class/type of the component to remove. despawn(entityId) - Removes an entity and all its associated components from the world. - Parameters: - entityId: The numeric ID of the entity to despawn. contains(entityId) - Checks if an entity with the given ID still exists in the world. - Parameters: - entityId: The numeric ID of the entity to check. - Returns: true if the entity exists, false otherwise. query(componentType1, componentType2, ...) - Returns an iterator that yields entities and their specified components. Only entities possessing all specified component types are returned. - Parameters: - componentType1, componentType2, ...: The types of components to query for. - Returns: An iterator yielding pairs of (entityId, component1, component2, ...). ``` -------------------------------- ### Matter Debugger: Toggle Keybind Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/MatterDebugger.md Configures a keybind (F4) to toggle the Matter debugger's visibility. This allows users to easily open and close the debugger during gameplay. ```lua local UserInputService = game:GetService("UserInputService") -- Connect to the InputBegan event to detect key presses UserInputService.InputBegan:Connect(function(input) if input.KeyCode == Enum.KeyCode.F4 then -- Toggle the debugger's visibility debugger:toggle() end end) ``` -------------------------------- ### Drive Car Component to Destinations Source: https://github.com/matter-ecs/matter/blob/main/docs/BestPractices/StateMachines.md System logic to process `Car` components. It queries for `Car` and `Model` components, moves the car towards its current destination, and removes the destination upon arrival. If no destinations remain, the entity is despawned. ```Lua for id, car, model in world:query(Car, Model) do local currentPosition = model.model.PrimaryPart.Position if (currentPosition - car.destinations[1]).magnitude < 2 then -- Arrived table.remove(car.destinations, 1) if #car.destinations == 0 then world:despawn(id) continue end end model.model.PrimaryPart.BodyPosition.Position = car.destinations[1] --example end ``` -------------------------------- ### Matter Debugger: Entity Highlight - findInstanceFromEntity Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/MatterDebugger.md Configures the debugger to highlight selected entities in the World inspector by providing a function to find the corresponding Roblox instance. This requires mapping entity IDs to their visual representations in the game. ```lua -- Set the findInstanceFromEntity function for the debugger debugger.findInstanceFromEntity = function(id) -- Check if the entity exists in the world if not world:contains(id) then return end -- Retrieve the Model component for the entity local model = world:get(id, components.Model) -- Return the instance if found, otherwise nil return model and model.model or nil end ``` -------------------------------- ### Bind CollectionService Tags to ECS Components in Lua Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/CollectionService.md This Lua script demonstrates how to bind Roblox's CollectionService tags to ECS components within the Matter ECS framework. It iterates through instances tagged in Roblox, spawns corresponding ECS entities with specified components, and handles dynamic tag additions and removals by updating ECS entities. Dependencies include Roblox's CollectionService and custom Components modules. ```lua local CollectionService = game:GetService("CollectionService") local ReplicatedStorage = game:GetService("ReplicatedStorage") local Components = require(ReplicatedStorage.Game.components) local boundTags = { Spinner = Components.Spinner, } local function setupTags(world) local function spawnBound(instance, component) local id = world:spawn( component(), Components.Model({ model = instance, }), Components.Transform({ cframe = instance.PrimaryPart.CFrame, }) ) instance:SetAttribute("entityId", id) end for tagName, component in pairs(boundTags) do for _, instance in ipairs(CollectionService:GetTagged(tagName)) do spawnBound(instance, component) end CollectionService:GetInstanceAddedSignal(tagName):Connect(function(instance) spawnBound(instance, component) end) CollectionService:GetInstanceRemovedSignal(tagName):Connect(function(instance) local id = instance:GetAttribute("entityId") if id then world:despawn(id) end end) end end return setupTags ``` -------------------------------- ### Matter Debugger API: Widget Reference Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/MatterDebugger.md Lists the available Plasma widgets that can be used within Matter ECS systems for creating debug UIs. Each widget serves a specific purpose for displaying information or capturing user input. ```apidoc Plasma Widgets: - arrow: 3D Arrow gizmo for debugging Vector math. - blur: Blurs the camera background. - button: Creates a clickable button. - checkbox: Creates a toggleable checkbox. - heading: Displays a section heading. - label: Displays plain text. - portal: Inserts instances into a different frame than the provided one. - row: Lays out elements horizontally. - slider: Creates a draggable slider for value selection. - space: Inserts empty space for layout. - spinner: Displays a loading spinner. - table: Displays data in a tabular format. - window: Creates a resizable and draggable window container. For detailed usage and parameters of each widget, refer to the [Plasma API documentation](https://matter-ecs.github.io/plasma/api/Plasma). ``` -------------------------------- ### Despawn Ship on Touch Event Source: https://github.com/matter-ecs/matter/blob/main/docs/BestPractices/Reconciliation.md This system uses Matter's `useEvent` utility to listen for the 'Touched' event on a ship's instance. When the event fires, it despawns the corresponding entity from the ECS world. ```lua for id, model in world:query(Model, Ship) do for _ in Matter.useEvent(model.Instance, "Touched") do world:despawn(id) end end ``` -------------------------------- ### Matter ECS: Prevent Early Returns Affecting Topologically-Aware State Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/CommonMistakes.md Explains how early returns in Matter ECS systems can disrupt topologically-aware functions like `useEvent` or `World:queryChanged`. These functions rely on consistent call sites to maintain state. Unintentional cleanup can cause `queryChanged` to re-process all entities as new, leading to unexpected behavior. ```lua function mySystem() if useThrottle(1) then for id, health in world:queryChanged(Health) do -- Uh oh! Every time this runs, *every* health component will be looped over. -- The for loop runs only once per second, which means that on next frame where this code -- isn't reached, the storage for queryChanged is cleaned up. end end end ``` -------------------------------- ### Scan Systems for Hot Reloading Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/HotReloading.md Configure the `HotReloader` to monitor a specific container for system modules. It takes callback functions for when systems are loaded and unloaded, handling system updates within the Matter loop. ```Lua local firstRunSystems = {} local systemsByModule = {} hotReloader:scan(container, function(module, context) -- The module HotReloader gives us can be a clone of the original module if it's been hot reloaded. local originalModule = context.originalModule -- Load the cloned module. If it has syntax errors, require will error. local ok, system = pcall(require, module) if not ok then warn("Error when hot-reloading system", module.name, system) return end if firstRunSystems then -- On the first run, we want to schedule all systems in one call, -- so we buffer them up and call one big `loop:scheduleSystems` at the end. table.insert(firstRunSystems, system) elseif systemsByModule[originalModule] then -- If this system was already loaded once before, we tell the loop to replace it. loop:replaceSystem(systemsByModule[originalModule], system) -- If you're also using the Matter debugger, tell the debugger the system was reloaded. -- debugger:replaceSystem(systemsByModule[originalModule], system) else -- If this is a new system (i.e., a new module was created during a hot reload), just schedule it. loop:scheduleSystem(system) end -- Keep a reference to the system, keyed by the original module, so we can detect if the system already existed -- or not systemsByModule[originalModule] = system end, function(_, context) -- This function runs when a system is being unloaded. -- context.isReloading is true if the system is about to be hot reloaded. Otherwise, it's been removed. -- If it's being hot reloaded, do nothing if context.isReloading then return end -- The system is being removed local originalModule = context.originalModule if systemsByModule[originalModule] then -- If the system was loaded, remove it from the loop loop:evictSystem(systemsByModule[originalModule]) systemsByModule[originalModule] = nil end end) ``` -------------------------------- ### Matter Debugger: Entity Highlight - Hover Selection Attributes Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/MatterDebugger.md Enables in-world hover selection by setting client-specific and server-specific attributes on instances. When holding ALT, hovering over an instance with these attributes will select the corresponding entity in the debugger. ```lua local name = RunService:IsServer() and "serverEntityId" or "clientEntityId" -- System to update entity ID attributes on Model components local function updateModelAttribute(world) -- Query for changed Model components for id, record in world:queryChanged(Components.Model) do -- If the component was added or updated if record.new then -- Set the appropriate attribute (clientEntityId or serverEntityId) with the entity ID record.new.model:SetAttribute(name, id) end end end ``` -------------------------------- ### Matter ECS: Incorrectly Using Stale Component Reference Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/CommonMistakes.md Illustrates a common mistake in Matter ECS where a component is updated via `patch` and `insert`, but the old, stale reference is used afterward, leading to incorrect logic. ```lua local health = world:get(id, Health) world:insert(id, health:patch({ current = health.current - 10 })) if health.current < 0 then -- ... end ``` -------------------------------- ### Update Model Instance Position Source: https://github.com/matter-ecs/matter/blob/main/docs/BestPractices/Reconciliation.md This system synchronizes the position of the physical ship instance in the DataModel with the 'goalPosition' defined in the 'Ship' component. It requires entities to have both 'Ship' and 'Model' components. ```lua for id, ship, model in world:query(Ship, Model) do model.instance.BodyPosition.Position = ship.goalPosition end ``` -------------------------------- ### Calculate Player Walk Speed Based on Components (Lua) Source: https://github.com/matter-ecs/matter/blob/main/docs/BestPractices/DerivedState.md Calculates a player's walk speed by querying for components that influence it, such as 'Poison' or 'HeavyWeapon'. It iterates through entities with the 'Player' component, determines speed modifiers, and inserts a 'WalkSpeed' component. The code emphasizes careful iteration over query results to handle potential nil values. ```lua local affectsWalkSpeed = {Poison, HeavyWeapon} local function walkSpeed(world) for id, player in world:query(Player) do local results = {world:get(id, unpack(affectsWalkSpeed))} -- NOTE: You can't be tricky by just checking the length of this table! -- We MUST iterate over it because the Lua length operator does not work as you might expect when a table has nil values in it. -- See for yourself: Lua says #{nil,nil,nil,1,nil} is 0! local modifier = 1 for _ in results do -- For each result, reduce speed by half. modifier *= 0.5 end -- The default Roblox walk speed is 16 local speed = 16 * modifier world:insert(id, WalkSpeed({ speed = speed, modifier = modifier, })) end end return walkSpeed ``` -------------------------------- ### Matter Debugger: Create Debug UI Elements in Lua Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/MatterDebugger.md Demonstrates how to use Plasma widgets within a Matter ECS system to create interactive debug UI elements like checkboxes and sliders. These widgets are only active when the debugger is open, making it safe to leave calls in production code. ```lua local function spinSpinners(world, _, ui) -- ui parameter provides access to Plasma widgets if ui.checkbox("Disable Spinning"):checked() then return end local transparency = ui.slider(1) -- Creates a slider widget with a default value of 1 local randomize = ui.button("Randomize colors!"):clicked() -- Creates a button widget -- Iterates through entities with Model and Spinner components for id, model in world:query(Components.Model, Components.Spinner) do model.model.PrimaryPart.Transparency = transparency if randomize then model.model.PrimaryPart.BrickColor = BrickColor.random() end end end ``` -------------------------------- ### Update Transforms Source: https://github.com/matter-ecs/matter/blob/main/docs/BestPractices/Reconciliation.md This Lua script synchronizes Transform components with Model instances. It updates Model instances when Transform components change and updates Transform components when unanchored Model instances move due to physics. This ensures consistency between the component state and the game world state. ```lua -- Handle Transform added/changed to existing entity with Model for id, transformRecord in world:queryChanged(Transform) do local model = world:get(id, Model) -- Take care to ignore the changed event if it was us that triggered it if model and transformRecord.new and not transformRecord.new.doNotReconcile then model.instance:SetPrimaryPartCFrame(transformRecord.new.cframe) end end -- Handle Model added/changed on existing entity with Transform for id, modelRecord in world:queryChanged(Model) do local transform = world:get(id, Transform) if transform and modelRecord.new then modelRecord.new.model:SetPrimaryPartCFrame(transform.cframe) end end -- Update Transform on unanchored Models for id, model, transform in world:query(Model, Transform) do if model.instance.PrimaryPart.Anchored then continue end local existingCFrame = transform.cframe local currentCFrame = model.instance.PrimaryPart.CFrame -- Only insert if actual position is different from the Transform component if currentCFrame ~= existingCFrame then world:insert( id, Components.Transform({ cframe = currentCFrame, doNotReconcile = true, }) ) end end ``` -------------------------------- ### Matter Debugger: Server-Side Authorization Source: https://github.com/matter-ecs/matter/blob/main/docs/Guides/MatterDebugger.md Defines an authorization function for the server-side debugger. This function determines which players are allowed to connect to the debugger in live games, preventing unauthorized access. ```lua -- Assign an authorize function to the debugger debugger.authorize = function(player) -- Example: Allow players with rank > 250 in group ID 372 if player:GetRankInGroup(372) > 250 then return true end -- By default, return false if the condition is not met return false end ``` -------------------------------- ### GetComponentFromEntity Source: https://github.com/matter-ecs/matter/blob/main/docs/Concepts.md Retrieves a specific component attached to an entity from the Matter World. This allows access to the data associated with that component for a given entity ID. ```lua local nameComponent = world:get(newEntityId, Name) print(nameComponent.name) ``` -------------------------------- ### Remove Models Source: https://github.com/matter-ecs/matter/blob/main/docs/BestPractices/Reconciliation.md This Lua script iterates through all Model components in the world. If a Model's instance is no longer a descendant of the game, it removes the Model component from the entity. This handles cases where instances are destroyed by external factors like physics, preventing orphaned components. ```lua for id, model in world:query(Model) do if model.instance:IsDescendantOf(game) == false then world:remove(id, Model) end end ``` -------------------------------- ### Update Humanoid Walk Speed from Component (Lua) Source: https://github.com/matter-ecs/matter/blob/main/docs/BestPractices/DerivedState.md Applies the calculated walk speed to a game entity's model, specifically targeting Roblox Humanoids. This snippet queries for entities possessing both a 'WalkSpeed' component and a 'Model' component, then updates the 'Humanoid.WalkSpeed' property if a Humanoid is found within the model. ```lua -- Update anything with WalkSpeed and Model (this could be a separate system) for id, walkSpeed, model in world:query(WalkSpeed, Model) do if model.model:FindFirstChild("Humanoid") then model.model.Humanoid.WalkSpeed = walkSpeed.speed end end ``` -------------------------------- ### Remove Model Instances on Component Removal Source: https://github.com/matter-ecs/matter/blob/main/docs/BestPractices/Reconciliation.md This system detects when a 'Model' component is removed from an entity. If the component had an associated instance, it destroys that instance in the DataModel to prevent orphaned objects. ```lua for _id, modelRecord in world:queryChanged(Model) do if modelRecord.new == nil then if modelRecord.old and modelRecord.old.instance then modelRecord.old.instance:Destroy() end end end ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.