2
0
Эх сурвалжийг харах

Improve Custom Godot servers page and fix typos

This also makes the example code conform to the engine code style.
Hugo Locurcio 7 жил өмнө
parent
commit
b2eb5ed8d4

+ 140 - 109
development/cpp/custom_godot_servers.rst

@@ -1,45 +1,44 @@
 .. _doc_custom_godot_servers:
 
-Custom Godot Servers
+Custom Godot servers
 ====================
 
 Introduction
 ------------
 
-Godot implements multi threading as servers. Servers are daemons which 
-manages data, processes, and pushes the result. Server implements the 
-mediator pattern which interprets resource ID and process data for the 
-engine and other modules. In addition, the server claims ownership for 
+Godot implements multi-threading as servers. Servers are daemons which
+manages data, processes, and pushes the result. Servers implement the
+mediator pattern which interprets resource ID and process data for the
+engine and other modules. In addition, the server claims ownership for
 its RID allocations.
 
+This guide assumes the reader knows how to create C++ modules and Godot
+data types. If not, refer to :ref:`doc_custom_modules_in_c++`.
 
-This guide assumes the reader knows how to create C++ modules and godot 
-data types. If not, refer to this guide :ref:`doc_custom_modules_in_c++`.
-
-References:
+References
 ~~~~~~~~~~~
 
-- `Why does Godot use Servers and RIDs? <https://godotengine.org/article/why-does-godot-use-servers-and-rids>`__
+- `Why does Godot use servers and RIDs? <https://godotengine.org/article/why-does-godot-use-servers-and-rids>`__
 
-- `Sigleton Pattern <https://en.wikipedia.org/wiki/Singleton_pattern>`__
+- `Singleton pattern <https://en.wikipedia.org/wiki/Singleton_pattern>`__
 
-- `Mediator Pattern <https://en.wikipedia.org/wiki/Mediator_pattern>`__
+- `Mediator pattern <https://en.wikipedia.org/wiki/Mediator_pattern>`__
 
 What for?
 ---------
 
-- Adding AI
-- Adding a custom asynchronous threads
-- Adding Input support
-- Adding writing threads
-- Adding custom VOIP protocol
-- etc.
+- Adding artificial intelligence.
+- Adding custom asynchronous threads.
+- Adding support for a new input device.
+- Adding writing threads.
+- Adding a custom VoIP protocol.
+- And more...
 
-Creating a Godot Server
+Creating a Godot server
 -----------------------
 
-At minimum, a server must to have: a static instance, sleep timer, thread loop, 
-initialize state, and cleanup. 
+At minimum, a server must have a static instance, a sleep timer, a thread loop,
+an initialization state and a cleanup procedure.
 
 .. code:: cpp
 
@@ -79,10 +78,10 @@ initialize state, and cleanup.
 	private:
 		uint64_t counter;
 		RID_Owner<InfiniteBus> bus_owner;
-		//https://github.com/godotengine/godot/blob/master/core/rid.h#L196
+		// https://github.com/godotengine/godot/blob/master/core/rid.h#L196
 		Set<RID> buses;
 		void _emit_occupy_room(uint64_t room, RID rid);
-		
+
 	public:
 		RID create_bus();
 		Variant get_bus_info(RID id);
@@ -92,8 +91,9 @@ initialize state, and cleanup.
 		void register_rooms();
 		HilbertHotel();
 	};
+
 	#endif
-	
+
 .. code:: cpp
 
 	#include "hilbert_hotel.h"
@@ -103,12 +103,13 @@ initialize state, and cleanup.
 	#include "dictionary.h"
 	#include "prime_225.h"
 
