Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion example/src/client/systems/roombasHurt.luau
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ local Matter = require(ReplicatedStorage.Lib.Matter)

local function roombasHurt(world)
for _, _, model in world:query(Components.Roomba, Components.Model) do
for _, part in Matter.useEvent(model.model.PrimaryPart, "Touched") do
for _, part in Matter.useEvent(model.PrimaryPart, "Touched") do
local touchedModel = part:FindFirstAncestorWhichIsA("Model")
if not touchedModel then
continue
Expand Down
6 changes: 3 additions & 3 deletions example/src/client/systems/spinSpinners.luau
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ local function spinSpinners(world, _, ui)
local randomize = ui.button("Randomize colors!"):clicked()

for _, model in world:query(Components.Model, Components.Spinner) do
model.model.PrimaryPart.CFrame = model.model.PrimaryPart.CFrame * CFrame.Angles(0, math.rad(5), 0)
model.model.PrimaryPart.Transparency = transparency
model.PrimaryPart.CFrame = model.PrimaryPart.CFrame * CFrame.Angles(0, math.rad(5), 0)
model.PrimaryPart.Transparency = transparency

if randomize then
model.model.PrimaryPart.BrickColor = BrickColor.random()
model.PrimaryPart.BrickColor = BrickColor.random()
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion example/src/server/systems/mothershipsSpawnRoombas.luau
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ local function mothershipsSpawnRoombas(world)
for id, model, lasering, transform in
world:query(Components.Model, Components.Lasering, Components.Transform, Components.Mothership)
do
model.model.Beam.Transparency = 1 - lasering.remainingTime
model.Beam.Transparency = 1 - lasering.remainingTime

