custom_godot_servers.rst 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. .. _doc_custom_godot_servers:
  2. Custom Godot servers
  3. ====================
  4. Introduction
  5. ------------
  6. Godot implements multi-threading as servers. Servers are daemons which
  7. manage data, process it, and push the result. Servers implement the
  8. mediator pattern which interprets resource ID and process data for the
  9. engine and other modules. In addition, the server claims ownership for
  10. its RID allocations.
  11. This guide assumes the reader knows how to create C++ modules and Godot
  12. data types. If not, refer to :ref:`doc_custom_modules_in_c++`.
  13. References
  14. ~~~~~~~~~~~
  15. - `Why does Godot use servers and RIDs? <https://godotengine.org/article/why-does-godot-use-servers-and-rids>`__
  16. - `Singleton pattern <https://en.wikipedia.org/wiki/Singleton_pattern>`__
  17. - `Mediator pattern <https://en.wikipedia.org/wiki/Mediator_pattern>`__
  18. What for?
  19. ---------
  20. - Adding artificial intelligence.
  21. - Adding custom asynchronous threads.
  22. - Adding support for a new input device.
  23. - Adding writing threads.
  24. - Adding a custom VoIP protocol.
  25. - And more...
  26. Creating a Godot server
  27. -----------------------
  28. At minimum, a server must have a static instance, a sleep timer, a thread loop,
  29. an initialization state and a cleanup procedure.
  30. .. code-block:: cpp
  31. #ifndef HILBERT_HOTEL_H
  32. #define HILBERT_HOTEL_H
  33. #include "core/list.h"
  34. #include "core/object.h"
  35. #include "core/os/thread.h"
  36. #include "core/os/mutex.h"
  37. #include "core/rid.h"
  38. #include "core/set.h"
  39. #include "core/variant.h"
  40. class HilbertHotel : public Object {
  41. GDCLASS(HilbertHotel, Object);
  42. static HilbertHotel *singleton;
  43. static void thread_func(void *p_udata);
  44. private:
  45. bool thread_exited;
  46. mutable bool exit_thread;
  47. Thread *thread;
  48. Mutex *mutex;
  49. public:
  50. static HilbertHotel *get_singleton();
  51. Error init();
  52. void lock();
  53. void unlock();
  54. void finish();
  55. protected:
  56. static void _bind_methods();
  57. private:
  58. uint64_t counter;
  59. RID_Owner<InfiniteBus> bus_owner;
  60. // https://github.com/godotengine/godot/blob/3.x/core/rid.h#L196
  61. Set<RID> buses;
  62. void _emit_occupy_room(uint64_t room, RID rid);
  63. public:
  64. RID create_bus();
  65. Variant get_bus_info(RID id);
  66. bool empty();
  67. bool delete_bus(RID id);
  68. void clear();
  69. void register_rooms();
  70. HilbertHotel();
  71. };
  72. #endif
  73. .. code-block:: cpp
  74. #include "hilbert_hotel.h"
  75. #include "core/dictionary.h"
  76. #include "core/list.h"
  77. #include "core/os/os.h"
  78. #include "core/variant.h"
  79. #include "prime_225.h"
  80. void HilbertHotel::thread_func(void *p_udata) {
  81. HilbertHotel *ac = (HilbertHotel *) p_udata;
  82. uint64_t msdelay = 1000;
  83. while (!ac->exit_thread) {
  84. if (!ac->empty()) {
  85. ac->lock();
  86. ac->register_rooms();
  87. ac->unlock();
  88. }
  89. OS::get_singleton()->delay_usec(msdelay * 1000);
  90. }
  91. }
  92. Error HilbertHotel::init() {
  93. thread_exited = false;
  94. counter = 0;
  95. mutex = Mutex::create();
  96. thread = Thread::create(HilbertHotel::thread_func, this);
  97. return OK;
  98. }
  99. HilbertHotel *HilbertHotel::singleton = NULL;
  100. HilbertHotel *HilbertHotel::get_singleton() {
  101. return singleton;
  102. }
  103. void HilbertHotel::register_rooms() {
  104. for (Set<RID>::Element *e = buses.front(); e; e = e->next()) {
  105. auto bus = bus_owner.getornull(e->get());
  106. if (bus) {
  107. uint64_t room = bus->next_room();
  108. _emit_occupy_room(room, bus->get_self());
  109. }
  110. }
  111. }
  112. void HilbertHotel::unlock() {
  113. if (!thread || !mutex) {
  114. return;
  115. }
  116. mutex->unlock();
  117. }
  118. void HilbertHotel::lock() {
  119. if (!thread || !mutex) {
  120. return;
  121. }
  122. mutex->lock();
  123. }
  124. void HilbertHotel::_emit_occupy_room(uint64_t room, RID rid) {
  125. _HilbertHotel::get_singleton()->_occupy_room(room, rid);
  126. }
  127. Variant HilbertHotel::get_bus_info(RID id) {
  128. InfiniteBus *)bus = bus_owner.getornull(id);
  129. if (bus) {
  130. Dictionary d;
  131. d["prime"] = bus->get_bus_num();
  132. d["current_room"] = bus->get_current_room();
  133. return d;
  134. }
  135. return Variant();
  136. }
  137. void HilbertHotel::finish() {
  138. if (!thread) {
  139. return;
  140. }
  141. exit_thread = true;
  142. Thread::wait_to_finish(thread);
  143. memdelete(thread);
  144. if (mutex) {
  145. memdelete(mutex);
  146. }
  147. thread = NULL;
  148. }
  149. RID HilbertHotel::create_bus() {
  150. lock();
  151. InfiniteBus *ptr = memnew(InfiniteBus(PRIME[counter++]));
  152. RID ret = bus_owner.make_rid(ptr);
  153. ptr->set_self(ret);
  154. buses.insert(ret);
  155. unlock();
  156. return ret;
  157. }
  158. // https://github.com/godotengine/godot/blob/3.x/core/rid.h#L187
  159. bool HilbertHotel::delete_bus(RID id) {
  160. if (bus_owner.owns(id)) {
  161. lock();
  162. InfiniteBus *b = bus_owner.get(id);
  163. bus_owner.free(id);
  164. buses.erase(id);
  165. memdelete(b);
  166. unlock();
  167. return true;
  168. }
  169. return false;
  170. }
  171. void HilbertHotel::clear() {
  172. for (Set<RID>::Element *e = buses.front(); e; e = e->next()) {
  173. delete_bus(e->get());
  174. }
  175. }
  176. bool HilbertHotel::empty() {
  177. return buses.size() <= 0;
  178. }
  179. void HilbertHotel::_bind_methods() {
  180. }
  181. HilbertHotel::HilbertHotel() {
  182. singleton = this;
  183. }
  184. .. code-block:: cpp
  185. /* prime_225.h */
  186. #include "core/int_types.h"
  187. const uint64_t PRIME[225] = {
  188. 2,3,5,7,11,13,17,19,23,
  189. 29,31,37,41,43,47,53,59,61,
  190. 67,71,73,79,83,89,97,101,103,
  191. 107,109,113,127,131,137,139,149,151,
  192. 157,163,167,173,179,181,191,193,197,
  193. 199,211,223,227,229,233,239,241,251,
  194. 257,263,269,271,277,281,283,293,307,
  195. 311,313,317,331,337,347,349,353,359,
  196. 367,373,379,383,389,397,401,409,419,
  197. 421,431,433,439,443,449,457,461,463,
  198. 467,479,487,491,499,503,509,521,523,
  199. 541,547,557,563,569,571,577,587,593,
  200. 599,601,607,613,617,619,631,641,643,
  201. 647,653,659,661,673,677,683,691,701,
  202. 709,719,727,733,739,743,751,757,761,
  203. 769,773,787,797,809,811,821,823,827,
  204. 829,839,853,857,859,863,877,881,883,
  205. 887,907,911,919,929,937,941,947,953,
  206. 967,971,977,983,991,997,1009,1013,1019,
  207. 1021,1031,1033,1039,1049,1051,1061,1063,1069,
  208. 1087,1091,1093,1097,1103,1109,1117,1123,1129,
  209. 1151,1153,1163,1171,1181,1187,1193,1201,1213,
  210. 1217,1223,1229,1231,1237,1249,1259,1277,1279,
  211. 1283,1289,1291,1297,1301,1303,1307,1319,1321,
  212. 1327,1361,1367,1373,1381,1399,1409,1423,1427
  213. };
  214. Custom managed resource data
  215. ----------------------------
  216. Godot servers implement a mediator pattern. All data types inherit ``RID_Data``.
  217. ``RID_Owner<MyRID_Data>`` owns the object when ``make_rid`` is called. During debug mode only,
  218. RID_Owner maintains a list of RIDs. In practice, RIDs are similar to writing
  219. object-oriented C code.
  220. .. code-block:: cpp
  221. class InfiniteBus : public RID_Data {
  222. RID self;
  223. private:
  224. uint64_t prime_num;
  225. uint64_t num;
  226. public:
  227. uint64_t next_room() {
  228. return prime_num * num++;
  229. }
  230. uint64_t get_bus_num() const {
  231. return prime_num;
  232. }
  233. uint64_t get_current_room() const {
  234. return prime_num * num;
  235. }
  236. _FORCE_INLINE_ void set_self(const RID &p_self) {
  237. self = p_self;
  238. }
  239. _FORCE_INLINE_ RID get_self() const {
  240. return self;
  241. }
  242. InfiniteBus(uint64_t prime) : prime_num(prime), num(1) {};
  243. ~InfiniteBus() {};
  244. }
  245. References
  246. ~~~~~~~~~~~
  247. - :ref:`RID<class_rid>`
  248. - `core/rid.h <https://github.com/godotengine/godot/blob/3.x/core/rid.h>`__
  249. Registering the class in GDScript
  250. ---------------------------------
  251. Servers are allocated in ``register_types.cpp``. The constructor sets the static
  252. instance and ``init()`` creates the managed thread; ``unregister_types.cpp``
  253. cleans up the server.
  254. Since a Godot server class creates an instance and binds it to a static singleton,
  255. binding the class might not reference the correct instance. Therefore, a dummy
  256. class must be created to reference the proper Godot server.
  257. In ``register_server_types()``, ``Engine::get_singleton()->add_singleton``
  258. is used to register the dummy class in GDScript.
  259. .. code-block:: cpp
  260. /* register_types.cpp */
  261. #include "register_types.h"
  262. #include "core/class_db.h"
  263. #include "core/engine.h"
  264. #include "hilbert_hotel.h"
  265. static HilbertHotel *hilbert_hotel = NULL;
  266. static _HilbertHotel *_hilbert_hotel = NULL;
  267. void register_hilbert_hotel_types() {
  268. hilbert_hotel = memnew(HilbertHotel);
  269. hilbert_hotel->init();
  270. _hilbert_hotel = memnew(_HilbertHotel);
  271. ClassDB::register_class<_HilbertHotel>();
  272. Engine::get_singleton()->add_singleton(Engine::Singleton("HilbertHotel", _HilbertHotel::get_singleton()));
  273. }
  274. void unregister_hilbert_hotel_types() {
  275. if (hilbert_hotel) {
  276. hilbert_hotel->finish();
  277. memdelete(hilbert_hotel);
  278. }
  279. if (_hilbert_hotel) {
  280. memdelete(_hilbert_hotel);
  281. }
  282. }
  283. .. code-block:: cpp
  284. /* register_types.h */
  285. /* Yes, the word in the middle must be the same as the module folder name */
  286. void register_hilbert_hotel_types();
  287. void unregister_hilbert_hotel_types();
  288. - `servers/register_server_types.cpp <https://github.com/godotengine/godot/blob/master/servers/register_server_types.cpp>`__
  289. Bind methods
  290. ~~~~~~~~~~~~
  291. The dummy class binds singleton methods to GDScript. In most cases, the dummy class methods wraps around.
  292. .. code-block:: cpp
  293. Variant _HilbertHotel::get_bus_info(RID id) {
  294. return HilbertHotel::get_singleton()->get_bus_info(id);
  295. }
  296. Binding Signals
  297. It is possible to emit signals to GDScript by calling the GDScript dummy object.
  298. .. code-block:: cpp
  299. void HilbertHotel::_emit_occupy_room(uint64_t room, RID rid) {
  300. _HilbertHotel::get_singleton()->_occupy_room(room, rid);
  301. }
  302. .. code-block:: cpp
  303. class _HilbertHotel : public Object {
  304. GDCLASS(_HilbertHotel, Object);
  305. friend class HilbertHotel;
  306. static _HilbertHotel *singleton;
  307. protected:
  308. static void _bind_methods();
  309. private:
  310. void _occupy_room(int room_number, RID bus);
  311. public:
  312. RID create_bus();
  313. void connect_signals();
  314. bool delete_bus(RID id);
  315. static _HilbertHotel *get_singleton();
  316. Variant get_bus_info(RID id);
  317. _HilbertHotel();
  318. ~_HilbertHotel();
  319. };
  320. #endif
  321. .. code-block:: cpp
  322. _HilbertHotel *_HilbertHotel::singleton = NULL;
  323. _HilbertHotel *_HilbertHotel::get_singleton() { return singleton; }
  324. RID _HilbertHotel::create_bus() {
  325. return HilbertHotel::get_singleton()->create_bus();
  326. }
  327. bool _HilbertHotel::delete_bus(RID rid) {
  328. return HilbertHotel::get_singleton()->delete_bus(rid);
  329. }
  330. void _HilbertHotel::_occupy_room(int room_number, RID bus) {
  331. emit_signal("occupy_room", room_number, bus);
  332. }
  333. Variant _HilbertHotel::get_bus_info(RID id) {
  334. return HilbertHotel::get_singleton()->get_bus_info(id);
  335. }
  336. void _HilbertHotel::_bind_methods() {
  337. ClassDB::bind_method(D_METHOD("get_bus_info", "r_id"), &_HilbertHotel::get_bus_info);
  338. ClassDB::bind_method(D_METHOD("create_bus"), &_HilbertHotel::create_bus);
  339. ClassDB::bind_method(D_METHOD("delete_bus"), &_HilbertHotel::delete_bus);
  340. ADD_SIGNAL(MethodInfo("occupy_room", PropertyInfo(Variant::INT, "room_number"), PropertyInfo(Variant::_RID, "r_id")));
  341. }
  342. void _HilbertHotel::connect_signals() {
  343. HilbertHotel::get_singleton()->connect("occupy_room", _HilbertHotel::get_singleton(), "_occupy_room");
  344. }
  345. _HilbertHotel::_HilbertHotel() {
  346. singleton = this;
  347. }
  348. _HilbertHotel::~_HilbertHotel() {
  349. }
  350. MessageQueue
  351. ------------
  352. In order to send commands into SceneTree, MessageQueue is a thread-safe buffer
  353. to queue set and call methods for other threads. To queue a command, obtain
  354. the target object RID and use either ``push_call``, ``push_set``, or ``push_notification``
  355. to execute the desired behavior. The queue will be flushed whenever either
  356. ``SceneTree::idle`` or ``SceneTree::iteration`` is executed.
  357. References:
  358. ~~~~~~~~~~~
  359. - `core/message_queue.cpp <https://github.com/godotengine/godot/blob/3.x/core/message_queue.cpp>`__
  360. Summing it up
  361. -------------
  362. Here is the GDScript sample code:
  363. ::
  364. extends Node
  365. func _ready():
  366. print("Start debugging")
  367. HilbertHotel.connect("occupy_room", self, "_print_occupy_room")
  368. var rid = HilbertHotel.create_bus()
  369. OS.delay_msec(2000)
  370. HilbertHotel.create_bus()
  371. OS.delay_msec(2000)
  372. HilbertHotel.create_bus()
  373. OS.delay_msec(2000)
  374. print(HilbertHotel.get_bus_info(rid))
  375. HilbertHotel.delete_bus(rid)
  376. print("Ready done")
  377. func _print_occupy_room(room_number, r_id):
  378. print("Room number: " + str(room_number) + ", RID: " + str(r_id))
  379. print(HilbertHotel.get_bus_info(r_id))
  380. Notes
  381. ~~~~~
  382. - The actual `Hilbert Hotel <https://en.wikipedia.org/wiki/Hilbert%27s_paradox_of_the_Grand_Hotel>`__ is impossible.
  383. - Connecting signal example code is pretty hacky.