瀏覽代碼

initialization

LanzaSchneider 1 年之前
當前提交
d0a35aa5b3
共有 7 個文件被更改,包括 300 次插入0 次删除
  1. 2 0
      .gitattributes
  2. 2 0
      .gitignore
  3. 0 0
      icon.svg
  4. 37 0
      icon.svg.import
  5. 162 0
      microserver.tscn
  6. 21 0
      project.godot
  7. 76 0
      test.tscn

+ 2 - 0
.gitattributes

@@ -0,0 +1,2 @@
+# Normalize EOL for all files that Git considers text files.
+* text=auto eol=lf

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+# Godot 4+ specific ignores
+.godot/

文件差異過大導致無法顯示
+ 0 - 0
icon.svg


+ 37 - 0
icon.svg.import

@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dcti4jbfioy8p"
+path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://icon.svg"
+dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false

+ 162 - 0
microserver.tscn

@@ -0,0 +1,162 @@
+[gd_scene load_steps=2 format=3 uid="uid://cdt4rn31xeo85"]
+
+[sub_resource type="GDScript" id="GDScript_r4hca"]
+script/source = "extends Node
+
+class Queue:
+	extends RefCounted
+	var _opaque:Array = []
+	var _mutex:Mutex = Mutex.new()
+	var _owner
+
+	func size() -> int:
+		var _size:int
+		_mutex.lock()
+		_size = _opaque.size()
+		_mutex.unlock()
+		return _size
+
+	func enqueue(val, check_exist:bool = false) -> bool:
+		_mutex.lock()
+		if (!check_exist || !_opaque.has(val)):
+			_opaque.push_back(val)
+		_mutex.unlock()
+		return true
+
+	func dequeue() -> Variant:
+		var ret = null
+		_mutex.lock()
+		ret = _opaque.pop_front()
+		_mutex.unlock()
+		return ret
+
+	func bind_owner(owner:Variant) -> void:
+		_mutex.lock()
+		_owner = owner
+		_mutex.unlock()
+
+	func get_owner() -> Variant:
+		var owner = null
+		_mutex.lock()
+		owner = _owner
+		_mutex.unlock()
+		return owner
+
+	func unbind_owner() -> void:
+		_mutex.lock()
+		_owner = null
+		_mutex.unlock()
+
+class Worker:
+	extends Thread
+	var should_working:bool
+	
+	func _main(global_mq:Queue):
+		print(\"Worker thread started [id: {0}]\".format([get_id()]))
+		while should_working:
+			var mq:Queue = global_mq.dequeue()
+			if null == mq:
+				OS.delay_msec(0)
+			else:
+				var msg = mq.dequeue()
+				if null == msg:
+					OS.delay_msec(0)
+				else:
+					var callback = mq.get_owner()
+					if null == callback:
+						continue
+					else:
+						callback.call(msg)
+				global_mq.enqueue(mq)
+		print(\"Worker thread stopped [id: {0}]\".format([get_id()]))
+
+	func start_working(owner) -> void:
+		should_working = true
+		start(Callable(self, '_main').bind(owner._global_mq))
+
+	func stop_working(wait:bool = true) -> void:
+		should_working = false
+		if wait:
+			wait_to_finish()
+
+const WORKER_AMOUNT_MIN:int = 1
+var WORKER_AMOUNT_MAX:int = OS.get_processor_count()
+
+var _should_running:bool = true
+var _global_mq:Queue = Queue.new()
+var _service_and_mq:Dictionary = {}
+var _workers:Array = []
+
+func _add_worker() -> void:
+	if _workers.size() >= WORKER_AMOUNT_MAX:
+		return
+	var worker:Worker = Worker.new()
+	worker.start_working(self)
+	_workers.push_back(worker)
+	print('worker count adjust to {0}'.format([_workers.size()]))
+
+func _kick_worker(worker:Worker) -> void:
+	worker.stop_working(false)
+	print('worker count adjust to {0}'.format([_workers.size()]))
+
+func start() -> void:
+	stop()
+	_should_running = true
+	check_workers()
+
+func stop() -> void:
+	_should_running = false
+	while _workers.size() > 0:
+		var worker:Worker = _workers.pop_back() as Worker
+		worker.stop_working()
+	while true:
+		var mq:Queue = _global_mq.dequeue() as Queue
+		if null == mq:
+			break
+	_service_and_mq.clear()
+
+func check_workers() -> void:
+	if !_should_running:
+		return
+	# TODO: remove dead workers
+	# check busy, and give more workers
+	if _global_mq.size() > 0: # maybe 1 ?
+		_add_worker()
+	# ensure min services
+	while _workers.size() < WORKER_AMOUNT_MIN:
+		_add_worker()
+	# release overamount services
+	while _workers.size() > WORKER_AMOUNT_MAX:
+		_kick_worker(_workers.pop_back() as Worker)
+
+func send_message(service_id:int, message) -> void:
+	var mq:Queue = instance_from_id(service_id) as Queue
+	mq.enqueue(message)
+
+func add_service(callback:Callable) -> int:
+	if _service_and_mq.has(callback):
+		return -1
+	var mq:Queue = Queue.new()
+	mq.bind_owner(callback)
+	_service_and_mq[callback] = mq
+	_global_mq.enqueue(mq)
+	return mq.get_instance_id()
+
+func remove_service(callback:Callable) -> bool:
+	if _service_and_mq.has(callback):
+		var mq:Queue = _service_and_mq[callback]
+		mq.unbind_owner()
+		_service_and_mq.erase(callback)
+		return true
+	return false
+"
+
+[node name="microserver" type="Node"]
+script = SubResource("GDScript_r4hca")
+
+[node name="thread_updator" type="Timer" parent="."]
+autostart = true
+
+[connection signal="tree_entered" from="." to="." method="start"]
+[connection signal="tree_exiting" from="." to="." method="stop"]
+[connection signal="timeout" from="thread_updator" to="." method="check_workers"]

+ 21 - 0
project.godot

@@ -0,0 +1,21 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+;   [section] ; section goes between []
+;   param=value ; assign values to parameters
+
+config_version=5
+
+[application]
+
+config/name="MicroServer"
+run/main_scene="res://test.tscn"
+config/features=PackedStringArray("4.0", "GL Compatibility")
+config/icon="res://icon.svg"
+
+[rendering]
+
+renderer/rendering_method="gl_compatibility"
+renderer/rendering_method.mobile="gl_compatibility"

+ 76 - 0
test.tscn

@@ -0,0 +1,76 @@
+[gd_scene load_steps=3 format=3 uid="uid://cvfeet1dqmpoe"]
+
+[ext_resource type="PackedScene" uid="uid://cdt4rn31xeo85" path="res://microserver.tscn" id="1_0r1oj"]
+
+[sub_resource type="GDScript" id="GDScript_loein"]
+script/source = "extends Node
+
+@export
+var server_path:NodePath
+
+var server
+
+var service_id_1:int
+var service_id_2:int
+
+const ECHO_FREQ:int = 4
+var echo:Thread
+
+func _ready():
+	server = get_node(server_path)
+	service_id_1 = server.add_service(callback_1)
+	service_id_2 = server.add_service(callback_2)
+	echo = Thread.new()
+	echo.start(func():
+		while server != null:
+			server.send_message(service_id_2, '')
+			OS.delay_msec(ECHO_FREQ)
+		)
+
+func _exit_tree():
+	server.remove_service(callback_1)
+	server.remove_service(callback_2)
+	server = null
+	echo.wait_to_finish()
+	echo = null
+
+func callback_1(message):
+	print('message received {0} by [thread: {1}]'.format([message, OS.get_thread_caller_id()]))
+
+var callback_2_counter:int
+var callback_2_tick:int = Time.get_ticks_msec()
+func callback_2(_message):
+	const COUNT:int = 250
+	callback_2_counter += 1
+	if callback_2_counter >= COUNT:
+		callback_2_counter = 0
+		print('processed {0} messages cost {1} ms (design: {2} ms)'.format([COUNT, Time.get_ticks_msec() - callback_2_tick, ECHO_FREQ * COUNT]))
+		callback_2_tick = Time.get_ticks_msec()
+
+func _on_button_button_up():
+	var message = 'click at {0} [thread: {1}]'.format([Time.get_time_string_from_system(), OS.get_thread_caller_id()])
+	server.send_message(service_id_1, message)
+
+func _on_timer_timeout():
+	var message = 'timer triggerd at {0} [thread: {1}]'.format([Time.get_time_string_from_system(), OS.get_thread_caller_id()])
+	server.send_message(service_id_1, message)
+"
+
+[node name="test" type="Node"]
+
+[node name="microserver" parent="." instance=ExtResource("1_0r1oj")]
+
+[node name="sub1" type="Node" parent="."]
+script = SubResource("GDScript_loein")
+server_path = NodePath("../microserver")
+
+[node name="Button" type="Button" parent="sub1"]
+offset_right = 8.0
+offset_bottom = 8.0
+text = "Send Message !"
+
+[node name="Timer" type="Timer" parent="sub1"]
+autostart = true
+
+[connection signal="button_up" from="sub1/Button" to="sub1" method="_on_button_button_up"]
+[connection signal="timeout" from="sub1/Timer" to="sub1" method="_on_timer_timeout"]

部分文件因文件數量過多而無法顯示