1+ core = core or {}
2+ core .events = core .events or {}
3+
4+ local function is_array (t )
5+ local i = 0
6+ for _ in pairs (t ) do
7+ i = i + 1
8+ if t [i ] == nil then return false end
9+ end
10+ return true
11+ end
12+
13+ local function remove_key (table , key )
14+ local element = table [key ]
15+ table [key ] = nil
16+ return element
17+ end
18+
19+ local function update_state_from_diff (old , diff , prefix )
20+ local events = {}
21+ for k in pairs (diff ) do
22+ if type (diff [k ]) == " table" and not is_array (diff [k ]) then
23+ if next (diff [k ]) == nil then
24+ old [k ] = {}
25+ else
26+ old [k ] = old [k ] or {}
27+
28+ update_state_from_diff (old [k ], remove_key (diff , k ), prefix .. " ." .. k )
29+ end
30+ else
31+ old [k ] = remove_key (diff , k )
32+ end
33+ table.insert (events , prefix .. " ." .. k )
34+ end
35+
36+ for _ , ev in ipairs (events ) do
37+ raiseEvent (ev )
38+ end
39+ end
40+
41+ local function get_dropped_and_added_affects (old_affects , new_affects )
42+ local added_affects = {}
43+ local dropped_affects = {}
44+
45+ if new_affects then table.sort (new_affects , function (left , right )
46+ return left .name < right .name
47+ end ) end
48+ if old_affects then table.sort (old_affects , function (left , right )
49+ return left .name < right .name
50+ end ) end
51+
52+ local old_aff_idx = 1
53+ local new_aff_idx = 1
54+ local old_aff_n = table .getn (old_affects )
55+ local new_aff_n = table .getn (new_affects )
56+ while true do
57+ if new_aff_idx > new_aff_n and old_aff_idx > old_aff_n then
58+ break
59+ elseif old_aff_idx > old_aff_n then
60+ table.insert (added_affects , 1 , new_affects [new_aff_idx ])
61+ new_aff_idx = new_aff_idx + 1
62+ elseif new_aff_idx > new_aff_n then
63+ table.insert (dropped_affects , 1 , old_affects [old_aff_idx ])
64+ old_aff_idx = old_aff_idx + 1
65+ elseif old_affects [old_aff_idx ].name == new_affects [new_aff_idx ].name then
66+ old_aff_idx = old_aff_idx + 1
67+ new_aff_idx = new_aff_idx + 1
68+ elseif old_affects [old_aff_idx ].name > new_affects [new_aff_idx ].name then
69+ table.insert (added_affects , 1 , new_affects [new_aff_idx ])
70+ new_aff_idx = new_aff_idx + 1
71+ elseif old_affects [old_aff_idx ].name < new_affects [new_aff_idx ].name then
72+ table.insert (dropped_affects , 1 , old_affects [old_aff_idx ])
73+ old_aff_idx = old_aff_idx + 1
74+ end
75+ end
76+
77+ return dropped_affects , added_affects
78+ end
79+
80+ function core .on_gmcp_char (event , args )
81+ local diff_table = gmcp .Char .State .update
82+
83+ local dropped = {}
84+ local added = {}
85+ if diff_table .affects then
86+ if not gmcp .Char .affects then gmcp .Char .affects = {} end
87+ dropped , added = get_dropped_and_added_affects (gmcp .Char .affects , diff_table .affects )
88+ end
89+
90+ update_state_from_diff (gmcp .Char , diff_table , " gmcp.Char" )
91+
92+ if table .getn (dropped ) > 0 then
93+ for i , affect in ipairs (dropped ) do
94+ raiseEvent (" affectDropped" , affect .name )
95+ end
96+ end
97+ if table .getn (added ) > 0 then
98+ for i , affect in ipairs (added ) do
99+ raiseEvent (" affectAdded" , affect .name )
100+ end
101+ end
102+ end
103+
104+ function core .on_gmcp_char_state (event , args )
105+ local diff_table = gmcp .Char .State .update
106+
107+ local dropped = {}
108+ local added = {}
109+ if diff_table .affects then
110+ if not gmcp .Char .affects then gmcp .Char .affects = {} end
111+ dropped , added = get_dropped_and_added_affects (gmcp .Char .affects , diff_table .affects )
112+ end
113+
114+ update_state_from_diff (gmcp .Char , diff_table , " gmcp.Char" )
115+
116+ if table .getn (dropped ) > 0 then
117+ for i , affect in ipairs (dropped ) do
118+ raiseEvent (" affectDropped" , affect .name )
119+ end
120+ end
121+ if table .getn (added ) > 0 then
122+ for i , affect in ipairs (added ) do
123+ raiseEvent (" affectAdded" , affect .name )
124+ end
125+ end
126+ end
127+
128+
129+ function core .initialize ()
130+ for _ , handlerID in pairs (core .events ) do
131+ killAnonymousEventHandler (handlerID )
132+ end
133+ core .events .ongmcpchar = registerAnonymousEventHandler (" gmcp.Char" , " core.on_gmcp_char" )
134+ core .events .ongmcpcharstate = registerAnonymousEventHandler (" gmcp.Char.State" , " core.on_gmcp_char_state" )
135+ end
136+
137+ function core .stop ()
138+ for _ , handlerID in pairs (core .events ) do
139+ killAnonymousEventHandler (handlerID )
140+ end
141+ end
142+
143+ core .initialize ()
0 commit comments