Skip to content

Commit

Permalink
Example (#93)
Browse files Browse the repository at this point in the history
* Initial commit

* Return static function

* Fix upvalues conflict

* Add examples to luau

* rename example folder

* Add queries example

* Add changetracking example

* Add wildcards example

* Delete example.project.json
  • Loading branch information
Ukendio authored Aug 3, 2024
1 parent e5634b1 commit a9f449b
Show file tree
Hide file tree
Showing 13 changed files with 1,041 additions and 0 deletions.
71 changes: 71 additions & 0 deletions demo.project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"name": "demo",
"tree": {
"$className": "DataModel",
"ReplicatedStorage": {
"Shared": {
"$path": "demo/src/shared"
},
"ecs": {
"$path": "src"
}
},
"ServerScriptService": {
"Server": {
"$path": "demo/src/server"
}
},
"StarterPlayer": {
"StarterPlayerScripts": {
"Client": {
"$path": "demo/src/client"
}
}
},
"Workspace": {
"$properties": {
"FilteringEnabled": true
},
"Baseplate": {
"$className": "Part",
"$properties": {
"Anchored": true,
"Color": [
0.38823,
0.37254,
0.38823
],
"Locked": true,
"Position": [
0,
-10,
0
],
"Size": [
512,
20,
512
]
}
}
},
"Lighting": {
"$properties": {
"Ambient": [
0,
0,
0
],
"Brightness": 2,
"GlobalShadows": true,
"Outlines": false,
"Technology": "Voxel"
}
},
"SoundService": {
"$properties": {
"RespectFilteringEnabled": true
}
}
}
}
6 changes: 6 additions & 0 deletions demo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Project place file
/example.rbxlx

# Roblox Studio lock files
/*.rbxlx.lock
/*.rbxl.lock
17 changes: 17 additions & 0 deletions demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# example
Generated by [Rojo](https://github.com/rojo-rbx/rojo) 7.4.1.

## Getting Started
To build the place from scratch, use:

```bash
rojo build -o "example.rbxlx"
```

Next, open `example.rbxlx` in Roblox Studio and start the Rojo server:

```bash
rojo serve
```

For more help, check out [the Rojo documentation](https://rojo.space/docs).
1 change: 1 addition & 0 deletions demo/src/client/init.client.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print("Hello world, from client!")
1 change: 1 addition & 0 deletions demo/src/server/init.server.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

258 changes: 258 additions & 0 deletions demo/src/shared/common.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
--!optimize 2
--!native

local jecs = require(game:GetService("ReplicatedStorage").ecs)

type World = jecs.WorldShim
type Entity<T = any> = jecs.Entity<T>

local function panic(str)
-- We don't want to interrupt the loop when we error
task.spawn(error, str)
end

local function Scheduler(world, ...)
local systems = { ... }
local systemsNames = {}
local N = #systems
local system
local dt

for i, module in systems do
local sys = require(module)
systems[i] = sys
local file, line = debug.info(2, "sl")
systemsNames[sys] = `{file}->::{line}::->{debug.info(sys, "n")}`
end

local function run()
local name = systemsNames[system]

debug.profilebegin(name)
debug.setmemorycategory(name)
system(world, dt)
debug.profileend()
end

local function loop(sinceLastFrame)
debug.profilebegin("loop()")

for i = N, 1, -1 do
system = systems[i]

dt = sinceLastFrame

local didNotYield, why = xpcall(function()
for _ in run do end
end, debug.traceback)

if didNotYield then
continue
end

if string.find(why, "thread is not yieldable") then
N -= 1
local name = table.remove(systems, i)
panic("Not allowed to yield in the systems."
.. "\n"
.. `System: {name} has been ejected`
)
else
panic(why)
end
end

debug.profileend()
debug.resetmemorycategory()
end

return loop
end

type Tracker<T> = { track: (world: World, fn: (changes: {
added: () -> () -> (number, T),
removed: () -> () -> number,
changed: () -> () -> (number, T, T)
}) -> ()) -> ()
}

type Entity<T = any> = number & { __nominal_type_dont_use: T }

local function diff(a, b)
local size = 0
for k, v in a do
if b[k] ~= v then
return true
end
size += 1
end
for k, v in b do
size -= 1
end

if size ~= 0 then
return true
end

return false
end

local function ChangeTracker<T>(world, T: Entity<T>): Tracker<T>
local PreviousT = jecs.pair(jecs.Rest, T)
local add = {}
local added
local removed
local is_trivial

local function changes_added()
added = true
local q = world:query(T):without(PreviousT):drain()
return function()
local id, data = q.next()
if not id then
return nil
end

is_trivial = typeof(data) ~= "table"

add[id] = data

return id, data
end
end

local function changes_changed()
local q = world:query(T, PreviousT):drain()

return function()
local id, new, old = q.next()
while true do
if not id then
return nil
end

if not is_trivial then
if diff(new, old) then
break
end
elseif new ~= old then
break
end

id, new, old = q.next()
end

local record = world.entityIndex.sparse[id]
local archetype = record.archetype
local column = archetype.records[PreviousT].column
local data = if is_trivial then new else table.clone(new)
archetype.columns[column][record.row] = data

return id, old, new
end
end

local function changes_removed()
removed = true

local q = world:query(PreviousT):without(T):drain()
return function()
local id = q.next()
if id then
world:remove(id, PreviousT)
end
return id
end
end

local changes = {
added = changes_added,
changed = changes_changed,
removed = changes_removed,
}

local function track(fn)
added = false
removed = false

fn(changes)

if not added then
for _ in changes_added() do
end
end

if not removed then
for _ in changes_removed() do
end
end

for e, data in add do
world:set(e, PreviousT, if is_trivial then data else table.clone(data))
end
end

local tracker = { track = track }

return tracker
end

local bt
do
local SUCCESS = 0
local FAILURE = 1
local RUNNING = 2

local function SEQUENCE(nodes)
return function(...)
for _, node in nodes do
local status = node(...)
if status == FAILURE or status == RUNNING then
return status
end
end
return SUCCESS
end
end
local function FALLBACK(nodes)
return function(...)
for _, node in nodes do
local status = node(...)
if status == SUCCESS or status == RUNNING then
return status
end
end
return FAILURE
end
end
bt = {
SEQUENCE = SEQUENCE,
FALLBACK = FALLBACK,
RUNNING = RUNNING
}
end

local function interval(s)
local pin

local function throttle()
if not pin then
pin = os.clock()
end

local elapsed = os.clock() - pin > s
if elapsed then
pin = os.clock()
end

return elapsed
end
return throttle
end

return {
Scheduler = Scheduler,
ChangeTracker = ChangeTracker,
interval = interval,
BehaviorTree = bt
}
11 changes: 11 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Examples

This folder contains code examples for the Luau/Typescript APIs.

## Run with Luau
To run the examples with Luau, run the following commands from the root of the repository:

```sh
cd examples/luau
luau path/to/file.luau
```
Loading

0 comments on commit a9f449b

Please sign in to comment.