1 /*************************************************************************/
2 /*  timer.cpp                                                            */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 
31 #include "timer.h"
32 
33 #include "core/engine.h"
34 
_notification(int p_what)35 void Timer::_notification(int p_what) {
36 
37 	switch (p_what) {
38 
39 		case NOTIFICATION_READY: {
40 
41 			if (autostart) {
42 #ifdef TOOLS_ENABLED
43 				if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root() == this || get_tree()->get_edited_scene_root()->is_a_parent_of(this)))
44 					break;
45 #endif
46 				start();
47 				autostart = false;
48 			}
49 		} break;
50 		case NOTIFICATION_INTERNAL_PROCESS: {
51 			if (timer_process_mode == TIMER_PROCESS_PHYSICS || !is_processing_internal())
52 				return;
53 			time_left -= get_process_delta_time();
54 
55 			if (time_left < 0) {
56 				if (!one_shot)
57 					time_left += wait_time;
58 				else
59 					stop();
60 
61 				emit_signal("timeout");
62 			}
63 
64 		} break;
65 		case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
66 			if (timer_process_mode == TIMER_PROCESS_IDLE || !is_physics_processing_internal())
67 				return;
68 			time_left -= get_physics_process_delta_time();
69 
70 			if (time_left < 0) {
71 				if (!one_shot)
72 					time_left += wait_time;
73 				else
74 					stop();
75 				emit_signal("timeout");
76 			}
77 
78 		} break;
79 	}
80 }
81 
set_wait_time(float p_time)82 void Timer::set_wait_time(float p_time) {
83 	ERR_FAIL_COND_MSG(p_time <= 0, "Time should be greater than zero.");
84 	wait_time = p_time;
85 }
get_wait_time() const86 float Timer::get_wait_time() const {
87 
88 	return wait_time;
89 }
90 
set_one_shot(bool p_one_shot)91 void Timer::set_one_shot(bool p_one_shot) {
92 
93 	one_shot = p_one_shot;
94 }
is_one_shot() const95 bool Timer::is_one_shot() const {
96 
97 	return one_shot;
98 }
99 
set_autostart(bool p_start)100 void Timer::set_autostart(bool p_start) {
101 
102 	autostart = p_start;
103 }
has_autostart() const104 bool Timer::has_autostart() const {
105 
106 	return autostart;
107 }
108 
start(float p_time)109 void Timer::start(float p_time) {
110 
111 	ERR_FAIL_COND_MSG(!is_inside_tree(), "Timer was not added to the SceneTree. Either add it or set autostart to true.");
112 
113 	if (p_time > 0) {
114 		set_wait_time(p_time);
115 	}
116 	time_left = wait_time;
117 	_set_process(true);
118 }
119 
stop()120 void Timer::stop() {
121 	time_left = -1;
122 	_set_process(false);
123 	autostart = false;
124 }
125 
set_paused(bool p_paused)126 void Timer::set_paused(bool p_paused) {
127 	if (paused == p_paused)
128 		return;
129 
130 	paused = p_paused;
131 	_set_process(processing);
132 }
133 
is_paused() const134 bool Timer::is_paused() const {
135 	return paused;
136 }
137 
is_stopped() const138 bool Timer::is_stopped() const {
139 	return get_time_left() <= 0;
140 }
141 
get_time_left() const142 float Timer::get_time_left() const {
143 
144 	return time_left > 0 ? time_left : 0;
145 }
146 
set_timer_process_mode(TimerProcessMode p_mode)147 void Timer::set_timer_process_mode(TimerProcessMode p_mode) {
148 
149 	if (timer_process_mode == p_mode)
150 		return;
151 
152 	switch (timer_process_mode) {
153 		case TIMER_PROCESS_PHYSICS:
154 			if (is_physics_processing_internal()) {
155 				set_physics_process_internal(false);
156 				set_process_internal(true);
157 			}
158 			break;
159 		case TIMER_PROCESS_IDLE:
160 			if (is_processing_internal()) {
161 				set_process_internal(false);
162 				set_physics_process_internal(true);
163 			}
164 			break;
165 	}
166 	timer_process_mode = p_mode;
167 }
168 
get_timer_process_mode() const169 Timer::TimerProcessMode Timer::get_timer_process_mode() const {
170 
171 	return timer_process_mode;
172 }
173 
_set_process(bool p_process,bool p_force)174 void Timer::_set_process(bool p_process, bool p_force) {
175 	switch (timer_process_mode) {
176 		case TIMER_PROCESS_PHYSICS: set_physics_process_internal(p_process && !paused); break;
177 		case TIMER_PROCESS_IDLE: set_process_internal(p_process && !paused); break;
178 	}
179 	processing = p_process;
180 }
181 
_bind_methods()182 void Timer::_bind_methods() {
183 
184 	ClassDB::bind_method(D_METHOD("set_wait_time", "time_sec"), &Timer::set_wait_time);
185 	ClassDB::bind_method(D_METHOD("get_wait_time"), &Timer::get_wait_time);
186 
187 	ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &Timer::set_one_shot);
188 	ClassDB::bind_method(D_METHOD("is_one_shot"), &Timer::is_one_shot);
189 
190 	ClassDB::bind_method(D_METHOD("set_autostart", "enable"), &Timer::set_autostart);
191 	ClassDB::bind_method(D_METHOD("has_autostart"), &Timer::has_autostart);
192 
193 	ClassDB::bind_method(D_METHOD("start", "time_sec"), &Timer::start, DEFVAL(-1));
194 	ClassDB::bind_method(D_METHOD("stop"), &Timer::stop);
195 
196 	ClassDB::bind_method(D_METHOD("set_paused", "paused"), &Timer::set_paused);
197 	ClassDB::bind_method(D_METHOD("is_paused"), &Timer::is_paused);
198 
199 	ClassDB::bind_method(D_METHOD("is_stopped"), &Timer::is_stopped);
200 
201 	ClassDB::bind_method(D_METHOD("get_time_left"), &Timer::get_time_left);
202 
203 	ClassDB::bind_method(D_METHOD("set_timer_process_mode", "mode"), &Timer::set_timer_process_mode);
204 	ClassDB::bind_method(D_METHOD("get_timer_process_mode"), &Timer::get_timer_process_mode);
205 
206 	ADD_SIGNAL(MethodInfo("timeout"));
207 
208 	ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_timer_process_mode", "get_timer_process_mode");
209 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "wait_time", PROPERTY_HINT_EXP_RANGE, "0.001,4096,0.001,or_greater"), "set_wait_time", "get_wait_time");
210 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "is_one_shot");
211 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autostart"), "set_autostart", "has_autostart");
212 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused", PROPERTY_HINT_NONE, "", 0), "set_paused", "is_paused");
213 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "time_left", PROPERTY_HINT_NONE, "", 0), "", "get_time_left");
214 
215 	BIND_ENUM_CONSTANT(TIMER_PROCESS_PHYSICS);
216 	BIND_ENUM_CONSTANT(TIMER_PROCESS_IDLE);
217 }
218 
Timer()219 Timer::Timer() {
220 	timer_process_mode = TIMER_PROCESS_IDLE;
221 	autostart = false;
222 	wait_time = 1;
223 	one_shot = false;
224 	time_left = -1;
225 	processing = false;
226 	paused = false;
227 }
228