lasering = lasering:patch({
remainingTime = lasering.remainingTime - Matter.useDeltaTime(),
Expand Down
7 changes: 1 addition & 6 deletions example/src/server/systems/playersAreTargets.luau
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,7 @@ local Matter = require(ReplicatedStorage.Lib.Matter)
local function playersAreTargets(world)
for _, player in ipairs(Players:GetPlayers()) do
for _, character in Matter.useEvent(player, "CharacterAdded") do
world:spawn(
Components.Target(),
Components.Model({
model = character,
})
)
world:spawn(Components.Target(), Components.Model(character))
end
end

Expand Down
10 changes: 5 additions & 5 deletions example/src/server/systems/removeMissingModels.luau
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ local Matter = require(ReplicatedStorage.Lib.Matter)

local function removeMissingModels(world)
for id, model in world:query(Components.Model) do
for _ in Matter.useEvent(model.model, "AncestryChanged") do
if model.model:IsDescendantOf(game) == false then
for _ in Matter.useEvent(model, "AncestryChanged") do
if model:IsDescendantOf(game) == false then
world:remove(id, Components.Model)
break
end
end
if not model.model.PrimaryPart then
if not model.PrimaryPart then
world:remove(id, Components.Model)
end
end

for _id, modelRecord in world:queryChanged(Components.Model) do
if modelRecord.new == nil then
if modelRecord.old and modelRecord.old.model then
modelRecord.old.model:Destroy()
if modelRecord.old then
modelRecord.old:Destroy()
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions example/src/server/systems/roombasMove.luau
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ local Components = require(ReplicatedStorage.Shared.components)
local function roombasMove(world)
local targets = {}
for _, model in world:query(Components.Model, Components.Target) do
table.insert(targets, model.model.PrimaryPart.CFrame.p)
table.insert(targets, model.PrimaryPart.CFrame.p)
end

for _, _, charge, model in world:query(Components.Roomba, Components.Charge, Components.Model) do
Expand All @@ -13,7 +13,7 @@ local function roombasMove(world)
end

local closestPosition, closestDistance
local currentPosition = model.model.PrimaryPart.CFrame.p
local currentPosition = model.PrimaryPart.CFrame.p

for _, target in ipairs(targets) do
local distance = (currentPosition - target).magnitude
Expand All @@ -24,7 +24,7 @@ local function roombasMove(world)
end

if closestPosition then
local body = model.model.Roomba
local body = model.Roomba
local force = body:GetMass() * 20

if closestDistance < 4 then
Expand Down
9 changes: 2 additions & 7 deletions example/src/server/systems/spawnMotherships.luau
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,7 @@ local function spawnMotherships(world)
model.Parent = workspace
model.PrimaryPart:SetNetworkOwner(nil)

world:insert(
id,
Components.Model({
model = model,
})
)
world:insert(id, Components.Model(model))
end

for id, mothership, transform in
Expand All @@ -58,7 +53,7 @@ local function spawnMotherships(world)
end

for _, mothership, model in world:query(Components.Mothership, Components.Model):without(Components.Lasering) do
model.model.Roomba.AlignPosition.Position = mothership.goal
model.Roomba.AlignPosition.Position = mothership.goal
end
end

Expand Down
7 changes: 1 addition & 6 deletions example/src/server/systems/spawnRoombas.luau
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,7 @@ local function spawnRoombas(world)
model.Parent = workspace
model.PrimaryPart:SetNetworkOwner(nil)

world:insert(
id,
Components.Model({
model = model,
})
)
world:insert(id, Components.Model(model))
end
end

Expand Down
8 changes: 4 additions & 4 deletions example/src/server/systems/updateTransforms.luau
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ local function updateTransforms(world)
end

if transformRecord.new and not transformRecord.new.doNotReconcile then
model.model:SetPrimaryPartCFrame(transformRecord.new.cframe)
model:SetPrimaryPartCFrame(transformRecord.new.cframe)
end
end

Expand All @@ -33,18 +33,18 @@ local function updateTransforms(world)
end

if modelRecord.new then
modelRecord.new.model:SetPrimaryPartCFrame(transform.cframe)
modelRecord.new:SetPrimaryPartCFrame(transform.cframe)
end
end

-- Update Transform on unanchored Models
for id, model, transform in world:query(Components.Model, Components.Transform) do
if model.model.PrimaryPart.Anchored then
if model.PrimaryPart.Anchored then
continue
end

local existingCFrame = transform.cframe
local currentCFrame = model.model.PrimaryPart.CFrame
local currentCFrame = model.PrimaryPart.CFrame

-- Despawn models that fall into the void
if currentCFrame.Y < -400 then
Expand Down
4 changes: 1 addition & 3 deletions example/src/shared/setupTags.luau
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ local function setupTags(world)
local function spawnBound(instance, component)
local id = world:spawn(
component(),
Components.Model({
model = instance,
}),
Components.Model(instance),
Components.Transform({
cframe = instance.PrimaryPart.CFrame,
})
Expand Down
3 changes: 1 addition & 2 deletions example/src/shared/start.luau
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ local function start(containers)
end

local model = world:get(id, components.Model)

return model and model.model or nil
return model
end

local loop = Matter.Loop.new(world, state, debugger:getWidgets())
Expand Down
2 changes: 1 addition & 1 deletion example/src/shared/systems/updateModelAttribute.luau
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ local name = RunService:IsServer() and "serverEntityId" or "clientEntityId"
local function updateModelAttribute(world)
for id, record in world:queryChanged(Components.Model) do
if record.new then
record.new.model:SetAttribute(name, id)
record.new:SetAttribute(name, id)
end
end
end
Expand Down
59 changes: 35 additions & 24 deletions lib/component.luau → lib/Component.luau
Original file line number Diff line number Diff line change
Expand Up @@ -43,28 +43,34 @@ local merge = require(script.Parent.immutable).merge
-- This is a special value we set inside the component's metatable that will allow us to detect when
-- a Component is accidentally inserted as a Component Instance.
-- It should not be accessible through indexing into a component instance directly.
local DIAGNOSTIC_COMPONENT_MARKER = {}
local DIAGNOSTIC_COMPONENT_MARKER = table.freeze({})

-- This tells the World whether the component should be unwrapped on insertion.
local PRIMITIVE_MARKER = table.freeze({})

local lastId = 0
local function newComponent(name, defaultData)
local function new(name: string, defaultData)
name = name or debug.info(2, "s") .. "@" .. debug.info(2, "l")

assert(
defaultData == nil or type(defaultData) == "table",
"if component default data is specified, it must be a table"
)
local ComponentInstance = {}
Comment thread
memorycode marked this conversation as resolved.
Outdated
ComponentInstance.__index = ComponentInstance

local component = {}
component.__index = component
function ComponentInstance.new(data)
-- If we aren't passed data, then we use the default data.
-- If no default data is provided, we want to default a table.
data = if data == nil then defaultData or {} else data

function component.new(data)
data = data or {}
local component = getmetatable(ComponentInstance :: any)
if typeof(data) == "table" then
if defaultData then
data = merge(defaultData, data)
end

if defaultData then
data = merge(defaultData, data)
return table.freeze(setmetatable(data, ComponentInstance))
else
component[PRIMITIVE_MARKER] = true
return table.freeze(setmetatable({ data = data, [PRIMITIVE_MARKER] = true }, ComponentInstance))
Comment thread
memorycode marked this conversation as resolved.
Outdated
end

return table.freeze(setmetatable(data, component))
end

--[=[
Expand Down Expand Up @@ -96,29 +102,29 @@ local function newComponent(name, defaultData)
@param partialNewData {} -- The table to be merged with the existing component data.
@return ComponentInstance -- A copy of the component instance with values from `partialNewData` overriding existing values.
]=]
function component:patch(partialNewData)
debug.profilebegin("patch")
local patch = getmetatable(self).new(merge(self, partialNewData))
debug.profileend()
return patch
function ComponentInstance:patch(partialNewData)
return getmetatable(self).new(merge(self, partialNewData))
end

lastId += 1
local id = lastId
setmetatable(component, {
setmetatable(ComponentInstance, {
__call = function(_, ...)
return component.new(...)
return ComponentInstance.new(...)
end,

__tostring = function()
return name
end,

__len = function()
return id
end,

[DIAGNOSTIC_COMPONENT_MARKER] = true,
})

return component
return ComponentInstance
end

local function assertValidType(value, position)
Expand All @@ -137,7 +143,6 @@ local function assertValidComponent(value, position)
assertValidType(value, position)

local metatable = getmetatable(value)

if getmetatable(metatable) ~= nil and getmetatable(metatable)[DIAGNOSTIC_COMPONENT_MARKER] then
error(
string.format(
Expand Down Expand Up @@ -177,10 +182,16 @@ local function assertComponentArgsProvided(...)
end
end

local function isPrimitive(componentInstance)
return componentInstance[PRIMITIVE_MARKER] ~= nil
end

return {
newComponent = newComponent,
new = new,
assertValidComponentInstance = assertValidComponentInstance,
assertValidComponentInstances = assertValidComponentInstances,
assertComponentArgsProvided = assertComponentArgsProvided,
assertValidComponent = assertValidComponent,

isPrimitive = isPrimitive,
}
22 changes: 13 additions & 9 deletions lib/World.luau
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
--!optimize 2

local Archetype = require(script.Parent.Archetype)
local Component = require(script.Parent.component)
local Component = require(script.Parent.Component)
local topoRuntime = require(script.Parent.topoRuntime)

local assertValidComponentInstances = Component.assertValidComponentInstances
Expand Down Expand Up @@ -244,10 +244,12 @@ local function executeDespawn(world: World, despawnCommand: DespawnCommand)
local archetype = entityRecord.archetype

-- Track changes
for _, componentStorage in archetype.fields do
local componentInstance = componentStorage[entityRecord.indexInArchetype]
local component = getmetatable(componentInstance :: any)
world:_trackChanged(component, entityId, componentInstance, nil)
for index, componentStorage in archetype.fields do
local data = componentStorage[entityRecord.indexInArchetype]
local componentId = archetype.indexToId[index]
local component = world.componentIdToComponent[componentId]

world:_trackChanged(component, entityId, data, nil)
end

-- TODO:
Expand All @@ -268,6 +270,9 @@ local function executeInsert(world: World, insertCommand: InsertCommand)

local oldArchetype = entityRecord.archetype
for _, componentInstance in componentInstances do
local isPrimitive = Component.isPrimitive(componentInstance)
local data = if isPrimitive then componentInstance.data else componentInstance

local component = getmetatable(componentInstance)
local componentId = #component
local componentIds = table.clone(oldArchetype.componentIds)
Expand All @@ -281,17 +286,16 @@ local function executeInsert(world: World, insertCommand: InsertCommand)
entityIndex = transitionArchetype(world, entityId, entityRecord, archetype)
oldComponentInstance = archetype.fields[archetype.idToIndex[componentId]][entityIndex]

-- FIXME:
-- This shouldn't be in a hotpath, probably better in createArchetype
-- FIXME: This shouldn't be in a hotpath, probably better in createArchetype
world.componentIdToComponent[componentId] = component
else
archetype = oldArchetype
entityIndex = entityRecord.indexInArchetype
oldComponentInstance = oldArchetype.fields[oldArchetype.idToIndex[componentId]][entityIndex]
end

archetype.fields[archetype.idToIndex[componentId]][entityIndex] = componentInstance
world:_trackChanged(component, entityId, oldComponentInstance, componentInstance)
archetype.fields[archetype.idToIndex[componentId]][entityIndex] = data
world:_trackChanged(component, entityId, oldComponentInstance, data)

oldArchetype = archetype
end
Expand Down
Loading