@@ -1243,4 +1243,251 @@ TEST("Hooks", function()
12431243 end
12441244
12451245end )
1246+
1247+ TEST ("scheduler" , function ()
1248+ type System = {
1249+ callback : (world : World ) -> ()
1250+ }
1251+ type Systems = { System }
1252+
1253+
1254+ type Events = {
1255+ RenderStepped : Systems ,
1256+ Heartbeat : Systems
1257+ }
1258+
1259+ local scheduler_new : (w : World ) -> {
1260+ components : {
1261+ Disabled : Entity ,
1262+ System : Entity <System >,
1263+ Phase : Entity ,
1264+ DependsOn : Entity
1265+ },
1266+
1267+ systems : {
1268+ collect : {
1269+ under_event : (event : Entity ) -> Systems ,
1270+ all : () -> Events
1271+ },
1272+ run : (events : Events ) -> ()
1273+ },
1274+
1275+ phases : {
1276+ RenderStepped : Entity ,
1277+ Heartbeat : Entity
1278+ },
1279+
1280+ phase : (after : Entity ) -> Entity
1281+ }
1282+
1283+ do
1284+ local world
1285+ local Disabled
1286+ local System
1287+ local DependsOn
1288+ local Phase
1289+ local RenderStepped
1290+ local Heartbeat
1291+
1292+ local function scheduler_collect_systems_under_phase_recursive (systems , phase )
1293+ for _ , system in world :query (System ):with (pair (DependsOn , phase )) do
1294+ table.insert (systems , system )
1295+ end
1296+ for dependant in world :query (Phase ):with (pair (DependsOn , phase )) do
1297+ scheduler_collect_systems_under_phase_recursive (systems , dependant )
1298+ end
1299+ end
1300+
1301+ local function scheduler_collect_systems_under_event (event )
1302+ local systems = {}
1303+ scheduler_collect_systems_under_phase_recursive (systems , event )
1304+ return systems
1305+ end
1306+
1307+ local function scheduler_collect_systems_all ()
1308+ local systems = {
1309+ RenderStepped = scheduler_collect_systems_under_event (
1310+ RenderStepped ),
1311+ Heartbeat = scheduler_collect_systems_under_event (
1312+ Heartbeat )
1313+ }
1314+ return systems
1315+ end
1316+
1317+ local function scheduler_run_systems (events )
1318+ for _ , system in events .RenderStepped do
1319+ system .callback (world )
1320+ end
1321+ for _ , system in events .Heartbeat do
1322+ system .callback (world )
1323+ end
1324+ end
1325+
1326+ local function scheduler_phase_new (after )
1327+ local phase = world :entity ()
1328+ world :add (phase , Phase )
1329+ local dependency = pair (DependsOn , after )
1330+ world :add (phase , dependency )
1331+ return phase
1332+ end
1333+
1334+ local function scheduler_systems_new (callback , phase )
1335+ local system = world :entity ()
1336+ world :set (system , System , { callback = callback })
1337+ world :add (system , pair (DependsOn , phase ))
1338+ return system
1339+ end
1340+
1341+ function scheduler_new (w )
1342+ world = w
1343+ Disabled = world :component ()
1344+ System = world :component ()
1345+ Phase = world :component ()
1346+ DependsOn = world :component ()
1347+
1348+ RenderStepped = world :component ()
1349+ Heartbeat = world :component ()
1350+
1351+ world :add (RenderStepped , Phase )
1352+ world :add (Heartbeat , Phase )
1353+
1354+ return {
1355+ phase = scheduler_phase_new ,
1356+
1357+ phases = {
1358+ RenderStepped = RenderStepped ,
1359+ Heartbeat = Heartbeat ,
1360+ },
1361+
1362+ world = world ,
1363+
1364+ collect_systems = {
1365+ under_event = scheduler_collect_systems_under_event ,
1366+ all = scheduler_collect_systems_all
1367+ },
1368+
1369+ run_systems = scheduler_run_systems ,
1370+
1371+ components = {
1372+ DependsOn = DependsOn ,
1373+ Disabled = Disabled ,
1374+ Heartbeat = Heartbeat ,
1375+ Phase = Phase ,
1376+ RenderStepped = RenderStepped ,
1377+ System = System ,
1378+ },
1379+
1380+ systems = {
1381+ run = scheduler_run_systems ,
1382+ collect = {
1383+ under_event = scheduler_collect_systems_under_event ,
1384+ all = scheduler_collect_systems_all
1385+ },
1386+ new = scheduler_systems_new ,
1387+ }
1388+ }
1389+ end
1390+ end
1391+
1392+ do CASE "event dependant phase"
1393+
1394+ local world = jecs .World .new ()
1395+ local scheduler = scheduler_new (world )
1396+ local components = scheduler .components
1397+ local phases = scheduler .phases
1398+ local Heartbeat = phases .Heartbeat
1399+ local DependsOn = components .DependsOn
1400+
1401+ local Physics = scheduler .phase (Heartbeat )
1402+ CHECK (world :target (Physics , DependsOn ) == Heartbeat )
1403+ end
1404+
1405+ do CASE "user-defined sub phases"
1406+ local world = jecs .World .new ()
1407+ local scheduler = scheduler_new (world )
1408+ local components = scheduler .components
1409+ local phases = scheduler .phases
1410+ local DependsOn = components .DependsOn
1411+
1412+ local A = scheduler .phase (phases .Heartbeat )
1413+ local B = scheduler .phase (A )
1414+
1415+ CHECK (world :target (B , DependsOn ) == A )
1416+ end
1417+
1418+ do CASE "phase order"
1419+ local world = jecs .World .new ()
1420+ local scheduler = scheduler_new (world )
1421+
1422+ local phases = scheduler .phases
1423+ local Physics = scheduler .phase (phases .Heartbeat )
1424+ local Collisions = scheduler .phase (Physics )
1425+
1426+ local order = "BEGIN"
1427+
1428+ local function move ()
1429+ order ..= "->move"
1430+ end
1431+
1432+ local function hit ()
1433+ order ..= "->hit"
1434+ end
1435+
1436+ local createSystem = scheduler .systems .new
1437+
1438+ createSystem (hit , Collisions )
1439+ createSystem (move , Physics )
1440+
1441+ local events = scheduler .systems .collect .all ()
1442+ scheduler .systems .run (events )
1443+
1444+ order ..= "->END"
1445+
1446+ CHECK (order == "BEGIN->move->hit->END" )
1447+ end
1448+
1449+ do CASE "collect only systems under phase recursive"
1450+ local world = jecs .World .new ()
1451+ local scheduler = scheduler_new (world )
1452+ local phases = scheduler .phases
1453+ local Heartbeat = phases .Heartbeat
1454+ local RenderStepped = phases .RenderStepped
1455+ local Render = scheduler .phase (RenderStepped )
1456+ local Physics = scheduler .phase (Heartbeat )
1457+ local Collisions = scheduler .phase (Physics )
1458+
1459+ local function move ()
1460+ end
1461+
1462+ local function hit ()
1463+ end
1464+
1465+ local function camera ()
1466+ end
1467+
1468+ local createSystem = scheduler .systems .new
1469+
1470+ createSystem (hit , Collisions )
1471+ createSystem (move , Physics )
1472+ createSystem (camera , Render )
1473+
1474+ local systems = scheduler .systems .collect .under_event (Collisions )
1475+
1476+ CHECK (# systems == 1 )
1477+ CHECK (systems [1 ].callback == hit )
1478+
1479+ systems = scheduler .systems .collect .under_event (Physics )
1480+
1481+ CHECK (# systems == 2 )
1482+
1483+ systems = scheduler .systems .collect .under_event (Heartbeat )
1484+
1485+ CHECK (# systems == 2 )
1486+
1487+ systems = scheduler .systems .collect .under_event (Render )
1488+
1489+ CHECK (# systems == 1 )
1490+ CHECK (systems [1 ].callback == camera )
1491+ end
1492+ end )
12461493FINISH ()
0 commit comments