Line data Source code
1 : function Timer() {}
2 :
3 16 : Timer.prototype.Schema =
4 : "<a:component type='system'/><empty/>";
5 :
6 16 : Timer.prototype.Init = function()
7 : {
8 45 : this.id = 0;
9 45 : this.time = 0;
10 45 : this.timers = new Map();
11 45 : this.turnLength = 0;
12 : };
13 :
14 : /**
15 : * @returns {number} - The elapsed time in milliseconds since the game was started.
16 : */
17 16 : Timer.prototype.GetTime = function()
18 : {
19 9 : return this.time;
20 : };
21 :
22 : /**
23 : * @returns {number} - The duration of the latest turn in milliseconds.
24 : */
25 16 : Timer.prototype.GetLatestTurnLength = function()
26 : {
27 1 : return this.turnLength;
28 : };
29 :
30 : /**
31 : * Create a new timer, which will call the 'funcname' method with arguments (data, lateness)
32 : * on the 'iid' component of the 'ent' entity, after at least 'time' milliseconds.
33 : * 'lateness' is how late the timer is executed after the specified time (in milliseconds).
34 : * @param {number} ent - The entity id to which the timer will be assigned to.
35 : * @param {number} iid - The component iid of the timer.
36 : * @param {string} funcname - The name of the function to be called in the component.
37 : * @param {number} time - The delay before running the function for the first time.
38 : * @param {any} data - The data to pass to the function.
39 : * @returns {number} - A non-zero id that can be passed to CancelTimer.
40 : */
41 16 : Timer.prototype.SetTimeout = function(ent, iid, funcname, time, data)
42 : {
43 11 : return this.SetInterval(ent, iid, funcname, time, 0, data);
44 : };
45 :
46 : /**
47 : * Create a new repeating timer, which will call the 'funcname' method with arguments (data, lateness)
48 : * on the 'iid' component of the 'ent' entity, after at least 'time' milliseconds.
49 : * 'lateness' is how late the timer is executed after the specified time (in milliseconds)
50 : * and then every 'repeattime' milliseconds thereafter.
51 : * @param {number} ent - The entity the timer will be assigned to.
52 : * @param {number} iid - The component iid of the timer.
53 : * @param {string} funcname - The name of the function to be called in the component.
54 : * @param {number} time - The delay before running the function for the first time.
55 : * @param {number} repeattime - If non-zero, the interval between each execution of the function.
56 : * @param {any} data - The data to pass to the function.
57 : * @returns {number} - A non-zero id that can be passed to CancelTimer.
58 : */
59 16 : Timer.prototype.SetInterval = function(ent, iid, funcname, time, repeattime, data)
60 : {
61 80 : let id = ++this.id;
62 :
63 80 : this.timers.set(id, {
64 : "entity": ent,
65 : "iid": iid,
66 : "functionName": funcname,
67 : "time": this.time + time,
68 : "repeatTime": repeattime,
69 : "data": data
70 : });
71 :
72 80 : return id;
73 : };
74 :
75 : /**
76 : * Updates the repeat time of a timer.
77 : * Note that this will take only effect after the next update.
78 : *
79 : * @param {number} timerID - The timer to update.
80 : * @param {number} newRepeatTime - The new repeat time to use.
81 : */
82 16 : Timer.prototype.UpdateRepeatTime = function(timerID, newRepeatTime)
83 : {
84 3 : let timer = this.timers.get(timerID);
85 3 : if (timer)
86 3 : this.timers.set(timerID, {
87 : "entity": timer.entity,
88 : "iid": timer.iid,
89 : "functionName": timer.functionName,
90 : "time": timer.time,
91 : "repeatTime": newRepeatTime,
92 : "data": timer.data
93 : });
94 : };
95 :
96 : /**
97 : * Cancels an existing timer that was created with SetTimeout/SetInterval.
98 : * @param {number} id - The timer's ID returned by either SetTimeout or SetInterval.
99 : */
100 16 : Timer.prototype.CancelTimer = function(id)
101 : {
102 52 : this.timers.delete(id);
103 : };
104 :
105 : /**
106 : * @param {{ "turnLength": number }} msg - A message containing the turn length in seconds.
107 : */
108 16 : Timer.prototype.OnUpdate = function(msg)
109 : {
110 206 : this.turnLength = Math.round(msg.turnLength * 1000);
111 206 : this.time += this.turnLength;
112 :
113 : // Collect the timers that need to run
114 : // (We do this in two stages to avoid deleting from the timer list while
115 : // we're in the middle of iterating through it)
116 206 : let run = [];
117 206 : for (let [id, timer] of this.timers)
118 168 : if (timer.time <= this.time)
119 156 : run.push(id);
120 :
121 206 : for (let id of run)
122 : {
123 516 : let timer = this.timers.get(id);
124 :
125 : // An earlier timer might have cancelled this one, so skip it
126 516 : if (!timer)
127 8 : continue;
128 :
129 : // The entity was probably destroyed; clean up the timer
130 508 : let timerTargetComponent = Engine.QueryInterface(timer.entity, timer.iid);
131 508 : if (!timerTargetComponent)
132 : {
133 0 : this.timers.delete(id);
134 0 : continue;
135 : }
136 :
137 508 : try
138 : {
139 508 : timerTargetComponent[timer.functionName](timer.data, this.time - timer.time);
140 : }
141 : catch (e)
142 : {
143 0 : error(
144 : "Error in timer on entity " + timer.entity + ", " +
145 : "IID" + timer.iid + ", " +
146 : "function " + timer.functionName + ": " +
147 : e + "\n" +
148 : // Indent the stack trace
149 : e.stack.trimRight().replace(/^/mg, ' ') + "\n");
150 : }
151 :
152 508 : if (!timer.repeatTime)
153 : {
154 11 : this.timers.delete(id);
155 11 : continue;
156 : }
157 :
158 497 : timer.time += timer.repeatTime;
159 :
160 : // Add it to the list to get re-executed if it's soon enough
161 497 : if (timer.time <= this.time)
162 360 : run.push(id);
163 : }
164 : };
165 :
166 16 : Engine.RegisterSystemComponentType(IID_Timer, "Timer", Timer);
|