Godot4 ノードの持つシグナルの名前と引数の数を得るスクリプトと使用例

無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4 で、ノードが持っている全てのシグナルの情報を受け取れる get_signal_list 関数の Array[Dictionary] 型の戻り値をメンバ変数に持ち、シグナル名や引数の数・名前などを取得するメンバ関数を持った自作のインナークラススクリプト実行結果を紹介します。

※ GodotEngine 4.3 を使用しています。.NET 版ではありません。
※スクリプトは自己責任でご使用ください。

前回の記事

前回は、Array[Dictionary] 型のデータにアクセスする、指定したキーの値と、指定したキーと値を持つ Dictionary 要素を、全て取得する2つの関数とテストコードの例を紹介しました。

シグナルのリストを取得する関数

ノードがもつシグナルのリストを取得する関数は、 Array[Dictionary] 型のデータを返します。

Array[Dictionaryget_signal_list() const 

Returns the list of existing signals as an Array of dictionaries.

Note: Due of the implementation, each Dictionary is formatted very similarly to the returned values of get_method_list.

既存の信号のリストを辞書の配列として返します。

注: 実装により、各ディクショナリは get_method_list の戻り値と非常によく似た形式になります。
Object — Godot Engine (4.x)の日本語のドキュメント #get_signal_list と Google 翻訳

戻り値のデータは、 get_method_list の戻り値と似ているので、こちらの説明を参考にしましょう。

Array[Dictionaryget_method_list() const 

Returns this object’s methods and their signatures as an Array of dictionaries. Each Dictionary contains the following entries:

  • name is the name of the method, as a String;
  • args is an Array of dictionaries representing the arguments;
  • default_args is the default arguments as an Array of variants;
  • flags is a combination of MethodFlags;
  • id is the method’s internal identifier int;
  • return is the returned value, as a Dictionary;

Note: The dictionaries of args and return are formatted identically to the results of get_property_list, although not all entries are used.

このオブジェクトのメソッドとそのシグネチャを辞書の配列として返します。各辞書には次のエントリが含まれます。

name はメソッドの名前 (文字列) です。

args は、引数を表す辞書の配列です。

default_args は、バリアントの配列としてのデフォルトの引数です。

flags は MethodFlags の組み合わせです。

id はメソッドの内部識別子 int です。

return は辞書としての戻り値です。

注: args と return のディクショナリは、すべてのエントリが使用されるわけではありませんが、get_property_list の結果と同じ形式になります。
Object — Godot Engine (4.x)の日本語のドキュメント #get_method_list と Google 翻訳

get_signal_list() の実際の戻り値

前述のとおり、get_signal_list 関数の戻り値は、get_method_list の戻り値に似ています。
以下は、Control ノードの get_signal_list 関数の戻り値print 出力したものです。

[{ "name": "resized", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "gui_input", "args": [{ "name": "event", "class_name": &"InputEvent", "type": 24, "hint": 17, "hint_string": "InputEvent", "usage": 6 }], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "mouse_entered", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "mouse_exited", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "focus_entered", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "focus_exited", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "size_flags_changed", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "minimum_size_changed", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "theme_changed", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "draw", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "visibility_changed", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "hidden", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "item_rect_changed", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "ready", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "renamed", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "tree_entered", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "tree_exiting", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "tree_exited", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "child_entered_tree", "args": [{ "name": "node", "class_name": &"Node", "type": 24, "hint": 0, "hint_string": "", "usage": 6 }], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "child_exiting_tree", "args": [{ "name": "node", "class_name": &"Node", "type": 24, "hint": 0, "hint_string": "", "usage": 6 }], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "child_order_changed", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "replacing_by", "args": [{ "name": "node", "class_name": &"Node", "type": 24, "hint": 0, "hint_string": "", "usage": 6 }], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "editor_description_changed", "args": [{ "name": "node", "class_name": &"Node", "type": 24, "hint": 0, "hint_string": "", "usage": 6 }], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "script_changed", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }, { "name": "property_list_changed", "args": [], "default_args": [], "flags": 1, "id": 0, "return": { "name": "", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 6 } }]

以下は、改行・タブ・カンマを用いて整形して print 出力したものです。
get_method_list の説明にあるように、 name, args, return などのキーを含む辞書が複数含まれた配列です。

[
	{
		"name": "resized",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "gui_input",
		"args": [
			{
				"name": "event",
				"class_name": &"InputEvent",
				"type": 24,
				"hint": 17,
				"hint_string": "InputEvent",
				"usage": 6
			}
		],
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "mouse_entered",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "mouse_exited",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "focus_entered",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "focus_exited",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "size_flags_changed",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "minimum_size_changed",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "theme_changed",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "draw",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "visibility_changed",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "hidden",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "item_rect_changed",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "ready",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "renamed",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "tree_entered",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "tree_exiting",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "tree_exited",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "child_entered_tree",
		"args": [
			{
				"name": "node",
				"class_name": &"Node",
				"type": 24,
				"hint": 0,
				"hint_string": "",
				"usage": 6
			}
		],
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "child_exiting_tree",
		"args": [
			{
				"name": "node",
				"class_name": &"Node",
				"type": 24,
				"hint": 0,
				"hint_string": "",
				"usage": 6
			}
		],
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "child_order_changed",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "replacing_by",
		"args": [
			{
				"name": "node",
				"class_name": &"Node",
				"type": 24,
				"hint": 0,
				"hint_string": "",
				"usage": 6
			}
		],
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "editor_description_changed",
		"args": [
			{
				"name": "node",
				"class_name": &"Node",
				"type": 24,
				"hint": 0,
				"hint_string": "",
				"usage": 6
			}
		],
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "script_changed",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	},
	{
		"name": "property_list_changed",
		"args": []
		"default_args": []
		"flags": 1,
		"id": 0,
		"return": {
			"name": "",
			"class_name": &"",
			"type": 0,
			"hint": 0,
			"hint_string": "",
			"usage": 6
		}
	}
]

整形する自作関数については、以下の記事を参照してください。

スクリプト

前述の get_signal_list 関数の戻り値のデータをメンバ変数に保持して、シグナルの名前や引数の数などを取得するメンバ関数を持ったインナークラスは以下です。

最初の2つの静的関数は、 Array[Dictionary] にアクセスする汎用関数です。
この二つの汎用関数については前回の記事を参照してください。

そのあとの SignalListInfo インナークラスです。
※詳細は、スクリプト内のコメントを参照してください。

例では、sc_util.gd というファイルに保存しています。
スクリプトファイルは、ファイルシステムドックの配置したいフォルダで右クリックして表示されるメニュー「新規作成」→「スクリプト」から作成できます。

extends Object
class_name ScUtil

## 辞書型の要素を持つ配列 [param array_dictionary] から、指定したキーの値を抽出して、配列 [param dest_array] に追加します。
## 指定したキーがない場合は何もしません。
static func get_array_dictionary_specified_key_values(array_dictionary: Array[Dictionary], key: StringName, dest_array: Array) -> void:
	for dictionary: Dictionary in array_dictionary:
		if dictionary.has(key) == true:
			dest_array.append(dictionary.get(key))
	return

## 辞書型の要素を持つ配列 [param array_dictionary] で、指定したキーと値を持つ辞書を抽出して、配列 [param dest_array] に追加します。
static func get_array_dictionary_matched_dictionary(array_dictionary: Array[Dictionary], key: StringName, value, dest_array: Array):
	for dictionary in array_dictionary:
		if dictionary.has(key) == true:
			var _value = dictionary.get(key)
			if _value != null and _value == value:
				dest_array.append(dictionary)
	return

## コンストラクタで渡されたオブジェクトの [method Object.get_signal_list] 関数で得られたシグナルのデータにアクセスしやすくするクラスです。
## RefCounted 派生で参照カウントがなくなると自動的に解放されるので free などの解放関数は呼ばないでください。
## [codeblock]
## extends Control
## func _ready():
##	# Control ノードの持つ全てのシグナルの名前を出力します。
## 	var signal_list_info := ScUtil.SignalListInfo.new(self)
## 	var signal_names: Array[StringName] = []
## 	signal_list_info.get_signal_names(signal_names)
## 	for signal_name in signal_names:
## 		print(signal_name)
## [/codeblock]
class SignalListInfo extends RefCounted:
	# [method Object.get_signal_list] 関数で得たシグナルの情報のリストです。
	var signal_list: Array[Dictionary]
	
	# シグナルの情報を得る対象を [param object] で指定して、本オブジェクトを構築します。
	func _init(object: Object):
		signal_list = object.get_signal_list()
		return
	
	## シグナル情報に含まれている全てのシグナル名を [param signal_names] に追加します。
	func get_signal_names(signal_names: Array):
		ScUtil.get_array_dictionary_specified_key_values(signal_list, "name", signal_names)
		return
	
	## [param signal_name] で指定したシグナルの持つ引数の情報の配列を [param args] に格納します。
	func get_signal_args(signal_name: StringName, args: Array[Dictionary]) -> void:
		# 複数のシグナル情報のリストから、指定した名前のシグナルの情報を取得します。
		var args_array_dictionarys: Array = []
		ScUtil.get_array_dictionary_matched_dictionary(signal_list, "name", signal_name, args_array_dictionarys)
		# 指定した名前を持つシグナルの情報は1つだけ見つかります。
		if args_array_dictionarys.size() != 1:
			push_error("ScSignalListInfo : args_array_dictionarys.size() != 1, size() = " + str(args_array_dictionarys.size()))
			return
		# 1つだけの要素を持つ配列から、その要素(辞書)を得ます。
		var args_array_dictionary: Dictionary = args_array_dictionarys[0]
		# シグナルの情報から args の値を取得します。
		if args_array_dictionary.has("args") == false:
			push_error("ScSignalListInfo : args_array_dictionarys.has(\"args\") == false")
			push_warning(ScUtil.to_pretty_print_string(args_array_dictionarys))
			return
		# args キーの値(Array[Dicitionary]) の配列の中にある辞書群を追加します。
		args.append_array(args_array_dictionary.get("args"))
		return
	
	## [param signal_name] で指定したシグナルの持つ引数の個数を返します。
	func get_signal_arg_count(signal_name: StringName) -> int:
		var args: Array[Dictionary]
		get_signal_args(signal_name, args)
		var count: int = args.size()
		return count
	
	## [param signal_name] で指定したシグナルの持つ全ての引数の名前を [param arg_names] に追加します。
	func get_signal_arg_names(signal_name: StringName, arg_names: Array):
		var args: Array[Dictionary]
		get_signal_args(signal_name, args)
		# args の値(辞書の配列)から引数の名前を持つ name キーの値を全て引数の配列 [param arg_names] に格納します。
		ScUtil.get_array_dictionary_specified_key_values(args, "name", arg_names)
		return

テスト

テスト用のシーンを作成して、そのルートノードにテスト用のスクリプトを割り当てて、そのスクリプト内でシグナルの情報を出力します。

メニュー「シーン」→「新規シーン」を選択して、シーンドックで「インターフェース」を選択して Control ルートノードのシーンを作成します。

ルートノードをリネーム(例では ScUtilTestScene)・選択して、右上の+ボタンの付いた「スクリプトをアタッチする」ボタンを押して、表示されたダイアログで gd スクリプトを作成して割り当てます。

Godot4 シグナル名と引数の数と名前を表示する関数の例2

割り当てたテスト用のスクリプトは以下で上書きします。

extends Control
class_name ScUtilTestScene

## sc_util.gd (ScUtil クラス) で定義されている関数やクラスを実際に使用するためのシーンです。

# Called when the node enters the scene tree for the first time.
func _ready():
	use_signal_list_info_1()
	return

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta):
	pass

## ScUtil.SignalListInfo オブジェクトを生成してノードの持つシグナルの名前と引数の数を取得・出力します。
func use_signal_list_info_1():
	var signal_list_info := ScUtil.SignalListInfo.new(self)
	# ノードの持っている全てのシグナルの名前を配列に取得します。
	var signal_names: Array[StringName] = []
	signal_list_info.get_signal_names(signal_names)
	# ノードが持っている全てのシグナルの名前と、その引数の数と引数名を取得して出力します。
	for signal_name in signal_names:
		var args_count: int = signal_list_info.get_signal_arg_count(signal_name)
		print("signal_name = %s, args_count = %s" % [signal_name, str(args_count)])
		# 引数があれば改行して名前を出力します。
		var arg_names: Array[StringName]
		signal_list_info.get_signal_arg_names(signal_name, arg_names)
		for arg_name in arg_names:
			print("\t%s" % arg_name)
	return

F6 キーでシーンを実行すると、出力ボトムパネルに、引数で渡したルートノード (Control) の持つシグナルの名前と引数の数、引数名が表示されました。

Godot4 シグナル名と引数の数と名前を表示する関数の例1
signal_name = resized, args_count = 0
signal_name = gui_input, args_count = 1
	event
signal_name = mouse_entered, args_count = 0
signal_name = mouse_exited, args_count = 0
signal_name = focus_entered, args_count = 0
signal_name = focus_exited, args_count = 0
signal_name = size_flags_changed, args_count = 0
signal_name = minimum_size_changed, args_count = 0
signal_name = theme_changed, args_count = 0
signal_name = draw, args_count = 0
signal_name = visibility_changed, args_count = 0
signal_name = hidden, args_count = 0
signal_name = item_rect_changed, args_count = 0
signal_name = ready, args_count = 0
signal_name = renamed, args_count = 0
signal_name = tree_entered, args_count = 0
signal_name = tree_exiting, args_count = 0
signal_name = tree_exited, args_count = 0
signal_name = child_entered_tree, args_count = 1
	node
signal_name = child_exiting_tree, args_count = 1
	node
signal_name = child_order_changed, args_count = 0
signal_name = replacing_by, args_count = 1
	node
signal_name = editor_description_changed, args_count = 1
	node
signal_name = script_changed, args_count = 0
signal_name = property_list_changed, args_count = 0

まとめ

今回は、無料・軽快な 2D / 3D 用のゲームエンジン Godot Engine 4 で、ノードが持っている全てのシグナルの情報を受け取れる get_signal_list 関数の Array[Dictionary] 型の戻り値をメンバ変数に持ち、シグナル名や引数の数・名前などを取得するメンバ関数を持った自作のインナークラススクリプト実行結果を紹介しました。

参照サイト Thank You!

記事一覧 → Compota-Soft-Press

コメント

Ads Blocker Image Powered by Code Help Pro

お願い - Ads Blocker Detected

このサイトは広告を掲載して運営しています。

ポップアップを閉じて閲覧できますが、よろしければ

このサイト内の広告を非表示にする拡張機能をオフにしていただけませんか?

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

We have detected that you are using extensions to block ads. Please support us by disabling these ads blocker.

タイトルとURLをコピーしました