-	oid HilbertHotel::thread_func(void *p_udata){
-		HilbertHotel *ac = (HilbertHotel *) p_udata;
+	oid HilbertHotel::thread_func(void *p_udata) {
 
+		HilbertHotel *ac = (HilbertHotel *) p_udata;
 		uint64_t msdelay = 1000;
-		while(!ac -> exit_thread){
-			if(!ac -> empty()) {
+
+		while (!ac -> exit_thread) {
+			if (!ac -> empty()) {
 				ac->lock();
 				ac->register_rooms();
 				ac->unlock();
@@ -117,60 +118,81 @@ initialize state, and cleanup.
 		}
 	}
 
-	Error HilbertHotel::init(){
+	Error HilbertHotel::init() {
 		thread_exited = false;
 		counter = 0;
 		mutex = Mutex::create();
 		thread = Thread::create(HilbertHotel::thread_func, this);
 		return OK;
 	}
+
 	HilbertHotel *HilbertHotel::singleton = NULL;
-	HilbertHotel *HilbertHotel::get_singleton() { return singleton; }
+
+	HilbertHotel *HilbertHotel::get_singleton() {
+		return singleton;
+	}
+
 	void HilbertHotel::register_rooms() {
-		for( Set<RID>::Element *e = buses.front(); e; e = e->next()) {
+		for (Set<RID>::Element *e = buses.front(); e; e = e->next()) {
 			auto bus = bus_owner.getornull(e->get());
-			if(bus){
+
+			if (bus) {
 				uint64_t room = bus->next_room();
 				_emit_occupy_room(room, bus->get_self());
-			}	
+			}
 		}
 	}
 
 	void HilbertHotel::unlock() {
-		if (!thread || !mutex)
+		if (!thread || !mutex) {
 			return;
+		}
+
 		mutex->unlock();
 	}
+
 	void HilbertHotel::lock() {
-		if (!thread || !mutex)
+		if (!thread || !mutex) {
 			return;
+		}
+
 		mutex->lock();
 	}
+
 	void HilbertHotel::_emit_occupy_room(uint64_t room, RID rid) {
 		_HilbertHotel::get_singleton()->_occupy_room(room, rid);
 	}
+
 	Variant HilbertHotel::get_bus_info(RID id){
 		InfiniteBus * bus = bus_owner.getornull(id);
-		if(bus){
+
+		if (bus) {
 			Dictionary d;
 			d["prime"] = bus->get_bus_num();
 			d["current_room"] = bus->get_current_room();
 			return d;
 		}
+
 		return Variant();
 	}
+
 	void HilbertHotel::finish() {
-		if (!thread)
+		if (!thread) {
 			return;
+		}
 
 		exit_thread = true;
 		Thread::wait_to_finish(thread);
-		
+
 		memdelete(thread);
-		if (mutex)
+
+		if (mutex) {
 			memdelete(mutex);
+		}
+
 		thread = NULL;
 	}
+
 	RID HilbertHotel::create_bus() {
 		lock();
 		InfiniteBus *ptr = memnew(InfiniteBus(PRIME[counter++]));
@@ -178,9 +200,11 @@ initialize state, and cleanup.
 		ptr->set_self(ret);
 		buses.insert(ret);
 		unlock();
+
 		return ret;
 	}
-	//https://github.com/godotengine/godot/blob/master/core/rid.h#L187
+
+	// https://github.com/godotengine/godot/blob/master/core/rid.h#L187
 	bool HilbertHotel::delete_bus(RID id) {
 		if (bus_owner.owns(id)) {
 			lock();
@@ -191,17 +215,20 @@ initialize state, and cleanup.
 			unlock();
 			return true;
 		}
+
 		return false;
 	}
+
 	void HilbertHotel::clear() {
-		
-		for( Set<RID>::Element *e = buses.front(); e; e = e->next()) {
+		for (Set<RID>::Element *e = buses.front(); e; e = e->next()) {
 			delete_bus(e->get());
 		}
 	}
+
 	bool HilbertHotel::empty() {
 		return buses.size() <= 0;
 	}
+
 	void HilbertHotel::_bind_methods() {
 	}
 
@@ -209,12 +236,12 @@ initialize state, and cleanup.
 		singleton = this;
 	}
 
-	
 .. code:: cpp
-	
+
 	/* prime_225.h */
-	
+
 	#include "int_types.h"
+
 	const uint64_t PRIME[225] = {2,3,5,7,11,13,17,19,23,
 	29,31,37,41,43,47,53,59,61,
 	67,71,73,79,83,89,97,101,103,
@@ -240,14 +267,14 @@ initialize state, and cleanup.
 	1217,1223,1229,1231,1237,1249,1259,1277,1279,
 	1283,1289,1291,1297,1301,1303,1307,1319,1321,
 	1327,1361,1367,1373,1381,1399,1409,1423,1427};
-	
-Custom Managed Resource Data
+
+Custom managed resource data
 ----------------------------
 
-Godot servers implement a mediator pattern. All data types inherit ``RID_Data``. 
-`RID_Owner<MyRID_Data>`` owns the object when ``make_rid`` is called. Only during debug mode, 
-RID_Owner maintains a list of RID. In practice, RID is similar to writing 
-object oriented C code.
+Godot servers implement a mediator pattern. All data types inherit ``RID_Data``.
+``RID_Owner<MyRID_Data>`` owns the object when ``make_rid`` is called. During debug mode only,
+RID_Owner maintains a list of RIDs. In practice, RIDs are similar to writing
+object-oriented C code.
 
 .. code:: cpp
 
@@ -262,39 +289,46 @@ object oriented C code.
 		uint64_t next_room() {
 			return prime_num * num++;
 		}
+
 		uint64_t get_bus_num() const {
 			return prime_num;
 		}
+
 		uint64_t get_current_room() const {
 			return prime_num * num;
 		}
-		_FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
-		_FORCE_INLINE_ RID get_self() const { return self; }
+
+		_FORCE_INLINE_ void set_self(const RID &p_self) {
+			self = p_self;
+		}
+
+		_FORCE_INLINE_ RID get_self() const {
+			return self;
+		}
 
 		InfiniteBus(uint64_t prime) : prime_num(prime), num(1) {};
 		~InfiniteBus() {};
 	}
-	
-References:
+
+References
 ~~~~~~~~~~~
 
 - :ref:`RID<class_rid>`
 - `core/rid.h <https://github.com/godotengine/godot/blob/master/core/rid.h>`__
 
-
-Registering the class to GDScript
+Registering the class in GDScript
 ---------------------------------
 
-Server are allocated in ``register_types.cpp``. The constructor sets the static
-instance and init creates the managed thread. ``unregister_types.cpp``
-cleans up the server
+Servers are allocated in ``register_types.cpp``. The constructor sets the static
+instance and ``init()`` creates the managed thread; ``unregister_types.cpp``
+cleans up the server.
 
-Since Godot Server class creates an instance and binds it to a static singleton,
-binding the class might not reference the correct instance. Therefore, a dummy 
-class must be created to reference the proper Godot Server.
-
-In ``register_godotserver_types()``, ``Engine::get_singleton()->add_singleton`` is used to register the dummy class to GDScript.
+Since a Godot server class creates an instance and binds it to a static singleton,
+binding the class might not reference the correct instance. Therefore, a dummy
+class must be created to reference the proper Godot server.
 
+In ``register_server_types()``, ``Engine::get_singleton()->add_singleton``
+is used to register the dummy class in GDScript.
 
 .. code:: cpp
 
@@ -308,39 +342,39 @@ In ``register_godotserver_types()``, ``Engine::get_singleton()->add_singleton``
 	static HilbertHotel *hilbert_hotel = NULL;
 	static _HilbertHotel *_hilbert_hotel = NULL;
 
-
 	void register_hilbert_hotel_types() {
-			hilbert_hotel = memnew(HilbertHotel);
-			hilbert_hotel->init();
-			_hilbert_hotel = memnew(_HilbertHotel);
-			ClassDB::register_class<_HilbertHotel>();
-			Engine::get_singleton()->add_singleton(Engine::Singleton("HilbertHotel", _HilbertHotel::get_singleton()));
+		hilbert_hotel = memnew(HilbertHotel);
+		hilbert_hotel->init();
+		_hilbert_hotel = memnew(_HilbertHotel);
+		ClassDB::register_class<_HilbertHotel>();
+		Engine::get_singleton()->add_singleton(Engine::Singleton("HilbertHotel", _HilbertHotel::get_singleton()));
 	}
 
 	void unregister_hilbert_hotel_types() {
-			if(hilbert_hotel){
-					hilbert_hotel->finish();
-					memdelete(hilbert_hotel);
-			}
-			if(_hilbert_hotel) {
-					memdelete(_hilbert_hotel);
-			}
+		if (hilbert_hotel) {
+			hilbert_hotel->finish();
+			memdelete(hilbert_hotel);
+		}
+
+		if (_hilbert_hotel) {
+			memdelete(_hilbert_hotel);
+		}
 	}
 
 .. code:: cpp
 
 	/* register_types.h */
+
+	/* Yes, the word in the middle must be the same as the module folder name */
 	void register_hilbert_hotel_types();
 	void unregister_hilbert_hotel_types();
-	/* yes, the word in the middle must be the same as the module folder name */
-
 
 - `servers/register_server_types.cpp <https://github.com/godotengine/godot/blob/master/servers/register_server_types.cpp>`__
 
-Bind methods 
+Bind methods
 ~~~~~~~~~~~~
 
-The dummy class binds singleton methods to gdscript. In most cases, the dummy class methods wraps around.
+The dummy class binds singleton methods to GDScript. In most cases, the dummy class methods wraps around.
 
 .. code:: cpp
 
@@ -350,7 +384,7 @@ The dummy class binds singleton methods to gdscript. In most cases, the dummy cl
 
 Binding Signals
 
-It is possible to emit signals to gdscript but calling the GDScript dummy object.
+It is possible to emit signals to GDScript but calling the GDScript dummy object.
 
 .. code:: cpp
 
@@ -362,7 +396,7 @@ It is possible to emit signals to gdscript but calling the GDScript dummy object
 
 	class _HilbertHotel : public Object {
 		GDCLASS(_HilbertHotel, Object);
-		
+
 		friend class HilbertHotel;
 		static _HilbertHotel *singleton;
 
@@ -371,19 +405,20 @@ It is possible to emit signals to gdscript but calling the GDScript dummy object
 
 	private:
 		void _occupy_room(int room_number, RID bus);
-		
+
 	public:
 		RID create_bus();
 		void connect_singals();
 		bool delete_bus(RID id);
 		static _HilbertHotel *get_singleton();
 		Variant get_bus_info(RID id);
-		
+
 		_HilbertHotel();
 		~_HilbertHotel();
 	};
+
 	#endif
-	
+
 .. code:: cpp
 
 	_HilbertHotel *_HilbertHotel::singleton = NULL;
@@ -392,38 +427,45 @@ It is possible to emit signals to gdscript but calling the GDScript dummy object
 	RID _HilbertHotel::create_bus() {
 		return HilbertHotel::get_singleton()->create_bus();
 	}
+
 	bool _HilbertHotel::delete_bus(RID rid) {
 		return HilbertHotel::get_singleton()->delete_bus(rid);
 	}
+
 	void _HilbertHotel::_occupy_room(int room_number, RID bus){
 		emit_signal("occupy_room", room_number, bus);
 	}
+
 	Variant _HilbertHotel::get_bus_info(RID id) {
 		return HilbertHotel::get_singleton()->get_bus_info(id);
 	}
+
 	void _HilbertHotel::_bind_methods() {
 		ClassDB::bind_method(D_METHOD("get_bus_info", "r_id"), &_HilbertHotel::get_bus_info);
 		ClassDB::bind_method(D_METHOD("create_bus"), &_HilbertHotel::create_bus);
 		ClassDB::bind_method(D_METHOD("delete_bus"), &_HilbertHotel::delete_bus);
 		ADD_SIGNAL(MethodInfo("occupy_room", PropertyInfo(Variant::INT, "room_number"), PropertyInfo(Variant::_RID, "r_id")));
 	}
+
 	void _HilbertHotel::connect_singals() {
 		HilbertHotel::get_singleton()->connect("occupy_room", _HilbertHotel::get_singleton(), "_occupy_room");
 	}
+
 	_HilbertHotel::_HilbertHotel() {
 		singleton = this;
 	}
+
 	_HilbertHotel::~_HilbertHotel() {
 	}
-	
+
 MessageQueue
 ------------
 
-In order to send commands into scenetree, MessageQueue is a thread safe buffer 
-to queue set and call methods for other threads. To queue a command, obtain 
-the target object RID and use either push_call, push_set, or push_notification 
-to execute the desired behavior. Queue will be flushed whenever either 
-``SceneTree::idle`` or ``SceneTree::iteration`` are executed.
+In order to send commands into SceneTree, MessageQueue is a thread-safe buffer
+to queue set and call methods for other threads. To queue a command, obtain
+the target object RID and use either ``push_call``, ``push_set``, or ``push_notification``
+to execute the desired behavior. The queue will be flushed whenever either
+``SceneTree::idle`` or ``SceneTree::iteration`` is executed.
 
 References:
 ~~~~~~~~~~~
@@ -433,19 +475,13 @@ References:
 Summing it up
 -------------
 
-Here is the GDScript sample code
+Here is the GDScript sample code:
 
 .. code::
-	
-	extends Node
 
-	# class member variables go here, for example:
-	# var a = 2
-	# var b = "textvar"
+	extends Node
 
 	func _ready():
-		# Called when the node is added to the scene for the first time.
-		# Initialization here
 		print("start Debugging")
 		HilbertHotel.connect("occupy_room", self, "_print_occupy_room")
 		var rid = HilbertHotel.create_bus()
@@ -457,18 +493,13 @@ Here is the GDScript sample code
 		print(HilbertHotel.get_bus_info(rid))
 		HilbertHotel.delete_bus(rid)
 		print("ready done")
-		pass
-
-
 
 	func _print_occupy_room(room_number, r_id):
 		print("room_num: "  + str(room_number) + " rid: " + str(r_id))
 		print(HilbertHotel.get_bus_info(r_id))
-		
+
 Notes
 ~~~~~
 
-- Actual `Hilbert Hotel <https://en.wikipedia.org/wiki/Hilbert%27s_paradox_of_the_Grand_Hotel>`__ is impossible
-
-- Connecting signal example code is pretty hacky
-
+- The actual `Hilbert Hotel <https://en.wikipedia.org/wiki/Hilbert%27s_paradox_of_the_Grand_Hotel>`__ is impossible.
+- Connecting signal example code is pretty hacky.