@@ -564,10 +564,48 @@ TEST("world", function()
564
564
565
565
end )
566
566
567
+ type Tracker <T > = { track : (world : World , fn : (changes : {
568
+ added : () -> () -> (number , T ),
569
+ removed : () -> () -> number ,
570
+ changed : () -> () -> (number , T , T )
571
+ }) -> ()) -> ()
572
+ }
573
+
574
+ type Entity <T = any > = number & { __nominal_type_dont_use : T }
575
+
576
+ local ChangeTracker : <T >(component : Entity <T >) -> Tracker <T >
577
+
578
+ do
579
+ local world : World
580
+ local T
581
+ local PreviousT
582
+ local addedComponents
583
+ local removedComponents
584
+ local isTrivial
585
+ local added
586
+ local removed
587
+
588
+ local function changes_added ()
589
+ added = true
590
+ local q = world :query (T ):without (PreviousT )
591
+ return function ()
592
+ local id , data = q :next ()
593
+ if not id then
594
+ return nil
595
+ end
567
596
568
- TEST ("changetracker" , function ()
569
- local world = jecs .World .new ()
570
- local Previous = world :component ()
597
+ if isTrivial == nil then
598
+ isTrivial = typeof (data ) ~= "table"
599
+ end
600
+
601
+ if not isTrivial then
602
+ data = table.clone (data )
603
+ end
604
+
605
+ addedComponents [id ] = data
606
+ return id , data
607
+ end
608
+ end
571
609
572
610
local function shallowEq (a , b )
573
611
for k , v in a do
@@ -578,112 +616,102 @@ TEST("changetracker", function()
578
616
return true
579
617
end
580
618
581
- local function ChangeTracker (world , component )
582
- local addedComponents = {}
583
- local removedComponents = {}
584
- local previous = jecs .pair (Previous , component )
585
- local isTrivial = nil
586
-
587
- local function track (fn )
588
- local added = false
589
- local removed = false
590
-
591
- local changes = {}
592
- function changes .added ()
593
- added = true
594
- local q = world :query (component ):without (previous )
595
- return function ()
596
- local id , data = q :next ()
597
- if not id then
598
- return nil
599
- end
619
+ local function changes_changed ()
620
+ local q = world :query (T , PreviousT )
600
621
601
- if isTrivial == nil then
602
- isTrivial = typeof (data ) ~= "table"
603
- end
622
+ return function ()
623
+ local id , new , old = q :next ()
624
+ while true do
625
+ if not id then
626
+ return nil
627
+ end
604
628
605
- if not isTrivial then
606
- data = table.clone (data )
629
+ if not isTrivial then
630
+ if not shallowEq (new , old ) then
631
+ break
607
632
end
608
-
609
- addedComponents [id ] = data
610
- return id , data
633
+ elseif new ~= old then
634
+ break
611
635
end
636
+
637
+ id , new , old = q :next ()
612
638
end
613
639
614
- function changes .changed ()
615
- local q = world :query (component , previous )
616
-
617
- return function ()
618
- local id , new , old = q :next ()
619
- while true do
620
- if not id then
621
- return nil
622
- end
623
-
624
- if not isTrivial then
625
- if not shallowEq (new , old ) then
626
- break
627
- end
628
- elseif new ~= old then
629
- break
630
- end
631
-
632
- id , new , old = q :next ()
633
- end
640
+ addedComponents [id ] = new
634
641
635
- addedComponents [id ] = new
642
+ return id , old , new
643
+ end
644
+ end
636
645
637
- return id , old , new
638
- end
646
+ local function changes_removed ()
647
+ removed = true
648
+
649
+ local q = world :query (PreviousT ):without (T )
650
+ return function ()
651
+ local id = q :next ()
652
+ if id then
653
+ table.insert (removedComponents , id )
639
654
end
655
+ return id
656
+ end
657
+ end
640
658
641
- function changes .removed ()
642
- removed = true
659
+ local changes = {
660
+ added = changes_added ,
661
+ changed = changes_changed ,
662
+ removed = changes_removed ,
663
+ }
643
664
644
- local q = world :query (previous ):without (component )
645
- return function ()
646
- local id = q :next ()
647
- if id then
648
- table.insert (removedComponents , id )
649
- end
650
- return id
651
- end
652
- end
665
+ local function track (worldToTrack , fn )
666
+ world = worldToTrack
667
+ added = true
668
+ removed = true
653
669
654
- fn (changes )
655
- if not added then
656
- for _ in changes .added () do
657
- end
658
- end
670
+ fn (changes )
659
671
660
- if not removed then
661
- for _ in changes .removed () do
662
- end
672
+ if not added then
673
+ for _ in changes_added () do
663
674
end
675
+ end
664
676
665
- for e , data in addedComponents do
666
- world : set ( e , previous , if isTrivial then data else table.clone ( data ))
677
+ if not removed then
678
+ for _ in changes_removed () do
667
679
end
680
+ end
668
681
669
- for _ , e in removedComponents do
670
- world :remove (e , previous )
671
- end
682
+ for e , data in addedComponents do
683
+ world :set (e , PreviousT , if isTrivial then data else table.clone (data ))
672
684
end
673
685
674
- return {
675
- track = track
676
- }
686
+ for _ , e in removedComponents do
687
+ world :remove (e , PreviousT )
688
+ end
689
+ end
690
+
691
+ local tracker = { track = track }
692
+
693
+ function ChangeTracker <T >(component : Entity <T >): Tracker <T >
694
+ T = component
695
+ -- We just use jecs.Rest because people will probably not use it anyways
696
+ PreviousT = jecs .pair (jecs .Rest , T )
697
+ addedComponents = {}
698
+ removedComponents = {}
699
+
700
+ return tracker
677
701
end
702
+ end
703
+
704
+ TEST ("changetracker" , function ()
705
+ local world = jecs .World .new ()
678
706
679
707
do CASE "should allow change tracking"
680
- local Test = world :component ()
681
- local TestTracker = ChangeTracker (world , Test )
708
+ local Test = world :component () :: Entity <{ foo : number }>
709
+ local TestTracker = ChangeTracker (Test )
682
710
683
711
local e = world :entity ()
684
712
world :set (e , Test , { foo = 11 })
685
713
686
- TestTracker .track (function (changes )
714
+ TestTracker .track (world , function (changes )
687
715
local added = 0
688
716
local changed = 0
689
717
local removed = 0
@@ -705,7 +733,7 @@ TEST("changetracker", function()
705
733
test .foo = test .foo + 1
706
734
end
707
735
708
- TestTracker .track (function (changes )
736
+ TestTracker .track (world , function (changes )
709
737
local added = 0
710
738
local changed = 0
711
739
local removed = 0
@@ -727,7 +755,7 @@ TEST("changetracker", function()
727
755
728
756
world :remove (e , Test )
729
757
730
- TestTracker .track (function (changes )
758
+ TestTracker .track (world , function (changes )
731
759
local added = 0
732
760
local changed = 0
733
761
local removed = 0
0 commit comments