Skip to content

Matter v0.9.0-beta.0

Pre-release
Pre-release
Compare
Choose a tag to compare
@LastTalon LastTalon released this 15 Nov 22:52
· 4 commits to main since this release
v0.9.0-beta.0
6f39460

We’re excited to announce the beta release of Matter v0.9.0-beta.0! This release introduces powerful new features, significant performance improvements, and some breaking changes to pave the way for a smoother developer experience and a more robust system overall. We’ve also deprecated old functionality, giving you time to transition your code before these features are fully removed in future versions.

This beta release is designed for testing in real-world projects. Your feedback is critical to ensuring the stability and usability of these changes before the final release. Be sure to read the migration guide below for detailed instructions on updating your code.


What is a beta release?

Beta releases allow developers to try out new features and changes before they’re finalized. v0.9.0-beta.0 is a pre-release version, meaning it includes features, including breaking changes, for the next update but may still have bugs or edge cases that need refinement.

To use this beta release, you’ll need to explicitly specify the beta version in your project’s dependencies (e.g., Matter = "matter-ecs/matter@0.9.0-beta.0"). This ensures that your v0.8 and earlier projects don’t unintentionally pick up experimental changes.

Why use the beta?

  • Access new features and performance improvements early.
  • Help identify bugs or issues in your specific workflows.
  • Influence the final version by providing feedback.

Your feedback directly shapes the quality of the final release. Please report any bugs or concerns you encounter while using the beta.


Highlights of this release

Added

  • A new Loop:setWorlds({ World }) method which simplifies managing worlds in the Loop.
  • A new deferred command mode for the registry which prevents iterator invalidation and optimizes command handling. This is now the default for Loop.
  • Debugger enhancements:
    • Nested worlds within Loop are now fully supported.
    • Systems can be sorted by run time for better performance profiling.

Changed

  • A breaking change: the Loop now requires a call to setWorlds before it can be used. The Debugger inherits this requirement.
  • Significant Performance Improvements:
    • Queries now run 7.5-15x faster thanks to a reworked storage layout.
    • Archetypes are now more cache-friendly.
  • System names in Loop are now cached, reducing overhead from debug.info.

Deprecated

  • World:remove() return values no longer reliably indicate component removal status.
  • World:optimizeQueries() has been deprecated as it no longer serves a purpose thanks to new storage changes.

Fixed

  • Resolved an issue where archetypes were skipped in queries.
  • Fixed World:queryChanged incorrectly omitting entities.

For more details, view the full changelog, or check out our documentation.


Migrating

Update your Loop initialization

Loop now requires a setWorlds({ World }) call before use. Update your setup code as follows:

Before:

local world = World.new()
local debugger = Debugger.new(Plasma)
local loop = Loop.new(world)

-- World is naively inferred from the loop parameter.

debugger:autoInitialize(loop)
loop:begin({
	default = RunService.Heartbeat,
})

After:

local world = World.new()
local debugger = Debugger.new(Plasma)
local loop = Loop.new(world)

-- World is explicitly set.
loop:setWorlds({ world })

debugger:autoInitialize(loop)
loop:begin({
	default = RunService.Heartbeat,
})

See the docs for more information.

Review deprecated methods

  • Replace any reliance on the return value of World:remove().
    • If the return value is necessary you can call World:get() immediately before World:remove(), but keep in mind that this can still be misleading with command buffering (be sure to understand carefully how buffering affects what is currently in the world and what will change later).
  • Potentially remove calls to World:optimizeQueries().
    • This can be done at a later time since it's now a no-op.

Prepare for deferred command mode

The registry now defaults to deferred command mode. This change is usually seamless but ensure your workflows don’t rely on immediate command execution.

The command buffering fundamentally changes how your actions interact with the underlying world data structure. This can result in different or unexpected behavior, particularly for edge cases involving entity lifecycle management, deferred commands, and query assumptions.

Why this change affects queries

The new deferred mode may:

  • Change the order in which entities are returned by queries.
  • Modify the visibility of entities in queries.
  • Surface subtle bugs in query logic that relied on undocumented or implicit behaviors.

For example, queries that previously assumed a consistent order across iterations or relied on immediate execution of commands (e.g., insert, remove) may exhibit unexpected results.

Example: Deferred command mode batches modifications to entities and flushes them between systems. This means entities created or modified during a system may not appear in queries until the next system call.

Before:

world:insert(entity, ComponentA)
for entity in world:query(ComponentA) do
    print(entity) -- Entity with ComponentA appears immediately
end

After:

world:insert(entity, ComponentA)
for entity in world:query(ComponentA) do
    print(entity) -- The entity won't appear yet
end

Solution: Adjust your expectations or use deferred-safe workflows. For example, if immediate visibility is required, flush the command buffer explicitly with world:commitCommands(). Alternatively, move the behavior to a system that runs after your current system (this is preferred for new systems, but may be cumbersome for existing systems).

world:insert(entity, ComponentA)
world:commitCommands()
for entity in world:query(ComponentA) do
    print(entity) -- Entity with ComponentA appears immediately again
end

Tips for testing systems and queries

With the new storage layout, archetype improvements, and command buffering your queries may exhibit different performance characteristics. Test critical code paths to verify and maximize performance gains.

  1. Validate Query Results: After updating, confirm that all queries return the expected results. Pay special attention to cases involving entity creation, deletion, or modification within the same frame.
  2. Check Deferred Command Dependencies: If your systems depend on immediate execution, use world:commitCommands() to apply changes early, but sparingly, to maintain performance.
  3. Profile Your Queries: Use the new runtime sorting feature in the Debugger to identify bottlenecks and ensure your queries are optimized for the new layout.
  4. Iterate on Small Datasets: Start with a reduced set of entities and components to verify correctness before scaling up.
  5. Handle Query Order Explicitly: Avoid assumptions about the natural order of query results. Use sorting or explicit filtering if order is critical.

How to provide feedback

Your input is invaluable to the final release of v0.9.0. Here’s how you can contribute:

  1. Report Bugs: Submit issues with detailed reproduction steps.
  2. Share Feedback: Tell us what you like and what could be improved.
  3. Test Use Cases: Try integrating the beta into your projects and let us know about any pain points.
  4. Get Involved: We welcome new contributors. Check our contribution guide or come talk to us.

Join the conversation in our GitHub issues or reach out through our discord server.

We can’t wait to hear your thoughts and see what you build with v0.9.0-beta.0!