Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 4 additions & 1 deletion .github/workflows/unit-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
uses: robinraju/release-downloader@v1.6
with:
repository: Roblox/luau
tag: "0.723"
tag: "0.735"
fileName: luau-ubuntu.zip
out-file-path: bin

Expand All @@ -23,3 +23,6 @@ jobs:

- name: Run unit tests
run: bin/luau test/tests.luau

- name: Run typechecking tests
run: bash test/typecheck/run.sh "$GITHUB_WORKSPACE/bin/luau-analyze"
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### Fixed

- Component type inference with Luau's new type solver. Components now use
`component<T>` and `read_component<T>`; mutating APIs such as `Registry:set()`
require `component<T>`, preventing incompatible values from being accepted.
See [PR #30](https://github.com/centau/ecr/pull/30) for details.
- Method `Registry:create(id)` causing an out of bounds buffer access if key was already in use with a different version.

---
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,17 @@ ECR is a Luau ECS library.
Read the [crash course](https://centau.github.io/ecr/tut/crash-course) for a
brief introduction to the library.

When using Luau's new type solver, declare components without constructors as
`ecr.component<<T>>()`.

## Code sample

```lua
local ecr = require(ecr)

-- define components
local Position = ecr.component() :: Vector3
local Velocity = ecr.component() :: Vector3
local Position = ecr.component<<Vector3>>()
local Velocity = ecr.component<<Vector3>>()

-- define a system
local function update_physics(world: ecr.Registry, dt: number)
Expand Down
8 changes: 4 additions & 4 deletions docs/api/Observer.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Excludes entities with the given components from the observer.
- **Type**

```lua
function Observer:exclude<T...>(components: ...unknown): Observer<T...>
function Observer:exclude<T...>(components: ...read_component<unknown>): Observer<T...>
```

- **Details**
Expand All @@ -32,7 +32,7 @@ Disconnects the observer, stopping any new changes from being tracked
- **Type**

```lua
function Observer:disconnect<T...>(): Observer<T...>
function Observer:disconnect(): Observer<T...>
```

The observer must be empty before it is disconnected.
Expand All @@ -50,7 +50,7 @@ Reconnects the Observer and allows it to track changes again.
- **Type**

```lua
function Observer:reconnect<T...>(): Observer<T...>
function Observer:reconnect(): Observer<T...>
```

--------------------------------------------------------------------------------
Expand All @@ -62,7 +62,7 @@ Clears all stored entities.
- **Type**

```lua
function Observer:clear<T...>(): Observer<T...>
function Observer:clear(): Observer<T...>
```

## Iteration
Expand Down
69 changes: 47 additions & 22 deletions docs/api/Registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,18 @@ Checks if the given entity exists in the registry.

### add()

Adds all given components to an entity.
Adds a component to an entity using its constructor.

- **Type**

```lua
function Registry:add<T...>(id: entity, components: T...)
function Registry:add<T>(id: entity, component: read_component<T>): T
```

- **Details**

Adds the given components to the entity by using each component
constructor or no value at all if the component is a tag type.
Adds the component to the entity by using its constructor, or no value if it
is a tag type. Returns the current value.

Adding a component to an entity that already has the component will do
nothing.
Expand All @@ -96,7 +96,7 @@ Adds or changes an entity's component.
- **Type**

```lua
function Registry:set<T>(id: entity, component: T, value: T)
function Registry:set<T>(id: entity, component: component<T>, value: T)
```

- **Details**
Expand All @@ -116,7 +116,7 @@ Updates an entity's component.
- **Type**

```lua
function Registry:patch<T>(id: entity, component: T, patcher: (T) -> T): T
function Registry:patch<T>(id: entity, component: component<T>, patcher: ((T) -> T)?): T
```

- **Details**
Expand Down Expand Up @@ -145,7 +145,7 @@ Checks if an entity has all of the given components.
- **Type**

```lua
function Registry:has<T...>(id: entity, components: T...): boolean
function Registry:has(id: entity, components: ...read_component<unknown>): boolean
```

- **Details**
Expand All @@ -161,12 +161,13 @@ Gets an entity's component values.
- **Type**

```lua
function Registry:get<T...>(id: entity, components: T...): T...
function Registry:get<T>(id: entity, component: read_component<T>): T
```

- **Details**

Will error if the entity does not have a component.
Will error if the entity does not have a component. There are overloads for
two through four component types, each returning the matching value tuple.

--------------------------------------------------------------------------------

Expand All @@ -177,7 +178,7 @@ Gets an entity's component value.
- **Type**

```lua
function Registry:try_get<T>(id: entity, components: T): T?
function Registry:try_get<T>(id: entity, component: read_component<T>): T?
```

- **Details**
Expand All @@ -193,7 +194,7 @@ Removes the given components from an entity.
- **Type**

```lua
function Registry:remove<T...>(id: entity, components: T...)
function Registry:remove(id: entity, components: ...read_component<unknown>)
```

- **Details**
Expand All @@ -209,7 +210,7 @@ Removes all entities and components from the registry.
- **Type**

```lua
function Registry:clear<T...>(components: T...)
function Registry:clear(components: ...read_component<unknown>)
```

- **Details**
Expand All @@ -229,7 +230,7 @@ Returns the first entity found that has a component matching the given value.
- **Type**

```lua
function Registry:find<T>(component: T, value: T): entity?
function Registry:find<T>(component: component<T>, value: T): entity?
```

- **Details**
Expand All @@ -245,7 +246,7 @@ Copies the values of a component and pastes it into another component
- **Type**

```lua
function Registry:copy<T>(copy: T, paste: T)
function Registry:copy<T>(copy: component<T>, paste: component<T>)
```

- **Details**
Expand All @@ -262,7 +263,7 @@ Creates a [`view`](View) with the given component types.
- **Type**

```lua
function Registry:view<T...>(components: T...): View<T...>
function Registry:view<T>(component: component<T>): View<T>
```

--------------------------------------------------------------------------------
Expand All @@ -274,7 +275,7 @@ Creates an [`observer`](Observer) with the given component types.
- **Type**

```lua
function Registry:track<T...>(...: T...): Observer<T...>
function Registry:track<T>(component: read_component<T>): Observer<T>
```

--------------------------------------------------------------------------------
Expand All @@ -286,7 +287,7 @@ Creates a [`group`](Group.md) with the given component types.
- **Type**

```lua
function Registry:group<T...>(...: T...): Group<T...>
function Registry:group<A, B>(a: read_component<A>, b: read_component<B>): Group<A, B>
```

- **Details**
Expand All @@ -312,7 +313,7 @@ added to an entity.
- **Type**

```lua
function Registry:on_add<T>(component: T): Signal<entity, T>
function Registry:on_add<T>(component: read_component<T>): Signal<entity, T>
```

The signal is fired *after* the component is changed.
Expand All @@ -333,7 +334,7 @@ changed for an entity.
- **Type**

```lua
function Registry:on_change<T>(component: T): Signal<entity, T>
function Registry:on_change<T>(component: read_component<T>): Signal<entity, T>
```

The signal is fired *before* the component is changed.
Expand All @@ -354,7 +355,7 @@ removed from an entity.
- **Type**

```lua
function Registry:on_remove<T>(component: T): Signal<entity, nil>
function Registry:on_remove(component: read_component<unknown>): Signal<entity, nil>
```

- **Details**
Expand All @@ -369,6 +370,30 @@ removed from an entity.

--------------------------------------------------------------------------------

### on_clear()

Returns a [signal](Signal) fired when the given component type is cleared.

- **Type**

```lua
function Registry:on_clear(component: read_component<unknown>): Signal<>
```

--------------------------------------------------------------------------------

### after_clear()

Returns a [signal](Signal) fired after the given component type is cleared.

- **Type**

```lua
function Registry:after_clear(component: read_component<unknown>): Signal<>
```

--------------------------------------------------------------------------------

### handle()

Returns a [handle](Handle) to an entity.
Expand Down Expand Up @@ -411,8 +436,8 @@ Returns the [pool](Pool) for a given component type.
- **Type**

```lua
function Registry:storage<T>(component: T): Pool<T>
function Registry:storage(): () -> (unknown, Pool<unknown>)
function Registry:storage<T>(component: component<T>): Pool<T>
function Registry:storage(): () -> (read_component<unknown>, Pool<unknown>)
```

- **Details**
Expand Down
2 changes: 1 addition & 1 deletion docs/api/View.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Excludes entities with the given components from the view.
- **Type**

```lua
function View:exclude<T...>(components: ...unknown): View<T...>
function View:exclude<T...>(components: ...read_component<unknown>): View<T...>
```

- **Details**
Expand Down
16 changes: 8 additions & 8 deletions docs/api/ecr.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ Creates a new component type.
- **Type**

```lua
function ecr.component(): unknown
function ecr.component<T>(constructor: () -> T): T
function ecr.component<T>(constructor: (() -> T)?): component<T>
```

- **Details**
Expand All @@ -45,8 +44,8 @@ Creates a new component type.
No constructor.

```lua
local Position = ecr.component() :: Vector3
local Health = ecr.component() :: number
local Position = ecr.component<<Vector3>>()
local Health = ecr.component<<number>>()
```

With constructor.
Expand All @@ -71,7 +70,7 @@ Creates a new tag component type.
- **Type**

```lua
function ecr.tag(): nil
function ecr.tag(): component<nil>
```

- **Details**
Expand All @@ -89,7 +88,7 @@ Checks if a component type is a tag.
- **Type**

```lua
function ecr.is_tag<T>(ctype: T): boolean
function ecr.is_tag(ctype: read_component<unknown>): boolean
```

--------------------------------------------------------------------------------
Expand Down Expand Up @@ -125,7 +124,8 @@ Associates names with components for debugging.
- **Type**

```lua
function ecr.name<T>(names: T & Map<string, unknown>) -> T
function ecr.name<T>(names: T & { read [string]: read_component<unknown> }): T
function ecr.name<T>(component: component<T>): string?
```

- **Details**
Expand Down Expand Up @@ -196,7 +196,7 @@ Special component type that represents entities in a registry.
- **Type**

```lua
ecr.entity: entity
ecr.entity: component<entity>
```

--------------------------------------------------------------------------------
Expand Down
1 change: 0 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,3 @@ features:
- title: In Development
details: Not recommended for production use.
---

2 changes: 1 addition & 1 deletion docs/tut/context.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ time [`Registry:context()`](../api/Registry#context) is called, subsequent calls
return the same entity.

```lua
local Round = ecr.component() :: number
local Round = ecr.component<<number>>()

registry:context():set(Round, 1)

Expand Down
13 changes: 6 additions & 7 deletions docs/tut/crash-course.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,12 @@ A component is data that can be added to entities.
There is the *component type*, which represents a type of data, and there is
the *component value*, which is a value for a type added to an entity.

Component types are created by `ecr.component()`, which returns an id
representing that type. This can be typecasted to the type of value it
represents.
Component types are created by `ecr.component<T>()`, which returns an id
representing a value of type `T`.

```lua
local Name = ecr.component() :: string
local Health = ecr.component() :: number
local Name = ecr.component<<string>>()
local Health = ecr.component<<number>>()
```

Entities can have any amount of components added to or removed from them,
Expand Down Expand Up @@ -152,8 +151,8 @@ component types must also be defined before the registry using them is created.
local ecr = require(ecr)

local cts = {
Health = ecr.component() :: number,
Poisoned = ecr.component() :: number
Health = ecr.component<<number>>(),
Poisoned = ecr.component<<number>>()
}

ecr.name(cts)
Expand Down
Loading
Loading