diff --git a/Global.gd b/Global.gd index 25eced2..67056ff 100644 --- a/Global.gd +++ b/Global.gd @@ -14,6 +14,7 @@ func AddInventoryItem(itemid, amount): if(player_inventory_items[x].item_id == itemid): print(str(player_inventory_items[x])) player_inventory_items[x].amount += amount + Database.SaveInventory(player_inventory_items) return #if we reached here then no exisiting item is found and we iterate the array again print("adding item") @@ -24,6 +25,8 @@ func AddInventoryItem(itemid, amount): player_inventory_items[x].shortdesc = "desc" player_inventory_items[x].item_id = itemid player_inventory_items[x].amount = amount + Database.SaveInventory(player_inventory_items) + return func GoToScene(scene): if current_scene != null: diff --git a/Menu.tscn b/Menu.tscn index a668ccd..09fa892 100644 --- a/Menu.tscn +++ b/Menu.tscn @@ -1,14 +1,16 @@ [gd_scene load_steps=7 format=2] -[ext_resource path="res://Menu.gd" type="Script" id=1] +[ext_resource path="res://MiscCodes/Menu.gd" type="Script" id=1] [ext_resource path="res://pictures/animations/Loading/loading_ring.png" type="Texture" id=2] [ext_resource path="res://MiscCodes/loading_ring.gd" type="Script" id=3] -[ext_resource path="res://ring_of_races_font.ttf" type="DynamicFontData" id=4] [ext_resource path="res://pictures/gui/backgrounds/treesbackground1.png" type="Texture" id=5] +[sub_resource type="DynamicFontData" id=2] +font_path = "res://ring_of_races_font.ttf" + [sub_resource type="DynamicFont" id=1] size = 30 -font_data = ExtResource( 4 ) +font_data = SubResource( 2 ) [node name="Main Menu" type="Node2D"] script = ExtResource( 1 ) diff --git a/MiscCodes/AnimationPlayer.gd b/MiscCodes/AnimationPlayer.gd new file mode 100644 index 0000000..e69de29 diff --git a/MiscCodes/KinematicBody2D.gd b/MiscCodes/KinematicBody2D.gd new file mode 100644 index 0000000..08dbaab --- /dev/null +++ b/MiscCodes/KinematicBody2D.gd @@ -0,0 +1,71 @@ +extends KinematicBody2D + +const GRAVITY = 0.0 +const WALK_SPEED = 200 +const interaction_circle_size = 150 +onready var background_map = get_node("/root/Map1/background") +onready var player = get_node("/root/Map1/Player") +onready var cell_size = background_map._get_cell_size() +onready var plants_map = get_node("/root/Map1/interaction_map") +onready var interaction = get_node("/root/Map1/player_interaction") + +var velocity = Vector2() +var world_position + +#Moving buttons +func _physics_process(delta): + if Input.is_key_pressed(KEY_SPACE) or Input.is_mouse_button_pressed(BUTTON_LEFT): + _interaction_process() + velocity.y += delta * GRAVITY + if Input.is_action_pressed("move_left"): + velocity.x = -WALK_SPEED + elif Input.is_action_pressed("move_right"): + velocity.x = WALK_SPEED + elif Input.is_action_pressed("move_up"): + velocity.y = -WALK_SPEED + elif Input.is_action_pressed("move_down"): + velocity.y = WALK_SPEED + else: + velocity.x = 0 + velocity.y = 0 + move_and_slide(velocity, Vector2(0, -1)) + Global.current_camera.Update() +# if(interaction.get_cell(int(self.position.x / cell_size.x), int(self.position.y / cell_size.y)) == -1): +# interaction.clear() +# interaction.set_cell(int(self.position.x / cell_size.x), int(self.position.y / cell_size.y), 0) + +func InteractWithCell(): + var plant_cell_mouse = plants_map.get_cell(int(world_position[0] / cell_size.x), int(world_position[1] / cell_size.y)) + var plant_cell_character = plants_map.get_cell(int(self.position.x / cell_size.x), int(self.position.y / cell_size.y)) + + var background_cell = background_map.get_cell(int(world_position[0] / cell_size.x), int(world_position[1] / cell_size.y)) + var interaction_cell = interaction.get_cell(int(world_position[0] / cell_size.x), int(world_position[1] / cell_size.y)) + if plant_cell_mouse > 0 and plant_cell_mouse % 2 == 0: + Global.AddInventoryItem(3, 1) + plants_map.set_cell(int(world_position[0] / cell_size.x), int(world_position[1] / cell_size.y), (plant_cell_mouse-1)) + AnimationOnInteraction(1) + elif plant_cell_character > 0 and plant_cell_character % 2 == 0: + Global.AddInventoryItem(3, 1) + plants_map.set_cell(int(self.position.x / cell_size.x), int(self.position.y / cell_size.y), (plant_cell_character-1)) + AnimationOnInteraction(1) + +func _interaction_process(): + if Input.is_key_pressed(KEY_SPACE) or Input.is_mouse_button_pressed(BUTTON_LEFT): + world_position = get_global_mouse_position() + InteractWithCell() + +func _input(event): + pass + +func AnimationOnInteraction(Item): + print("Item = ", Item, " Animation") + var itemimage = TextureRect.new() + itemimage.texture = load("res://pictures/inventory_iconpictures/food_items/herbs/saffron.png") + itemimage.set_position(Vector2(randf()*20-40, randf()*40-20)) + add_child(itemimage) + yield(get_tree().create_timer(1.0), "timeout") + remove_child(itemimage) + +func _ready(): + Global.player_inventory_items = Database.GetInventoryItems() + diff --git a/MiscCodes/Menu.gd b/MiscCodes/Menu.gd new file mode 100644 index 0000000..41fc6a5 --- /dev/null +++ b/MiscCodes/Menu.gd @@ -0,0 +1,9 @@ +extends Node2D + +func _ready(): + pass # Replace with function body. + +func _on_Btn_PlayGame_pressed(): + Global.LoadSave() + Global.GoToScene("river_intersection_home_2") + diff --git a/MiscCodes/Menu_Buttons.gd b/MiscCodes/Menu_Buttons.gd new file mode 100644 index 0000000..5e08f24 --- /dev/null +++ b/MiscCodes/Menu_Buttons.gd @@ -0,0 +1,16 @@ +extends Button + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/MiscCodes/Menu_PlayGame.gd b/MiscCodes/Menu_PlayGame.gd new file mode 100644 index 0000000..bda25cc --- /dev/null +++ b/MiscCodes/Menu_PlayGame.gd @@ -0,0 +1,27 @@ +extends Button + + +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + + +# Called when the node enters the scene tree for the first time. +func _ready(): + + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass + + + +func _on_Button_gui_input(event): + print(event) + if event == InputEventScreenTouch.CONNECT_ONESHOT: + get_tree().change_scene("res://river_intersection_home2.tscn") + + # get_tree().change_scene("res://river_intersection_home2.tscn") + pass # Replace with function body. diff --git a/MiscCodes/MiscButtons.gd b/MiscCodes/MiscButtons.gd new file mode 100644 index 0000000..cc9a950 --- /dev/null +++ b/MiscCodes/MiscButtons.gd @@ -0,0 +1,14 @@ +extends TouchScreenButton + +#func _input(always): +func _physics_process(delta): + if Input.is_action_pressed("move_left") and Input.is_action_pressed("move_right"): + show() + elif Input.is_action_pressed("ui_end"): + hide() + + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/MiscCodes/Tilemap_CameraView.gd b/MiscCodes/Tilemap_CameraView.gd new file mode 100644 index 0000000..7970bbb --- /dev/null +++ b/MiscCodes/Tilemap_CameraView.gd @@ -0,0 +1,77 @@ +extends Camera2D + + +onready var player = get_node("/root/Map1/Player") +onready var background_map = get_node("/root/Map1/background") +onready var screen_size = self.get_viewport_rect().size + +func _ready(): + calculate_bounds() + Global.current_camera = self + $dev_statistics.visible = Global.dev_stats + +var once = true +var lockedPlayerCamera = false +var min_x = 0 +var min_y = 0 +var max_x = 0 +var max_y = 0 +var max_x_pixel = 0 +var max_y_pixel = 0 + +#function that calculates the borders/bounds of the map +func calculate_bounds(): + var used_cells = background_map.get_used_cells() + for pos in used_cells: + if pos.x < min_x: + min_x = int(pos.x) + elif pos.x > max_x: + max_x = int(pos.x) + if pos.y < min_y: + min_y = int(pos.y) + elif pos.y > max_y: + max_y = int(pos.y) + print(min_x,"-",max_x, " AND " ,min_y , "-" , max_y) + max_x_pixel = (max_x * 32) + max_y_pixel = (max_y * 32) + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta): + if(Global.dev_stats): + $dev_statistics/fps_stats.text = "FPS: " + str(Performance.get_monitor(Performance.TIME_FPS)) + CameraToPlayer() + if once: + once = false + #AnimateMoveCamera(player.position, Vector2(player.position.x - 100,player.position.y - 10), "position", 2) + pass + +func get_global_pos(): + return Vector2(position.x, position.y) + +#Move camera to position +func MoveCamera(x, y): + if x < int(screen_size.x / 2): + pass + else: + position.x = x + if y < int(screen_size.y / 2): + pass + else: + position.y = y + +func _on_Tween_tween_completed(object, key): + print(object, key) + lockedPlayerCamera = false + +func AnimateMoveCamera(source, destination, key, time): + var tween = get_node("/root/Map1/Tween") + lockedPlayerCamera = true + tween.interpolate_property(get_node("/root/Map1/Camera2D"), key, source, destination, time, Tween.TRANS_LINEAR, Tween.EASE_IN_OUT) + tween.start() + +func CameraToPlayer(): + if lockedPlayerCamera == false: + MoveCamera(player.position.x, player.position.y) + +func Update(): + CameraToPlayer() diff --git a/MiscCodes/TouchScreenButton.gd b/MiscCodes/TouchScreenButton.gd new file mode 100644 index 0000000..05fcf91 --- /dev/null +++ b/MiscCodes/TouchScreenButton.gd @@ -0,0 +1,6 @@ +extends TouchScreenButton + +onready var ShowInventory = Global.ShowInventory + +func _input(always): + ShowInventory = 1; diff --git a/MiscCodes/background_script.gd b/MiscCodes/background_script.gd new file mode 100644 index 0000000..61eb943 --- /dev/null +++ b/MiscCodes/background_script.gd @@ -0,0 +1,20 @@ +extends TileMap + +onready var player = get_node("/root/Map1/Player") + +func _ready(): + pass # Replace with function body. + +func _get_cell_size(): + return cell_size + +func _unhandled_input(event): + var pl_pos = player.position + var pl_pos_tile = Vector2(pl_pos.x / cell_size.x, pl_pos.y / cell_size.y) + var pl_tile = get_cellv(pl_pos_tile) + if event == Input.action_press("map_interaction"): + if(pl_tile != -1): + set_cellv(pl_pos_tile, -1) + +func _on_Inventory_pressed(): + Global.GoToScene("inventory_screen") diff --git a/MiscScenes/Control.tscn b/MiscScenes/Control.tscn new file mode 100644 index 0000000..f74fd5e --- /dev/null +++ b/MiscScenes/Control.tscn @@ -0,0 +1,19 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://arrow_down.png" type="Texture" id=1] + +[sub_resource type="GradientTexture" id=1] + +[node name="Control" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="TouchScreenButton" type="TouchScreenButton" parent="."] +position = Vector2( 890.674, 223.37 ) +scale = Vector2( 4.01662, 3.80615 ) +normal = ExtResource( 1 ) +pressed = SubResource( 1 ) +action = "ui_right" diff --git a/Other/Planten.tres b/Other/Planten.tres new file mode 100644 index 0000000..26989cb --- /dev/null +++ b/Other/Planten.tres @@ -0,0 +1,3 @@ +[gd_resource type="TileSet" format=2] + +[resource] diff --git a/Other/Planten.tsx b/Other/Planten.tsx new file mode 100644 index 0000000..a4789ae --- /dev/null +++ b/Other/Planten.tsx @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Other/Planten.tsx.import b/Other/Planten.tsx.import new file mode 100644 index 0000000..3d8c19f --- /dev/null +++ b/Other/Planten.tsx.import @@ -0,0 +1,18 @@ +[remap] + +importer="vnen.tiled_tileset_importer" +type="TileSet" +valid=false + +[deps] + +source_file="res://Other/Planten.tsx" +[params] + +custom_properties=true +tile_metadata=false +image_flags=7 +embed_internal_images=false +save_tiled_properties=false +apply_offset=false +post_import_script="" diff --git a/Other/Plants.tres b/Other/Plants.tres new file mode 100644 index 0000000..841c0f3 --- /dev/null +++ b/Other/Plants.tres @@ -0,0 +1,182 @@ +[gd_resource type="TileSet" load_steps=2 format=2] + +[ext_resource path="res://pictures/tileset_images/Plants.png" type="Texture" id=1] + + + +[resource] +0/name = "Plants.png 0" +0/texture = ExtResource( 1 ) +0/tex_offset = Vector2( 0, 0 ) +0/modulate = Color( 1, 1, 1, 1 ) +0/region = Rect2( 32, 0, 32, 32 ) +0/tile_mode = 2 +0/autotile/icon_coordinate = Vector2( 0, 0 ) +0/autotile/tile_size = Vector2( 32, 32 ) +0/autotile/spacing = 0 +0/autotile/occluder_map = [ ] +0/autotile/navpoly_map = [ ] +0/autotile/priority_map = [ Vector3( 1, 0, 2 ) ] +0/autotile/z_index_map = [ Vector3( 0, 0, 1 ), Vector3( 1, 0, 1 ), Vector3( 2, 0, 2 ) ] +0/occluder_offset = Vector2( 0, 0 ) +0/navigation_offset = Vector2( 0, 0 ) +0/shape_offset = Vector2( 0, 0 ) +0/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +0/shape_one_way = false +0/shape_one_way_margin = 0.0 +0/shapes = [ ] +0/z_index = 0 +1/name = "Plants.png 1" +1/texture = ExtResource( 1 ) +1/tex_offset = Vector2( 0, 0 ) +1/modulate = Color( 1, 1, 1, 1 ) +1/region = Rect2( 32, 0, 32, 32 ) +1/tile_mode = 0 +1/occluder_offset = Vector2( 0, 0 ) +1/navigation_offset = Vector2( 0, 0 ) +1/shape_offset = Vector2( 0, 0 ) +1/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +1/shape_one_way = false +1/shape_one_way_margin = 0.0 +1/shapes = [ ] +1/z_index = 0 +2/name = "Plants.png 2" +2/texture = ExtResource( 1 ) +2/tex_offset = Vector2( 0, 0 ) +2/modulate = Color( 1, 1, 1, 1 ) +2/region = Rect2( 64, 0, 32, 32 ) +2/tile_mode = 0 +2/occluder_offset = Vector2( 0, 0 ) +2/navigation_offset = Vector2( 0, 0 ) +2/shape_offset = Vector2( 0, 0 ) +2/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +2/shape_one_way = false +2/shape_one_way_margin = 0.0 +2/shapes = [ ] +2/z_index = 0 +3/name = "Plants.png 3" +3/texture = ExtResource( 1 ) +3/tex_offset = Vector2( 0, 0 ) +3/modulate = Color( 1, 1, 1, 1 ) +3/region = Rect2( 96, 0, 32, 32 ) +3/tile_mode = 0 +3/occluder_offset = Vector2( 0, 0 ) +3/navigation_offset = Vector2( 0, 0 ) +3/shape_offset = Vector2( 0, 0 ) +3/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +3/shape_one_way = false +3/shape_one_way_margin = 0.0 +3/shapes = [ ] +3/z_index = 0 +4/name = "Plants.png 4" +4/texture = ExtResource( 1 ) +4/tex_offset = Vector2( 0, 0 ) +4/modulate = Color( 1, 1, 1, 1 ) +4/region = Rect2( 0, 0, 32, 32 ) +4/tile_mode = 0 +4/occluder_offset = Vector2( 0, 0 ) +4/navigation_offset = Vector2( 0, 0 ) +4/shape_offset = Vector2( 0, 0 ) +4/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +4/shape_one_way = false +4/shape_one_way_margin = 0.0 +4/shapes = [ ] +4/z_index = 0 +5/name = "Plants.png 5" +5/texture = ExtResource( 1 ) +5/tex_offset = Vector2( 0, 0 ) +5/modulate = Color( 1, 1, 1, 1 ) +5/region = Rect2( 128, 0, 32, 32 ) +5/tile_mode = 0 +5/occluder_offset = Vector2( 0, 0 ) +5/navigation_offset = Vector2( 0, 0 ) +5/shape_offset = Vector2( 0, 0 ) +5/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +5/shape_one_way = false +5/shape_one_way_margin = 0.0 +5/shapes = [ ] +5/z_index = 0 +6/name = "Plants.png 6" +6/texture = ExtResource( 1 ) +6/tex_offset = Vector2( 0, 0 ) +6/modulate = Color( 1, 1, 1, 1 ) +6/region = Rect2( 160, 0, 32, 32 ) +6/tile_mode = 0 +6/occluder_offset = Vector2( 0, 0 ) +6/navigation_offset = Vector2( 0, 0 ) +6/shape_offset = Vector2( 0, 0 ) +6/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +6/shape_one_way = false +6/shape_one_way_margin = 0.0 +6/shapes = [ ] +6/z_index = 0 +7/name = "Plants.png 7" +7/texture = ExtResource( 1 ) +7/tex_offset = Vector2( 0, 0 ) +7/modulate = Color( 1, 1, 1, 1 ) +7/region = Rect2( 192, 0, 32, 32 ) +7/tile_mode = 0 +7/occluder_offset = Vector2( 0, 0 ) +7/navigation_offset = Vector2( 0, 0 ) +7/shape_offset = Vector2( 0, 0 ) +7/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +7/shape_one_way = false +7/shape_one_way_margin = 0.0 +7/shapes = [ ] +7/z_index = 0 +8/name = "Plants.png 8" +8/texture = ExtResource( 1 ) +8/tex_offset = Vector2( 0, 0 ) +8/modulate = Color( 1, 1, 1, 1 ) +8/region = Rect2( 224, 0, 32, 32 ) +8/tile_mode = 0 +8/occluder_offset = Vector2( 0, 0 ) +8/navigation_offset = Vector2( 0, 0 ) +8/shape_offset = Vector2( 0, 0 ) +8/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +8/shape_one_way = false +8/shape_one_way_margin = 0.0 +8/shapes = [ ] +8/z_index = 0 +9/name = "Plants.png 9" +9/texture = ExtResource( 1 ) +9/tex_offset = Vector2( 0, 0 ) +9/modulate = Color( 1, 1, 1, 1 ) +9/region = Rect2( 256, 0, 32, 32 ) +9/tile_mode = 0 +9/occluder_offset = Vector2( 0, 0 ) +9/navigation_offset = Vector2( 0, 0 ) +9/shape_offset = Vector2( 0, 0 ) +9/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +9/shape_one_way = false +9/shape_one_way_margin = 0.0 +9/shapes = [ ] +9/z_index = 0 +10/name = "Plants.png 10" +10/texture = ExtResource( 1 ) +10/tex_offset = Vector2( 0, 0 ) +10/modulate = Color( 1, 1, 1, 1 ) +10/region = Rect2( 288, 0, 32, 32 ) +10/tile_mode = 0 +10/occluder_offset = Vector2( 0, 0 ) +10/navigation_offset = Vector2( 0, 0 ) +10/shape_offset = Vector2( 0, 0 ) +10/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +10/shape_one_way = false +10/shape_one_way_margin = 0.0 +10/shapes = [ ] +10/z_index = 0 +11/name = "Plants.png 11" +11/texture = ExtResource( 1 ) +11/tex_offset = Vector2( 0, 0 ) +11/modulate = Color( 1, 1, 1, 1 ) +11/region = Rect2( 320, 0, 32, 32 ) +11/tile_mode = 0 +11/occluder_offset = Vector2( 0, 0 ) +11/navigation_offset = Vector2( 0, 0 ) +11/shape_offset = Vector2( 0, 0 ) +11/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +11/shape_one_way = false +11/shape_one_way_margin = 0.0 +11/shapes = [ ] +11/z_index = 0 diff --git a/Other/Vloer.tres b/Other/Vloer.tres new file mode 100644 index 0000000..9708ad5 --- /dev/null +++ b/Other/Vloer.tres @@ -0,0 +1,202 @@ +[gd_resource type="TileSet" load_steps=2 format=2] + +[ext_resource path="res://omgeving/vloer32x32/TilesetGodotVloer.png" type="Texture" id=1] + +[resource] +0/name = "Vloer 0" +0/texture = ExtResource( 1 ) +0/tex_offset = Vector2( 0, 0 ) +0/modulate = Color( 1, 1, 1, 1 ) +0/region = Rect2( 0, 0, -1, -1 ) +0/tile_mode = 2 +0/autotile/icon_coordinate = Vector2( 0, 0 ) +0/autotile/tile_size = Vector2( 32, 32 ) +0/autotile/spacing = 0 +0/autotile/occluder_map = [ ] +0/autotile/navpoly_map = [ ] +0/autotile/priority_map = [ ] +0/autotile/z_index_map = [ ] +0/occluder_offset = Vector2( 0, 0 ) +0/navigation_offset = Vector2( 0, 0 ) +0/shape_offset = Vector2( 0, 0 ) +0/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +0/shape_one_way = false +0/shape_one_way_margin = 0.0 +0/shapes = [ ] +0/z_index = 0 +1/name = "TilesetGodotVloer.png 1" +1/texture = ExtResource( 1 ) +1/tex_offset = Vector2( 0, 0 ) +1/modulate = Color( 1, 1, 1, 1 ) +1/region = Rect2( -32, 0, 32, 32 ) +1/tile_mode = 1 +1/autotile/bitmask_mode = 0 +1/autotile/bitmask_flags = [ ] +1/autotile/icon_coordinate = Vector2( 0, 0 ) +1/autotile/tile_size = Vector2( 32, 32 ) +1/autotile/spacing = 0 +1/autotile/occluder_map = [ ] +1/autotile/navpoly_map = [ ] +1/autotile/priority_map = [ ] +1/autotile/z_index_map = [ ] +1/occluder_offset = Vector2( 0, 0 ) +1/navigation_offset = Vector2( 0, 0 ) +1/shape_offset = Vector2( 0, 0 ) +1/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +1/shape_one_way = false +1/shape_one_way_margin = 0.0 +1/shapes = [ ] +1/z_index = 0 +2/name = "TilesetGodotVloer.png 2" +2/texture = ExtResource( 1 ) +2/tex_offset = Vector2( 0, 0 ) +2/modulate = Color( 1, 1, 1, 1 ) +2/region = Rect2( 0, 0, 176, 176 ) +2/tile_mode = 1 +2/autotile/bitmask_mode = 0 +2/autotile/bitmask_flags = [ ] +2/autotile/icon_coordinate = Vector2( 0, 0 ) +2/autotile/tile_size = Vector2( 32, 32 ) +2/autotile/spacing = 0 +2/autotile/occluder_map = [ ] +2/autotile/navpoly_map = [ ] +2/autotile/priority_map = [ ] +2/autotile/z_index_map = [ ] +2/occluder_offset = Vector2( 0, 0 ) +2/navigation_offset = Vector2( 0, 0 ) +2/shape_offset = Vector2( 0, 0 ) +2/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +2/shape_one_way = false +2/shape_one_way_margin = 0.0 +2/shapes = [ ] +2/z_index = 0 +3/name = "TilesetGodotVloer.png 3" +3/texture = ExtResource( 1 ) +3/tex_offset = Vector2( 0, 0 ) +3/modulate = Color( 1, 1, 1, 1 ) +3/region = Rect2( 352, 0, 176, 176 ) +3/tile_mode = 1 +3/autotile/bitmask_mode = 0 +3/autotile/bitmask_flags = [ ] +3/autotile/icon_coordinate = Vector2( 0, 0 ) +3/autotile/tile_size = Vector2( 176, 176 ) +3/autotile/spacing = 0 +3/autotile/occluder_map = [ ] +3/autotile/navpoly_map = [ ] +3/autotile/priority_map = [ ] +3/autotile/z_index_map = [ ] +3/occluder_offset = Vector2( 0, 0 ) +3/navigation_offset = Vector2( 0, 0 ) +3/shape_offset = Vector2( 0, 0 ) +3/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +3/shape_one_way = false +3/shape_one_way_margin = 0.0 +3/shapes = [ ] +3/z_index = 0 +4/name = "TilesetGodotVloer.png 4" +4/texture = ExtResource( 1 ) +4/tex_offset = Vector2( 0, 0 ) +4/modulate = Color( 1, 1, 1, 1 ) +4/region = Rect2( 0, 0, 176, 176 ) +4/tile_mode = 1 +4/autotile/bitmask_mode = 0 +4/autotile/bitmask_flags = [ ] +4/autotile/icon_coordinate = Vector2( 0, 0 ) +4/autotile/tile_size = Vector2( 176, 176 ) +4/autotile/spacing = 0 +4/autotile/occluder_map = [ ] +4/autotile/navpoly_map = [ ] +4/autotile/priority_map = [ ] +4/autotile/z_index_map = [ ] +4/occluder_offset = Vector2( 0, 0 ) +4/navigation_offset = Vector2( 0, 0 ) +4/shape_offset = Vector2( 0, 0 ) +4/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +4/shape_one_way = false +4/shape_one_way_margin = 0.0 +4/shapes = [ ] +4/z_index = 0 +5/name = "TilesetGodotVloer.png 5" +5/texture = ExtResource( 1 ) +5/tex_offset = Vector2( 0, 0 ) +5/modulate = Color( 1, 1, 1, 1 ) +5/region = Rect2( 176, 0, 176, 176 ) +5/tile_mode = 0 +5/occluder_offset = Vector2( 0, 0 ) +5/navigation_offset = Vector2( 0, 0 ) +5/shape_offset = Vector2( 0, 0 ) +5/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +5/shape_one_way = false +5/shape_one_way_margin = 0.0 +5/shapes = [ ] +5/z_index = 0 +6/name = "TilesetGodotVloer.png 6" +6/texture = ExtResource( 1 ) +6/tex_offset = Vector2( 0, 0 ) +6/modulate = Color( 1, 1, 1, 1 ) +6/region = Rect2( 352, 0, 176, 176 ) +6/tile_mode = 0 +6/occluder_offset = Vector2( 0, 0 ) +6/navigation_offset = Vector2( 0, 0 ) +6/shape_offset = Vector2( 0, 0 ) +6/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +6/shape_one_way = false +6/shape_one_way_margin = 0.0 +6/shapes = [ ] +6/z_index = 0 +7/name = "TilesetGodotVloer.png 7" +7/texture = ExtResource( 1 ) +7/tex_offset = Vector2( 0, 0 ) +7/modulate = Color( 1, 1, 1, 1 ) +7/region = Rect2( 528, 0, 176, 176 ) +7/tile_mode = 0 +7/occluder_offset = Vector2( 0, 0 ) +7/navigation_offset = Vector2( 0, 0 ) +7/shape_offset = Vector2( 0, 0 ) +7/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +7/shape_one_way = false +7/shape_one_way_margin = 0.0 +7/shapes = [ ] +7/z_index = 0 +8/name = "TilesetGodotVloer.png 8" +8/texture = ExtResource( 1 ) +8/tex_offset = Vector2( 0, 0 ) +8/modulate = Color( 1, 1, 1, 1 ) +8/region = Rect2( 704, 0, 176, 176 ) +8/tile_mode = 0 +8/occluder_offset = Vector2( 0, 0 ) +8/navigation_offset = Vector2( 0, 0 ) +8/shape_offset = Vector2( 0, 0 ) +8/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +8/shape_one_way = false +8/shape_one_way_margin = 0.0 +8/shapes = [ ] +8/z_index = 0 +9/name = "TilesetGodotVloer.png 9" +9/texture = ExtResource( 1 ) +9/tex_offset = Vector2( 0, 0 ) +9/modulate = Color( 1, 1, 1, 1 ) +9/region = Rect2( 880, 0, 176, 176 ) +9/tile_mode = 0 +9/occluder_offset = Vector2( 0, 0 ) +9/navigation_offset = Vector2( 0, 0 ) +9/shape_offset = Vector2( 0, 0 ) +9/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +9/shape_one_way = false +9/shape_one_way_margin = 0.0 +9/shapes = [ ] +9/z_index = 0 +10/name = "TilesetGodotVloer.png 10" +10/texture = ExtResource( 1 ) +10/tex_offset = Vector2( 0, 0 ) +10/modulate = Color( 1, 1, 1, 1 ) +10/region = Rect2( 1056, 0, 176, 176 ) +10/tile_mode = 0 +10/occluder_offset = Vector2( 0, 0 ) +10/navigation_offset = Vector2( 0, 0 ) +10/shape_offset = Vector2( 0, 0 ) +10/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +10/shape_one_way = false +10/shape_one_way_margin = 0.0 +10/shapes = [ ] +10/z_index = 0 diff --git a/Other/default_env.tres b/Other/default_env.tres new file mode 100644 index 0000000..3e42e6f Binary files /dev/null and b/Other/default_env.tres differ diff --git a/Other/ring_of_races_font.tres b/Other/ring_of_races_font.tres new file mode 100644 index 0000000..92adcc4 --- /dev/null +++ b/Other/ring_of_races_font.tres @@ -0,0 +1,5 @@ +[gd_resource type="DynamicFontData" format=2] + +[resource] +resource_local_to_scene = true +font_path = "res://ring_of_races_font.ttf" diff --git a/Ring of Races_v03.apk b/Ring of Races_v03.apk index 0b6b867..33e326d 100644 Binary files a/Ring of Races_v03.apk and b/Ring of Races_v03.apk differ diff --git a/Ring of Races_v03_GLE2.apk b/Ring of Races_v03_GLE2.apk new file mode 100644 index 0000000..af53699 Binary files /dev/null and b/Ring of Races_v03_GLE2.apk differ diff --git a/Rule1.tscn b/Rule1.tscn index 66e7a61..5fe390e 100644 --- a/Rule1.tscn +++ b/Rule1.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=3 format=2] -[ext_resource path="res://Vloer.tres" type="TileSet" id=1] -[ext_resource path="res://Planten.tres" type="TileSet" id=2] +[ext_resource path="res://Other/Vloer.tres" type="TileSet" id=1] +[ext_resource path="res://Other/Planten.tres" type="TileSet" id=2] [node name="Node2D" type="Node2D"] position = Vector2( 109, 0 ) diff --git a/Storage/Database.gd b/Storage/Database.gd index 0eddc5e..35b184e 100644 --- a/Storage/Database.gd +++ b/Storage/Database.gd @@ -1,7 +1,7 @@ extends Node const SQLite = preload("res://addons/godot-sqlite/bin/gdsqlite.gdns") -var path = "res://Storage/World1.db" +var path = "user://storage.db" var db_name = "RingOfRaces" var db = null var verbose = true @@ -37,7 +37,11 @@ func OpenConnection(): self.db.path = path self.db.verbose_mode = verbose var create = false + print(path) + + # This does not seem to work. The file is in the right place, but being recreated everytime. The file is findable in Res:// and C:/ .. But not after the user folder if !file.file_exists(path): + print("File not existing, so creating new db") create = true self.db.open_db() if create: @@ -53,8 +57,9 @@ func GetInventoryItems(): ret = db.select_rows("player_inventory", "",["*"]) return ret -func SaveInventory(inventory): - if(inventory == null or len(inventory) != 40): +func SaveInventory(player_inventory_items): + print("Now on inventory save file") + if(player_inventory_items == null or len(player_inventory_items) != 40): Global.Log("Bad inventory save!", 3) return OpenConnectionIfClosed() diff --git a/export_presets.cfg b/export_presets.cfg index 3be27f6..5609a06 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -7,7 +7,7 @@ custom_features="" export_filter="all_resources" include_filter="" exclude_filter="" -export_path="./Ring of Races_v03.apk" +export_path="./Ring of Races_v03_GLE2.apk" patch_list=PoolStringArray( ) script_export_mode=1 script_encryption_key="" diff --git a/modules/godot_remote/.gitignore b/modules/godot_remote/.gitignore new file mode 100644 index 0000000..de85c23 --- /dev/null +++ b/modules/godot_remote/.gitignore @@ -0,0 +1,39 @@ +# SConstruct +*.dblite +__pycache__ +*.pyc + +# Visual Studio Cache +.vs/ + +# VSCode Cache +.vscode/ + +# Binaries +*.obj +*.iobj +*.so +*.dll +*.o +*.dylib +*.pdb +*.ipdb +*.ilk +*.exe +*.exp +*.lib +*.vcxproj.filters +*.vcxproj.user +*.os +*.out +api.json +.import/ +.mono/ +obj/ +libs/ +bin/ + +# exist only for testing +test.gd + +godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/*.png diff --git a/modules/godot_remote/.gitmodules b/modules/godot_remote/.gitmodules new file mode 100644 index 0000000..64fc4d4 --- /dev/null +++ b/modules/godot_remote/.gitmodules @@ -0,0 +1,3 @@ +[submodule "godot-cpp"] + path = godot-cpp + url = https://github.com/GodotNativeTools/godot-cpp diff --git a/modules/godot_remote/Android.mk b/modules/godot_remote/Android.mk new file mode 100644 index 0000000..efdf487 --- /dev/null +++ b/modules/godot_remote/Android.mk @@ -0,0 +1,47 @@ +# Android.mk +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := godot-cpp +ifeq ($(TARGET_ARCH_ABI),x86) + LOCAL_SRC_FILES := godot-cpp/bin/libgodot-cpp.android.release.x86.a +endif +ifeq ($(TARGET_ARCH_ABI),x86_64) + LOCAL_SRC_FILES := godot-cpp/bin/libgodot-cpp.android.release.x86_64.a +endif +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) + LOCAL_SRC_FILES := godot-cpp/bin/libgodot-cpp.android.release.armv7.a +endif +ifeq ($(TARGET_ARCH_ABI),arm64-v8a) + LOCAL_SRC_FILES := godot-cpp/bin/libgodot-cpp.android.release.arm64v8.a +endif +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := godot_remote.android.release.$(TARGET_ARCH_ABI) +LOCAL_CPPFLAGS := -std=c++14 +LOCAL_CPP_FEATURES := rtti exceptions +LOCAL_LDLIBS := -llog + +LOCAL_SRC_FILES := \ +godot_remote/GodotRemote.cpp \ +godot_remote/GRClient.cpp \ +godot_remote/GRDevice.cpp \ +godot_remote/GRInputData.cpp \ +godot_remote/GRNotifications.cpp \ +godot_remote/GRPacket.cpp \ +godot_remote/GRResources.cpp \ +godot_remote/GRServer.cpp \ +godot_remote/GRUtils.cpp \ +godot_remote/jpge.cpp \ +godot_remote/register_types.cpp + +LOCAL_C_INCLUDES := \ +godot-cpp/godot-headers \ +godot-cpp/include/ \ +godot-cpp/include/core \ +godot-cpp/include/gen \ + +LOCAL_STATIC_LIBRARIES := godot-cpp + +include $(BUILD_SHARED_LIBRARY) \ No newline at end of file diff --git a/modules/godot_remote/GodotRemoteGDNative_only_for_developing.sln b/modules/godot_remote/GodotRemoteGDNative_only_for_developing.sln new file mode 100644 index 0000000..3c7c323 --- /dev/null +++ b/modules/godot_remote/GodotRemoteGDNative_only_for_developing.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30611.23 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GodotRemoteGDNative", "GodotRemoteGDNative_only_for_developing.vcxproj", "{4D452F2C-8FBB-476B-A990-1E9E5DB93D32}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + debug|x64 = debug|x64 + debug|x86 = debug|x86 + release|x64 = release|x64 + release|x86 = release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4D452F2C-8FBB-476B-A990-1E9E5DB93D32}.debug|x64.ActiveCfg = debug|x64 + {4D452F2C-8FBB-476B-A990-1E9E5DB93D32}.debug|x64.Build.0 = debug|x64 + {4D452F2C-8FBB-476B-A990-1E9E5DB93D32}.debug|x86.ActiveCfg = debug|Win32 + {4D452F2C-8FBB-476B-A990-1E9E5DB93D32}.debug|x86.Build.0 = debug|Win32 + {4D452F2C-8FBB-476B-A990-1E9E5DB93D32}.release|x64.ActiveCfg = release|x64 + {4D452F2C-8FBB-476B-A990-1E9E5DB93D32}.release|x64.Build.0 = release|x64 + {4D452F2C-8FBB-476B-A990-1E9E5DB93D32}.release|x86.ActiveCfg = release|Win32 + {4D452F2C-8FBB-476B-A990-1E9E5DB93D32}.release|x86.Build.0 = release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2D6E9625-5E11-4AF3-A331-3B18E40A974D} + EndGlobalSection +EndGlobal diff --git a/modules/godot_remote/GodotRemoteGDNative_only_for_developing.vcxproj b/modules/godot_remote/GodotRemoteGDNative_only_for_developing.vcxproj new file mode 100644 index 0000000..4e61081 --- /dev/null +++ b/modules/godot_remote/GodotRemoteGDNative_only_for_developing.vcxproj @@ -0,0 +1,215 @@ + + + + + debug + Win32 + + + release + Win32 + + + debug + x64 + + + release + x64 + + + + 16.0 + Win32Proj + {4d452f2c-8fbb-476b-a990-1e9e5db93d32} + GodotRemoteGDNative + 10.0 + GodotRemoteGDNative + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + godot_remote.windows.$(Configuration).$(PlatformArchitecture) + $(SolutionDir)\bin\ + $(SolutionDir)obj\$(PlatformTarget)\ + $(ProjectDir)godot-cpp\bin;$(LibraryPath) + $(ProjectDir)godot-cpp\include;$(ProjectDir)godot-cpp\godot_headers;$(ProjectDir)godot-cpp\include\gen;$(ProjectDir)godot-cpp\include\core;$(IncludePath) + + + false + godot_remote.windows.$(Configuration).$(PlatformArchitecture) + $(SolutionDir)\bin\ + $(SolutionDir)obj\$(PlatformTarget)\ + $(ProjectDir)godot-cpp\bin;$(LibraryPath) + $(ProjectDir)godot-cpp\include;$(ProjectDir)godot-cpp\godot_headers;$(ProjectDir)godot-cpp\include\gen;$(ProjectDir)godot-cpp\include\core;$(IncludePath) + + + $(ProjectDir)godot-cpp\include;$(ProjectDir)godot-cpp\godot-headers;$(ProjectDir)godot-cpp\include\gen;$(ProjectDir)godot-cpp\include\core;$(IncludePath) + $(ProjectDir)godot-cpp\bin;$(LibraryPath) + $(SolutionDir)\bin\ + godot_remote.windows.$(Configuration).$(PlatformArchitecture) + $(SolutionDir)obj\$(PlatformTarget)\ + false + + + false + $(ProjectDir)godot-cpp\include;$(ProjectDir)godot-cpp\godot-headers;$(ProjectDir)godot-cpp\include\gen;$(ProjectDir)godot-cpp\include\core;$(IncludePath) + $(ProjectDir)godot-cpp\bin;$(LibraryPath) + $(SolutionDir)\bin\ + godot_remote.windows.$(Configuration).$(PlatformArchitecture) + $(SolutionDir)obj\$(PlatformTarget)\ + + + + Level3 + false + WIN32;_DEBUG;GDNATIVE_LIBRARY;TOOLS_ENABLED;DEBUG_ENABLED;%(PreprocessorDefinitions) + true + true + ProgramDatabase + true + + + NotSet + true + libgodot-cpp.windows.$(Configuration).$(PlatformArchitecture).lib; + + + + + Level3 + true + true + false + WIN32;GDNATIVE_LIBRARY;TOOLS_ENABLED;NDEBUG;%(PreprocessorDefinitions) + true + true + + + NotSet + true + true + false + libgodot-cpp.windows.$(Configuration).$(PlatformArchitecture).lib; + + + + + Level3 + false + true + WIN64;_DEBUG;GDNATIVE_LIBRARY;TOOLS_ENABLED;DEBUG_ENABLED;%(PreprocessorDefinitions) + true + Sync + true + ProgramDatabase + stdcpp14 + + + NotSet + true + libgodot-cpp.windows.$(Configuration).$(PlatformArchitecture).lib; + $(OutDir)$(TargetName)$(TargetExt) + UseLinkTimeCodeGeneration + + + + + Level3 + + + false + false + WIN64;GDNATIVE_LIBRARY;TOOLS_ENABLED;NDEBUG;%(PreprocessorDefinitions) + true + true + Sync + + + NotSet + true + true + false + libgodot-cpp.windows.$(Configuration).$(PlatformArchitecture).lib; + $(OutDir)$(TargetName)$(TargetExt) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/godot_remote/Images/Icons/Close_icon.png b/modules/godot_remote/Images/Icons/Close_icon.png new file mode 100644 index 0000000..75d41c7 Binary files /dev/null and b/modules/godot_remote/Images/Icons/Close_icon.png differ diff --git a/modules/godot_remote/Images/Icons/Close_icon.png.import b/modules/godot_remote/Images/Icons/Close_icon.png.import new file mode 100644 index 0000000..947c653 --- /dev/null +++ b/modules/godot_remote/Images/Icons/Close_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Close_icon.png-55bdce32d084d5e5f806a4a5d837ea4b.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://modules/godot_remote/Images/Icons/Close_icon.png" +dest_files=[ "res://.import/Close_icon.png-55bdce32d084d5e5f806a4a5d837ea4b.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/Images/Icons/Close_icon.svg b/modules/godot_remote/Images/Icons/Close_icon.svg new file mode 100644 index 0000000..4147c7b --- /dev/null +++ b/modules/godot_remote/Images/Icons/Close_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/Images/Icons/Close_icon.svg.import b/modules/godot_remote/Images/Icons/Close_icon.svg.import new file mode 100644 index 0000000..6f325c5 --- /dev/null +++ b/modules/godot_remote/Images/Icons/Close_icon.svg.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Close_icon.svg-eb6caf74ca6969dc2a8ada8a0b98f1d5.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://modules/godot_remote/Images/Icons/Close_icon.svg" +dest_files=[ "res://.import/Close_icon.svg-eb6caf74ca6969dc2a8ada8a0b98f1d5.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/Images/Icons/Connected_icon.png b/modules/godot_remote/Images/Icons/Connected_icon.png new file mode 100644 index 0000000..4e66d5b Binary files /dev/null and b/modules/godot_remote/Images/Icons/Connected_icon.png differ diff --git a/modules/godot_remote/Images/Icons/Connected_icon.png.import b/modules/godot_remote/Images/Icons/Connected_icon.png.import new file mode 100644 index 0000000..77c4c97 --- /dev/null +++ b/modules/godot_remote/Images/Icons/Connected_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Connected_icon.png-e646ca1b6ff2d860a81b4e89f1619f50.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://modules/godot_remote/Images/Icons/Connected_icon.png" +dest_files=[ "res://.import/Connected_icon.png-e646ca1b6ff2d860a81b4e89f1619f50.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/Images/Icons/Connected_icon.svg b/modules/godot_remote/Images/Icons/Connected_icon.svg new file mode 100644 index 0000000..4a22c6f --- /dev/null +++ b/modules/godot_remote/Images/Icons/Connected_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/Images/Icons/Connected_icon.svg.import b/modules/godot_remote/Images/Icons/Connected_icon.svg.import new file mode 100644 index 0000000..e76a773 --- /dev/null +++ b/modules/godot_remote/Images/Icons/Connected_icon.svg.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Connected_icon.svg-91c77637b50d393da88a03a3c4a31090.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://modules/godot_remote/Images/Icons/Connected_icon.svg" +dest_files=[ "res://.import/Connected_icon.svg-91c77637b50d393da88a03a3c4a31090.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/Images/Icons/Disconnected_icon.png b/modules/godot_remote/Images/Icons/Disconnected_icon.png new file mode 100644 index 0000000..6312ee8 Binary files /dev/null and b/modules/godot_remote/Images/Icons/Disconnected_icon.png differ diff --git a/modules/godot_remote/Images/Icons/Disconnected_icon.png.import b/modules/godot_remote/Images/Icons/Disconnected_icon.png.import new file mode 100644 index 0000000..064549c --- /dev/null +++ b/modules/godot_remote/Images/Icons/Disconnected_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Disconnected_icon.png-ec94adf71229facb1d8116765a16fdcd.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://modules/godot_remote/Images/Icons/Disconnected_icon.png" +dest_files=[ "res://.import/Disconnected_icon.png-ec94adf71229facb1d8116765a16fdcd.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/Images/Icons/Disconnected_icon.svg b/modules/godot_remote/Images/Icons/Disconnected_icon.svg new file mode 100644 index 0000000..ac3060e --- /dev/null +++ b/modules/godot_remote/Images/Icons/Disconnected_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/Images/Icons/Disconnected_icon.svg.import b/modules/godot_remote/Images/Icons/Disconnected_icon.svg.import new file mode 100644 index 0000000..00d5f04 --- /dev/null +++ b/modules/godot_remote/Images/Icons/Disconnected_icon.svg.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Disconnected_icon.svg-8ac048c62e1e64861e3552cc93c93d53.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://modules/godot_remote/Images/Icons/Disconnected_icon.svg" +dest_files=[ "res://.import/Disconnected_icon.svg-8ac048c62e1e64861e3552cc93c93d53.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/Images/Icons/Error_icon.png b/modules/godot_remote/Images/Icons/Error_icon.png new file mode 100644 index 0000000..9aea76c Binary files /dev/null and b/modules/godot_remote/Images/Icons/Error_icon.png differ diff --git a/modules/godot_remote/Images/Icons/Error_icon.png.import b/modules/godot_remote/Images/Icons/Error_icon.png.import new file mode 100644 index 0000000..979ea54 --- /dev/null +++ b/modules/godot_remote/Images/Icons/Error_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Error_icon.png-3f424e587d3cb0431a257db9d2ea385d.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://modules/godot_remote/Images/Icons/Error_icon.png" +dest_files=[ "res://.import/Error_icon.png-3f424e587d3cb0431a257db9d2ea385d.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/Images/Icons/Error_icon.svg b/modules/godot_remote/Images/Icons/Error_icon.svg new file mode 100644 index 0000000..05e5480 --- /dev/null +++ b/modules/godot_remote/Images/Icons/Error_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/Images/Icons/Error_icon.svg.import b/modules/godot_remote/Images/Icons/Error_icon.svg.import new file mode 100644 index 0000000..650cb4f --- /dev/null +++ b/modules/godot_remote/Images/Icons/Error_icon.svg.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Error_icon.svg-b652e469ed1378493bd3d78653637703.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://modules/godot_remote/Images/Icons/Error_icon.svg" +dest_files=[ "res://.import/Error_icon.svg-b652e469ed1378493bd3d78653637703.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/Images/Icons/Warning_icon.png b/modules/godot_remote/Images/Icons/Warning_icon.png new file mode 100644 index 0000000..c06a1f6 Binary files /dev/null and b/modules/godot_remote/Images/Icons/Warning_icon.png differ diff --git a/modules/godot_remote/Images/Icons/Warning_icon.png.import b/modules/godot_remote/Images/Icons/Warning_icon.png.import new file mode 100644 index 0000000..d3cd095 --- /dev/null +++ b/modules/godot_remote/Images/Icons/Warning_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Warning_icon.png-3b98f3fb52d2ad40673fed73dff42ea6.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://modules/godot_remote/Images/Icons/Warning_icon.png" +dest_files=[ "res://.import/Warning_icon.png-3b98f3fb52d2ad40673fed73dff42ea6.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/Images/Icons/Warning_icon.svg b/modules/godot_remote/Images/Icons/Warning_icon.svg new file mode 100644 index 0000000..698288d --- /dev/null +++ b/modules/godot_remote/Images/Icons/Warning_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/Images/Icons/Warning_icon.svg.import b/modules/godot_remote/Images/Icons/Warning_icon.svg.import new file mode 100644 index 0000000..48de049 --- /dev/null +++ b/modules/godot_remote/Images/Icons/Warning_icon.svg.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Warning_icon.svg-d7cff469ecb7ebc653295abfc7c04800.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://modules/godot_remote/Images/Icons/Warning_icon.svg" +dest_files=[ "res://.import/Warning_icon.svg-d7cff469ecb7ebc653295abfc7c04800.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/Images/NoSignal/NoSignal.pdn b/modules/godot_remote/Images/NoSignal/NoSignal.pdn new file mode 100644 index 0000000..6d48bc6 Binary files /dev/null and b/modules/godot_remote/Images/NoSignal/NoSignal.pdn differ diff --git a/modules/godot_remote/Images/NoSignal/NoSignal.png b/modules/godot_remote/Images/NoSignal/NoSignal.png new file mode 100644 index 0000000..98509e7 Binary files /dev/null and b/modules/godot_remote/Images/NoSignal/NoSignal.png differ diff --git a/modules/godot_remote/Images/NoSignal/NoSignal.png.import b/modules/godot_remote/Images/NoSignal/NoSignal.png.import new file mode 100644 index 0000000..0220536 --- /dev/null +++ b/modules/godot_remote/Images/NoSignal/NoSignal.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/NoSignal.png-27de0974ec5cc467f5b572d6723aefde.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://modules/godot_remote/Images/NoSignal/NoSignal.png" +dest_files=[ "res://.import/NoSignal.png-27de0974ec5cc467f5b572d6723aefde.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/Images/NoSignal/NoSignalVertical.pdn b/modules/godot_remote/Images/NoSignal/NoSignalVertical.pdn new file mode 100644 index 0000000..56ca817 Binary files /dev/null and b/modules/godot_remote/Images/NoSignal/NoSignalVertical.pdn differ diff --git a/modules/godot_remote/Images/NoSignal/NoSignalVertical.png b/modules/godot_remote/Images/NoSignal/NoSignalVertical.png new file mode 100644 index 0000000..b999bd7 Binary files /dev/null and b/modules/godot_remote/Images/NoSignal/NoSignalVertical.png differ diff --git a/modules/godot_remote/Images/NoSignal/NoSignalVertical.png.import b/modules/godot_remote/Images/NoSignal/NoSignalVertical.png.import new file mode 100644 index 0000000..c0745bf --- /dev/null +++ b/modules/godot_remote/Images/NoSignal/NoSignalVertical.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/NoSignalVertical.png-9f616e3a19712373e669287fcd3cf0a9.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://modules/godot_remote/Images/NoSignal/NoSignalVertical.png" +dest_files=[ "res://.import/NoSignalVertical.png-9f616e3a19712373e669287fcd3cf0a9.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/Images/Screenshots/mobile_settings.png b/modules/godot_remote/Images/Screenshots/mobile_settings.png new file mode 100644 index 0000000..fb7a03d Binary files /dev/null and b/modules/godot_remote/Images/Screenshots/mobile_settings.png differ diff --git a/modules/godot_remote/Images/Screenshots/mobile_settings.png.import b/modules/godot_remote/Images/Screenshots/mobile_settings.png.import new file mode 100644 index 0000000..3d65662 --- /dev/null +++ b/modules/godot_remote/Images/Screenshots/mobile_settings.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/mobile_settings.png-796e6d8df2995de699cde1a8e2870e85.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://modules/godot_remote/Images/Screenshots/mobile_settings.png" +dest_files=[ "res://.import/mobile_settings.png-796e6d8df2995de699cde1a8e2870e85.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/Images/Screenshots/settings.png b/modules/godot_remote/Images/Screenshots/settings.png new file mode 100644 index 0000000..c0f9dce Binary files /dev/null and b/modules/godot_remote/Images/Screenshots/settings.png differ diff --git a/modules/godot_remote/Images/Screenshots/settings.png.import b/modules/godot_remote/Images/Screenshots/settings.png.import new file mode 100644 index 0000000..d6c3728 --- /dev/null +++ b/modules/godot_remote/Images/Screenshots/settings.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/settings.png-f8eef4d7d1f2459d5277f22ea0ef6cb3.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://modules/godot_remote/Images/Screenshots/settings.png" +dest_files=[ "res://.import/settings.png-f8eef4d7d1f2459d5277f22ea0ef6cb3.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/LICENSE b/modules/godot_remote/LICENSE new file mode 100644 index 0000000..e38bbb6 --- /dev/null +++ b/modules/godot_remote/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-2021 DmitriySalnikov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the Software), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, andor sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/modules/godot_remote/README.md b/modules/godot_remote/README.md new file mode 100644 index 0000000..3488aa7 --- /dev/null +++ b/modules/godot_remote/README.md @@ -0,0 +1,723 @@ +# Godot Remote + +This is cross platform native module for [Godot Engine](https://github.com/godotengine/godot) v3 for control apps and games over WiFi or ADB. + +If you are developing on a non-touch device, this module is the best way to quickly test touch input or test mobile sensors data. + +[Video Demonstration](https://youtu.be/LbFcQnS3z3E) + +[Custom Packets Demo](https://youtu.be/RmhppDWZZk8) + +## Support + +[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/I2I53VZ2D) + +[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://paypal.me/dmitriysalnikov) + +## Compiling the Module + +### As a module + +1. [configure environment](https://docs.godotengine.org/en/3.2/development/compiling/index.html) to build editor for your platform (you need to clone [3.2 branch](https://github.com/godotengine/godot/tree/3.2) not master) +2. copy ```godot_remote``` folder to the ```modules/``` directory or make [symlink](https://en.wikipedia.org/wiki/Symbolic_link) +3. compile engine with instructions from documentation above (e.g. ```scons p=windows tools=yes -j[place here count of your CPU threads]```) +4. run ```bin/godot[based on config]```. + +If everything compiles successfully, you'll find the new category in project settings ```Debug/Godot Remote``` where you can configure server. + +![Settings](Images/Screenshots/settings.png) + +### As a GDNative library + +1. [Configure environment](https://docs.godotengine.org/en/3.2/development/compiling/index.html) to build editor for your platform +2. Generate api.json for GDNative api. ```bin/godot --gdnative-generate-json-api api.json``` +3. Copy api.json to the root directory of this repository +4. Compile godot-cpp (e.g. in godot-cpp directory run ```scons generate_bindings=true platform=windows target=release bits=64 -j8 ../api.json```) +5. Compile module for your platform (Available platforms: windows, osx, linux, ios, android. Tested platforms: windows, linux, android) + 1. For android: Run in root directory ```[path to your android ndk root dir]/ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk APP_PLATFORM=android-21``` + 2. For all other platforms: ```scons platform=windows target=release -j8``` +6. Use produced library in ```bin/``` + +GDNative has limitations so here ```GodotRemote``` is not a singleton and you need to create autoload scene with attached NativeScript for ```GodotRemote``` class. Also there is no any settings in ```Debug/Godot Remote```. + +Enum constants in this version changed too (see [API Reference] ) + +**Currently, the GDNative version does not support the assignment of sensor data, so the editor will not support accelerometer, gyroscope, etc. +Also, this version may crash at a random moment.** + +If GDNative becomes more stable, I will add the necessary code to easily integrate this module into any project, but now it just works.. sometimes. + +### Additional parameters + +Also module has additional compilation parameters for scons script + +1. ```godot_remote_no_default_resources``` (yes/no) default no - compile with or without default resources +2. ```godot_remote_disable_server``` (yes/no) default no - do not include server code +3. ```godot_remote_disable_client``` (yes/no) default no - do not include client code + +## Download + +Precompiled binaries can be found on [GitHub Releases](https://github.com/DmitriySalnikov/GodotRemote/releases) page + +### Mobile app + +On releases page you can found precompiled mobile app but also it can be downloaded from [Google Play](https://play.google.com/store/apps/details?id=com.dmitriysalnikov.godotremote) + +## Configure Mobile App + +To open settings menu you need to touch the screen with 5 fingers at once. + +Then you'll see this settings menu: + +![Settings](Images/Screenshots/mobile_settings.png) + +**Important:** after entering server address you should apply it by pressing `Set Type and Address` or `Set Type and Port` + +## Custom client + +If need to support other platforms or you need a specific version of module integrated to the client app, you can build client from source code placed [here](godot_remote_client). + +If you don't want to use my client app you can check the [example client project](examples/simple_client) and build your own client. + +Or you can donate me some money with request to buy iPhone and adapt a client for it 🙂 + +## API Reference + +Methods will be declared follows this template: + +```python +return_type function_name([arg_name1 : type [= defalut value]][, arg_name2 : type [= defalut value]]) +``` + +**Important:** All enums in GDNative version is exposed in GodotRemote class because of limitations. +For example, if you want to use StreamState.STREAM_ACTIVE from GRClient you need to get property GRClient_STREAM_ACTIVE of GodotRemote __object__ + +```python +# Godot module: +GRClient.STREAM_ACTIVE: + +# GDNative +# *GodotRemote is autoload scene with attached NativeScript +GodotRemote.GRClient_STREAM_ACTIVE +``` + +### GodotRemote + +Main class of module. + +```python +# --- Properties + +# Canvas layer that shows notifications +# type int, default 128 +notifications_layer + +# Notifications position on screen +# type GRNotifications.NotificationsPosition, default TC +notifications_position + +# Is notifications enabled +# type bool, default true +notifications_enabled + +# Base duration for showing notifications +# type float, default 3.0 +notifications_duration + +# Notifcations style +# type GRNotificationStyle +notifications_style + +# --- Methods + +# Notifications + +# Adds or fully update existing notification +# @title: Notification title +# @text: Text of notification +# @notification_icon: Notification icon from enum NotificationIcon +# @update_existing: Updates existing notification +# @duration_multiplier: Multiply base notifications duration +void add_notification(title: String, text: String, notification_icon: GRNotifications.NotificationIcon = 0, update_existing: bool = true, duration_multiplier: float = 1.0) + +# Adds new notification or append text to existing notification +# @title: Notification title +# @text: Text of notification +# @icon: Notification icon from enum NotificationIcon +# @add_to_new_line: Adds text to new line or adds to current line +void add_notification_or_append_string(title: String, text: String, icon: GRNotifications.NotificationIcon, add_to_new_line: bool = true, duration_multiplier: float = 1.0) + +# Adds notification or update one line of notification text +# @title: Notification title +# @id: Line ID +# @text: Text of notification +# @icon: Notification icon from enum NotificationIcon +# @duration_multiplier: Multiply base notifications duration +void add_notification_or_update_line(title: String, id: String, text: String, icon: GRNotifications.NotificationIcon, duration_multiplier: float = 1.0) + +# Clear all notifications +void clear_notifications() + +# Get notifications list +# @return list of all visible notifications +Array get_all_notifications() + +# Get notification with specified title or null +# @title: Notification title +# @return matched notification +GRNotificationPanel get_notification(title: String) + +# Get all notifications with specified title +# @title: Notification title +# @return list of visible notifications +Array get_notifications_with_title(title: String) + +# Remove notifications with specified title +# @title: Notifications title +# @is_all_entries: Delete all notifications with @title if true +void remove_notification(title: String, is_all_entries: bool = true) + +# Remove exact notification by reference +# @notification: Notification reference +void remove_notification_exact(notification: Node) + +# Client/Server + +# Create device: client or server +# @device_type: Type of device +# @return true if device created successful +bool create_remote_device(device_type: GodotRemote.DeviceType = 0) + +# Start device +# @return true if device valid +bool start_remote_device() + +# Create and start device +# @device_type: Type of device +void create_and_start_device(device_type: GodotRemote.DeviceType = 0) + +# Remove and delete currently working device +# @return true if succeed +bool remove_remote_device() + +# Get device +# @return client, server or null +GRDevice get_device() + +# Utility functions + +# Not exposed to GDScript fuctions from Input class +# And currently not available in GDNative +void set_accelerometer(value: Vector3) +void set_gravity(value: Vector3) +void set_gyroscope(value: Vector3) +void set_magnetometer(value: Vector3) + +# Set GodotRemote log level +# @level: Level of logging +void set_log_level(level: LogLevel) + +# Get GodotRemote module version +# @return module version in format "MAJOR.MINOR.BUILD" +String get_version() + +# --- Signals + +# Device added +device_added() + +# Device removed +device_removed() + +# --- Enumerations + +DeviceType: + DEVICE_AUTO = 0 + DEVICE_SERVER = 1 + DEVICE_CLIENT = 2 + +LogLevel: + LL_NONE = 4 + LL_DEBUG = 0 + LL_NORMAL = 1 + LL_WARNING = 2 + LL_ERROR = 3 +``` + +### GRNotifications + +Container for all notifications + +```python + +# --- Signals + +# Called when a single notification is added +notification_added(title: String, text: String) + +# Called when a single notification is removed +notification_removed(title: String, is_cleared: bool) + +# Called when all notifications are cleared +notifications_cleared() + +# Called when notifications are enabled or disabled +notifications_toggled(is_enabled: bool) + +# --- Enumerations + +NotificationIcon: + ICON_NONE = 0 + ICON_ERROR = 1 + ICON_WARNING = 2 + ICON_SUCCESS = 3 + ICON_FAIL = 4 + +NotificationsPosition: + TOP_LEFT = 0 + TOP_CENTER = 1 + TOP_RIGHT = 2 + BOTTOM_LEFT = 3 + BOTTOM_CENTER = 4 + BOTTOM_RIGHT = 5 +``` + +### GRNotificationStyle + +Helper class to store parameters of notifications style + +```python +# --- Properties + +# Style of background notifications panel +# type StyleBox +panel_style + +# Theme for notification close button +# type Theme +close_button_theme + +# Close button icon texture +# type Texture +close_button_icon + +# Notification title font +# type Font +title_font + +# Notification text font +# type Font +text_font + +# --- Methods + +# Get notification icon from this style +# @notification_icon: Notfication icon id +# @return icon texture of null +Texture get_notification_icon(notification_icon: GRNotifications.NotificationIcon) + +# Set notification icon in this style +# @notification_icon: Notfication icon id +# @icon_texture: Icon texture +void set_notification_icon(notification_icon: GRNotifications.NotificationIcon, icon_texture: Texture) + +``` + +### GRInputData + +Container for all InputEvents + +```python +# --- Enumerations + +InputType: + _NoneIT = 0 + _InputDeviceSensors = 1 + _InputEvent = 64 + _InputEventAction = 65 + _InputEventGesture = 66 + _InputEventJoypadButton = 67 + _InputEventJoypadMotion = 68 + _InputEventKey = 69 + _InputEventMagnifyGesture = 70 + _InputEventMIDI = 71 + _InputEventMouse = 72 + _InputEventMouseButton = 73 + _InputEventMouseMotion = 74 + _InputEventPanGesture = 75 + _InputEventScreenDrag = 76 + _InputEventScreenTouch = 77 + _InputEventWithModifiers = 78 + _InputEventMAX = 79 +``` + +### GRPacket + +The basic data type used to exchange information between the client and the server + +```python +# --- Enumerations + +PacketType: + NonePacket = 0 + SyncTime = 1 + ImageData = 2 + InputData = 3 + ServerSettings = 4 + MouseModeSync = 5 + CustomInputScene = 6 + ClientStreamOrientation = 7 + ClientStreamAspect = 8 + CustomUserData = 9 + Ping = 128 + Pong = 192 +``` + +### GRDevice + +Base class for client and server + +```python +# --- Properties + +# Connection port +# type int, default 52341 +port + +# --- Methods + +# Send user data to remote device +# @packet_id: any data to identify your packet +# @user_data: any data to send to remote device +# @full_objects: flag for full serialization of objects, possibly with their executable code. For more info check Godot's PacketPeer.put_var() and PacketPeer.get_var() +void send_user_data(packet_id: Variant, user_data: Variant, full_objects: bool = false) + +# Get average FPS +# @return average FPS +float get_avg_fps() + +# Get minimum FPS +# @return minimum FPS +float get_min_fps() + +# Get maximum FPS +# @return maximum FPS +float get_max_fps() + +# Get average ping +# @return average ping +float get_avg_ping() + +# Get minimum ping +# @return minimum ping +float get_min_ping() + +# Get maximum ping +# @return maximum ping +float get_max_ping() + +# Get device status +WorkingStatus get_status() + +# Start device +void start() + +# Stop device +void stop() + +# --- Signals + +# Device status changed +status_changed(status: GRDevice.WorkingStatus) + +# User data received from a remote device +user_data_received(packet_id: Variant, user_data: Variant) + +# --- Enumerations + +ImageCompressionType: + COMPRESSION_UNCOMPRESSED = 0 + COMPRESSION_JPG = 1 + COMPRESSION_PNG = 2 + +Subsampling: + SUBSAMPLING_Y_ONLY = 0 + SUBSAMPLING_H1V1 = 1 + SUBSAMPLING_H2V1 = 2 + SUBSAMPLING_H2V2 = 3 + +TypesOfServerSettings: + SERVER_SETTINGS_USE_INTERNAL = 0 + SERVER_SETTINGS_VIDEO_STREAM_ENABLED = 1 + SERVER_SETTINGS_COMPRESSION_TYPE = 2 + SERVER_SETTINGS_JPG_QUALITY = 3 + SERVER_SETTINGS_SKIP_FRAMES = 4 + SERVER_SETTINGS_RENDER_SCALE = 5 + +WorkingStatus: + STATUS_STARTING = 3 + STATUS_STOPPING = 2 + STATUS_WORKING = 1 + STATUS_STOPPED = 0 +``` + +### GRServer + +```python +# --- Properties + +# Server password +# type String, default "" +password + +# Path to the custom input scene. +# type String, default "" +custom_input_scene + +# Is custom input scene compressed +## Doesn't work in GDNative +# type bool, default true +custom_input_scene_compressed + +# Compression type of custom input scene +## Doesn't work in GDNative +# type File.CompressionMode, default FastLZ +custom_input_scene_compression_type + +# --- Methods + +# Set whether the stream is enabled +bool set_video_stream_enabled(value : bool) + +# Get whether the stream is enabled +bool is_video_stream_enabled() + +# Set how many frames to skip +bool set_skip_frames(frames : int) + +# Get the number of skipping frames +int get_skip_frames() + +# Set JPG quality +bool set_jpg_quality(quality : int) + +# Get JPG quality +int get_jpg_quality() + +# Set the scale of the stream +bool set_render_scale(scale : float) + +# Get stream scale +float get_render_scale() + +# Force update custom input scene on client +void force_update_custom_input_scene() + +# Get resize viewport node +# @return resize viewport or null +GRSViewport get_gr_viewport() + + +# --- Signals + +# On client connected +client_connected(device_id: String) + +# On client disconnected +client_disconnected(device_id: String) + +# On orientation of client's screen or viewport changed +client_viewport_orientation_changed(is_vertical: bool) + +# On client's screen or viewport aspect ratio changed +client_viewport_aspect_ratio_changed(stream_aspect: float) + +``` + +### GRClient + +```python +# --- Properties + +# Capture input only when containing control has focus +# type bool, default false +capture_on_focus + +# Capture input only when stream image hovered +# type bool, default true +capture_when_hover + +# Capture mouse pointer and touch events +# type bool, default true +capture_pointer + +# Capture input +# type bool, default true +capture_input + +# Type of connection +# type GRClient.ConnectionType, default CONNECTION_WiFi +connection_type + +# Frequency of sending data to the server +# type int, default 60 +target_send_fps + +# Stretch mode of stream image +# type GRClient.StretchMode, default STRETCH_KEEP_ASPECT +stretch_mode + +# Use texture filtering of stream image +# type bool, default true +texture_filtering + +# Password +# type String, default "" +password + +# ID of device +# type String, default 6 random digits and characters +device_id + +# Sync viewport orientation with server +# type bool, default true +viewport_orientation_syncing + +# Sync viewport aspect ratio with server +# type bool, default true +viewport_aspect_ratio_syncing + +# Receive updated server settings +# type bool, default false +server_settings_syncing + +# --- Methods + +# Restore settings on server +void disable_overriding_server_settings() + +# Get the current visible custom input scene +# @return: Custom input scene +Node get_custom_input_scene() + +# Get server address +# @return server address +String get_address() + +# Is connected to server +# @return true if connected to server +bool is_connected_to_host() + +# Is stream active +# @return true if stream active +bool is_stream_active() + +# Set server address to connect +# @ip: IP of server +# @return true if address is valid +bool set_address(ip: String) + +# Set both server address and port +# @ip: IP of server +# @port: Port of server +# @return true if address is valid +bool set_address_port(ip: String, port: int) + +# Set the control to show stream in +# @control_node: Control where stream will be shown +# @position_in_node: Position of stream in parent +void set_control_to_show_in(control_node: Control, position_in_node: int = 0) + +# Set custom material for no signal screen +# @material: Custom material +void set_custom_no_signal_material(material: Material) + +# Set custom horizontal texture for no signal screen +# @texture: Custom texture +void set_custom_no_signal_texture(texture: Texture) + +# Set custom vertical texture for no signal screen +# @texture: Custom texture +void set_custom_no_signal_vertical_texture(texture: Texture) + +# Override setting on server +# @setting: Which setting need to change +# @value: Value of setting +void set_server_setting(setting: GRdevice.TypesOfServerSettings, value: Variant) + +# --- Signals + +# On custom input scene added and becomes visible +custom_input_scene_added() + +# On custom input scene removed +custom_input_scene_removed() + +# On connection state changed +connection_state_changed(is_connected: bool) + +# On stream state changed +stream_state_changed(state: GRClient.StreamState) + +# On mouse mode changed on server +mouse_mode_changed(mouse_mode: Input.MouseMode) + +# On received server settings from server +server_settings_received(settings: Dictionary) + +# --- Enumerations + +ConnectionType: + CONNECTION_ADB = 1 + CONNECTION_WiFi = 0 + +StreamState: + STREAM_NO_SIGNAL = 0 + STREAM_ACTIVE = 1 + STREAM_NO_IMAGE = 2 + +StretchMode: + STRETCH_KEEP_ASPECT = 0 + STRETCH_FILL = 1 +``` + +There is no need to describe other classes here + +## Custom Input Scenes + +In custom input scenes you can use everything you want but to send InputEvent's from client to server you must emulate input. Or use the send_user_data() method and user_data_received signal for send and receive custom packets. +Example: + +```python +# -- With InputEvent's + +func _on_pressed(): + # Create event for pressed state + var iea_p = InputEventAction.new() + iea_p.pressed = true + iea_p.action = "jump" + # Create event for released state + var iea_r = InputEventAction.new() + iea_r.pressed = false + iea_p.action = "jump" + # Parse event to send it to the server + Input.parse_input_event(iea_p) + Input.parse_input_event(iea_r) + +# -- With custom packets + +# on first device +func _ready(): + GodotRemote.get_device().connect("user_data_received", self, "_on_user_data_received") + +func _on_user_data_received(id, data): + print("Received packet: %s, data: %s" % [id, data]) + +# on second device +func _on_button_pressed(): + GodotRemote.get_device().send_user_data("bg_color", color, false) +``` + +## License + +MIT license diff --git a/modules/godot_remote/SConstruct b/modules/godot_remote/SConstruct new file mode 100644 index 0000000..d5bb421 --- /dev/null +++ b/modules/godot_remote/SConstruct @@ -0,0 +1,470 @@ +#!/usr/bin/env python + +import os +import sys +import subprocess + +if sys.version_info < (3,): + def decode_utf8(x): + return x +else: + import codecs + def decode_utf8(x): + return codecs.utf_8_decode(x)[0] + +# Workaround for MinGW. See: +# http://www.scons.org/wiki/LongCmdLinesOnWin32 +if (os.name=="nt"): + import subprocess + + def mySubProcess(cmdline,env): + #print "SPAWNED : " + cmdline + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, startupinfo=startupinfo, shell = False, env = env) + data, err = proc.communicate() + rv = proc.wait() + if rv: + print("=====") + print(err.decode("utf-8")) + print("=====") + return rv + + def mySpawn(sh, escape, cmd, args, env): + + newargs = ' '.join(args[1:]) + cmdline = cmd + " " + newargs + + rv=0 + if len(cmdline) > 32000 and cmd.endswith("ar") : + cmdline = cmd + " " + args[1] + " " + args[2] + " " + for i in range(3,len(args)) : + rv = mySubProcess( cmdline + args[i], env ) + if rv : + break + else: + rv = mySubProcess( cmdline, env ) + + return rv + +def add_sources(sources, dir, extension): + for f in os.listdir(dir): + if f.endswith('.' + extension): + sources.append(dir + '/' + f) + + +# Try to detect the host platform automatically. +# This is used if no `platform` argument is passed +if sys.platform.startswith('linux'): + host_platform = 'linux' +elif sys.platform.startswith('freebsd'): + host_platform = 'freebsd' +elif sys.platform == 'darwin': + host_platform = 'osx' +elif sys.platform == 'win32' or sys.platform == 'msys': + host_platform = 'windows' +else: + raise ValueError( + 'Could not detect platform automatically, please specify with ' + 'platform=' + ) + +env = Environment(ENV = os.environ) + +is64 = sys.maxsize > 2**32 +if ( + env['TARGET_ARCH'] == 'amd64' or + env['TARGET_ARCH'] == 'emt64' or + env['TARGET_ARCH'] == 'x86_64' or + env['TARGET_ARCH'] == 'arm64-v8a' +): + is64 = True + +opts = Variables([], ARGUMENTS) +opts.Add(EnumVariable( + 'platform', + 'Target platform', + host_platform, + allowed_values=('linux', 'freebsd', 'osx', 'windows', 'android', 'ios'), + ignorecase=2 +)) +opts.Add(EnumVariable( + 'bits', + 'Target platform bits', + '64' if is64 else '32', + ('32', '64') +)) +opts.Add(BoolVariable( + 'use_llvm', + 'Use the LLVM compiler - only effective when targeting Linux or FreeBSD', + False +)) +opts.Add(BoolVariable( + 'use_mingw', + 'Use the MinGW compiler instead of MSVC - only effective on Windows', + False +)) +# Must be the same setting as used for cpp_bindings +opts.Add(EnumVariable( + 'target', + 'Compilation target', + 'debug', + allowed_values=('debug', 'release'), + ignorecase=2 +)) +opts.Add(PathVariable( + 'headers_dir', + 'Path to the directory containing Godot headers', + 'godot-cpp/godot-headers', + PathVariable.PathIsDir +)) +opts.Add(PathVariable( + 'custom_api_file', + 'Path to a custom JSON API file', + None, + PathVariable.PathIsFile +)) +opts.Add(EnumVariable( + 'generate_bindings', + 'Generate GDNative API bindings', + 'auto', + allowed_values = ['yes', 'no', 'auto', 'true'], + ignorecase = 2 +)) +opts.Add(EnumVariable( + 'android_arch', + 'Target Android architecture', + 'armv7', + ['armv7','arm64v8','x86','x86_64'] +)) +opts.Add( + 'macos_deployment_target', + 'macOS deployment target', + 'default' +) +opts.Add(EnumVariable( + 'ios_arch', + 'Target iOS architecture', + 'arm64', + ['armv7', 'arm64', 'x86_64'] +)) +opts.Add(BoolVariable( + 'ios_simulator', + 'Target iOS Simulator', + False +)) +opts.Add( + 'IPHONEPATH', + 'Path to iPhone toolchain', + '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain', +) +opts.Add( + 'android_api_level', + 'Target Android API level', + '18' if ARGUMENTS.get("android_arch", 'armv7') in ['armv7', 'x86'] else '21' +) +opts.Add( + 'ANDROID_NDK_ROOT', + 'Path to your Android NDK installation. By default, uses ANDROID_NDK_ROOT from your defined environment variables.', + os.environ.get("ANDROID_NDK_ROOT", None) +) +opts.Add(BoolVariable( + 'generate_template_get_node', + "Generate a template version of the Node class's get_node.", + True +)) + +# GODOT REMOTE CUSTOM OPTIONS + +opts.Add(BoolVariable( + 'godot_remote_no_default_resources', + 'Compile without embeded resources.', + False +)) +opts.Add(BoolVariable( + 'godot_remote_disable_server', + 'Compile without server side.', + False +)) +opts.Add(BoolVariable( + 'godot_remote_disable_client', + 'Compile without client side.', + False +)) + +# END + +opts.Update(env) +Help(opts.GenerateHelpText(env)) + +# This makes sure to keep the session environment variables on Windows. +# This way, you can run SCons in a Visual Studio 2017 prompt and it will find +# all the required tools +if host_platform == 'windows' and env['platform'] != 'android': + if env['bits'] == '64': + env = Environment(TARGET_ARCH='amd64') + elif env['bits'] == '32': + env = Environment(TARGET_ARCH='x86') + + opts.Update(env) + +if env['platform'] == 'linux' or env['platform'] == 'freebsd': + env['SHLIBSUFFIX'] = '.so' + if env['use_llvm']: + env['CXX'] = 'clang++' + + env.Append(CCFLAGS=['-fPIC', '-std=c++14', '-Wwrite-strings']) + env.Append(LINKFLAGS=["-Wl,-R,'$$ORIGIN'"]) + + if env['target'] == 'debug': + env.Append(CCFLAGS=['-Og', '-g']) + elif env['target'] == 'release': + env.Append(CCFLAGS=['-O3']) + + if env['bits'] == '64': + env.Append(CCFLAGS=['-m64']) + env.Append(LINKFLAGS=['-m64']) + elif env['bits'] == '32': + env.Append(CCFLAGS=['-m32']) + env.Append(LINKFLAGS=['-m32']) + +elif env['platform'] == 'osx': + # Use Clang on macOS by default + env['CXX'] = 'clang++' + env['SHLIBSUFFIX'] = '.dylib' + if env['bits'] == '32': + raise ValueError( + 'Only 64-bit builds are supported for the macOS target.' + ) + + env.Append(CCFLAGS=['-std=c++14', '-arch', 'x86_64']) + + if env['macos_deployment_target'] != 'default': + env.Append(CCFLAGS=['-mmacosx-version-min=' + env['macos_deployment_target']]) + + env.Append(LINKFLAGS=[ + '-arch', + 'x86_64', + '-framework', + 'Cocoa', + '-Wl,-undefined,dynamic_lookup', + ]) + + if env['target'] == 'debug': + env.Append(CCFLAGS=['-Og', '-g']) + elif env['target'] == 'release': + env.Append(CCFLAGS=['-O3']) + +elif env['platform'] == 'ios': + env['SHLIBSUFFIX'] = '.dylib' + if env['ios_simulator']: + sdk_name = 'iphonesimulator' + env.Append(CCFLAGS=['-mios-simulator-version-min=10.0']) + env['LIBSUFFIX'] = ".simulator" + env['LIBSUFFIX'] + else: + sdk_name = 'iphoneos' + env.Append(CCFLAGS=['-miphoneos-version-min=10.0']) + + try: + sdk_path = decode_utf8(subprocess.check_output(['xcrun', '--sdk', sdk_name, '--show-sdk-path']).strip()) + except (subprocess.CalledProcessError, OSError): + raise ValueError("Failed to find SDK path while running xcrun --sdk {} --show-sdk-path.".format(sdk_name)) + + compiler_path = env['IPHONEPATH'] + '/usr/bin/' + env['ENV']['PATH'] = env['IPHONEPATH'] + "/Developer/usr/bin/:" + env['ENV']['PATH'] + + env['CC'] = compiler_path + 'clang' + env['CXX'] = compiler_path + 'clang++' + env['AR'] = compiler_path + 'ar' + env['RANLIB'] = compiler_path + 'ranlib' + + env.Append(CCFLAGS=['-std=c++14', '-arch', env['ios_arch'], '-isysroot', sdk_path]) + env.Append(LINKFLAGS=[ + '-arch', + env['ios_arch'], + '-framework', + 'Cocoa', + '-Wl,-undefined,dynamic_lookup', + '-isysroot', sdk_path, + '-F' + sdk_path + ]) + + if env['target'] == 'debug': + env.Append(CCFLAGS=['-Og', '-g']) + elif env['target'] == 'release': + env.Append(CCFLAGS=['-O3']) + +elif env['platform'] == 'windows': + env['SHLIBSUFFIX'] = '.dll' + if host_platform == 'windows' and not env['use_mingw']: + # MSVC + env.Append(LINKFLAGS=['/WX']) + if env['target'] == 'debug': + env.Append(CCFLAGS=['/Z7', '/Od', '/EHsc', '/D_DEBUG', '/MDd']) + elif env['target'] == 'release': + env.Append(CCFLAGS=['/O2', '/EHsc', '/DNDEBUG', '/MD']) + + elif host_platform == 'linux' or host_platform == 'freebsd' or host_platform == 'osx': + # Cross-compilation using MinGW + if env['bits'] == '64': + env['CXX'] = 'x86_64-w64-mingw32-g++' + env['AR'] = "x86_64-w64-mingw32-ar" + env['RANLIB'] = "x86_64-w64-mingw32-ranlib" + env['LINK'] = "x86_64-w64-mingw32-g++" + elif env['bits'] == '32': + env['CXX'] = 'i686-w64-mingw32-g++' + env['AR'] = "i686-w64-mingw32-ar" + env['RANLIB'] = "i686-w64-mingw32-ranlib" + env['LINK'] = "i686-w64-mingw32-g++" + + elif host_platform == 'windows' and env['use_mingw']: + # Don't Clone the environment. Because otherwise, SCons will pick up msvc stuff. + env = Environment(ENV = os.environ, tools=["mingw"]) + opts.Update(env) + #env = env.Clone(tools=['mingw']) + + env["SPAWN"] = mySpawn + + # Native or cross-compilation using MinGW + if host_platform == 'linux' or host_platform == 'freebsd' or host_platform == 'osx' or env['use_mingw']: + # These options are for a release build even using target=debug + env.Append(CCFLAGS=['-O3', '-std=c++14', '-Wwrite-strings']) + env.Append(LINKFLAGS=[ + '--static', + '-Wl,--no-undefined', + '-static-libgcc', + '-static-libstdc++', + ]) + +elif env['platform'] == 'android': + env['SHLIBSUFFIX'] = '.so' + + if env['target'] == 'debug': + env.Append(CCFLAGS=['-Og']) + elif env['target'] == 'release': + env.Append(CCFLAGS=['-O3']) + + if host_platform == 'windows': + # Don't Clone the environment. Because otherwise, SCons will pick up msvc stuff. + env = Environment(ENV = os.environ, tools=["mingw"]) + opts.Update(env) + #env = env.Clone(tools=['mingw']) + + env["SPAWN"] = mySpawn + + # Verify NDK root + if not 'ANDROID_NDK_ROOT' in env: + raise ValueError("To build for Android, ANDROID_NDK_ROOT must be defined. Please set ANDROID_NDK_ROOT to the root folder of your Android NDK installation.") + + # Validate API level + api_level = int(env['android_api_level']) + if env['android_arch'] in ['x86_64', 'arm64v8'] and api_level < 21: + print("WARN: 64-bit Android architectures require an API level of at least 21; setting android_api_level=21") + env['android_api_level'] = '21' + api_level = 21 + + # Setup toolchain + toolchain = env['ANDROID_NDK_ROOT'] + "/toolchains/llvm/prebuilt/" + if host_platform == "windows": + toolchain += "windows" + import platform as pltfm + if pltfm.machine().endswith("64"): + toolchain += "-x86_64" + elif host_platform == "linux": + toolchain += "linux-x86_64" + elif host_platform == "osx": + toolchain += "darwin-x86_64" + env.PrependENVPath('PATH', toolchain + "/bin") # This does nothing half of the time, but we'll put it here anyways + + # Get architecture info + arch_info_table = { + "armv7" : { + "march":"armv7-a", "target":"armv7a-linux-androideabi", "tool_path":"arm-linux-androideabi", "compiler_path":"armv7a-linux-androideabi", + "ccflags" : ['-mfpu=neon'] + }, + "arm64v8" : { + "march":"armv8-a", "target":"aarch64-linux-android", "tool_path":"aarch64-linux-android", "compiler_path":"aarch64-linux-android", + "ccflags" : [] + }, + "x86" : { + "march":"i686", "target":"i686-linux-android", "tool_path":"i686-linux-android", "compiler_path":"i686-linux-android", + "ccflags" : ['-mstackrealign'] + }, + "x86_64" : {"march":"x86-64", "target":"x86_64-linux-android", "tool_path":"x86_64-linux-android", "compiler_path":"x86_64-linux-android", + "ccflags" : [] + } + } + arch_info = arch_info_table[env['android_arch']] + + # Setup tools + env['CC'] = toolchain + "/bin/clang" + env['CXX'] = toolchain + "/bin/clang++" + env['AR'] = toolchain + "/bin/" + arch_info['tool_path'] + "-ar" + + env.Append(CCFLAGS=['--target=' + arch_info['target'] + env['android_api_level'], '-march=' + arch_info['march'], '-fPIC'])#, '-fPIE', '-fno-addrsig', '-Oz']) + env.Append(CCFLAGS=arch_info['ccflags']) + +arch_suffix = env['bits'] +if env['platform'] == 'android': + arch_suffix = env['android_arch'] +if env['platform'] == 'ios': + arch_suffix = env['ios_arch'] + +env.Append(CPPPATH=[ + '.', + env['headers_dir'], + 'godot_remote', + 'godot-cpp/include', + 'godot-cpp/include/gen', + 'godot-cpp/include/core', +]) + +env.Append(LIBPATH=['godot-cpp/bin/']) +env.Append(LIBS=[ + 'libgodot-cpp.{}.{}.{}{}'.format( # godot-cpp lib + env['platform'], + env['target'], + arch_suffix, + env['LIBSUFFIX']), +]) + +# Generate bindings? +json_api_file = '' + +if 'custom_api_file' in env: + json_api_file = env['custom_api_file'] +else: + json_api_file = os.path.join(os.getcwd(), env['headers_dir'], 'api.json') + +if env['generate_bindings'] == 'auto': + # Check if generated files exist + should_generate_bindings = not os.path.isfile(os.path.join(os.getcwd(), 'src', 'gen', 'Object.cpp')) +else: + should_generate_bindings = env['generate_bindings'] in ['yes', 'true'] + +env.Append(CPPDEFINES=['GDNATIVE_LIBRARY']) + +if env['godot_remote_no_default_resources'] == True: + env.Append(CPPDEFINES=['NO_GODOTREMOTE_DEFAULT_RESOURCES']) + +if env['godot_remote_disable_server'] == True: + env.Append(CPPDEFINES=['NO_GODOTREMOTE_SERVER']) + +if env['godot_remote_disable_client'] == True: + env.Append(CPPDEFINES=['NO_GODOTREMOTE_CLIENT']) + +# Sources to compile +sources = [] +add_sources(sources, 'godot_remote', 'cpp') + +library = env.SharedLibrary( + target='bin/' + 'godot_remote.{}.{}.{}{}'.format( + env['platform'], + env['target'], + arch_suffix, + env['SHLIBSUFFIX'] + #env['LIBSUFFIX'] + ), source=sources +) +Default(library) diff --git a/modules/godot_remote/build_android_gdn.bat b/modules/godot_remote/build_android_gdn.bat new file mode 100644 index 0000000..b3ff921 --- /dev/null +++ b/modules/godot_remote/build_android_gdn.bat @@ -0,0 +1 @@ +%ANDROID_NDK_ROOT%/ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk APP_PLATFORM=android-21 -j8 \ No newline at end of file diff --git a/modules/godot_remote/build_godot_cpp.bat b/modules/godot_remote/build_godot_cpp.bat new file mode 100644 index 0000000..b959792 --- /dev/null +++ b/modules/godot_remote/build_godot_cpp.bat @@ -0,0 +1,14 @@ +cd godot-cpp +set cpu=%NUMBER_OF_PROCESSORS% +set api=custom_api_file="../api.json" + +scons generate_bindings=true platform=windows target=release bits=64 -j%cpu% %api% +scons platform=windows target=release bits=64 -j%cpu% %api% +scons platform=windows target=debug bits=64 -j%cpu% %api% + +scons platform=android target=debug android_arch=arm64v8 -j%cpu% %api% + +scons platform=android target=release android_arch=arm64v8 -j%cpu% %api% +scons platform=android target=release android_arch=armv7 -j%cpu% %api% +scons platform=android target=release android_arch=x86 -j%cpu% %api% +scons platform=android target=release android_arch=x86_64 -j%cpu% %api% \ No newline at end of file diff --git a/modules/godot_remote/build_windows.bat b/modules/godot_remote/build_windows.bat new file mode 100644 index 0000000..d1c8b33 --- /dev/null +++ b/modules/godot_remote/build_windows.bat @@ -0,0 +1 @@ +scons platform=windows bits=64 target=release -j8 \ No newline at end of file diff --git a/modules/godot_remote/examples/custom_input_scene/CustomInput.gd b/modules/godot_remote/examples/custom_input_scene/CustomInput.gd new file mode 100644 index 0000000..846f841 --- /dev/null +++ b/modules/godot_remote/examples/custom_input_scene/CustomInput.gd @@ -0,0 +1,10 @@ +extends Control + +# If you want to disable capturing touch events or mouse pointer +# you can use this method +func _enter_tree(): + GodotRemote.get_device().set_capture_pointer(false) + +# And after removing this scene you need to restore value +func _exit_tree(): + GodotRemote.get_device().set_capture_pointer(true) diff --git a/modules/godot_remote/examples/custom_input_scene/CustomInput.tscn b/modules/godot_remote/examples/custom_input_scene/CustomInput.tscn new file mode 100644 index 0000000..9b8d726 --- /dev/null +++ b/modules/godot_remote/examples/custom_input_scene/CustomInput.tscn @@ -0,0 +1,40 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://CustomInput.gd" type="Script" id=1] +[ext_resource path="res://icon.png" type="Texture" id=2] + +[node name="CustomInput" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Control" type="Control" parent="."] +anchor_top = 0.5 +anchor_bottom = 0.5 +margin_top = -20.0 +margin_right = 40.0 +margin_bottom = 20.0 + +[node name="TouchScreenButton" type="TouchScreenButton" parent="Control"] +position = Vector2( 33, -180 ) +scale = Vector2( 5.45313, 6.5 ) +normal = ExtResource( 2 ) +action = "ui_left" + +[node name="Control2" type="Control" parent="."] +anchor_left = 1.0 +anchor_top = 0.5 +anchor_right = 1.0 +anchor_bottom = 0.5 +margin_left = -40.0 +margin_top = -20.0 +margin_bottom = 20.0 + +[node name="TouchScreenButton2" type="TouchScreenButton" parent="Control2"] +position = Vector2( -342.74, -180 ) +scale = Vector2( 5.45313, 6.5 ) +normal = ExtResource( 2 ) +action = "ui_right" diff --git a/modules/godot_remote/examples/custom_input_scene/Main.tscn b/modules/godot_remote/examples/custom_input_scene/Main.tscn new file mode 100644 index 0000000..ec12619 --- /dev/null +++ b/modules/godot_remote/examples/custom_input_scene/Main.tscn @@ -0,0 +1,37 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://Player.gd" type="Script" id=2] +[ext_resource path="res://icon.png" type="Texture" id=3] + +[sub_resource type="RectangleShape2D" id=1] +extents = Vector2( 32.04, 30.9 ) + +[sub_resource type="RectangleShape2D" id=2] +extents = Vector2( 32, 32 ) + +[node name="Main" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Ground" type="StaticBody2D" parent="."] +position = Vector2( 522, 493.5 ) +scale = Vector2( 17.1563, 0.265625 ) + +[node name="Sprite" type="Sprite" parent="Ground"] +texture = ExtResource( 3 ) + +[node name="CollisionShape2D" type="CollisionShape2D" parent="Ground"] +shape = SubResource( 1 ) + +[node name="Player" type="KinematicBody2D" parent="."] +position = Vector2( 527.072, 375.837 ) +script = ExtResource( 2 ) + +[node name="Sprite" type="Sprite" parent="Player"] +texture = ExtResource( 3 ) + +[node name="CollisionShape2D" type="CollisionShape2D" parent="Player"] +shape = SubResource( 2 ) diff --git a/modules/godot_remote/examples/custom_input_scene/Player.gd b/modules/godot_remote/examples/custom_input_scene/Player.gd new file mode 100644 index 0000000..d278a1d --- /dev/null +++ b/modules/godot_remote/examples/custom_input_scene/Player.gd @@ -0,0 +1,15 @@ +extends KinematicBody2D + +var speed = 500.0 + +# Basic player logic +func _physics_process(delta): + var direction = Vector2() + + if Input.is_action_pressed("ui_left"): + direction.x -= 1 + if Input.is_action_pressed("ui_right"): + direction.x += 1 + + var velocity = (direction * speed + Vector2.DOWN * 98) + move_and_slide(velocity, Vector2.UP) diff --git a/modules/godot_remote/examples/custom_input_scene/default_env.tres b/modules/godot_remote/examples/custom_input_scene/default_env.tres new file mode 100644 index 0000000..20207a4 --- /dev/null +++ b/modules/godot_remote/examples/custom_input_scene/default_env.tres @@ -0,0 +1,7 @@ +[gd_resource type="Environment" load_steps=2 format=2] + +[sub_resource type="ProceduralSky" id=1] + +[resource] +background_mode = 2 +background_sky = SubResource( 1 ) diff --git a/modules/godot_remote/examples/custom_input_scene/icon.png b/modules/godot_remote/examples/custom_input_scene/icon.png new file mode 100644 index 0000000..0af4d53 Binary files /dev/null and b/modules/godot_remote/examples/custom_input_scene/icon.png differ diff --git a/modules/godot_remote/examples/custom_input_scene/icon.png.import b/modules/godot_remote/examples/custom_input_scene/icon.png.import new file mode 100644 index 0000000..96cbf46 --- /dev/null +++ b/modules/godot_remote/examples/custom_input_scene/icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.png" +dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/examples/custom_input_scene/project.godot b/modules/godot_remote/examples/custom_input_scene/project.godot new file mode 100644 index 0000000..77ed7c1 --- /dev/null +++ b/modules/godot_remote/examples/custom_input_scene/project.godot @@ -0,0 +1,49 @@ +; 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=4 + +_global_script_classes=[ ] +_global_script_class_icons={ + +} + +[application] + +config/name="Custom Input Scene" +run/main_scene="res://Main.tscn" +config/icon="res://icon.png" + +[debug] + +godot_remote/server_custom_input_scene/custom_input_scene="res://CustomInput.tscn" +godot_remote/server/video_stream_enabled=false + +[input] + +ui_left={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777231,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":14,"pressure":0.0,"pressed":false,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"unicode":0,"echo":false,"script":null) + ] +} +ui_right={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777233,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":15,"pressure":0.0,"pressed":false,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"unicode":0,"echo":false,"script":null) + ] +} + +[rendering] + +quality/driver/driver_name="GLES2" +vram_compression/import_etc=true +vram_compression/import_etc2=false +environment/default_environment="res://default_env.tres" diff --git a/modules/godot_remote/examples/custom_user_packets/Control.gd b/modules/godot_remote/examples/custom_user_packets/Control.gd new file mode 100644 index 0000000..ccab0f7 --- /dev/null +++ b/modules/godot_remote/examples/custom_user_packets/Control.gd @@ -0,0 +1,16 @@ +extends Control + +func _ready() -> void: + GodotRemote.connect("device_added", self, "device_added") + +func device_added(): + print(GodotRemote.get_device().get_custom_input_scene()) + GodotRemote.get_device().connect("user_data_received", self, "user_data_received") + +func user_data_received(packet_id, user_data): + print("Received packet: %s, data: %s" % [packet_id, user_data]) + match packet_id: + "bg_color": VisualServer.set_default_clear_color(user_data) + +func _on_HSlider_value_changed(value: float) -> void: + GodotRemote.get_device().send_user_data("slider_value", value, false) diff --git a/modules/godot_remote/examples/custom_user_packets/Control.tscn b/modules/godot_remote/examples/custom_user_packets/Control.tscn new file mode 100644 index 0000000..f9078e8 --- /dev/null +++ b/modules/godot_remote/examples/custom_user_packets/Control.tscn @@ -0,0 +1,74 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://Control.gd" type="Script" id=1] +[ext_resource path="res://icon.png" type="Texture" id=2] + +[sub_resource type="Animation" id=1] +resource_name = "New Anim" +length = 3.0 +loop = true +tracks/0/type = "value" +tracks/0/path = NodePath("Control:rect_position") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/keys = { +"times": PoolRealArray( 0, 0.9, 2.2 ), +"transitions": PoolRealArray( 1, 1, 1 ), +"update": 0, +"values": [ Vector2( 730, 32 ), Vector2( 815.526, 473.886 ), Vector2( 203.097, 448.007 ) ] +} +tracks/1/type = "value" +tracks/1/path = NodePath("Control:rect_rotation") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/keys = { +"times": PoolRealArray( 0, 0.9, 2.2 ), +"transitions": PoolRealArray( 1, 1, 1 ), +"update": 0, +"values": [ 0.0, 422.2, -251.5 ] +} + +[node name="Control" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="HSlider" type="HSlider" parent="."] +margin_left = 9.0 +margin_top = 129.0 +margin_right = 409.0 +margin_bottom = 162.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Label" type="Label" parent="."] +margin_left = 15.0 +margin_top = 103.0 +margin_right = 334.0 +margin_bottom = 125.0 +text = "Remote progress bar value" + +[node name="Control" type="TextureRect" parent="."] +margin_left = 454.735 +margin_top = 458.64 +margin_right = 518.738 +margin_bottom = 522.641 +rect_rotation = 25.3133 +texture = ExtResource( 2 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +autoplay = "New Anim" +"anims/New Anim" = SubResource( 1 ) + +[connection signal="value_changed" from="HSlider" to="." method="_on_HSlider_value_changed"] diff --git a/modules/godot_remote/examples/custom_user_packets/ControlColorRemote.gd b/modules/godot_remote/examples/custom_user_packets/ControlColorRemote.gd new file mode 100644 index 0000000..d50a91d --- /dev/null +++ b/modules/godot_remote/examples/custom_user_packets/ControlColorRemote.gd @@ -0,0 +1,12 @@ +extends Control + +func _ready() -> void: + GodotRemote.get_device().connect("user_data_received", self, "user_data_received") + +func _on_ColorPickerButton_color_changed(color: Color) -> void: + GodotRemote.get_device().send_user_data("bg_color", color, false) + +func user_data_received(packet_id, user_data): + print("Received packet: %s, data: %s" % [packet_id, user_data]) + match packet_id: + "slider_value": $ProgressBar.value = user_data diff --git a/modules/godot_remote/examples/custom_user_packets/ControlColorRemote.tscn b/modules/godot_remote/examples/custom_user_packets/ControlColorRemote.tscn new file mode 100644 index 0000000..297b7aa --- /dev/null +++ b/modules/godot_remote/examples/custom_user_packets/ControlColorRemote.tscn @@ -0,0 +1,61 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://ControlColorRemote.gd" type="Script" id=1] + +[node name="Control" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +script = ExtResource( 1 ) +__meta__ = { +"_edit_lock_": true, +"_edit_use_anchors_": false +} + +[node name="ProgressBar" type="ProgressBar" parent="."] +anchor_left = 0.0556641 +anchor_top = 0.0383333 +anchor_right = 0.959961 +anchor_bottom = 0.0883333 +__meta__ = { +"_edit_use_anchors_": true +} + +[node name="Control" type="Control" parent="."] +anchor_left = 0.319902 +anchor_top = 0.262483 +anchor_right = 0.702714 +anchor_bottom = 0.945817 +margin_bottom = -3.8147e-06 +__meta__ = { +"_edit_use_anchors_": true +} + +[node name="VBoxContainer" type="VBoxContainer" parent="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Label" type="Label" parent="Control/VBoxContainer"] +margin_top = 45.0 +margin_right = 391.0 +margin_bottom = 59.0 +size_flags_vertical = 6 +size_flags_stretch_ratio = 0.35 +text = "SELECT BACKGROUND COLOR" +align = 1 +__meta__ = { +"_edit_use_anchors_": true +} + +[node name="ColorPickerButton" type="ColorPickerButton" parent="Control/VBoxContainer"] +margin_top = 109.0 +margin_right = 391.0 +margin_bottom = 410.0 +size_flags_vertical = 3 +__meta__ = { +"_edit_use_anchors_": true +} + +[connection signal="color_changed" from="Control/VBoxContainer/ColorPickerButton" to="." method="_on_ColorPickerButton_color_changed"] diff --git a/modules/godot_remote/examples/custom_user_packets/default_env.tres b/modules/godot_remote/examples/custom_user_packets/default_env.tres new file mode 100644 index 0000000..20207a4 --- /dev/null +++ b/modules/godot_remote/examples/custom_user_packets/default_env.tres @@ -0,0 +1,7 @@ +[gd_resource type="Environment" load_steps=2 format=2] + +[sub_resource type="ProceduralSky" id=1] + +[resource] +background_mode = 2 +background_sky = SubResource( 1 ) diff --git a/modules/godot_remote/examples/custom_user_packets/icon.png b/modules/godot_remote/examples/custom_user_packets/icon.png new file mode 100644 index 0000000..1128fca Binary files /dev/null and b/modules/godot_remote/examples/custom_user_packets/icon.png differ diff --git a/modules/godot_remote/examples/custom_user_packets/icon.png.import b/modules/godot_remote/examples/custom_user_packets/icon.png.import new file mode 100644 index 0000000..9725e52 --- /dev/null +++ b/modules/godot_remote/examples/custom_user_packets/icon.png.import @@ -0,0 +1,36 @@ +[remap] + +importer="texture" +type="StreamTexture" +path.s3tc="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.s3tc.stex" +path.etc="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.etc.stex" +metadata={ +"imported_formats": [ "s3tc", "etc" ], +"vram_texture": true +} + +[deps] + +source_file="res://icon.png" +dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.s3tc.stex", "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.etc.stex" ] + +[params] + +compress/mode=2 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=true +flags/filter=true +flags/mipmaps=true +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=false +svg/scale=1.0 diff --git a/modules/godot_remote/examples/custom_user_packets/project.godot b/modules/godot_remote/examples/custom_user_packets/project.godot new file mode 100644 index 0000000..61f760c --- /dev/null +++ b/modules/godot_remote/examples/custom_user_packets/project.godot @@ -0,0 +1,26 @@ +; 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=4 + +[application] + +config/name="Custom User Packets" +run/main_scene="res://Control.tscn" +config/icon="res://icon.png" + +[debug] + +godot_remote/server_custom_input_scene/custom_input_scene="res://ControlColorRemote.tscn" + +[rendering] + +quality/driver/driver_name="GLES2" +vram_compression/import_etc=true +vram_compression/import_etc2=false +environment/default_environment="res://default_env.tres" diff --git a/modules/godot_remote/examples/simple_client/UniqueL0ngNameThatINeverOverrideFromServer/ControlToShowStream.gd b/modules/godot_remote/examples/simple_client/UniqueL0ngNameThatINeverOverrideFromServer/ControlToShowStream.gd new file mode 100644 index 0000000..3ceeb5a --- /dev/null +++ b/modules/godot_remote/examples/simple_client/UniqueL0ngNameThatINeverOverrideFromServer/ControlToShowStream.gd @@ -0,0 +1,32 @@ +extends Control + + +# firstly you need to disable autostart GodotRemote in Project Settings/Debug/Godot Remote/General +# and change the Network/Limits/Connect Timeout Seconds to 1 otherwise app will be closing very long time +func _ready(): + # create client + GodotRemote.create_remote_device(GodotRemote.DEVICE_CLIENT) + + # get device and convert it to client class + var d : GRClient = GodotRemote.get_device() + # set control where you want to see stream. it can be whole screen control or custom 'viewport' + d.set_control_to_show_in(self) + # set address of server. optional if you want to connect to other projects on one pc or if you use connection over adb + d.set_address("127.0.0.1") + # set password to get acces to the server if it need one + d.password = "1234" + # and change other settings if you need it + + # start client + GodotRemote.start_remote_device() + +# If you need to support custom input scenes best way to avoid any errors by overriding resources +# from server is just put all assets of this project to folder with unique and long name +# +# Example: +# *res:// +# -UniqueL0ngNameThatINeverOverrideFromServer +# -icon.png +# -default_env.tres +# -Scene.tscn +# -Scene.gd diff --git a/modules/godot_remote/examples/simple_client/UniqueL0ngNameThatINeverOverrideFromServer/ControlToShowStream.tscn b/modules/godot_remote/examples/simple_client/UniqueL0ngNameThatINeverOverrideFromServer/ControlToShowStream.tscn new file mode 100644 index 0000000..b117538 --- /dev/null +++ b/modules/godot_remote/examples/simple_client/UniqueL0ngNameThatINeverOverrideFromServer/ControlToShowStream.tscn @@ -0,0 +1,11 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://UniqueL0ngNameThatINeverOverrideFromServer/ControlToShowStream.gd" type="Script" id=1] + +[node name="ControlToShowStreamIn" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} diff --git a/modules/godot_remote/examples/simple_client/UniqueL0ngNameThatINeverOverrideFromServer/icon.png b/modules/godot_remote/examples/simple_client/UniqueL0ngNameThatINeverOverrideFromServer/icon.png new file mode 100644 index 0000000..35be6c8 Binary files /dev/null and b/modules/godot_remote/examples/simple_client/UniqueL0ngNameThatINeverOverrideFromServer/icon.png differ diff --git a/modules/godot_remote/examples/simple_client/UniqueL0ngNameThatINeverOverrideFromServer/icon.png.import b/modules/godot_remote/examples/simple_client/UniqueL0ngNameThatINeverOverrideFromServer/icon.png.import new file mode 100644 index 0000000..899cebf --- /dev/null +++ b/modules/godot_remote/examples/simple_client/UniqueL0ngNameThatINeverOverrideFromServer/icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon.png-9b69519d77c698a6f97b5d1c3f5e548f.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://UniqueL0ngNameThatINeverOverrideFromServer/icon.png" +dest_files=[ "res://.import/icon.png-9b69519d77c698a6f97b5d1c3f5e548f.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/examples/simple_client/project.godot b/modules/godot_remote/examples/simple_client/project.godot new file mode 100644 index 0000000..4f6193b --- /dev/null +++ b/modules/godot_remote/examples/simple_client/project.godot @@ -0,0 +1,34 @@ +; 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=4 + +[application] + +config/name="Example Client" +run/main_scene="res://UniqueL0ngNameThatINeverOverrideFromServer/ControlToShowStream.tscn" +config/icon="res://UniqueL0ngNameThatINeverOverrideFromServer/icon.png" + +[debug] + +settings/stdout/verbose_stdout=true +godot_remote/general/autostart=false + +[editor_plugins] + +enabled=PoolStringArray( ) + +[network] + +limits/tcp/connect_timeout_seconds=1 + +[rendering] + +quality/driver/driver_name="GLES2" +vram_compression/import_etc=true +vram_compression/import_etc2=false diff --git a/modules/godot_remote/examples/viewport_size_syncing/Main.gd b/modules/godot_remote/examples/viewport_size_syncing/Main.gd new file mode 100644 index 0000000..cb04a37 --- /dev/null +++ b/modules/godot_remote/examples/viewport_size_syncing/Main.gd @@ -0,0 +1,23 @@ +extends Control + +var is_vertical = false +var screen_aspect = OS.window_size.x / OS.window_size.y + +func _ready(): + # Waiting for one frame until the device is created + yield(get_tree(), "idle_frame") + # Connect to server signals + GodotRemote.get_device().connect("client_viewport_orientation_changed", self, "_screen_rotated") + GodotRemote.get_device().connect("client_viewport_aspect_ratio_changed", self, "_screen_aspect_changed") + +# Simple functions to resize window +func _screen_rotated(_is_vertical): + is_vertical = _is_vertical + if _is_vertical: + OS.window_size = Vector2(600, 600 / screen_aspect) + else: + OS.window_size = Vector2(600 * screen_aspect, 600) + +func _screen_aspect_changed(_aspect): + screen_aspect = _aspect + _screen_rotated(is_vertical) diff --git a/modules/godot_remote/examples/viewport_size_syncing/Main.tscn b/modules/godot_remote/examples/viewport_size_syncing/Main.tscn new file mode 100644 index 0000000..41213b4 --- /dev/null +++ b/modules/godot_remote/examples/viewport_size_syncing/Main.tscn @@ -0,0 +1,15 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://icon.png" type="Texture" id=1] +[ext_resource path="res://Main.gd" type="Script" id=2] + +[node name="Main" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +script = ExtResource( 2 ) + +[node name="TextureRect" type="TextureRect" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +texture = ExtResource( 1 ) +stretch_mode = 1 diff --git a/modules/godot_remote/examples/viewport_size_syncing/default_env.tres b/modules/godot_remote/examples/viewport_size_syncing/default_env.tres new file mode 100644 index 0000000..20207a4 --- /dev/null +++ b/modules/godot_remote/examples/viewport_size_syncing/default_env.tres @@ -0,0 +1,7 @@ +[gd_resource type="Environment" load_steps=2 format=2] + +[sub_resource type="ProceduralSky" id=1] + +[resource] +background_mode = 2 +background_sky = SubResource( 1 ) diff --git a/modules/godot_remote/examples/viewport_size_syncing/icon.png b/modules/godot_remote/examples/viewport_size_syncing/icon.png new file mode 100644 index 0000000..6117566 Binary files /dev/null and b/modules/godot_remote/examples/viewport_size_syncing/icon.png differ diff --git a/modules/godot_remote/examples/viewport_size_syncing/icon.png.import b/modules/godot_remote/examples/viewport_size_syncing/icon.png.import new file mode 100644 index 0000000..96cbf46 --- /dev/null +++ b/modules/godot_remote/examples/viewport_size_syncing/icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.png" +dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/examples/viewport_size_syncing/project.godot b/modules/godot_remote/examples/viewport_size_syncing/project.godot new file mode 100644 index 0000000..4edafa0 --- /dev/null +++ b/modules/godot_remote/examples/viewport_size_syncing/project.godot @@ -0,0 +1,26 @@ +; 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=4 + +[application] + +config/name="Viewport Size Syncing" +run/main_scene="res://Main.tscn" +config/icon="res://icon.png" + +[display] + +window/size/width=600 + +[rendering] + +quality/driver/driver_name="GLES2" +vram_compression/import_etc=true +vram_compression/import_etc2=false +environment/default_environment="res://default_env.tres" diff --git a/modules/godot_remote/godot_remote/GRClient.cpp b/modules/godot_remote/godot_remote/GRClient.cpp new file mode 100644 index 0000000..f1ec16d --- /dev/null +++ b/modules/godot_remote/godot_remote/GRClient.cpp @@ -0,0 +1,2001 @@ +/* GRClient.cpp */ + +#ifndef NO_GODOTREMOTE_CLIENT + +#include "GRClient.h" +#include "GRNotifications.h" +#include "GRPacket.h" +#include "GRResources.h" +#include "GodotRemote.h" + +#ifndef GDNATIVE_LIBRARY + +#include "core/input_map.h" +#include "core/io/file_access_pack.h" +#include "core/io/ip.h" +#include "core/io/resource_loader.h" +#include "core/io/tcp_server.h" +#include "core/os/dir_access.h" +#include "core/os/file_access.h" +#include "core/os/input_event.h" +#include "core/os/thread_safe.h" +#include "main/input_default.h" +#include "scene/gui/control.h" +#include "scene/main/node.h" +#include "scene/main/scene_tree.h" +#include "scene/main/viewport.h" +#include "scene/resources/material.h" +#include "scene/resources/packed_scene.h" +#include "scene/resources/texture.h" + +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace godot; + +#define BUTTON_WHEEL_UP GlobalConstants::BUTTON_WHEEL_UP +#define BUTTON_WHEEL_DOWN GlobalConstants::BUTTON_WHEEL_DOWN +#define BUTTON_WHEEL_LEFT GlobalConstants::BUTTON_WHEEL_LEFT +#define BUTTON_WHEEL_RIGHT GlobalConstants::BUTTON_WHEEL_RIGHT +#endif + +enum class DeletingVarName { + CONTROL_TO_SHOW_STREAM, + TEXTURE_TO_SHOW_STREAM, + INPUT_COLLECTOR, + CUSTOM_INPUT_SCENE, +}; + +using namespace GRUtils; + +#ifndef GDNATIVE_LIBRARY +void GRClient::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_update_texture_from_image", "image"), &GRClient::_update_texture_from_image); + ClassDB::bind_method(D_METHOD("_update_stream_texture_state", "state"), &GRClient::_update_stream_texture_state); + ClassDB::bind_method(D_METHOD("_force_update_stream_viewport_signals"), &GRClient::_force_update_stream_viewport_signals); + ClassDB::bind_method(D_METHOD("_viewport_size_changed"), &GRClient::_viewport_size_changed); + ClassDB::bind_method(D_METHOD("_load_custom_input_scene", "_data"), &GRClient::_load_custom_input_scene); + ClassDB::bind_method(D_METHOD("_remove_custom_input_scene"), &GRClient::_remove_custom_input_scene); + ClassDB::bind_method(D_METHOD("_on_node_deleting", "var_name"), &GRClient::_on_node_deleting); + + ClassDB::bind_method(D_METHOD("set_control_to_show_in", "control_node", "position_in_node"), &GRClient::set_control_to_show_in, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("set_custom_no_signal_texture", "texture"), &GRClient::set_custom_no_signal_texture); + ClassDB::bind_method(D_METHOD("set_custom_no_signal_vertical_texture", "texture"), &GRClient::set_custom_no_signal_vertical_texture); + ClassDB::bind_method(D_METHOD("set_custom_no_signal_material", "material"), &GRClient::set_custom_no_signal_material); + ClassDB::bind_method(D_METHOD("set_address_port", "ip", "port"), &GRClient::set_address_port); + ClassDB::bind_method(D_METHOD("set_address", "ip"), &GRClient::set_address); + ClassDB::bind_method(D_METHOD("set_server_setting", "setting", "value"), &GRClient::set_server_setting); + ClassDB::bind_method(D_METHOD("disable_overriding_server_settings"), &GRClient::disable_overriding_server_settings); + + ClassDB::bind_method(D_METHOD("get_custom_input_scene"), &GRClient::get_custom_input_scene); + ClassDB::bind_method(D_METHOD("get_address"), &GRClient::get_address); + ClassDB::bind_method(D_METHOD("is_stream_active"), &GRClient::is_stream_active); + ClassDB::bind_method(D_METHOD("is_connected_to_host"), &GRClient::is_connected_to_host); + + ADD_SIGNAL(MethodInfo("custom_input_scene_added")); + ADD_SIGNAL(MethodInfo("custom_input_scene_removed")); + + ADD_SIGNAL(MethodInfo("stream_state_changed", PropertyInfo(Variant::INT, "state", PROPERTY_HINT_ENUM))); + ADD_SIGNAL(MethodInfo("connection_state_changed", PropertyInfo(Variant::BOOL, "is_connected"))); + ADD_SIGNAL(MethodInfo("mouse_mode_changed", PropertyInfo(Variant::INT, "mouse_mode"))); + ADD_SIGNAL(MethodInfo("server_settings_received", PropertyInfo(Variant::DICTIONARY, "settings"))); + + // SETGET + ClassDB::bind_method(D_METHOD("set_capture_on_focus", "val"), &GRClient::set_capture_on_focus); + ClassDB::bind_method(D_METHOD("set_capture_when_hover", "val"), &GRClient::set_capture_when_hover); + ClassDB::bind_method(D_METHOD("set_capture_pointer", "val"), &GRClient::set_capture_pointer); + ClassDB::bind_method(D_METHOD("set_capture_input", "val"), &GRClient::set_capture_input); + ClassDB::bind_method(D_METHOD("set_connection_type", "type"), &GRClient::set_connection_type); + ClassDB::bind_method(D_METHOD("set_target_send_fps", "fps"), &GRClient::set_target_send_fps); + ClassDB::bind_method(D_METHOD("set_stretch_mode", "mode"), &GRClient::set_stretch_mode); + ClassDB::bind_method(D_METHOD("set_texture_filtering", "is_filtered"), &GRClient::set_texture_filtering); + ClassDB::bind_method(D_METHOD("set_password", "password"), &GRClient::set_password); + ClassDB::bind_method(D_METHOD("set_device_id", "id"), &GRClient::set_device_id); + ClassDB::bind_method(D_METHOD("set_viewport_orientation_syncing", "is_syncing"), &GRClient::set_viewport_orientation_syncing); + ClassDB::bind_method(D_METHOD("set_viewport_aspect_ratio_syncing", "is_syncing"), &GRClient::set_viewport_aspect_ratio_syncing); + ClassDB::bind_method(D_METHOD("set_server_settings_syncing", "is_syncing"), &GRClient::set_server_settings_syncing); + + ClassDB::bind_method(D_METHOD("is_capture_on_focus"), &GRClient::is_capture_on_focus); + ClassDB::bind_method(D_METHOD("is_capture_when_hover"), &GRClient::is_capture_when_hover); + ClassDB::bind_method(D_METHOD("is_capture_pointer"), &GRClient::is_capture_pointer); + ClassDB::bind_method(D_METHOD("is_capture_input"), &GRClient::is_capture_input); + ClassDB::bind_method(D_METHOD("get_connection_type"), &GRClient::get_connection_type); + ClassDB::bind_method(D_METHOD("get_target_send_fps"), &GRClient::get_target_send_fps); + ClassDB::bind_method(D_METHOD("get_stretch_mode"), &GRClient::get_stretch_mode); + ClassDB::bind_method(D_METHOD("get_texture_filtering"), &GRClient::get_texture_filtering); + ClassDB::bind_method(D_METHOD("get_password"), &GRClient::get_password); + ClassDB::bind_method(D_METHOD("get_device_id"), &GRClient::get_device_id); + ClassDB::bind_method(D_METHOD("is_viewport_orientation_syncing"), &GRClient::is_viewport_orientation_syncing); + ClassDB::bind_method(D_METHOD("is_viewport_aspect_ratio_syncing"), &GRClient::is_viewport_aspect_ratio_syncing); + ClassDB::bind_method(D_METHOD("is_server_settings_syncing"), &GRClient::is_server_settings_syncing); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "capture_on_focus"), "set_capture_on_focus", "is_capture_on_focus"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "capture_when_hover"), "set_capture_when_hover", "is_capture_when_hover"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "capture_pointer"), "set_capture_pointer", "is_capture_pointer"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "capture_input"), "set_capture_input", "is_capture_input"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "connection_type", PROPERTY_HINT_ENUM, "WiFi,ADB"), "set_connection_type", "get_connection_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "target_send_fps", PROPERTY_HINT_RANGE, "1,1000"), "set_target_send_fps", "get_target_send_fps"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_mode", PROPERTY_HINT_ENUM, "Fill,Keep Aspect"), "set_stretch_mode", "get_stretch_mode"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "texture_filtering"), "set_texture_filtering", "get_texture_filtering"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "password"), "set_password", "get_password"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "device_id"), "set_device_id", "get_device_id"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "viewport_orientation_syncing"), "set_viewport_orientation_syncing", "is_viewport_orientation_syncing"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "viewport_aspect_ratio_syncing"), "set_viewport_aspect_ratio_syncing", "is_viewport_aspect_ratio_syncing"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "server_settings_syncing"), "set_server_settings_syncing", "is_server_settings_syncing"); + + BIND_ENUM_CONSTANT(CONNECTION_ADB); + BIND_ENUM_CONSTANT(CONNECTION_WiFi); + + BIND_ENUM_CONSTANT(STRETCH_KEEP_ASPECT); + BIND_ENUM_CONSTANT(STRETCH_FILL); + + BIND_ENUM_CONSTANT(STREAM_NO_SIGNAL); + BIND_ENUM_CONSTANT(STREAM_ACTIVE); + BIND_ENUM_CONSTANT(STREAM_NO_IMAGE); +} + +#else + +void GRClient::_register_methods() { + /////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////// + /* + METHOD_REG(GRClient::_internal_call_only_deffered_start); + METHOD_REG(GRClient::_internal_call_only_deffered_stop); + + METHOD_REG(GRClient::_internal_call_only_deffered_restart); + + METHOD_REG(GRClient::get_avg_ping); + METHOD_REG(GRClient::get_avg_fps); + + METHOD_REG(GRClient::get_port); + METHOD_REG(GRClient::set_port); + + METHOD_REG(GRClient::start); + METHOD_REG(GRClient::stop); + METHOD_REG(GRClient::get_status); + + register_signal("status_changed", "status", GODOT_VARIANT_TYPE_INT); + register_property("port", &GRClient::set_port, &GRClient::get_port, 52341); + */ + /////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////// + + METHOD_REG(GRClient, _notification); + METHOD_REG(GRClient, _thread_connection); + METHOD_REG(GRClient, _thread_image_decoder); + + METHOD_REG(GRClient, _update_texture_from_image); + METHOD_REG(GRClient, _update_stream_texture_state); + METHOD_REG(GRClient, _force_update_stream_viewport_signals); + METHOD_REG(GRClient, _viewport_size_changed); + METHOD_REG(GRClient, _load_custom_input_scene); + METHOD_REG(GRClient, _remove_custom_input_scene); + METHOD_REG(GRClient, _on_node_deleting); + + METHOD_REG(GRClient, set_control_to_show_in); + METHOD_REG(GRClient, set_custom_no_signal_texture); + METHOD_REG(GRClient, set_custom_no_signal_vertical_texture); + METHOD_REG(GRClient, set_custom_no_signal_material); + METHOD_REG(GRClient, set_address_port); + METHOD_REG(GRClient, set_address); + METHOD_REG(GRClient, set_server_setting); + METHOD_REG(GRClient, disable_overriding_server_settings); + + METHOD_REG(GRClient, get_custom_input_scene); + METHOD_REG(GRClient, get_address); + METHOD_REG(GRClient, is_stream_active); + METHOD_REG(GRClient, is_connected_to_host); + + register_signal("custom_input_scene_added", Dictionary::make()); + register_signal("custom_input_scene_removed", Dictionary::make()); + + register_signal("stream_state_changed", "state", GODOT_VARIANT_TYPE_INT); + register_signal("connection_state_changed", "is_connected", GODOT_VARIANT_TYPE_BOOL); + register_signal("mouse_mode_changed", "mouse_mode", GODOT_VARIANT_TYPE_INT); + register_signal("server_settings_received", "settings", GODOT_VARIANT_TYPE_DICTIONARY); + + // SETGET + METHOD_REG(GRClient, set_capture_on_focus); + METHOD_REG(GRClient, set_capture_when_hover); + METHOD_REG(GRClient, set_capture_pointer); + METHOD_REG(GRClient, set_capture_input); + METHOD_REG(GRClient, set_connection_type); + METHOD_REG(GRClient, set_target_send_fps); + METHOD_REG(GRClient, set_stretch_mode); + METHOD_REG(GRClient, set_texture_filtering); + METHOD_REG(GRClient, set_password); + METHOD_REG(GRClient, set_device_id); + METHOD_REG(GRClient, set_viewport_orientation_syncing); + METHOD_REG(GRClient, set_viewport_aspect_ratio_syncing); + METHOD_REG(GRClient, set_server_settings_syncing); + + METHOD_REG(GRClient, is_capture_on_focus); + METHOD_REG(GRClient, is_capture_when_hover); + METHOD_REG(GRClient, is_capture_pointer); + METHOD_REG(GRClient, is_capture_input); + METHOD_REG(GRClient, get_connection_type); + METHOD_REG(GRClient, get_target_send_fps); + METHOD_REG(GRClient, get_stretch_mode); + METHOD_REG(GRClient, get_texture_filtering); + METHOD_REG(GRClient, get_password); + METHOD_REG(GRClient, get_device_id); + METHOD_REG(GRClient, is_viewport_orientation_syncing); + METHOD_REG(GRClient, is_viewport_aspect_ratio_syncing); + METHOD_REG(GRClient, is_server_settings_syncing); + + register_property("capture_on_focus", &GRClient::set_capture_on_focus, &GRClient::is_capture_on_focus, false); + register_property("capture_when_hover", &GRClient::set_capture_when_hover, &GRClient::is_capture_when_hover, false); + register_property("capture_pointer", &GRClient::set_capture_pointer, &GRClient::is_capture_pointer, true); + register_property("capture_input", &GRClient::set_capture_input, &GRClient::is_capture_input, true); + register_property("connection_type", &GRClient::set_connection_type, &GRClient::get_connection_type, CONNECTION_WiFi, GODOT_METHOD_RPC_MODE_DISABLED, GODOT_PROPERTY_USAGE_DEFAULT, GODOT_PROPERTY_HINT_ENUM, "WiFi,ADB"); + register_property("target_send_fps", &GRClient::set_target_send_fps, &GRClient::get_target_send_fps, 60, GODOT_METHOD_RPC_MODE_DISABLED, GODOT_PROPERTY_USAGE_DEFAULT, GODOT_PROPERTY_HINT_RANGE, "1,1000"); + register_property("stretch_mode", &GRClient::set_stretch_mode, &GRClient::get_stretch_mode, STRETCH_KEEP_ASPECT, GODOT_METHOD_RPC_MODE_DISABLED, GODOT_PROPERTY_USAGE_DEFAULT, GODOT_PROPERTY_HINT_ENUM, "Fill,Keep Aspect"); + register_property("texture_filtering", &GRClient::set_texture_filtering, &GRClient::get_texture_filtering, true); + register_property("password", &GRClient::set_password, &GRClient::get_password, ""); + register_property("device_id", &GRClient::set_device_id, &GRClient::get_device_id, ""); + register_property("viewport_orientation_syncing", &GRClient::set_viewport_orientation_syncing, &GRClient::is_viewport_orientation_syncing, true); + register_property("viewport_aspect_ratio_syncing", &GRClient::set_viewport_aspect_ratio_syncing, &GRClient::is_viewport_aspect_ratio_syncing, true); + register_property("server_settings_syncing", &GRClient::set_server_settings_syncing, &GRClient::is_server_settings_syncing, true); +} + +#endif + +void GRClient::_notification(int p_notification) { + switch (p_notification) { + case NOTIFICATION_POSTINITIALIZE: +#ifndef GDNATIVE_LIBRARY + _init(); +#endif + break; + case NOTIFICATION_PREDELETE: { + _deinit(); + GRDevice::_deinit(); + break; + case NOTIFICATION_EXIT_TREE: + is_deleting = true; + if (get_status() == (int)WorkingStatus::STATUS_WORKING) { + _internal_call_only_deffered_stop(); + } + break; + } + } +} + +void GRClient::_init() { + set_name("GodotRemoteClient"); + LEAVE_IF_EDITOR(); + +#ifndef GDNATIVE_LIBRARY +#else + GRDevice::_init(); +#endif + +#ifndef GDNATIVE_LIBRARY + Math::randomize(); + device_id = str(Math::randd() * Math::rand()).md5_text().substr(0, 6); +#else + RandomNumberGenerator *rng = memnew(RandomNumberGenerator); + rng->randomize(); + device_id = str(rng->randf() * rng->randf()).md5_text().substr(0, 6); + memdelete(rng); +#endif + + Mutex_create(connection_mutex); + +#ifndef NO_GODOTREMOTE_DEFAULT_RESOURCES + no_signal_image.instance(); + GetPoolVectorFromBin(tmp_no_signal, GRResources::Bin_NoSignalPNG); + no_signal_image->load_png_from_buffer(tmp_no_signal); + + no_signal_vertical_image.instance(); + GetPoolVectorFromBin(tmp_no_signal_vert, GRResources::Bin_NoSignalVerticalPNG); + no_signal_vertical_image->load_png_from_buffer(tmp_no_signal_vert); + + Ref shader = newref(Shader); + shader->set_code(GRResources::Txt_CRT_Shader); + no_signal_mat.instance(); + no_signal_mat->set_shader(shader); +#endif +} + +void GRClient::_deinit() { + LEAVE_IF_EDITOR(); + + is_deleting = true; + if (get_status() == (int)WorkingStatus::STATUS_WORKING) { + _internal_call_only_deffered_stop(); + } + set_control_to_show_in(nullptr, 0); + Mutex_delete(connection_mutex); + +#ifndef NO_GODOTREMOTE_DEFAULT_RESOURCES + no_signal_mat.unref(); + no_signal_image.unref(); + no_signal_vertical_image.unref(); +#endif +} + +void GRClient::_internal_call_only_deffered_start() { + switch ((WorkingStatus)get_status()) { + case WorkingStatus::STATUS_WORKING: + ERR_FAIL_MSG("Can't start already working GodotRemote Client"); + case WorkingStatus::STATUS_STARTING: + ERR_FAIL_MSG("Can't start already starting GodotRemote Client"); + case WorkingStatus::STATUS_STOPPING: + ERR_FAIL_MSG("Can't start stopping GodotRemote Client"); + } + + _log("Starting GodotRemote client. Version: " + str(GodotRemote::get_singleton()->get_version()), LogLevel::LL_NORMAL); + set_status(WorkingStatus::STATUS_STARTING); + + if (thread_connection) { + Mutex_lock(connection_mutex); + thread_connection->break_connection = true; + thread_connection->stop_thread = true; + Mutex_unlock(connection_mutex); + thread_connection->close_thread(); + memdelete(thread_connection); + thread_connection = nullptr; + } + thread_connection = memnew(ConnectionThreadParamsClient); + thread_connection->dev = this; + thread_connection->peer.instance(); + Thread_start(thread_connection->thread_ref, GRClient, _thread_connection, thread_connection, this); + + call_deferred("_update_stream_texture_state", StreamState::STREAM_NO_SIGNAL); + set_status(WorkingStatus::STATUS_WORKING); +} + +void GRClient::_internal_call_only_deffered_stop() { + switch ((WorkingStatus)get_status()) { + case WorkingStatus::STATUS_STOPPED: + ERR_FAIL_MSG("Can't stop already stopped GodotRemote Client"); + case WorkingStatus::STATUS_STOPPING: + ERR_FAIL_MSG("Can't stop already stopping GodotRemote Client"); + case WorkingStatus::STATUS_STARTING: + ERR_FAIL_MSG("Can't stop starting GodotRemote Client"); + } + + _log("Stopping GodotRemote client", LogLevel::LL_DEBUG); + set_status(WorkingStatus::STATUS_STOPPING); + _remove_custom_input_scene(); + + if (thread_connection) { + Mutex_lock(connection_mutex); + thread_connection->break_connection = true; + thread_connection->stop_thread = true; + Mutex_unlock(connection_mutex); + thread_connection->close_thread(); + memdelete(thread_connection); + thread_connection = nullptr; + } + + _send_queue_resize(0); + + call_deferred("_update_stream_texture_state", StreamState::STREAM_NO_SIGNAL); + set_status(WorkingStatus::STATUS_STOPPED); +} + +void GRClient::set_control_to_show_in(Control *ctrl, int position_in_node) { + if (tex_shows_stream && !tex_shows_stream->is_queued_for_deletion()) { + tex_shows_stream->dev = nullptr; + tex_shows_stream->queue_del(); + tex_shows_stream = nullptr; + } + if (input_collector && !input_collector->is_queued_for_deletion()) { + input_collector->dev = nullptr; + input_collector->queue_del(); + input_collector = nullptr; + } + if (control_to_show_in && !control_to_show_in->is_queued_for_deletion() && + control_to_show_in->is_connected("resized", this, "_viewport_size_changed")) { + control_to_show_in->disconnect("resized", this, "_viewport_size_changed"); + control_to_show_in->disconnect("tree_exiting", this, "_on_node_deleting"); + } + + _remove_custom_input_scene(); + + control_to_show_in = ctrl; + + if (control_to_show_in && !control_to_show_in->is_queued_for_deletion()) { + control_to_show_in->connect("resized", this, "_viewport_size_changed"); + + tex_shows_stream = memnew(GRTextureRect); + input_collector = memnew(GRInputCollector); + + tex_shows_stream->connect("tree_exiting", this, "_on_node_deleting", vec_args({ (int)DeletingVarName::TEXTURE_TO_SHOW_STREAM })); + input_collector->connect("tree_exiting", this, "_on_node_deleting", vec_args({ (int)DeletingVarName::INPUT_COLLECTOR })); + control_to_show_in->connect("tree_exiting", this, "_on_node_deleting", vec_args({ (int)DeletingVarName::CONTROL_TO_SHOW_STREAM })); + + tex_shows_stream->set_name("GodotRemoteStreamSprite"); + input_collector->set_name("GodotRemoteInputCollector"); + + tex_shows_stream->set_expand(true); + tex_shows_stream->set_anchor(MARGIN_RIGHT, 1.f); + tex_shows_stream->set_anchor(MARGIN_BOTTOM, 1.f); + tex_shows_stream->dev = this; + tex_shows_stream->this_in_client = &tex_shows_stream; + + control_to_show_in->add_child(tex_shows_stream); + control_to_show_in->move_child(tex_shows_stream, position_in_node); + control_to_show_in->add_child(input_collector); + + input_collector->set_tex_rect(tex_shows_stream); + input_collector->dev = this; + input_collector->this_in_client = &input_collector; + + signal_connection_state = StreamState::STREAM_ACTIVE; // force execute update function + call_deferred("_update_stream_texture_state", StreamState::STREAM_NO_SIGNAL); + call_deferred("_force_update_stream_viewport_signals"); // force update if client connected faster than scene loads + } +} + +void GRClient::_on_node_deleting(int var_name) { + switch ((DeletingVarName)var_name) { + case DeletingVarName::CONTROL_TO_SHOW_STREAM: + control_to_show_in = nullptr; + set_control_to_show_in(nullptr, 0); + break; + case DeletingVarName::TEXTURE_TO_SHOW_STREAM: + tex_shows_stream = nullptr; + break; + case DeletingVarName::INPUT_COLLECTOR: + input_collector = nullptr; + break; + case DeletingVarName::CUSTOM_INPUT_SCENE: + custom_input_scene = nullptr; + break; + default: + break; + } +} + +void GRClient::set_custom_no_signal_texture(Ref custom_tex) { + custom_no_signal_texture = custom_tex; + call_deferred("_update_stream_texture_state", signal_connection_state); +} + +void GRClient::set_custom_no_signal_vertical_texture(Ref custom_tex) { + custom_no_signal_vertical_texture = custom_tex; + call_deferred("_update_stream_texture_state", signal_connection_state); +} + +void GRClient::set_custom_no_signal_material(Ref custom_mat) { + custom_no_signal_material = custom_mat; + call_deferred("_update_stream_texture_state", signal_connection_state); +} + +bool GRClient::is_capture_on_focus() { + if (input_collector && !input_collector->is_queued_for_deletion()) + return input_collector->is_capture_on_focus(); + return false; +} + +void GRClient::set_capture_on_focus(bool value) { + if (input_collector && !input_collector->is_queued_for_deletion()) + input_collector->set_capture_on_focus(value); +} + +bool GRClient::is_capture_when_hover() { + if (input_collector && !input_collector->is_queued_for_deletion()) + return input_collector->is_capture_when_hover(); + return false; +} + +void GRClient::set_capture_when_hover(bool value) { + if (input_collector && !input_collector->is_queued_for_deletion()) + input_collector->set_capture_when_hover(value); +} + +bool GRClient::is_capture_pointer() { + if (input_collector && !input_collector->is_queued_for_deletion()) + return input_collector->is_capture_pointer(); + return false; +} + +void GRClient::set_capture_pointer(bool value) { + if (input_collector && !input_collector->is_queued_for_deletion()) + input_collector->set_capture_pointer(value); +} + +bool GRClient::is_capture_input() { + if (input_collector && !input_collector->is_queued_for_deletion()) + return input_collector->is_capture_input(); + return false; +} + +void GRClient::set_capture_input(bool value) { + if (input_collector && !input_collector->is_queued_for_deletion()) + input_collector->set_capture_input(value); +} + +void GRClient::set_connection_type(ENUM_ARG(ConnectionType) type) { + con_type = (ConnectionType)type; +} + +ENUM_ARG(GRClient::ConnectionType) +GRClient::get_connection_type() { + return con_type; +} + +void GRClient::set_target_send_fps(int fps) { + ERR_FAIL_COND(fps <= 0); + send_data_fps = fps; +} + +int GRClient::get_target_send_fps() { + return send_data_fps; +} + +void GRClient::set_stretch_mode(ENUM_ARG(StretchMode) stretch) { + stretch_mode = (StretchMode)stretch; + call_deferred("_update_stream_texture_state", signal_connection_state); +} + +ENUM_ARG(GRClient::StretchMode) +GRClient::get_stretch_mode() { + return stretch_mode; +} + +void GRClient::set_texture_filtering(bool is_filtering) { + is_filtering_enabled = is_filtering; +} + +bool GRClient::get_texture_filtering() { + return is_filtering_enabled; +} + +ENUM_ARG(GRClient::StreamState) +GRClient::get_stream_state() { + return signal_connection_state; +} + +bool GRClient::is_stream_active() { + return signal_connection_state; +} + +String GRClient::get_address() { + return (String)server_address; +} + +bool GRClient::set_address(String ip) { + return set_address_port(ip, port); +} + +bool GRClient::set_address_port(String ip, uint16_t _port) { + bool all_ok = false; + +#ifndef GDNATIVE_LIBRARY + IP_Address adr; +#else + String adr; +#endif + + if (ip.is_valid_ip_address()) { + adr = ip; + if (adr.is_valid_ip()) { + server_address = ip; + port = _port; + restart(); + all_ok = true; + } else { + _log("Address is invalid: " + ip, LogLevel::LL_ERROR); + GRNotifications::add_notification("Resolve Address Error", "Address is invalid: " + ip, GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + } + } else { + adr = IP::get_singleton()->resolve_hostname(adr); + if (adr.is_valid_ip()) { + _log("Resolved address for " + ip + "\n" + adr, LogLevel::LL_DEBUG); + server_address = ip; + port = _port; + restart(); + all_ok = true; + } else { + _log("Can't resolve address for " + ip, LogLevel::LL_ERROR); + GRNotifications::add_notification("Resolve Address Error", "Can't resolve address: " + ip, GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + } + } + + return all_ok; +} + +void GRClient::set_input_buffer(int mb) { + + input_buffer_size_in_mb = mb; + restart(); +} + +void GRClient::set_viewport_orientation_syncing(bool is_syncing) { + _viewport_orientation_syncing = is_syncing; + if (is_syncing) { + if (input_collector && !input_collector->is_queued_for_deletion()) { + _force_update_stream_viewport_signals(); + } + } +} + +bool GRClient::is_viewport_orientation_syncing() { + return _viewport_orientation_syncing; +} + +void GRClient::set_viewport_aspect_ratio_syncing(bool is_syncing) { + _viewport_aspect_ratio_syncing = is_syncing; + if (is_syncing) { + call_deferred("_viewport_size_changed"); // force update screen aspect + } +} + +bool GRClient::is_viewport_aspect_ratio_syncing() { + return _viewport_aspect_ratio_syncing; +} + +void GRClient::set_server_settings_syncing(bool is_syncing) { + _server_settings_syncing = is_syncing; +} + +bool GRClient::is_server_settings_syncing() { + return _server_settings_syncing; +} + +void GRClient::set_password(String _pass) { + password = _pass; +} + +String GRClient::get_password() { + return password; +} + +void GRClient::set_device_id(String _id) { + ERR_FAIL_COND(_id.empty()); + device_id = _id; +} + +String GRClient::get_device_id() { + return device_id; +} + +bool GRClient::is_connected_to_host() { + if (thread_connection && thread_connection->peer.is_valid()) { + return thread_connection->peer->is_connected_to_host() && is_connection_working; + } + return false; +} + +Node *GRClient::get_custom_input_scene() { + return custom_input_scene; +} + +void GRClient::_force_update_stream_viewport_signals() { + is_vertical = ScreenOrientation::NONE; + if (!control_to_show_in || control_to_show_in->is_queued_for_deletion()) { + return; + } + + call_deferred("_viewport_size_changed"); // force update screen aspect ratio +} + +void GRClient::_load_custom_input_scene(Ref _data) { + _remove_custom_input_scene(); + + if (_data->get_scene_path().empty() || _data->get_scene_data().size() == 0) { + _log("Scene not specified or data is empty. Removing custom input scene", LogLevel::LL_DEBUG); + return; + } + + if (!control_to_show_in) { + _log("Not specified control to show", LogLevel::LL_ERROR); + return; + } + + Error err = Error::OK; +#ifndef GDNATIVE_LIBRARY + FileAccess *file = FileAccess::open(custom_input_scene_tmp_pck_file, FileAccess::ModeFlags::WRITE, &err); +#else + File *file = memnew(File); + err = file->open(custom_input_scene_tmp_pck_file, File::ModeFlags::WRITE); +#endif + if ((int)err) { + _log("Can't open temp file to store custom input scene: " + custom_input_scene_tmp_pck_file + ", code: " + str((int)err), LogLevel::LL_ERROR); + } else { + + PoolByteArray scene_data; + if (_data->is_compressed()) { + err = decompress_bytes(_data->get_scene_data(), _data->get_original_size(), scene_data, _data->get_compression_type()); + } else { + scene_data = _data->get_scene_data(); + } + + if ((int)err) { + _log("Can't decompress or set scene_data: Code: " + str((int)err), LogLevel::LL_ERROR); + } else { + +#ifndef GDNATIVE_LIBRARY + auto r = scene_data.read(); + file->store_buffer(r.ptr(), scene_data.size()); + release_pva_read(r); +#else + file->store_buffer(scene_data); +#endif + file->close(); + +#ifndef GDNATIVE_LIBRARY + if (PackedData::get_singleton()->is_disabled()) { + err = Error::FAILED; + } else { +#if VERSION_MINOR >= 2 && VERSION_PATCH >= 4 + err = PackedData::get_singleton()->add_pack(custom_input_scene_tmp_pck_file, true, 0); +#else + err = PackedData::get_singleton()->add_pack(custom_input_scene_tmp_pck_file, true); +#endif + } +#else + err = ProjectSettings::get_singleton()->load_resource_pack(custom_input_scene_tmp_pck_file, true, 0) ? Error::OK : Error::FAILED; +#endif + + if ((int)err) { + _log("Can't load PCK file: " + custom_input_scene_tmp_pck_file, LogLevel::LL_ERROR); + } else { + +#ifndef GDNATIVE_LIBRARY + Ref pck = ResourceLoader::load(_data->get_scene_path(), "", false, &err); +#else + Ref pck = ResourceLoader::get_singleton()->load(_data->get_scene_path(), "", false); + err = pck->can_instance() ? Error::OK : Error::FAILED; +#endif + if ((int)err) { + _log("Can't load scene file: " + _data->get_scene_path() + ", code: " + str((int)err), LogLevel::LL_ERROR); + } else { + + custom_input_scene = pck->instance(); + if (!custom_input_scene) { + _log("Can't instance scene from PCK file: " + custom_input_scene_tmp_pck_file + ", scene: " + _data->get_scene_path(), LogLevel::LL_ERROR); + } else { + + control_to_show_in->add_child(custom_input_scene); + custom_input_scene->connect("tree_exiting", this, "_on_node_deleting", vec_args({ (int)DeletingVarName::CUSTOM_INPUT_SCENE })); + + _reset_counters(); + emit_signal("custom_input_scene_added"); + } + } + } + } + } + + if (file) { + memdelete(file); + } +} + +void GRClient::_remove_custom_input_scene() { + if (custom_input_scene && !custom_input_scene->is_queued_for_deletion()) { + + custom_input_scene->queue_del(); + custom_input_scene = nullptr; + emit_signal("custom_input_scene_removed"); + + Error err = Error::OK; +#ifndef GDNATIVE_LIBRARY + DirAccess *dir = DirAccess::open(custom_input_scene_tmp_pck_file.get_base_dir(), &err); +#else + Directory *dir = memnew(Directory); + dir->open(custom_input_scene_tmp_pck_file.get_base_dir()); +#endif + if ((int)err) { + _log("Can't open folder: " + custom_input_scene_tmp_pck_file.get_base_dir(), LogLevel::LL_ERROR); + } else { + if (dir && dir->file_exists(custom_input_scene_tmp_pck_file)) { + err = dir->remove(custom_input_scene_tmp_pck_file); + if ((int)err) { + _log("Can't delete file: " + custom_input_scene_tmp_pck_file + ". Code: " + str((int)err), LogLevel::LL_ERROR); + } + } + } + + if (dir) { + memdelete(dir); + } + } +} + +void GRClient::_viewport_size_changed() { + if (!control_to_show_in || control_to_show_in->is_queued_for_deletion()) { + return; + } + + if (_viewport_orientation_syncing) { + Vector2 size = control_to_show_in->get_size(); + ScreenOrientation tmp_vert = size.x < size.y ? ScreenOrientation::VERTICAL : ScreenOrientation::HORIZONTAL; + if (tmp_vert != is_vertical) { + is_vertical = tmp_vert; + Mutex_lock(send_queue_mutex); + Ref packet = _find_queued_packet_by_type >(); + if (packet.is_valid()) { + packet->set_vertical(is_vertical == ScreenOrientation::VERTICAL); + Mutex_unlock(send_queue_mutex); + goto ratio_sync; + } + Mutex_unlock(send_queue_mutex); + + if (packet.is_null()) { + packet.instance(); + packet->set_vertical(is_vertical == ScreenOrientation::VERTICAL); + send_packet(packet); + } + } + } + +ratio_sync: + + if (_viewport_aspect_ratio_syncing) { + Vector2 size = control_to_show_in->get_size(); + + Mutex_lock(send_queue_mutex); + Ref packet = _find_queued_packet_by_type >(); + if (packet.is_valid()) { + packet->set_aspect(size.x / size.y); + Mutex_unlock(send_queue_mutex); + return; + } + Mutex_unlock(send_queue_mutex); + + if (packet.is_null()) { + packet.instance(); + packet->set_aspect(size.x / size.y); + send_packet(packet); + } + } +} + +void GRClient::_update_texture_from_image(Ref img) { + if (tex_shows_stream && !tex_shows_stream->is_queued_for_deletion()) { + if (img.is_valid()) { + Ref tex = tex_shows_stream->get_texture(); + if (tex.is_valid()) { + tex->create_from_image(img); + } else { + tex.instance(); + tex->create_from_image(img); + tex_shows_stream->set_texture(tex); + } + + uint32_t new_flags = Texture::FLAG_MIPMAPS | (is_filtering_enabled ? Texture::FLAG_FILTER : 0); + if (tex->get_flags() != new_flags) { + tex->set_flags(new_flags); + } + } else { + tex_shows_stream->set_texture(nullptr); + } + } +} + +void GRClient::_update_stream_texture_state(ENUM_ARG(StreamState) _stream_state) { + if (is_deleting) + return; + + if (tex_shows_stream && !tex_shows_stream->is_queued_for_deletion()) { + switch (_stream_state) { + case StreamState::STREAM_NO_SIGNAL: { + tex_shows_stream->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED); + + if (custom_no_signal_texture.is_valid() || custom_no_signal_vertical_texture.is_valid()) { + tex_shows_stream->set_texture(no_signal_is_vertical ? + (custom_no_signal_vertical_texture.is_valid() ? custom_no_signal_vertical_texture : custom_no_signal_texture) : + (custom_no_signal_texture.is_valid() ? custom_no_signal_texture : custom_no_signal_vertical_texture)); + } +#ifndef NO_GODOTREMOTE_DEFAULT_RESOURCES + else { + _update_texture_from_image(no_signal_is_vertical ? no_signal_vertical_image : no_signal_image); + } +#endif + if (custom_no_signal_material.is_valid()) { + tex_shows_stream->set_material(custom_no_signal_material); + } +#ifndef NO_GODOTREMOTE_DEFAULT_RESOURCES + else { + tex_shows_stream->set_material(no_signal_mat); + } +#endif + break; + } + case StreamState::STREAM_ACTIVE: { + tex_shows_stream->set_stretch_mode(stretch_mode == StretchMode::STRETCH_KEEP_ASPECT ? TextureRect::STRETCH_KEEP_ASPECT_CENTERED : TextureRect::STRETCH_SCALE); + tex_shows_stream->set_material(nullptr); + break; + } + case StreamState::STREAM_NO_IMAGE: + tex_shows_stream->set_stretch_mode(TextureRect::STRETCH_SCALE); + tex_shows_stream->set_material(nullptr); + tex_shows_stream->set_texture(nullptr); + break; + default: + _log("Wrong stream state!", LogLevel::LL_ERROR); + break; + } + + if (signal_connection_state != _stream_state) { + call_deferred("emit_signal", "stream_state_changed", _stream_state); + signal_connection_state = (StreamState)_stream_state; + } + } +} + +void GRClient::_reset_counters() { + GRDevice::_reset_counters(); + sync_time_client = 0; + sync_time_server = 0; +} + +void GRClient::set_server_setting(ENUM_ARG(TypesOfServerSettings) param, Variant value) { + Mutex_lock(send_queue_mutex); + Ref packet = _find_queued_packet_by_type >(); + if (packet.is_valid()) { + packet->add_setting(param, value); + Mutex_unlock(send_queue_mutex); + return; + } + Mutex_unlock(send_queue_mutex); + + if (packet.is_null()) { + packet.instance(); + packet->add_setting(param, value); + send_packet(packet); + } +} + +void GRClient::disable_overriding_server_settings() { + set_server_setting(TypesOfServerSettings::SERVER_SETTINGS_USE_INTERNAL, true); +} + +////////////////////////////////////////////// +////////////////// STATIC //////////////////// +////////////////////////////////////////////// + +void GRClient::_thread_connection(THREAD_DATA p_userdata) { + ConnectionThreadParamsClient *con_thread = (ConnectionThreadParamsClient *)p_userdata; + GRClient *dev = con_thread->dev; + Ref con = con_thread->peer; + + OS *os = OS::get_singleton(); + Thread_set_name("GRemote_connection"); + GRDevice::AuthResult prev_auth_error = GRDevice::AuthResult::OK; + + const String con_error_title = "Connection Error"; + + while (!con_thread->stop_thread) { + if (os->get_ticks_usec() - dev->prev_valid_connection_time > 1000_ms) { + dev->call_deferred("_update_stream_texture_state", StreamState::STREAM_NO_SIGNAL); + dev->call_deferred("_remove_custom_input_scene"); + } + + if (con->get_status() == StreamPeerTCP::STATUS_CONNECTED || con->get_status() == StreamPeerTCP::STATUS_CONNECTING) { + con->disconnect_from_host(); + } + + dev->_send_queue_resize(0); + +#ifndef GDNATIVE_LIBRARY + IP_Address adr; +#else + String adr; +#endif + + if (dev->con_type == CONNECTION_ADB) { +#ifndef GDNATIVE_LIBRARY + adr = IP_Address("127.0.0.1"); +#else + adr = "127.0.0.1"; +#endif + } else { + if (dev->server_address.is_valid_ip_address()) { + adr = dev->server_address; + if (adr.is_valid_ip()) { + } else { + _log("Address is invalid: " + dev->server_address, LogLevel::LL_ERROR); + if (prev_auth_error != GRDevice::AuthResult::Error) + GRNotifications::add_notification("Resolve Address Error", "Address is invalid: " + dev->server_address, GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + prev_auth_error = GRDevice::AuthResult::Error; + } + } else { + adr = IP::get_singleton()->resolve_hostname(adr); + if (adr.is_valid_ip()) { + _log("Resolved address for " + dev->server_address + "\n" + adr, LogLevel::LL_DEBUG); + } else { + _log("Can't resolve address for " + dev->server_address, LogLevel::LL_ERROR); + if (prev_auth_error != GRDevice::AuthResult::Error) + GRNotifications::add_notification("Resolve Address Error", "Can't resolve address: " + dev->server_address, GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + prev_auth_error = GRDevice::AuthResult::Error; + } + } + } + + String address = (String)adr + ":" + str(dev->port); + Error err = con->connect_to_host(adr, dev->port); + + _log("Connecting to " + address, LogLevel::LL_DEBUG); + if ((int)err) { + switch (err) { + case Error::FAILED: + _log("Failed to open socket or can't connect to host", LogLevel::LL_ERROR); + break; + case Error::ERR_UNAVAILABLE: + _log("Socket is unavailable", LogLevel::LL_ERROR); + break; + case Error::ERR_INVALID_PARAMETER: + _log("Host address is invalid", LogLevel::LL_ERROR); + break; + case Error::ERR_ALREADY_EXISTS: + _log("Socket already in use", LogLevel::LL_ERROR); + break; + } + sleep_usec(250_ms); + continue; + } + + while (con->get_status() == StreamPeerTCP::STATUS_CONNECTING) { + sleep_usec(1_ms); + } + + if (con->get_status() != StreamPeerTCP::STATUS_CONNECTED) { + _log("Connection timed out with " + address, LogLevel::LL_DEBUG); + if (prev_auth_error != GRDevice::AuthResult::Timeout) { + GRNotifications::add_notification(con_error_title, "Connection timed out: " + address, GRNotifications::NotificationIcon::ICON_WARNING, true, 1.f); + prev_auth_error = GRDevice::AuthResult::Timeout; + } + sleep_usec(200_ms); + continue; + } + + con->set_no_delay(true); + + bool long_wait = false; + + Ref ppeer = newref(PacketPeerStream); + ppeer->set_stream_peer(con); + ppeer->set_input_buffer_max_size(dev->input_buffer_size_in_mb * 1024 * 1024); + + GRDevice::AuthResult res = _auth_on_server(dev, ppeer); + switch (res) { + case GRDevice::AuthResult::OK: { + _log("Successful connected to " + address, LogLevel::LL_NORMAL); + + dev->call_deferred("_update_stream_texture_state", StreamState::STREAM_NO_IMAGE); + + con_thread->break_connection = false; + con_thread->peer = con; + con_thread->ppeer = ppeer; + + dev->is_connection_working = true; + dev->call_deferred("emit_signal", "connection_state_changed", true); + dev->call_deferred("_force_update_stream_viewport_signals"); // force update screen aspect ratio and orientation + GRNotifications::add_notification("Connected", "Connected to " + address, GRNotifications::NotificationIcon::ICON_SUCCESS, true, 1.f); + + _connection_loop(con_thread); + + con_thread->peer.unref(); + con_thread->ppeer.unref(); + + dev->is_connection_working = false; + dev->call_deferred("emit_signal", "connection_state_changed", false); + dev->call_deferred("emit_signal", "mouse_mode_changed", Input::MouseMode::MOUSE_MODE_VISIBLE); + break; + } + case GRDevice::AuthResult::Error: + if (res != prev_auth_error) + GRNotifications::add_notification(con_error_title, "Can't connect to " + address, GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + long_wait = true; + break; + case GRDevice::AuthResult::Timeout: + if (res != prev_auth_error) + GRNotifications::add_notification(con_error_title, "Timeout\n" + address, GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + long_wait = true; + break; + case GRDevice::AuthResult::RefuseConnection: + if (res != prev_auth_error) + GRNotifications::add_notification(con_error_title, "Connection refused\n" + address, GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + long_wait = true; + break; + case GRDevice::AuthResult::VersionMismatch: + GRNotifications::add_notification(con_error_title, "Version mismatch\n" + address, GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + long_wait = true; + break; + case GRDevice::AuthResult::IncorrectPassword: + GRNotifications::add_notification(con_error_title, "Incorrect password\n" + address, GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + long_wait = true; + break; + case GRDevice::AuthResult::PasswordRequired: + GRNotifications::add_notification(con_error_title, "Required password but it's not implemented.... " + address, GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + break; + default: + if (res != prev_auth_error) + GRNotifications::add_notification(con_error_title, "Unknown error code: " + str((int)res) + "\n" + address, GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + _log("Unknown error code: " + str((int)res) + ". Disconnecting. " + address, LogLevel::LL_NORMAL); + break; + } + + ((Ref)ppeer->get_stream_peer())->disconnect_from_host(); + ppeer->set_output_buffer_max_size(0); + ppeer->set_input_buffer_max_size(0); + + prev_auth_error = res; + + if (con->is_connected_to_host()) { + con->disconnect_from_host(); + } + + if (long_wait) { + sleep_usec(888_ms); + } + } + + dev->call_deferred("_update_stream_texture_state", StreamState::STREAM_NO_SIGNAL); + _log("Connection thread stopped", LogLevel::LL_DEBUG); + con_thread->finished = true; +} + +void GRClient::_connection_loop(ConnectionThreadParamsClient *con_thread) { + GRClient *dev = con_thread->dev; + Ref connection = con_thread->peer; + Ref ppeer = con_thread->ppeer; + // Data sync with _img_thread + ImgProcessingStorageClient *ipsc = memnew(ImgProcessingStorageClient); + ipsc->dev = dev; + + Thread_define(_img_thread); + Thread_start(_img_thread, GRClient, _thread_image_decoder, ipsc, dev); + + OS *os = OS::get_singleton(); + Error err = Error::OK; + String address = CONNECTION_ADDRESS(connection); + + dev->_reset_counters(); + + //Array stream_queue; // Ref + std::vector > stream_queue; // Ref + + uint64_t time64 = os->get_ticks_usec(); + uint64_t prev_cycle_time = 0; + uint64_t prev_send_input_time = time64; + uint64_t prev_ping_sending_time = time64; + uint64_t next_image_required_frametime = time64; + uint64_t prev_display_image_time = time64 - 16_ms; + + bool ping_sended = false; + + TimeCountInit(); + while (!con_thread->break_connection && !con_thread->stop_thread && connection->is_connected_to_host()) { + Mutex_lock(dev->connection_mutex); + TimeCount("Cycle start"); + uint64_t cycle_start_time = os->get_ticks_usec(); + + bool nothing_happens = true; + uint64_t start_while_time = 0; + dev->prev_valid_connection_time = time64; + int send_data_time_us = (1000000 / dev->send_data_fps); + + /////////////////////////////////////////////////////////////////// + // SENDING + bool is_queued_send = false; // this placed here for android compiler + + // INPUT + TimeCountReset(); + time64 = os->get_ticks_usec(); + if ((time64 - prev_send_input_time) > send_data_time_us) { + prev_send_input_time = time64; + nothing_happens = false; + + if (dev->input_collector) { + Ref pack = dev->input_collector->get_collected_input_data(); + + if (pack.is_valid()) { + err = ppeer->put_var(pack->get_data()); + if ((int)err) { + _log("Put input data failed with code: " + str((int)err), LogLevel::LL_ERROR); + goto end_send; + } + } else { + _log("Can't get input data from input collector", LogLevel::LL_ERROR); + } + TimeCount("Input send"); + } + } + + // PING + TimeCountReset(); + time64 = os->get_ticks_usec(); + if ((time64 - prev_ping_sending_time) > 100_ms && !ping_sended) { + nothing_happens = false; + ping_sended = true; + + Ref pack(memnew(GRPacketPing)); + err = ppeer->put_var(pack->get_data()); + prev_ping_sending_time = time64; + + if ((int)err) { + _log("Send ping failed with code: " + str((int)err), LogLevel::LL_ERROR); + goto end_send; + } + TimeCount("Ping send"); + } + + // SEND QUEUE + start_while_time = os->get_ticks_usec(); + while (!dev->send_queue.empty() && (os->get_ticks_usec() - start_while_time) <= send_data_time_us / 2) { + is_queued_send = true; + Ref packet = dev->_send_queue_pop_front(); + + if (packet.is_valid()) { + err = ppeer->put_var(packet->get_data()); + + if ((int)err) { + _log("Put data from queue failed with code: " + str((int)err), LogLevel::LL_ERROR); + goto end_send; + } + } + } + if (is_queued_send) { + TimeCount("Send queued data"); + } + end_send: + + if (!connection->is_connected_to_host()) { + _log("Lost connection after sending!", LogLevel::LL_ERROR); + GRNotifications::add_notification("Error", "Lost connection after sending data!", GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + Mutex_unlock(dev->connection_mutex); + continue; + } + + /////////////////////////////////////////////////////////////////// + // RECEIVING + + // Send to processing one of buffered images + time64 = os->get_ticks_usec(); + TimeCountReset(); + if (!ipsc->_is_processing_img && !stream_queue.empty() && time64 >= next_image_required_frametime) { + nothing_happens = false; + + Ref pack = stream_queue.front(); + stream_queue.erase(stream_queue.begin()); + + if (pack.is_null()) { + _log("Queued image data is null", LogLevel::LL_ERROR); + goto end_img_process; + } + + uint64_t frametime = pack->get_frametime() > 1000_ms ? 1000_ms : pack->get_frametime(); + next_image_required_frametime = time64 + frametime - prev_cycle_time; + + dev->_update_avg_fps(time64 - prev_display_image_time); + prev_display_image_time = time64; + + if (pack->get_is_empty()) { + dev->_update_avg_fps(0); + dev->call_deferred("_update_texture_from_image", Ref()); + dev->call_deferred("_update_stream_texture_state", StreamState::STREAM_NO_IMAGE); + } else { + ipsc->tex_data = pack->get_image_data(); + ipsc->compression_type = (ImageCompressionType)pack->get_compression_type(); + ipsc->size = pack->get_size(); + ipsc->format = pack->get_format(); + ipsc->_is_processing_img = true; + } + + pack.unref(); + TimeCount("Get image from queue"); + } + end_img_process: + + // check if image displayed less then few seconds ago. if not then remove texture + const double image_loss_time = 1.5; + if (os->get_ticks_usec() > int64_t(prev_display_image_time + uint64_t(1000_ms * image_loss_time))) { + if (dev->signal_connection_state != StreamState::STREAM_NO_IMAGE) { + dev->call_deferred("_update_stream_texture_state", StreamState::STREAM_NO_IMAGE); + dev->_reset_counters(); + } + } + + if (stream_queue.size() > 10) { + //for (int i = 0; i)stream_queue[i]).unref(); + //} + stream_queue.clear(); + } + + // Get some packets + TimeCountReset(); + start_while_time = os->get_ticks_usec(); + while (ppeer->get_available_packet_count() > 0 && (os->get_ticks_usec() - start_while_time) <= send_data_time_us / 2) { + nothing_happens = false; + +#ifndef GDNATIVE_LIBRARY + Variant buf; + err = ppeer->get_var(buf); +#else + Variant buf = ppeer->get_var(); +#endif + + if ((int)err) + goto end_recv; + + Ref pack = GRPacket::create(buf); + if (pack.is_null()) { + _log("Incorrect GRPacket", LogLevel::LL_ERROR); + continue; + } + + GRPacket::PacketType type = pack->get_type(); + + switch (type) { + case GRPacket::PacketType::SyncTime: { + Ref data = pack; + if (data.is_null()) { + _log("Incorrect GRPacketSyncTime", LogLevel::LL_ERROR); + continue; + } + + dev->sync_time_client = os->get_ticks_usec(); + dev->sync_time_server = data->get_time(); + + break; + } + case GRPacket::PacketType::ImageData: { + Ref data = pack; + if (data.is_null()) { + _log("Incorrect GRPacketImageData", LogLevel::LL_ERROR); + continue; + } + + stream_queue.push_back(data); + break; + } + case GRPacket::PacketType::ServerSettings: { + if (!dev->_server_settings_syncing) { + continue; + } + + Ref data = pack; + if (data.is_null()) { + _log("Incorrect GRPacketServerSettings", LogLevel::LL_ERROR); + continue; + } + + dev->call_deferred("emit_signal", "server_settings_received", map_to_dict(data->get_settings())); + break; + } + case GRPacket::PacketType::MouseModeSync: { + Ref data = pack; + if (data.is_null()) { + _log("Incorrect GRPacketMouseModeSync", LogLevel::LL_ERROR); + continue; + } + + dev->call_deferred("emit_signal", "mouse_mode_changed", data->get_mouse_mode()); + break; + } + case GRPacket::PacketType::CustomInputScene: { + Ref data = pack; + if (data.is_null()) { + _log("Incorrect GRPacketCustomInputScene", LogLevel::LL_ERROR); + continue; + } + + dev->call_deferred("_load_custom_input_scene", data); + break; + } + case GRPacket::PacketType::CustomUserData: { + Ref data = pack; + if (data.is_null()) { + _log("Incorrect GRPacketCustomUserData", LogLevel::LL_ERROR); + break; + } + dev->call_deferred("emit_signal", "user_data_received", data->get_packet_id(), data->get_user_data()); + break; + } + case GRPacket::PacketType::Ping: { + Ref pack(memnew(GRPacketPong)); + err = ppeer->put_var(pack->get_data()); + if ((int)err) { + _log("Send pong failed with code: " + str((int)err), LogLevel::LL_NORMAL); + break; + } + break; + } + case GRPacket::PacketType::Pong: { + dev->_update_avg_ping(os->get_ticks_usec() - prev_ping_sending_time); + ping_sended = false; + break; + } + default: + _log("Not supported packet type! " + str((int)type), LogLevel::LL_WARNING); + break; + } + } + TimeCount("End receiving"); + end_recv: + Mutex_unlock(dev->connection_mutex); + + if (!connection->is_connected_to_host()) { + _log("Lost connection after receiving!", LogLevel::LL_ERROR); + GRNotifications::add_notification("Error", "Lost connection after receiving data!", GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + continue; + } + + if (nothing_happens) + sleep_usec(1_ms); + + prev_cycle_time = os->get_ticks_usec() - cycle_start_time; + } + + dev->_send_queue_resize(0); + stream_queue.clear(); + + if (connection->is_connected_to_host()) { + _log("Lost connection to " + address, LogLevel::LL_ERROR); + GRNotifications::add_notification("Disconnected", "Closing connection to " + address, GRNotifications::NotificationIcon::ICON_FAIL, true, 1.f); + } else { + _log("Closing connection to " + address, LogLevel::LL_ERROR); + GRNotifications::add_notification("Disconnected", "Lost connection to " + address, GRNotifications::NotificationIcon::ICON_FAIL, true, 1.f); + } + + ipsc->_thread_closing = true; + Thread_close(_img_thread); + memdelete(ipsc); + + _log("Closing connection", LogLevel::LL_NORMAL); + con_thread->break_connection = true; +} + +void GRClient::_thread_image_decoder(THREAD_DATA p_userdata) { + ImgProcessingStorageClient *ipsc = (ImgProcessingStorageClient *)p_userdata; + GRClient *dev = ipsc->dev; + Error err = Error::OK; + + while (!ipsc->_thread_closing) { + if (!ipsc->_is_processing_img) { + sleep_usec(1_ms); + continue; + } + + Ref img(memnew(Image)); + ImageCompressionType type = ipsc->compression_type; + + TimeCountInit(); + switch (type) { + case ImageCompressionType::COMPRESSION_UNCOMPRESSED: { +#ifndef GDNATIVE_LIBRARY + img->create(ipsc->size.x, ipsc->size.y, false, (Image::Format)ipsc->format, ipsc->tex_data); +#else + img->create_from_data((int)ipsc->size.x, (int)ipsc->size.y, false, (Image::Format)ipsc->format, ipsc->tex_data); +#endif + if (img_is_empty(img)) { // is NOT OK + err = Error::FAILED; + _log("Incorrect uncompressed image data.", LogLevel::LL_ERROR); + GRNotifications::add_notification("Stream Error", "Incorrect uncompressed image data.", GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + } + break; + } + case ImageCompressionType::COMPRESSION_JPG: { + err = img->load_jpg_from_buffer(ipsc->tex_data); + if ((int)err || img_is_empty(img)) { // is NOT OK + _log("Can't decode JPG image.", LogLevel::LL_ERROR); + GRNotifications::add_notification("Stream Error", "Can't decode JPG image. Code: " + str((int)err), GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + } + break; + } + case ImageCompressionType::COMPRESSION_PNG: { + err = img->load_png_from_buffer(ipsc->tex_data); + if ((int)err || img_is_empty(img)) { // is NOT OK + _log("Can't decode PNG image.", LogLevel::LL_ERROR); + GRNotifications::add_notification("Stream Error", "Can't decode PNG image. Code: " + str((int)err), GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + } + break; + } + default: + _log("Not implemented image decoder type: " + str((int)type), LogLevel::LL_ERROR); + break; + } + + if (!(int)err) { // is OK + TimeCount("Create Image Time"); + dev->call_deferred("_update_texture_from_image", img); + + if (dev->signal_connection_state != StreamState::STREAM_ACTIVE) { + dev->call_deferred("_update_stream_texture_state", StreamState::STREAM_ACTIVE); + } + } + + ipsc->_is_processing_img = false; + } +} + +GRDevice::AuthResult GRClient::_auth_on_server(GRClient *dev, Ref &ppeer) { +#define wait_packet(_n) \ + time = (uint32_t)OS::get_singleton()->get_ticks_msec(); \ + while (ppeer->get_available_packet_count() == 0) { \ + if (OS::get_singleton()->get_ticks_msec() - time > 150) { \ + _log("Connection timeout. Disconnecting. Waited: " + str(_n), LogLevel::LL_DEBUG); \ + goto timeout; \ + } \ + if (!con->is_connected_to_host()) { \ + return GRDevice::AuthResult::Error; \ + } \ + sleep_usec(1_ms); \ + } +#define packet_error_check(_t) \ + if ((int)err) { \ + _log(_t, LogLevel::LL_DEBUG); \ + return GRDevice::AuthResult::Error; \ + } + + Ref con = ppeer->get_stream_peer(); + String address = CONNECTION_ADDRESS(con); + uint32_t time = 0; + + Error err = Error::OK; + Variant ret; + // GET first packet + wait_packet("first_packet"); +#ifndef GDNATIVE_LIBRARY + err = ppeer->get_var(ret); + packet_error_check("Can't get first authorization packet from server. Code: " + str((int)err)); +#else + err = Error::OK; + ret = ppeer->get_var(); +#endif + + if ((int)ret == (int)GRDevice::AuthResult::RefuseConnection) { + _log("Connection refused", LogLevel::LL_ERROR); + return GRDevice::AuthResult::RefuseConnection; + } + if ((int)ret == (int)GRDevice::AuthResult::TryToConnect) { + Dictionary data; + data["id"] = dev->device_id; + data["version"] = get_gr_version(); + data["password"] = dev->password; + + // PUT auth data + err = ppeer->put_var(data); + packet_error_check("Can't put authorization data to server. Code: " + str((int)err)); + + // GET result + wait_packet("result"); +#ifndef GDNATIVE_LIBRARY + err = ppeer->get_var(ret); + packet_error_check("Can't get final authorization packet from server. Code: " + str((int)err)); +#else + err = Error::OK; + ret = ppeer->get_var(); +#endif + + if ((int)ret == (int)GRDevice::AuthResult::OK) { + return GRDevice::AuthResult::OK; + } else { + GRDevice::AuthResult r = (GRDevice::AuthResult)(int)ret; + switch (r) { + case GRDevice::AuthResult::Error: + _log("Can't connect to server", LogLevel::LL_ERROR); + return r; + case GRDevice::AuthResult::VersionMismatch: + _log("Version mismatch", LogLevel::LL_ERROR); + return r; + case GRDevice::AuthResult::IncorrectPassword: + _log("Incorrect password", LogLevel::LL_ERROR); + return r; + } + } + } + + return GRDevice::AuthResult::Error; + +timeout: + con->disconnect_from_host(); + _log("Connection timeout. Disconnecting", LogLevel::LL_NORMAL); + return GRDevice::AuthResult::Timeout; + +#undef wait_packet +#undef packet_error_check +} + +////////////////////////////////////////////// +///////////// INPUT COLLECTOR //////////////// +////////////////////////////////////////////// + +void GRInputCollector::_update_stream_rect() { + if (!dev || dev->get_status() != GRDevice::WorkingStatus::STATUS_WORKING) + return; + + if (texture_rect && !texture_rect->is_queued_for_deletion()) { + switch (dev->get_stretch_mode()) { + case GRClient::StretchMode::STRETCH_KEEP_ASPECT: { + Ref tex = texture_rect->get_texture(); + if (tex.is_null()) + goto fill; + + Vector2 pos = texture_rect->get_global_position(); + Vector2 outer_size = texture_rect->get_size(); + Vector2 inner_size = tex->get_size(); + float asp_rec = outer_size.x / outer_size.y; + float asp_tex = inner_size.x / inner_size.y; + + if (asp_rec > asp_tex) { + float width = outer_size.y * asp_tex; + stream_rect = Rect2(Vector2(pos.x + (outer_size.x - width) / 2, pos.y), Vector2(width, outer_size.y)); + return; + } else { + float height = outer_size.x / asp_tex; + stream_rect = Rect2(Vector2(pos.x, pos.y + (outer_size.y - height) / 2), Vector2(outer_size.x, height)); + return; + } + break; + } + case GRClient::StretchMode::STRETCH_FILL: + default: + fill: + stream_rect = Rect2(texture_rect->get_global_position(), texture_rect->get_size()); + return; + } + } + if (parent && !parent->is_queued_for_deletion()) { + stream_rect = Rect2(parent->get_global_position(), parent->get_size()); + } + return; +} + +void GRInputCollector::_collect_input(Ref ie) { + Ref data = GRInputDataEvent::parse_event(ie, stream_rect); + if (data.is_valid()) { + _TS_LOCK_; + collected_input_data.push_back(data); + _TS_UNLOCK_; + } +} + +void GRInputCollector::_release_pointers() { + { + auto buttons = mouse_buttons.keys(); + for (int i = 0; i < buttons.size(); i++) { + if (mouse_buttons[buttons[i]]) { + Ref iemb(memnew(InputEventMouseButton)); + iemb->set_button_index(buttons[i]); + iemb->set_pressed(false); + buttons[i] = false; + _collect_input(iemb); + } + } + buttons.clear(); + } + + { + auto touches = screen_touches.keys(); + for (int i = 0; i < touches.size(); i++) { + if (screen_touches[touches[i]]) { + Ref iest(memnew(InputEventScreenTouch)); + iest->set_index(touches[i]); + iest->set_pressed(false); + touches[i] = false; + _collect_input(iest); + } + } + touches.clear(); + } +} + +#ifndef GDNATIVE_LIBRARY + +void GRInputCollector::_bind_methods() { + ClassDB::bind_method(D_METHOD("_input", "input_event"), &GRInputCollector::_input); + + ClassDB::bind_method(D_METHOD("is_capture_on_focus"), &GRInputCollector::is_capture_on_focus); + ClassDB::bind_method(D_METHOD("set_capture_on_focus", "value"), &GRInputCollector::set_capture_on_focus); + ClassDB::bind_method(D_METHOD("is_capture_when_hover"), &GRInputCollector::is_capture_when_hover); + ClassDB::bind_method(D_METHOD("set_capture_when_hover", "value"), &GRInputCollector::set_capture_when_hover); + ClassDB::bind_method(D_METHOD("is_capture_pointer"), &GRInputCollector::is_capture_pointer); + ClassDB::bind_method(D_METHOD("set_capture_pointer", "value"), &GRInputCollector::set_capture_pointer); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "capture_on_focus"), "set_capture_on_focus", "is_capture_on_focus"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "capture_when_hover"), "set_capture_when_hover", "is_capture_when_hover"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "capture_pointer"), "set_capture_pointer", "is_capture_pointer"); +} + +#else + +void GRInputCollector::_register_methods() { + METHOD_REG(GRInputCollector, _notification); + + METHOD_REG(GRInputCollector, _input); + + METHOD_REG(GRInputCollector, is_capture_on_focus); + METHOD_REG(GRInputCollector, set_capture_on_focus); + METHOD_REG(GRInputCollector, is_capture_when_hover); + METHOD_REG(GRInputCollector, set_capture_when_hover); + METHOD_REG(GRInputCollector, is_capture_pointer); + METHOD_REG(GRInputCollector, set_capture_pointer); + + register_property("capture_on_focus", &GRInputCollector::set_capture_on_focus, &GRInputCollector::is_capture_on_focus, false); + register_property("capture_when_hover", &GRInputCollector::set_capture_when_hover, &GRInputCollector::is_capture_when_hover, true); + register_property("capture_pointer", &GRInputCollector::set_capture_pointer, &GRInputCollector::is_capture_pointer, true); +} + +#endif + +void GRInputCollector::_input(Ref ie) { + if (!parent || (capture_only_when_control_in_focus && !parent->has_focus()) || + (dev && dev->get_status() != GRDevice::WorkingStatus::STATUS_WORKING) || + !dev->is_stream_active() || !is_inside_tree()) { + return; + } + + _TS_LOCK_; + if (collected_input_data.size() >= 256) { + collected_input_data.resize(0); + } + _TS_UNLOCK_; + + _update_stream_rect(); + + if (ie.is_null()) { + _log("InputEvent is null", LogLevel::LL_ERROR); + return; + } + + { + Ref iemb = ie; + if (iemb.is_valid()) { + int idx = (int)iemb->get_button_index(); + + if ((!stream_rect.has_point(iemb->get_position()) && capture_pointer_only_when_hover_control) || dont_capture_pointer) { + if (idx == BUTTON_WHEEL_UP || idx == BUTTON_WHEEL_DOWN || + idx == BUTTON_WHEEL_LEFT || idx == BUTTON_WHEEL_RIGHT) { + return; + } else { + if (iemb->is_pressed() || !((bool)mouse_buttons[idx])) + return; + } + } + + mouse_buttons[idx] = iemb->is_pressed(); + goto end; + } + } + + { + Ref iemm = ie; + if (iemm.is_valid()) { + if ((!stream_rect.has_point(iemm->get_position()) && capture_pointer_only_when_hover_control) || dont_capture_pointer) + return; + goto end; + } + } + + { + Ref iest = ie; + if (iest.is_valid()) { + int idx = (int)iest->get_index(); + if ((!stream_rect.has_point(iest->get_position()) && capture_pointer_only_when_hover_control) || dont_capture_pointer) { + if (iest->is_pressed() || !((bool)screen_touches[idx])) + return; + } + + screen_touches[idx] = iest->is_pressed(); + goto end; + } + } + + { + Ref iesd = ie; + if (iesd.is_valid()) { + if ((!stream_rect.has_point(iesd->get_position()) && capture_pointer_only_when_hover_control) || dont_capture_pointer) + return; + goto end; + } + } + + { + Ref iemg = ie; + if (iemg.is_valid()) { + if ((!stream_rect.has_point(iemg->get_position()) && capture_pointer_only_when_hover_control) || dont_capture_pointer) + return; + goto end; + } + } + + { + Ref iepg = ie; + if (iepg.is_valid()) { + if ((!stream_rect.has_point(iepg->get_position()) && capture_pointer_only_when_hover_control) || dont_capture_pointer) + return; + goto end; + } + } + +end: + + _collect_input(ie); +} + +void GRInputCollector::_notification(int p_notification) { + switch (p_notification) { + case NOTIFICATION_POSTINITIALIZE: +#ifndef GDNATIVE_LIBRARY + _init(); +#endif + break; + case NOTIFICATION_PREDELETE: + _deinit(); + break; + case NOTIFICATION_ENTER_TREE: { + parent = cast_to(get_parent()); + break; + } + case NOTIFICATION_EXIT_TREE: { + parent = nullptr; + break; + } + case NOTIFICATION_PROCESS: { + _TS_LOCK_; + auto w = sensors.write(); + w[0] = Input::get_singleton()->get_accelerometer(); + w[1] = Input::get_singleton()->get_gravity(); + w[2] = Input::get_singleton()->get_gyroscope(); + w[3] = Input::get_singleton()->get_magnetometer(); + release_pva_write(w); + _TS_UNLOCK_; + break; + } + } +} + +bool GRInputCollector::is_capture_on_focus() { + return capture_only_when_control_in_focus; +} + +void GRInputCollector::set_capture_on_focus(bool value) { + capture_only_when_control_in_focus = value; +} + +bool GRInputCollector::is_capture_when_hover() { + return capture_pointer_only_when_hover_control; +} + +void GRInputCollector::set_capture_when_hover(bool value) { + capture_pointer_only_when_hover_control = value; +} + +bool GRInputCollector::is_capture_pointer() { + return !dont_capture_pointer; +} + +void GRInputCollector::set_capture_pointer(bool value) { + if (!value) { + _release_pointers(); + } + dont_capture_pointer = !value; +} + +bool GRInputCollector::is_capture_input() { + return is_processing_input(); +} + +void GRInputCollector::set_capture_input(bool value) { + set_process_input(value); +} + +void GRInputCollector::set_tex_rect(TextureRect *tr) { + texture_rect = tr; +} + +Ref GRInputCollector::get_collected_input_data() { + Ref res(memnew(GRPacketInputData)); + Ref s(memnew(GRInputDeviceSensorsData)); + + _TS_LOCK_; + + s->set_sensors(sensors); + collected_input_data.push_back(s); + res->set_input_data(collected_input_data); + collected_input_data.resize(0); + + _TS_UNLOCK_; + return res; +} + +void GRInputCollector::_init() { + LEAVE_IF_EDITOR(); + _TS_LOCK_; + parent = nullptr; + set_process(true); + set_process_input(true); + sensors.resize(4); + _TS_UNLOCK_; +} + +void GRInputCollector::_deinit() { + LEAVE_IF_EDITOR(); + _TS_LOCK_; + sensors.resize(0); + collected_input_data.resize(0); + if (this_in_client) + *this_in_client = nullptr; + mouse_buttons.clear(); + screen_touches.clear(); + _TS_UNLOCK_; +} + +////////////////////////////////////////////// +/////////////// TEXTURE RECT ///////////////// +////////////////////////////////////////////// + +void GRTextureRect::_tex_size_changed() { + if (dev) { + Vector2 v = get_size(); + bool is_vertical = v.x < v.y; + if (is_vertical != dev->no_signal_is_vertical) { + dev->no_signal_is_vertical = is_vertical; + dev->_update_stream_texture_state(dev->signal_connection_state); // update texture + } + } +} + +#ifndef GDNATIVE_LIBRARY + +void GRTextureRect::_bind_methods() { + ClassDB::bind_method(D_METHOD("_tex_size_changed"), &GRTextureRect::_tex_size_changed); +} + +#else + +void GRTextureRect::_register_methods() { + METHOD_REG(GRTextureRect, _notification); + + METHOD_REG(GRTextureRect, _tex_size_changed); +} + +#endif + +void GRTextureRect::_notification(int p_notification) { + switch (p_notification) { + case NOTIFICATION_POSTINITIALIZE: +#ifndef GDNATIVE_LIBRARY + _init(); +#endif + break; + case NOTIFICATION_PREDELETE: + _deinit(); + break; + } +} + +void GRTextureRect::_init() { + LEAVE_IF_EDITOR(); + connect("resized", this, "_tex_size_changed"); +} + +void GRTextureRect::_deinit() { + if (this_in_client) + *this_in_client = nullptr; + LEAVE_IF_EDITOR(); + disconnect("resized", this, "_tex_size_changed"); +} + +#endif // !NO_GODOTREMOTE_CLIENT diff --git a/modules/godot_remote/godot_remote/GRClient.h b/modules/godot_remote/godot_remote/GRClient.h new file mode 100644 index 0000000..2776e46 --- /dev/null +++ b/modules/godot_remote/godot_remote/GRClient.h @@ -0,0 +1,338 @@ +/* GRClient.h */ +#pragma once + +#ifndef NO_GODOTREMOTE_CLIENT + +#include "GRDevice.h" + +#ifndef GDNATIVE_LIBRARY +#include "core/io/ip_address.h" +#include "core/io/stream_peer_tcp.h" +#include "scene/gui/texture_rect.h" +#include "scene/main/node.h" + +#else + +#include +#include +#include +#include +#include +#include +#include +using namespace godot; +#endif + +class GRClient : public GRDevice { + GD_S_CLASS(GRClient, GRDevice); + + friend class GRTextureRect; + + enum class ScreenOrientation : int { + NONE = 0, + VERTICAL = 1, + HORIZONTAL = 2, + }; + +public: + enum ConnectionType : int { + CONNECTION_WiFi = 0, + CONNECTION_ADB = 1, + }; + + enum StretchMode : int { + STRETCH_KEEP_ASPECT = 0, + STRETCH_FILL = 1, + }; + + enum StreamState : int { + STREAM_NO_SIGNAL = 0, + STREAM_ACTIVE = 1, + STREAM_NO_IMAGE = 2, + }; + +#ifndef GDNATIVE_LIBRARY +private: +#else +public: +#endif + + class ImgProcessingStorageClient : public Object { + GD_CLASS(ImgProcessingStorageClient, Object); + + public: + GRClient *dev = nullptr; + PoolByteArray tex_data; + uint64_t framerate = 0; + int format = 0; + ImageCompressionType compression_type = ImageCompressionType::COMPRESSION_UNCOMPRESSED; + Size2 size; + bool _is_processing_img = false; + bool _thread_closing = false; + + static void _register_methods(){}; + void _init() { + LEAVE_IF_EDITOR(); + tex_data = PoolByteArray(); + }; + + ~ImgProcessingStorageClient() { + LEAVE_IF_EDITOR(); + tex_data.resize(0); + } + }; + + class ConnectionThreadParamsClient : public Object { + GD_CLASS(ConnectionThreadParamsClient, Object); + + public: + GRClient *dev = nullptr; + Ref peer; + Ref ppeer; + + Thread_define(thread_ref); + + bool break_connection = false; + bool stop_thread = false; + bool finished = false; + + void close_thread() { + break_connection = true; + stop_thread = true; + Thread_close(thread_ref); + } + + static void _register_methods(){}; + void _init(){}; + + ~ConnectionThreadParamsClient() { + LEAVE_IF_EDITOR(); + close_thread(); + if (peer.is_valid()) { + peer.unref(); + } + if (ppeer.is_valid()) { + ppeer.unref(); + } + }; + }; + +private: + bool is_deleting = false; + bool is_connection_working = false; + Node *settings_menu_node = nullptr; + class Control *control_to_show_in = nullptr; + class GRTextureRect *tex_shows_stream = nullptr; + class GRInputCollector *input_collector = nullptr; + ConnectionThreadParamsClient *thread_connection = nullptr; + ScreenOrientation is_vertical = ScreenOrientation::NONE; + + String device_id = "UNKNOWN"; + String server_address = String("127.0.0.1"); + + String password; + bool is_filtering_enabled = true; + bool _viewport_orientation_syncing = true; + bool _viewport_aspect_ratio_syncing = true; + bool _server_settings_syncing = false; + StretchMode stretch_mode = StretchMode::STRETCH_KEEP_ASPECT; + + Mutex_define(connection_mutex); + ConnectionType con_type = ConnectionType::CONNECTION_WiFi; + int input_buffer_size_in_mb = 4; + int send_data_fps = 60; + + uint64_t sync_time_client = 0; + uint64_t sync_time_server = 0; + + // NO SIGNAL screen + uint64_t prev_valid_connection_time = 0; + StreamState signal_connection_state = StreamState::STREAM_NO_SIGNAL; + bool no_signal_is_vertical = false; + Ref custom_no_signal_texture; + Ref custom_no_signal_vertical_texture; + Ref custom_no_signal_material; + +#ifndef NO_GODOTREMOTE_DEFAULT_RESOURCES + Ref no_signal_image; + Ref no_signal_vertical_image; + Ref no_signal_mat; +#endif + + Node *custom_input_scene = nullptr; + String custom_input_scene_tmp_pck_file = "user://custom_input_scene.pck"; + + void _force_update_stream_viewport_signals(); + void _load_custom_input_scene(Ref _data); + void _remove_custom_input_scene(); + void _viewport_size_changed(); + void _on_node_deleting(int var_name); + + void _update_texture_from_image(Ref img); + void _update_stream_texture_state(ENUM_ARG(StreamState) _stream_state); + virtual void _reset_counters() override; + + THREAD_FUNC void _thread_connection(THREAD_DATA p_userdata); + THREAD_FUNC void _thread_image_decoder(THREAD_DATA p_userdata); + + static void _connection_loop(ConnectionThreadParamsClient *con_thread); + static GRDevice::AuthResult _auth_on_server(GRClient *dev, Ref &con); + +protected: + virtual void _internal_call_only_deffered_start() override; + virtual void _internal_call_only_deffered_stop() override; + +#ifndef GDNATIVE_LIBRARY + static void _bind_methods(); +#else +public: + static void _register_methods(); + +protected: +#endif + + void _notification(int p_notification); + +public: + void set_control_to_show_in(class Control *ctrl, int position_in_node DEF_ARG(= 0)); + void set_custom_no_signal_texture(Ref custom_tex); + void set_custom_no_signal_vertical_texture(Ref custom_tex); + void set_custom_no_signal_material(Ref custom_mat); + + bool is_capture_on_focus(); + void set_capture_on_focus(bool value); + bool is_capture_when_hover(); + void set_capture_when_hover(bool value); + bool is_capture_pointer(); + void set_capture_pointer(bool value); + bool is_capture_input(); + void set_capture_input(bool value); + void set_connection_type(ENUM_ARG(ConnectionType) type); + ENUM_ARG(ConnectionType) + get_connection_type(); + void set_target_send_fps(int fps); + int get_target_send_fps(); + void set_stretch_mode(ENUM_ARG(StretchMode) stretch); + ENUM_ARG(StretchMode) + get_stretch_mode(); + void set_texture_filtering(bool is_filtering); + bool get_texture_filtering(); + void set_viewport_orientation_syncing(bool is_syncing); + bool is_viewport_orientation_syncing(); + void set_viewport_aspect_ratio_syncing(bool is_syncing); + bool is_viewport_aspect_ratio_syncing(); + void set_server_settings_syncing(bool is_syncing); + bool is_server_settings_syncing(); + void set_password(String _pass); + String get_password(); + void set_device_id(String _id); + String get_device_id(); + + ENUM_ARG(StreamState) + get_stream_state(); + bool is_stream_active(); + bool is_connected_to_host(); + Node *get_custom_input_scene(); + String get_address(); + bool set_address(String ip); + bool set_address_port(String ip, uint16_t _port); + void set_input_buffer(int mb); + + void set_server_setting(ENUM_ARG(TypesOfServerSettings) param, Variant value); + void disable_overriding_server_settings(); + + void _init(); + void _deinit(); +}; + +class GRInputCollector : public Node { + GD_CLASS(GRInputCollector, Node); + friend GRClient; + + _TS_CLASS_; + +private: + GRClient *dev = nullptr; + GRInputCollector **this_in_client = nullptr; //somebody help + + class TextureRect *texture_rect = nullptr; + //Array collected_input_data; // Ref + std::vector > collected_input_data; + class Control *parent; + bool capture_only_when_control_in_focus = false; + bool capture_pointer_only_when_hover_control = true; + bool dont_capture_pointer = false; + + Rect2 stream_rect; + PoolVector3Array sensors; + + Dictionary mouse_buttons; + Dictionary screen_touches; + +protected: + void _collect_input(Ref ie); + void _update_stream_rect(); + void _release_pointers(); + +#ifndef GDNATIVE_LIBRARY + static void _bind_methods(); +#else +public: + static void _register_methods(); + +protected: +#endif + + void _input(Ref ie); + void _notification(int p_notification); + +public: + bool is_capture_on_focus(); + void set_capture_on_focus(bool value); + bool is_capture_when_hover(); + void set_capture_when_hover(bool value); + bool is_capture_pointer(); + void set_capture_pointer(bool value); + bool is_capture_input(); + void set_capture_input(bool value); + + void set_tex_rect(class TextureRect *tr); + + Ref get_collected_input_data(); + + void _init(); + void _deinit(); +}; + +class GRTextureRect : public TextureRect { + GD_CLASS(GRTextureRect, TextureRect); + friend GRClient; + + GRClient *dev = nullptr; + GRTextureRect **this_in_client = nullptr; + void _tex_size_changed(); + +protected: +#ifndef GDNATIVE_LIBRARY + static void _bind_methods(); +#else +public: + static void _register_methods(); + +protected: +#endif + + void _notification(int p_notification); + +public: + void _init(); + void _deinit(); +}; + +#ifndef GDNATIVE_LIBRARY +VARIANT_ENUM_CAST(GRClient::ConnectionType) +VARIANT_ENUM_CAST(GRClient::StretchMode) +VARIANT_ENUM_CAST(GRClient::StreamState) +#endif + +#endif // !NO_GODOTREMOTE_CLIENT diff --git a/modules/godot_remote/godot_remote/GRDevice.cpp b/modules/godot_remote/godot_remote/GRDevice.cpp new file mode 100644 index 0000000..e99ae61 --- /dev/null +++ b/modules/godot_remote/godot_remote/GRDevice.cpp @@ -0,0 +1,255 @@ +/* GRDevice.cpp */ +#include "GRDevice.h" +#include "GodotRemote.h" + +#ifndef GDNATIVE_LIBRARY +#else +#include +using namespace godot; +#endif + +using namespace GRUtils; + +#ifndef GDNATIVE_LIBRARY + +void GRDevice::_bind_methods() { + ClassDB::bind_method(D_METHOD("_internal_call_only_deffered_start"), &GRDevice::_internal_call_only_deffered_start); + ClassDB::bind_method(D_METHOD("_internal_call_only_deffered_stop"), &GRDevice::_internal_call_only_deffered_stop); + + ClassDB::bind_method(D_METHOD("_internal_call_only_deffered_restart"), &GRDevice::_internal_call_only_deffered_restart); + + ClassDB::bind_method(D_METHOD("get_avg_ping"), &GRDevice::get_avg_ping); + ClassDB::bind_method(D_METHOD("get_min_ping"), &GRDevice::get_min_ping); + ClassDB::bind_method(D_METHOD("get_max_ping"), &GRDevice::get_max_ping); + ClassDB::bind_method(D_METHOD("get_avg_fps"), &GRDevice::get_avg_fps); + ClassDB::bind_method(D_METHOD("get_min_fps"), &GRDevice::get_min_fps); + ClassDB::bind_method(D_METHOD("get_max_fps"), &GRDevice::get_max_fps); + + ClassDB::bind_method(D_METHOD("get_port"), &GRDevice::get_port); + ClassDB::bind_method(D_METHOD("set_port", "port"), &GRDevice::set_port, DEFVAL(52341)); + + //ClassDB::bind_method(D_METHOD("send_packet", "packet"), &GRDevice::send_packet); + ClassDB::bind_method(D_METHOD("send_user_data", "packet_id", "user_data", "full_objects"), &GRDevice::send_user_data, DEFVAL(false)); + + ClassDB::bind_method(D_METHOD("start"), &GRDevice::start); + ClassDB::bind_method(D_METHOD("stop"), &GRDevice::stop); + ClassDB::bind_method(D_METHOD("get_status"), &GRDevice::get_status); + + ADD_SIGNAL(MethodInfo("status_changed", PropertyInfo(Variant::INT, "status"))); + ADD_SIGNAL(MethodInfo("user_data_received", PropertyInfo(Variant::NIL, "packet_id"), PropertyInfo(Variant::NIL, "user_data"))); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "port"), "set_port", "get_port"); + + BIND_ENUM_CONSTANT(STATUS_STARTING); + BIND_ENUM_CONSTANT(STATUS_STOPPING); + BIND_ENUM_CONSTANT(STATUS_WORKING); + BIND_ENUM_CONSTANT(STATUS_STOPPED); + + BIND_ENUM_CONSTANT(SERVER_SETTINGS_USE_INTERNAL); + BIND_ENUM_CONSTANT(SERVER_SETTINGS_VIDEO_STREAM_ENABLED); + BIND_ENUM_CONSTANT(SERVER_SETTINGS_COMPRESSION_TYPE); + BIND_ENUM_CONSTANT(SERVER_SETTINGS_JPG_QUALITY); + BIND_ENUM_CONSTANT(SERVER_SETTINGS_SKIP_FRAMES); + BIND_ENUM_CONSTANT(SERVER_SETTINGS_RENDER_SCALE); + + BIND_ENUM_CONSTANT(SUBSAMPLING_Y_ONLY); + BIND_ENUM_CONSTANT(SUBSAMPLING_H1V1); + BIND_ENUM_CONSTANT(SUBSAMPLING_H2V1); + BIND_ENUM_CONSTANT(SUBSAMPLING_H2V2); + + BIND_ENUM_CONSTANT(COMPRESSION_UNCOMPRESSED); + BIND_ENUM_CONSTANT(COMPRESSION_JPG); + BIND_ENUM_CONSTANT(COMPRESSION_PNG); +} + +#else + +void GRDevice::_register_methods() { + METHOD_REG(GRDevice, _notification); + + METHOD_REG(GRDevice, _internal_call_only_deffered_start); + METHOD_REG(GRDevice, _internal_call_only_deffered_stop); + + METHOD_REG(GRDevice, _internal_call_only_deffered_restart); + + METHOD_REG(GRDevice, get_avg_ping); + METHOD_REG(GRDevice, get_min_ping); + METHOD_REG(GRDevice, get_max_ping); + METHOD_REG(GRDevice, get_avg_fps); + METHOD_REG(GRDevice, get_min_fps); + METHOD_REG(GRDevice, get_max_fps); + + METHOD_REG(GRDevice, get_port); + METHOD_REG(GRDevice, set_port); + + //METHOD_REG(GRDevice, send_packet); + METHOD_REG(GRDevice, send_user_data); + + METHOD_REG(GRDevice, start); + METHOD_REG(GRDevice, stop); + METHOD_REG(GRDevice, get_status); + + register_signal("status_changed", "status", GODOT_VARIANT_TYPE_INT); + register_signal("user_data_received", "packet_id", GODOT_VARIANT_TYPE_NIL, "user_data", GODOT_VARIANT_TYPE_NIL); + + register_property("port", &GRDevice::set_port, &GRDevice::get_port, 52341); +} + +#endif + +void GRDevice::_notification(int p_notification) { + switch (p_notification) { + case NOTIFICATION_POSTINITIALIZE: +#ifndef GDNATIVE_LIBRARY + _init(); +#endif + break; + case NOTIFICATION_PREDELETE: + _deinit(); + break; + } +} + +void GRDevice::_reset_counters() { + avg_fps = min_fps = max_fps = 0; + avg_ping = min_ping = max_ping = 0; + fps_queue = ping_queue = iterable_queue(); +} + +void GRDevice::_update_avg_ping(uint64_t ping) { + ping_queue.add_value_limited(ping, avg_ping_max_count); + calculate_avg_min_max_values(ping_queue, &avg_ping, &min_ping, &max_ping, &GRDevice::_ping_calc_modifier); +} + +void GRDevice::_update_avg_fps(uint64_t frametime) { + fps_queue.add_value_limited(frametime, (int)round(Engine::get_singleton()->get_frames_per_second())); + calculate_avg_min_max_values(fps_queue, &avg_fps, &min_fps, &max_fps, &GRDevice::_fps_calc_modifier); +} + +float GRDevice::_ping_calc_modifier(double i) { + return float(i * 0.001); +} + +float GRDevice::_fps_calc_modifier(double i) { + if (i > 0) + return float(1000000.0 / i); + else + return 0; +} + +void GRDevice::send_user_data(Variant packet_id, Variant user_data, bool full_objects) { + Mutex_lock(send_queue_mutex); + Ref packet = newref(GRPacketCustomUserData); + send_packet(packet); + + packet->set_packet_id(packet_id); + packet->set_send_full_objects(full_objects); + packet->set_user_data(user_data); + + Mutex_unlock(send_queue_mutex); +} + +void GRDevice::_send_queue_resize(int new_size) { + Mutex_lock(send_queue_mutex); + send_queue.resize(new_size); + Mutex_unlock(send_queue_mutex); +} + +Ref GRDevice::_send_queue_pop_front() { + Mutex_lock(send_queue_mutex); + Ref packet; + if (send_queue.size() > 0) { + packet = send_queue.front(); + send_queue.erase(send_queue.begin()); + } + Mutex_unlock(send_queue_mutex); + return packet; +} + +void GRDevice::set_status(WorkingStatus status) { + working_status = status; + emit_signal("status_changed", working_status); +} + +float GRDevice::get_avg_ping() { + return avg_ping; +} + +float GRDevice::get_min_ping() { + return min_ping; +} + +float GRDevice::get_max_ping() { + return max_ping; +} + +float GRDevice::get_avg_fps() { + return avg_fps; +} + +float GRDevice::get_min_fps() { + return min_fps; +} + +float GRDevice::get_max_fps() { + return max_fps; +} + +uint16_t GRDevice::get_port() { + return port; +} + +void GRDevice::set_port(uint16_t _port) { + port = _port; + restart(); +} + +void GRDevice::send_packet(Ref packet) { + ERR_FAIL_COND(packet.is_null()); + + Mutex_lock(send_queue_mutex); + if (send_queue.size() > 10000) + send_queue.resize(0); + + send_queue.push_back(packet); + Mutex_unlock(send_queue_mutex); +} + +void GRDevice::start() { + call_deferred("_internal_call_only_deffered_start"); +} + +void GRDevice::stop() { + call_deferred("_internal_call_only_deffered_stop"); +} + +void GRDevice::restart() { + call_deferred("_internal_call_only_deffered_restart"); +} + +void GRDevice::_internal_call_only_deffered_restart() { + if (get_status() == (int)WorkingStatus::STATUS_WORKING) { + _internal_call_only_deffered_stop(); + _internal_call_only_deffered_start(); + } +} + +GRDevice::WorkingStatus GRDevice::get_status() { + return working_status; +} + +void GRDevice::_init() { + LEAVE_IF_EDITOR(); + port = GET_PS(GodotRemote::ps_general_port_name); + + Mutex_delete(send_queue_mutex); + Mutex_create(send_queue_mutex); +} + +void GRDevice::_deinit() { + LEAVE_IF_EDITOR(); + Mutex_delete(send_queue_mutex); + if (GodotRemote::get_singleton()) { + GodotRemote::get_singleton()->device = nullptr; + } +} diff --git a/modules/godot_remote/godot_remote/GRDevice.h b/modules/godot_remote/godot_remote/GRDevice.h new file mode 100644 index 0000000..5dd61ca --- /dev/null +++ b/modules/godot_remote/godot_remote/GRDevice.h @@ -0,0 +1,143 @@ +/* GRDevice.h */ +#pragma once + +#include "GRInputData.h" +#include "GRPacket.h" +#include "GRUtils.h" + +#ifndef GDNATIVE_LIBRARY +#include "scene/main/node.h" +#else +#include +#include +#include +#include +#include +#include +#include +using namespace godot; +#endif + +class GRDevice : public Node { + GD_CLASS(GRDevice, Node); + +public: + enum class AuthResult : int { + OK = 0, + Error = 1, + Timeout = 2, + TryToConnect = 3, + RefuseConnection = 4, + VersionMismatch = 5, + IncorrectPassword = 6, + PasswordRequired = 7, + }; + + enum WorkingStatus : int { + STATUS_STOPPED = 0, + STATUS_WORKING = 1, + STATUS_STOPPING = 2, + STATUS_STARTING = 3, + }; + + enum TypesOfServerSettings : int { + SERVER_SETTINGS_USE_INTERNAL = 0, + SERVER_SETTINGS_VIDEO_STREAM_ENABLED = 1, + SERVER_SETTINGS_COMPRESSION_TYPE = 2, + SERVER_SETTINGS_JPG_QUALITY = 3, + SERVER_SETTINGS_SKIP_FRAMES = 4, + SERVER_SETTINGS_RENDER_SCALE = 5, + }; + + enum Subsampling : int { + SUBSAMPLING_Y_ONLY = 0, + SUBSAMPLING_H1V1 = 1, + SUBSAMPLING_H2V1 = 2, + SUBSAMPLING_H2V2 = 3 + }; + + enum ImageCompressionType : int { + COMPRESSION_UNCOMPRESSED = 0, + COMPRESSION_JPG = 1, + COMPRESSION_PNG = 2, + }; + +private: + WorkingStatus working_status = WorkingStatus::STATUS_STOPPED; + +protected: + template + T _find_queued_packet_by_type() { + for (int i = 0; i < send_queue.size(); i++) { + T o = send_queue[i]; + if (o.is_valid()) { + return o; + } + } + return T(); + } + + GRUtils::iterable_queue fps_queue; + GRUtils::iterable_queue ping_queue; + float avg_ping = 0, min_ping = 0, max_ping = 0; + float avg_fps = 0, min_fps = 0, max_fps = 0; + uint32_t avg_ping_max_count = 100; + + Mutex_define(send_queue_mutex); + std::vector > send_queue; + + void set_status(WorkingStatus status); + void _update_avg_ping(uint64_t ping); + void _update_avg_fps(uint64_t frametime); + static float _ping_calc_modifier(double i); + static float _fps_calc_modifier(double i); + void _send_queue_resize(int new_size); + Ref _send_queue_pop_front(); + + virtual void _reset_counters(); + virtual void _internal_call_only_deffered_start(){}; + virtual void _internal_call_only_deffered_stop(){}; + +#ifndef GDNATIVE_LIBRARY + static void _bind_methods(); +#else +public: + static void _register_methods(); + +protected: +#endif + + void _notification(int p_notification); + +public: + uint16_t port = 52341; + + float get_avg_ping(); + float get_min_ping(); + float get_max_ping(); + float get_avg_fps(); + float get_min_fps(); + float get_max_fps(); + uint16_t get_port(); + void set_port(uint16_t _port); + + void send_packet(Ref packet); + void send_user_data(Variant packet_id, Variant user_data, bool full_objects = false); + + void start(); + void stop(); + void restart(); + void _internal_call_only_deffered_restart(); + + virtual WorkingStatus get_status(); + + void _init(); + void _deinit(); +}; + +#ifndef GDNATIVE_LIBRARY +VARIANT_ENUM_CAST(GRDevice::WorkingStatus) +VARIANT_ENUM_CAST(GRDevice::Subsampling) +VARIANT_ENUM_CAST(GRDevice::ImageCompressionType) +VARIANT_ENUM_CAST(GRDevice::TypesOfServerSettings) +#endif diff --git a/modules/godot_remote/godot_remote/GRInputData.cpp b/modules/godot_remote/godot_remote/GRInputData.cpp new file mode 100644 index 0000000..bff312c --- /dev/null +++ b/modules/godot_remote/godot_remote/GRInputData.cpp @@ -0,0 +1,461 @@ +/* GRInputData.cpp */ +#include "GRInputData.h" +#include "GRPacket.h" + +#ifndef GDNATIVE_LIBRARY +#include "core/os/os.h" +#include "scene/main/scene_tree.h" +#include "scene/main/viewport.h" +#else + +#include +#include +#include +using namespace godot; +#endif + +using namespace GRUtils; + +void GRInputDeviceSensorsData::set_sensors(PoolVector3Array _sensors) { + data->resize(0); + data->put_8((uint8_t)get_type()); + data->put_var(_sensors); +} + +PoolVector3Array GRInputDeviceSensorsData::get_sensors() { + data->seek(0); + data->get_8(); + return data->get_var(); +} + +Ref GRInputData::create(const PoolByteArray &buf) { +#define CREATE(_d) \ + { \ + Ref<_d> id(memnew(_d)); \ + id->data->set_data_array(buf); \ + return id; \ + } + + InputType type = (InputType)((PoolByteArray)buf)[0]; + switch (type) { + case InputType::_NoneIT: + ERR_PRINT("Can't create GRInputData with type 'None'!"); + break; + // ADDITIONAL CLASSES + case InputType::_InputDeviceSensors: + CREATE(GRInputDeviceSensorsData); + + // INPUT EVENTS + case InputType::_InputEvent: + case InputType::_InputEventWithModifiers: + case InputType::_InputEventMouse: + case InputType::_InputEventGesture: + ERR_PRINT("Can't create GRInputData for abstract InputEvent! Type index: " + str((int)type)); + break; + case InputType::_InputEventAction: + CREATE(GRIEDataAction); + case InputType::_InputEventJoypadButton: + CREATE(GRIEDataJoypadButton); + case InputType::_InputEventJoypadMotion: + CREATE(GRIEDataJoypadMotion); + case InputType::_InputEventKey: + CREATE(GRIEDataKey); + case InputType::_InputEventMagnifyGesture: + CREATE(GRIEDataMagnifyGesture); + case InputType::_InputEventMIDI: + CREATE(GRIEDataMIDI); + case InputType::_InputEventMouseButton: + CREATE(GRIEDataMouseButton); + case InputType::_InputEventMouseMotion: + CREATE(GRIEDataMouseMotion); + case InputType::_InputEventPanGesture: + CREATE(GRIEDataPanGesture); + case InputType::_InputEventScreenDrag: + CREATE(GRIEDataScreenDrag); + case InputType::_InputEventScreenTouch: + CREATE(GRIEDataScreenTouch); + } +#undef CREATE + + ERR_PRINT("Can't create unsupported GRInputData! Type index: " + str((int)type)); + return Ref(); +} + +Ref GRInputDataEvent::parse_event(const Ref &ev, const Rect2 &rect) { + if (ev.is_null()) + ERR_FAIL_COND_V(ev.is_null(), Ref()); + +#define PARSE(_i, _d) \ + { \ + Ref<_i> ie = ev; \ + if (ie.is_valid()) { \ + Ref<_d> data(memnew(_d)); \ + data->_parse_event(ie, rect); \ + return data; \ + } \ + } + + PARSE(InputEventKey, GRIEDataKey); + PARSE(InputEventMouseButton, GRIEDataMouseButton); + PARSE(InputEventMouseMotion, GRIEDataMouseMotion); + PARSE(InputEventScreenTouch, GRIEDataScreenTouch); + PARSE(InputEventScreenDrag, GRIEDataScreenDrag); + PARSE(InputEventMagnifyGesture, GRIEDataMagnifyGesture); + PARSE(InputEventPanGesture, GRIEDataPanGesture); + PARSE(InputEventJoypadButton, GRIEDataJoypadButton); + PARSE(InputEventJoypadMotion, GRIEDataJoypadMotion); + PARSE(InputEventAction, GRIEDataAction); + PARSE(InputEventMIDI, GRIEDataMIDI); + +#undef PARSE + + ERR_PRINT("Not supported InputEvent type: " + str(ev)); + return Ref(); +} + +Ref GRInputDataEvent::construct_event(const Rect2 &rect) { + ERR_FAIL_COND_V(!data->get_size(), Ref()); + +#define CONSTRUCT(_i) \ + { \ + Ref<_i> ev(memnew(_i)); \ + return _construct_event(ev, vp_size); \ + } + + InputType type = _get_type(); + ERR_FAIL_COND_V_MSG(type < InputType::_InputEvent || type >= InputType::_InputEventMAX, Ref(), "Not InputEvent"); + + Rect2 vp_size = rect; + if (vp_size.size.x == 0 && vp_size.size.y == 0 && + vp_size.position.x == 0 && vp_size.position.y == 0) { + if (ST() && ST()->get_root()) { + //vp_size = SceneTree::get_singleton()->get_root()->get_visible_rect(); + vp_size = Rect2(OS::get_singleton()->get_window_size(), ST()->get_root()->get_size()); + } + } + + switch (type) { + case InputType::_NoneIT: + ERR_PRINT("Can't create GRInputDataEvent with type 'None'!"); + break; + case InputType::_InputEvent: + case InputType::_InputEventWithModifiers: + case InputType::_InputEventMouse: + case InputType::_InputEventGesture: + ERR_PRINT("Can't create GRInputDataEvent for abstract InputEvent! Type index: " + str((int)type)); + break; + case InputType::_InputEventAction: + CONSTRUCT(InputEventAction); + case InputType::_InputEventJoypadButton: + CONSTRUCT(InputEventJoypadButton); + case InputType::_InputEventJoypadMotion: + CONSTRUCT(InputEventJoypadMotion); + case InputType::_InputEventKey: + CONSTRUCT(InputEventKey); + case InputType::_InputEventMagnifyGesture: + CONSTRUCT(InputEventMagnifyGesture); + case InputType::_InputEventMIDI: + CONSTRUCT(InputEventMIDI); + case InputType::_InputEventMouseButton: + CONSTRUCT(InputEventMouseButton); + case InputType::_InputEventMouseMotion: + CONSTRUCT(InputEventMouseMotion); + case InputType::_InputEventPanGesture: + CONSTRUCT(InputEventPanGesture); + case InputType::_InputEventScreenDrag: + CONSTRUCT(InputEventScreenDrag); + case InputType::_InputEventScreenTouch: + CONSTRUCT(InputEventScreenTouch); + } + +#undef CONSTRUCT + + return Ref(); +} + +#define fix(_e) ((Vector2(_e) - rect.position) / rect.size) +#define fix_rel(_e) (Vector2(_e) / rect.size) + +#define restore(_e) ((Vector2(_e) * rect.size) + ((rect.position - rect.size) / 2.f)) +#define restore_rel(_e) (Vector2(_e) * rect.size) + +#define CONSTRUCT(_type) Ref _type::_construct_event(Ref ev, const Rect2 &rect) +#define PARSE(_type) void _type::_parse_event(const Ref &ev, const Rect2 &rect) + +////////////////////////////////////////////////////////////////////////// +// InputEventWithModifiers +CONSTRUCT(GRIEDataWithModifiers) { + GRInputDataEvent::_construct_event(ev, rect); + Ref iewm = ev; + uint8_t flags = (uint8_t)data->get_8(); + iewm->set_alt(flags & (1 << 0)); + iewm->set_shift(flags & (1 << 1)); + iewm->set_control(flags & (1 << 2)); + iewm->set_metakey(flags & (1 << 3)); + iewm->set_command(flags & (1 << 4)); + return iewm; +} + +PARSE(GRIEDataWithModifiers) { + GRInputDataEvent::_parse_event(ev, rect); + Ref iewm = ev; + data->put_8((uint8_t)iewm->get_alt() | (uint8_t)iewm->get_shift() << 1 | (uint8_t)iewm->get_control() << 2 | + (uint8_t)iewm->get_metakey() << 3 | (uint8_t)iewm->get_command() << 4); +} + +////////////////////////////////////////////////////////////////////////// +// InputEventMouse +CONSTRUCT(GRIEDataMouse) { + GRIEDataWithModifiers::_construct_event(ev, rect); + Ref iem = ev; + iem->set_button_mask(data->get_32()); + iem->set_position(restore(data->get_var())); + iem->set_global_position(restore(data->get_var())); + return iem; +} + +PARSE(GRIEDataMouse) { + GRIEDataWithModifiers::_parse_event(ev, rect); + Ref iem = ev; + data->put_32(iem->get_button_mask()); + data->put_var(fix(iem->get_position())); + data->put_var(fix(iem->get_global_position())); +} + +////////////////////////////////////////////////////////////////////////// +// InputEventGesture +CONSTRUCT(GRIEDataGesture) { + GRIEDataWithModifiers::_construct_event(ev, rect); + Ref ieg = ev; + ieg->set_position(restore(data->get_var())); + return ieg; +} + +PARSE(GRIEDataGesture) { + GRIEDataWithModifiers::_parse_event(ev, rect); + Ref ieg = ev; + data->put_var(fix(ieg->get_position())); +} + +////////////////////////////////////////////////////////////////////////// +// InputEventKey +CONSTRUCT(GRIEDataKey) { + GRIEDataWithModifiers::_construct_event(ev, rect); + Ref iek = ev; + uint8_t flags = (uint8_t)data->get_8(); + iek->set_pressed(flags & 1); + iek->set_echo((flags >> 1) & 1); + iek->set_scancode(data->get_32()); + iek->set_unicode(data->get_32()); + return iek; +} + +PARSE(GRIEDataKey) { + GRIEDataWithModifiers::_parse_event(ev, rect); + Ref iek = ev; + data->put_8((uint8_t)iek->is_pressed() | (uint8_t)iek->is_echo() << 1); + data->put_32(iek->get_scancode()); + data->put_32(iek->get_unicode()); +} + +////////////////////////////////////////////////////////////////////////// +// InputEventMouseButton +CONSTRUCT(GRIEDataMouseButton) { + GRIEDataMouse::_construct_event(ev, rect); + Ref iemb = ev; + iemb->set_factor(data->get_float()); + iemb->set_button_index(data->get_16()); + uint8_t flags = (uint8_t)data->get_8(); + iemb->set_pressed(flags & 1); + iemb->set_doubleclick((flags >> 1) & 1); + return iemb; +} + +PARSE(GRIEDataMouseButton) { + GRIEDataMouse::_parse_event(ev, rect); + Ref iemb = ev; + data->put_float(iemb->get_factor()); + data->put_16(iemb->get_button_index()); + data->put_8((uint8_t)iemb->is_pressed() | (uint8_t)iemb->is_doubleclick() << 1); +} + +////////////////////////////////////////////////////////////////////////// +// InputEventMouseMotion +CONSTRUCT(GRIEDataMouseMotion) { + GRIEDataMouse::_construct_event(ev, rect); + Ref iemm = ev; + iemm->set_pressure(data->get_float()); + iemm->set_tilt(data->get_var()); + iemm->set_relative(restore_rel(data->get_var())); + iemm->set_speed(restore_rel(data->get_var())); + return iemm; +} + +PARSE(GRIEDataMouseMotion) { + GRIEDataMouse::_parse_event(ev, rect); + Ref iemm = ev; + data->put_float(iemm->get_pressure()); + data->put_var(iemm->get_tilt()); + data->put_var(fix_rel(iemm->get_relative())); + data->put_var(fix_rel(iemm->get_speed())); +} + +////////////////////////////////////////////////////////////////////////// +// InputEventScreenTouch +CONSTRUCT(GRIEDataScreenTouch) { + GRInputDataEvent::_construct_event(ev, rect); + Ref iest = ev; + iest->set_index(data->get_8()); + iest->set_pressed(data->get_8()); + iest->set_position(restore(data->get_var())); + return iest; +} + +PARSE(GRIEDataScreenTouch) { + GRInputDataEvent::_parse_event(ev, rect); + Ref iest = ev; + data->put_8(iest->get_index()); + data->put_8(iest->is_pressed()); + data->put_var(fix(iest->get_position())); +} + +////////////////////////////////////////////////////////////////////////// +// InputEventScreenDrag +CONSTRUCT(GRIEDataScreenDrag) { + GRInputDataEvent::_construct_event(ev, rect); + Ref iesd = ev; + iesd->set_index(data->get_8()); + iesd->set_position(restore(data->get_var())); + iesd->set_relative(restore_rel(data->get_var())); + iesd->set_speed(restore_rel(data->get_var())); + return iesd; +} + +PARSE(GRIEDataScreenDrag) { + GRInputDataEvent::_parse_event(ev, rect); + Ref iesd = ev; + data->put_8(iesd->get_index()); + data->put_var(fix(iesd->get_position())); + data->put_var(fix_rel(iesd->get_relative())); + data->put_var(fix_rel(iesd->get_speed())); +} + +////////////////////////////////////////////////////////////////////////// +// InputEventMagnifyGesture +CONSTRUCT(GRIEDataMagnifyGesture) { + GRIEDataGesture::_construct_event(ev, rect); + Ref iemg = ev; + iemg->set_factor(data->get_float()); + return iemg; +} + +PARSE(GRIEDataMagnifyGesture) { + GRIEDataGesture::_parse_event(ev, rect); + Ref iemg = ev; + data->put_float(iemg->get_factor()); +} + +////////////////////////////////////////////////////////////////////////// +// InputEventPanGesture +CONSTRUCT(GRIEDataPanGesture) { + GRIEDataGesture::_construct_event(ev, rect); + Ref iepg = ev; + iepg->set_delta(restore_rel(data->get_var())); + return iepg; +} + +PARSE(GRIEDataPanGesture) { + GRIEDataGesture::_parse_event(ev, rect); + Ref iepg = ev; + data->put_var(fix_rel(iepg->get_delta())); +} + +////////////////////////////////////////////////////////////////////////// +// InputEventPanGesture +CONSTRUCT(GRIEDataJoypadButton) { + GRInputDataEvent::_construct_event(ev, rect); + Ref iejb = ev; + iejb->set_button_index(data->get_32()); + iejb->set_pressure(data->get_float()); + iejb->set_pressed(data->get_8()); + return iejb; +} + +PARSE(GRIEDataJoypadButton) { + GRInputDataEvent::_parse_event(ev, rect); + Ref iejb = ev; + data->put_32(iejb->get_button_index()); + data->put_float(iejb->get_pressure()); + data->put_8(iejb->is_pressed()); +} + +////////////////////////////////////////////////////////////////////////// +// InputEventJoypadMotion +CONSTRUCT(GRIEDataJoypadMotion) { + GRInputDataEvent::_construct_event(ev, rect); + Ref iejm = ev; + iejm->set_axis(data->get_32()); + iejm->set_axis_value(data->get_float()); + return iejm; +} + +PARSE(GRIEDataJoypadMotion) { + GRInputDataEvent::_parse_event(ev, rect); + Ref iejm = ev; + data->put_32(iejm->get_axis()); + data->put_float(iejm->get_axis_value()); +} + +////////////////////////////////////////////////////////////////////////// +// InputEventAction +CONSTRUCT(GRIEDataAction) { + GRInputDataEvent::_construct_event(ev, rect); + Ref iea = ev; + iea->set_action(data->get_var()); + iea->set_strength(data->get_float()); + iea->set_pressed(data->get_8()); + return iea; +} + +PARSE(GRIEDataAction) { + GRInputDataEvent::_parse_event(ev, rect); + Ref iea = ev; + data->put_var(iea->get_action()); + data->put_float(iea->get_strength()); + data->put_8(iea->is_pressed()); +} + +////////////////////////////////////////////////////////////////////////// +// InputEventAction +CONSTRUCT(GRIEDataMIDI) { + GRInputDataEvent::_construct_event(ev, rect); + Ref iemidi = ev; + iemidi->set_channel(data->get_32()); + iemidi->set_message(data->get_32()); + iemidi->set_pitch(data->get_32()); + iemidi->set_velocity(data->get_32()); + iemidi->set_instrument(data->get_32()); + iemidi->set_pressure(data->get_32()); + iemidi->set_controller_number(data->get_32()); + iemidi->set_controller_value(data->get_32()); + return iemidi; +} + +PARSE(GRIEDataMIDI) { + GRInputDataEvent::_parse_event(ev, rect); + Ref iemidi = ev; + data->put_32(iemidi->get_channel()); + data->put_32(iemidi->get_message()); + data->put_32(iemidi->get_pitch()); + data->put_32(iemidi->get_velocity()); + data->put_32(iemidi->get_instrument()); + data->put_32(iemidi->get_pressure()); + data->put_32(iemidi->get_controller_number()); + data->put_32(iemidi->get_controller_value()); +} + +#undef fix +#undef fix_rel +#undef restore +#undef CONSTRUCT +#undef PARSE diff --git a/modules/godot_remote/godot_remote/GRInputData.h b/modules/godot_remote/godot_remote/GRInputData.h new file mode 100644 index 0000000..6dc364d --- /dev/null +++ b/modules/godot_remote/godot_remote/GRInputData.h @@ -0,0 +1,213 @@ +/* GRInputData.h */ +#pragma once + +#include "GRUtils.h" +#ifndef GDNATIVE_LIBRARY +#include "core/io/stream_peer.h" +#include "core/os/input_event.h" +#include "core/reference.h" +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace godot; +#endif + +////////////////////////////////////////////////////////////////////////// +// BASE CLASS + +// GodotRemoteInputData +class GRInputData : public Reference { + GD_CLASS(GRInputData, Reference); + friend class GRInputDeviceSensorsData; + +public: + enum InputType : int { + _NoneIT = 0, + // Custom Input Data + _InputDeviceSensors = 1, + + // Input Events + _InputEvent = 64, + _InputEventAction = 65, + _InputEventGesture = 66, + _InputEventJoypadButton = 67, + _InputEventJoypadMotion = 68, + _InputEventKey = 69, + _InputEventMagnifyGesture = 70, + _InputEventMIDI = 71, + _InputEventMouse = 72, + _InputEventMouseButton = 73, + _InputEventMouseMotion = 74, + _InputEventPanGesture = 75, + _InputEventScreenDrag = 76, + _InputEventScreenTouch = 77, + _InputEventWithModifiers = 78, + _InputEventMAX, + }; + +protected: +#ifndef GDNATIVE_LIBRARY + static void _bind_methods() { + BIND_ENUM_CONSTANT(_NoneIT); + BIND_ENUM_CONSTANT(_InputDeviceSensors); + + BIND_ENUM_CONSTANT(_InputEvent); + BIND_ENUM_CONSTANT(_InputEventAction); + BIND_ENUM_CONSTANT(_InputEventGesture); + BIND_ENUM_CONSTANT(_InputEventJoypadButton); + BIND_ENUM_CONSTANT(_InputEventJoypadMotion); + BIND_ENUM_CONSTANT(_InputEventKey); + BIND_ENUM_CONSTANT(_InputEventMagnifyGesture); + BIND_ENUM_CONSTANT(_InputEventMIDI); + BIND_ENUM_CONSTANT(_InputEventMouse); + BIND_ENUM_CONSTANT(_InputEventMouseButton); + BIND_ENUM_CONSTANT(_InputEventMouseMotion); + BIND_ENUM_CONSTANT(_InputEventPanGesture); + BIND_ENUM_CONSTANT(_InputEventScreenDrag); + BIND_ENUM_CONSTANT(_InputEventScreenTouch); + BIND_ENUM_CONSTANT(_InputEventWithModifiers); + BIND_ENUM_CONSTANT(_InputEventMAX); + } +#else +public: + void _init(){}; + static void _register_methods(){}; +protected: +#endif + + Ref data; + virtual InputType _get_type() { return InputType::_NoneIT; }; + +public: + GRInputData() { + data = Ref(memnew(StreamPeerBuffer)); + } + + ~GRInputData() { + data->resize(0); + } + + PoolByteArray get_data() { + return data->get_data_array(); + } + void set_data(PoolByteArray &_data) { + data->set_data_array(_data); + } + virtual InputType get_type() { + if (data->get_size()) { + data->seek(0); + return (InputType)data->get_8(); + } else { + return _get_type(); + } + }; + static Ref create(const PoolByteArray &buf); +}; + +////////////////////////////////////////////////////////////////////////// +// TODO for now all custom classes must add first 8 bits for type +// data->put_8((uint8_t)get_type()) + +////////////////////////////////////////////////////////////////////////// +// ADDITIONAL CLASSES + +// Device Sensors +class GRInputDeviceSensorsData : public GRInputData { + GD_S_CLASS(GRInputDeviceSensorsData, GRInputData); + +protected: + GDNATIVE_BASIC_REGISTER; + + virtual InputType _get_type() override { return InputType::_InputDeviceSensors; }; + +public: + virtual void set_sensors(PoolVector3Array _sensors); + virtual PoolVector3Array get_sensors(); +}; + +////////////////////////////////////////////////////////////////////////// +// INPUT EVENTS + +// GodotRemoteInputEventData +class GRInputDataEvent : public GRInputData { + GD_S_CLASS(GRInputDataEvent, GRInputData); + +protected: + GDNATIVE_BASIC_REGISTER; + + virtual Ref _construct_event(Ref ev, const Rect2 &rect) { + data->seek(0); + data->get_8(); + ev->set_device(data->get_32()); + return data; + }; + virtual void _parse_event(const Ref &ev, const Rect2 &rect) { + data->resize(0); + data->put_8((uint8_t)get_type()); + data->put_32(ev->get_device()); + }; + virtual InputType _get_type() override { return InputType::_NoneIT; }; + +public: + Ref construct_event(const Rect2 &rect = Rect2()); + static Ref parse_event(const Ref &ev, const Rect2 &rect); +}; + +#define INPUT_EVENT_DATA(__class, _parent, _type) \ + class __class : public _parent { \ + GD_S_CLASS(__class, _parent); \ + friend GRInputDataEvent; \ + friend GRInputData; \ + \ + protected: \ + GDNATIVE_BASIC_REGISTER; \ + \ + virtual Ref _construct_event(Ref ev, const Rect2 &rect) override; \ + virtual void _parse_event(const Ref &ev, const Rect2 &rect) override; \ + virtual InputType _get_type() override { return _type; }; \ + \ + public: \ + } + +INPUT_EVENT_DATA(GRIEDataWithModifiers, GRInputDataEvent, InputType::_InputEventWithModifiers); +INPUT_EVENT_DATA(GRIEDataMouse, GRIEDataWithModifiers, InputType::_InputEventMouse); +INPUT_EVENT_DATA(GRIEDataGesture, GRIEDataWithModifiers, InputType::_InputEventGesture); + +INPUT_EVENT_DATA(GRIEDataKey, GRIEDataWithModifiers, InputType::_InputEventKey); +INPUT_EVENT_DATA(GRIEDataMouseButton, GRIEDataMouse, InputType::_InputEventMouseButton); +INPUT_EVENT_DATA(GRIEDataMouseMotion, GRIEDataMouse, InputType::_InputEventMouseMotion); +INPUT_EVENT_DATA(GRIEDataScreenTouch, GRInputDataEvent, InputType::_InputEventScreenTouch); +INPUT_EVENT_DATA(GRIEDataScreenDrag, GRInputDataEvent, InputType::_InputEventScreenDrag); +INPUT_EVENT_DATA(GRIEDataMagnifyGesture, GRIEDataGesture, InputType::_InputEventMagnifyGesture); +INPUT_EVENT_DATA(GRIEDataPanGesture, GRIEDataGesture, InputType::_InputEventPanGesture); +INPUT_EVENT_DATA(GRIEDataJoypadButton, GRInputDataEvent, InputType::_InputEventJoypadButton); +INPUT_EVENT_DATA(GRIEDataJoypadMotion, GRInputDataEvent, InputType::_InputEventJoypadMotion); +INPUT_EVENT_DATA(GRIEDataAction, GRInputDataEvent, InputType::_InputEventAction); +INPUT_EVENT_DATA(GRIEDataMIDI, GRInputDataEvent, InputType::_InputEventMIDI); + +#undef INPUT_EVENT_DATA + +#ifndef GDNATIVE_LIBRARY +VARIANT_ENUM_CAST(GRInputData::InputType) +#endif diff --git a/modules/godot_remote/godot_remote/GRNotifications.cpp b/modules/godot_remote/godot_remote/GRNotifications.cpp new file mode 100644 index 0000000..d615eae --- /dev/null +++ b/modules/godot_remote/godot_remote/GRNotifications.cpp @@ -0,0 +1,1012 @@ +/* GRNotifications.cpp */ +#include "GRNotifications.h" +#include "GRResources.h" +#include "GRUtils.h" +#include "GodotRemote.h" + +#ifndef GDNATIVE_LIBRARY + +#define add_s_override add_style_override +#define set_b_icon set_icon + +#include "core/engine.h" +#include "core/os/input_event.h" +#include "scene/animation/tween.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/label.h" +#include "scene/gui/texture_rect.h" +#else + +#define add_s_override add_stylebox_override +#define set_b_icon set_button_icon + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace godot; +#endif + +using namespace GRUtils; + +GRNotifications *GRNotifications::singleton = nullptr; +GRNotificationPanelSTATIC_DATA *GRNotificationPanel::_default_data = nullptr; + +std::vector GRNotifications::_get_notifications_with_title(String title) { // GRNotificationPanel * + std::vector res; // GRNotificationPanel * + + if (singleton) { + for (int i = (int)singleton->notifications.size() - 1; i >= 0; i--) { + if (((GRNotificationPanel *)notifications[i])->get_title() == title) { + res.push_back(notifications[i]); + } + } + } + return res; +} + +GRNotificationPanel *GRNotifications::_get_notification(String title) { + for (int i = (int)singleton->notifications.size() - 1; i >= 0; i--) { + if (((GRNotificationPanel *)notifications[i])->get_title() == title) { + return notifications[i]; + } + } + return nullptr; +} + +void GRNotifications::_set_notifications_position(ENUM_ARG(NotificationsPosition) positon) { + NotificationsPosition pos = (NotificationsPosition)positon; + if (notif_list_node) { + switch (pos) { + case NotificationsPosition::TOP_LEFT: + case NotificationsPosition::TOP_CENTER: + case NotificationsPosition::TOP_RIGHT: + notif_list_node->set_v_grow_direction(Control::GROW_DIRECTION_END); + notif_list_node->set_alignment(BoxContainer::ALIGN_BEGIN); + break; + case NotificationsPosition::BOTTOM_LEFT: + case NotificationsPosition::BOTTOM_CENTER: + case NotificationsPosition::BOTTOM_RIGHT: + notif_list_node->set_v_grow_direction(Control::GROW_DIRECTION_BEGIN); + notif_list_node->set_alignment(BoxContainer::ALIGN_END); + break; + } + } + + _set_all_notifications_positions(pos); + notifications_position = pos; +} + +void GRNotifications::_add_notification_or_append_string(String title, String text, ENUM_ARG(NotificationIcon) icon, bool new_string, float duration_multiplier) { + if (!notifications_enabled) + return; + + auto *np = _get_notification(title); + if (np) { + np->update_text(np->get_text() + (new_string ? "\n" + text : text)); + } else { + _add_notification(title, text, icon, false, duration_multiplier); + } +} + +void GRNotifications::_add_notification_or_update_line(String title, String id, String text, ENUM_ARG(NotificationIcon) icon, float duration_multiplier) { + if (!notifications_enabled) + return; + + auto *np = cast_to(_get_notification(title)); + if (np) { + _log("Updating existing updatable notification with Title: \"" + title + "\" ID: \"" + id + "\" Text:\"" + text + "\"", LogLevel::LL_DEBUG); + np->set_updatable_line(this, title, id, text, (NotificationIcon)icon, duration_multiplier, style); + } else { + + np = memnew(GRNotificationPanelUpdatable); + notif_list_node->add_child(np); + if (notifications_position <= NotificationsPosition::TOP_RIGHT) + notif_list_node->move_child(np, 0); + notifications.push_back(np); + + _log("New updatable notification added with Title: \"" + title + "\"" + " and Text:\"" + text + "\"", LogLevel::LL_DEBUG); + emit_signal("notification_added", title, text); + + np->set_updatable_line(this, title, id, text, (NotificationIcon)icon, duration_multiplier, style); + + // FORCE UPDATE SIZE OF CONTEINER + notif_list_node->call("_size_changed"); + } +} + +void GRNotifications::_set_all_notifications_positions(NotificationsPosition pos) { + for (int i = (int)singleton->notifications.size() - 1; i >= 0; i--) { + GRNotificationPanel *np = notifications[i]; + if (np && !np->is_queued_for_deletion()) + np->set_notification_position((NotificationsPosition)pos); + } +} + +void GRNotifications::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_POSTINITIALIZE: +#ifndef GDNATIVE_LIBRARY + _init(); +#endif + break; + case NOTIFICATION_PREDELETE: + _deinit(); + break; + case NOTIFICATION_EXIT_TREE: { + GRNotificationPanel::clear_styles(); + break; + } + } +} + +#ifndef GDNATIVE_LIBRARY + +void GRNotifications::_bind_methods() { + ClassDB::bind_method(D_METHOD("_set_notifications_position", "pos"), &GRNotifications::_set_notifications_position); + ClassDB::bind_method(D_METHOD("_add_notification_or_append_string", "title", "text", "icon", "new_string", "duration_multiplier"), &GRNotifications::_add_notification_or_append_string); + ClassDB::bind_method(D_METHOD("_add_notification_or_update_line", "title", "id", "text", "icon", "duration_multiplier"), &GRNotifications::_add_notification_or_update_line); + ClassDB::bind_method(D_METHOD("_add_notification", "title", "text", "icon", "update_existing", "duration_multiplier"), &GRNotifications::_add_notification); + ClassDB::bind_method(D_METHOD("_remove_notification", "title", "is_all_entries"), &GRNotifications::_remove_notification); + ClassDB::bind_method(D_METHOD("_remove_exact_notification", "notification"), &GRNotifications::_remove_exact_notification); + ClassDB::bind_method(D_METHOD("_clear_notifications"), &GRNotifications::_clear_notifications); + + ClassDB::bind_method(D_METHOD("_remove_list"), &GRNotifications::_remove_list); + + ADD_SIGNAL(MethodInfo("notifications_toggled", PropertyInfo(Variant::BOOL, "is_enabled"))); + ADD_SIGNAL(MethodInfo("notifications_cleared")); + ADD_SIGNAL(MethodInfo("notification_added", PropertyInfo(Variant::STRING, "title"), PropertyInfo(Variant::STRING, "text"))); + ADD_SIGNAL(MethodInfo("notification_removed", PropertyInfo(Variant::STRING, "title"), PropertyInfo(Variant::BOOL, "is_cleared"))); + + BIND_ENUM_CONSTANT(ICON_NONE); + BIND_ENUM_CONSTANT(ICON_ERROR); + BIND_ENUM_CONSTANT(ICON_WARNING); + BIND_ENUM_CONSTANT(ICON_SUCCESS); + BIND_ENUM_CONSTANT(ICON_FAIL); + + BIND_ENUM_CONSTANT(TOP_LEFT); + BIND_ENUM_CONSTANT(TOP_CENTER); + BIND_ENUM_CONSTANT(TOP_RIGHT); + BIND_ENUM_CONSTANT(BOTTOM_LEFT); + BIND_ENUM_CONSTANT(BOTTOM_CENTER); + BIND_ENUM_CONSTANT(BOTTOM_RIGHT); +} + +#else + +void GRNotifications::_register_methods() { + METHOD_REG(GRNotifications, _notification); + + METHOD_REG(GRNotifications, _set_notifications_position); + METHOD_REG(GRNotifications, _add_notification_or_append_string); + METHOD_REG(GRNotifications, _add_notification_or_update_line); + METHOD_REG(GRNotifications, _add_notification); + METHOD_REG(GRNotifications, _remove_notification); + METHOD_REG(GRNotifications, _remove_exact_notification); + METHOD_REG(GRNotifications, _clear_notifications); + + METHOD_REG(GRNotifications, _remove_list); + + register_signal("notifications_toggled", "is_enabled", GODOT_VARIANT_TYPE_BOOL); + register_signal("notifications_cleared", Dictionary::make()); + register_signal("notification_added", "title", GODOT_VARIANT_TYPE_STRING, "text", GODOT_VARIANT_TYPE_STRING); + register_signal("notification_removed", "title", GODOT_VARIANT_TYPE_STRING, "is_cleared", GODOT_VARIANT_TYPE_BOOL); +} + +#endif + +GRNotificationPanel *GRNotifications::get_notification(String title) { + if (singleton) { + return singleton->_get_notification(title); + } + return nullptr; +} + +Array GRNotifications::get_all_notifications() { + Array arr; + if (singleton) { + for (int i = 0; i < singleton->notifications.size(); i++) { + arr.append(singleton->notifications[i]); + } + } + return arr; +} + +Array GRNotifications::get_notifications_with_title(String title) { + Array arr; + if (singleton) { + auto list = singleton->_get_notifications_with_title(title); + for (int i = 0; i < list.size(); i++) { + arr.append(list[i]); + } + } + return arr; +} + +GRNotifications::NotificationsPosition GRNotifications::get_notifications_position() { + if (singleton) { + return singleton->notifications_position; + } + return NotificationsPosition::TOP_CENTER; +} + +void GRNotifications::set_notifications_position(NotificationsPosition positon) { + if (singleton) { + singleton->call_deferred("_set_notifications_position", positon); + } +} + +bool GRNotifications::get_notifications_enabled() { + if (singleton) + return singleton->notifications_enabled; + return false; +} + +void GRNotifications::set_notifications_enabled(bool _enabled) { + if (singleton) { + singleton->notifications_enabled = _enabled; + singleton->emit_signal("notifications_toggled", _enabled); + if (!_enabled) { + clear_notifications(); + } + } +} + +float GRNotifications::get_notifications_duration() { + if (singleton) + return singleton->notifications_duration; + return 0.f; +} + +void GRNotifications::set_notifications_duration(float _duration) { + if (singleton) + singleton->notifications_duration = _duration; +} + +Ref GRNotifications::get_notifications_style() { + if (singleton) { + if (singleton->style.is_valid()) + return singleton->style; + return GRNotificationPanel::generate_default_style(); + } + return Ref(); +} + +void GRNotifications::set_notifications_style(Ref _style) { + if (singleton) { + singleton->style = _style; + } +} + +void GRNotifications::add_notification_or_append_string(String title, String text, NotificationIcon icon, bool new_string, float duration_multiplier) { + if (singleton) { + singleton->call_deferred("_add_notification_or_append_string", title, text, icon, new_string, duration_multiplier); + } +} + +void GRNotifications::add_notification_or_update_line(String title, String id, String text, NotificationIcon icon, float duration_multiplier) { + if (singleton) { + singleton->call_deferred("_add_notification_or_update_line", title, id, text, icon, duration_multiplier); + } +} + +void GRNotifications::add_notification(String title, String text, NotificationIcon icon, bool update_existing, float duration_multiplier) { + if (singleton) { + singleton->call_deferred("_add_notification", title, text, icon, update_existing, duration_multiplier); + } +} + +void GRNotifications::remove_notification(String title, bool all_entries) { + if (singleton) { + singleton->call_deferred("_remove_notification", title, all_entries); + } +} + +void GRNotifications::remove_notification_exact(Node *_notif) { + if (singleton) { + singleton->call_deferred("_remove_exact_notification", _notif); + } +} + +void GRNotifications::clear_notifications() { + if (singleton) { + singleton->call_deferred("_clear_notifications"); + } +} + +void GRNotifications::_add_notification(String title, String text, ENUM_ARG(NotificationIcon) icon, bool update_existing, float duration_multiplier) { + if (!notifications_enabled) + return; + + if (notif_list_node && !notif_list_node->is_queued_for_deletion()) { + GRNotificationPanel *np; + if (update_existing) { + np = _get_notification(title); + if (np) { + _log("Updating existing notification with Title: \"" + title + "\"" + " and Text:\"" + text + "\"", LogLevel::LL_DEBUG); + if (notifications_position <= NotificationsPosition::TOP_RIGHT) { + notif_list_node->move_child(np, 0); + } else { + notif_list_node->move_child(np, notif_list_node->get_child_count() - 1); + } + goto set_new_data; + } + } + + np = memnew(GRNotificationPanel); + notif_list_node->add_child(np); + if (notifications_position <= NotificationsPosition::TOP_RIGHT) + notif_list_node->move_child(np, 0); + notifications.push_back(np); + + _log("New notification added with Title: \"" + title + "\"" + " and Text:\"" + text + "\"", LogLevel::LL_DEBUG); + emit_signal("notification_added", title, text); + + set_new_data: + + np->set_data(this, title, text, (NotificationIcon)icon, duration_multiplier, style); + + // FORCE UPDATE SIZE OF CONTEINER + notif_list_node->call("_size_changed"); + } +} + +void GRNotifications::_remove_notification(String title, bool all_entries) { + if (all_entries) { + auto nps = _get_notifications_with_title(title); + for (int i = 0; i < nps.size(); i++) { + _remove_exact_notification(nps[i]); + } + } else { + _remove_exact_notification(_get_notification(title)); + } +} + +void GRNotifications::_remove_exact_notification(Node *_notif) { + GRNotificationPanel *np = cast_to(_notif); + if (np) { + emit_signal("notification_removed", np->get_text(), clearing_notifications); + + notif_list_node->remove_child(np); + vec_remove_idx(notifications, np); + memdelete(np); + + // FORCE UPDATE SIZE OF CONTEINER + notif_list_node->call("_size_changed"); + } +} + +void GRNotifications::_clear_notifications() { + clearing_notifications = true; + for (int i = 0; i < notifications.size(); i++) { + GRNotificationPanel *tmp = notifications[i]; + notif_list_node->remove_child(tmp); + vec_remove_idx(notifications, tmp); + memdelete(tmp); + } + emit_signal("notifications_cleared"); + clearing_notifications = false; +} + +GRNotifications *GRNotifications::get_singleton() { + return singleton; +} + +void GRNotifications::_init() { + set_name("Notifications"); + + LEAVE_IF_EDITOR(); + + if (!singleton) + singleton = this; + + GRNotificationPanel::_default_data = new GRNotificationPanelSTATIC_DATA(); + + notifications_enabled = GET_PS(GodotRemote::ps_notifications_enabled_name); + notifications_position = (NotificationsPosition)(int)GET_PS(GodotRemote::ps_noticications_position_name); + notifications_duration = GET_PS(GodotRemote::ps_notifications_duration_name); + + notif_list_node = memnew(VBoxContainer); + notif_list_node->set_name("NotificationList"); + call_deferred("add_child", notif_list_node); // add new function to check ST() and then add_child to prevent leak when generation mono glue + + notif_list_node->set_anchor_and_margin(MARGIN_LEFT, 0.f, 8.f); + notif_list_node->set_anchor_and_margin(MARGIN_RIGHT, 1.f, -8.f); + notif_list_node->set_anchor_and_margin(MARGIN_TOP, 0.f, 8.f); + notif_list_node->set_anchor_and_margin(MARGIN_BOTTOM, 1.f, -8.f); + notif_list_node->set_h_grow_direction(Control::GROW_DIRECTION_BOTH); + notif_list_node->set_mouse_filter(Control::MouseFilter::MOUSE_FILTER_IGNORE); + + set_notifications_position(notifications_position); +} + +void GRNotifications::_deinit() { + LEAVE_IF_EDITOR(); + + if (this == singleton) + singleton = nullptr; + call_deferred("_remove_list"); + + notifications.clear(); + GRNotificationPanel::_default_data->_default_close_texture.unref(); + GRNotificationPanel::_default_data->_default_style.unref(); + GRNotificationPanel::_default_data->_default_textures.clear(); + delete GRNotificationPanel::_default_data; + GRNotificationPanel::_default_data = nullptr; + + style.unref(); +} + +void GRNotifications::_remove_list() { + _clear_notifications(); + remove_child(notif_list_node); + memdelete(notif_list_node); + notif_list_node = nullptr; +} + +////////////////////////////////////////////////////////////////////////// +// NOTIFICATION PANEL +////////////////////////////////////////////////////////////////////////// + +void GRNotificationPanel::_panel_hovered() { + tween_node->stop_all(); + tween_node->reset_all(); + is_hovered = true; +} + +void GRNotificationPanel::_panel_lose_hover() { + _setup_tween(tween_node); + tween_node->start(); + is_hovered = false; +} + +void GRNotificationPanel::_remove_this_notification() { + if (owner && !owner->is_queued_for_deletion()) { + owner->remove_notification_exact(this); + } +} + +void GRNotificationPanel::_setup_tween(Tween *_tween) { + const float duration = owner->get_notifications_duration() * duration_mul; + _tween->remove_all(); + _tween->interpolate_property(this, NodePath("modulate"), Color(1, 1, 1, 1), Color(1, 1, 1, 0), duration, Tween::TRANS_QUART, Tween::EASE_IN); + _tween->interpolate_callback(this, duration, "_remove_this_notification", Variant(), Variant(), Variant(), Variant(), Variant()); +} + +void GRNotificationPanel::_update_style() { + Ref s = _default_data->_default_style; + if (style.is_valid()) + s = style; + + add_s_override("panel", s->get_panel_style()); + + title_node->add_font_override("font", s->get_title_font()); + text_node->add_font_override("font", s->get_text_font()); + + close_node->set_theme(s->get_close_button_theme()); + close_node->add_font_override("font", s->get_title_font()); + close_node->set_text(s->get_close_button_icon().is_null() ? "[x]" : ""); + close_node->set_b_icon(s->get_close_button_icon()); + + icon_tex_node->set_texture(s->get_notification_icon(notification_icon)); + icon_tex_node->set_visible(icon_tex_node->get_texture().is_valid()); +} + +Ref GRNotificationPanel::generate_default_style() { + Ref res_style(memnew(GRNotificationStyle)); + + Ref panel(memnew(StyleBoxFlat)); + panel->set_bg_color(Color(0.172549f, 0.188235f, 0.305882f, 0.300588f)); + panel->set_corner_detail(1); + panel->set_border_width_all(1); + panel->set_border_color(Color(0.482353f, 0.47451f, 0.52549f, 0.686275f)); + panel->set_shadow_color(Color(0, 0, 0, 0.254902f)); + panel->set_shadow_size(2); + panel->set_default_margin(MARGIN_BOTTOM, 4); + panel->set_default_margin(MARGIN_LEFT, 4); + panel->set_default_margin(MARGIN_RIGHT, 4); + panel->set_default_margin(MARGIN_TOP, 5); + res_style->set_panel_style(panel); + + Ref btn_nrm(memnew(StyleBoxEmpty)); + btn_nrm->set_default_margin(MARGIN_BOTTOM, 1); + btn_nrm->set_default_margin(MARGIN_LEFT, 1); + btn_nrm->set_default_margin(MARGIN_RIGHT, 1); + btn_nrm->set_default_margin(MARGIN_TOP, 1); + + Ref btn_prsd(memnew(StyleBoxEmpty)); + btn_prsd->set_default_margin(MARGIN_BOTTOM, 0); + btn_prsd->set_default_margin(MARGIN_LEFT, 1); + btn_prsd->set_default_margin(MARGIN_RIGHT, 1); + btn_prsd->set_default_margin(MARGIN_TOP, 2); + + Ref close_btn_theme(memnew(Theme)); + close_btn_theme->set_stylebox("hover", "Button", btn_nrm); + close_btn_theme->set_stylebox("normal", "Button", btn_nrm); + close_btn_theme->set_stylebox("pressed", "Button", btn_prsd); + res_style->set_close_button_theme(close_btn_theme); + +#ifndef NO_GODOTREMOTE_DEFAULT_RESOURCES +#define SetIcon(_i) res_style->set_notification_icon(_i, _default_data->_default_textures[(int)_i]) + + if (_default_data->_default_textures.empty() || _default_data->_default_close_texture.is_null()) + _load_default_textures(); + + res_style->set_close_button_icon(_default_data->_default_close_texture); + SetIcon(GRNotifications::NotificationIcon::ICON_ERROR); + SetIcon(GRNotifications::NotificationIcon::ICON_WARNING); + SetIcon(GRNotifications::NotificationIcon::ICON_SUCCESS); + SetIcon(GRNotifications::NotificationIcon::ICON_FAIL); + +#undef SetIcon +#endif + + return res_style; +} + +#ifndef NO_GODOTREMOTE_DEFAULT_RESOURCES +void GRNotificationPanel::_load_default_textures() { + +#define LoadTex(_i, _n) \ + { \ + img.instance(); \ + GetPoolVectorFromBin(tmp_arr, _n); \ + img->load_png_from_buffer(tmp_arr); \ + \ + tex.instance(); \ + tex->create_from_image(img); \ + _default_data->_default_textures[(int)_i] = tex; \ + } + + Ref img; + Ref tex; + + LoadTex(GRNotifications::NotificationIcon::ICON_ERROR, GRResources::Bin_ErrorIconPNG); + LoadTex(GRNotifications::NotificationIcon::ICON_WARNING, GRResources::Bin_WarningIconPNG); + LoadTex(GRNotifications::NotificationIcon::ICON_SUCCESS, GRResources::Bin_ConnectedIconPNG); + LoadTex(GRNotifications::NotificationIcon::ICON_FAIL, GRResources::Bin_DisconnectedIconPNG); + + { + img.instance(); + GetPoolVectorFromBin(tmp_arr, GRResources::Bin_CloseIconPNG); + img->load_png_from_buffer(tmp_arr); + + tex.instance(); + tex->create_from_image(img); + _default_data->_default_close_texture = tex; + } + +#undef LoadTex +} +#endif + +#ifndef GDNATIVE_LIBRARY + +void GRNotificationPanel::_bind_methods() { + ClassDB::bind_method(D_METHOD("_remove_this_notification"), &GRNotificationPanel::_remove_this_notification); + ClassDB::bind_method(D_METHOD("_panel_hovered"), &GRNotificationPanel::_panel_hovered); + ClassDB::bind_method(D_METHOD("_panel_lose_hover"), &GRNotificationPanel::_panel_lose_hover); + + ClassDB::bind_method(D_METHOD("get_title"), &GRNotificationPanel::get_title); + ClassDB::bind_method(D_METHOD("get_text"), &GRNotificationPanel::get_text); + ClassDB::bind_method(D_METHOD("update_text", "text"), &GRNotificationPanel::update_text); +} + +#else + +void GRNotificationPanel::_register_methods() { + METHOD_REG(GRNotificationPanel, _notification); + + METHOD_REG(GRNotificationPanel, _remove_this_notification); + METHOD_REG(GRNotificationPanel, _panel_hovered); + METHOD_REG(GRNotificationPanel, _panel_lose_hover); + + METHOD_REG(GRNotificationPanel, get_title); + METHOD_REG(GRNotificationPanel, get_text); + METHOD_REG(GRNotificationPanel, update_text); +} + +#endif + +void GRNotificationPanel::_notification(int p_notification) { + switch (p_notification) { + case NOTIFICATION_POSTINITIALIZE: +#ifndef GDNATIVE_LIBRARY + _init(); +#endif + break; + case NOTIFICATION_PREDELETE: + _deinit(); + break; + } +} + +void GRNotificationPanel::clear_styles() { + if (_default_data) { + _default_data->_default_style.unref(); +#ifndef NO_GODOTREMOTE_DEFAULT_RESOURCES + _default_data->_default_close_texture.unref(); + _default_data->_default_textures.clear(); +#endif + } +} + +void GRNotificationPanel::set_notification_position(GRNotifications::NotificationsPosition position) { + switch (position) { + case GRNotifications::NotificationsPosition::TOP_LEFT: + case GRNotifications::NotificationsPosition::BOTTOM_LEFT: + set_h_size_flags(0); + break; + case GRNotifications::NotificationsPosition::TOP_RIGHT: + case GRNotifications::NotificationsPosition::BOTTOM_RIGHT: + set_h_size_flags(SIZE_SHRINK_END); + break; + case GRNotifications::NotificationsPosition::TOP_CENTER: + case GRNotifications::NotificationsPosition::BOTTOM_CENTER: + set_h_size_flags(SIZE_SHRINK_CENTER); + break; + } +} + +void GRNotificationPanel::set_data(GRNotifications *_owner, String title, String text, GRNotifications::NotificationIcon icon, float duration_multiplier, Ref _style) { + owner = _owner; + notification_icon = icon; + title_node->set_text(title); + text_node->set_text(text); + duration_mul = duration_multiplier; + style = _style; + + _update_style(); + _setup_tween(tween_node); + tween_node->start(); + + if (owner) { + set_notification_position((GRNotifications::NotificationsPosition)owner->get_notifications_position()); + } +} + +String GRNotificationPanel::get_title() { + return title_node->get_text(); +} + +String GRNotificationPanel::get_text() { + return text_node->get_text(); +} + +void GRNotificationPanel::update_text(String text) { + text_node->set_text(text); + _setup_tween(tween_node); + + if (!is_hovered) + tween_node->start(); +} + +void GRNotificationPanel::_init() { + set_name("NotificationPanel"); + + LEAVE_IF_EDITOR(); + + if (_default_data && _default_data->_default_style.is_null()) + _default_data->_default_style = generate_default_style(); + + set_mouse_filter(Control::MouseFilter::MOUSE_FILTER_PASS); + connect("mouse_entered", this, "_panel_hovered"); + connect("mouse_exited", this, "_panel_lose_hover"); + + vbox_node = memnew(VBoxContainer); + hbox_node = memnew(HBoxContainer); + icon_tex_node = memnew(TextureRect); + title_node = memnew(Label); + text_node = memnew(Label); + close_node = memnew(Button); + tween_node = memnew(Tween); + + add_child(vbox_node); + add_child(tween_node); + vbox_node->add_child(hbox_node); + vbox_node->add_child(text_node); + hbox_node->add_child(icon_tex_node); + hbox_node->add_child(title_node); + hbox_node->add_child(close_node); + + vbox_node->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); + vbox_node->set_h_grow_direction(Control::GROW_DIRECTION_BOTH); + vbox_node->set_v_grow_direction(Control::GROW_DIRECTION_BOTH); + + hbox_node->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); + hbox_node->set_h_grow_direction(Control::GROW_DIRECTION_BOTH); + hbox_node->set_v_grow_direction(Control::GROW_DIRECTION_BOTH); + + icon_tex_node->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); + icon_tex_node->set_h_size_flags(SIZE_FILL); + icon_tex_node->set_h_grow_direction(Control::GROW_DIRECTION_BOTH); + icon_tex_node->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED); + + title_node->set_h_size_flags(SIZE_EXPAND_FILL); + title_node->set_h_grow_direction(Control::GROW_DIRECTION_BOTH); + title_node->set_v_size_flags(SIZE_FILL); + title_node->set_align(Label::ALIGN_CENTER); + title_node->set_valign(Label::VALIGN_CENTER); + title_node->set_text("UNTITLED"); + + text_node->set_h_grow_direction(Control::GROW_DIRECTION_BOTH); + text_node->set_custom_minimum_size(Size2(128, 0)); + text_node->set_align(Label::ALIGN_CENTER); + text_node->set_text("EMPTY TEXT"); + + close_node->set_focus_mode(Control::FOCUS_NONE); + close_node->connect("pressed", this, "_remove_this_notification"); + + //_setup_tween(tween_node); + //_update_style(); +} + +void GRNotificationPanel::_deinit() { + LEAVE_IF_EDITOR(); + + if (style.is_valid()) + style.unref(); +} + +////////////////////////////////////////////////////////////////////////// +// UPDATABLE NOTIFICATION PANEL +////////////////////////////////////////////////////////////////////////// + +void GRNotificationPanelUpdatable::_init() { + LEAVE_IF_EDITOR(); +#ifndef GDNATIVE_LIBRARY +#else + GRNotificationPanel::_init(); +#endif +} + +void GRNotificationPanelUpdatable::_deinit() { + LEAVE_IF_EDITOR(); +} + +String GRNotificationPanelUpdatable::_get_text_from_lines() { + String res = ""; + int i = 0; + for (auto lv : lines) { + res += str(lv.second); + if (i < lines.size() - 1) { + res += "\n"; + } + i++; + } + return res; +} + +#ifndef GDNATIVE_LIBRARY +void GRNotificationPanelUpdatable::_bind_methods() { + ClassDB::bind_method(D_METHOD("clear_lines"), &GRNotificationPanelUpdatable::clear_lines); + ClassDB::bind_method(D_METHOD("remove_updatable_line", "id"), &GRNotificationPanelUpdatable::remove_updatable_line); +} + +#else + +void GRNotificationPanelUpdatable::_register_methods() { + METHOD_REG(GRNotificationPanelUpdatable, _notification); + + METHOD_REG(GRNotificationPanelUpdatable, clear_lines); + METHOD_REG(GRNotificationPanelUpdatable, remove_updatable_line); +} + +#endif + +void GRNotificationPanelUpdatable::_notification(int p_notification) { + switch (p_notification) { + case NOTIFICATION_POSTINITIALIZE: +#ifndef GDNATIVE_LIBRARY + _init(); +#endif + break; + case NOTIFICATION_PREDELETE: + _deinit(); + GRNotificationPanel::_deinit(); + break; + } +} + +void GRNotificationPanelUpdatable::set_updatable_line(GRNotifications *_owner, String title, String id, String text, GRNotifications::NotificationIcon icon, float duration_multiplier, Ref _style) { + if (configured) { + lines[id] = text; + text_node->set_text(_get_text_from_lines()); + + _setup_tween(tween_node); + if (!is_hovered) { + tween_node->start(); + } + } else { + owner = _owner; + notification_icon = icon; + lines[id] = text; + title_node->set_text(title); + text_node->set_text(_get_text_from_lines()); + duration_mul = duration_multiplier; + style = _style; + + _update_style(); + _setup_tween(tween_node); + tween_node->start(); + + if (owner) { + set_notification_position((GRNotifications::NotificationsPosition)owner->get_notifications_position()); + } + } +} + +void GRNotificationPanelUpdatable::remove_updatable_line(String id) { + if (lines.find(id) != lines.end()) { + lines.erase(id); + text_node->set_text(_get_text_from_lines()); + + _setup_tween(tween_node); + if (!is_hovered) { + tween_node->start(); + } + } +} + +void GRNotificationPanelUpdatable::clear_lines() { + lines.clear(); + text_node->set_text(_get_text_from_lines()); + + _setup_tween(tween_node); + if (!is_hovered) { + tween_node->start(); + } +} + +// STYLE REF + +#ifndef GDNATIVE_LIBRARY +void GRNotificationStyle::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_notification_icon", "notification_icon", "icon_texture"), &GRNotificationStyle::set_notification_icon); + ClassDB::bind_method(D_METHOD("get_notification_icon", "notification_icon"), &GRNotificationStyle::get_notification_icon); + + ClassDB::bind_method(D_METHOD("set_panel_style", "style"), &GRNotificationStyle::set_panel_style); + ClassDB::bind_method(D_METHOD("set_close_button_theme", "theme"), &GRNotificationStyle::set_close_button_theme); + ClassDB::bind_method(D_METHOD("set_close_button_icon", "icon"), &GRNotificationStyle::set_close_button_icon); + ClassDB::bind_method(D_METHOD("set_title_font", "font"), &GRNotificationStyle::set_title_font); + ClassDB::bind_method(D_METHOD("set_text_font", "font"), &GRNotificationStyle::set_text_font); + + ClassDB::bind_method(D_METHOD("get_panel_style"), &GRNotificationStyle::get_panel_style); + ClassDB::bind_method(D_METHOD("get_close_button_theme"), &GRNotificationStyle::get_close_button_theme); + ClassDB::bind_method(D_METHOD("get_close_button_icon"), &GRNotificationStyle::get_close_button_icon); + ClassDB::bind_method(D_METHOD("get_title_font"), &GRNotificationStyle::get_title_font); + ClassDB::bind_method(D_METHOD("get_text_font"), &GRNotificationStyle::get_text_font); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "panel_style"), "set_panel_style", "get_panel_style"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "close_button_theme"), "set_close_button_theme", "get_close_button_theme"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "close_button_icon"), "set_close_button_icon", "get_close_button_icon"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "title_font"), "set_title_font", "get_title_font"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "text_font"), "set_text_font", "get_text_font"); +} + +#else + +void GRNotificationStyle::_register_methods() { + METHOD_REG(GRNotificationStyle, _notification); + + METHOD_REG(GRNotificationStyle, set_notification_icon); + METHOD_REG(GRNotificationStyle, get_notification_icon); + + METHOD_REG(GRNotificationStyle, set_panel_style); + METHOD_REG(GRNotificationStyle, set_close_button_theme); + METHOD_REG(GRNotificationStyle, set_close_button_icon); + METHOD_REG(GRNotificationStyle, set_title_font); + METHOD_REG(GRNotificationStyle, set_text_font); + + METHOD_REG(GRNotificationStyle, get_panel_style); + METHOD_REG(GRNotificationStyle, get_close_button_theme); + METHOD_REG(GRNotificationStyle, get_close_button_icon); + METHOD_REG(GRNotificationStyle, get_title_font); + METHOD_REG(GRNotificationStyle, get_text_font); + + register_property >("panel_style", &GRNotificationStyle::set_panel_style, &GRNotificationStyle::get_panel_style, nullptr); + register_property >("close_button_theme", &GRNotificationStyle::set_close_button_theme, &GRNotificationStyle::get_close_button_theme, nullptr); + register_property >("close_button_icon", &GRNotificationStyle::set_close_button_icon, &GRNotificationStyle::get_close_button_icon, nullptr); + register_property >("title_font", &GRNotificationStyle::set_title_font, &GRNotificationStyle::get_title_font, nullptr); + register_property >("text_font", &GRNotificationStyle::set_text_font, &GRNotificationStyle::get_text_font, nullptr); +} + +#endif + +void GRNotificationStyle::_notification(int p_notification) { + switch (p_notification) { + case NOTIFICATION_POSTINITIALIZE: +#ifndef GDNATIVE_LIBRARY + _init(); +#endif + break; + case NOTIFICATION_PREDELETE: + _deinit(); + break; + } +} + +void GRNotificationStyle::_init() { + LEAVE_IF_EDITOR(); + + for (int i = 0; i < GRNotifications::NotificationIcon::ICON_MAX; i++) { + n_icons[i] = Ref(); + } +} + +void GRNotificationStyle::_deinit() { + LEAVE_IF_EDITOR(); + + panel_style.unref(); + close_button_theme.unref(); + close_button_icon.unref(); + title_font.unref(); + text_font.unref(); + + for (int i = 0; i < GRNotifications::NotificationIcon::ICON_MAX; i++) { + n_icons[i].unref(); + } +} + +void GRNotificationStyle::set_panel_style(Ref style) { + panel_style = style; +} + +Ref GRNotificationStyle::get_panel_style() { + return panel_style; +} + +void GRNotificationStyle::set_close_button_theme(Ref theme) { + close_button_theme = theme; +} + +Ref GRNotificationStyle::get_close_button_theme() { + return close_button_theme; +} + +void GRNotificationStyle::set_close_button_icon(Ref icon) { + close_button_icon = icon; +} + +Ref GRNotificationStyle::get_close_button_icon() { + return close_button_icon; +} + +void GRNotificationStyle::set_title_font(Ref font) { + title_font = font; +} + +Ref GRNotificationStyle::get_title_font() { + return title_font; +} + +void GRNotificationStyle::set_text_font(Ref font) { + text_font = font; +} + +Ref GRNotificationStyle::get_text_font() { + return text_font; +} + +void GRNotificationStyle::set_notification_icon(ENUM_ARG(GRNotifications::NotificationIcon) notification_icon, Ref icon_texture) { + ERR_FAIL_INDEX(notification_icon, (int)GRNotifications::NotificationIcon::ICON_MAX); + n_icons[notification_icon] = icon_texture; +} + +Ref GRNotificationStyle::get_notification_icon(ENUM_ARG(GRNotifications::NotificationIcon) notification_icon) { + return n_icons[notification_icon]; +} diff --git a/modules/godot_remote/godot_remote/GRNotifications.h b/modules/godot_remote/godot_remote/GRNotifications.h new file mode 100644 index 0000000..8f80ff9 --- /dev/null +++ b/modules/godot_remote/godot_remote/GRNotifications.h @@ -0,0 +1,287 @@ +/* GRNotifications.h */ +#pragma once + +#include "GRUtils.h" + +#ifndef GDNATIVE_LIBRARY +#include "core/reference.h" +#include "scene/gui/panel_container.h" +#include "scene/main/canvas_layer.h" +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace godot; +#endif + +class GRNotificationPanel; +class GRNotificationStyle; +class GRNotificationPanelSTATIC_DATA; + +class GRNotifications : public CanvasLayer { + GD_CLASS(GRNotifications, CanvasLayer); + + friend class GRNotificationPanel; + +public: + enum NotificationIcon : int { + ICON_NONE, + ICON_ERROR, + ICON_WARNING, + ICON_SUCCESS, + ICON_FAIL, + + ICON_MAX, + }; + + enum NotificationsPosition : int { + TOP_LEFT = 0, + TOP_CENTER = 1, + TOP_RIGHT = 2, + BOTTOM_LEFT = 3, + BOTTOM_CENTER = 4, + BOTTOM_RIGHT = 5, + }; + +private: + static GRNotifications *singleton; + + bool clearing_notifications = false; + + float notifications_duration = 2.0; + bool notifications_enabled = true; + NotificationsPosition notifications_position = NotificationsPosition::TOP_LEFT; + + class VBoxContainer *notif_list_node = nullptr; + std::vector notifications; // GRNotificationPanel * + Ref style; + + std::vector _get_notifications_with_title(String title); // GRNotificationPanel * + GRNotificationPanel *_get_notification(String title); + + void _set_all_notifications_positions(NotificationsPosition pos); + + void _set_notifications_position(ENUM_ARG(NotificationsPosition) positon); + void _add_notification_or_append_string(String title, String text, ENUM_ARG(NotificationIcon) icon, bool new_string, float duration_multiplier); + void _add_notification_or_update_line(String title, String id, String text, ENUM_ARG(NotificationIcon) icon, float duration_multiplier); + void _add_notification(String title, String text, ENUM_ARG(NotificationIcon) icon, bool update_existing, float duration_multiplier); + void _remove_notification(String title, bool all_entries); + void _remove_exact_notification(Node *_notif); + void _clear_notifications(); + + void _remove_list(); + +protected: +#ifndef GDNATIVE_LIBRARY + static void _bind_methods(); +#else +public: + static void _register_methods(); + +protected: +#endif + + void _notification(int p_what); + +public: + /// All functions below need to be called after init notification manager + /// For example call this after yield(get_tree(), "idle_frame") + + static GRNotificationPanel *get_notification(String title); + static Array get_all_notifications(); + static Array get_notifications_with_title(String title); + + static NotificationsPosition get_notifications_position(); + static void set_notifications_position(NotificationsPosition positon); + static bool get_notifications_enabled(); + static void set_notifications_enabled(bool _enabled); + static float get_notifications_duration(); + static void set_notifications_duration(float _duration); + static Ref get_notifications_style(); + static void set_notifications_style(Ref _style); + + // append text to existing notification or add new notification + static void add_notification_or_append_string(String title, String text, NotificationIcon icon = NotificationIcon::ICON_NONE, bool new_string = true, float duration_multiplier = 1.f); + + // update text in existing notification or add new notification + static void add_notification_or_update_line(String title, String id, String text, NotificationIcon icon = NotificationIcon::ICON_NONE, float duration_multiplier = 1.); + + static void add_notification(String title, String text, NotificationIcon icon DEF_ARG(= NotificationIcon::ICON_NONE), bool update_existing = true, float duration_multiplier = 1.f); + static void remove_notification(String title, bool all_entries = true); + static void remove_notification_exact(Node *_notif); + static void clear_notifications(); + static GRNotifications *get_singleton(); + + void _init(); + void _deinit(); +}; + +// Stupid class to bypass GDNative limitations +// but also it can be changed back by changing default-style generating +class GRNotificationPanelSTATIC_DATA { +public: + Ref _default_style; +#ifndef NO_GODOTREMOTE_DEFAULT_RESOURCES + Dictionary _default_textures; + Ref _default_close_texture; +#endif +}; + +class GRNotificationPanel : public PanelContainer { + GD_CLASS(GRNotificationPanel, PanelContainer); + + friend GRNotifications; + +protected: + GRNotifications *owner = nullptr; + + GRNotifications::NotificationIcon notification_icon = GRNotifications::NotificationIcon::ICON_NONE; + float duration_mul = 1.f; + bool is_hovered = false; + Ref style; + + static GRNotificationPanelSTATIC_DATA *_default_data; + + class VBoxContainer *vbox_node = nullptr; + class HBoxContainer *hbox_node = nullptr; + class TextureRect *icon_tex_node = nullptr; + class Label *title_node = nullptr; + class Label *text_node = nullptr; + class Button *close_node = nullptr; + class Tween *tween_node = nullptr; + + void _panel_hovered(); + void _panel_lose_hover(); + void _remove_this_notification(); + void _setup_tween(Tween *_tween); + void _update_style(); + + static Ref generate_default_style(); +#ifndef NO_GODOTREMOTE_DEFAULT_RESOURCES + static void _load_default_textures(); +#endif + +protected: +#ifndef GDNATIVE_LIBRARY + static void _bind_methods(); +#else +public: + static void _register_methods(); + +protected: +#endif + + void _notification(int p_notification); + +public: + static void clear_styles(); + + void set_notification_position(GRNotifications::NotificationsPosition position); + virtual void set_data(GRNotifications *_owner, String title, String text, GRNotifications::NotificationIcon icon, float duration_multiplier DEF_ARG(= 1.f), Ref _style DEF_ARG(= Ref())); + String get_title(); + String get_text(); + void update_text(String text); + + void _init(); + void _deinit(); +}; + +class GRNotificationPanelUpdatable : public GRNotificationPanel { + GD_S_CLASS(GRNotificationPanelUpdatable, GRNotificationPanel); + + friend GRNotifications; + +protected: + std::map lines; + String _get_text_from_lines(); + bool configured = false; + +#ifndef GDNATIVE_LIBRARY + static void _bind_methods(); +#else +public: + static void _register_methods(); + +protected: +#endif + + void _notification(int p_notification); + +public: + void set_updatable_line(GRNotifications *_owner, String title, String id, String text, GRNotifications::NotificationIcon icon, float duration_multiplier DEF_ARG(= 1.f), Ref _style DEF_ARG(= Ref())); + void remove_updatable_line(String id); + void clear_lines(); + + void _init(); + void _deinit(); +}; + +// STYLE REF + +class GRNotificationStyle : public Reference { + GD_CLASS(GRNotificationStyle, Reference); + +private: + Ref panel_style; + Ref close_button_theme; + Ref close_button_icon; + Ref title_font; + Ref text_font; + Ref n_icons[GRNotifications::NotificationIcon::ICON_MAX]; + +protected: +#ifndef GDNATIVE_LIBRARY + static void _bind_methods(); +#else +public: + static void _register_methods(); + +protected: +#endif + + void _notification(int p_notification); + +public: + void set_panel_style(Ref style); + Ref get_panel_style(); + + void set_close_button_theme(Ref theme); + Ref get_close_button_theme(); + + void set_close_button_icon(Ref icon); + Ref get_close_button_icon(); + + void set_title_font(Ref font); + Ref get_title_font(); + + void set_text_font(Ref font); + Ref get_text_font(); + + void set_notification_icon(ENUM_ARG(GRNotifications::NotificationIcon) notification_icon, Ref icon_texture); + Ref get_notification_icon(ENUM_ARG(GRNotifications::NotificationIcon) notification_icon); + + void _init(); + void _deinit(); +}; + +#ifndef GDNATIVE_LIBRARY +VARIANT_ENUM_CAST(GRNotifications::NotificationsPosition) +VARIANT_ENUM_CAST(GRNotifications::NotificationIcon) +#endif diff --git a/modules/godot_remote/godot_remote/GRPacket.cpp b/modules/godot_remote/godot_remote/GRPacket.cpp new file mode 100644 index 0000000..7f6edf5 --- /dev/null +++ b/modules/godot_remote/godot_remote/GRPacket.cpp @@ -0,0 +1,428 @@ +/* GRPacket.cpp */ +#include "GRPacket.h" + +#ifndef GDNATIVE_LIBRARY + +#include "core/os/os.h" +#else + +using namespace godot; +#endif + +using namespace GRUtils; + +Ref GRPacket::create(const PoolByteArray &bytes) { + if (bytes.size() == 0) { + ERR_FAIL_V_MSG(Ref(), "Can't create GRPacket from empty data!"); + } + + PacketType type = (PacketType)((PoolByteArray)bytes)[0]; + Ref buf(memnew(StreamPeerBuffer)); + buf->set_data_array(bytes); + +#define CREATE(type) \ + { \ + Ref packet(memnew(type)); \ + if (packet->_create(buf)) { \ + return packet; \ + } else { \ + return Ref(); \ + } \ + } + + switch (type) { + case PacketType::NonePacket: + ERR_FAIL_V_MSG(Ref(), "Can't create abstract GRPacket!"); + case PacketType::SyncTime: + CREATE(GRPacketSyncTime); + case PacketType::ImageData: + CREATE(GRPacketImageData); + case PacketType::InputData: + CREATE(GRPacketInputData); + case PacketType::ServerSettings: + CREATE(GRPacketServerSettings); + case PacketType::MouseModeSync: + CREATE(GRPacketMouseModeSync); + case PacketType::CustomInputScene: + CREATE(GRPacketCustomInputScene); + case PacketType::ClientStreamOrientation: + CREATE(GRPacketClientStreamOrientation); + case PacketType::ClientStreamAspect: + CREATE(GRPacketClientStreamAspect); + case PacketType::CustomUserData: + CREATE(GRPacketCustomUserData); + + // Requests + case PacketType::Ping: + CREATE(GRPacketPing); + + // Responses + case PacketType::Pong: + CREATE(GRPacketPong); + default: + ERR_FAIL_V_MSG(Ref(), "Can't create unknown GRPacket! Type: " + str((int)type)); + } +#undef CREATE + return Ref(); +} + +////////////////////////////////////////////////////////////////////////// +// SYNC TIME + +Ref GRPacketSyncTime::_get_data() { + auto buf = GRPacket::_get_data(); + buf->put_var(OS::get_singleton()->get_ticks_usec()); + return buf; +} + +bool GRPacketSyncTime::_create(Ref buf) { + GRPacket::_create(buf); + time = buf->get_var(); + return true; +} + +uint64_t GRPacketSyncTime::get_time() { + return time; +} + +////////////////////////////////////////////////////////////////////////// +// IMAGE DATA +Ref GRPacketImageData::_get_data() { + auto buf = GRPacket::_get_data(); + buf->put_8(is_empty); + buf->put_32((int)compression); + buf->put_var(size); + buf->put_var(format); + buf->put_var(img_data); + buf->put_var(start_time); + buf->put_var(frametime); + return buf; +} + +bool GRPacketImageData::_create(Ref buf) { + GRPacket::_create(buf); + is_empty = (bool)buf->get_8(); + compression = (int)buf->get_32(); + size = buf->get_var(); + format = buf->get_var(); + img_data = buf->get_var(); + start_time = buf->get_var(); + frametime = buf->get_var(); + return true; +} + +PoolByteArray GRPacketImageData::get_image_data() { + return img_data; +} + +int GRPacketImageData::get_compression_type() { + return (int)compression; +} + +uint64_t GRPacketImageData::get_start_time() { + return start_time; +} + +uint64_t GRPacketImageData::get_frametime() { + return frametime; +} + +bool GRPacketImageData::get_is_empty() { + return is_empty; +} + +Size2 GRPacketImageData::get_size() { + return size; +} + +int GRPacketImageData::get_format() { + return format; +} + +void GRPacketImageData::set_compression_type(int type) { + compression = type; +} + +void GRPacketImageData::set_start_time(uint64_t time) { + start_time = time; +} + +void GRPacketImageData::set_image_data(PoolByteArray &buf) { + img_data = buf; +} + +void GRPacketImageData::set_frametime(uint64_t _frametime) { + frametime = _frametime; +} + +void GRPacketImageData::set_is_empty(bool _empty) { + is_empty = _empty; +} + +void GRPacketImageData::set_size(Size2 _size) { + size = _size; +} + +void GRPacketImageData::set_format(int _format) { + format = _format; +} + +////////////////////////////////////////////////////////////////////////// +// INPUT DATA +Ref GRPacketInputData::_get_data() { + auto buf = GRPacket::_get_data(); + int count = 0; + + for (int i = 0; i < (int)inputs.size(); i++) { + Ref inp = inputs[i]; + if (inp.is_valid()) { + count++; + } else { + //inputs.remove(i); + inputs.erase(inputs.begin() + i); + i--; + } + } + buf->put_32(count); + + for (int i = 0; i < (int)inputs.size(); i++) { + buf->put_var(((Ref)inputs[i])->get_data()); + } + return buf; +} + +bool GRPacketInputData::_create(Ref buf) { + GRPacket::_create(buf); + int size = (int)buf->get_32(); // get size + for (int i = 0; i < size; i++) { + Ref id = GRInputData::create(buf->get_var()); + if (id.is_null()) + return false; + inputs.push_back(id); + } + return true; +} + +int GRPacketInputData::get_inputs_count() { + return (int)inputs.size(); +} + +Ref GRPacketInputData::get_input_data(int idx) { + ERR_FAIL_INDEX_V(idx, (int)inputs.size(), Ref()); + return inputs[idx]; +} + +void GRPacketInputData::remove_input_data(int idx) { + ERR_FAIL_INDEX(idx, (int)inputs.size()); + + //inputs.remove(idx); + inputs.erase(inputs.begin() + idx); +} + +void GRPacketInputData::add_input_data(Ref &input) { + inputs.push_back(input); +} + +void GRPacketInputData::set_input_data(std::vector > &_inputs) { + inputs = _inputs; +} + +////////////////////////////////////////////////////////////////////////// +// SERVER SETTINGS +Ref GRPacketServerSettings::_get_data() { + auto buf = GRPacket::_get_data(); + buf->put_var(map_to_dict(settings)); + return buf; +} + +bool GRPacketServerSettings::_create(Ref buf) { + GRPacket::_create(buf); + settings = dict_to_map(buf->get_var()); + return true; +} + +std::map GRPacketServerSettings::get_settings() { + return settings; +} + +void GRPacketServerSettings::set_settings(std::map &_settings) { + settings = _settings; +} + +void GRPacketServerSettings::add_setting(int _setting, Variant value) { + settings[_setting] = value; +} + +////////////////////////////////////////////////////////////////////////// +// MOUSE MODE SYNC + +Ref GRPacketMouseModeSync::_get_data() { + auto buf = GRPacket::_get_data(); + buf->put_8(mouse_mode); + return buf; +} + +bool GRPacketMouseModeSync::_create(Ref buf) { + GRPacket::_create(buf); + mouse_mode = (Input::MouseMode)buf->get_8(); + return true; +} +Input::MouseMode GRPacketMouseModeSync::get_mouse_mode() { + return mouse_mode; +} + +void GRPacketMouseModeSync::set_mouse_mode(Input::MouseMode _mode) { + mouse_mode = _mode; +} + +////////////////////////////////////////////////////////////////////////// +// CUSTOM INPUT SCENE + +Ref GRPacketCustomInputScene::_get_data() { + auto buf = GRPacket::_get_data(); + buf->put_string(scene_path); + buf->put_8(compressed); + buf->put_8(compression_type); + buf->put_32(original_data_size); + buf->put_var(scene_data); + return buf; +} + +bool GRPacketCustomInputScene::_create(Ref buf) { + GRPacket::_create(buf); + scene_path = buf->get_string(); + compressed = buf->get_8(); + compression_type = (uint8_t)buf->get_8(); + original_data_size = (int)buf->get_32(); + scene_data = buf->get_var(); + return true; +} + +String GRPacketCustomInputScene::get_scene_path() { + return scene_path; +} + +void GRPacketCustomInputScene::set_scene_path(String _path) { + scene_path = _path; +} + +PoolByteArray GRPacketCustomInputScene::get_scene_data() { + return scene_data; +} + +void GRPacketCustomInputScene::set_scene_data(PoolByteArray _data) { + scene_data = _data; +} + +bool GRPacketCustomInputScene::is_compressed() { + return compressed; +} + +void GRPacketCustomInputScene::set_compressed(bool val) { + compressed = val; +} + +int GRPacketCustomInputScene::get_original_size() { + return original_data_size; +} + +void GRPacketCustomInputScene::set_original_size(int val) { + original_data_size = val; +} + +int GRPacketCustomInputScene::get_compression_type() { + return compression_type; +} + +void GRPacketCustomInputScene::set_compression_type(int val) { + compression_type = val; +} + +////////////////////////////////////////////////////////////////////////// +// CLIENT DEVICE ROTATION + +Ref GRPacketClientStreamOrientation::_get_data() { + auto buf = GRPacket::_get_data(); + buf->put_8(vertical); + return buf; +} + +bool GRPacketClientStreamOrientation::_create(Ref buf) { + GRPacket::_create(buf); + vertical = buf->get_8(); + return true; +} + +bool GRPacketClientStreamOrientation::is_vertical() { + return vertical; +} + +void GRPacketClientStreamOrientation::set_vertical(bool val) { + vertical = val; +} + +////////////////////////////////////////////////////////////////////////// +// CLIENT SCREEN ASCPECT + +Ref GRPacketClientStreamAspect::_get_data() { + auto buf = GRPacket::_get_data(); + buf->put_float(stream_aspect); + return buf; +} + +bool GRPacketClientStreamAspect::_create(Ref buf) { + GRPacket::_create(buf); + stream_aspect = buf->get_float(); + return true; +} + +float GRPacketClientStreamAspect::get_aspect() { + return stream_aspect; +} + +void GRPacketClientStreamAspect::set_aspect(float val) { + stream_aspect = val; +} + +////////////////////////////////////////////////////////////////////////// +// CUSTOM USER DATA + +Ref GRPacketCustomUserData::_get_data() { + auto buf = GRPacket::_get_data(); + buf->put_string(packet_id); + buf->put_8(full_objects); + buf->put_var(user_data, full_objects); + return buf; +} + +bool GRPacketCustomUserData::_create(Ref buf) { + GRPacket::_create(buf); + packet_id = buf->get_string(); + full_objects = buf->get_8(); + user_data = buf->get_var(full_objects); + return true; +} + +Variant GRPacketCustomUserData::get_packet_id() { + return packet_id; +} + +void GRPacketCustomUserData::set_packet_id(Variant val) { + packet_id = val; +} + +bool GRPacketCustomUserData::get_send_full_objects() { + return full_objects; +} + +void GRPacketCustomUserData::set_send_full_objects(bool val) { + full_objects = val; +} + +Variant GRPacketCustomUserData::get_user_data() { + return user_data; +} + +void GRPacketCustomUserData::set_user_data(Variant val) { + user_data = val; +} diff --git a/modules/godot_remote/godot_remote/GRPacket.h b/modules/godot_remote/godot_remote/GRPacket.h new file mode 100644 index 0000000..334eec1 --- /dev/null +++ b/modules/godot_remote/godot_remote/GRPacket.h @@ -0,0 +1,358 @@ +/* GRPacket.h */ +#pragma once + +#include "GRInputData.h" +#include "GRUtils.h" + +#ifndef GDNATIVE_LIBRARY + +#include "core/io/stream_peer.h" +#include "core/reference.h" +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +class GRPacket : public Reference { + GD_CLASS(GRPacket, Reference); + +public: + enum PacketType : int { + NonePacket = 0, + SyncTime = 1, + ImageData = 2, + InputData = 3, + ServerSettings = 4, + MouseModeSync = 5, + CustomInputScene = 6, + ClientStreamOrientation = 7, + ClientStreamAspect = 8, + CustomUserData = 9, + + // Requests + Ping = 128, + + // Responses + Pong = 192, + }; + +protected: +#ifndef GDNATIVE_LIBRARY + static void _bind_methods() { + BIND_ENUM_CONSTANT(NonePacket); + BIND_ENUM_CONSTANT(SyncTime); + BIND_ENUM_CONSTANT(ImageData); + BIND_ENUM_CONSTANT(InputData); + BIND_ENUM_CONSTANT(ServerSettings); + BIND_ENUM_CONSTANT(MouseModeSync); + BIND_ENUM_CONSTANT(CustomInputScene); + BIND_ENUM_CONSTANT(ClientStreamOrientation); + BIND_ENUM_CONSTANT(ClientStreamAspect); + BIND_ENUM_CONSTANT(CustomUserData); + BIND_ENUM_CONSTANT(Ping); + BIND_ENUM_CONSTANT(Pong); + } +#else +public: + void _init(){}; + static void _register_methods(){}; +protected: +#endif + + virtual Ref _get_data() { + Ref buf(memnew(StreamPeerBuffer)); + buf->put_8((uint8_t)get_type()); + return buf; + }; + virtual bool _create(Ref buf) { + buf->get_8(); + return true; + }; + +public: + virtual PacketType get_type() { return PacketType::NonePacket; }; + static Ref create(const PoolByteArray &bytes); + PoolByteArray get_data() { + return _get_data()->get_data_array(); + }; +}; + +////////////////////////////////////////////////////////////////////////// +// SyncTime +class GRPacketSyncTime : public GRPacket { + GD_S_CLASS(GRPacketSyncTime, GRPacket); + friend GRPacket; + + uint64_t time = 0; + +protected: + GDNATIVE_BASIC_REGISTER; + + virtual Ref _get_data() override; + virtual bool _create(Ref buf) override; + +public: + virtual PacketType get_type() override { return PacketType::SyncTime; }; + + uint64_t get_time(); +}; + +////////////////////////////////////////////////////////////////////////// +// IMAGE DATA +class GRPacketImageData : public GRPacket { + GD_S_CLASS(GRPacketImageData, GRPacket); + friend GRPacket; + + /*GRDevice::ImageCompressionType*/int compression = 1 /*GRDevice::ImageCompressionType::JPG*/; + Size2 size; + int format = 0; + PoolByteArray img_data; + uint64_t start_time = 0; + uint64_t frametime = 0; + bool is_empty = false; + +protected: + GDNATIVE_BASIC_REGISTER; + + virtual Ref _get_data() override; + virtual bool _create(Ref buf) override; + +public: + virtual PacketType get_type() override { return PacketType::ImageData; }; + + PoolByteArray get_image_data(); + int get_compression_type(); + Size2 get_size(); + int get_format(); + uint64_t get_start_time(); + uint64_t get_frametime(); + bool get_is_empty(); + + void set_image_data(PoolByteArray &buf); + void set_compression_type(int type); + void set_size(Size2 _size); + void set_format(int _format); + void set_start_time(uint64_t time); + void set_frametime(uint64_t _frametime); + void set_is_empty(bool _empty); + + ~GRPacketImageData() { + //img_data.resize(0); + } +}; + +////////////////////////////////////////////////////////////////////////// +// INPUT DATA +class GRPacketInputData : public GRPacket { + GD_S_CLASS(GRPacketInputData, GRPacket); + friend GRPacket; + + std::vector > inputs; + +protected: + GDNATIVE_BASIC_REGISTER; + + virtual Ref _get_data() override; + virtual bool _create(Ref buf) override; + +public: + virtual PacketType get_type() override { return PacketType::InputData; }; + + int get_inputs_count(); + Ref get_input_data(int idx); + void remove_input_data(int idx); + void add_input_data(Ref &input); + void set_input_data(std::vector > &_inputs); // Ref + + ~GRPacketInputData() { + //inputs.clear(); + } +}; + +////////////////////////////////////////////////////////////////////////// +// SERVER SETTINGS +class GRPacketServerSettings : public GRPacket { + GD_S_CLASS(GRPacketServerSettings, GRPacket); + friend GRPacket; + + std::map settings; + +protected: + GDNATIVE_BASIC_REGISTER; + + virtual Ref _get_data() override; + virtual bool _create(Ref buf) override; + +public: + virtual PacketType get_type() override { return PacketType::ServerSettings; }; + + std::map get_settings(); + void set_settings(std::map &_settings); + void add_setting(int _setting, Variant value); + + ~GRPacketServerSettings() { + //settings.clear(); + } +}; + +////////////////////////////////////////////////////////////////////////// +// MOUSE MODE SYNC +class GRPacketMouseModeSync : public GRPacket { + GD_S_CLASS(GRPacketMouseModeSync, GRPacket); + friend GRPacket; + + Input::MouseMode mouse_mode; + +protected: + GDNATIVE_BASIC_REGISTER; + + virtual Ref _get_data() override; + virtual bool _create(Ref buf) override; + +public: + virtual PacketType get_type() override { return PacketType::MouseModeSync; }; + + Input::MouseMode get_mouse_mode(); + void set_mouse_mode(Input::MouseMode _mode); +}; + +////////////////////////////////////////////////////////////////////////// +// CUSTOM INPUT SCENE +class GRPacketCustomInputScene : public GRPacket { + GD_S_CLASS(GRPacketCustomInputScene, GRPacket); + friend GRPacket; + + String scene_path; + bool compressed; + int compression_type; + int original_data_size; + PoolByteArray scene_data; + +protected: + GDNATIVE_BASIC_REGISTER; + + virtual Ref _get_data() override; + virtual bool _create(Ref buf) override; + +public: + virtual PacketType get_type() override { return PacketType::CustomInputScene; }; + + String get_scene_path(); + void set_scene_path(String _path); + PoolByteArray get_scene_data(); + void set_scene_data(PoolByteArray _data); + bool is_compressed(); + void set_compressed(bool val); + int get_original_size(); + void set_original_size(int val); + int get_compression_type(); + void set_compression_type(int val); + + ~GRPacketCustomInputScene() { + //scene_data.resize(0); + } +}; + +////////////////////////////////////////////////////////////////////////// +// CLIENT DEVICE ROTATION +class GRPacketClientStreamOrientation : public GRPacket { + GD_S_CLASS(GRPacketClientStreamOrientation, GRPacket); + friend GRPacket; + + bool vertical; + +protected: + GDNATIVE_BASIC_REGISTER; + + virtual Ref _get_data() override; + virtual bool _create(Ref buf) override; + +public: + virtual PacketType get_type() override { return PacketType::ClientStreamOrientation; }; + + bool is_vertical(); + void set_vertical(bool val); +}; + +////////////////////////////////////////////////////////////////////////// +// CLIENT SCREEN ASCPECT +class GRPacketClientStreamAspect : public GRPacket { + GD_S_CLASS(GRPacketClientStreamAspect, GRPacket); + friend GRPacket; + + float stream_aspect; + +protected: + GDNATIVE_BASIC_REGISTER; + + virtual Ref _get_data() override; + virtual bool _create(Ref buf) override; + +public: + virtual PacketType get_type() override { return PacketType::ClientStreamAspect; }; + + float get_aspect(); + void set_aspect(float val); +}; + +////////////////////////////////////////////////////////////////////////// +// CUSTOM USER DATA +class GRPacketCustomUserData : public GRPacket { + GD_S_CLASS(GRPacketCustomUserData, GRPacket); + friend GRPacket; + + Variant packet_id; + bool full_objects = false; + Variant user_data; + +protected: + GDNATIVE_BASIC_REGISTER; + + virtual Ref _get_data() override; + virtual bool _create(Ref buf) override; + +public: + virtual PacketType get_type() override { return PacketType::CustomUserData; }; + + Variant get_packet_id(); + void set_packet_id(Variant val); + bool get_send_full_objects(); + void set_send_full_objects(bool val); + Variant get_user_data(); + void set_user_data(Variant val); +}; + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +// REQUESTS AND RESPONSES + +#define BASIC_PACKET(_name, _type) \ + class _name : public GRPacket { \ + GD_S_CLASS(_name, GRPacket); \ + friend GRPacket; \ + \ + protected: \ + GDNATIVE_BASIC_REGISTER; \ + virtual Ref _get_data() override { return GRPacket::_get_data(); }; \ + virtual bool _create(Ref buf) override { return true; }; \ + \ + public: \ + virtual PacketType get_type() override { return _type; }; \ + } + +BASIC_PACKET(GRPacketPing, PacketType::Ping); +BASIC_PACKET(GRPacketPong, PacketType::Pong); + +#undef BASIC_PACKET + +#ifndef GDNATIVE_LIBRARY +VARIANT_ENUM_CAST(GRPacket::PacketType) +#endif diff --git a/modules/godot_remote/godot_remote/GRResources.cpp b/modules/godot_remote/godot_remote/GRResources.cpp new file mode 100644 index 0000000..10eb124 --- /dev/null +++ b/modules/godot_remote/godot_remote/GRResources.cpp @@ -0,0 +1,1498 @@ +/* GRBinResources.cpp */ + +#include "GRResources.h" +#ifndef NO_GODOTREMOTE_DEFAULT_RESOURCES + +namespace GRResources { + +// based on https://github.com/hiulit/Godot-3-2D-CRT-Shader/blob/master/crt_shader.shader +const char *Txt_CRT_Shader = R"( + shader_type canvas_item; + +uniform float vignette_opacity : hint_range(0.1, 0.5, 0.01) = float(0.4); +uniform bool show_vignette = true; +uniform bool show_curvature = true; // Curvature works best on stretch mode 2d. +uniform vec2 screen_size = vec2(160.0, 90.0); +uniform float aberration_amount : hint_range(0.0, 10.0, 0.05) = float(0.25); + +vec2 CRTCurveUV(vec2 uv) { + if (show_curvature) { + uv = uv * 2.0 - 1.0; + vec2 offset = abs(uv.yx) / vec2(6.0, 5.0); + uv = uv + uv * offset * offset; + uv = uv * 0.5 + 0.5; + } + return uv; +} + +void DrawVignette(inout vec3 color, vec2 uv) { + if (show_vignette) { + float vignette = uv.x * uv.y * (1.0 - uv.x) * (1.0 - uv.y); + vignette = clamp(pow((screen_size.x / 4.0) * vignette, vignette_opacity), 0.0, 1.0); + color *= vignette; + } else { + return; + } +} + +void fragment() { + vec2 screen_crtUV = CRTCurveUV(UV); + vec3 color = texture(TEXTURE, screen_crtUV).rgb; + + if (aberration_amount > 0.0) { + float adjusted_amount = aberration_amount / screen_size.x; + color.r = texture(TEXTURE, vec2(screen_crtUV.x + adjusted_amount, screen_crtUV.y)).r; + color.g = texture(TEXTURE, screen_crtUV).g; + color.b = texture(TEXTURE, vec2(screen_crtUV.x - adjusted_amount, screen_crtUV.y)).b; + } + + vec2 crtUV = CRTCurveUV(UV); + if (crtUV.x < 0.0 || crtUV.x > 1.0 || crtUV.y < 0.0 || crtUV.y > 1.0) { + color = vec3(0.0, 0.0, 0.0); + } + + DrawVignette(color, crtUV); + COLOR = vec4(color, 1.0); +} +)"; + +const unsigned int Bin_NoSignalPNG_size = 10838; +const unsigned char Bin_NoSignalPNG[] = { + 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, + 0, 0, 2, 128, 0, 0, 1, 104, 8, 3, 0, 0, 0, 240, 236, 186, + 99, 0, 0, 0, 1, 115, 82, 71, 66, 0, 174, 206, 28, 233, 0, 0, + 0, 4, 103, 65, 77, 65, 0, 0, 177, 143, 11, 252, 97, 5, 0, 0, + 3, 0, 80, 76, 84, 69, 32, 37, 49, 32, 39, 52, 33, 40, 53, 37, + 41, 53, 39, 44, 55, 35, 43, 57, 41, 45, 57, 43, 48, 59, 44, 48, + 59, 45, 49, 61, 47, 52, 63, 49, 52, 61, 56, 55, 57, 58, 57, 59, + 36, 47, 64, 36, 50, 67, 38, 54, 72, 38, 56, 76, 40, 58, 78, 41, + 61, 82, 49, 53, 64, 51, 56, 66, 52, 56, 67, 53, 57, 68, 55, 60, + 70, 58, 60, 68, 58, 62, 72, 42, 65, 87, 43, 68, 91, 55, 65, 79, + 59, 64, 74, 60, 64, 74, 62, 66, 76, 60, 70, 84, 45, 71, 96, 45, + 73, 98, 47, 78, 106, 48, 79, 107, 48, 80, 109, 49, 83, 113, 52, 91, + 123, 64, 63, 65, 65, 64, 66, 64, 68, 78, 72, 71, 73, 76, 76, 76, + 66, 70, 80, 67, 72, 82, 68, 72, 82, 70, 74, 84, 72, 75, 84, 72, + 77, 86, 75, 78, 88, 77, 81, 90, 79, 83, 92, 82, 82, 82, 80, 83, + 91, 81, 85, 94, 88, 87, 89, 92, 92, 92, 83, 87, 96, 85, 88, 97, + 87, 91, 100, 90, 93, 102, 92, 95, 104, 92, 96, 103, 94, 97, 105, 96, + 95, 97, 99, 99, 99, 96, 99, 106, 97, 100, 107, 98, 101, 110, 100, 103, + 109, 101, 104, 111, 108, 108, 108, 100, 103, 112, 102, 106, 113, 104, 106, 113, + 104, 107, 116, 106, 108, 114, 106, 109, 117, 108, 110, 117, 110, 112, 118, 109, + 112, 120, 115, 115, 115, 114, 116, 123, 118, 120, 125, 123, 123, 123, 53, 94, + 128, 54, 97, 132, 56, 100, 135, 56, 100, 136, 57, 105, 142, 59, 108, 148, + 60, 111, 152, 60, 113, 154, 62, 118, 161, 63, 120, 164, 64, 121, 165, 65, + 125, 170, 118, 121, 128, 120, 122, 128, 121, 124, 129, 122, 125, 132, 125, 126, + 129, 124, 127, 132, 62, 134, 187, 66, 128, 174, 67, 131, 179, 64, 135, 187, + 70, 139, 190, 72, 140, 191, 126, 128, 133, 126, 129, 136, 71, 140, 192, 72, + 142, 194, 73, 144, 197, 75, 148, 202, 84, 148, 195, 88, 150, 197, 92, 153, + 198, 98, 157, 200, 103, 160, 202, 109, 163, 204, 113, 166, 205, 116, 168, 206, + 123, 172, 209, 130, 130, 131, 128, 131, 137, 129, 132, 138, 130, 133, 140, 132, + 134, 139, 133, 135, 140, 133, 136, 141, 138, 139, 139, 135, 137, 144, 136, 138, + 145, 137, 140, 145, 139, 142, 148, 140, 142, 145, 140, 143, 149, 142, 144, 149, + 143, 146, 152, 147, 147, 148, 144, 147, 153, 146, 148, 154, 148, 149, 152, 148, + 150, 156, 150, 152, 156, 155, 155, 156, 152, 154, 160, 154, 156, 162, 156, 158, + 161, 157, 159, 164, 159, 160, 162, 158, 160, 165, 162, 162, 163, 161, 163, 168, + 162, 164, 169, 164, 166, 169, 165, 167, 172, 166, 168, 172, 169, 169, 169, 168, + 170, 175, 173, 173, 173, 170, 172, 176, 172, 174, 179, 174, 176, 180, 176, 175, + 176, 177, 177, 177, 176, 178, 182, 179, 180, 180, 181, 181, 181, 179, 181, 185, + 182, 184, 187, 185, 185, 185, 184, 186, 190, 186, 188, 191, 189, 189, 189, 132, + 178, 212, 137, 181, 214, 141, 184, 215, 142, 184, 216, 148, 188, 217, 152, 190, + 219, 187, 189, 192, 189, 190, 194, 157, 193, 220, 161, 196, 222, 191, 192, 196, + 165, 199, 224, 166, 200, 224, 170, 202, 225, 176, 206, 228, 181, 209, 229, 186, + 211, 231, 189, 214, 232, 193, 193, 193, 192, 194, 197, 194, 196, 199, 197, 197, + 197, 195, 196, 200, 196, 197, 200, 199, 200, 203, 199, 201, 204, 201, 201, 201, + 200, 201, 204, 203, 204, 207, 205, 205, 205, 205, 206, 209, 207, 208, 211, 209, + 209, 209, 208, 209, 212, 211, 212, 214, 212, 213, 213, 213, 214, 216, 215, 216, + 218, 217, 217, 218, 218, 218, 220, 221, 221, 221, 196, 218, 234, 202, 222, 236, + 221, 222, 224, 206, 224, 238, 209, 226, 239, 223, 224, 225, 212, 228, 240, 216, + 231, 241, 220, 233, 242, 224, 225, 225, 226, 226, 228, 227, 228, 229, 229, 229, + 229, 230, 231, 232, 233, 233, 233, 234, 235, 236, 235, 236, 237, 237, 237, 237, + 227, 237, 245, 239, 239, 240, 230, 240, 246, 232, 240, 247, 236, 243, 248, 241, + 240, 239, 241, 241, 241, 243, 243, 244, 246, 246, 246, 241, 246, 250, 245, 249, + 251, 249, 249, 249, 248, 250, 253, 250, 252, 253, 254, 254, 254, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 146, 77, 57, 65, 0, 0, 0, 9, 112, 72, + 89, 115, 0, 0, 14, 195, 0, 0, 14, 195, 1, 199, 111, 168, 100, 0, + 0, 38, 223, 73, 68, 65, 84, 120, 94, 237, 157, 127, 124, 85, 229, 157, + 231, 143, 100, 136, 19, 44, 139, 213, 172, 81, 150, 29, 178, 107, 171, 84, + 70, 10, 19, 144, 205, 98, 38, 53, 147, 25, 42, 162, 130, 36, 50, 238, + 14, 139, 45, 85, 166, 20, 82, 75, 110, 17, 71, 107, 138, 35, 241, 119, + 169, 45, 169, 76, 73, 161, 68, 144, 133, 5, 161, 224, 12, 173, 226, 14, + 45, 149, 161, 90, 45, 21, 7, 55, 70, 157, 169, 99, 28, 136, 6, 91, + 54, 19, 189, 245, 252, 177, 207, 143, 207, 57, 231, 57, 231, 124, 207, 143, + 11, 225, 44, 247, 246, 251, 126, 189, 224, 62, 231, 121, 206, 61, 207, 205, + 57, 239, 243, 252, 62, 247, 90, 12, 195, 48, 12, 195, 48, 12, 195, 48, + 12, 195, 48, 12, 195, 48, 12, 195, 48, 12, 195, 48, 12, 195, 48, 12, + 195, 48, 12, 195, 48, 12, 195, 48, 12, 195, 48, 12, 195, 48, 12, 195, + 48, 12, 195, 48, 12, 195, 48, 204, 25, 64, 245, 149, 51, 23, 206, 105, + 152, 82, 134, 205, 56, 46, 148, 32, 156, 130, 170, 11, 28, 42, 203, 17, + 197, 48, 62, 42, 191, 215, 99, 131, 103, 107, 17, 23, 73, 173, 218, 239, + 211, 216, 10, 81, 185, 243, 151, 8, 129, 95, 170, 253, 193, 171, 107, 71, + 32, 250, 20, 169, 216, 250, 26, 66, 76, 209, 51, 251, 93, 232, 161, 88, + 136, 216, 40, 98, 5, 44, 127, 220, 182, 95, 64, 24, 248, 4, 180, 237, + 190, 26, 196, 159, 10, 195, 214, 9, 151, 17, 102, 138, 157, 57, 80, 195, + 161, 14, 241, 17, 196, 9, 248, 77, 153, 116, 0, 27, 32, 32, 160, 221, + 141, 248, 83, 224, 65, 121, 156, 151, 177, 193, 20, 57, 213, 3, 202, 11, + 123, 224, 229, 247, 117, 32, 80, 133, 6, 137, 19, 240, 136, 76, 250, 17, + 54, 128, 22, 240, 205, 127, 252, 249, 171, 42, 96, 219, 211, 145, 112, 242, + 252, 92, 30, 230, 37, 108, 48, 69, 206, 38, 101, 69, 111, 131, 8, 222, + 163, 130, 182, 12, 106, 206, 174, 66, 0, 84, 136, 127, 65, 1, 71, 203, + 72, 240, 154, 76, 250, 1, 54, 128, 22, 112, 150, 8, 85, 60, 171, 130, + 247, 233, 120, 81, 95, 19, 93, 153, 97, 213, 78, 63, 168, 26, 175, 192, + 204, 70, 29, 210, 172, 233, 203, 70, 15, 67, 136, 41, 54, 42, 148, 20, + 182, 118, 97, 107, 255, 207, 30, 107, 118, 26, 105, 247, 28, 56, 42, 18, + 186, 59, 39, 98, 187, 98, 107, 175, 109, 247, 60, 82, 167, 246, 215, 2, + 142, 127, 226, 149, 65, 219, 206, 31, 248, 138, 218, 114, 138, 56, 219, 126, + 92, 109, 107, 60, 1, 173, 133, 42, 248, 152, 138, 94, 248, 236, 59, 34, + 220, 183, 189, 89, 109, 213, 246, 11, 142, 90, 205, 114, 231, 151, 174, 177, + 172, 91, 95, 30, 180, 243, 47, 77, 81, 105, 66, 190, 77, 191, 20, 197, + 116, 254, 103, 247, 168, 173, 151, 212, 81, 36, 219, 213, 118, 243, 211, 226, + 115, 217, 239, 62, 249, 5, 181, 197, 20, 25, 95, 84, 151, 114, 3, 182, + 60, 234, 181, 56, 146, 111, 170, 136, 6, 169, 163, 224, 61, 245, 191, 18, + 240, 97, 21, 148, 188, 35, 59, 207, 137, 2, 110, 85, 65, 105, 107, 173, + 170, 69, 21, 207, 75, 193, 117, 177, 186, 90, 253, 111, 219, 205, 143, 33, + 160, 187, 228, 247, 229, 177, 105, 31, 171, 23, 155, 126, 1, 107, 116, 177, + 42, 121, 217, 17, 150, 41, 34, 190, 163, 174, 157, 46, 135, 12, 62, 163, + 162, 193, 183, 101, 204, 63, 98, 67, 35, 5, 252, 62, 194, 138, 9, 241, + 2, 126, 127, 206, 156, 7, 15, 168, 144, 93, 105, 89, 23, 138, 114, 211, + 69, 182, 57, 181, 128, 33, 84, 115, 114, 45, 54, 20, 147, 3, 2, 150, + 31, 67, 88, 242, 102, 154, 97, 76, 230, 204, 98, 187, 186, 116, 178, 217, + 167, 85, 20, 28, 17, 27, 122, 96, 112, 251, 90, 125, 125, 69, 33, 165, + 75, 74, 219, 145, 76, 8, 168, 123, 207, 221, 107, 117, 185, 38, 100, 136, + 19, 208, 99, 142, 136, 83, 153, 190, 58, 221, 154, 169, 68, 124, 36, 82, + 64, 91, 52, 237, 174, 81, 129, 55, 59, 55, 171, 215, 167, 3, 2, 174, + 151, 175, 189, 205, 40, 159, 215, 234, 44, 153, 34, 66, 251, 33, 10, 22, + 79, 192, 87, 68, 187, 74, 5, 110, 177, 172, 177, 170, 143, 188, 213, 178, + 158, 150, 175, 125, 147, 172, 137, 170, 163, 33, 5, 124, 69, 190, 202, 49, + 151, 175, 171, 152, 90, 171, 178, 82, 54, 198, 236, 237, 149, 149, 162, 144, + 115, 241, 11, 152, 151, 254, 77, 81, 65, 217, 203, 248, 138, 12, 188, 230, + 8, 56, 80, 123, 129, 190, 31, 94, 185, 101, 180, 214, 90, 100, 243, 130, + 124, 125, 73, 148, 109, 186, 183, 212, 32, 178, 81, 166, 31, 144, 217, 84, + 171, 56, 89, 245, 170, 79, 252, 174, 204, 144, 41, 42, 158, 84, 151, 80, + 14, 141, 184, 2, 138, 58, 81, 93, 236, 62, 55, 253, 85, 203, 250, 149, + 124, 189, 77, 68, 124, 65, 6, 132, 25, 186, 247, 162, 198, 84, 148, 119, + 178, 15, 160, 228, 220, 44, 163, 60, 124, 2, 110, 85, 106, 170, 67, 244, + 141, 22, 232, 30, 205, 4, 8, 40, 202, 225, 9, 42, 48, 219, 178, 174, + 84, 129, 6, 171, 76, 189, 170, 38, 164, 242, 110, 133, 8, 40, 245, 119, + 202, 168, 153, 50, 148, 151, 71, 154, 36, 67, 246, 149, 50, 146, 41, 38, + 214, 169, 11, 39, 202, 58, 159, 128, 170, 154, 83, 21, 218, 117, 50, 148, + 183, 44, 249, 98, 207, 20, 17, 78, 47, 184, 70, 189, 142, 151, 251, 168, + 66, 106, 141, 8, 40, 69, 2, 29, 26, 45, 224, 218, 111, 42, 75, 181, + 157, 190, 86, 157, 160, 22, 2, 78, 178, 172, 63, 80, 129, 58, 167, 119, + 62, 29, 101, 156, 44, 161, 117, 33, 44, 143, 174, 62, 157, 234, 2, 123, + 221, 32, 205, 169, 143, 49, 50, 25, 179, 66, 93, 56, 121, 53, 71, 84, + 87, 87, 111, 144, 27, 47, 161, 140, 89, 45, 211, 117, 19, 12, 2, 202, + 235, 171, 93, 249, 52, 94, 71, 203, 125, 254, 65, 134, 164, 174, 74, 182, + 117, 50, 202, 67, 11, 56, 203, 186, 66, 189, 218, 223, 19, 81, 186, 57, + 231, 49, 29, 7, 19, 29, 25, 45, 160, 232, 253, 106, 1, 103, 194, 115, + 213, 233, 222, 41, 67, 155, 68, 224, 121, 25, 120, 66, 70, 5, 85, 14, + 117, 166, 152, 51, 157, 11, 244, 149, 211, 3, 30, 214, 183, 101, 248, 121, + 92, 107, 209, 242, 195, 216, 157, 168, 130, 85, 1, 38, 37, 187, 95, 6, + 132, 17, 163, 213, 171, 122, 159, 170, 121, 101, 21, 172, 138, 166, 8, 1, + 245, 60, 157, 109, 127, 198, 178, 30, 149, 175, 189, 15, 40, 238, 191, 255, + 254, 251, 38, 65, 64, 209, 215, 9, 148, 128, 51, 173, 17, 234, 85, 188, + 9, 119, 133, 172, 130, 85, 81, 168, 4, 84, 183, 207, 160, 119, 164, 132, + 105, 68, 230, 12, 68, 185, 102, 231, 155, 43, 68, 231, 64, 183, 252, 133, + 128, 170, 115, 32, 133, 208, 78, 137, 139, 173, 74, 29, 57, 98, 162, 7, + 83, 68, 145, 164, 180, 147, 5, 146, 174, 148, 175, 112, 210, 214, 139, 128, + 129, 43, 224, 112, 61, 231, 247, 11, 203, 154, 37, 95, 251, 85, 42, 86, + 104, 69, 11, 168, 181, 147, 37, 244, 100, 21, 35, 71, 2, 85, 79, 69, + 85, 230, 245, 42, 78, 29, 132, 215, 122, 21, 41, 213, 206, 152, 156, 110, + 164, 9, 132, 128, 149, 74, 150, 222, 133, 205, 63, 80, 49, 66, 8, 221, + 47, 254, 63, 175, 116, 171, 87, 41, 224, 189, 42, 176, 126, 214, 61, 106, + 95, 181, 4, 65, 247, 104, 86, 63, 47, 187, 186, 14, 174, 128, 120, 131, + 44, 42, 149, 187, 162, 53, 87, 37, 180, 206, 247, 187, 189, 96, 82, 64, + 61, 125, 178, 105, 214, 138, 126, 249, 170, 102, 128, 117, 127, 120, 205, 129, + 133, 150, 245, 11, 25, 218, 90, 102, 85, 138, 172, 213, 145, 152, 162, 67, + 119, 107, 61, 6, 229, 140, 151, 46, 2, 129, 154, 10, 209, 195, 47, 14, + 178, 81, 230, 13, 200, 137, 139, 175, 122, 35, 143, 96, 235, 97, 185, 1, + 60, 1, 173, 62, 21, 60, 134, 158, 141, 157, 87, 133, 155, 109, 95, 19, + 43, 32, 138, 92, 160, 230, 9, 87, 98, 227, 59, 78, 17, 104, 235, 194, + 149, 155, 128, 197, 201, 116, 115, 54, 193, 254, 142, 174, 203, 28, 151, 4, + 122, 120, 87, 141, 120, 8, 220, 1, 58, 171, 82, 187, 37, 233, 213, 101, + 94, 13, 68, 80, 237, 51, 96, 8, 168, 11, 51, 57, 23, 167, 90, 129, + 224, 86, 145, 18, 39, 96, 185, 55, 109, 119, 76, 27, 54, 94, 155, 172, + 70, 98, 28, 25, 37, 122, 174, 152, 41, 58, 42, 239, 65, 89, 100, 31, + 249, 134, 59, 134, 60, 126, 131, 154, 130, 29, 124, 1, 253, 19, 235, 58, + 85, 6, 118, 234, 254, 176, 234, 150, 90, 115, 212, 250, 43, 187, 79, 245, + 151, 37, 245, 186, 62, 151, 109, 69, 7, 67, 64, 75, 174, 63, 16, 136, + 80, 195, 143, 244, 4, 239, 123, 235, 38, 201, 4, 87, 64, 61, 234, 226, + 19, 80, 184, 175, 143, 209, 247, 152, 51, 213, 118, 165, 22, 93, 45, 45, + 172, 123, 82, 231, 57, 176, 193, 249, 160, 76, 17, 82, 57, 177, 126, 122, + 221, 196, 192, 92, 234, 232, 250, 134, 177, 8, 42, 174, 104, 168, 19, 93, + 149, 50, 9, 98, 172, 242, 154, 89, 181, 198, 66, 41, 177, 79, 125, 237, + 69, 8, 106, 212, 238, 216, 95, 135, 177, 49, 161, 126, 86, 93, 96, 205, + 85, 36, 101, 147, 174, 171, 245, 45, 230, 191, 162, 254, 74, 53, 2, 164, + 24, 95, 63, 187, 78, 53, 1, 24, 134, 97, 24, 134, 97, 24, 134, 97, + 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, + 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, + 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, + 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, + 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, + 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, + 24, 134, 97, 24, 134, 57, 195, 185, 156, 97, 124, 64, 140, 172, 64, 174, + 12, 3, 32, 70, 86, 32, 87, 134, 1, 16, 35, 43, 144, 43, 195, 0, + 136, 145, 21, 200, 149, 97, 0, 196, 200, 10, 228, 202, 48, 0, 98, 100, + 5, 114, 101, 24, 0, 49, 178, 2, 185, 50, 12, 128, 24, 89, 129, 92, + 25, 6, 64, 140, 172, 64, 174, 12, 3, 32, 70, 86, 32, 87, 134, 1, + 16, 35, 43, 144, 43, 195, 0, 136, 145, 21, 200, 149, 97, 0, 196, 200, + 10, 228, 202, 48, 0, 98, 100, 5, 114, 101, 24, 0, 49, 178, 2, 185, + 50, 12, 128, 24, 89, 129, 92, 25, 6, 64, 140, 172, 64, 174, 12, 3, + 32, 70, 86, 32, 87, 134, 1, 16, 35, 43, 144, 43, 195, 0, 136, 145, + 21, 200, 149, 97, 0, 196, 200, 10, 228, 202, 48, 0, 98, 100, 5, 114, + 101, 24, 0, 49, 178, 2, 185, 50, 12, 128, 24, 89, 129, 92, 25, 6, + 64, 140, 172, 64, 174, 12, 3, 32, 70, 86, 32, 87, 134, 1, 16, 35, + 43, 144, 43, 195, 0, 136, 145, 21, 200, 149, 97, 0, 196, 200, 10, 228, + 202, 48, 0, 98, 100, 5, 114, 101, 24, 0, 49, 178, 2, 185, 50, 12, + 128, 24, 89, 129, 92, 25, 6, 64, 140, 172, 64, 174, 12, 3, 32, 70, + 86, 32, 87, 134, 1, 16, 35, 43, 144, 43, 195, 0, 136, 145, 21, 200, + 149, 97, 0, 196, 200, 10, 228, 202, 48, 0, 98, 100, 5, 114, 101, 24, + 0, 49, 178, 2, 185, 50, 12, 128, 24, 89, 129, 92, 79, 55, 83, 167, + 53, 78, 155, 138, 240, 105, 224, 52, 31, 94, 163, 50, 57, 237, 185, 252, + 127, 7, 98, 100, 133, 202, 115, 90, 8, 21, 29, 6, 169, 6, 72, 136, + 98, 106, 83, 199, 174, 67, 189, 3, 182, 102, 240, 232, 225, 93, 157, 115, + 147, 222, 83, 0, 51, 86, 109, 57, 216, 221, 143, 163, 219, 3, 125, 61, + 207, 117, 182, 205, 64, 26, 5, 62, 180, 9, 82, 162, 153, 214, 222, 185, + 237, 197, 158, 129, 65, 100, 98, 15, 246, 245, 28, 222, 213, 17, 255, 87, + 224, 216, 6, 72, 8, 48, 21, 169, 30, 72, 160, 193, 62, 62, 98, 239, + 8, 236, 99, 130, 148, 104, 32, 70, 86, 168, 60, 15, 225, 220, 122, 116, + 168, 248, 32, 83, 145, 234, 209, 135, 20, 146, 25, 29, 225, 3, 75, 122, + 186, 154, 176, 199, 41, 209, 246, 156, 35, 182, 159, 129, 29, 109, 216, 35, + 68, 31, 118, 49, 136, 243, 85, 228, 177, 227, 40, 246, 11, 209, 189, 113, + 46, 118, 10, 49, 13, 187, 120, 12, 208, 158, 108, 65, 178, 71, 59, 82, + 40, 218, 177, 143, 143, 23, 145, 72, 114, 16, 59, 25, 68, 158, 27, 7, + 136, 145, 21, 42, 79, 194, 19, 242, 186, 20, 36, 96, 27, 109, 159, 166, + 183, 35, 249, 86, 140, 101, 218, 70, 218, 62, 205, 192, 22, 250, 240, 133, + 9, 216, 216, 73, 236, 111, 210, 67, 223, 167, 132, 128, 246, 115, 72, 242, + 83, 152, 128, 71, 176, 143, 159, 184, 19, 89, 196, 2, 118, 171, 132, 0, + 5, 8, 216, 222, 139, 61, 34, 217, 120, 42, 10, 110, 196, 65, 34, 25, + 36, 221, 40, 68, 192, 169, 93, 216, 35, 142, 30, 178, 20, 36, 4, 180, + 87, 33, 205, 71, 65, 2, 54, 98, 151, 0, 17, 55, 129, 162, 136, 5, + 180, 187, 84, 138, 159, 212, 2, 54, 197, 149, 126, 14, 131, 157, 216, 187, + 96, 154, 122, 112, 136, 56, 122, 8, 181, 10, 16, 112, 149, 219, 180, 140, + 103, 35, 246, 55, 161, 4, 180, 27, 145, 104, 82, 144, 128, 157, 216, 37, + 64, 47, 146, 41, 138, 89, 64, 155, 184, 183, 211, 10, 216, 129, 212, 36, + 14, 81, 23, 37, 153, 85, 120, 123, 2, 253, 225, 150, 102, 106, 1, 167, + 189, 136, 228, 100, 14, 135, 75, 114, 82, 192, 67, 72, 52, 41, 72, 192, + 168, 59, 34, 166, 65, 93, 212, 2, 30, 85, 73, 62, 210, 9, 56, 149, + 248, 179, 35, 200, 39, 158, 14, 130, 136, 146, 32, 76, 248, 232, 105, 5, + 156, 155, 208, 248, 243, 113, 36, 212, 193, 32, 5, 164, 234, 202, 66, 4, + 156, 139, 61, 66, 108, 195, 14, 4, 69, 45, 160, 189, 69, 165, 153, 164, + 18, 176, 145, 110, 43, 71, 64, 54, 141, 98, 73, 89, 254, 73, 250, 131, + 106, 164, 20, 176, 128, 44, 36, 135, 241, 54, 23, 90, 64, 34, 171, 66, + 4, 220, 133, 61, 194, 96, 7, 130, 226, 22, 48, 252, 89, 211, 8, 216, + 24, 57, 110, 65, 19, 215, 134, 166, 152, 129, 247, 165, 98, 7, 222, 228, + 144, 78, 64, 114, 184, 35, 142, 224, 173, 26, 33, 224, 17, 36, 123, 20, + 34, 32, 118, 32, 136, 126, 79, 145, 11, 216, 175, 18, 13, 210, 8, 88, + 80, 249, 39, 137, 105, 245, 80, 164, 111, 156, 73, 2, 167, 59, 149, 128, + 145, 117, 93, 52, 129, 191, 33, 66, 64, 59, 212, 235, 42, 64, 192, 152, + 82, 153, 106, 93, 106, 138, 92, 64, 123, 151, 74, 245, 72, 33, 96, 250, + 246, 159, 75, 65, 163, 210, 5, 150, 78, 129, 209, 164, 52, 2, 54, 185, + 115, 30, 233, 9, 156, 134, 40, 1, 67, 127, 106, 1, 2, 198, 221, 216, + 145, 3, 90, 197, 46, 96, 240, 116, 36, 11, 152, 182, 255, 107, 66, 14, + 57, 70, 65, 92, 135, 163, 27, 59, 218, 218, 218, 187, 14, 99, 211, 143, + 191, 47, 159, 70, 64, 250, 56, 9, 248, 7, 173, 34, 5, 12, 14, 153, + 164, 23, 48, 98, 16, 80, 19, 57, 158, 85, 244, 2, 230, 85, 178, 75, + 162, 128, 5, 53, 208, 92, 98, 186, 113, 65, 136, 12, 220, 110, 76, 227, + 14, 196, 152, 248, 11, 241, 20, 2, 158, 204, 45, 36, 78, 148, 175, 187, + 19, 41, 96, 176, 181, 152, 94, 192, 216, 81, 241, 112, 67, 8, 20, 189, + 128, 129, 153, 198, 68, 1, 11, 107, 160, 185, 164, 175, 132, 195, 67, 48, + 230, 21, 163, 218, 73, 190, 234, 41, 89, 192, 168, 91, 40, 127, 176, 115, + 85, 123, 123, 123, 103, 212, 95, 232, 235, 75, 69, 11, 24, 40, 145, 211, + 11, 24, 55, 241, 24, 125, 2, 139, 95, 64, 255, 137, 77, 18, 176, 13, + 177, 65, 122, 186, 218, 231, 182, 205, 109, 235, 136, 170, 221, 98, 39, 212, + 125, 132, 62, 169, 255, 173, 196, 16, 161, 239, 138, 38, 11, 72, 183, 97, + 123, 218, 220, 18, 110, 106, 7, 233, 130, 111, 212, 52, 70, 64, 127, 199, + 46, 181, 128, 9, 29, 163, 96, 111, 223, 161, 4, 4, 180, 205, 186, 37, + 73, 192, 110, 196, 250, 217, 229, 221, 245, 211, 34, 230, 112, 83, 23, 129, + 161, 139, 31, 104, 254, 132, 199, 128, 124, 149, 94, 162, 128, 116, 1, 232, + 31, 42, 154, 70, 246, 7, 204, 162, 45, 70, 64, 127, 155, 32, 181, 128, + 209, 131, 128, 26, 236, 22, 164, 20, 4, 52, 7, 175, 18, 4, 36, 111, + 211, 126, 127, 165, 211, 72, 150, 130, 81, 119, 112, 144, 240, 7, 8, 8, + 24, 46, 2, 125, 93, 156, 68, 1, 169, 102, 228, 160, 255, 47, 16, 159, + 130, 250, 27, 76, 177, 226, 4, 244, 25, 144, 90, 64, 164, 70, 18, 241, + 182, 82, 16, 208, 188, 196, 9, 2, 62, 135, 72, 147, 190, 96, 35, 159, + 110, 39, 166, 92, 25, 19, 238, 11, 6, 198, 192, 136, 18, 12, 41, 138, + 36, 1, 169, 190, 230, 96, 184, 120, 158, 26, 44, 104, 143, 62, 215, 145, + 182, 4, 244, 117, 236, 210, 10, 152, 56, 53, 19, 30, 227, 86, 148, 132, + 128, 134, 28, 241, 2, 146, 167, 61, 228, 31, 93, 81, 167, 156, 145, 11, + 127, 128, 96, 191, 82, 197, 201, 69, 203, 7, 119, 108, 20, 221, 134, 185, + 51, 124, 235, 29, 146, 4, 164, 186, 192, 212, 71, 243, 132, 24, 56, 212, + 213, 22, 90, 82, 17, 43, 160, 217, 108, 221, 134, 40, 15, 90, 192, 224, + 41, 219, 22, 106, 106, 208, 119, 112, 105, 8, 232, 13, 94, 197, 11, 72, + 221, 166, 212, 8, 21, 85, 83, 31, 68, 90, 18, 196, 32, 241, 128, 239, + 154, 53, 198, 150, 165, 73, 2, 18, 117, 43, 221, 65, 146, 159, 163, 123, + 219, 42, 226, 246, 146, 196, 11, 104, 72, 150, 82, 192, 80, 193, 220, 24, + 58, 215, 244, 80, 96, 105, 8, 232, 45, 121, 139, 23, 144, 248, 107, 233, + 49, 102, 162, 39, 226, 31, 71, 139, 134, 156, 104, 206, 191, 216, 145, 178, + 23, 147, 32, 32, 37, 14, 125, 228, 246, 216, 103, 66, 18, 4, 244, 90, + 5, 225, 38, 39, 41, 96, 104, 16, 48, 220, 40, 12, 77, 155, 42, 74, + 68, 64, 119, 45, 101, 188, 128, 68, 233, 68, 175, 52, 104, 66, 170, 73, + 176, 161, 31, 1, 113, 70, 53, 249, 195, 27, 219, 146, 27, 146, 9, 2, + 18, 243, 124, 61, 72, 42, 136, 36, 1, 221, 22, 91, 74, 1, 131, 103, + 86, 148, 202, 161, 225, 0, 242, 4, 150, 138, 128, 142, 102, 177, 2, 82, + 35, 24, 17, 11, 78, 137, 86, 96, 202, 69, 49, 241, 83, 193, 221, 27, + 189, 241, 58, 146, 4, 1, 137, 62, 48, 93, 181, 37, 144, 36, 160, 219, + 174, 76, 39, 96, 168, 205, 34, 100, 11, 117, 247, 201, 135, 78, 74, 69, + 64, 103, 152, 36, 86, 64, 194, 141, 1, 36, 5, 33, 198, 139, 131, 235, + 30, 34, 8, 127, 130, 32, 47, 174, 138, 89, 102, 157, 32, 32, 113, 99, + 68, 180, 242, 226, 73, 20, 208, 169, 132, 195, 195, 123, 148, 128, 161, 209, + 5, 17, 23, 62, 17, 122, 95, 63, 37, 35, 32, 174, 67, 172, 128, 68, + 203, 142, 122, 94, 66, 66, 116, 67, 210, 174, 72, 72, 26, 145, 149, 116, + 119, 68, 57, 152, 32, 96, 30, 113, 30, 131, 72, 41, 140, 100, 1, 81, + 179, 167, 19, 16, 73, 46, 234, 205, 8, 123, 80, 189, 245, 210, 17, 80, + 95, 136, 88, 1, 137, 81, 64, 178, 65, 35, 32, 46, 16, 221, 136, 14, + 19, 187, 42, 196, 227, 32, 125, 158, 227, 5, 36, 142, 29, 49, 190, 150, + 64, 178, 128, 168, 218, 195, 231, 140, 56, 101, 161, 30, 175, 218, 39, 84, + 123, 83, 183, 112, 233, 8, 168, 155, 24, 177, 2, 18, 67, 24, 145, 245, + 23, 209, 153, 69, 74, 34, 68, 245, 77, 114, 132, 106, 149, 199, 11, 72, + 76, 101, 135, 31, 75, 72, 67, 10, 1, 245, 20, 103, 42, 1, 67, 143, + 0, 170, 216, 112, 147, 155, 232, 131, 149, 144, 128, 170, 151, 21, 43, 96, + 33, 82, 17, 179, 169, 201, 93, 88, 64, 205, 183, 144, 28, 12, 251, 31, + 47, 32, 49, 144, 233, 239, 131, 60, 55, 24, 131, 49, 96, 152, 70, 64, + 117, 230, 194, 130, 132, 5, 12, 149, 203, 104, 89, 99, 203, 131, 104, 240, + 148, 146, 128, 116, 203, 215, 16, 48, 188, 72, 36, 186, 1, 69, 100, 24, + 211, 117, 8, 144, 122, 205, 215, 96, 232, 106, 198, 11, 72, 204, 131, 248, + 27, 86, 177, 238, 23, 40, 160, 90, 195, 154, 70, 192, 208, 32, 32, 110, + 138, 208, 123, 137, 46, 95, 241, 10, 72, 92, 11, 113, 130, 99, 5, 12, + 183, 224, 163, 219, 117, 196, 149, 140, 172, 174, 195, 164, 95, 117, 24, 28, + 68, 137, 23, 48, 105, 49, 87, 188, 128, 198, 100, 14, 33, 32, 145, 179, + 184, 229, 210, 8, 136, 4, 15, 212, 21, 225, 158, 92, 184, 209, 81, 188, + 2, 54, 17, 23, 185, 45, 94, 64, 196, 24, 16, 79, 22, 3, 98, 192, + 45, 245, 138, 44, 65, 226, 23, 115, 184, 4, 12, 140, 23, 48, 188, 52, + 32, 112, 185, 78, 65, 64, 226, 244, 136, 10, 34, 124, 150, 67, 2, 134, + 61, 67, 66, 248, 136, 225, 249, 204, 34, 22, 144, 56, 97, 118, 172, 128, + 225, 180, 152, 89, 4, 98, 48, 165, 16, 1, 47, 159, 75, 175, 60, 36, + 240, 215, 161, 241, 2, 18, 183, 197, 208, 9, 72, 52, 48, 183, 164, 17, + 48, 228, 144, 251, 0, 67, 184, 215, 135, 4, 143, 226, 21, 112, 6, 53, + 95, 118, 120, 200, 74, 64, 226, 196, 20, 80, 5, 75, 86, 37, 126, 249, + 17, 240, 137, 93, 112, 9, 56, 100, 85, 48, 209, 153, 21, 121, 135, 79, + 124, 80, 192, 240, 41, 119, 255, 160, 240, 200, 127, 104, 40, 176, 152, 5, + 164, 206, 118, 248, 79, 142, 237, 132, 68, 183, 1, 195, 25, 22, 208, 9, + 1, 237, 233, 158, 64, 246, 125, 109, 65, 188, 128, 196, 131, 63, 5, 116, + 66, 146, 4, 164, 234, 148, 100, 1, 195, 5, 39, 18, 4, 136, 240, 8, + 85, 57, 69, 45, 32, 209, 171, 8, 99, 8, 24, 190, 184, 209, 189, 224, + 83, 25, 134, 241, 152, 177, 145, 92, 28, 19, 192, 60, 227, 241, 2, 18, + 157, 16, 255, 20, 245, 169, 9, 72, 204, 85, 134, 191, 111, 40, 40, 96, + 232, 47, 52, 58, 219, 225, 50, 53, 120, 23, 23, 183, 128, 81, 15, 136, + 153, 24, 2, 18, 85, 12, 82, 194, 16, 251, 166, 92, 143, 21, 160, 169, + 43, 177, 53, 104, 174, 153, 142, 23, 144, 232, 250, 7, 198, 1, 17, 75, + 98, 172, 6, 160, 5, 76, 245, 165, 17, 1, 1, 195, 215, 192, 216, 33, + 252, 121, 131, 227, 230, 197, 45, 32, 177, 92, 50, 132, 33, 32, 113, 122, + 35, 171, 213, 112, 225, 26, 120, 2, 185, 0, 26, 219, 183, 17, 62, 27, + 24, 159, 34, 94, 64, 162, 136, 242, 63, 172, 114, 138, 2, 82, 149, 112, + 144, 128, 128, 225, 102, 41, 18, 36, 225, 246, 97, 176, 206, 41, 114, 1, + 19, 30, 70, 149, 24, 2, 18, 125, 200, 96, 125, 226, 64, 76, 186, 158, + 212, 186, 59, 151, 105, 109, 27, 163, 75, 66, 163, 26, 141, 23, 144, 40, + 242, 253, 19, 172, 39, 47, 160, 190, 191, 162, 30, 91, 53, 8, 156, 50, + 196, 122, 248, 206, 83, 248, 207, 9, 12, 5, 22, 187, 128, 201, 51, 255, + 134, 128, 68, 5, 70, 125, 203, 170, 132, 184, 16, 225, 49, 172, 66, 153, + 209, 25, 81, 16, 26, 165, 88, 188, 128, 68, 9, 229, 47, 152, 79, 85, + 192, 20, 67, 232, 126, 1, 195, 131, 128, 7, 87, 25, 132, 15, 103, 180, + 16, 37, 197, 46, 96, 242, 136, 175, 33, 32, 177, 198, 42, 112, 58, 92, + 136, 214, 126, 148, 171, 5, 49, 151, 188, 192, 70, 41, 150, 32, 32, 49, + 180, 99, 38, 159, 186, 128, 201, 149, 176, 95, 192, 240, 133, 73, 2, 111, + 4, 69, 47, 32, 253, 12, 134, 129, 33, 32, 85, 92, 70, 116, 109, 137, + 234, 50, 170, 182, 142, 102, 90, 99, 211, 220, 208, 217, 36, 138, 97, 243, + 51, 38, 8, 72, 8, 22, 156, 204, 243, 192, 14, 46, 198, 146, 218, 176, + 128, 78, 227, 140, 184, 75, 253, 248, 206, 3, 49, 184, 159, 132, 127, 220, + 168, 248, 5, 36, 154, 211, 62, 140, 139, 75, 125, 135, 49, 189, 208, 190, + 128, 197, 251, 62, 26, 219, 87, 117, 110, 220, 113, 240, 72, 111, 191, 211, + 137, 9, 47, 215, 35, 202, 12, 163, 101, 158, 32, 32, 49, 91, 17, 253, + 21, 224, 216, 193, 37, 149, 128, 241, 133, 168, 192, 39, 32, 117, 59, 37, + 224, 255, 188, 197, 47, 96, 210, 242, 59, 83, 64, 162, 23, 66, 175, 231, + 36, 142, 25, 61, 105, 98, 16, 59, 14, 238, 16, 174, 70, 211, 11, 72, + 221, 110, 212, 178, 66, 5, 210, 93, 98, 5, 244, 86, 170, 36, 116, 236, + 124, 2, 18, 31, 55, 17, 223, 157, 92, 2, 2, 146, 143, 145, 123, 152, + 6, 80, 125, 188, 208, 228, 144, 160, 145, 24, 225, 78, 245, 221, 28, 68, + 201, 25, 46, 56, 195, 118, 167, 175, 130, 169, 161, 164, 200, 175, 31, 69, + 186, 75, 74, 1, 169, 71, 2, 13, 76, 1, 211, 12, 196, 134, 240, 13, + 5, 150, 130, 128, 241, 237, 16, 83, 64, 106, 207, 65, 162, 106, 165, 30, + 235, 72, 215, 4, 196, 206, 6, 70, 203, 31, 132, 171, 209, 244, 157, 16, + 178, 188, 143, 122, 94, 15, 201, 46, 41, 5, 76, 24, 93, 53, 79, 68, + 138, 113, 88, 2, 188, 89, 81, 10, 2, 198, 55, 68, 124, 117, 32, 241, + 231, 218, 221, 161, 126, 8, 245, 85, 139, 131, 233, 230, 65, 194, 213, 107, + 120, 248, 48, 44, 160, 33, 105, 146, 128, 84, 29, 156, 167, 215, 233, 132, + 138, 167, 88, 1, 205, 105, 241, 216, 142, 157, 41, 32, 162, 10, 196, 108, + 51, 148, 132, 128, 68, 170, 135, 79, 64, 178, 139, 23, 252, 193, 34, 98, + 201, 73, 244, 227, 115, 1, 136, 86, 102, 168, 142, 15, 151, 175, 169, 7, + 162, 5, 68, 14, 118, 158, 104, 6, 78, 11, 151, 78, 169, 5, 140, 173, + 89, 13, 1, 83, 12, 91, 83, 152, 109, 6, 66, 192, 118, 252, 106, 38, + 141, 120, 15, 196, 200, 10, 245, 57, 227, 5, 140, 187, 19, 125, 2, 70, + 168, 186, 197, 56, 88, 59, 125, 251, 167, 233, 3, 11, 8, 195, 131, 223, + 93, 69, 92, 93, 195, 159, 68, 1, 233, 22, 90, 176, 22, 158, 214, 65, + 124, 11, 68, 172, 128, 190, 243, 20, 247, 117, 187, 134, 128, 228, 23, 217, + 165, 0, 111, 151, 80, 117, 82, 28, 242, 62, 129, 24, 89, 161, 62, 103, + 130, 128, 196, 232, 132, 131, 95, 192, 168, 81, 174, 195, 29, 115, 103, 76, + 107, 108, 218, 178, 35, 226, 215, 166, 140, 107, 23, 15, 209, 133, 28, 240, + 25, 56, 53, 220, 103, 50, 11, 159, 68, 1, 35, 230, 42, 250, 158, 243, + 110, 145, 169, 109, 244, 80, 74, 122, 1, 227, 58, 118, 158, 128, 39, 49, + 8, 168, 49, 110, 151, 18, 17, 48, 102, 240, 202, 127, 98, 11, 120, 90, + 195, 36, 159, 178, 0, 140, 104, 150, 27, 99, 197, 77, 196, 165, 53, 171, + 247, 100, 1, 35, 235, 199, 222, 29, 93, 29, 237, 171, 58, 123, 34, 229, + 137, 21, 208, 63, 204, 20, 78, 119, 241, 4, 60, 137, 65, 64, 141, 145, + 87, 169, 8, 24, 61, 120, 21, 16, 176, 145, 168, 154, 146, 137, 234, 103, + 134, 161, 107, 200, 254, 109, 115, 165, 194, 141, 237, 228, 249, 54, 255, 148, + 100, 1, 99, 235, 199, 88, 10, 16, 48, 70, 46, 79, 192, 148, 191, 214, + 73, 224, 221, 207, 37, 35, 96, 100, 123, 56, 32, 96, 92, 109, 29, 73, + 33, 223, 62, 64, 117, 18, 52, 81, 234, 23, 246, 29, 209, 130, 52, 139, + 92, 41, 10, 17, 48, 162, 181, 44, 112, 5, 60, 169, 65, 64, 141, 247, + 179, 23, 37, 35, 96, 228, 144, 84, 80, 192, 84, 223, 221, 226, 167, 63, + 117, 5, 44, 72, 94, 159, 19, 96, 208, 55, 12, 148, 70, 192, 132, 145, + 226, 72, 98, 5, 12, 206, 232, 69, 54, 240, 92, 1, 137, 91, 13, 41, + 126, 168, 118, 55, 146, 74, 73, 192, 168, 114, 33, 36, 96, 244, 189, 29, + 69, 228, 92, 23, 73, 194, 212, 96, 8, 175, 74, 147, 164, 17, 144, 90, + 151, 154, 130, 126, 99, 128, 45, 89, 192, 200, 170, 194, 253, 188, 216, 54, + 136, 168, 41, 144, 106, 226, 158, 210, 18, 18, 48, 162, 131, 27, 22, 144, + 232, 135, 198, 226, 55, 36, 153, 194, 206, 105, 96, 149, 87, 42, 1, 11, + 150, 92, 226, 171, 233, 195, 2, 134, 7, 204, 35, 254, 14, 231, 116, 16, + 141, 158, 136, 166, 50, 209, 241, 115, 31, 196, 42, 33, 1, 35, 150, 6, + 134, 5, 188, 188, 49, 126, 129, 124, 128, 196, 129, 249, 32, 83, 11, 57, + 188, 81, 45, 42, 210, 9, 88, 120, 7, 180, 199, 95, 140, 167, 17, 144, + 250, 66, 89, 129, 35, 32, 113, 27, 71, 52, 85, 168, 2, 27, 73, 37, + 37, 32, 245, 32, 17, 41, 224, 229, 83, 147, 150, 28, 121, 12, 20, 86, + 255, 42, 102, 36, 63, 40, 224, 16, 244, 47, 173, 128, 5, 214, 194, 3, + 161, 129, 106, 36, 120, 16, 2, 210, 121, 64, 64, 162, 141, 72, 157, 106, + 9, 213, 156, 116, 62, 80, 73, 9, 72, 54, 206, 233, 179, 146, 182, 14, + 123, 177, 144, 254, 135, 75, 19, 161, 17, 73, 248, 187, 213, 210, 10, 120, + 249, 220, 2, 202, 217, 174, 208, 68, 118, 42, 1, 233, 30, 61, 4, 36, + 206, 96, 248, 175, 1, 68, 97, 41, 69, 146, 148, 148, 128, 164, 86, 17, + 183, 101, 83, 248, 136, 4, 233, 199, 255, 252, 52, 166, 58, 122, 63, 209, + 186, 76, 45, 96, 250, 241, 192, 141, 196, 77, 148, 78, 64, 234, 211, 56, + 2, 18, 245, 115, 100, 101, 65, 93, 23, 124, 168, 210, 18, 144, 154, 156, + 140, 170, 23, 162, 38, 125, 13, 182, 156, 84, 241, 167, 89, 149, 88, 8, + 230, 195, 229, 146, 160, 0, 1, 47, 111, 74, 49, 162, 52, 176, 145, 124, + 232, 32, 165, 128, 84, 199, 78, 11, 72, 213, 54, 42, 129, 130, 26, 154, + 194, 80, 96, 137, 9, 72, 252, 165, 145, 2, 138, 126, 92, 92, 83, 176, + 191, 51, 226, 113, 145, 180, 180, 199, 78, 213, 31, 237, 162, 15, 95, 136, + 128, 226, 239, 221, 24, 63, 177, 115, 144, 40, 99, 21, 41, 5, 164, 58, + 118, 250, 144, 196, 169, 139, 122, 192, 75, 64, 205, 153, 232, 148, 18, 19, + 144, 24, 188, 138, 17, 80, 92, 135, 85, 187, 200, 146, 170, 187, 139, 94, + 98, 87, 24, 141, 29, 7, 233, 217, 170, 222, 29, 145, 181, 85, 97, 2, + 10, 230, 118, 69, 124, 157, 65, 239, 150, 152, 95, 132, 72, 43, 32, 209, + 177, 211, 2, 98, 195, 132, 90, 91, 14, 168, 21, 110, 122, 116, 161, 88, + 4, 60, 141, 204, 104, 235, 216, 242, 98, 207, 209, 126, 81, 150, 228, 7, + 250, 122, 15, 111, 235, 136, 253, 141, 161, 2, 105, 108, 235, 216, 113, 168, + 167, 127, 80, 46, 242, 207, 15, 244, 247, 190, 56, 180, 135, 87, 76, 107, + 90, 213, 117, 80, 254, 5, 34, 147, 193, 129, 190, 158, 67, 187, 54, 174, + 106, 58, 185, 47, 18, 41, 10, 32, 70, 86, 32, 87, 134, 1, 16, 35, + 43, 144, 43, 195, 0, 136, 145, 21, 200, 149, 97, 0, 196, 200, 10, 228, + 202, 48, 0, 98, 100, 5, 114, 101, 24, 0, 49, 178, 2, 185, 50, 12, + 128, 24, 89, 129, 92, 25, 6, 64, 140, 172, 64, 174, 12, 3, 32, 70, + 86, 32, 87, 134, 1, 16, 35, 43, 144, 43, 195, 0, 136, 145, 21, 200, + 149, 97, 0, 196, 200, 10, 228, 202, 48, 0, 98, 100, 5, 114, 101, 24, + 0, 49, 178, 2, 185, 50, 12, 128, 24, 89, 129, 92, 25, 6, 64, 140, + 172, 64, 174, 12, 3, 32, 70, 86, 32, 87, 134, 1, 16, 35, 43, 144, + 43, 195, 0, 136, 145, 21, 200, 149, 97, 0, 196, 200, 10, 228, 202, 48, + 0, 98, 100, 5, 114, 101, 24, 0, 49, 178, 2, 185, 50, 12, 128, 24, + 89, 129, 92, 25, 6, 64, 140, 172, 64, 174, 12, 3, 32, 70, 86, 32, + 87, 134, 1, 16, 35, 43, 144, 43, 195, 0, 136, 145, 21, 200, 149, 97, + 0, 196, 200, 10, 228, 202, 48, 0, 98, 100, 5, 114, 101, 24, 0, 49, + 178, 2, 185, 50, 12, 128, 24, 89, 129, 92, 25, 6, 64, 140, 172, 64, + 174, 12, 3, 32, 70, 86, 32, 87, 134, 1, 16, 35, 43, 144, 43, 195, + 0, 136, 145, 21, 200, 149, 97, 0, 196, 200, 10, 228, 202, 48, 0, 98, + 100, 5, 114, 101, 24, 0, 49, 178, 2, 185, 50, 12, 128, 24, 89, 129, + 92, 25, 6, 64, 12, 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, + 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, 97, 24, + 134, 97, 24, 134, 97, 24, 134, 97, 24, 134, 41, 97, 134, 143, 25, 247, + 113, 4, 193, 185, 227, 198, 12, 71, 144, 97, 78, 43, 163, 46, 153, 183, + 184, 245, 171, 243, 177, 5, 230, 125, 181, 117, 241, 255, 184, 100, 20, 182, + 24, 230, 52, 49, 252, 226, 121, 75, 114, 185, 214, 150, 150, 214, 49, 136, + 81, 140, 89, 186, 180, 165, 53, 151, 107, 153, 127, 49, 151, 131, 204, 233, + 99, 248, 165, 11, 148, 125, 130, 220, 231, 134, 33, 82, 112, 214, 205, 57, + 21, 41, 28, 92, 112, 41, 43, 200, 156, 46, 206, 255, 170, 182, 79, 146, + 187, 24, 145, 130, 49, 218, 63, 73, 235, 87, 125, 69, 35, 195, 12, 33, + 231, 139, 154, 214, 193, 44, 2, 81, 0, 42, 90, 207, 71, 36, 195, 12, + 53, 31, 111, 241, 4, 108, 201, 185, 69, 221, 24, 175, 92, 20, 59, 156, + 135, 88, 134, 25, 106, 70, 181, 24, 170, 229, 230, 159, 255, 159, 63, 121, + 233, 165, 159, 188, 248, 252, 249, 70, 1, 184, 180, 229, 92, 236, 204, 48, + 67, 205, 240, 197, 134, 128, 45, 173, 162, 207, 33, 105, 245, 69, 46, 225, + 177, 24, 230, 116, 49, 252, 75, 166, 107, 78, 125, 108, 84, 203, 66, 192, + 197, 220, 11, 102, 78, 27, 159, 243, 9, 72, 209, 186, 224, 44, 236, 203, + 48, 67, 206, 60, 163, 181, 71, 147, 11, 76, 145, 48, 204, 208, 49, 252, + 230, 228, 18, 240, 243, 220, 6, 100, 134, 16, 179, 69, 247, 9, 95, 31, + 36, 130, 214, 197, 151, 96, 119, 137, 49, 93, 194, 48, 133, 51, 110, 241, + 37, 142, 67, 163, 230, 97, 22, 46, 129, 214, 220, 124, 167, 16, 28, 246, + 137, 47, 141, 67, 144, 97, 78, 130, 79, 182, 230, 114, 159, 215, 3, 206, + 99, 22, 39, 182, 255, 28, 114, 139, 241, 150, 207, 229, 114, 185, 75, 85, + 144, 97, 78, 130, 49, 114, 224, 57, 215, 58, 239, 92, 203, 186, 212, 28, + 131, 78, 162, 181, 69, 104, 55, 234, 47, 90, 133, 178, 173, 75, 121, 110, + 152, 57, 73, 206, 213, 109, 190, 165, 185, 37, 151, 252, 121, 186, 234, 215, + 161, 53, 119, 211, 37, 139, 115, 106, 128, 176, 117, 49, 79, 141, 48, 39, + 197, 112, 119, 141, 65, 107, 174, 213, 55, 218, 156, 2, 241, 22, 132, 114, + 159, 227, 161, 105, 230, 100, 184, 41, 117, 163, 47, 158, 220, 127, 195, 1, + 195, 76, 152, 243, 232, 134, 205, 155, 214, 62, 56, 123, 82, 25, 98, 52, + 23, 76, 191, 127, 221, 230, 39, 254, 230, 182, 218, 114, 68, 72, 42, 27, + 174, 153, 174, 168, 159, 92, 133, 40, 147, 242, 186, 175, 175, 125, 98, 243, + 186, 251, 26, 42, 17, 97, 89, 147, 241, 6, 135, 107, 166, 87, 32, 133, + 57, 243, 25, 83, 112, 169, 23, 193, 210, 86, 99, 233, 160, 65, 89, 243, + 207, 7, 109, 144, 239, 126, 208, 115, 99, 242, 166, 119, 17, 109, 247, 60, + 236, 234, 84, 241, 10, 226, 4, 239, 191, 188, 122, 10, 162, 193, 133, 143, + 190, 137, 52, 187, 239, 251, 147, 116, 92, 85, 63, 98, 60, 30, 213, 41, + 204, 153, 207, 240, 5, 5, 181, 250, 226, 104, 93, 252, 239, 112, 80, 147, + 73, 47, 64, 10, 240, 4, 226, 135, 175, 118, 181, 148, 188, 51, 19, 241, + 117, 136, 0, 249, 237, 227, 145, 32, 105, 62, 134, 104, 197, 191, 61, 168, + 198, 142, 234, 177, 105, 240, 115, 181, 55, 83, 4, 12, 85, 5, 44, 201, + 253, 119, 28, 212, 224, 143, 221, 82, 14, 252, 131, 142, 31, 241, 44, 182, + 93, 238, 209, 9, 33, 157, 250, 26, 116, 130, 224, 219, 136, 114, 217, 42, + 219, 157, 115, 176, 97, 208, 205, 35, 227, 197, 194, 144, 10, 120, 19, 14, + 234, 81, 19, 170, 30, 215, 171, 248, 225, 7, 176, 105, 240, 5, 149, 18, + 46, 207, 6, 235, 84, 130, 101, 125, 3, 17, 6, 143, 139, 232, 102, 132, + 13, 122, 252, 109, 77, 230, 204, 101, 40, 171, 224, 47, 133, 250, 193, 103, + 31, 129, 17, 30, 186, 170, 125, 20, 91, 38, 3, 159, 150, 41, 68, 133, + 250, 166, 110, 55, 54, 96, 211, 71, 179, 101, 93, 135, 160, 193, 17, 245, + 6, 166, 24, 144, 143, 90, 14, 9, 75, 253, 143, 112, 42, 30, 128, 16, + 30, 239, 40, 153, 62, 237, 107, 255, 57, 108, 149, 73, 132, 128, 246, 3, + 50, 97, 248, 171, 216, 242, 209, 91, 97, 77, 65, 208, 224, 7, 242, 13, + 76, 113, 48, 100, 195, 48, 225, 22, 96, 101, 31, 132, 16, 28, 251, 213, + 123, 242, 229, 43, 42, 225, 123, 42, 74, 146, 63, 246, 62, 66, 162, 174, + 157, 32, 146, 40, 1, 223, 148, 195, 52, 70, 65, 215, 103, 28, 183, 217, + 42, 219, 249, 166, 96, 0, 219, 199, 68, 184, 199, 233, 209, 48, 69, 192, + 240, 207, 15, 137, 129, 185, 5, 225, 129, 104, 175, 117, 182, 185, 182, 162, + 172, 178, 110, 221, 192, 38, 213, 56, 171, 112, 59, 179, 59, 167, 84, 84, + 45, 116, 21, 92, 41, 210, 28, 1, 239, 175, 95, 248, 51, 4, 109, 91, + 182, 2, 159, 68, 216, 126, 109, 250, 136, 17, 13, 110, 113, 248, 172, 72, + 42, 19, 172, 199, 118, 189, 220, 144, 153, 48, 197, 194, 121, 133, 204, 255, + 70, 209, 218, 66, 60, 167, 185, 19, 82, 216, 247, 33, 98, 180, 126, 249, + 99, 68, 219, 59, 149, 42, 245, 78, 133, 124, 64, 110, 32, 60, 93, 132, + 221, 94, 239, 253, 66, 90, 167, 212, 235, 85, 7, 185, 208, 25, 15, 124, + 15, 35, 136, 235, 176, 93, 171, 55, 153, 34, 226, 146, 128, 128, 75, 150, + 32, 16, 67, 112, 31, 106, 57, 76, 249, 59, 144, 66, 150, 82, 38, 43, + 17, 63, 80, 173, 183, 157, 26, 249, 95, 69, 85, 235, 8, 40, 107, 209, + 242, 163, 216, 216, 108, 89, 87, 32, 104, 207, 209, 239, 153, 133, 77, 199, + 56, 71, 64, 167, 203, 204, 20, 15, 163, 124, 15, 28, 45, 187, 123, 207, + 158, 221, 203, 177, 17, 193, 114, 177, 207, 221, 203, 176, 33, 33, 31, 211, + 172, 118, 74, 182, 96, 147, 108, 3, 226, 159, 196, 118, 45, 182, 7, 133, + 144, 166, 128, 214, 118, 108, 188, 224, 141, 246, 29, 61, 91, 189, 197, 179, + 27, 66, 178, 128, 197, 203, 185, 134, 128, 203, 254, 247, 9, 121, 25, 63, + 216, 31, 163, 224, 242, 159, 124, 32, 247, 57, 177, 207, 83, 112, 105, 75, + 224, 139, 220, 36, 174, 87, 127, 128, 8, 135, 167, 145, 128, 177, 103, 175, + 122, 157, 18, 16, 112, 53, 54, 142, 120, 165, 230, 211, 234, 29, 130, 31, + 32, 2, 7, 97, 1, 139, 23, 67, 192, 229, 255, 130, 235, 104, 159, 248, + 26, 162, 66, 220, 245, 27, 236, 98, 191, 125, 7, 162, 104, 1, 29, 151, + 142, 201, 161, 151, 97, 85, 53, 245, 51, 103, 214, 79, 148, 173, 190, 151, + 144, 112, 157, 218, 77, 224, 116, 41, 234, 3, 2, 222, 135, 141, 238, 50, + 119, 228, 112, 157, 122, 131, 192, 49, 238, 155, 254, 77, 22, 176, 248, 240, + 4, 92, 246, 182, 184, 132, 249, 67, 91, 182, 245, 136, 66, 240, 175, 16, + 25, 224, 14, 81, 68, 246, 108, 251, 159, 135, 242, 98, 215, 227, 78, 25, + 72, 10, 232, 140, 28, 203, 166, 157, 213, 160, 199, 73, 242, 175, 142, 183, + 172, 95, 170, 160, 238, 104, 40, 156, 5, 8, 13, 1, 1, 157, 98, 175, + 123, 152, 91, 24, 62, 166, 222, 32, 120, 12, 17, 223, 214, 155, 44, 96, + 241, 226, 9, 184, 79, 92, 193, 35, 141, 35, 71, 142, 188, 172, 109, 192, + 254, 39, 68, 10, 114, 70, 123, 239, 13, 123, 160, 253, 50, 177, 75, 227, + 97, 177, 243, 143, 17, 73, 10, 232, 172, 43, 120, 119, 132, 216, 112, 135, + 241, 68, 41, 231, 148, 128, 110, 219, 48, 170, 4, 124, 24, 27, 175, 120, + 115, 39, 223, 83, 111, 16, 56, 198, 97, 229, 11, 11, 88, 188, 184, 2, + 222, 46, 218, 118, 221, 151, 143, 188, 236, 178, 203, 62, 117, 78, 83, 222, + 118, 43, 225, 103, 142, 255, 122, 47, 130, 45, 119, 218, 249, 185, 231, 92, + 36, 118, 25, 121, 249, 17, 219, 254, 16, 77, 69, 82, 192, 26, 56, 145, + 159, 40, 54, 102, 98, 67, 26, 226, 180, 1, 245, 168, 180, 209, 6, 20, + 61, 90, 159, 128, 107, 177, 241, 188, 87, 24, 238, 84, 239, 16, 252, 8, + 17, 114, 240, 80, 192, 2, 22, 47, 174, 128, 187, 197, 5, 108, 146, 254, + 9, 62, 182, 197, 222, 135, 161, 150, 187, 229, 133, 189, 91, 135, 151, 236, + 181, 183, 99, 143, 145, 77, 34, 122, 183, 142, 38, 5, 188, 200, 153, 157, + 88, 40, 54, 92, 1, 175, 180, 172, 199, 17, 220, 172, 247, 115, 135, 88, + 242, 162, 122, 246, 9, 232, 44, 89, 120, 194, 235, 5, 255, 10, 227, 221, + 110, 47, 184, 89, 111, 179, 128, 197, 139, 35, 224, 162, 103, 108, 251, 232, + 31, 202, 210, 77, 235, 245, 186, 138, 109, 89, 244, 67, 121, 97, 159, 89, + 164, 183, 126, 106, 55, 67, 192, 79, 93, 214, 107, 219, 123, 117, 52, 41, + 96, 153, 104, 73, 42, 94, 21, 210, 84, 214, 127, 230, 95, 213, 134, 40, + 229, 156, 210, 236, 61, 44, 121, 118, 10, 58, 217, 91, 49, 5, 172, 116, + 214, 210, 60, 224, 117, 169, 157, 134, 163, 89, 162, 74, 88, 192, 226, 197, + 21, 112, 175, 109, 31, 190, 232, 83, 90, 175, 145, 245, 246, 27, 42, 182, + 101, 201, 30, 121, 97, 29, 1, 95, 183, 27, 33, 224, 101, 35, 15, 217, + 246, 223, 199, 8, 104, 109, 85, 74, 8, 116, 215, 245, 53, 21, 54, 134, + 90, 236, 77, 42, 222, 157, 9, 17, 53, 173, 79, 192, 71, 16, 150, 157, + 147, 17, 206, 194, 194, 87, 213, 212, 71, 149, 35, 247, 251, 23, 200, 77, + 22, 176, 152, 113, 171, 224, 191, 19, 253, 91, 81, 176, 105, 187, 102, 216, + 63, 209, 177, 62, 1, 151, 252, 216, 158, 225, 150, 128, 221, 182, 189, 71, + 87, 211, 180, 128, 222, 92, 240, 206, 218, 242, 225, 181, 122, 206, 87, 8, + 232, 182, 249, 236, 205, 147, 43, 71, 47, 116, 215, 12, 62, 44, 222, 227, + 8, 56, 199, 170, 88, 33, 59, 218, 18, 53, 221, 230, 140, 251, 217, 47, + 55, 84, 86, 78, 119, 231, 130, 165, 180, 18, 22, 176, 120, 113, 5, 252, + 171, 143, 236, 188, 83, 190, 125, 172, 195, 126, 74, 199, 250, 75, 192, 221, + 118, 231, 199, 244, 30, 35, 255, 68, 8, 114, 167, 142, 165, 5, 172, 84, + 11, 96, 52, 239, 252, 10, 58, 213, 136, 132, 239, 235, 160, 32, 223, 231, + 52, 20, 69, 88, 62, 228, 225, 8, 216, 251, 51, 167, 145, 135, 182, 162, + 177, 240, 185, 223, 88, 230, 42, 219, 151, 18, 22, 176, 120, 113, 5, 108, + 121, 195, 182, 159, 27, 169, 12, 28, 249, 95, 251, 79, 96, 236, 197, 47, + 224, 178, 19, 255, 119, 154, 222, 99, 228, 46, 219, 254, 103, 29, 25, 33, + 160, 59, 120, 103, 34, 5, 172, 113, 202, 54, 31, 170, 131, 235, 86, 207, + 30, 121, 209, 108, 20, 189, 14, 93, 131, 7, 56, 230, 60, 205, 196, 2, + 22, 47, 158, 128, 119, 126, 104, 219, 27, 255, 112, 164, 96, 90, 183, 83, + 0, 6, 4, 20, 69, 96, 143, 28, 41, 28, 121, 89, 151, 109, 255, 246, + 46, 68, 70, 8, 88, 41, 186, 41, 1, 84, 49, 103, 253, 13, 182, 76, + 6, 165, 154, 148, 128, 120, 142, 201, 237, 118, 152, 56, 5, 32, 11, 88, + 196, 120, 2, 182, 60, 245, 145, 168, 252, 58, 254, 178, 109, 203, 160, 189, + 15, 81, 45, 75, 124, 189, 224, 150, 150, 189, 246, 224, 182, 182, 185, 29, + 162, 23, 240, 209, 223, 33, 42, 74, 64, 175, 127, 225, 146, 87, 11, 239, + 43, 126, 129, 77, 3, 61, 42, 24, 22, 240, 53, 116, 51, 40, 107, 213, + 34, 106, 5, 11, 88, 188, 24, 2, 182, 220, 45, 39, 227, 4, 39, 246, + 32, 194, 41, 1, 127, 232, 173, 191, 250, 91, 181, 94, 193, 182, 143, 99, + 108, 80, 16, 37, 160, 53, 235, 223, 244, 190, 46, 121, 185, 236, 217, 178, + 46, 116, 166, 227, 92, 100, 15, 68, 16, 18, 240, 53, 253, 6, 65, 153, + 215, 116, 4, 79, 122, 79, 180, 179, 128, 197, 139, 41, 96, 75, 110, 247, + 254, 183, 222, 122, 125, 207, 237, 216, 148, 44, 63, 110, 219, 191, 49, 87, + 199, 44, 219, 243, 211, 183, 222, 218, 255, 148, 177, 146, 58, 82, 64, 171, + 46, 248, 40, 7, 158, 243, 29, 177, 9, 219, 154, 99, 88, 85, 21, 20, + 48, 191, 201, 252, 122, 132, 149, 94, 143, 69, 48, 248, 168, 177, 244, 217, + 89, 17, 205, 2, 22, 31, 62, 1, 53, 254, 229, 166, 203, 247, 252, 48, + 97, 129, 96, 180, 128, 214, 217, 247, 24, 189, 135, 129, 151, 110, 115, 165, + 105, 56, 224, 214, 207, 239, 172, 190, 16, 145, 214, 133, 122, 184, 90, 49, + 248, 90, 231, 21, 136, 6, 147, 54, 185, 29, 224, 247, 55, 251, 190, 53, + 193, 89, 155, 16, 120, 3, 83, 4, 16, 2, 6, 88, 226, 54, 0, 35, + 136, 17, 208, 178, 134, 215, 173, 124, 252, 71, 7, 158, 222, 190, 110, 229, + 116, 255, 202, 192, 9, 95, 88, 187, 243, 192, 211, 79, 60, 220, 224, 125, + 95, 135, 101, 141, 190, 110, 142, 102, 102, 93, 53, 241, 112, 199, 133, 179, + 86, 111, 127, 246, 217, 237, 171, 103, 97, 121, 191, 67, 229, 204, 21, 15, + 127, 227, 129, 133, 117, 196, 91, 152, 51, 156, 100, 1, 19, 137, 21, 144, + 97, 98, 57, 55, 169, 124, 75, 193, 34, 22, 144, 57, 89, 254, 227, 222, + 61, 187, 239, 186, 227, 246, 220, 151, 33, 83, 65, 124, 57, 183, 236, 142, + 187, 238, 222, 179, 247, 63, 225, 96, 12, 83, 40, 147, 228, 188, 196, 71, + 31, 252, 250, 237, 55, 246, 239, 251, 225, 110, 243, 89, 163, 88, 150, 237, + 222, 243, 247, 251, 223, 248, 151, 227, 31, 252, 86, 54, 254, 39, 227, 96, + 12, 83, 40, 254, 137, 49, 44, 194, 2, 203, 110, 95, 230, 114, 187, 223, + 205, 159, 226, 13, 154, 192, 23, 249, 13, 13, 85, 206, 24, 52, 83, 202, + 156, 119, 215, 238, 61, 251, 220, 178, 236, 184, 249, 148, 240, 79, 62, 240, + 177, 31, 209, 146, 86, 57, 100, 237, 150, 155, 119, 69, 252, 126, 112, 245, + 13, 183, 124, 246, 28, 132, 11, 231, 70, 172, 54, 101, 74, 154, 115, 151, + 180, 44, 146, 253, 16, 209, 154, 187, 243, 109, 219, 89, 131, 32, 89, 174, + 106, 87, 143, 143, 140, 225, 192, 220, 113, 251, 56, 90, 142, 226, 221, 75, + 232, 78, 72, 67, 231, 172, 250, 91, 59, 3, 35, 38, 233, 169, 60, 121, + 119, 153, 226, 193, 24, 134, 89, 244, 186, 253, 129, 49, 9, 114, 167, 40, + 16, 95, 127, 3, 188, 126, 220, 246, 30, 19, 145, 203, 98, 236, 55, 220, + 238, 115, 196, 48, 204, 191, 239, 146, 238, 93, 223, 174, 183, 24, 134, 196, + 252, 102, 132, 159, 218, 191, 117, 31, 246, 85, 15, 137, 236, 113, 37, 91, + 244, 148, 237, 174, 144, 17, 44, 255, 208, 104, 46, 70, 252, 128, 245, 85, + 234, 139, 213, 46, 88, 33, 254, 171, 186, 118, 214, 88, 203, 42, 155, 88, + 222, 48, 171, 202, 26, 59, 187, 94, 38, 84, 92, 45, 227, 20, 85, 215, + 94, 91, 101, 89, 23, 85, 85, 93, 255, 167, 191, 39, 54, 207, 153, 121, + 109, 101, 245, 239, 91, 99, 71, 91, 21, 227, 43, 174, 190, 86, 173, 185, + 170, 187, 225, 191, 200, 23, 166, 228, 24, 229, 253, 56, 220, 146, 31, 219, + 246, 29, 158, 114, 123, 221, 135, 145, 36, 95, 115, 87, 224, 11, 22, 45, + 255, 200, 89, 50, 45, 136, 248, 1, 235, 27, 110, 68, 192, 154, 216, 217, + 124, 195, 250, 26, 171, 178, 243, 47, 111, 104, 235, 172, 93, 121, 253, 26, + 209, 186, 171, 90, 115, 227, 13, 235, 255, 72, 37, 143, 239, 108, 110, 22, + 53, 245, 204, 85, 183, 93, 255, 168, 40, 47, 43, 58, 219, 102, 221, 219, + 57, 193, 186, 165, 217, 170, 89, 243, 197, 217, 43, 190, 91, 110, 89, 43, + 30, 152, 217, 193, 77, 194, 146, 100, 152, 247, 45, 169, 82, 185, 31, 255, + 237, 238, 187, 239, 188, 99, 249, 178, 214, 47, 47, 218, 111, 127, 100, 148, + 135, 119, 252, 214, 126, 125, 81, 75, 235, 178, 219, 239, 184, 243, 107, 187, + 159, 218, 103, 219, 251, 92, 29, 91, 23, 144, 223, 202, 220, 236, 10, 216, + 222, 96, 89, 211, 31, 178, 42, 182, 212, 88, 214, 67, 93, 21, 86, 213, + 250, 223, 183, 218, 175, 183, 172, 250, 111, 169, 228, 213, 162, 68, 188, 254, + 175, 173, 207, 110, 40, 183, 126, 111, 253, 104, 171, 249, 94, 81, 26, 110, + 25, 47, 59, 33, 19, 255, 151, 168, 197, 69, 114, 221, 106, 225, 229, 122, + 234, 135, 27, 152, 162, 231, 47, 220, 117, 45, 250, 9, 56, 217, 221, 248, + 240, 196, 241, 183, 255, 233, 132, 175, 75, 178, 236, 55, 246, 7, 111, 188, + 117, 252, 132, 30, 248, 19, 120, 107, 4, 115, 243, 112, 40, 63, 82, 192, + 234, 171, 234, 167, 136, 238, 132, 216, 26, 223, 97, 157, 211, 41, 202, 178, + 217, 15, 137, 141, 53, 99, 203, 58, 43, 100, 89, 39, 87, 84, 85, 117, + 150, 89, 214, 216, 53, 214, 204, 219, 196, 198, 183, 166, 88, 171, 101, 101, + 219, 49, 65, 10, 88, 211, 33, 130, 183, 220, 96, 221, 43, 191, 171, 252, + 17, 181, 54, 154, 41, 53, 46, 246, 22, 86, 221, 137, 181, 126, 14, 111, + 35, 94, 241, 22, 34, 193, 7, 206, 122, 104, 33, 32, 253, 27, 33, 82, + 192, 41, 55, 182, 117, 9, 201, 198, 207, 110, 94, 185, 90, 8, 120, 182, + 165, 53, 235, 24, 127, 246, 198, 135, 218, 219, 31, 218, 32, 23, 34, 140, + 221, 210, 222, 222, 190, 74, 8, 248, 69, 177, 177, 170, 214, 90, 35, 215, + 108, 65, 64, 81, 242, 89, 205, 205, 214, 67, 29, 98, 151, 46, 22, 176, + 36, 49, 191, 169, 124, 249, 93, 119, 239, 222, 179, 119, 223, 254, 215, 255, + 249, 237, 95, 159, 248, 240, 195, 103, 16, 173, 120, 230, 195, 15, 79, 252, + 250, 237, 183, 94, 223, 191, 111, 239, 158, 167, 238, 190, 203, 27, 147, 105, + 37, 190, 30, 85, 162, 219, 128, 178, 148, 187, 170, 179, 97, 242, 181, 126, + 1, 43, 58, 39, 86, 87, 87, 95, 36, 247, 24, 223, 57, 190, 186, 122, + 108, 149, 117, 173, 76, 161, 5, 124, 228, 106, 177, 243, 104, 111, 1, 42, + 83, 74, 24, 69, 160, 100, 145, 26, 22, 108, 205, 45, 91, 30, 88, 6, + 184, 124, 249, 50, 245, 227, 112, 122, 7, 143, 220, 39, 112, 160, 0, 13, + 106, 0, 230, 130, 206, 242, 97, 157, 19, 133, 102, 126, 1, 203, 85, 237, + 171, 24, 189, 70, 191, 58, 2, 118, 200, 47, 243, 16, 255, 25, 2, 62, + 192, 43, 77, 75, 153, 121, 167, 244, 61, 209, 17, 45, 64, 209, 182, 219, + 32, 123, 13, 163, 215, 151, 149, 117, 138, 70, 224, 181, 178, 13, 232, 10, + 56, 193, 250, 150, 116, 74, 173, 223, 43, 147, 126, 138, 160, 35, 224, 95, + 207, 182, 172, 242, 13, 170, 19, 226, 8, 56, 83, 186, 204, 139, 253, 74, + 149, 83, 250, 166, 242, 220, 2, 234, 55, 186, 20, 159, 93, 83, 63, 161, + 174, 67, 232, 180, 114, 101, 205, 245, 143, 172, 177, 206, 17, 157, 95, 235, + 122, 57, 46, 248, 221, 137, 86, 77, 103, 221, 196, 230, 27, 212, 126, 117, + 223, 173, 157, 120, 235, 159, 89, 215, 127, 93, 132, 133, 151, 227, 187, 174, + 154, 220, 38, 122, 193, 183, 162, 19, 114, 227, 141, 86, 121, 71, 243, 132, + 250, 118, 174, 130, 75, 149, 81, 11, 78, 218, 192, 220, 2, 114, 12, 80, + 83, 243, 197, 246, 219, 228, 58, 133, 138, 91, 218, 255, 180, 226, 207, 172, + 242, 233, 162, 16, 155, 40, 187, 18, 242, 215, 46, 39, 180, 173, 156, 141, + 197, 208, 83, 86, 172, 188, 186, 92, 167, 212, 143, 182, 172, 63, 186, 119, + 69, 141, 40, 35, 167, 212, 88, 23, 92, 37, 162, 106, 106, 196, 17, 154, + 219, 111, 197, 243, 36, 76, 9, 50, 106, 126, 97, 63, 86, 237, 208, 154, + 155, 31, 227, 223, 169, 208, 169, 250, 39, 204, 239, 10, 103, 141, 107, 209, + 63, 126, 94, 8, 75, 115, 45, 227, 78, 199, 15, 3, 142, 45, 43, 187, + 90, 214, 189, 204, 239, 18, 31, 159, 183, 180, 48, 5, 197, 238, 243, 35, + 150, 97, 157, 26, 101, 247, 118, 116, 172, 62, 233, 53, 52, 76, 209, 50, + 102, 94, 75, 250, 159, 237, 111, 205, 181, 204, 15, 255, 60, 220, 16, 81, + 201, 147, 110, 191, 155, 124, 124, 220, 130, 165, 185, 228, 214, 96, 107, 46, + 183, 116, 193, 159, 159, 135, 55, 49, 204, 208, 49, 236, 252, 113, 55, 47, + 17, 130, 181, 210, 69, 225, 210, 86, 153, 214, 114, 243, 184, 255, 192, 63, + 10, 205, 156, 46, 70, 141, 25, 55, 111, 193, 98, 89, 206, 73, 90, 21, + 8, 183, 44, 94, 48, 111, 220, 152, 211, 212, 241, 101, 24, 151, 179, 70, + 157, 55, 230, 146, 113, 55, 205, 155, 63, 255, 230, 207, 11, 110, 158, 63, + 127, 222, 77, 227, 46, 25, 115, 222, 168, 179, 176, 3, 195, 48, 12, 195, + 48, 12, 195, 48, 12, 195, 48, 12, 195, 48, 12, 195, 48, 12, 195, 48, + 12, 195, 48, 12, 195, 48, 12, 195, 48, 12, 195, 48, 103, 52, 150, 245, + 255, 0, 128, 20, 24, 163, 171, 37, 166, 53, 0, 0, 0, 0, 73, 69, + 78, 68, 174, 66, 96, 130 +}; + +const unsigned int Bin_NoSignalVerticalPNG_size = 9623; +const unsigned char Bin_NoSignalVerticalPNG[] = { + 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, + 0, 0, 1, 104, 0, 0, 2, 128, 8, 3, 0, 0, 0, 134, 196, 18, + 149, 0, 0, 0, 1, 115, 82, 71, 66, 0, 174, 206, 28, 233, 0, 0, + 0, 4, 103, 65, 77, 65, 0, 0, 177, 143, 11, 252, 97, 5, 0, 0, + 3, 0, 80, 76, 84, 69, 32, 37, 49, 32, 39, 52, 33, 40, 53, 37, + 41, 53, 39, 44, 55, 35, 43, 57, 41, 45, 57, 43, 48, 59, 44, 48, + 59, 45, 49, 61, 47, 52, 63, 49, 52, 61, 56, 55, 57, 58, 57, 59, + 36, 47, 64, 36, 50, 67, 38, 54, 72, 38, 56, 76, 40, 58, 78, 41, + 61, 82, 49, 53, 64, 51, 56, 66, 52, 56, 67, 53, 57, 68, 55, 60, + 70, 58, 60, 68, 58, 62, 72, 42, 65, 87, 43, 68, 91, 55, 65, 79, + 59, 64, 74, 60, 64, 74, 62, 66, 76, 60, 70, 84, 45, 71, 96, 45, + 73, 98, 47, 78, 106, 48, 79, 107, 48, 80, 109, 49, 83, 113, 52, 91, + 123, 64, 63, 65, 65, 64, 66, 64, 68, 78, 72, 71, 73, 76, 76, 76, + 66, 70, 80, 67, 72, 82, 68, 72, 82, 70, 74, 84, 72, 75, 84, 72, + 77, 86, 75, 78, 88, 77, 81, 90, 79, 83, 92, 84, 84, 84, 80, 83, + 91, 81, 85, 94, 88, 87, 89, 91, 91, 91, 83, 87, 96, 85, 88, 97, + 87, 91, 100, 90, 93, 102, 92, 95, 104, 92, 96, 103, 94, 97, 105, 96, + 95, 97, 99, 99, 99, 96, 99, 106, 97, 100, 107, 98, 101, 110, 100, 103, + 109, 101, 104, 111, 107, 107, 107, 100, 103, 112, 102, 106, 113, 104, 106, 113, + 104, 107, 116, 106, 108, 114, 106, 109, 117, 108, 110, 117, 110, 112, 118, 109, + 112, 120, 115, 115, 115, 114, 116, 123, 118, 120, 125, 123, 123, 123, 53, 94, + 128, 54, 97, 132, 56, 100, 135, 56, 100, 136, 57, 105, 142, 59, 108, 148, + 60, 111, 152, 60, 113, 154, 62, 118, 161, 63, 120, 164, 64, 121, 165, 65, + 125, 170, 118, 121, 128, 120, 122, 128, 121, 124, 129, 122, 125, 132, 125, 126, + 129, 124, 127, 132, 62, 134, 187, 66, 128, 174, 67, 131, 179, 64, 135, 187, + 70, 139, 190, 72, 140, 191, 126, 128, 133, 126, 129, 136, 71, 140, 192, 72, + 142, 194, 73, 144, 197, 75, 148, 202, 84, 148, 195, 88, 150, 197, 92, 153, + 198, 98, 157, 200, 103, 160, 202, 109, 163, 204, 113, 166, 205, 116, 168, 206, + 123, 172, 209, 131, 131, 131, 128, 131, 137, 129, 132, 138, 130, 133, 140, 132, + 134, 139, 133, 135, 140, 133, 136, 141, 138, 138, 139, 135, 137, 144, 136, 138, + 145, 137, 140, 145, 139, 142, 148, 140, 142, 145, 140, 143, 149, 142, 144, 149, + 143, 146, 152, 147, 147, 147, 144, 147, 153, 146, 148, 154, 148, 149, 152, 148, + 150, 156, 150, 152, 156, 154, 155, 156, 152, 154, 160, 154, 156, 162, 156, 158, + 161, 157, 159, 164, 159, 160, 162, 158, 160, 165, 162, 162, 162, 161, 163, 168, + 162, 164, 169, 164, 166, 169, 165, 167, 172, 166, 168, 172, 169, 169, 169, 168, + 170, 175, 174, 174, 174, 170, 172, 176, 172, 174, 179, 174, 176, 180, 176, 175, + 176, 177, 177, 177, 176, 178, 182, 179, 180, 180, 180, 180, 180, 179, 181, 185, + 182, 184, 187, 185, 185, 185, 184, 186, 190, 186, 188, 191, 189, 189, 189, 132, + 178, 212, 137, 181, 214, 141, 184, 215, 142, 184, 216, 148, 188, 217, 152, 190, + 219, 187, 189, 192, 189, 190, 194, 157, 193, 220, 161, 196, 222, 191, 192, 196, + 165, 199, 224, 166, 200, 224, 170, 202, 225, 176, 206, 228, 181, 209, 229, 186, + 211, 231, 189, 214, 232, 193, 193, 193, 192, 194, 197, 194, 196, 199, 197, 197, + 197, 195, 196, 200, 196, 197, 200, 199, 200, 203, 199, 201, 204, 201, 201, 201, + 200, 201, 204, 203, 204, 207, 205, 205, 205, 205, 206, 209, 207, 208, 211, 209, + 209, 209, 208, 209, 212, 211, 212, 214, 213, 213, 213, 213, 214, 216, 215, 216, + 218, 218, 218, 218, 218, 218, 220, 221, 221, 221, 196, 218, 234, 202, 222, 236, + 221, 222, 224, 206, 224, 238, 209, 226, 239, 223, 224, 225, 212, 228, 240, 216, + 231, 241, 220, 233, 242, 224, 225, 225, 226, 226, 228, 227, 228, 229, 229, 229, + 230, 230, 231, 232, 233, 233, 233, 234, 235, 236, 235, 236, 237, 237, 237, 237, + 227, 237, 245, 239, 239, 240, 230, 240, 246, 232, 240, 247, 236, 243, 248, 241, + 240, 239, 241, 241, 241, 243, 243, 244, 245, 245, 245, 241, 246, 250, 245, 249, + 251, 249, 249, 249, 248, 250, 253, 250, 252, 253, 254, 254, 254, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 140, 254, 66, 143, 0, 0, 0, 9, 112, 72, + 89, 115, 0, 0, 14, 195, 0, 0, 14, 195, 1, 199, 111, 168, 100, 0, + 0, 34, 32, 73, 68, 65, 84, 120, 94, 237, 220, 127, 124, 23, 245, 125, + 7, 240, 43, 25, 113, 193, 50, 172, 102, 70, 25, 27, 217, 108, 145, 202, + 160, 176, 128, 44, 195, 44, 53, 99, 163, 210, 40, 32, 68, 230, 54, 134, + 45, 85, 86, 10, 169, 229, 251, 45, 226, 180, 164, 88, 137, 191, 75, 109, + 73, 101, 229, 91, 40, 40, 50, 24, 88, 42, 110, 180, 138, 27, 45, 45, + 163, 218, 90, 170, 14, 23, 131, 110, 117, 226, 32, 10, 182, 44, 139, 126, + 235, 253, 177, 207, 143, 215, 221, 189, 239, 215, 55, 1, 46, 143, 38, 238, + 245, 124, 60, 32, 119, 159, 207, 125, 127, 189, 238, 115, 159, 207, 231, 238, + 190, 137, 67, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 244, 238, 84, 125, 89, 227, 194, 217, 13, + 147, 202, 176, 90, 202, 5, 26, 150, 123, 161, 234, 124, 79, 101, 57, 138, + 254, 223, 170, 252, 122, 135, 11, 79, 214, 162, 44, 85, 173, 217, 238, 67, + 88, 139, 169, 220, 249, 83, 44, 193, 79, 205, 246, 240, 194, 186, 33, 40, + 62, 67, 21, 219, 94, 196, 210, 0, 50, 235, 117, 196, 96, 44, 68, 105, + 154, 146, 65, 151, 63, 232, 186, 79, 99, 25, 66, 65, 187, 110, 103, 13, + 202, 207, 196, 160, 245, 106, 159, 97, 121, 224, 152, 141, 8, 60, 117, 40, + 79, 81, 42, 232, 47, 233, 170, 253, 88, 129, 72, 208, 110, 59, 202, 207, + 192, 221, 250, 121, 158, 197, 202, 128, 81, 221, 101, 62, 191, 219, 245, 236, + 155, 118, 33, 114, 232, 71, 149, 10, 250, 144, 174, 250, 14, 86, 192, 6, + 253, 242, 191, 253, 232, 5, 179, 224, 186, 211, 80, 113, 250, 126, 164, 159, + 230, 25, 172, 12, 24, 155, 205, 167, 63, 210, 160, 22, 111, 51, 139, 174, + 94, 180, 206, 170, 194, 2, 84, 168, 127, 209, 160, 135, 235, 66, 120, 81, + 87, 125, 11, 43, 96, 131, 158, 169, 150, 42, 158, 52, 139, 119, 216, 114, + 213, 207, 36, 12, 169, 131, 170, 189, 241, 184, 26, 63, 65, 190, 140, 121, + 74, 217, 67, 149, 13, 31, 132, 165, 254, 171, 194, 124, 120, 215, 126, 230, + 109, 199, 127, 248, 64, 147, 215, 137, 222, 182, 255, 168, 170, 104, 47, 140, + 199, 122, 197, 182, 35, 174, 219, 113, 95, 157, 217, 222, 6, 61, 230, 225, + 231, 187, 93, 183, 184, 255, 51, 102, 205, 107, 178, 174, 251, 160, 89, 183, + 130, 160, 157, 133, 102, 241, 1, 83, 188, 240, 201, 215, 212, 114, 231, 142, + 38, 179, 86, 123, 92, 57, 234, 52, 233, 141, 159, 249, 168, 227, 220, 240, + 108, 183, 91, 124, 102, 146, 169, 83, 33, 111, 254, 169, 58, 236, 138, 63, + 188, 205, 172, 61, 99, 158, 69, 219, 97, 214, 155, 30, 87, 239, 203, 125, + 253, 145, 79, 152, 181, 126, 235, 147, 230, 45, 111, 196, 90, 160, 222, 6, + 164, 125, 201, 20, 52, 232, 216, 149, 55, 204, 255, 38, 232, 123, 205, 162, + 246, 154, 158, 172, 244, 24, 244, 54, 179, 168, 247, 74, 173, 57, 250, 141, + 167, 244, 142, 180, 135, 201, 26, 243, 191, 235, 54, 61, 128, 5, 59, 5, + 186, 163, 136, 85, 247, 88, 189, 90, 13, 7, 93, 99, 15, 19, 237, 89, + 111, 199, 244, 75, 95, 53, 239, 209, 182, 43, 225, 195, 166, 24, 190, 162, + 75, 254, 13, 43, 150, 14, 250, 27, 88, 54, 198, 149, 14, 250, 27, 179, + 103, 223, 189, 223, 44, 185, 149, 106, 42, 174, 142, 3, 159, 30, 19, 108, + 208, 49, 166, 187, 95, 135, 21, 99, 98, 36, 232, 242, 99, 88, 214, 94, + 238, 205, 105, 192, 175, 202, 14, 243, 22, 117, 183, 108, 35, 87, 14, 169, + 21, 59, 177, 222, 177, 206, 126, 14, 213, 232, 108, 203, 119, 189, 48, 85, + 208, 118, 182, 210, 190, 206, 182, 83, 245, 161, 75, 5, 29, 152, 173, 202, + 204, 139, 190, 48, 205, 105, 52, 129, 223, 151, 26, 180, 171, 186, 222, 143, + 154, 133, 151, 11, 91, 204, 207, 199, 35, 65, 111, 208, 63, 143, 52, 225, + 120, 91, 103, 95, 178, 95, 178, 57, 168, 134, 18, 4, 253, 188, 234, 247, + 204, 194, 245, 142, 51, 210, 204, 73, 182, 57, 206, 227, 250, 103, 231, 4, + 103, 188, 25, 240, 116, 208, 207, 235, 159, 122, 46, 247, 121, 83, 82, 235, + 84, 86, 234, 206, 210, 221, 81, 89, 169, 26, 173, 47, 28, 116, 81, 231, + 60, 201, 44, 234, 209, 238, 51, 122, 65, 157, 122, 216, 160, 187, 106, 207, + 183, 251, 253, 249, 235, 135, 219, 221, 167, 94, 230, 105, 253, 243, 25, 213, + 86, 237, 168, 221, 160, 94, 198, 236, 209, 253, 250, 101, 170, 77, 153, 238, + 50, 204, 59, 126, 93, 191, 96, 63, 245, 136, 121, 171, 122, 202, 229, 7, + 173, 142, 101, 243, 161, 58, 253, 122, 117, 114, 240, 51, 253, 243, 70, 85, + 240, 9, 189, 160, 18, 176, 163, 168, 153, 171, 153, 124, 245, 88, 100, 118, + 194, 22, 93, 20, 8, 5, 189, 205, 236, 2, 243, 20, 157, 195, 21, 59, + 178, 142, 67, 208, 234, 184, 26, 103, 22, 102, 57, 206, 101, 102, 161, 193, + 41, 51, 63, 77, 23, 111, 242, 93, 169, 22, 204, 46, 222, 169, 139, 26, + 245, 82, 81, 63, 211, 4, 189, 228, 94, 166, 11, 251, 39, 117, 142, 165, + 168, 182, 27, 10, 218, 28, 158, 230, 64, 188, 74, 47, 21, 29, 71, 255, + 112, 27, 85, 129, 55, 235, 168, 49, 63, 199, 232, 109, 76, 163, 91, 171, + 22, 76, 20, 145, 129, 213, 6, 189, 238, 75, 102, 111, 216, 189, 16, 234, + 117, 149, 90, 4, 61, 193, 113, 126, 199, 44, 168, 115, 38, 111, 63, 218, + 54, 171, 143, 56, 123, 80, 233, 103, 55, 239, 206, 76, 57, 130, 225, 216, + 58, 243, 57, 122, 159, 89, 105, 222, 160, 126, 215, 67, 170, 171, 171, 55, + 234, 21, 117, 42, 96, 218, 204, 26, 93, 111, 187, 72, 4, 173, 63, 135, + 205, 228, 67, 248, 57, 92, 111, 243, 175, 122, 73, 239, 22, 19, 234, 122, + 93, 20, 176, 65, 207, 116, 46, 53, 63, 221, 175, 171, 34, 219, 221, 6, + 166, 225, 201, 212, 128, 106, 131, 86, 179, 13, 27, 116, 35, 246, 167, 153, + 228, 236, 212, 75, 155, 213, 194, 83, 122, 225, 97, 93, 20, 221, 101, 177, + 65, 189, 255, 56, 223, 190, 67, 59, 145, 114, 190, 162, 151, 159, 194, 103, + 82, 61, 51, 230, 190, 170, 235, 48, 13, 82, 135, 121, 167, 94, 80, 159, + 124, 184, 249, 105, 30, 103, 122, 12, 221, 117, 152, 166, 150, 18, 180, 61, + 63, 119, 221, 15, 59, 206, 253, 250, 231, 145, 187, 140, 59, 239, 188, 243, + 142, 9, 8, 90, 141, 185, 145, 22, 221, 232, 12, 49, 63, 213, 131, 176, + 247, 117, 215, 97, 154, 182, 9, 218, 52, 147, 238, 224, 153, 122, 184, 124, + 240, 43, 101, 50, 117, 139, 77, 234, 204, 107, 146, 29, 129, 84, 208, 102, + 144, 210, 31, 220, 102, 167, 62, 148, 105, 69, 122, 38, 102, 39, 105, 170, + 137, 153, 120, 117, 3, 179, 157, 201, 165, 94, 221, 6, 181, 32, 248, 65, + 15, 182, 231, 250, 63, 113, 156, 153, 250, 231, 113, 83, 139, 43, 167, 233, + 65, 219, 120, 245, 17, 55, 209, 148, 232, 153, 180, 25, 49, 77, 39, 84, + 111, 202, 204, 147, 244, 251, 107, 176, 213, 222, 156, 214, 118, 162, 138, 10, + 186, 210, 132, 114, 100, 97, 211, 183, 76, 137, 250, 224, 118, 30, 242, 239, + 207, 183, 155, 159, 58, 232, 219, 205, 194, 134, 153, 183, 153, 109, 205, 165, + 36, 59, 178, 174, 121, 74, 79, 45, 60, 126, 208, 120, 128, 110, 250, 102, + 31, 169, 222, 182, 74, 237, 190, 226, 113, 127, 214, 145, 24, 180, 61, 157, + 220, 60, 115, 229, 113, 253, 211, 92, 225, 176, 243, 143, 181, 251, 23, 58, + 206, 79, 244, 210, 182, 50, 167, 82, 189, 180, 121, 166, 126, 204, 78, 35, + 2, 221, 250, 76, 215, 54, 105, 48, 167, 134, 118, 90, 231, 209, 157, 102, + 48, 161, 85, 31, 210, 140, 138, 247, 97, 237, 94, 189, 2, 65, 208, 78, + 167, 89, 60, 134, 17, 214, 45, 154, 198, 234, 186, 234, 148, 187, 68, 208, + 56, 132, 192, 92, 31, 88, 133, 149, 175, 122, 77, 218, 181, 7, 75, 127, + 238, 162, 181, 105, 242, 236, 202, 253, 170, 61, 6, 189, 204, 20, 123, 26, + 96, 102, 82, 138, 63, 193, 117, 42, 109, 134, 218, 17, 219, 134, 107, 240, + 129, 77, 255, 9, 34, 104, 219, 56, 245, 57, 184, 233, 165, 225, 6, 85, + 83, 42, 232, 242, 224, 116, 253, 152, 77, 114, 140, 221, 99, 102, 134, 231, + 133, 174, 217, 107, 33, 253, 88, 229, 109, 104, 91, 238, 161, 47, 250, 231, + 26, 99, 54, 154, 75, 12, 221, 79, 99, 156, 116, 174, 50, 109, 186, 96, + 231, 31, 102, 26, 224, 204, 54, 215, 69, 221, 78, 51, 63, 209, 234, 109, + 63, 164, 251, 114, 143, 8, 218, 209, 215, 145, 20, 181, 212, 240, 29, 123, + 1, 227, 141, 245, 106, 78, 39, 130, 182, 179, 185, 80, 208, 106, 31, 219, + 231, 232, 124, 192, 59, 197, 190, 204, 238, 80, 115, 105, 187, 238, 17, 251, + 154, 93, 27, 189, 55, 218, 175, 85, 142, 175, 159, 86, 55, 62, 114, 173, + 96, 120, 125, 195, 72, 44, 26, 151, 54, 212, 169, 33, 179, 76, 67, 137, + 83, 94, 51, 179, 86, 92, 192, 84, 219, 212, 215, 94, 136, 69, 203, 108, + 142, 237, 237, 50, 86, 198, 213, 207, 172, 139, 92, 11, 77, 85, 54, 225, + 170, 218, 208, 77, 176, 75, 235, 47, 51, 51, 75, 99, 76, 253, 172, 58, + 211, 117, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 209, 175, 200, 88, 234, + 11, 72, 87, 64, 5, 101, 11, 233, 10, 168, 160, 108, 33, 93, 1, 21, + 148, 45, 164, 43, 160, 130, 178, 133, 116, 5, 84, 80, 182, 144, 174, 128, + 10, 202, 22, 210, 21, 80, 65, 217, 66, 186, 2, 42, 40, 91, 72, 87, + 64, 5, 101, 11, 233, 10, 168, 160, 108, 33, 93, 1, 21, 148, 45, 164, + 43, 160, 130, 178, 133, 116, 5, 84, 80, 182, 144, 174, 128, 10, 202, 22, + 210, 21, 80, 65, 217, 66, 186, 2, 42, 40, 91, 72, 87, 64, 5, 101, + 11, 233, 10, 168, 160, 108, 33, 93, 1, 21, 148, 45, 164, 43, 160, 130, + 178, 133, 116, 5, 84, 80, 182, 144, 174, 128, 10, 202, 22, 210, 21, 80, + 65, 217, 66, 186, 2, 42, 40, 91, 72, 87, 64, 5, 101, 11, 233, 10, + 168, 160, 108, 33, 93, 1, 21, 148, 45, 164, 43, 160, 130, 178, 133, 116, + 5, 84, 80, 182, 144, 174, 128, 10, 202, 22, 210, 21, 80, 65, 217, 66, + 186, 2, 42, 40, 91, 72, 87, 64, 5, 101, 11, 233, 10, 168, 160, 108, + 33, 93, 1, 21, 148, 45, 164, 43, 160, 130, 178, 133, 116, 5, 84, 80, + 182, 144, 174, 128, 10, 202, 22, 210, 21, 80, 65, 217, 66, 186, 2, 42, + 40, 91, 72, 87, 64, 5, 101, 11, 233, 10, 168, 160, 108, 33, 93, 1, + 21, 148, 45, 164, 43, 160, 226, 140, 77, 153, 130, 133, 83, 119, 6, 15, + 29, 59, 101, 234, 148, 201, 88, 236, 87, 144, 174, 128, 138, 177, 99, 219, + 182, 110, 221, 250, 144, 181, 26, 69, 158, 213, 219, 125, 173, 40, 18, 166, + 172, 222, 122, 168, 203, 85, 186, 218, 31, 45, 76, 69, 97, 239, 204, 221, + 116, 176, 227, 184, 126, 232, 241, 246, 31, 183, 197, 30, 186, 21, 175, 169, + 204, 69, 145, 48, 185, 117, 251, 115, 230, 177, 234, 133, 15, 22, 90, 80, + 26, 88, 29, 124, 158, 54, 20, 121, 90, 241, 172, 74, 244, 163, 26, 120, + 152, 146, 84, 45, 30, 93, 64, 81, 28, 210, 21, 80, 49, 118, 236, 15, + 236, 155, 54, 34, 77, 236, 33, 20, 43, 177, 167, 110, 249, 49, 106, 224, + 64, 66, 38, 201, 90, 15, 116, 227, 49, 208, 30, 121, 242, 118, 148, 43, + 177, 253, 59, 253, 209, 34, 170, 160, 251, 161, 200, 142, 218, 142, 10, 45, + 82, 85, 64, 177, 242, 16, 138, 164, 22, 212, 41, 157, 40, 146, 196, 163, + 15, 160, 40, 14, 233, 10, 168, 8, 7, 253, 77, 148, 65, 122, 208, 45, + 135, 80, 46, 28, 236, 85, 212, 73, 143, 116, 143, 134, 2, 77, 15, 122, + 242, 163, 40, 15, 217, 30, 106, 31, 50, 232, 72, 32, 61, 4, 125, 0, + 117, 218, 28, 148, 9, 89, 6, 29, 121, 254, 212, 160, 219, 80, 26, 145, + 120, 60, 134, 76, 142, 28, 7, 190, 3, 162, 241, 165, 6, 61, 253, 8, + 138, 35, 186, 228, 11, 203, 160, 221, 240, 190, 239, 33, 104, 84, 25, 145, + 38, 167, 101, 26, 244, 33, 20, 90, 105, 65, 111, 69, 97, 204, 38, 108, + 144, 102, 242, 115, 216, 48, 174, 35, 24, 219, 210, 130, 110, 137, 116, 57, + 130, 72, 58, 20, 244, 17, 20, 90, 165, 131, 94, 141, 42, 11, 133, 66, + 166, 65, 135, 27, 101, 114, 208, 169, 173, 82, 57, 80, 114, 42, 80, 34, + 103, 213, 243, 96, 163, 212, 160, 83, 14, 35, 43, 216, 48, 20, 180, 27, + 26, 15, 75, 7, 29, 238, 211, 34, 157, 150, 146, 109, 208, 93, 40, 53, + 146, 131, 62, 136, 162, 68, 63, 192, 70, 137, 194, 25, 68, 61, 138, 173, + 82, 130, 158, 139, 162, 100, 221, 126, 63, 29, 126, 145, 34, 74, 141, 146, + 65, 79, 69, 13, 60, 135, 226, 64, 182, 65, 135, 142, 254, 196, 160, 75, + 54, 172, 146, 253, 244, 28, 108, 146, 198, 27, 32, 146, 131, 22, 165, 73, + 252, 221, 20, 217, 155, 219, 81, 172, 149, 12, 90, 84, 26, 177, 73, 126, + 198, 65, 203, 23, 72, 10, 122, 58, 10, 172, 142, 237, 15, 109, 61, 128, + 89, 173, 21, 52, 173, 152, 80, 151, 115, 168, 173, 117, 78, 203, 234, 208, + 44, 194, 203, 42, 49, 232, 80, 14, 221, 219, 87, 183, 180, 22, 194, 239, + 220, 219, 52, 122, 216, 76, 71, 185, 82, 50, 232, 78, 212, 120, 66, 163, + 146, 150, 117, 208, 226, 73, 146, 130, 150, 29, 71, 59, 122, 192, 185, 29, + 40, 208, 82, 59, 143, 41, 216, 64, 59, 238, 77, 7, 230, 202, 1, 14, + 51, 143, 164, 160, 67, 251, 119, 43, 10, 167, 200, 81, 217, 123, 223, 209, + 160, 69, 31, 80, 42, 232, 216, 225, 118, 20, 21, 190, 172, 131, 22, 83, + 162, 132, 160, 101, 199, 225, 31, 173, 225, 39, 17, 135, 123, 136, 252, 40, + 193, 52, 82, 38, 136, 253, 150, 20, 180, 60, 26, 196, 0, 39, 219, 57, + 198, 225, 216, 64, 144, 120, 84, 196, 130, 142, 61, 44, 54, 149, 206, 60, + 232, 96, 74, 148, 16, 180, 152, 55, 200, 169, 224, 228, 163, 40, 84, 210, + 222, 133, 152, 62, 137, 93, 36, 95, 31, 197, 9, 65, 79, 198, 186, 38, + 31, 44, 15, 48, 140, 14, 177, 196, 142, 219, 114, 165, 84, 208, 40, 23, + 162, 83, 233, 204, 131, 14, 90, 76, 60, 104, 57, 52, 135, 246, 184, 56, + 125, 141, 15, 35, 214, 38, 84, 43, 114, 196, 20, 13, 189, 195, 150, 36, + 4, 221, 138, 117, 165, 24, 122, 122, 241, 104, 236, 128, 120, 211, 244, 187, + 189, 18, 65, 203, 247, 239, 65, 149, 39, 251, 160, 253, 87, 136, 7, 45, + 122, 142, 200, 14, 143, 55, 173, 40, 241, 88, 175, 147, 213, 100, 99, 181, + 37, 9, 65, 139, 55, 233, 199, 102, 161, 84, 65, 167, 26, 15, 218, 255, + 60, 37, 130, 14, 186, 166, 96, 208, 8, 250, 28, 163, 15, 130, 246, 50, + 20, 99, 13, 62, 158, 136, 51, 114, 221, 76, 180, 185, 248, 20, 212, 16, + 19, 225, 227, 177, 43, 118, 82, 66, 208, 98, 200, 20, 179, 8, 77, 244, + 101, 182, 32, 33, 104, 111, 124, 78, 15, 90, 236, 237, 160, 61, 4, 167, + 80, 70, 31, 4, 237, 141, 43, 177, 160, 229, 196, 33, 114, 14, 40, 171, + 146, 99, 148, 221, 78, 123, 169, 51, 200, 120, 208, 37, 174, 171, 205, 109, + 245, 217, 130, 132, 160, 189, 55, 148, 30, 116, 48, 126, 116, 139, 99, 36, + 252, 38, 251, 34, 104, 180, 73, 241, 158, 109, 208, 226, 3, 183, 155, 2, + 65, 76, 241, 226, 23, 137, 13, 49, 96, 186, 71, 83, 182, 209, 226, 65, + 139, 94, 167, 228, 169, 167, 150, 20, 52, 58, 255, 244, 160, 131, 55, 95, + 24, 27, 92, 135, 13, 247, 82, 125, 17, 52, 166, 120, 177, 160, 197, 196, + 65, 158, 113, 25, 226, 121, 82, 58, 105, 209, 187, 40, 207, 69, 186, 192, + 64, 60, 232, 164, 9, 125, 154, 164, 160, 241, 60, 169, 65, 139, 131, 109, + 178, 120, 177, 240, 84, 58, 195, 160, 131, 254, 206, 78, 137, 190, 137, 53, + 197, 126, 62, 241, 90, 161, 171, 53, 154, 168, 75, 11, 35, 114, 41, 250, + 120, 210, 13, 20, 37, 30, 180, 56, 129, 76, 221, 61, 30, 17, 116, 240, + 68, 246, 146, 71, 106, 208, 98, 66, 20, 234, 4, 67, 227, 65, 134, 65, + 255, 32, 56, 184, 77, 142, 226, 243, 217, 236, 68, 242, 177, 86, 43, 90, + 123, 194, 197, 92, 35, 126, 93, 168, 115, 83, 100, 108, 211, 226, 65, 139, + 17, 47, 121, 223, 8, 34, 232, 231, 130, 61, 107, 130, 21, 121, 134, 131, + 14, 198, 90, 125, 169, 7, 139, 74, 232, 176, 205, 48, 232, 71, 197, 224, + 171, 171, 98, 65, 139, 243, 179, 88, 31, 43, 250, 239, 200, 112, 29, 72, + 154, 173, 198, 187, 144, 120, 208, 226, 130, 127, 194, 142, 9, 19, 65, 31, + 20, 153, 233, 42, 209, 3, 133, 130, 22, 147, 113, 61, 108, 6, 205, 41, + 237, 218, 223, 153, 6, 253, 77, 177, 162, 167, 255, 162, 202, 6, 93, 106, + 192, 19, 205, 21, 99, 79, 130, 164, 164, 221, 142, 72, 212, 241, 160, 197, + 236, 206, 155, 209, 204, 193, 84, 67, 176, 21, 161, 160, 131, 121, 147, 222, + 249, 105, 65, 139, 6, 165, 87, 197, 85, 1, 249, 41, 51, 13, 58, 60, + 183, 137, 5, 45, 174, 211, 197, 130, 22, 205, 34, 233, 214, 38, 204, 73, + 186, 101, 232, 182, 135, 206, 50, 227, 65, 99, 77, 243, 206, 11, 19, 238, + 242, 216, 42, 17, 244, 143, 229, 35, 213, 30, 18, 143, 9, 5, 141, 50, + 197, 158, 73, 97, 69, 81, 207, 224, 203, 48, 104, 213, 37, 5, 207, 118, + 36, 116, 183, 50, 171, 160, 67, 239, 87, 176, 207, 111, 101, 25, 116, 48, + 114, 168, 55, 149, 18, 180, 152, 13, 217, 142, 73, 68, 98, 214, 173, 108, + 131, 22, 179, 200, 57, 167, 29, 116, 236, 10, 99, 200, 244, 196, 91, 97, + 162, 95, 207, 44, 104, 157, 71, 240, 150, 91, 100, 149, 12, 58, 118, 114, + 41, 122, 193, 228, 43, 133, 103, 26, 180, 62, 112, 130, 23, 41, 202, 177, + 207, 6, 45, 6, 37, 68, 16, 16, 239, 46, 229, 28, 220, 55, 93, 124, + 98, 95, 112, 81, 174, 100, 208, 222, 96, 216, 219, 160, 197, 254, 79, 9, + 90, 204, 0, 188, 179, 33, 172, 42, 226, 238, 110, 198, 65, 139, 1, 175, + 45, 22, 180, 40, 136, 5, 45, 14, 192, 208, 133, 204, 68, 83, 86, 139, + 102, 4, 126, 239, 17, 15, 218, 124, 33, 202, 242, 122, 243, 222, 4, 109, + 114, 11, 6, 133, 77, 98, 118, 42, 130, 22, 167, 157, 222, 220, 81, 124, + 206, 224, 114, 66, 134, 65, 155, 87, 23, 243, 117, 113, 9, 201, 166, 32, + 62, 68, 236, 132, 69, 244, 51, 242, 184, 76, 53, 181, 16, 29, 23, 189, + 143, 25, 15, 58, 97, 182, 211, 155, 160, 237, 14, 199, 138, 34, 102, 23, + 226, 45, 138, 123, 88, 40, 145, 147, 163, 224, 66, 99, 214, 65, 139, 196, + 68, 151, 108, 131, 22, 175, 21, 59, 5, 23, 159, 60, 182, 19, 82, 76, + 15, 167, 229, 29, 184, 241, 160, 69, 11, 243, 158, 187, 247, 65, 7, 237, + 88, 124, 158, 32, 104, 49, 153, 59, 56, 217, 131, 2, 165, 27, 155, 101, + 26, 52, 238, 128, 99, 45, 196, 6, 45, 186, 135, 216, 73, 137, 104, 254, + 177, 110, 37, 213, 84, 241, 234, 126, 255, 27, 15, 90, 132, 231, 237, 224, + 169, 115, 44, 209, 171, 196, 130, 198, 25, 42, 214, 66, 130, 160, 19, 246, + 88, 136, 127, 42, 154, 97, 208, 232, 37, 197, 51, 250, 108, 149, 24, 89, + 66, 95, 0, 209, 68, 115, 137, 222, 109, 43, 69, 244, 144, 222, 235, 199, + 131, 22, 239, 40, 186, 131, 123, 17, 180, 184, 56, 224, 11, 130, 70, 65, + 42, 127, 42, 157, 125, 208, 50, 51, 15, 170, 196, 41, 90, 36, 77, 113, + 4, 38, 79, 163, 187, 142, 43, 157, 157, 157, 71, 143, 30, 181, 137, 64, + 60, 152, 120, 208, 98, 7, 35, 78, 159, 120, 175, 177, 160, 189, 214, 47, + 175, 207, 130, 31, 116, 252, 250, 75, 20, 54, 236, 139, 160, 19, 78, 148, + 81, 37, 198, 109, 121, 210, 164, 164, 220, 168, 10, 136, 68, 66, 23, 134, + 196, 139, 97, 90, 24, 15, 90, 238, 224, 200, 213, 172, 222, 4, 45, 247, + 19, 248, 65, 203, 175, 144, 38, 243, 94, 176, 15, 130, 142, 94, 207, 84, + 80, 37, 246, 127, 112, 115, 89, 155, 44, 14, 225, 228, 11, 108, 162, 15, + 15, 13, 150, 226, 90, 48, 78, 116, 18, 130, 22, 113, 68, 238, 56, 148, + 10, 218, 223, 227, 98, 48, 5, 63, 104, 172, 151, 224, 93, 185, 233, 139, + 160, 35, 223, 67, 83, 188, 42, 49, 23, 242, 183, 214, 196, 21, 200, 148, + 19, 112, 49, 232, 132, 190, 227, 41, 250, 156, 244, 160, 101, 79, 238, 149, + 89, 226, 13, 165, 7, 45, 111, 0, 91, 94, 208, 225, 155, 17, 201, 208, + 89, 245, 69, 208, 178, 139, 176, 188, 42, 113, 1, 76, 158, 133, 203, 247, + 155, 220, 115, 132, 134, 36, 217, 230, 197, 67, 241, 77, 145, 132, 160, 67, + 195, 70, 232, 136, 17, 253, 111, 122, 208, 161, 183, 109, 120, 65, 139, 25, + 122, 42, 76, 198, 250, 36, 232, 216, 17, 229, 85, 201, 47, 22, 5, 49, + 200, 16, 139, 193, 185, 84, 152, 200, 170, 3, 141, 68, 153, 34, 154, 36, + 186, 253, 164, 160, 101, 147, 238, 18, 109, 186, 85, 252, 166, 69, 137, 160, + 101, 39, 111, 32, 104, 121, 75, 57, 21, 166, 210, 125, 19, 180, 252, 96, + 154, 95, 21, 170, 56, 208, 170, 62, 220, 148, 150, 208, 128, 146, 114, 195, + 48, 244, 70, 85, 43, 65, 212, 171, 101, 147, 194, 67, 147, 130, 14, 207, + 28, 14, 172, 214, 123, 115, 242, 244, 130, 216, 180, 116, 208, 209, 41, 30, + 130, 22, 239, 233, 200, 214, 48, 20, 107, 118, 130, 37, 182, 61, 138, 109, + 4, 60, 33, 210, 21, 108, 185, 146, 28, 116, 116, 74, 20, 84, 137, 65, + 45, 73, 234, 221, 149, 104, 235, 233, 106, 63, 112, 160, 35, 220, 208, 16, + 126, 98, 208, 209, 206, 180, 216, 25, 109, 164, 37, 131, 150, 79, 170, 33, + 23, 49, 132, 71, 127, 91, 65, 28, 42, 246, 148, 53, 212, 80, 98, 48, + 70, 35, 93, 193, 150, 43, 41, 65, 71, 166, 120, 65, 85, 168, 243, 136, + 43, 113, 171, 41, 122, 148, 68, 121, 179, 177, 196, 160, 123, 248, 156, 90, + 201, 160, 35, 243, 101, 27, 180, 252, 44, 209, 55, 46, 46, 140, 216, 169, + 116, 31, 5, 29, 153, 18, 137, 170, 146, 121, 149, 188, 204, 33, 166, 38, + 9, 186, 188, 239, 171, 36, 7, 221, 227, 140, 23, 211, 176, 148, 160, 229, + 231, 84, 108, 208, 98, 204, 15, 174, 105, 128, 108, 105, 230, 109, 244, 85, + 208, 225, 150, 43, 171, 210, 167, 68, 197, 216, 237, 128, 176, 146, 215, 21, + 252, 80, 83, 130, 46, 245, 187, 51, 138, 119, 73, 42, 45, 232, 112, 207, + 101, 131, 198, 138, 22, 191, 115, 143, 10, 205, 164, 216, 87, 65, 135, 167, + 68, 225, 125, 144, 50, 41, 234, 40, 209, 111, 88, 233, 109, 186, 59, 152, + 180, 165, 4, 93, 122, 63, 249, 111, 48, 45, 232, 112, 80, 38, 104, 217, + 104, 227, 77, 68, 238, 87, 125, 176, 245, 89, 208, 161, 41, 81, 184, 106, + 114, 248, 56, 132, 210, 191, 146, 101, 77, 79, 233, 0, 126, 44, 246, 81, + 106, 208, 99, 219, 196, 8, 21, 178, 61, 120, 120, 106, 208, 161, 95, 158, + 48, 65, 203, 155, 15, 102, 139, 16, 121, 224, 234, 143, 223, 119, 65, 203, + 41, 81, 164, 106, 108, 139, 72, 195, 234, 232, 161, 219, 240, 36, 253, 234, + 236, 145, 80, 160, 233, 65, 143, 157, 146, 116, 72, 28, 47, 96, 186, 98, + 164, 7, 45, 147, 51, 65, 99, 89, 75, 152, 44, 201, 211, 73, 125, 173, + 178, 239, 130, 150, 159, 56, 90, 165, 134, 241, 237, 226, 12, 164, 251, 209, + 94, 198, 172, 77, 109, 11, 77, 17, 143, 110, 143, 92, 8, 44, 17, 180, + 138, 186, 45, 252, 203, 73, 7, 219, 34, 253, 85, 122, 208, 178, 5, 235, + 160, 229, 168, 158, 52, 251, 151, 45, 66, 189, 200, 153, 6, 141, 123, 10, + 26, 74, 124, 40, 214, 80, 18, 54, 181, 181, 240, 144, 154, 170, 23, 90, + 123, 236, 155, 163, 166, 204, 105, 89, 173, 30, 91, 104, 91, 61, 55, 254, + 212, 120, 73, 13, 37, 17, 211, 213, 131, 191, 249, 232, 214, 194, 234, 150, + 132, 235, 87, 120, 164, 129, 34, 31, 138, 149, 240, 90, 242, 11, 161, 202, + 136, 174, 199, 153, 135, 148, 10, 154, 178, 132, 116, 5, 84, 80, 182, 144, + 174, 128, 10, 202, 22, 210, 21, 80, 65, 217, 66, 186, 2, 42, 40, 91, + 72, 87, 64, 5, 101, 11, 233, 10, 168, 160, 108, 33, 93, 1, 21, 148, + 45, 164, 43, 160, 130, 178, 133, 116, 5, 84, 80, 182, 144, 174, 128, 10, + 202, 22, 210, 21, 80, 65, 217, 66, 186, 2, 42, 40, 91, 72, 87, 64, + 5, 101, 11, 233, 10, 168, 160, 108, 33, 93, 1, 21, 148, 45, 164, 43, + 160, 130, 178, 133, 116, 5, 84, 80, 182, 144, 174, 128, 10, 202, 22, 210, + 21, 80, 65, 217, 66, 186, 2, 42, 40, 91, 72, 87, 64, 5, 101, 11, + 233, 10, 168, 160, 108, 33, 93, 1, 21, 148, 45, 164, 43, 160, 130, 178, + 133, 116, 5, 84, 80, 182, 144, 174, 128, 10, 202, 22, 210, 21, 80, 65, + 217, 66, 186, 2, 42, 40, 91, 72, 87, 64, 5, 101, 11, 233, 10, 168, + 160, 108, 33, 93, 1, 21, 148, 45, 164, 43, 160, 130, 178, 133, 116, 5, + 84, 80, 182, 144, 174, 128, 10, 202, 22, 210, 21, 80, 65, 217, 66, 186, + 2, 42, 40, 91, 72, 87, 64, 5, 101, 11, 233, 10, 168, 160, 108, 33, + 93, 1, 21, 148, 45, 164, 43, 160, 130, 178, 133, 116, 5, 84, 80, 182, + 144, 174, 128, 10, 202, 22, 210, 21, 80, 65, 217, 66, 186, 2, 42, 40, + 91, 72, 151, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 168, 95, 24, 60, 98, 244, 251, 176, 8, 231, 140, 30, 49, 24, 139, + 148, 145, 97, 163, 230, 45, 206, 125, 118, 62, 214, 96, 222, 103, 115, 139, + 255, 122, 212, 48, 172, 209, 25, 27, 124, 209, 188, 37, 249, 124, 174, 185, + 57, 55, 2, 37, 198, 136, 165, 75, 155, 115, 249, 124, 243, 252, 139, 216, + 174, 179, 48, 248, 226, 5, 38, 101, 37, 255, 177, 65, 40, 84, 222, 115, + 93, 222, 20, 170, 172, 23, 92, 204, 168, 207, 220, 121, 159, 181, 41, 107, + 249, 139, 80, 168, 140, 176, 57, 107, 185, 207, 134, 154, 58, 157, 150, 243, + 84, 15, 225, 145, 77, 26, 13, 218, 200, 157, 135, 66, 58, 125, 239, 107, + 14, 130, 110, 206, 251, 77, 119, 68, 208, 206, 213, 6, 231, 162, 148, 78, + 223, 176, 102, 17, 105, 126, 254, 121, 191, 247, 129, 139, 47, 254, 192, 69, + 231, 205, 23, 13, 122, 105, 243, 57, 216, 152, 78, 223, 224, 197, 34, 232, + 230, 156, 26, 251, 180, 92, 168, 112, 9, 231, 120, 103, 110, 240, 167, 100, + 166, 94, 63, 34, 186, 19, 21, 244, 98, 206, 58, 50, 240, 177, 80, 208, + 73, 114, 11, 222, 131, 109, 233, 12, 204, 19, 189, 113, 178, 124, 228, 148, + 145, 78, 199, 224, 235, 122, 110, 209, 31, 103, 31, 125, 90, 100, 143, 251, + 254, 208, 88, 152, 34, 183, 120, 20, 54, 215, 196, 233, 35, 149, 50, 122, + 241, 40, 47, 171, 97, 243, 112, 246, 221, 131, 92, 126, 190, 215, 168, 7, + 189, 255, 83, 163, 177, 72, 37, 125, 64, 205, 224, 62, 110, 79, 76, 70, + 44, 238, 177, 127, 246, 228, 23, 227, 33, 31, 83, 147, 191, 139, 205, 34, + 149, 52, 66, 159, 160, 228, 115, 243, 212, 57, 200, 197, 242, 92, 165, 39, + 185, 102, 21, 239, 176, 191, 202, 169, 93, 147, 91, 202, 107, 31, 61, 58, + 199, 246, 201, 75, 243, 75, 70, 253, 121, 239, 186, 13, 79, 46, 127, 237, + 168, 197, 121, 51, 193, 206, 45, 230, 169, 98, 15, 6, 251, 215, 138, 114, + 249, 92, 232, 172, 164, 23, 212, 67, 176, 148, 255, 24, 79, 97, 74, 187, + 182, 215, 157, 114, 105, 249, 191, 192, 19, 198, 141, 155, 125, 255, 198, 45, + 155, 215, 221, 61, 107, 66, 25, 74, 172, 243, 167, 221, 185, 126, 203, 195, + 127, 119, 99, 109, 57, 10, 180, 202, 134, 143, 78, 51, 234, 39, 86, 161, + 72, 42, 175, 251, 252, 186, 135, 183, 172, 191, 163, 161, 18, 5, 142, 51, + 17, 15, 240, 124, 116, 90, 5, 106, 250, 147, 17, 167, 220, 138, 83, 44, + 205, 137, 75, 215, 66, 89, 211, 143, 186, 93, 40, 182, 223, 29, 100, 48, + 113, 243, 235, 40, 118, 59, 238, 245, 99, 171, 120, 30, 101, 202, 155, 207, + 174, 153, 132, 98, 184, 224, 254, 151, 81, 231, 118, 126, 99, 130, 45, 171, + 58, 142, 146, 192, 253, 182, 166, 63, 25, 188, 224, 148, 122, 229, 82, 114, + 139, 127, 3, 79, 42, 77, 120, 26, 31, 30, 30, 70, 249, 224, 53, 126, + 252, 218, 107, 141, 40, 175, 67, 1, 20, 119, 140, 65, 133, 214, 116, 12, + 197, 198, 255, 222, 109, 230, 164, 245, 88, 21, 126, 100, 182, 238, 87, 178, + 234, 56, 180, 252, 95, 226, 73, 133, 63, 246, 91, 45, 252, 171, 45, 31, + 242, 36, 214, 125, 183, 217, 138, 88, 108, 157, 13, 182, 66, 249, 10, 138, + 124, 219, 244, 184, 48, 27, 43, 66, 123, 255, 59, 131, 202, 52, 232, 107, + 241, 164, 129, 154, 216, 97, 189, 193, 148, 15, 222, 143, 85, 225, 19, 166, + 38, 222, 62, 187, 235, 76, 133, 227, 124, 17, 5, 194, 131, 170, 184, 9, + 203, 66, 71, 120, 44, 232, 15, 178, 236, 58, 62, 21, 155, 119, 156, 117, + 8, 159, 60, 96, 187, 136, 251, 177, 38, 117, 125, 72, 215, 36, 116, 4, + 47, 219, 126, 189, 1, 171, 33, 77, 142, 115, 21, 22, 133, 67, 230, 1, + 253, 139, 254, 10, 65, 38, 150, 134, 191, 154, 96, 220, 133, 15, 30, 120, + 205, 132, 246, 161, 80, 255, 236, 217, 166, 171, 18, 130, 118, 239, 210, 21, + 131, 95, 192, 90, 200, 145, 10, 103, 18, 22, 133, 111, 233, 7, 244, 55, + 153, 77, 239, 226, 61, 116, 101, 39, 62, 184, 114, 236, 103, 111, 232, 31, + 159, 49, 21, 95, 55, 69, 90, 241, 216, 155, 88, 82, 125, 196, 56, 85, + 149, 20, 244, 203, 122, 250, 39, 26, 110, 167, 120, 222, 38, 167, 108, 231, + 203, 74, 23, 214, 143, 169, 229, 14, 111, 100, 237, 87, 6, 127, 60, 147, + 164, 243, 11, 226, 39, 44, 65, 239, 185, 165, 182, 162, 172, 178, 110, 125, + 215, 102, 211, 121, 86, 248, 147, 135, 157, 147, 42, 170, 22, 250, 81, 175, + 82, 117, 94, 208, 119, 214, 47, 252, 33, 22, 93, 87, 247, 210, 143, 96, + 217, 125, 113, 218, 144, 33, 13, 126, 243, 126, 82, 85, 149, 41, 27, 176, + 94, 175, 87, 244, 139, 244, 63, 231, 158, 202, 245, 141, 52, 185, 230, 132, + 239, 31, 236, 196, 135, 119, 239, 64, 193, 112, 251, 227, 143, 81, 236, 238, + 52, 145, 212, 123, 29, 201, 126, 189, 130, 229, 105, 106, 217, 159, 101, 220, + 169, 118, 142, 215, 138, 143, 152, 39, 185, 192, 155, 79, 191, 129, 25, 248, + 122, 172, 215, 218, 213, 126, 105, 84, 36, 232, 37, 75, 176, 80, 66, 116, + 155, 164, 203, 119, 229, 175, 225, 195, 235, 86, 39, 173, 66, 121, 87, 181, + 93, 247, 122, 146, 255, 86, 93, 132, 23, 180, 62, 250, 203, 143, 98, 101, + 139, 227, 92, 138, 69, 119, 182, 125, 204, 76, 172, 122, 201, 122, 65, 123, + 83, 148, 254, 104, 88, 232, 198, 235, 178, 21, 187, 119, 239, 90, 142, 149, + 20, 203, 213, 54, 43, 150, 97, 69, 75, 252, 250, 65, 181, 215, 82, 163, + 93, 230, 70, 148, 63, 130, 245, 90, 172, 119, 171, 224, 101, 208, 206, 14, + 172, 60, 29, 204, 150, 143, 158, 101, 30, 18, 236, 69, 4, 63, 16, 130, + 62, 71, 4, 189, 236, 159, 79, 234, 183, 251, 214, 190, 18, 81, 47, 255, + 222, 91, 122, 155, 147, 123, 131, 168, 151, 54, 71, 190, 224, 171, 249, 249, + 253, 14, 10, 60, 143, 163, 2, 231, 40, 65, 183, 160, 78, 184, 67, 65, + 175, 193, 138, 154, 174, 121, 71, 193, 227, 230, 17, 202, 183, 80, 128, 39, + 25, 96, 65, 47, 255, 47, 188, 95, 247, 228, 231, 80, 20, 115, 235, 47, + 176, 137, 251, 234, 205, 40, 74, 14, 218, 203, 236, 152, 158, 210, 13, 170, + 170, 169, 111, 108, 172, 31, 175, 123, 229, 103, 80, 113, 149, 217, 76, 241, + 134, 182, 250, 72, 208, 119, 96, 165, 189, 204, 159, 121, 175, 55, 15, 80, + 188, 100, 191, 20, 94, 29, 24, 65, 47, 123, 85, 189, 213, 226, 193, 173, + 219, 59, 84, 163, 254, 91, 20, 70, 220, 172, 154, 124, 199, 246, 191, 63, + 88, 84, 155, 158, 240, 218, 116, 98, 208, 222, 25, 134, 238, 122, 157, 6, + 59, 255, 42, 190, 48, 198, 113, 126, 106, 22, 237, 128, 103, 120, 23, 146, + 212, 217, 118, 40, 104, 175, 25, 171, 83, 106, 175, 113, 63, 96, 30, 160, + 60, 128, 130, 175, 216, 213, 129, 21, 244, 94, 245, 78, 15, 77, 29, 58, + 116, 232, 37, 45, 93, 238, 127, 160, 80, 201, 139, 254, 248, 37, 183, 171, + 245, 18, 181, 201, 212, 231, 212, 198, 223, 69, 97, 98, 208, 222, 245, 161, + 215, 135, 168, 21, 127, 26, 172, 90, 173, 215, 162, 253, 190, 59, 173, 69, + 223, 139, 149, 231, 131, 115, 201, 175, 155, 7, 40, 94, 178, 184, 82, 55, + 160, 130, 190, 73, 245, 189, 237, 99, 135, 94, 114, 201, 37, 31, 60, 123, + 78, 209, 245, 59, 143, 39, 78, 252, 124, 15, 22, 155, 111, 113, 139, 115, + 207, 190, 80, 109, 50, 116, 172, 58, 191, 126, 27, 93, 121, 98, 208, 53, + 248, 236, 197, 241, 106, 165, 17, 43, 58, 9, 175, 143, 182, 103, 47, 162, + 143, 86, 51, 136, 80, 208, 235, 176, 242, 84, 208, 184, 119, 154, 71, 40, + 223, 65, 129, 158, 124, 43, 3, 42, 232, 93, 234, 141, 206, 209, 57, 43, + 239, 221, 234, 238, 197, 20, 110, 133, 254, 0, 43, 236, 242, 146, 61, 238, + 14, 108, 49, 116, 142, 42, 222, 101, 139, 19, 131, 190, 208, 59, 91, 91, + 168, 86, 252, 160, 47, 115, 156, 7, 177, 168, 102, 109, 134, 55, 117, 43, + 170, 110, 37, 20, 180, 119, 233, 233, 225, 96, 214, 241, 51, 156, 23, 249, + 179, 142, 38, 187, 62, 144, 130, 94, 244, 132, 154, 61, 253, 190, 110, 173, + 54, 198, 195, 166, 180, 121, 209, 183, 245, 7, 120, 98, 145, 93, 251, 190, + 219, 132, 160, 63, 120, 201, 17, 215, 221, 99, 139, 19, 131, 46, 83, 61, + 189, 241, 130, 10, 167, 178, 254, 195, 255, 109, 86, 84, 171, 245, 90, 231, + 27, 184, 133, 226, 53, 92, 61, 106, 202, 160, 43, 189, 107, 127, 119, 5, + 83, 24, 175, 99, 151, 71, 136, 54, 160, 130, 222, 227, 186, 207, 93, 248, + 65, 27, 227, 208, 122, 247, 37, 83, 218, 188, 100, 183, 254, 0, 94, 208, + 135, 221, 169, 8, 250, 146, 161, 7, 93, 247, 95, 74, 4, 237, 108, 51, + 31, 93, 177, 83, 133, 23, 205, 178, 152, 194, 185, 155, 77, 185, 127, 102, + 168, 122, 136, 80, 208, 247, 97, 89, 15, 146, 67, 188, 11, 219, 47, 152, + 83, 193, 42, 111, 39, 190, 121, 190, 94, 29, 96, 93, 199, 63, 169, 249, + 132, 106, 168, 54, 197, 233, 238, 247, 108, 105, 40, 232, 37, 223, 117, 167, + 251, 45, 186, 221, 117, 119, 219, 238, 37, 57, 232, 224, 90, 199, 206, 218, + 242, 193, 181, 246, 154, 134, 10, 218, 239, 147, 221, 45, 19, 43, 135, 47, + 244, 175, 89, 223, 171, 30, 227, 5, 61, 219, 169, 88, 169, 39, 54, 154, + 57, 205, 246, 230, 205, 238, 179, 13, 149, 149, 211, 252, 107, 29, 122, 231, + 104, 3, 42, 232, 191, 125, 199, 45, 122, 237, 245, 189, 109, 238, 99, 182, + 52, 220, 162, 119, 185, 133, 247, 218, 45, 134, 254, 137, 10, 226, 22, 91, + 154, 28, 116, 165, 185, 96, 103, 189, 246, 51, 196, 86, 163, 42, 190, 97, + 23, 149, 98, 167, 215, 145, 171, 101, 125, 19, 208, 11, 250, 200, 15, 189, + 78, 24, 125, 185, 184, 145, 114, 92, 220, 78, 208, 253, 191, 54, 160, 130, + 86, 83, 55, 247, 7, 106, 110, 167, 83, 252, 163, 227, 39, 49, 167, 11, + 7, 189, 236, 228, 255, 76, 177, 91, 12, 125, 212, 117, 255, 211, 22, 166, + 4, 237, 79, 126, 37, 29, 116, 141, 215, 86, 67, 204, 132, 194, 239, 86, + 2, 69, 213, 173, 171, 209, 207, 246, 60, 17, 199, 188, 187, 186, 3, 43, + 232, 91, 222, 118, 221, 135, 126, 95, 77, 146, 135, 78, 105, 247, 26, 116, + 36, 104, 213, 164, 59, 244, 76, 123, 232, 37, 155, 92, 247, 151, 183, 162, + 48, 37, 232, 74, 53, 92, 70, 152, 102, 235, 252, 29, 214, 164, 110, 189, + 11, 146, 130, 198, 253, 92, 127, 248, 147, 188, 6, 61, 192, 130, 110, 126, + 236, 29, 117, 208, 182, 253, 77, 203, 214, 110, 119, 47, 138, 154, 151, 132, + 102, 29, 205, 205, 123, 220, 238, 237, 45, 115, 219, 212, 104, 244, 206, 63, + 161, 40, 45, 232, 96, 156, 243, 21, 205, 13, 171, 138, 159, 96, 85, 176, + 179, 234, 120, 208, 47, 98, 184, 75, 218, 59, 230, 166, 140, 49, 192, 130, + 110, 94, 161, 79, 194, 149, 147, 187, 81, 224, 181, 232, 111, 7, 215, 69, + 255, 209, 92, 119, 82, 39, 224, 152, 91, 43, 105, 65, 59, 51, 255, 215, + 110, 235, 43, 234, 219, 40, 142, 115, 129, 119, 26, 238, 211, 35, 161, 18, + 11, 250, 69, 251, 0, 165, 44, 232, 218, 225, 145, 224, 155, 55, 3, 45, + 232, 230, 252, 174, 125, 175, 188, 114, 120, 247, 77, 88, 213, 150, 159, 112, + 221, 95, 200, 171, 121, 203, 118, 127, 255, 149, 87, 246, 61, 38, 238, 204, + 164, 6, 237, 212, 69, 111, 245, 225, 123, 26, 67, 54, 99, 221, 58, 134, + 171, 157, 209, 160, 139, 155, 229, 215, 149, 86, 5, 35, 167, 210, 125, 191, + 184, 149, 226, 221, 97, 25, 48, 65, 91, 225, 203, 250, 203, 119, 127, 187, + 135, 11, 212, 233, 65, 59, 103, 221, 38, 70, 177, 174, 103, 110, 244, 195, + 105, 216, 239, 247, 43, 175, 173, 185, 0, 133, 206, 5, 246, 180, 198, 232, + 126, 177, 112, 41, 138, 97, 194, 102, 127, 194, 241, 230, 150, 208, 183, 152, + 188, 107, 76, 145, 7, 244, 43, 9, 65, 71, 44, 241, 59, 232, 20, 37, + 130, 118, 156, 193, 117, 171, 30, 252, 206, 254, 199, 119, 172, 95, 53, 45, + 124, 101, 122, 220, 39, 214, 237, 220, 255, 248, 195, 247, 54, 4, 223, 19, + 115, 156, 225, 87, 205, 182, 26, 235, 170, 19, 110, 254, 93, 48, 115, 205, + 142, 39, 159, 220, 177, 102, 38, 110, 139, 121, 42, 27, 87, 222, 251, 197, + 187, 22, 214, 37, 60, 164, 223, 232, 57, 232, 30, 149, 12, 154, 224, 156, + 158, 218, 107, 47, 44, 98, 208, 61, 251, 237, 61, 187, 119, 221, 122, 243, + 77, 249, 79, 35, 180, 83, 242, 233, 252, 178, 155, 111, 93, 177, 123, 207, + 239, 226, 201, 40, 221, 4, 125, 158, 246, 206, 91, 63, 127, 245, 165, 125, + 123, 191, 189, 75, 222, 115, 45, 105, 217, 174, 221, 255, 178, 239, 165, 255, + 58, 241, 214, 47, 245, 32, 52, 17, 79, 70, 233, 194, 39, 196, 184, 56, + 10, 203, 110, 90, 230, 187, 41, 188, 15, 190, 143, 7, 88, 145, 47, 50, + 103, 163, 202, 59, 87, 121, 119, 56, 247, 214, 93, 187, 247, 250, 109, 243, + 132, 252, 150, 199, 247, 222, 10, 217, 135, 98, 45, 167, 79, 109, 252, 227, + 224, 214, 148, 191, 223, 81, 125, 245, 245, 31, 57, 27, 203, 167, 238, 26, + 92, 213, 127, 151, 56, 103, 73, 243, 34, 61, 30, 170, 222, 246, 150, 87, + 93, 239, 90, 146, 182, 220, 244, 10, 129, 119, 196, 116, 58, 127, 194, 61, + 129, 158, 93, 61, 122, 73, 242, 96, 216, 80, 152, 89, 127, 67, 33, 50, + 19, 235, 189, 202, 211, 223, 71, 253, 145, 152, 222, 45, 58, 236, 190, 37, + 78, 10, 111, 81, 13, 252, 240, 75, 112, 88, 157, 32, 138, 239, 32, 44, + 59, 233, 190, 228, 79, 87, 82, 166, 119, 191, 185, 73, 103, 60, 163, 213, + 174, 253, 191, 39, 191, 169, 244, 125, 247, 151, 254, 151, 53, 204, 77, 196, + 221, 126, 152, 139, 30, 115, 253, 43, 122, 202, 242, 183, 69, 119, 158, 242, + 135, 82, 46, 55, 95, 184, 61, 127, 165, 250, 175, 234, 202, 153, 35, 29, + 167, 108, 124, 121, 195, 204, 42, 103, 228, 172, 122, 93, 81, 113, 133, 46, + 51, 170, 174, 188, 82, 157, 107, 95, 88, 85, 53, 227, 79, 127, 77, 173, + 158, 221, 120, 101, 101, 245, 175, 59, 35, 135, 59, 21, 99, 42, 174, 184, + 210, 92, 11, 173, 187, 250, 15, 245, 143, 1, 108, 88, 240, 203, 223, 75, + 190, 235, 186, 55, 7, 209, 238, 241, 111, 202, 106, 159, 243, 239, 92, 41, + 139, 150, 191, 227, 221, 130, 81, 82, 254, 80, 202, 213, 215, 96, 193, 25, + 95, 104, 186, 122, 67, 141, 83, 89, 248, 155, 171, 91, 10, 181, 171, 102, + 172, 85, 189, 111, 213, 218, 107, 174, 222, 240, 7, 166, 122, 76, 161, 169, + 73, 245, 48, 141, 171, 111, 156, 113, 191, 106, 255, 21, 133, 150, 153, 183, + 23, 198, 57, 215, 55, 57, 53, 107, 63, 57, 107, 229, 215, 202, 29, 103, + 229, 93, 141, 109, 3, 188, 203, 30, 20, 124, 235, 95, 71, 251, 221, 127, + 220, 181, 226, 150, 155, 151, 47, 203, 125, 122, 209, 62, 247, 29, 209, 190, + 111, 254, 165, 123, 120, 81, 115, 110, 217, 77, 55, 223, 242, 185, 93, 143, + 237, 117, 221, 189, 126, 236, 185, 5, 137, 191, 53, 210, 228, 7, 221, 218, + 224, 56, 211, 238, 113, 42, 182, 214, 56, 206, 61, 155, 42, 156, 170, 13, + 191, 238, 180, 206, 112, 156, 250, 47, 155, 234, 53, 170, 133, 207, 248, 130, + 243, 145, 141, 229, 206, 175, 109, 24, 238, 52, 221, 174, 90, 247, 214, 49, + 122, 48, 28, 255, 15, 170, 247, 81, 213, 117, 107, 84, 254, 27, 146, 126, + 33, 110, 0, 249, 43, 255, 58, 156, 189, 227, 173, 135, 189, 183, 79, 158, + 120, 245, 63, 78, 134, 134, 198, 101, 191, 112, 223, 122, 233, 149, 19, 39, + 237, 196, 89, 9, 174, 81, 231, 231, 225, 169, 194, 116, 208, 213, 151, 215, + 171, 169, 159, 62, 248, 199, 180, 57, 103, 23, 84, 219, 156, 117, 143, 90, + 89, 59, 178, 172, 80, 161, 219, 174, 190, 210, 89, 85, 40, 115, 156, 145, + 107, 157, 198, 27, 213, 202, 151, 39, 57, 107, 116, 39, 209, 54, 78, 7, + 93, 211, 166, 22, 175, 191, 218, 185, 93, 255, 206, 208, 125, 230, 94, 203, + 192, 117, 81, 112, 193, 243, 22, 92, 107, 246, 188, 138, 114, 227, 21, 20, + 194, 91, 222, 253, 21, 21, 116, 242, 239, 24, 234, 160, 39, 93, 211, 178, + 73, 133, 57, 102, 86, 211, 170, 53, 42, 232, 179, 28, 27, 103, 219, 152, + 179, 30, 186, 167, 181, 245, 158, 141, 250, 130, 210, 200, 173, 173, 173, 173, + 171, 85, 208, 159, 84, 43, 171, 107, 157, 181, 250, 90, 42, 130, 86, 45, + 217, 105, 106, 114, 238, 105, 83, 155, 108, 26, 224, 65, 203, 223, 24, 90, + 126, 235, 138, 93, 187, 247, 236, 221, 119, 248, 63, 95, 253, 249, 201, 183, + 223, 126, 2, 197, 198, 19, 111, 191, 125, 242, 231, 175, 190, 114, 120, 223, + 222, 61, 187, 31, 91, 113, 107, 48, 215, 203, 37, 124, 221, 95, 179, 125, + 180, 110, 181, 151, 23, 26, 38, 94, 25, 14, 186, 162, 48, 190, 186, 186, + 250, 66, 189, 197, 152, 194, 152, 234, 234, 145, 85, 206, 149, 186, 38, 57, + 232, 251, 174, 80, 27, 15, 15, 46, 244, 15, 76, 162, 73, 107, 139, 204, + 180, 58, 151, 95, 182, 60, 114, 25, 122, 249, 242, 101, 230, 151, 191, 237, + 6, 129, 252, 251, 241, 68, 17, 13, 102, 98, 119, 126, 161, 124, 80, 97, + 188, 138, 51, 28, 116, 185, 233, 53, 140, 225, 107, 237, 79, 47, 232, 54, + 253, 37, 50, 245, 159, 8, 250, 174, 254, 124, 69, 191, 247, 122, 254, 43, + 74, 165, 164, 244, 208, 170, 239, 221, 168, 71, 175, 225, 27, 202, 202, 10, + 170, 147, 190, 82, 247, 209, 126, 208, 227, 156, 47, 235, 236, 204, 245, 227, + 50, 189, 31, 212, 162, 23, 244, 23, 102, 57, 78, 249, 70, 51, 24, 122, + 65, 55, 234, 125, 214, 159, 47, 54, 247, 206, 25, 253, 198, 80, 126, 65, + 210, 239, 38, 27, 31, 89, 91, 63, 174, 174, 77, 197, 182, 106, 85, 205, + 140, 251, 214, 58, 103, 171, 201, 134, 51, 67, 207, 171, 191, 54, 222, 169, + 41, 212, 141, 111, 186, 218, 108, 87, 247, 181, 218, 241, 55, 252, 153, 51, + 227, 243, 106, 89, 229, 63, 102, 211, 229, 19, 91, 212, 172, 227, 6, 12, + 134, 215, 92, 227, 148, 183, 53, 141, 171, 111, 29, 232, 93, 135, 154, 75, + 47, 56, 237, 164, 243, 11, 74, 252, 33, 171, 154, 79, 182, 222, 168, 175, + 55, 85, 92, 223, 250, 167, 21, 127, 230, 148, 79, 83, 141, 114, 188, 30, + 210, 244, 95, 39, 24, 215, 178, 106, 22, 110, 174, 76, 90, 185, 234, 138, + 114, 91, 83, 175, 230, 115, 127, 112, 251, 202, 26, 213, 230, 39, 213, 56, + 231, 95, 174, 138, 106, 212, 164, 176, 162, 169, 245, 6, 220, 111, 28, 208, + 134, 205, 63, 181, 63, 138, 226, 17, 127, 91, 41, 99, 5, 51, 78, 190, + 251, 188, 103, 116, 179, 253, 99, 50, 167, 98, 105, 190, 121, 116, 95, 252, + 130, 251, 200, 178, 178, 43, 116, 159, 241, 238, 244, 190, 121, 75, 79, 45, + 106, 181, 249, 252, 62, 249, 243, 198, 101, 183, 183, 181, 173, 57, 237, 107, + 126, 3, 192, 136, 121, 205, 189, 255, 115, 63, 185, 124, 243, 252, 62, 251, + 147, 85, 149, 3, 252, 100, 187, 71, 239, 27, 189, 96, 169, 247, 119, 231, + 75, 200, 229, 243, 75, 23, 252, 57, 255, 134, 244, 153, 24, 116, 222, 232, + 235, 150, 168, 32, 115, 201, 77, 123, 169, 254, 51, 199, 185, 230, 235, 70, + 255, 86, 255, 251, 227, 35, 3, 207, 176, 17, 163, 231, 45, 88, 172, 219, + 173, 253, 203, 209, 26, 150, 155, 23, 47, 152, 55, 122, 4, 255, 50, 105, + 118, 222, 51, 236, 220, 17, 163, 70, 95, 59, 111, 254, 252, 235, 62, 174, + 92, 55, 127, 254, 188, 107, 71, 143, 26, 113, 238, 48, 254, 65, 99, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 10, 113, + 156, 255, 3, 35, 249, 94, 107, 244, 110, 153, 35, 0, 0, 0, 0, 73, + 69, 78, 68, 174, 66, 96, 130 +}; + +const unsigned int Bin_CloseIconPNG_size = 384; +const unsigned char Bin_CloseIconPNG[] = { + 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, + 0, 0, 0, 14, 0, 0, 0, 14, 8, 6, 0, 0, 0, 31, 72, 45, + 209, 0, 0, 0, 4, 115, 66, 73, 84, 8, 8, 8, 8, 124, 8, 100, + 136, 0, 0, 0, 9, 112, 72, 89, 115, 0, 0, 12, 235, 0, 0, 12, + 235, 1, 229, 214, 68, 210, 0, 0, 0, 25, 116, 69, 88, 116, 83, 111, + 102, 116, 119, 97, 114, 101, 0, 119, 119, 119, 46, 105, 110, 107, 115, 99, + 97, 112, 101, 46, 111, 114, 103, 155, 238, 60, 26, 0, 0, 0, 253, 73, + 68, 65, 84, 40, 145, 197, 80, 61, 106, 195, 48, 20, 254, 94, 176, 236, + 34, 159, 66, 131, 38, 31, 32, 71, 40, 24, 26, 146, 20, 74, 182, 210, + 27, 244, 40, 189, 65, 233, 148, 64, 32, 208, 14, 38, 23, 209, 164, 65, + 186, 132, 76, 82, 153, 190, 46, 114, 8, 114, 183, 14, 121, 211, 227, 123, + 223, 31, 15, 184, 217, 56, 231, 230, 222, 251, 173, 181, 182, 202, 111, 214, + 218, 202, 123, 191, 117, 206, 205, 71, 108, 54, 46, 68, 244, 10, 96, 35, + 132, 56, 92, 139, 173, 181, 149, 16, 226, 0, 96, 147, 56, 0, 128, 98, + 92, 66, 8, 207, 82, 74, 73, 68, 139, 178, 44, 63, 157, 115, 203, 190, + 239, 127, 138, 162, 216, 3, 104, 1, 28, 153, 249, 229, 18, 148, 87, 74, + 238, 45, 128, 46, 193, 45, 128, 46, 198, 184, 214, 90, 159, 255, 20, 2, + 128, 49, 166, 148, 82, 238, 137, 104, 145, 160, 35, 51, 175, 148, 82, 167, + 107, 222, 44, 23, 230, 134, 68, 52, 49, 255, 87, 213, 75, 162, 49, 166, + 204, 30, 241, 24, 66, 88, 49, 243, 23, 128, 54, 61, 236, 110, 34, 172, + 235, 250, 131, 136, 30, 146, 251, 82, 41, 117, 106, 154, 230, 123, 24, 134, + 39, 0, 29, 51, 223, 19, 209, 251, 68, 200, 204, 111, 0, 118, 121, 37, + 173, 245, 57, 198, 184, 6, 176, 75, 156, 27, 205, 47, 127, 197, 122, 191, + 111, 246, 89, 173, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130 +}; + +const unsigned int Bin_ConnectedIconPNG_size = 468; +const unsigned char Bin_ConnectedIconPNG[] = { + 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, + 0, 0, 0, 14, 0, 0, 0, 14, 8, 6, 0, 0, 0, 31, 72, 45, + 209, 0, 0, 0, 4, 115, 66, 73, 84, 8, 8, 8, 8, 124, 8, 100, + 136, 0, 0, 0, 9, 112, 72, 89, 115, 0, 0, 12, 235, 0, 0, 12, + 235, 1, 229, 214, 68, 210, 0, 0, 0, 25, 116, 69, 88, 116, 83, 111, + 102, 116, 119, 97, 114, 101, 0, 119, 119, 119, 46, 105, 110, 107, 115, 99, + 97, 112, 101, 46, 111, 114, 103, 155, 238, 60, 26, 0, 0, 1, 81, 73, + 68, 65, 84, 40, 145, 125, 146, 205, 46, 67, 97, 16, 134, 159, 249, 162, + 108, 164, 104, 90, 196, 66, 220, 65, 19, 92, 128, 68, 74, 154, 88, 11, + 193, 13, 88, 183, 18, 246, 42, 164, 161, 43, 145, 216, 72, 72, 202, 222, + 198, 169, 136, 149, 29, 225, 42, 208, 133, 149, 68, 162, 167, 125, 45, 206, + 57, 90, 63, 167, 239, 238, 155, 153, 103, 222, 153, 201, 7, 49, 202, 171, + 148, 201, 171, 148, 137, 203, 91, 231, 99, 86, 149, 17, 71, 99, 11, 88, + 6, 34, 168, 14, 170, 26, 86, 242, 172, 88, 255, 3, 230, 180, 59, 13, + 118, 9, 54, 18, 227, 240, 2, 182, 224, 89, 225, 254, 27, 12, 156, 62, + 159, 226, 160, 159, 48, 89, 207, 138, 117, 7, 16, 140, 215, 13, 82, 21, + 120, 20, 140, 2, 155, 1, 35, 25, 176, 212, 197, 232, 108, 144, 137, 53, + 208, 34, 224, 11, 45, 35, 153, 229, 85, 202, 248, 36, 194, 165, 237, 68, + 232, 206, 224, 8, 112, 194, 46, 124, 222, 87, 97, 160, 63, 129, 95, 3, + 166, 1, 90, 52, 210, 238, 131, 94, 133, 157, 155, 45, 56, 188, 182, 226, + 49, 176, 14, 156, 14, 49, 190, 210, 71, 50, 153, 192, 191, 137, 160, 246, + 190, 146, 229, 40, 191, 0, 195, 192, 155, 67, 185, 43, 219, 120, 0, 152, + 215, 126, 170, 73, 179, 102, 48, 217, 121, 32, 143, 194, 152, 195, 76, 192, + 121, 24, 79, 181, 176, 218, 188, 246, 38, 255, 131, 130, 49, 85, 197, 76, + 46, 236, 178, 29, 158, 250, 27, 110, 225, 223, 254, 134, 128, 231, 4, 254, + 78, 200, 4, 154, 83, 121, 10, 116, 25, 158, 252, 63, 61, 59, 180, 16, + 173, 225, 162, 104, 248, 35, 178, 6, 21, 208, 107, 187, 94, 175, 66, 7, + 61, 52, 178, 17, 212, 85, 51, 42, 167, 103, 84, 78, 199, 229, 191, 0, + 140, 116, 130, 2, 17, 139, 179, 85, 0, 0, 0, 0, 73, 69, 78, 68, + 174, 66, 96, 130 +}; + +const unsigned int Bin_DisconnectedIconPNG_size = 472; +const unsigned char Bin_DisconnectedIconPNG[] = { + 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, + 0, 0, 0, 14, 0, 0, 0, 14, 8, 6, 0, 0, 0, 31, 72, 45, + 209, 0, 0, 0, 4, 115, 66, 73, 84, 8, 8, 8, 8, 124, 8, 100, + 136, 0, 0, 0, 9, 112, 72, 89, 115, 0, 0, 12, 235, 0, 0, 12, + 235, 1, 229, 214, 68, 210, 0, 0, 0, 25, 116, 69, 88, 116, 83, 111, + 102, 116, 119, 97, 114, 101, 0, 119, 119, 119, 46, 105, 110, 107, 115, 99, + 97, 112, 101, 46, 111, 114, 103, 155, 238, 60, 26, 0, 0, 1, 85, 73, + 68, 65, 84, 40, 145, 125, 146, 207, 74, 2, 113, 16, 199, 63, 179, 172, + 212, 189, 53, 123, 11, 15, 245, 16, 33, 94, 50, 130, 22, 252, 33, 251, + 2, 73, 151, 160, 30, 160, 75, 160, 217, 93, 68, 118, 97, 59, 25, 148, + 8, 61, 68, 65, 79, 145, 127, 136, 174, 26, 178, 211, 193, 223, 234, 134, + 218, 156, 126, 204, 204, 231, 55, 51, 223, 25, 216, 98, 26, 4, 121, 13, + 130, 252, 182, 184, 252, 73, 246, 253, 2, 174, 123, 3, 248, 64, 10, 141, + 17, 137, 81, 189, 149, 48, 28, 175, 129, 106, 204, 17, 208, 7, 10, 91, + 138, 12, 113, 156, 178, 116, 187, 111, 0, 206, 178, 210, 2, 218, 67, 245, + 14, 152, 101, 128, 153, 245, 121, 36, 73, 95, 141, 217, 95, 130, 182, 189, + 2, 208, 144, 40, 186, 2, 42, 22, 158, 1, 21, 235, 107, 0, 7, 192, + 53, 128, 163, 139, 118, 207, 237, 239, 117, 53, 166, 36, 97, 56, 176, 112, + 69, 194, 112, 160, 198, 148, 128, 186, 205, 241, 21, 68, 52, 8, 242, 204, + 231, 203, 161, 129, 31, 84, 207, 36, 138, 158, 1, 180, 90, 61, 70, 228, + 9, 216, 93, 73, 42, 158, 195, 116, 170, 107, 50, 136, 232, 198, 119, 106, + 185, 156, 58, 196, 241, 23, 144, 86, 156, 1, 39, 18, 134, 47, 106, 76, + 201, 182, 253, 10, 156, 102, 4, 27, 210, 110, 127, 59, 2, 10, 60, 90, + 103, 43, 51, 83, 15, 232, 101, 102, 110, 217, 156, 88, 64, 5, 192, 74, + 252, 1, 120, 168, 54, 17, 185, 0, 118, 50, 235, 120, 64, 228, 18, 152, + 224, 186, 69, 233, 116, 38, 171, 3, 168, 213, 14, 73, 146, 190, 149, 124, + 147, 125, 162, 90, 150, 40, 122, 135, 116, 143, 128, 189, 136, 34, 112, 15, + 140, 50, 192, 8, 104, 226, 186, 197, 20, 250, 215, 212, 247, 61, 245, 125, + 111, 91, 252, 23, 65, 71, 136, 220, 66, 197, 208, 215, 0, 0, 0, 0, + 73, 69, 78, 68, 174, 66, 96, 130 +}; + +const unsigned int Bin_ErrorIconPNG_size = 353; +const unsigned char Bin_ErrorIconPNG[] = { + 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, + 0, 0, 0, 14, 0, 0, 0, 14, 8, 6, 0, 0, 0, 31, 72, 45, + 209, 0, 0, 0, 4, 115, 66, 73, 84, 8, 8, 8, 8, 124, 8, 100, + 136, 0, 0, 0, 9, 112, 72, 89, 115, 0, 0, 25, 214, 0, 0, 25, + 214, 1, 24, 209, 202, 237, 0, 0, 0, 25, 116, 69, 88, 116, 83, 111, + 102, 116, 119, 97, 114, 101, 0, 119, 119, 119, 46, 105, 110, 107, 115, 99, + 97, 112, 101, 46, 111, 114, 103, 155, 238, 60, 26, 0, 0, 0, 222, 73, + 68, 65, 84, 40, 145, 157, 146, 189, 78, 2, 81, 16, 70, 207, 76, 184, + 157, 182, 210, 155, 245, 105, 160, 118, 179, 5, 52, 210, 194, 203, 108, 107, + 178, 9, 144, 220, 68, 237, 208, 167, 193, 208, 19, 58, 108, 55, 126, 22, + 119, 33, 196, 63, 188, 158, 114, 50, 103, 190, 201, 189, 99, 156, 160, 170, + 234, 19, 194, 12, 105, 0, 20, 169, 168, 53, 102, 47, 180, 109, 109, 49, + 110, 15, 189, 118, 148, 198, 227, 18, 233, 30, 184, 224, 123, 222, 144, 38, + 182, 92, 62, 28, 197, 78, 138, 167, 131, 126, 64, 64, 105, 139, 197, 163, + 169, 170, 250, 244, 122, 175, 191, 36, 125, 77, 134, 194, 9, 97, 150, 33, + 1, 92, 2, 83, 71, 26, 102, 72, 9, 105, 232, 192, 117, 182, 104, 86, + 120, 182, 148, 120, 119, 96, 147, 173, 73, 27, 7, 86, 255, 72, 92, 57, + 109, 91, 147, 158, 248, 175, 236, 9, 161, 118, 139, 113, 139, 52, 33, 125, + 238, 217, 37, 49, 187, 179, 166, 217, 57, 64, 119, 70, 229, 153, 228, 61, + 102, 183, 54, 159, 63, 193, 167, 19, 211, 104, 116, 5, 76, 129, 1, 112, + 211, 149, 215, 72, 207, 132, 80, 91, 211, 236, 14, 189, 31, 239, 148, 76, + 139, 11, 217, 182, 9, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, + 130 +}; + +const unsigned int Bin_WarningIconPNG_size = 350; +const unsigned char Bin_WarningIconPNG[] = { + 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, + 0, 0, 0, 14, 0, 0, 0, 14, 8, 6, 0, 0, 0, 31, 72, 45, + 209, 0, 0, 0, 4, 115, 66, 73, 84, 8, 8, 8, 8, 124, 8, 100, + 136, 0, 0, 0, 9, 112, 72, 89, 115, 0, 0, 25, 214, 0, 0, 25, + 214, 1, 24, 209, 202, 237, 0, 0, 0, 25, 116, 69, 88, 116, 83, 111, + 102, 116, 119, 97, 114, 101, 0, 119, 119, 119, 46, 105, 110, 107, 115, 99, + 97, 112, 101, 46, 111, 114, 103, 155, 238, 60, 26, 0, 0, 0, 219, 73, + 68, 65, 84, 40, 145, 157, 210, 61, 110, 194, 64, 16, 197, 241, 255, 155, + 180, 73, 27, 250, 149, 125, 26, 168, 227, 3, 100, 139, 52, 112, 25, 119, + 193, 18, 37, 18, 73, 71, 114, 26, 44, 247, 136, 14, 234, 245, 164, 8, + 70, 40, 31, 36, 203, 43, 87, 243, 219, 183, 35, 173, 56, 139, 119, 113, + 68, 111, 51, 228, 99, 160, 56, 30, 111, 112, 127, 199, 168, 21, 154, 237, + 48, 171, 19, 106, 99, 133, 212, 0, 183, 252, 156, 3, 34, 42, 204, 87, + 39, 120, 68, 203, 243, 139, 126, 137, 35, 85, 10, 207, 47, 242, 46, 142, + 112, 181, 23, 154, 190, 55, 251, 77, 97, 244, 54, 203, 64, 0, 119, 88, + 154, 26, 242, 73, 6, 26, 30, 60, 49, 32, 100, 67, 40, 236, 10, 4, + 208, 27, 208, 93, 1, 59, 195, 125, 157, 205, 228, 107, 195, 168, 129, 67, + 6, 219, 147, 82, 109, 10, 205, 22, 17, 1, 255, 7, 114, 228, 143, 42, + 23, 59, 3, 80, 152, 175, 144, 170, 63, 154, 247, 200, 31, 20, 154, 87, + 248, 242, 197, 188, 125, 186, 199, 210, 20, 52, 198, 189, 252, 220, 71, 27, + 232, 223, 72, 169, 86, 185, 216, 13, 179, 31, 173, 248, 73, 235, 173, 142, + 53, 34, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130 +}; + +} // namespace GRResources + +#endif diff --git a/modules/godot_remote/godot_remote/GRResources.h b/modules/godot_remote/godot_remote/GRResources.h new file mode 100644 index 0000000..3999a0a --- /dev/null +++ b/modules/godot_remote/godot_remote/GRResources.h @@ -0,0 +1,53 @@ +/* GRBinResources.h */ +#ifndef NO_GODOTREMOTE_DEFAULT_RESOURCES + +#ifndef GRRESOURCES_H +#define GRRESOURCES_H + +#ifndef GDNATIVE_LIBRARY +#define GetPoolVectorFromBin(to_var, res) \ + PoolByteArray to_var; \ + to_var.resize(res##_size); \ + auto to_var##write = to_var.write(); \ + memcpy(to_var##write.ptr(), res, res##_size); \ + to_var##write.release() +#else +#define GetPoolVectorFromBin(to_var, res) \ + PoolByteArray to_var; \ + to_var.resize(res##_size); \ + auto to_var##write = to_var.write(); \ + memcpy(to_var##write.ptr(), res, res##_size); +#endif + +namespace GRResources { + +extern const char *Txt_CRT_Shader; + +extern const unsigned int Bin_NoSignalPNG_size; +extern const unsigned char Bin_NoSignalPNG[]; + +extern const unsigned int Bin_NoSignalVerticalPNG_size; +extern const unsigned char Bin_NoSignalVerticalPNG[]; + +// NOTIFICATION ICONS + +extern const unsigned int Bin_CloseIconPNG_size; +extern const unsigned char Bin_CloseIconPNG[]; + +extern const unsigned int Bin_ConnectedIconPNG_size; +extern const unsigned char Bin_ConnectedIconPNG[]; + +extern const unsigned int Bin_DisconnectedIconPNG_size; +extern const unsigned char Bin_DisconnectedIconPNG[]; + +extern const unsigned int Bin_ErrorIconPNG_size; +extern const unsigned char Bin_ErrorIconPNG[]; + +extern const unsigned int Bin_WarningIconPNG_size; +extern const unsigned char Bin_WarningIconPNG[]; + +} // namespace GRResources + +#endif // !GRRESOURCES_H + +#endif diff --git a/modules/godot_remote/godot_remote/GRServer.cpp b/modules/godot_remote/godot_remote/GRServer.cpp new file mode 100644 index 0000000..3cd7e79 --- /dev/null +++ b/modules/godot_remote/godot_remote/GRServer.cpp @@ -0,0 +1,1805 @@ +/* GRServer.cpp */ + +#ifndef NO_GODOTREMOTE_SERVER + +#include "GRServer.h" +#include "GRNotifications.h" +#include "GRPacket.h" +#include "GodotRemote.h" + +#ifndef GDNATIVE_LIBRARY + +#include "core/input_map.h" +#include "core/io/pck_packer.h" +#include "core/io/resource_loader.h" +#include "core/os/dir_access.h" +#include "core/os/file_access.h" +#include "core/os/input_event.h" +#include "core/os/thread_safe.h" +#include "main/input_default.h" +#include "scene/main/node.h" +#include "scene/main/scene_tree.h" + +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace godot; +#endif + +using namespace GRUtils; + +#ifndef GDNATIVE_LIBRARY + +void GRServer::_bind_methods() { + ClassDB::bind_method(D_METHOD("_load_settings"), &GRServer::_load_settings); + ClassDB::bind_method(D_METHOD("_remove_resize_viewport", "vp"), &GRServer::_remove_resize_viewport); + ClassDB::bind_method(D_METHOD("_on_grviewport_deleting"), &GRServer::_on_grviewport_deleting); + + ClassDB::bind_method(D_METHOD("get_gr_viewport"), &GRServer::get_gr_viewport); + ClassDB::bind_method(D_METHOD("force_update_custom_input_scene"), &GRServer::force_update_custom_input_scene); + + ClassDB::bind_method(D_METHOD("set_video_stream_enabled", "value"), &GRServer::set_video_stream_enabled); + ClassDB::bind_method(D_METHOD("set_skip_frames", "frames"), &GRServer::set_skip_frames); + //ClassDB::bind_method(D_METHOD("set_auto_adjust_scale"), &GRServer::set_auto_adjust_scale); + ClassDB::bind_method(D_METHOD("set_jpg_quality", "quality"), &GRServer::set_jpg_quality); + ClassDB::bind_method(D_METHOD("set_render_scale", "scale"), &GRServer::set_render_scale); + ClassDB::bind_method(D_METHOD("set_password", "password"), &GRServer::set_password); + ClassDB::bind_method(D_METHOD("set_custom_input_scene", "_scn"), &GRServer::set_custom_input_scene); + ClassDB::bind_method(D_METHOD("set_custom_input_scene_compressed", "_is_compressed"), &GRServer::set_custom_input_scene_compressed); + ClassDB::bind_method(D_METHOD("set_custom_input_scene_compression_type", "_type"), &GRServer::set_custom_input_scene_compression_type); + + ClassDB::bind_method(D_METHOD("is_video_stream_enabled"), &GRServer::is_video_stream_enabled); + ClassDB::bind_method(D_METHOD("get_skip_frames"), &GRServer::get_skip_frames); + //ClassDB::bind_method(D_METHOD("is_auto_adjust_scale"), &GRServer::is_auto_adjust_scale); + ClassDB::bind_method(D_METHOD("get_jpg_quality"), &GRServer::get_jpg_quality); + ClassDB::bind_method(D_METHOD("get_render_scale"), &GRServer::get_render_scale); + ClassDB::bind_method(D_METHOD("get_password"), &GRServer::get_password); + ClassDB::bind_method(D_METHOD("get_custom_input_scene"), &GRServer::get_custom_input_scene); + ClassDB::bind_method(D_METHOD("is_custom_input_scene_compressed"), &GRServer::is_custom_input_scene_compressed); + ClassDB::bind_method(D_METHOD("get_custom_input_scene_compression_type"), &GRServer::get_custom_input_scene_compression_type); + + //ADD_PROPERTY(PropertyInfo(Variant::BOOL, "video_stream_enabled"), "set_video_stream_enabled", "is_video_stream_enabled"); + //ADD_PROPERTY(PropertyInfo(Variant::INT, "skip_frames"), "set_skip_frames", "get_skip_frames"); + ////ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_adjust_scale"), "set_auto_adjust_scale", "is_auto_adjust_scale"); + //ADD_PROPERTY(PropertyInfo(Variant::INT, "jpg_quality"), "set_jpg_quality", "get_jpg_quality"); + //ADD_PROPERTY(PropertyInfo(Variant::INT, "render_scale"), "set_render_scale", "get_render_scale"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "password"), "set_password", "get_password"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "custom_input_scene"), "set_custom_input_scene", "get_custom_input_scene"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_input_scene_compressed"), "set_custom_input_scene_compressed", "is_custom_input_scene_compressed"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "custom_input_scene_compression_type"), "set_custom_input_scene_compression_type", "get_custom_input_scene_compression_type"); + + ADD_SIGNAL(MethodInfo("client_connected", PropertyInfo(Variant::STRING, "device_id"))); + ADD_SIGNAL(MethodInfo("client_disconnected", PropertyInfo(Variant::STRING, "device_id"))); + + ADD_SIGNAL(MethodInfo("client_viewport_orientation_changed", PropertyInfo(Variant::BOOL, "is_vertical"))); + ADD_SIGNAL(MethodInfo("client_viewport_aspect_ratio_changed", PropertyInfo(Variant::REAL, "stream_aspect_ratio"))); +} + +#else + +void GRServer::_register_methods() { + /////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////// + /* + METHOD_REG(GRServer, _internal_call_only_deffered_start); + METHOD_REG(GRServer, _internal_call_only_deffered_stop); + + METHOD_REG(GRServer, _internal_call_only_deffered_restart); + + METHOD_REG(GRServer, get_avg_ping); + METHOD_REG(GRServer, get_avg_fps); + + METHOD_REG(GRServer, get_port); + METHOD_REG(GRServer, set_port); + + METHOD_REG(GRServer, start); + METHOD_REG(GRServer, stop); + METHOD_REG(GRServer, get_status); + + register_signal("status_changed", "status", GODOT_VARIANT_TYPE_INT); + register_property("port", &GRServer::set_port, &GRServer::get_port, 52341); + */ + /////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////// + + METHOD_REG(GRServer, _notification); + METHOD_REG(GRServer, _thread_listen); + METHOD_REG(GRServer, _thread_connection); + METHOD_REG(GRServer, _on_grviewport_deleting); + + METHOD_REG(GRServer, _load_settings); + METHOD_REG(GRServer, _remove_resize_viewport); + + METHOD_REG(GRServer, get_gr_viewport); + METHOD_REG(GRServer, force_update_custom_input_scene); + + METHOD_REG(GRServer, set_video_stream_enabled); + METHOD_REG(GRServer, set_skip_frames); + //METHOD_REG(GRServer, set_auto_adjust_scale); + METHOD_REG(GRServer, set_jpg_quality); + METHOD_REG(GRServer, set_render_scale); + METHOD_REG(GRServer, set_password); + METHOD_REG(GRServer, set_custom_input_scene); + METHOD_REG(GRServer, set_custom_input_scene_compressed); + METHOD_REG(GRServer, set_custom_input_scene_compression_type); + + METHOD_REG(GRServer, is_video_stream_enabled); + METHOD_REG(GRServer, get_skip_frames); + //METHOD_REG(GRServer, is_auto_adjust_scale); + METHOD_REG(GRServer, get_jpg_quality); + METHOD_REG(GRServer, get_render_scale); + METHOD_REG(GRServer, get_password); + METHOD_REG(GRServer, get_custom_input_scene); + METHOD_REG(GRServer, is_custom_input_scene_compressed); + METHOD_REG(GRServer, get_custom_input_scene_compression_type); + + //register_property("video_stream_enabled", &GRServer::set_video_stream_enabled, &GRServer::is_video_stream_enabled, true); + //register_property("skip_frames", &GRServer::set_skip_frames, &GRServer::get_skip_frames, 0); + ////register_property("auto_adjust_scale", &GRServer::set_auto_adjust_scale, &GRServer::is_auto_adjust_scale, true); + //register_property("jpg_quality", &GRServer::set_jpg_quality, &GRServer::get_jpg_quality, 80); + //register_property("render_scale", &GRServer::set_render_scale, &GRServer::get_render_scale, 0.3f); + register_property("password", &GRServer::set_password, &GRServer::get_password, ""); + register_property("custom_input_scene", &GRServer::set_custom_input_scene, &GRServer::get_custom_input_scene, ""); + register_property("custom_input_scene_compressed", &GRServer::set_custom_input_scene_compressed, &GRServer::is_custom_input_scene_compressed, true); + register_property("custom_input_scene_compression_type", &GRServer::set_custom_input_scene_compression_type, &GRServer::get_custom_input_scene_compression_type, 0); + + register_signal("client_connected", "device_id", GODOT_VARIANT_TYPE_STRING); + register_signal("client_disconnected", "device_id", GODOT_VARIANT_TYPE_STRING); + + register_signal("client_viewport_orientation_changed", "is_vertical", GODOT_VARIANT_TYPE_BOOL); + register_signal("client_viewport_aspect_ratio_changed", "stream_aspect_ratio", GODOT_VARIANT_TYPE_REAL); +} + +#endif + +void GRServer::_notification(int p_notification) { + switch (p_notification) { + case NOTIFICATION_POSTINITIALIZE: +#ifndef GDNATIVE_LIBRARY + _init(); +#endif + break; + case NOTIFICATION_PREDELETE: { + _deinit(); + GRDevice::_deinit(); + break; + case NOTIFICATION_EXIT_TREE: + if (get_status() == (int)WorkingStatus::STATUS_WORKING) { + _internal_call_only_deffered_stop(); + } + break; + } + } +} + +void GRServer::set_auto_adjust_scale(bool _val) { + auto_adjust_scale = _val; +} + +bool GRServer::is_auto_adjust_scale() { + return auto_adjust_scale; +} + +bool GRServer::set_video_stream_enabled(bool val) { + if (resize_viewport && !resize_viewport->is_queued_for_deletion() && + resize_viewport->is_video_stream_enabled() != val) { + resize_viewport->set_video_stream_enabled(val); + return true; + } + return false; +} + +bool GRServer::is_video_stream_enabled() { + if (resize_viewport && !resize_viewport->is_queued_for_deletion()) + return resize_viewport->is_video_stream_enabled(); + return false; +} + +bool GRServer::set_compression_type(ImageCompressionType _type) { + if (resize_viewport && !resize_viewport->is_queued_for_deletion() && + resize_viewport->get_compression_type() != _type) { + resize_viewport->set_compression_type(_type); + return true; + } + return false; +} + +GRDevice::ImageCompressionType GRServer::get_compression_type() { + if (resize_viewport && !resize_viewport->is_queued_for_deletion()) + return resize_viewport->get_compression_type(); + return ImageCompressionType::COMPRESSION_UNCOMPRESSED; +} + +bool GRServer::set_render_scale(float _scale) { + if (resize_viewport && !resize_viewport->is_queued_for_deletion() && + resize_viewport->get_rendering_scale() != _scale) { + resize_viewport->set_rendering_scale(_scale); + return true; + } + return false; +} + +float GRServer::get_render_scale() { + if (resize_viewport && !resize_viewport->is_queued_for_deletion()) + return resize_viewport->get_rendering_scale(); + return -1; +} + +bool GRServer::set_skip_frames(int fps) { + if (resize_viewport && !resize_viewport->is_queued_for_deletion() && + resize_viewport->get_skip_frames() != fps) { + resize_viewport->set_skip_frames(fps); + return true; + } + return false; +} + +int GRServer::get_skip_frames() { + if (resize_viewport && !resize_viewport->is_queued_for_deletion()) + return resize_viewport->get_skip_frames(); + return -1; +} + +bool GRServer::set_jpg_quality(int quality) { + ERR_FAIL_COND_V(quality < 0 || quality > 100, false); + if (resize_viewport && !resize_viewport->is_queued_for_deletion() && + resize_viewport->get_jpg_quality() != quality) { + resize_viewport->set_jpg_quality(quality); + return true; + } + return false; +} + +int GRServer::get_jpg_quality() { + if (resize_viewport && !resize_viewport->is_queued_for_deletion()) + return resize_viewport->get_jpg_quality(); + return -1; +} + +void GRServer::set_password(String _pass) { + password = _pass; +} + +String GRServer::get_password() { + return password; +} + +void GRServer::set_custom_input_scene(String _scn) { + if (custom_input_scene != _scn) { + custom_input_scene = _scn; + force_update_custom_input_scene(); + } +} + +String GRServer::get_custom_input_scene() { + return custom_input_scene; +} + +void GRServer::set_custom_input_scene_compressed(bool _is_compressed) { + custom_input_pck_compressed = _is_compressed; +} + +bool GRServer::is_custom_input_scene_compressed() { + return custom_input_pck_compressed; +} + +void GRServer::set_custom_input_scene_compression_type(int _type) { + custom_input_pck_compression_type = ENUM_CONV(Compression::Mode) _type; +} + +int GRServer::get_custom_input_scene_compression_type() { + return custom_input_pck_compression_type; +} + +void GRServer::_init() { + set_name("GodotRemoteServer"); + LEAVE_IF_EDITOR(); + + tcp_server.instance(); + +#ifndef GDNATIVE_LIBRARY +#else + GRDevice::_init(); +#endif + + Mutex_create(connection_mutex); + + custom_input_scene_regex_resource_finder.instance(); + custom_input_scene_regex_resource_finder->compile(custom_input_scene_regex_resource_finder_pattern); + init_server_utils(); +} + +void GRServer::_deinit() { + LEAVE_IF_EDITOR(); + if (get_status() == (int)WorkingStatus::STATUS_WORKING) { + _internal_call_only_deffered_stop(); + } + Mutex_delete(connection_mutex); + + custom_input_scene_regex_resource_finder.unref(); + deinit_server_utils(); +} + +void GRServer::_internal_call_only_deffered_start() { + switch ((WorkingStatus)get_status()) { + case WorkingStatus::STATUS_WORKING: + ERR_FAIL_MSG("Can't start already working GodotRemote Server"); + case WorkingStatus::STATUS_STARTING: + ERR_FAIL_MSG("Can't start already starting GodotRemote Server"); + case WorkingStatus::STATUS_STOPPING: + ERR_FAIL_MSG("Can't start stopping GodotRemote Server"); + } + + set_status(WorkingStatus::STATUS_STARTING); + _log("Starting GodotRemote server. Version: " + str(GodotRemote::get_singleton()->get_version()), LogLevel::LL_NORMAL); + + if (server_thread_listen) { + server_thread_listen->close_thread(); + memdelete(server_thread_listen); + server_thread_listen = nullptr; + } + + if (!resize_viewport) { + resize_viewport = memnew(GRSViewport); + add_child(resize_viewport); + } + + server_thread_listen = memnew(ListenerThreadParamsServer); + server_thread_listen->dev = this; + Thread_start(server_thread_listen->thread_ref, GRServer, _thread_listen, server_thread_listen, this); + + set_status(WorkingStatus::STATUS_WORKING); + call_deferred("_load_settings"); + + GRNotifications::add_notification("Godot Remote Server Status", "Server started", GRNotifications::GRNotifications::NotificationIcon::ICON_SUCCESS, true, 1.f); +} + +void GRServer::_internal_call_only_deffered_stop() { + switch ((WorkingStatus)get_status()) { + case WorkingStatus::STATUS_STOPPED: + ERR_FAIL_MSG("Can't stop already stopped GodotRemote Server"); + case WorkingStatus::STATUS_STOPPING: + ERR_FAIL_MSG("Can't stop already stopping GodotRemote Server"); + case WorkingStatus::STATUS_STARTING: + ERR_FAIL_MSG("Can't stop starting GodotRemote Server"); + } + + set_status(WorkingStatus::STATUS_STOPPING); + _log("Stopping GodotRemote server", LogLevel::LL_NORMAL); + + if (server_thread_listen) { + server_thread_listen->close_thread(); + memdelete(server_thread_listen); + server_thread_listen = nullptr; + } + + if (resize_viewport) + resize_viewport->set_process(false); + call_deferred("_remove_resize_viewport", resize_viewport); + resize_viewport = nullptr; + + _send_queue_resize(0); + + set_status(WorkingStatus::STATUS_STOPPED); + + GRNotifications::add_notification("Godot Remote Server Status", "Server stopped", GRNotifications::NotificationIcon::ICON_FAIL, true, 1.f); +} + +void GRServer::_remove_resize_viewport(Node *node) { + GRSViewport *vp = cast_to(node); + if (vp && !vp->is_queued_for_deletion()) { + remove_child(vp); + memdelete(vp); + } +} + +void GRServer::_on_grviewport_deleting() { + resize_viewport = nullptr; +} + +GRSViewport *GRServer::get_gr_viewport() { + return resize_viewport; +} + +void GRServer::force_update_custom_input_scene() { + custom_input_scene_was_updated = false; +} + +void GRServer::_adjust_viewport_scale() { + if (!resize_viewport) + return; + + const float smooth = 0.8f; + float scale = resize_viewport->auto_scale; + + if (!auto_adjust_scale) { + //if (scale == -1.f) + // return; + + scale = -1.f; + goto end; + } + + if (prev_avg_fps == 0) { + prev_avg_fps = avg_fps; + } else { + prev_avg_fps = (prev_avg_fps * smooth) + (avg_fps * (1.f - smooth)); + } + _log(prev_avg_fps, LogLevel::LL_NORMAL); + + if (prev_avg_fps < resize_viewport->get_skip_frames() - 4) { + scale -= 0.001f; + } else if (prev_avg_fps > resize_viewport->get_skip_frames() - 1) { + scale += 0.0012f; + } + + if (scale < 0.1f) + scale = 0.1f; + if (scale > 1) + scale = 1; + +end: + resize_viewport->auto_scale = scale; + prev_avg_fps = 0; + resize_viewport->call_deferred("_update_size"); +} + +void GRServer::_load_settings() { + using_client_settings = false; + + const String title = "Server settings updated"; + GRNotifications::add_notification_or_update_line(title, "title", "Loaded default server settings", GRNotifications::NotificationIcon::ICON_NONE, 1.f); + + // only updated by server itself + password = GET_PS(GodotRemote::ps_server_password_name); + set_custom_input_scene(GET_PS(GodotRemote::ps_server_custom_input_scene_name)); +#ifndef GDNATIVE_LIBRARY + set_custom_input_scene_compressed(GET_PS(GodotRemote::ps_server_custom_input_scene_compressed_name)); + set_custom_input_scene_compression_type(ENUM_CONV(Compression::Mode)(int) GET_PS(GodotRemote::ps_server_custom_input_scene_compression_type_name)); +#endif + + GRNotifications::add_notification_or_update_line(title, "cis", "Custom input scene: " + str(get_custom_input_scene()), GRNotifications::NotificationIcon::ICON_NONE, 1.f); + if (!get_custom_input_scene().empty()) { + GRNotifications::add_notification_or_update_line(title, "cisc", "Scene compressed: " + str(is_custom_input_scene_compressed()), GRNotifications::NotificationIcon::ICON_NONE, 1.f); + GRNotifications::add_notification_or_update_line(title, "cisct", "Scene compression type: " + str(get_custom_input_scene_compression_type()), GRNotifications::NotificationIcon::ICON_NONE, 1.f); + } + + // can be updated by client + auto_adjust_scale = GET_PS(GodotRemote::ps_server_auto_adjust_scale_name); // TODO move to viewport + + GRNotifications::add_notification_or_update_line(title, "auto_scale", "Auto adjust scale: " + str(auto_adjust_scale), GRNotifications::NotificationIcon::ICON_NONE, 1.f); // TODO not completed + if (resize_viewport && !resize_viewport->is_queued_for_deletion()) { + set_video_stream_enabled((bool)GET_PS(GodotRemote::ps_server_stream_enabled_name)); + set_compression_type((ImageCompressionType)(int)GET_PS(GodotRemote::ps_server_compression_type_name)); + set_jpg_quality(GET_PS(GodotRemote::ps_server_jpg_quality_name)); + set_render_scale(GET_PS(GodotRemote::ps_server_scale_of_sending_stream_name)); + set_skip_frames(GET_PS(GodotRemote::ps_server_stream_skip_frames_name)); + + GRNotifications::add_notification_or_update_line(title, "stream", "Stream enabled: " + str(is_video_stream_enabled()), GRNotifications::NotificationIcon::ICON_NONE, 1.f); + GRNotifications::add_notification_or_update_line(title, "compression", "Compression type: " + str(get_render_scale()), GRNotifications::NotificationIcon::ICON_NONE, 1.f); + GRNotifications::add_notification_or_update_line(title, "quality", "JPG Quality: " + str(get_jpg_quality()), GRNotifications::NotificationIcon::ICON_NONE, 1.f); + GRNotifications::add_notification_or_update_line(title, "skip", "Skip Frames: " + str(get_skip_frames()), GRNotifications::NotificationIcon::ICON_NONE, 1.f); + GRNotifications::add_notification_or_update_line(title, "scale", "Scale of stream: " + str(get_render_scale()), GRNotifications::NotificationIcon::ICON_NONE, 1.f); + } else { + _log("Resize viewport not found!", LogLevel::LL_ERROR); + GRNotifications::add_notification("Critical Error", "Resize viewport not found!", GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + } + + // notification + GRNotificationPanelUpdatable *np = cast_to(GRNotifications::get_notification(title)); + if (np) { + np->clear_lines(); + } +} + +void GRServer::_update_settings_from_client(const std::map settings) { +#define SET_BODY(_func, _id, _text, _type) \ + if (_func(value)) { \ + GRNotifications::add_notification_or_update_line(title, _id, _text + str((_type value)), GRNotifications::NotificationIcon::ICON_NONE, 1.f); \ + using_client_settings = true; \ + using_client_settings_recently_updated = true; \ + } +#define SET_BODY_CONVERT(_func, _conv, _id, _text, _type) \ + if (_func(_conv(value))) { \ + GRNotifications::add_notification_or_update_line(title, _id, _text + str((_type value)), GRNotifications::NotificationIcon::ICON_NONE, 1.f); \ + using_client_settings = true; \ + using_client_settings_recently_updated = true; \ + } + + const String title = "Server settings updated"; + + GRNotificationPanelUpdatable *np = cast_to(GRNotifications::get_notification(title)); + if (np) { + np->remove_updatable_line("title"); + } + + if (!resize_viewport || resize_viewport->is_queued_for_deletion()) { + _log("Resize viewport not found!", LogLevel::LL_ERROR); + GRNotifications::add_notification("Critical Error", "Resize viewport not found!", GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + } + + for (auto p : settings) { + Variant key = p.first; + Variant value = p.second; + _log("Trying to set server setting from client with key: " + str((int)key) + " and value: " + str(value), LogLevel::LL_DEBUG); + + if (key.get_type() == Variant::INT) { + TypesOfServerSettings k = (TypesOfServerSettings)(int)key; + switch (k) { + case TypesOfServerSettings::SERVER_SETTINGS_USE_INTERNAL: + if ((bool)value) { + call_deferred("_load_settings"); + return; + } + break; + case TypesOfServerSettings::SERVER_SETTINGS_VIDEO_STREAM_ENABLED: { + SET_BODY(set_video_stream_enabled, "stream", "Stream enabled: ", (bool)); + break; + } + case TypesOfServerSettings::SERVER_SETTINGS_COMPRESSION_TYPE: { + SET_BODY_CONVERT(set_compression_type, (ImageCompressionType)(int), "compression", "Compression type: ", (int)); + break; + } + case TypesOfServerSettings::SERVER_SETTINGS_JPG_QUALITY: { + SET_BODY(set_jpg_quality, "quality", "JPG Quality: ", (int)); + break; + } + case TypesOfServerSettings::SERVER_SETTINGS_SKIP_FRAMES: { + SET_BODY(set_skip_frames, "skip", "Skip Frames: ", (int)); + break; + } + case TypesOfServerSettings::SERVER_SETTINGS_RENDER_SCALE: { + SET_BODY(set_render_scale, "scale", "Scale of stream: ", (float)); + break; + } + default: + _log("Unknown server setting with code: " + str((int)k), LogLevel::LL_NORMAL); + break; + } + } + } + +#undef SET_BODY +#undef SET_BODY_CONVERT +} + +void GRServer::_reset_counters() { + GRDevice::_reset_counters(); + prev_avg_fps = 0; +} + +////////////////////////////////////////////// +////////////////// STATIC //////////////////// +////////////////////////////////////////////// + +void GRServer::_thread_listen(THREAD_DATA p_userdata) { + Thread_set_name("GR_listen_thread"); + ListenerThreadParamsServer *this_thread_info = (ListenerThreadParamsServer *)p_userdata; + GRServer *dev = this_thread_info->dev; + Ref srv = dev->tcp_server; + OS *os = OS::get_singleton(); + ConnectionThreadParamsServer *connection_thread_info = nullptr; + Error err = Error::OK; + bool listening_error_notification_shown = false; + + while (!this_thread_info->stop_thread) { + if (!srv->is_listening()) { + err = srv->listen(dev->port); + + if (err != Error::OK) { + switch (err) { + case Error::ERR_UNAVAILABLE: { + String txt = "Socket listening unavailable"; + _log(txt, LogLevel::LL_ERROR); + if (!listening_error_notification_shown) + GRNotifications::add_notification("Can't start listening", txt, GRNotifications::NotificationIcon::ICON_ERROR, true, 1.25f); + break; + } + case Error::ERR_ALREADY_IN_USE: { + String txt = "Socket already in use"; + _log(txt, LogLevel::LL_ERROR); + if (!listening_error_notification_shown) + GRNotifications::add_notification("Can't start listening", txt, GRNotifications::NotificationIcon::ICON_ERROR, true, 1.25f); + break; + } + case Error::ERR_INVALID_PARAMETER: { + String txt = "Invalid listening address"; + _log(txt, LogLevel::LL_ERROR); + if (!listening_error_notification_shown) + GRNotifications::add_notification("Can't start listening", txt, GRNotifications::NotificationIcon::ICON_ERROR, true, 1.25f); + break; + } + case Error::ERR_CANT_CREATE: { + String txt = "Can't bind listener"; + _log(txt, LogLevel::LL_ERROR); + if (!listening_error_notification_shown) + GRNotifications::add_notification("Can't start listening", txt, GRNotifications::NotificationIcon::ICON_ERROR, true, 1.25f); + break; + } + case Error::FAILED: { + String txt = "Failed to start listening"; + _log(txt, LogLevel::LL_ERROR); + if (!listening_error_notification_shown) + GRNotifications::add_notification("Can't start listening", txt, GRNotifications::NotificationIcon::ICON_ERROR, true, 1.25f); + break; + } + } + + listening_error_notification_shown = true; + sleep_usec(1000_ms); + continue; + } else { + _log("Start listening port " + str(dev->port), LogLevel::LL_NORMAL); + GRNotifications::add_notification("Start listening", "Start listening on port: " + str(dev->port), GRNotifications::NotificationIcon::ICON_SUCCESS, true, 1.f); + } + } + listening_error_notification_shown = false; + + if (connection_thread_info) { + if (connection_thread_info->ppeer.is_null()) { + connection_thread_info->break_connection = true; + } + + if (connection_thread_info->finished || connection_thread_info->break_connection) { + _log("Waiting connection thread...", LogLevel::LL_DEBUG); + connection_thread_info->close_thread(); + memdelete(connection_thread_info); + connection_thread_info = nullptr; + } + } + + if (srv->is_connection_available()) { + Ref con = srv->take_connection(); + con->set_no_delay(true); + String address = CONNECTION_ADDRESS(con); + + Ref ppeer(memnew(PacketPeerStream)); + ppeer->set_stream_peer(con); + ppeer->set_output_buffer_max_size(_grutils_data_server->compress_buffer.size()); + + if (!connection_thread_info) { + Dictionary ret_data; + GRDevice::AuthResult res = _auth_client(dev, ppeer, ret_data, false); + String dev_id = ""; + + if (ret_data.has("id")) { + dev_id = ret_data["id"]; + } + + switch (res) { + case GRDevice::AuthResult::OK: + connection_thread_info = memnew(ConnectionThreadParamsServer); + connection_thread_info->device_id = dev_id; + + connection_thread_info->dev = dev; + connection_thread_info->ppeer = ppeer; + + dev->custom_input_scene_was_updated = false; + dev->client_connected++; + + Thread_start(connection_thread_info->thread_ref, GRServer, _thread_connection, connection_thread_info, dev); + _log("New connection from " + address, LogLevel::LL_NORMAL); + + dev->call_deferred("emit_signal", "client_connected", dev_id); + GRNotifications::add_notification("Connected", "Client connected: " + address + "\nDevice ID: " + connection_thread_info->device_id, GRNotifications::NotificationIcon::ICON_SUCCESS, true, 1.f); + break; + + case GRDevice::AuthResult::VersionMismatch: + case GRDevice::AuthResult::IncorrectPassword: + case GRDevice::AuthResult::Error: + case GRDevice::AuthResult::RefuseConnection: + case GRDevice::AuthResult::Timeout: + continue; + default: + _log("Unknown error code. Disconnecting. " + address, LogLevel::LL_NORMAL); + continue; + } + + } else { + Dictionary ret_data; + GRDevice::AuthResult res = _auth_client(dev, ppeer, ret_data, true); + } + } else { + _log("Waiting...", LogLevel::LL_DEBUG); + sleep_usec(33_ms); + } + } + + if (connection_thread_info) { + _log("Closing connection thread...", LogLevel::LL_DEBUG); + connection_thread_info->break_connection = true; + connection_thread_info->close_thread(); + memdelete(connection_thread_info); + connection_thread_info = nullptr; + } + + dev->tcp_server->stop(); + this_thread_info->finished = true; +} + +void GRServer::_thread_connection(THREAD_DATA p_userdata) { + ConnectionThreadParamsServer *thread_info = (ConnectionThreadParamsServer *)p_userdata; + Ref connection = thread_info->ppeer->get_stream_peer(); + Ref ppeer = thread_info->ppeer; + GRServer *dev = thread_info->dev; + dev->_reset_counters(); + dev->_send_queue_resize(0); + + GodotRemote *gr = GodotRemote::get_singleton(); + OS *os = OS::get_singleton(); + Input *input = Input::get_singleton(); + Error err = Error::OK; + + Input::MouseMode mouse_mode = Input::MOUSE_MODE_VISIBLE; + String address = CONNECTION_ADDRESS(connection); + Thread_set_name("GR_connection " + address); + + uint64_t time64 = os->get_ticks_usec(); + uint64_t prev_send_settings_time = time64; + uint64_t prev_send_image_time = time64; + uint64_t prev_ping_sending_time = time64; + uint64_t prev_process_image_time = time64; + //uint64_t prev_send_sync_time = time64; + + bool ping_sended = false; + bool time_synced = false; + + TimeCountInit(); + while (!thread_info->break_connection && connection.is_valid() && + !connection->is_queued_for_deletion() && connection->is_connected_to_host()) { + + bool nothing_happens = true; + float fps = Engine::get_singleton()->get_frames_per_second(); + if (fps == 0) { + fps = 1; + } + + if (dev->resize_viewport && !dev->resize_viewport->is_queued_for_deletion()) { + if (dev->resize_viewport->get_skip_frames()) + fps = fps / dev->resize_viewport->get_skip_frames(); + + if (!dev->resize_viewport->is_processing()) { + dev->resize_viewport->set_process(true); + dev->resize_viewport->force_get_image(); + } + } + + uint64_t send_data_time_us = uint64_t(1000000.0 / fps); + TimeCount("Cycle start"); + + /////////////////////////////////////////////////////////////////// + // SENDING + bool is_queued_send = false; // this placed here for android compiler + uint64_t start_while_time = os->get_ticks_usec(); + + // TIME SYNC + //time = os->get_ticks_usec(); + //if (time - prev_send_sync_time > 1000_ms) { + if (!time_synced) { + time_synced = true; + nothing_happens = false; + //prev_send_sync_time = time; + Ref pack(memnew(GRPacketSyncTime)); + err = ppeer->put_var(pack->get_data()); + if ((int)err) { + _log("Can't send sync time data! Code: " + str((int)err), LogLevel::LL_ERROR); + goto end_send; + } + TimeCount("Sync Time Send"); + } + + // IMAGE + TimeCountReset(); + time64 = os->get_ticks_usec(); + // if image compressed and data is ready + if (dev->resize_viewport && !dev->resize_viewport->is_queued_for_deletion() && + dev->resize_viewport->has_compressed_image_data()) { + nothing_happens = false; + + Ref pack(memnew(GRPacketImageData)); + + auto ips = dev->resize_viewport->get_last_compressed_image_data(); + + if (!(ips->ret_data.size() == 0) || ips->is_empty) { // if not broken image or force empty image :) + pack->set_is_empty(ips->is_empty); + pack->set_compression_type((int)ips->compression_type); + pack->set_size(Size2((float)ips->width, (float)ips->height)); + pack->set_format(ips->format); + pack->set_image_data(ips->ret_data); + pack->set_start_time(os->get_ticks_usec()); + pack->set_frametime(send_data_time_us); + + err = ppeer->put_var(pack->get_data()); + + // avg fps + dev->_update_avg_fps(time64 - prev_send_image_time); + dev->_adjust_viewport_scale(); + prev_send_image_time = time64; + + if ((int)err) { + _log("Can't send image data! Code: " + str((int)err), LogLevel::LL_ERROR); + memdelete(ips); + ips = nullptr; + goto end_send; + } + } + memdelete(ips); + ips = nullptr; + } else { + if (!dev->is_video_stream_enabled()) { + dev->_update_avg_fps(0); + } + } + + // SERVER SETTINGS + TimeCountReset(); + time64 = os->get_ticks_usec(); + if (time64 - prev_send_settings_time > 1000_ms && dev->using_client_settings) { + prev_send_settings_time = time64; + if (dev->using_client_settings_recently_updated) { + dev->using_client_settings_recently_updated = false; + } else { + nothing_happens = false; + + Ref pack(memnew(GRPacketServerSettings)); + pack->add_setting((int)TypesOfServerSettings::SERVER_SETTINGS_VIDEO_STREAM_ENABLED, dev->is_video_stream_enabled()); + pack->add_setting((int)TypesOfServerSettings::SERVER_SETTINGS_COMPRESSION_TYPE, dev->get_compression_type()); + pack->add_setting((int)TypesOfServerSettings::SERVER_SETTINGS_JPG_QUALITY, dev->get_jpg_quality()); + pack->add_setting((int)TypesOfServerSettings::SERVER_SETTINGS_RENDER_SCALE, dev->get_render_scale()); + pack->add_setting((int)TypesOfServerSettings::SERVER_SETTINGS_SKIP_FRAMES, dev->get_skip_frames()); + + err = ppeer->put_var(pack->get_data()); + if ((int)err) { + _log("Send server settings failed with code: " + str((int)err), LogLevel::LL_ERROR); + goto end_send; + } + TimeCount("Send server settings"); + } + } + + // MOUSE MODE + TimeCountReset(); + if (input->get_mouse_mode() != mouse_mode) { + nothing_happens = false; + mouse_mode = input->get_mouse_mode(); + + Ref pack(memnew(GRPacketMouseModeSync)); + pack->set_mouse_mode(mouse_mode); + + err = ppeer->put_var(pack->get_data()); + if ((int)err) { + _log("Send mouse mode sync failed with code: " + str((int)err), LogLevel::LL_ERROR); + goto end_send; + } + TimeCount("Send image data"); + } + + // PING + TimeCountReset(); + time64 = os->get_ticks_usec(); + if ((time64 - prev_ping_sending_time) > 100_ms && !ping_sended) { + nothing_happens = false; + ping_sended = true; + + Ref pack(memnew(GRPacketPing)); + err = ppeer->put_var(pack->get_data()); + + prev_ping_sending_time = time64; + if ((int)err) { + _log("Send ping failed with code: " + str((int)err), LogLevel::LL_ERROR); + goto end_send; + } + TimeCount("Ping"); + } + + // CUSTOM INPUT SCENE + TimeCountReset(); + if (!dev->custom_input_scene_was_updated) { + dev->custom_input_scene_was_updated = true; + + Ref pack; + if (!dev->custom_input_scene.empty()) { + pack = dev->_create_custom_input_pack(dev->custom_input_scene, dev->custom_input_pck_compressed, dev->custom_input_pck_compression_type); + } else { + pack.instance(); + } + + err = ppeer->put_var(pack->get_data()); + + if ((int)err) { + _log("Send custom input failed with code: " + str((int)err), LogLevel::LL_ERROR); + goto end_send; + } + TimeCount("Custom input"); + } + + // SEND QUEUE + TimeCountReset(); + while (!dev->send_queue.empty() && (os->get_ticks_usec() - start_while_time) <= send_data_time_us / 2) { + is_queued_send = true; + Ref packet = dev->_send_queue_pop_front(); + + if (packet.is_valid()) { + err = ppeer->put_var(packet->get_data()); + + if ((int)err) { + _log("Put data from queue failed with code: " + str((int)err), LogLevel::LL_ERROR); + goto end_send; + } + } + } + if (is_queued_send) { + TimeCount("Send queued data"); + } + + end_send: + + if (!connection->is_connected_to_host()) { + _log("Lost connection after sending!", LogLevel::LL_ERROR); + GRNotifications::add_notification("Error", "Lost connection after sending data!", GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + continue; + } + + /////////////////////////////////////////////////////////////////// + // RECEIVING + TimeCountReset(); + uint64_t recv_start_time = os->get_ticks_usec(); + while (connection->is_connected_to_host() && ppeer->get_available_packet_count() > 0 && + (os->get_ticks_usec() - recv_start_time) < send_data_time_us / 2) { + nothing_happens = false; + Variant res; +#ifndef GDNATIVE_LIBRARY + err = (Error)(int)ppeer->get_var(res); +#else + err = Error::OK; + res = ppeer->get_var(); +#endif + + if ((int)err) { + _log("Can't receive packet!", LogLevel::LL_ERROR); + continue; + } + + //_log(str_arr((PoolByteArray)res, true)); + Ref pack = GRPacket::create(res); + if (pack.is_null()) { + _log("Received packet was NULL", LogLevel::LL_ERROR); + continue; + } + + GRPacket::PacketType type = pack->get_type(); + //_log((int)type); + + switch (type) { + case GRPacket::PacketType::SyncTime: { + ERR_PRINT("NOT IMPLEMENTED"); + break; + } + case GRPacket::PacketType::ImageData: { + ERR_PRINT("NOT IMPLEMENTED"); + break; + } + case GRPacket::PacketType::InputData: { + Ref data = pack; + if (data.is_null()) { + _log("Incorrect GRPacketInputData", LogLevel::LL_ERROR); + break; + } + + for (int i = 0; i < data->get_inputs_count(); i++) { + Ref id = data->get_input_data(i); + GRInputData::InputType ev_type = id->get_type(); + + if (ev_type >= GRInputData::InputType::_InputEvent) { + Ref ied = id; + if (ied.is_null()) { + _log("GRInputDataEvent is null", LogLevel::LL_ERROR); + continue; + } + + Ref ev = ied->construct_event(); + if (ev.is_valid()) { + Input::get_singleton()->call_deferred("parse_input_event", ev); + } + } else { + switch (ev_type) { + case GRInputData::InputType::_NoneIT: { + _log("Not valid input type! 0", LogLevel::LL_NORMAL); + break; + } + case GRInputData::InputType::_InputDeviceSensors: { + Ref sd = id; + if (sd.is_null()) { + _log("GRInputDeviceSensorsData is null", LogLevel::LL_ERROR); + continue; + } + + auto s = sd->get_sensors(); + set_accelerometer(s[0]); + set_gravity(s[1]); + set_gyroscope(s[2]); + set_magnetometer(s[3]); + + break; + } + default: { + _log("Not supported input type! " + str((int)ev_type), LogLevel::LL_ERROR); + continue; + break; + } + } + } + } + break; + } + case GRPacket::PacketType::ServerSettings: { + Ref data = pack; + if (data.is_null()) { + _log("Incorrect GRPacketServerSettings", LogLevel::LL_ERROR); + break; + } + dev->_update_settings_from_client(data->get_settings()); + break; + } + case GRPacket::PacketType::ClientStreamOrientation: { + Ref data = pack; + if (data.is_null()) { + _log("Incorrect GRPacketClientStreamOrientation", LogLevel::LL_ERROR); + break; + } + dev->call_deferred("emit_signal", "client_viewport_orientation_changed", data->is_vertical()); + break; + } + case GRPacket::PacketType::ClientStreamAspect: { + Ref data = pack; + if (data.is_null()) { + _log("Incorrect GRPacketClientStreamAspect", LogLevel::LL_ERROR); + break; + } + dev->call_deferred("emit_signal", "client_viewport_aspect_ratio_changed", data->get_aspect()); + break; + } + case GRPacket::PacketType::CustomUserData: { + Ref data = pack; + if (data.is_null()) { + _log("Incorrect GRPacketCustomUserData", LogLevel::LL_ERROR); + break; + } + dev->call_deferred("emit_signal", "user_data_received", data->get_packet_id(), data->get_user_data()); + break; + } + case GRPacket::PacketType::Ping: { + Ref pack(memnew(GRPacketPong)); + err = ppeer->put_var(pack->get_data()); + + if ((int)err) { + _log("Send pong failed with code: " + str((int)err), LogLevel::LL_ERROR); + goto end_recv; + } + break; + } + case GRPacket::PacketType::Pong: { + dev->_update_avg_ping(os->get_ticks_usec() - prev_ping_sending_time); + ping_sended = false; + break; + } + default: { + _log("Not supported packet type! " + str((int)type), LogLevel::LL_WARNING); + break; + } + } + } + TimeCount("End receiving"); + end_recv: + + if (!connection->is_connected_to_host()) { + _log("Lost connection after receiving!", LogLevel::LL_ERROR); + GRNotifications::add_notification("Error", "Lost connection after receiving data!", GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + continue; + } + + if (nothing_happens) // for less cpu using + sleep_usec(1_ms); + } + + _log("Closing connection thread with address: " + address, LogLevel::LL_DEBUG); + + if (dev->resize_viewport) + dev->resize_viewport->set_process(false); + + if (connection->is_connected_to_host()) { + GRNotifications::add_notification("Disconnected", "Closing connection with " + address, GRNotifications::NotificationIcon::ICON_FAIL, false, 1.f); + } else { + GRNotifications::add_notification("Disconnected", "Client disconnected: " + address, GRNotifications::NotificationIcon::ICON_FAIL, false, 1.f); + } + + if (ppeer.is_valid()) { + ppeer.unref(); + } + thread_info->ppeer.unref(); + thread_info->break_connection = true; + dev->client_connected--; + dev->_send_queue_resize(0); + + dev->call_deferred("_load_settings"); + dev->call_deferred("emit_signal", "client_disconnected", thread_info->device_id); + + thread_info->finished = true; +} + +GRServer::AuthResult GRServer::_auth_client(GRServer *dev, Ref &ppeer, Dictionary &ret_data, bool refuse_connection) { + // _v - variable definition, _n - dict key, _c - fail condition, _e - error message, _r - return value on fail condition +#define packet_error_check(_t) \ + if ((int)err) { \ + _log(_t, LogLevel::LL_DEBUG); \ + con->disconnect_from_host(); \ + return GRDevice::AuthResult::Error; \ + } +#define dict_get(_t, _v, _n, _c, _e, _r) \ + _t _v; \ + if (dict.has(_n)) \ + _v = V_CAST(dict[_n], _t); \ + else \ + goto error_dict; \ + if (_c) { \ + ppeer->put_var((int)_r); \ + _log(_e, LogLevel::LL_DEBUG); \ + con->disconnect_from_host(); \ + return _r; \ + } +#define wait_packet(_n) \ + time = (uint32_t)OS::get_singleton()->get_ticks_msec(); \ + while (ppeer->get_available_packet_count() == 0) { \ + if (OS::get_singleton()->get_ticks_msec() - time > 150) { \ + _log("Connection timeout. Refusing " + address + ". Waited: " + str(_n), LogLevel::LL_DEBUG); \ + goto timeout; \ + } \ + if (!con->is_connected_to_host()) { \ + return GRDevice::AuthResult::Error; \ + } \ + sleep_usec(1_ms); \ + } + + Ref con = ppeer->get_stream_peer(); + String address = CONNECTION_ADDRESS(con); + uint32_t time = 0; + + Error err = Error::OK; + Variant res; + if (!refuse_connection) { + // PUT client can try to connect + err = ppeer->put_var((int)GRDevice::AuthResult::TryToConnect); + packet_error_check("Can't send authorization init packet to " + address + ". Code: " + str((int)err)); + + // GET auth data + wait_packet("auth_data"); + +#ifndef GDNATIVE_LIBRARY + err = (Error)(int)ppeer->get_var(res); + packet_error_check("Can't get authorization data from client to " + address + ". Code: " + str((int)err)); +#else + err = Error::OK; + res = ppeer->get_var(); +#endif + + Dictionary dict = res; + if (dict.empty()) { + goto error_dict; + } else { + dict_get(String, id, "id", + id.empty(), "Device ID field is empty or does not exists. " + address, + GRDevice::AuthResult::VersionMismatch); + + ret_data["id"] = id; + + dict_get(PoolByteArray, ver, "version", + ver.size() == 0, "Version field is empty or does not exists. " + address, + GRDevice::AuthResult::VersionMismatch); + + if (!validate_version(ver)) { + _log("Version mismatch", LogLevel::LL_ERROR); + return GRDevice::AuthResult::VersionMismatch; + } + + if (!dev->password.empty()) { + dict_get(String, password, "password", + password != dev->password, "Incorrect password. " + address, + GRDevice::AuthResult::IncorrectPassword); + } + } + + // PUT auth ok + err = ppeer->put_var((int)GRDevice::AuthResult::OK); + packet_error_check("Can't send final authorization packet from client to " + address + ". Code: " + str((int)err)); + + return GRDevice::AuthResult::OK; + + error_dict: + _log("Got invalid authorization data from client. " + address, LogLevel::LL_NORMAL); + err = ppeer->put_var((int)GRDevice::AuthResult::Error); + packet_error_check("Can't send error code to client " + address + ". Code: " + str((int)err)); + con->disconnect_from_host(); + return GRDevice::AuthResult::Error; + + } else { + // PUT refuse connection + Error err = ppeer->put_var((int)GRDevice::AuthResult::RefuseConnection); + con->disconnect_from_host(); + return GRDevice::AuthResult::RefuseConnection; + } +timeout: + con->disconnect_from_host(); + return GRDevice::AuthResult::Timeout; + +#undef dict_get +#undef wait_packet +#undef packet_error_check +} + +Ref GRServer::_create_custom_input_pack(String _scene_path, bool compress, ENUM_ARG(Compression::Mode) compression_type) { + Ref pack = memnew(GRPacketCustomInputScene); + std::vector files; + _scan_resource_for_dependencies_recursive(_scene_path, files); +#ifndef GDNATIVE_LIBRARY +#else + compress = false; +#endif + + if (files.size()) { + String pck_file = _scene_path.get_base_dir() + "tmp.pck"; + Ref pck = memnew(PCKPacker); + Error err = pck->pck_start(pck_file); + + if ((int)err) { + _log("Can't create PCK file. Code: " + str((int)err), LogLevel::LL_ERROR); + } else { + + Error add_err = Error::OK; + for (int i = 0; i < files.size(); i++) { + add_err = pck->add_file(files[i], files[i]); + if ((int)add_err) { + _log("Can't add file to PCK. Code: " + str((int)add_err), LogLevel::LL_ERROR); + break; + } + } + + if (!(int)add_err) { + err = pck->flush(); + + if ((int)err) { + _log("Can't flush PCK file. Code: " + str((int)err), LogLevel::LL_ERROR); + } else { + + // if OK show which files added + _log(str(files.size()) + " files added to custom input PCK", LogLevel::LL_NORMAL); + _log(str_arr(files, true, 0, ",\n"), LogLevel::LL_DEBUG); + +#ifndef GDNATIVE_LIBRARY + FileAccess *file = FileAccess::open(pck_file, FileAccess::ModeFlags::READ, &err); +#else + File *file = memnew(File); + err = file->open(pck_file, File::ModeFlags::READ); +#endif + + if ((int)err) { + _log("Can't open PCK file for reading. Code: " + str((int)err), LogLevel::LL_ERROR); + } else { + PoolByteArray arr; +#ifndef GDNATIVE_LIBRARY + err = arr.resize(file->get_len()); + if ((int)err) { + _log("Can't resize temp buffer array. Code: " + str((int)err), LogLevel::LL_ERROR); + } else { +#else + { +#endif + +#ifndef GDNATIVE_LIBRARY + auto w = arr.write(); + int res = file->get_buffer(w.ptr(), arr.size()); + release_pva_write(w); + file->close(); + + if (res != arr.size()) { +#else + arr = file->get_buffer(file->get_len()); + int file_length = (int)file->get_len(); + file->close(); + + if (file_length != arr.size()) { + int res = (int)Error::ERR_FILE_CANT_READ; +#endif + + _log("PCK was not fully read. " + str(res) + " of " + str(arr.size()), LogLevel::LL_ERROR); + } else { + + if (compress) { + PoolByteArray com; + err = compress_bytes(arr, com, compression_type); + if ((int)err) { + _log("Can't compress PCK data. Code: " + str((int)err), LogLevel::LL_ERROR); + } + + pack->set_scene_path(_scene_path); + pack->set_scene_data(com); + pack->set_compressed(true); + pack->set_compression_type(compression_type); + pack->set_original_size(arr.size()); + } else { + pack->set_scene_path(_scene_path); + pack->set_scene_data(arr); + pack->set_compressed(false); + pack->set_compression_type(0); + } + +#ifndef GDNATIVE_LIBRARY + DirAccess *dir = DirAccess::open(_scene_path.get_base_dir()); + if (dir) { + dir->remove(pck_file); + memdelete(dir); + } +#else + Directory *dir = memnew(Directory); + if (dir) { + dir->open(_scene_path.get_base_dir()); + dir->remove(pck_file); + memdelete(dir); + } +#endif + } + } + } + memdelete(file); + } + } + } + } else { + _log("Files to pack not found! Scene path: " + _scene_path, LogLevel::LL_ERROR); + } + + files.clear(); + return pack; +} + +void GRServer::_scan_resource_for_dependencies_recursive(String _d, std::vector &_arr) { + if (!is_vector_contains(_arr, _d)) { + _arr.push_back(_d); + } else { + return; + } + + Error err = Error::OK; + + String text = file_get_as_string(_d, &err); + + if ((int)err) { + _log("Can't read file as text: " + _d, LogLevel::LL_ERROR); + } else { + String imp = _d + ".import"; + text += file_get_as_string(imp, &err); + if ((int)err) { + _log(".import file not found for " + imp, LogLevel::LL_DEBUG); + } else { + if (!is_vector_contains(_arr, imp)) { + _arr.push_back(imp); + } + } + // Check for .md5 files in .import folder + String imp_folder = "res://.import/"; // workaround for GDNative + if (_d.begins_with(imp_folder)) { + String md5 = _d.get_basename() + ".md5"; + text += file_get_as_string(md5, &err); + // Not error == OK + if (!(int)err) { + if (!is_vector_contains(_arr, md5)) { + _arr.push_back(md5); + } + } + } + + Array res = custom_input_scene_regex_resource_finder->search_all(text); + + for (int i = 0; i < res.size(); i++) { + Ref rem = res[i]; + String path = rem->get_string(1); + path = path.trim_suffix("\\"); // Needed for avoiding escape symbols in build-in scripts + + _scan_resource_for_dependencies_recursive(path, _arr); + } + } +} + +////////////////////////////////////////////// +////////////// GRSViewport /////////////////// +////////////////////////////////////////////// + +void GRSViewport::_processing_thread(THREAD_DATA p_user) { + GRSViewport *vp = (GRSViewport *)p_user; + + while (vp->is_thread_active) { + TimeCountInit(); + vp->_TS_LOCK_; + + if (img_is_empty(vp->last_image)) { + vp->_TS_UNLOCK_; + sleep_usec(1_ms); + continue; + } + + ImgProcessingViewportStorage *ips = memnew(ImgProcessingViewportStorage); + Ref img = vp->last_image; + vp->last_image = newref(Image); + + vp->_TS_UNLOCK_; + + if (!ips) { + goto end; + } + + ips->width = (int)img->get_width(); + ips->height = (int)img->get_height(); + ips->compression_type = vp->compression_type; + ips->jpg_quality = vp->jpg_quality; + + ips->format = img->get_format(); + if (!(ips->format == Image::FORMAT_RGBA8 || ips->format == Image::FORMAT_RGB8)) { + img->convert(Image::FORMAT_RGB8); + ips->format = img->get_format(); + + if (ips->format != Image::FORMAT_RGB8) { + _log("Can't convert stream image to RGB8.", LogLevel::LL_ERROR); + GRNotifications::add_notification("Stream Error", "Can't convert stream image to RGB8.", GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + goto end; + } + + TimeCount("Image Convert"); + } + ips->bytes_in_color = img->get_format() == Image::FORMAT_RGB8 ? 3 : 4; + + if (img->get_data().size() == 0) + goto end; + + switch (ips->compression_type) { + case GRDevice::ImageCompressionType::COMPRESSION_UNCOMPRESSED: { + ips->ret_data = img->get_data(); + TimeCount("Image processed: Uncompressed"); + break; + } + case GRDevice::ImageCompressionType::COMPRESSION_JPG: { + if (!img_is_empty(img)) { + Error err = compress_jpg(ips->ret_data, img->get_data(), ips->width, ips->height, ips->bytes_in_color, ips->jpg_quality, GRServer::Subsampling::SUBSAMPLING_H2V2); + if ((int)err) { + _log("Can't compress stream image JPG. Code: " + str((int)err), LogLevel::LL_ERROR); + GRNotifications::add_notification("Stream Error", "Can't compress stream image to JPG. Code: " + str((int)err), GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + } + } + TimeCount("Image processed: JPG"); + break; + } + case GRDevice::ImageCompressionType::COMPRESSION_PNG: { + ips->ret_data = img->save_png_to_buffer(); + if (ips->ret_data.size() == 0) { + _log("Can't compress stream image to PNG.", LogLevel::LL_ERROR); + GRNotifications::add_notification("Stream Error", "Can't compress stream image to PNG.", GRNotifications::NotificationIcon::ICON_ERROR, true, 1.f); + } + TimeCount("Image processed: PNG"); + break; + } + default: + _log("Not implemented compression type: " + str((int)ips->compression_type), LogLevel::LL_ERROR); + break; + } + end: + if (vp->video_stream_enabled) + vp->_set_img_data(ips); + } +} + +#ifndef GDNATIVE_LIBRARY + +void GRSViewport::_bind_methods() { + ClassDB::bind_method(D_METHOD("_update_size"), &GRSViewport::_update_size); + ClassDB::bind_method(D_METHOD("_on_renderer_deleting"), &GRSViewport::_on_renderer_deleting); + ClassDB::bind_method(D_METHOD("set_rendering_scale"), &GRSViewport::set_rendering_scale); + ClassDB::bind_method(D_METHOD("get_rendering_scale"), &GRSViewport::get_rendering_scale); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "rendering_scale", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_rendering_scale", "get_rendering_scale"); +} + +#else + +void GRSViewport::_register_methods() { + METHOD_REG(GRSViewport, _notification); + METHOD_REG(GRSViewport, _processing_thread); + METHOD_REG(GRSViewport, _on_renderer_deleting); + + METHOD_REG(GRSViewport, _update_size); + METHOD_REG(GRSViewport, set_rendering_scale); + METHOD_REG(GRSViewport, get_rendering_scale); + + register_property("rendering_scale", &GRSViewport::set_rendering_scale, &GRSViewport::get_rendering_scale, 0.3f, GODOT_METHOD_RPC_MODE_DISABLED, GODOT_PROPERTY_USAGE_DEFAULT, GODOT_PROPERTY_HINT_RANGE, "0,1,0.001"); +} + +#endif + +void GRSViewport::_set_img_data(ImgProcessingViewportStorage *_data) { + _TS_LOCK_; + if (last_image_data) + memdelete(last_image_data); + + last_image_data = _data; + _TS_UNLOCK_; +} + +void GRSViewport::_on_renderer_deleting() { + renderer = nullptr; +} + +void GRSViewport::_notification(int p_notification) { + TimeCountInit(); + switch (p_notification) { + case NOTIFICATION_POSTINITIALIZE: +#ifndef GDNATIVE_LIBRARY + _init(); +#endif + break; + case NOTIFICATION_PREDELETE: + _deinit(); + break; + case NOTIFICATION_PROCESS: { + frames_from_prev_image++; + + if (video_stream_enabled) { + is_empty_image_sended = false; + + if (frames_from_prev_image > skip_frames && img_is_empty(last_image)) { + frames_from_prev_image = 0; + + if (get_texture().is_null()) + break; + + auto tmp_image = get_texture()->get_data(); + _TS_LOCK_; + + last_image = tmp_image; + TimeCount("Get image data from VisualServer"); + + if (img_is_empty(last_image)) + _log("Can't copy viewport image data", LogLevel::LL_ERROR); + + _TS_UNLOCK_; + } + } else { + if (!is_empty_image_sended) { + is_empty_image_sended = true; + ImgProcessingViewportStorage *ipsv = memnew(ImgProcessingViewportStorage); + ipsv->width = 0; + ipsv->height = 0; + ipsv->format = Image::Format::FORMAT_RGB8; + ipsv->bytes_in_color = 3; + ipsv->jpg_quality = 1; + ipsv->is_empty = true; + _set_img_data(ipsv); + } + } + break; + } + case NOTIFICATION_ENTER_TREE: { + main_vp = ST()->get_root(); + main_vp->connect("size_changed", this, "_update_size"); + _update_size(); + + renderer = memnew(GRSViewportRenderer); + renderer->tex = main_vp->get_texture(); + renderer->connect("tree_exiting", this, "_on_renderer_deleting"); + add_child(renderer); + + break; + } + case NOTIFICATION_EXIT_TREE: { + if (renderer) { + remove_child(renderer); + //renderer->queue_del(); + memdelete(renderer); + } + main_vp->disconnect("size_changed", this, "_update_size"); + main_vp = nullptr; + break; + } + default: + break; + } +} + +void GRSViewport::_update_size() { + float scale = rendering_scale; + if (auto_scale > 0) + scale = auto_scale; + + if (main_vp && main_vp->get_texture().is_valid()) { + Vector2 size = main_vp->get_size() * scale; + if (get_size() == size) + return; + + if (size.x < 8) + size.x = 8; + else if (size.x > Image::MAX_WIDTH) + size.x = Image::MAX_WIDTH; + + if (size.y < 8) + size.y = 8; + else if (size.y > Image::MAX_HEIGHT) + size.y = Image::MAX_HEIGHT; + + set_size(size); + } +} + +GRSViewport::ImgProcessingViewportStorage *GRSViewport::get_last_compressed_image_data() { + _TS_LOCK_; + auto res = last_image_data; + last_image_data = nullptr; + _TS_UNLOCK_; + + return res; +} + +bool GRSViewport::has_compressed_image_data() { + return last_image_data; +} + +void GRSViewport::force_get_image() { + frames_from_prev_image = skip_frames; +} + +void GRSViewport::set_video_stream_enabled(bool val) { + video_stream_enabled = val; +} + +bool GRSViewport::is_video_stream_enabled() { + return video_stream_enabled; +} + +void GRSViewport::set_rendering_scale(float val) { + rendering_scale = val; + call_deferred("_update_size"); +} + +float GRSViewport::get_rendering_scale() { + return rendering_scale; +} + +void GRSViewport::set_compression_type(GRDevice::ImageCompressionType val) { + compression_type = val; +} + +GRDevice::ImageCompressionType GRSViewport::get_compression_type() { + return compression_type; +} + +void GRSViewport::set_jpg_quality(int _quality) { + ERR_FAIL_COND(_quality < 0 || _quality > 100); + jpg_quality = _quality; +} + +int GRSViewport::get_jpg_quality() { + return jpg_quality; +} + +void GRSViewport::set_skip_frames(int skip) { + skip_frames = skip; +} + +int GRSViewport::get_skip_frames() { + return skip_frames; +} + +void GRSViewport::_init() { + set_name("GRSViewport"); + LEAVE_IF_EDITOR(); + + set_process(false); + + rendering_scale = GET_PS(GodotRemote::ps_server_scale_of_sending_stream_name); + + set_hdr(false); + set_disable_3d(true); + set_keep_3d_linear(true); + set_usage(Viewport::USAGE_2D); + set_update_mode(Viewport::UPDATE_ALWAYS); + set_disable_input(true); + set_shadow_atlas_quadrant_subdiv(0, Viewport::SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED); + set_shadow_atlas_quadrant_subdiv(1, Viewport::SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED); + set_shadow_atlas_quadrant_subdiv(2, Viewport::SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED); + set_shadow_atlas_quadrant_subdiv(3, Viewport::SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED); + + _TS_LOCK_; + last_image = newref(Image); + _TS_UNLOCK_; + is_thread_active = true; + Thread_start(_thread_process, GRSViewport, _processing_thread, this, this); +} + +void GRSViewport::_deinit() { + LEAVE_IF_EDITOR(); + + is_thread_active = false; + _close_thread(); + + _TS_LOCK_; + if (last_image_data) + memdelete(last_image_data); + last_image_data = nullptr; + last_image.unref(); + _TS_UNLOCK_; +} + +////////////////////////////////////////////// +/////////// GRSViewportRenderer ///////////// +////////////////////////////////////////////// + +#ifndef GDNATIVE_LIBRARY +void GRSViewportRenderer::_bind_methods() { +} + +#else + +void GRSViewportRenderer::_register_methods() { + METHOD_REG(GRSViewportRenderer, _notification); +} + +#endif + +void GRSViewportRenderer::_notification(int p_notification) { + switch (p_notification) { + case NOTIFICATION_POSTINITIALIZE: +#ifndef GDNATIVE_LIBRARY + _init(); +#endif + break; + case NOTIFICATION_PREDELETE: + _deinit(); + break; + case NOTIFICATION_ENTER_TREE: { + vp = get_viewport(); + break; + } + case NOTIFICATION_EXIT_TREE: { + vp = nullptr; + tex.unref(); + break; + } + case NOTIFICATION_PROCESS: { + update(); + break; + } + case NOTIFICATION_DRAW: { + draw_texture_rect(tex, Rect2(Vector2(), vp->get_size()), false); + break; + } + default: + break; + } +} + +void GRSViewportRenderer::_init() { + set_name("GRSViewportRenderer"); + LEAVE_IF_EDITOR(); + set_process(true); + + set_mouse_filter(Control::MOUSE_FILTER_IGNORE); +} + +void GRSViewportRenderer::_deinit() { + LEAVE_IF_EDITOR(); +} +#endif // !NO_GODOTREMOTE_SERVER diff --git a/modules/godot_remote/godot_remote/GRServer.h b/modules/godot_remote/godot_remote/GRServer.h new file mode 100644 index 0000000..5ffc68a --- /dev/null +++ b/modules/godot_remote/godot_remote/GRServer.h @@ -0,0 +1,289 @@ +/* GRServer.h */ +#pragma once + +#ifndef NO_GODOTREMOTE_SERVER + +#include "GRDevice.h" + +#ifndef GDNATIVE_LIBRARY + +#include "core/io/compression.h" +#include "core/io/stream_peer_tcp.h" +#include "core/io/tcp_server.h" +#include "modules/regex/regex.h" +#include "scene/gui/control.h" +#include "scene/main/viewport.h" +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace godot; +#endif + +class GRServer : public GRDevice { + GD_S_CLASS(GRServer, GRDevice); + +private: +#ifndef GDNATIVE_LIBRARY +#else +public: +#endif + class ListenerThreadParamsServer : public Object { + GD_CLASS(ListenerThreadParamsServer, Object); + + public: + GRServer *dev = nullptr; + Thread_define(thread_ref); + + bool stop_thread = false; + bool finished = false; + + static void _register_methods(){}; + void _init(){}; + + void close_thread() { + stop_thread = true; + Thread_close(thread_ref); + } + + ~ListenerThreadParamsServer() { + LEAVE_IF_EDITOR(); + close_thread(); + } + }; + + class ConnectionThreadParamsServer : public Object { + GD_CLASS(ConnectionThreadParamsServer, Object); + + public: + String device_id = ""; + GRServer *dev = nullptr; + Ref ppeer; + + Thread_define(thread_ref); + + bool break_connection = false; + bool finished = false; + + static void _register_methods(){}; + void _init(){}; + + void close_thread() { + break_connection = true; + Thread_close(thread_ref); + } + + ~ConnectionThreadParamsServer() { + LEAVE_IF_EDITOR(); + close_thread(); + if (ppeer.is_valid()) { + ppeer.unref(); + } + } + }; + +private: + Mutex_define(connection_mutex); + ListenerThreadParamsServer *server_thread_listen = nullptr; + Ref tcp_server; + class GRSViewport *resize_viewport = nullptr; + int client_connected = 0; + + bool using_client_settings = false; + bool using_client_settings_recently_updated = false; + + String password; + String custom_input_scene; + bool custom_input_scene_was_updated = false; + bool auto_adjust_scale = false; + + bool custom_input_pck_compressed = true; + ENUM_ARG(Compression::Mode) + custom_input_pck_compression_type = ENUM_CONV(Compression::Mode) 0; + const String custom_input_scene_regex_resource_finder_pattern = "\\\"(res://.*?)\\\""; + Ref custom_input_scene_regex_resource_finder; + + float prev_avg_fps = 0; + void _adjust_viewport_scale(); + + void _load_settings(); + void _update_settings_from_client(const std::map settings); + void _remove_resize_viewport(Node *vp); + void _on_grviewport_deleting(); + + virtual void _reset_counters() override; + + THREAD_FUNC void _thread_listen(THREAD_DATA p_userdata); + THREAD_FUNC void _thread_connection(THREAD_DATA p_userdata); + + static AuthResult _auth_client(GRServer *dev, Ref &ppeer, Dictionary &ret_data, bool refuse_connection DEF_ARG(= false)); + + Ref _create_custom_input_pack(String _scene_path, bool compress DEF_ARG(= true), ENUM_ARG(Compression::Mode) compression_type DEF_ARG(= ENUM_CONV(Compression::Mode) 0)); + void _scan_resource_for_dependencies_recursive(String _dir, std::vector &_arr); + +protected: + virtual void _internal_call_only_deffered_start() override; + virtual void _internal_call_only_deffered_stop() override; + +#ifndef GDNATIVE_LIBRARY + static void _bind_methods(); +#else +public: + static void _register_methods(); + +protected: +#endif + + void _notification(int p_notification); + +public: + void set_auto_adjust_scale(bool _val); + bool is_auto_adjust_scale(); + void set_password(String _pass); + String get_password(); + void set_custom_input_scene(String _scn); + String get_custom_input_scene(); + void set_custom_input_scene_compressed(bool _is_compressed); + bool is_custom_input_scene_compressed(); + void set_custom_input_scene_compression_type(int _type); + int get_custom_input_scene_compression_type(); + + // VIEWPORT + bool set_video_stream_enabled(bool val); + bool is_video_stream_enabled(); + bool set_compression_type(ImageCompressionType _type); + ImageCompressionType get_compression_type(); + bool set_jpg_quality(int _quality); + int get_jpg_quality(); + bool set_skip_frames(int fps); + int get_skip_frames(); + bool set_render_scale(float _scale); + float get_render_scale(); + // NOT VIEWPORT + + GRSViewport *get_gr_viewport(); + void force_update_custom_input_scene(); + + void _init(); + void _deinit(); +}; + +class GRSViewport : public Viewport { + GD_CLASS(GRSViewport, Viewport); + friend GRServer; + friend class ImgProcessingViewportStorage; + _TS_CLASS_; + +public: + class ImgProcessingViewportStorage : public Object { + GD_CLASS(ImgProcessingViewportStorage, Object); + + public: + PoolByteArray ret_data; + GRDevice::ImageCompressionType compression_type = GRDevice::ImageCompressionType::COMPRESSION_UNCOMPRESSED; + int width, height, format; + int bytes_in_color, jpg_quality; + bool is_empty = false; + + static void _register_methods(){}; + void _init() { + LEAVE_IF_EDITOR(); + ret_data = PoolByteArray(); + }; + + ~ImgProcessingViewportStorage() { + LEAVE_IF_EDITOR(); + ret_data.resize(0); + } + }; + +private: + Thread_define(_thread_process); + + Ref last_image; + ImgProcessingViewportStorage *last_image_data = nullptr; + + void _close_thread() { Thread_close(_thread_process); } + void _set_img_data(ImgProcessingViewportStorage *_data); + void _on_renderer_deleting(); + + THREAD_FUNC void _processing_thread(THREAD_DATA p_user); + +protected: + Viewport *main_vp = nullptr; + class GRSViewportRenderer *renderer = nullptr; + bool video_stream_enabled = true; + float rendering_scale = 0.3f; + float auto_scale = 0.5f; + int jpg_quality = 80; + int skip_frames = 0; + GRDevice::ImageCompressionType compression_type = GRDevice::ImageCompressionType::COMPRESSION_UNCOMPRESSED; + + uint16_t frames_from_prev_image = 0; + bool is_empty_image_sended = false; + bool is_thread_active = false; + +#ifndef GDNATIVE_LIBRARY + static void _bind_methods(); +#else +public: + static void _register_methods(); + +protected: +#endif + + void _notification(int p_notification); + void _update_size(); + +public: + ImgProcessingViewportStorage *get_last_compressed_image_data(); + bool has_compressed_image_data(); + void force_get_image(); + + void set_video_stream_enabled(bool val); + bool is_video_stream_enabled(); + void set_rendering_scale(float val); + float get_rendering_scale(); + void set_compression_type(GRDevice::ImageCompressionType val); + GRDevice::ImageCompressionType get_compression_type(); + void set_jpg_quality(int _quality); + int get_jpg_quality(); + void set_skip_frames(int skip); + int get_skip_frames(); + + void _init(); + void _deinit(); +}; + +class GRSViewportRenderer : public Control { + GD_CLASS(GRSViewportRenderer, Control); + +protected: + Viewport *vp = nullptr; + +#ifndef GDNATIVE_LIBRARY + static void _bind_methods(); +#else +public: + static void _register_methods(); + +protected: +#endif + + void _notification(int p_notification); + +public: + Ref tex; + + void _init(); + void _deinit(); +}; + +#endif // !NO_GODOTREMOTE_SERVER diff --git a/modules/godot_remote/godot_remote/GRUtils.cpp b/modules/godot_remote/godot_remote/GRUtils.cpp new file mode 100644 index 0000000..38d15ef --- /dev/null +++ b/modules/godot_remote/godot_remote/GRUtils.cpp @@ -0,0 +1,556 @@ +/* GRUtils.cpp */ + +#include "GRUtils.h" +#include "GodotRemote.h" + +#ifndef GDNATIVE_LIBRARY +#include "core/io/compression.h" + +#else +#include + +using namespace godot; +#endif + +#ifndef NO_GODOTREMOTE_SERVER +// richgel999/jpeg-compressor: https://github.com/richgel999/jpeg-compressor +#include "jpge.h" +#endif + +GRUtilsData *GRUtils::_grutils_data = nullptr; + +namespace GRUtils { +void init() { + LEAVE_IF_EDITOR(); + _grutils_data = memnew(GRUtilsData); + _grutils_data->current_loglevel = GodotRemote::LogLevel::LL_NORMAL; + + GR_PACKET_HEADER('G', 'R', 'H', 'D'); +#include "GRVersion.h" + + GET_PS_SET(_grutils_data->current_loglevel, GodotRemote::ps_general_loglevel_name); +} + +void deinit() { + LEAVE_IF_EDITOR(); + if (_grutils_data) { + _grutils_data->internal_PACKET_HEADER.resize(0); + _grutils_data->internal_VERSION.resize(0); + memdelete(_grutils_data); + _grutils_data = nullptr; + } +} + +#ifndef NO_GODOTREMOTE_SERVER +GRUtilsDataServer *_grutils_data_server = nullptr; + +void init_server_utils() { + LEAVE_IF_EDITOR(); + _grutils_data_server = new GRUtilsDataServer(); + + GET_PS_SET(_grutils_data_server->compress_buffer_size_mb, GodotRemote::ps_server_jpg_buffer_mb_size_name); + _grutils_data_server->compress_buffer.resize((1024 * 1024) * _grutils_data_server->compress_buffer_size_mb); +} + +void deinit_server_utils() { + LEAVE_IF_EDITOR(); + _grutils_data_server->compress_buffer.resize(0); + delete _grutils_data_server; +} +#endif + +void __log(const Variant &val, int lvl, String file, int line) { +#ifdef DEBUG_ENABLED +#ifndef GDNATIVE_LIBRARY + if (lvl >= _grutils_data->current_loglevel && lvl < LogLevel::LL_NONE) { + String file_line = ""; + if (file != "") { + int idx = file.find("godot_remote"); + if (idx != -1) { + file = file.substr(file.find("godot_remote"), file.length()); + } + + file_line = "\n At: " + file + ":" + str(line); + } + + if (lvl == LogLevel::LL_ERROR) { + print_error("[GodotRemote Error] " + str(val) + file_line); + } else if (lvl == LogLevel::LL_WARNING) { + print_error("[GodotRemote Warning] " + str(val) + file_line); + } else { + print_line("[GodotRemote] " + str(val)); + } + } + +#else + +#define print_error_ext() Godot::print_error(str(val), "[GodotRemote Error]", file, line) +#define print_warning_ext() Godot::print_warning(str(val), "[GodotRemote Warning]", file, line) + + if (lvl >= _grutils_data->current_loglevel && lvl < LogLevel::LL_NONE) { + if (file != "") { + int idx = file.find("godot_remote"); + if (idx != -1) + file = file.substr(file.find("godot_remote"), file.length()); + } + + if (lvl == LogLevel::LL_ERROR) { + print_error_ext(); + } else if (lvl == LogLevel::LL_WARNING) { + print_warning_ext(); + } else { + Godot::print("[GodotRemote] " + str(val)); + } + } +#undef print_error_ext +#undef print_warning_ext +#endif +#endif +} + +String str_arr(const Array arr, const bool force_full, const int max_shown_items, String separator) { + String res = "[ "; + int s = arr.size(); + bool is_long = false; + if (s > max_shown_items && !force_full) { + s = max_shown_items; + is_long = true; + } + + for (int i = 0; i < s; i++) { + res += str(arr[i]); + if (i != s - 1 || is_long) { + res += separator; + } + } + + if (is_long) { + res += String::num_int64(int64_t(arr.size()) - s) + " more items..."; + } + + return res + " ]"; +}; + +String str_arr(const Dictionary arr, const bool force_full, const int max_shown_items, String separator) { + String res = "{ "; + int s = arr.size(); + bool is_long = false; + if (s > max_shown_items && !force_full) { + s = max_shown_items; + is_long = true; + } + + Array keys = arr.keys(); + Array values = arr.values(); + + for (int i = 0; i < s; i++) { + res += str(keys[i]) + " : " + str(values[i]); + if (i != s - 1 || is_long) { + res += separator; + } + } + + keys.clear(); + values.clear(); + + if (is_long) { + res += String::num_int64(int64_t(arr.size()) - s) + " more items..."; + } + + return res + " }"; +}; + +String str_arr(const uint8_t *data, const int size, const bool force_full, const int max_shown_items, String separator) { + String res = "[ "; + int s = size; + bool is_long = false; + if (s > max_shown_items && !force_full) { + s = max_shown_items; + is_long = true; + } + + for (int i = 0; i < s; i++) { + res += str(data[i]); + if (i != s - 1 || is_long) { + res += separator; + } + } + + if (is_long) { + res += String::num_int64(int64_t(size) - s) + " more bytes..."; + } + + return res + " ]"; +}; + +#ifndef NO_GODOTREMOTE_SERVER +Error compress_jpg(PoolByteArray &ret, const PoolByteArray &img_data, int width, int height, int bytes_for_color, int quality, int subsampling) { + PoolByteArray res; + ERR_FAIL_COND_V(img_data.size() == 0, Error::ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(quality < 1 || quality > 100, Error::ERR_INVALID_PARAMETER); + + jpge::params params; + params.m_quality = quality; + params.m_subsampling = (jpge::subsampling_t)subsampling; + + ERR_FAIL_COND_V(!params.check(), Error::ERR_INVALID_PARAMETER); + auto rb = _grutils_data_server->compress_buffer.read(); + auto ri = img_data.read(); + int size = _grutils_data_server->compress_buffer.size(); + + TimeCountInit(); + + ERR_FAIL_COND_V_MSG(!jpge::compress_image_to_jpeg_file_in_memory( + (void *)rb.ptr(), + size, + width, + height, + bytes_for_color, + (const unsigned char *)ri.ptr(), + params), + Error::FAILED, "Can't compress image."); + + TimeCount("Compress jpg"); + + release_pva_read(ri); + res.resize(size); + auto wr = res.write(); + memcpy(wr.ptr(), rb.ptr(), size); + release_pva_read(rb); + release_pva_write(wr); + + TimeCount("Combine arrays"); + + _log("JPG size: " + str(res.size()), GodotRemote::LogLevel::LL_DEBUG); + + ret = res; + return Error::OK; +} +#endif + +Error compress_bytes(const PoolByteArray &bytes, PoolByteArray &res, int type) { +#ifndef GDNATIVE_LIBRARY + Error err = res.resize(bytes.size()); + + ERR_FAIL_COND_V_MSG(err, err, "Can't resize output array"); + + int size = 0; + { + auto r = bytes.read(); + auto w = res.write(); + size = Compression::compress(w.ptr(), r.ptr(), bytes.size(), (Compression::Mode)type); + } + + if (size) { + res.resize(size); + } else { + ERR_PRINT("Can't resize output array after compression"); + err = Error::FAILED; + res = PoolByteArray(); + } + + return err; +#else + // TODO I don't found any ways to implement compression in GDNative + _log("Compression not supported in GDNative library", GodotRemote::LogLevel::LL_ERROR); + res = bytes; + return Error::OK; +#endif +} + +Error decompress_bytes(const PoolByteArray &bytes, int output_size, PoolByteArray &res, int type) { +#ifndef GDNATIVE_LIBRARY + Error err = res.resize(output_size); + ERR_FAIL_COND_V_MSG(err, err, "Can't resize output array"); + + int size = 0; + { + auto r = bytes.read(); + auto w = res.write(); + size = Compression::decompress(w.ptr(), output_size, r.ptr(), bytes.size(), (Compression::Mode)type); + } + if (output_size == -1) { + ERR_PRINT("Can't decompress bytes"); + err = Error::FAILED; + res = PoolByteArray(); + } else if (output_size != size) { + ERR_PRINT("Desired size not equal to real size"); + err = Error::FAILED; + res = PoolByteArray(); + } + return err; +#else + // TODO I don't found any ways to implement compression in GDNative + _log("Compression not supported in GDNative library", GodotRemote::LogLevel::LL_ERROR); + res = bytes; + return Error::OK; +#endif +} + +String str(const Variant &val) { + Variant::Type type = val.get_type(); + switch (type) { + case Variant::NIL: { + return "NULL"; + } + case Variant::BOOL: { + return val ? "True" : "False"; + } + case Variant::INT: { + return String::num_int64(val); + } + case Variant::REAL: { + return String::num_real(val); + } + case Variant::STRING: { + return val; + } + case Variant::VECTOR2: { + Vector2 v2 = val; + return String("V2(") + v2 + ")"; + } + case Variant::RECT2: { + Rect2 r = val; + return String("R2((") + String::num_real(r.position.x) + ", " + String::num_real(r.position.y) + "), (" + String::num_real(r.size.x) + ", " + String::num_real(r.size.y) + "))"; + } + case Variant::VECTOR3: { + Vector3 v3 = val; + return String("V3(") + v3 + ")"; + } + case Variant::TRANSFORM: { + Transform t3d = val; + return String("T3D(") + t3d + ")"; + } + case Variant::TRANSFORM2D: { + Transform2D t2d = val; + return String("T2D(") + t2d + ")"; + } + case Variant::PLANE: { + Plane pln = val; + return String("P(") + pln + ")"; + } + case Variant::QUAT: { + Quat q = val; + return String("Q(") + q + ")"; + } +#ifndef GDNATIVE_LIBRARY + case Variant::AABB: { +#else + case Variant::RECT3: { +#endif + AABB ab = val; + return String("AABB(") + ab + ")"; + } + case Variant::BASIS: { + Basis bs = val; + return String("B(") + bs + ")"; + } + case Variant::COLOR: { + Color c = val; + return String("C(") + c + ")"; + } + case Variant::NODE_PATH: { + NodePath np = val; + return String("NP: ") + np + ")"; + } + case Variant::_RID: { + RID rid = val; +#ifndef GDNATIVE_LIBRARY + return String("RID:") + String::num_int64(rid.get_id()); +#else + return String("RID:") + String::num_int64(rid.get_id()); +#endif + } + case Variant::OBJECT: { + Object *obj = val; + if (obj) + return obj->to_string(); + else { + return String("[NULL]"); + } + } + case Variant::DICTIONARY: { + return str_arr(V_CAST(val, Dictionary)); + } + case Variant::ARRAY: { + return str_arr(V_CAST(val, Array)); + } + case Variant::POOL_BYTE_ARRAY: { + return str_arr(V_CAST(val, PoolByteArray)); + } + case Variant::POOL_INT_ARRAY: { + return str_arr(V_CAST(val, PoolIntArray)); + } + case Variant::POOL_REAL_ARRAY: { + return str_arr(V_CAST(val, PoolRealArray)); + } + case Variant::POOL_STRING_ARRAY: { + return str_arr(V_CAST(val, PoolStringArray)); + } + case Variant::POOL_VECTOR2_ARRAY: { + return str_arr(V_CAST(val, PoolVector2Array)); + } + case Variant::POOL_VECTOR3_ARRAY: { + return str_arr(V_CAST(val, PoolVector3Array)); + } + case Variant::POOL_COLOR_ARRAY: { + return str_arr(V_CAST(val, PoolColorArray)); + } + } +#ifndef GDNATIVE_LIBRARY + return String("|? ") + Variant::get_type_name(type) + " ?|"; +#else + return String("|? ") + type + " ?|"; +#endif +} + +bool validate_packet(const uint8_t *data) { + if (data[0] == _grutils_data->internal_PACKET_HEADER[0] && data[1] == _grutils_data->internal_PACKET_HEADER[1] && data[2] == _grutils_data->internal_PACKET_HEADER[2] && data[3] == _grutils_data->internal_PACKET_HEADER[3]) + return true; + return false; +} + +bool validate_version(const PoolByteArray &data) { + if (data.size() < 2) + return false; + if (((PoolByteArray)data)[0] == _grutils_data->internal_VERSION[0] && ((PoolByteArray)data)[1] == _grutils_data->internal_VERSION[1]) + return true; + return false; +} + +bool validate_version(const uint8_t *data) { + if (data[0] == _grutils_data->internal_VERSION[0] && data[1] == _grutils_data->internal_VERSION[1]) + return true; + return false; +} + +bool compare_pool_byte_arrays(const PoolByteArray &a, const PoolByteArray &b) { + if (a.size() != b.size()) + return false; + auto r_a = a.read(); + auto r_b = b.read(); + for (int i = 0; i < a.size(); i++) { + if (r_a[i] != r_b[i]) + return false; + } + + return true; +} + +void set_gravity(const Vector3 &p_gravity) { +#ifndef GDNATIVE_LIBRARY + auto *id = (InputDefault *)Input::get_singleton(); + if (id) + id->set_gravity(p_gravity); +#else + Input *id = Input::get_singleton(); + if (ClassDB::get_singleton()->class_has_method(id->get_class(), "set_gravity")) { + id->call("set_gravity", p_gravity); + } +#endif +} + +void set_accelerometer(const Vector3 &p_accel) { +#ifndef GDNATIVE_LIBRARY + auto *id = (InputDefault *)Input::get_singleton(); + if (id) + id->set_accelerometer(p_accel); +#else + Input *id = Input::get_singleton(); + if (ClassDB::get_singleton()->class_has_method(id->get_class(), "set_accelerometer")) { + id->call("set_accelerometer", p_accel); + } +#endif +} + +void set_magnetometer(const Vector3 &p_magnetometer) { +#ifndef GDNATIVE_LIBRARY + auto *id = (InputDefault *)Input::get_singleton(); + if (id) + id->set_magnetometer(p_magnetometer); +#else + Input *id = Input::get_singleton(); + if (ClassDB::get_singleton()->class_has_method(id->get_class(), "set_magnetometer")) { + id->call("set_magnetometer", p_magnetometer); + } +#endif +} + +void set_gyroscope(const Vector3 &p_gyroscope) { +#ifndef GDNATIVE_LIBRARY + auto *id = (InputDefault *)Input::get_singleton(); + if (id) + id->set_gyroscope(p_gyroscope); +#else + Input *id = Input::get_singleton(); + if (ClassDB::get_singleton()->class_has_method(id->get_class(), "set_gyroscope")) { + id->call("set_gyroscope", p_gyroscope); + } +#endif +} + +#ifndef GDNATIVE_LIBRARY +Vector vec_args(const std::vector &args) { + Vector res; + for (Variant v : args) { + res.push_back(v); + } + + return res; +} + +#else +Array vec_args(const std::vector &args) { + return vec_to_arr(args); +} + +String _gdn_get_file_as_string(String path, Error *ret_err) { + auto f = memnew(File); + Error r = f->open(path, File::ModeFlags::READ); + *ret_err = r; + if (r == Error::OK) { + String txt = f->get_as_text(); + f->close(); + memdelete(f); + return txt; + } else { + memdelete(f); + } + return ""; +} + +Variant _gdn_dictionary_get_key_at_index(Dictionary d, int idx) { + Array k = d.keys(); + Variant r = k[idx]; + k.clear(); + return r; +} + +Variant _gdn_dictionary_get_value_at_index(Dictionary d, int idx) { + Array v = d.values(); + Variant r = v[idx]; + v.clear(); + return r; +} + +Ref _gdn_thread_create(Object *instance, String func_name, const Object *user_data) { + Ref t = newref(Thread); + t->start(instance, func_name, user_data); + return t; +} + +Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed) { + Variant ret; + if (!ProjectSettings::get_singleton()->has_setting(p_var)) { + ProjectSettings::get_singleton()->set(p_var, p_default); + } + ret = ProjectSettings::get_singleton()->get(p_var); + + ProjectSettings::get_singleton()->set_initial_value(p_var, p_default); + //ProjectSettings::get_singleton()->set_builtin_order(p_var); + //ProjectSettings::get_singleton()->set_restart_if_changed(p_var, p_restart_if_changed); + return ret; +} +#endif + +} // namespace GRUtils diff --git a/modules/godot_remote/godot_remote/GRUtils.h b/modules/godot_remote/godot_remote/GRUtils.h new file mode 100644 index 0000000..63ffd34 --- /dev/null +++ b/modules/godot_remote/godot_remote/GRUtils.h @@ -0,0 +1,639 @@ +/* GRUtils.h */ +#ifndef GRUTILS_H +#define GRUTILS_H + +#include +#include +#include +#include +#include + +#ifndef GDNATIVE_LIBRARY +#include "core/image.h" +#include "core/io/marshalls.h" +#include "core/os/os.h" +#include "core/print_string.h" +#include "core/project_settings.h" +#include "core/variant.h" +#include "core/version_generated.gen.h" +#include "main/input_default.h" +//#define VERSION_MINOR 2 +//#define VERSION_PATCH 3 + +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace godot; +#endif + +// ================================================================= +// CONDITIONAL DEFINES + +#ifndef GDNATIVE_LIBRARY +#define ENUM_ARG(en) en +#define ENUM_CONV(en) (en) + +#define DEF_ARG(a) a +#define DEF_ARGS(a) + +#define ST() SceneTree::get_singleton() +#define GD_CLASS(c, p) GDCLASS(c, p) +#define GD_S_CLASS(c, p) GDCLASS(c, p) +#define V_CAST(var, type) ((type)var) + +// Bind constant with custom name +//ClassDB::bind_integer_constant(get_class_static(), __constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant); +#define BIND_ENUM_CONSTANT_CUSTOM(m_enum, m_const, m_name) ClassDB::bind_integer_constant(get_class_static(), #m_enum, m_name, ((int)(m_enum::m_const))); +#define GDNATIVE_BASIC_REGISTER +#define GDNATIVE_BASIC_REGISTER_NO_INIT + +#define queue_del queue_delete +#define img_is_empty(img) img->empty() +#define is_valid_ip is_valid +#define release_pva_read(pva) pva.release() +#define release_pva_write(pva) pva.release() + +#define dict_get_key_at_index(dict, i) dict.get_key_at_index(i) +#define dict_get_value_at_index(dict, i) dict.get_value_at_index(i) + +#define file_get_as_string(path, err) FileAccess::get_file_as_string(path, err); + +#define THREAD_FUNC static +#define THREAD_DATA void * +#define _TS_CLASS_ _THREAD_SAFE_CLASS_ +#define _TS_METHOD_ _THREAD_SAFE_METHOD_ +#define _TS_LOCK_ _THREAD_SAFE_LOCK_ +#define _TS_UNLOCK_ _THREAD_SAFE_UNLOCK_ +#define Thread_set_name(_name) Thread::set_name(_name) + +#if VERSION_MINOR >= 2 && VERSION_PATCH >= 4 +#define Mutex_define(_var) Mutex _var +#define Mutex_create(_var) +#define Mutex_delete(_var) +#define Mutex_lock(_var) _var.lock() +#define Mutex_unlock(_var) _var.unlock() + +#define t_wait_to_finish(thread) thread.wait_to_finish() +#define Thread_define(_var) class Thread _var +#define Thread_start(_var, _class, function, data_to_send, inst) _var.start(&_class::function, data_to_send) +#define Thread_close(_name) \ + if (_name.is_started()) \ + t_wait_to_finish(_name); +#else +#define Mutex_define(_var) Mutex *_var = nullptr +#define Mutex_create(_var) _var = Mutex::create() +#define Mutex_delete(_var) \ + if (_var) { \ + memdelete(_var); \ + _var = nullptr; \ + } + +#define Mutex_lock(_var) _var->lock() +#define Mutex_unlock(_var) _var->unlock() + +#define t_wait_to_finish(thread) Thread::wait_to_finish(thread) +#define Thread_define(_var) class Thread *_var = nullptr +#define Thread_start(_var, _class, function, data_to_send, inst) _var = Thread::create(&_class::function, data_to_send) +#define Thread_close(_name) \ + if (_name) { \ + t_wait_to_finish(_name); \ + memdelete(_name); \ + _name = nullptr; \ + } +#endif + +#else + +enum Margin : int { + MARGIN_LEFT, + MARGIN_TOP, + MARGIN_RIGHT, + MARGIN_BOTTOM +}; + +// THREAD SAFE classes +// ORIGINAL CODE FROM GODOT CORE +// because GDNative don't has it + +class ThreadSafe { + + Mutex *mutex; + +public: + inline void lock() const { + if (mutex) mutex->lock(); + } + inline void unlock() const { + if (mutex) mutex->unlock(); + } + + ThreadSafe() { + mutex = Mutex::_new(); + if (!mutex) { + + WARN_PRINT("THREAD_SAFE defined, but no default mutex type"); + } + } + + ~ThreadSafe() { + if (mutex) + mutex->free(); + } +}; + +class ThreadSafeMethod { + + const ThreadSafe *_ts; + +public: + ThreadSafeMethod(const ThreadSafe *p_ts) { + + _ts = p_ts; + _ts->lock(); + } + + ~ThreadSafeMethod() { _ts->unlock(); } +}; + +#define THREAD_FUNC +#define THREAD_DATA Variant +#define _TS_CLASS_ ThreadSafe __thread__safe__ +#define _TS_METHOD_ ThreadSafeMethod __thread_safe_method__(&__thread__safe__) +#define _TS_LOCK_ __thread__safe__.lock() +#define _TS_UNLOCK_ __thread__safe__.unlock() + +#define Mutex_define(_var) Ref _var +#define Mutex_create(_var) _var = newref(Mutex) +#define Mutex_lock(_var) _var->lock() +#define Mutex_unlock(_var) _var->unlock() +#define Mutex_delete(_var) \ + if (_var.is_valid()) { \ + _var.unref(); \ + _var = Ref(); \ + } + +#define Thread_define(_var) Ref _var +#define t_wait_to_finish(thread) thread->wait_to_finish() +#define Thread_start(_var, _class, function, data_to_send, inst) _var = _gdn_thread_create(inst, #function, data_to_send) +#define Thread_set_name(_name) +#define Thread_close(_name) \ + if (_name.is_valid()) { \ + t_wait_to_finish(_name); \ + _name.unref(); \ + _name = Ref(); \ + } + +// THREAD SAFE END + +#define ENUM_ARG(en) int +#define ENUM_CONV(en) + +#define DEF_ARG(a) +//#define DEF_ARGS(...) ,__VA_ARGS__ + +#define CONST_FAKE_SET() \ + void set_constant(int val) {} +#define CONST_FAKE_REG(cl) register_method("set_constant", &cl::set_constant) +#define METHOD_REG(cl, fn) register_method(#fn, &cl::fn) + +#define CONST_FUNC_CAT(cl, en, val) _get_##cl##_##en##_##val +#define CONST_FUNC_CAT_S(cl, en, val) "_get_" #cl "_" #en "_" #val +#define CONST_GET(cl, en, val) \ + int CONST_FUNC_CAT(cl, en, val)() { return (int)cl::en::val; } + +#define CONST_REG(cl, en, val) \ + register_method(CONST_FUNC_CAT_S(cl, en, val), &GodotRemote::CONST_FUNC_CAT(cl, en, val)); \ + register_property(#cl "_" #val, &GodotRemote::set_constant, &GodotRemote::CONST_FUNC_CAT(cl, en, val), cl::en::val) + +#define ST() ((SceneTree *)Engine::get_singleton()->get_main_loop()) +#define GD_CLASS(c, p) GODOT_CLASS(c, p) +#define GD_S_CLASS(c, p) GODOT_SUBCLASS(c, p) +#define V_CAST(var, type) (var.operator type()) +#define GLOBAL_DEF(m_var, m_value) _GLOBAL_DEF(m_var, m_value) +#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var) + +#define queue_del queue_free +#define is_valid_ip is_valid_ip_address +#define img_is_empty(img) img->is_empty() +#define release_pva_read(pva) +#define release_pva_write(pva) + +#define dict_get_key_at_index(dict, i) _gdn_dictionary_get_key_at_index(dict, i) +#define dict_get_value_at_index(dict, i) _gdn_dictionary_get_value_at_index(dict, i) + +#define file_get_as_string(path, err) _gdn_get_file_as_string(path, err) + +#define memnew(obj) obj::_new() +#define memdelete(obj) obj->free() + +#define GDNATIVE_BASIC_REGISTER \ +public: \ + void _init(){}; \ + static void _register_methods(){}; \ + \ +protected: + +#define GDNATIVE_BASIC_REGISTER_NO_INIT \ +public: \ + static void _register_methods(){}; \ + \ +protected: + +#define ERR_FAIL_V_MSG(m_retval, m_msg) \ + { \ + ERR_PRINT(String("Method failed. Returning: ") + #m_retval + ".\n" + m_msg); \ + return m_retval; \ + } +#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \ + { \ + if (((int)m_cond)) { \ + ERR_PRINT(String("Condition \"") + #m_cond + "\" is true. Returned: " + #m_retval + ".\n" + m_msg); \ + return m_retval; \ + } \ + } +#define ERR_FAIL_MSG(m_msg) \ + { \ + ERR_PRINT(String("Method failed.\n") + m_msg); \ + return; \ + } + +#endif + +// ================================================================= +// DEBUG DEFINES + +#ifdef DEBUG_ENABLED + +#define TimeCountInit() uint64_t simple_time_counter = OS::get_singleton()->get_ticks_usec() +#define TimeCountReset() simple_time_counter = OS::get_singleton()->get_ticks_usec() +// Shows delta between this and previous counter. Need to call TimeCountInit before +#define TimeCount(str) \ + GRUtils::_log(str + String(": ") + String::num((OS::get_singleton()->get_ticks_usec() - simple_time_counter) / 1000.0, 3) + " ms", GodotRemote::LogLevel::LL_DEBUG); \ + simple_time_counter = OS::get_singleton()->get_ticks_usec() +#else + +#define TimeCountInit() +#define TimeCountReset() +#define TimeCount(str) + +#endif // DEBUG_ENABLED + +// ================================================================= +// GLOBAL DEFINES + +#define sleep_usec(usec) OS::get_singleton()->delay_usec(usec) + +#define LEAVE_IF_EDITOR() \ + if (Engine::get_singleton()->is_editor_hint()) \ + return; + +#define newref(_class) Ref<_class>(memnew(_class)) +#define max(x, y) (x > y ? x : y) +#define min(x, y) (x < y ? x : y) +#define _log(val, ll) __log(val, ll, __FILE__, __LINE__) +#define is_vector_contains(vec, val) (std::find(vec.begin(), vec.end(), val) != vec.end()) + +#define GR_VERSION(x, y, z) \ + if (_grutils_data->internal_VERSION.size() == 0) { \ + _grutils_data->internal_VERSION.append(x); \ + _grutils_data->internal_VERSION.append(y); \ + _grutils_data->internal_VERSION.append(z); \ + } + +#define GR_PACKET_HEADER(a, b, c, d) \ + if (_grutils_data->internal_PACKET_HEADER.size() == 0) { \ + _grutils_data->internal_PACKET_HEADER.append(a); \ + _grutils_data->internal_PACKET_HEADER.append(b); \ + _grutils_data->internal_PACKET_HEADER.append(c); \ + _grutils_data->internal_PACKET_HEADER.append(d); \ + } + +#define CONNECTION_ADDRESS(con) str(con->get_connected_host()) + ":" + str(con->get_connected_port()) + +// Get Project Setting +#define GET_PS(setting_name) \ + ProjectSettings::get_singleton()->get_setting(setting_name) +// Get Project Setting and set it to variable +#define GET_PS_SET(variable_to_store, setting_name) \ + variable_to_store = ProjectSettings::get_singleton()->get_setting(setting_name) + +enum LogLevel : int { + LL_DEBUG = 0, + LL_NORMAL = 1, + LL_WARNING = 2, + LL_ERROR = 3, + LL_NONE, +}; + +namespace GRUtils { +// DEFINES + +template > +class iterable_queue : public std::queue { +public: + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + + iterator begin() { return this->c.begin(); } + iterator end() { return this->c.end(); } + const_iterator begin() const { return this->c.begin(); } + const_iterator end() const { return this->c.end(); } + void add_value_limited(T value, uint32_t limit) { + if (value > 100000) + this->push(100000); + else + this->push(value); + while (this->size() > limit) { + this->pop(); + } + } +}; + +class GRUtilsData : public Object { + GD_CLASS(GRUtilsData, Object); + GDNATIVE_BASIC_REGISTER; + +public: + int current_loglevel; + PoolByteArray internal_PACKET_HEADER; + PoolByteArray internal_VERSION; +}; + +#ifndef NO_GODOTREMOTE_SERVER +class GRUtilsDataServer { +public: + PoolByteArray compress_buffer; + int compress_buffer_size_mb; +}; + +extern GRUtilsDataServer *_grutils_data_server; +#endif +extern GRUtilsData *_grutils_data; + +extern void init(); +extern void deinit(); + +#ifndef NO_GODOTREMOTE_SERVER +extern void init_server_utils(); +extern void deinit_server_utils(); +extern Error compress_jpg(PoolByteArray &ret, const PoolByteArray &img_data, int width, int height, int bytes_for_color = 4, int quality = 75, int subsampling = 3 /*Subsampling ::SUBSAMPLING_H2V2*/); +#endif + +extern Error compress_bytes(const PoolByteArray &bytes, PoolByteArray &res, int type); +extern Error decompress_bytes(const PoolByteArray &bytes, int output_size, PoolByteArray &res, int type); +extern void __log(const Variant &val, int lvl = 1 /*LogLevel::LL_NORMAL*/, String file = "", int line = 0); + +extern String str(const Variant &val); +extern String str_arr(const Array arr, const bool force_full = false, const int max_shown_items = 32, String separator = ", "); +extern String str_arr(const Dictionary arr, const bool force_full = false, const int max_shown_items = 32, String separator = ", "); +extern String str_arr(const uint8_t *data, const int size, const bool force_full = false, const int max_shown_items = 64, String separator = ", "); + +extern bool validate_packet(const uint8_t *data); +extern bool validate_version(const PoolByteArray &data); +extern bool validate_version(const uint8_t *data); + +extern bool compare_pool_byte_arrays(const PoolByteArray &a, const PoolByteArray &b); + +extern void set_gravity(const Vector3 &p_gravity); +extern void set_accelerometer(const Vector3 &p_accel); +extern void set_magnetometer(const Vector3 &p_magnetometer); +extern void set_gyroscope(const Vector3 &p_gyroscope); + +// LITERALS + +// conversion from usec to msec. most useful to OS::delay_usec() +constexpr uint32_t operator"" _ms(unsigned long long val) { + return (int)val * 1000; +} + +// IMPLEMENTATINS + +template +extern String str_arr(const std::vector arr, const bool force_full = false, const int max_shown_items = 32, String separator = ", ") { + String res = "[ "; + int s = (int)arr.size(); + bool is_long = false; + if (s > max_shown_items && !force_full) { + s = max_shown_items; + is_long = true; + } + + for (int i = 0; i < s; i++) { + res += str(arr[i]); + if (i != s - 1 || is_long) { + res += separator; + } + } + + if (is_long) { + res += str(int64_t(arr.size()) - s) + " more items..."; + } + + return res + " ]"; +} + +template +extern String str_arr(const std::map arr, const bool force_full = false, const int max_shown_items = 32, String separator = ", ") { + String res = "{ "; + int s = (int)arr.size(); + bool is_long = false; + if (s > max_shown_items && !force_full) { + s = max_shown_items; + is_long = true; + } + + int i = 0; + for (auto p : arr) { + if (i++ >= s) + break; + res += str(p.first) + " : " + str(p.second); + if (i != s - 1 || is_long) { + res += separator; + } + } + + if (is_long) { + res += String::num_int64(int64_t(arr.size()) - s) + " more items..."; + } + + return res + " }"; +} + +#ifndef GDNATIVE_LIBRARY +template +static String str_arr(PoolVector arr, const bool force_full = false, const int max_shown_items = 64, String separator = ", ") { + String res = "[ "; + int s = arr.size(); + bool is_long = false; + if (s > max_shown_items && !force_full) { + s = max_shown_items; + is_long = true; + } + + auto r = arr.read(); + for (int i = 0; i < s; i++) { + res += str(r[i]); + if (i != s - 1 || is_long) { + res += separator; + } + } + release_pva_read(r); + + if (is_long) { + res += str(int64_t(arr.size()) - s) + " more items..."; + } + + return res + " ]"; +}; +#else + +#define POOLARRAYS_STR_ARR(TYPE) \ + static String str_arr(TYPE arr, const bool force_full = false, const int max_shown_items = 32, String separator = ", ") { \ + String res = "[ "; \ + int s = arr.size(); \ + bool is_long = false; \ + if (s > max_shown_items && !force_full) { \ + s = max_shown_items; \ + is_long = true; \ + } \ + \ + auto r = arr.read(); \ + for (int i = 0; i < s; i++) { \ + res += str(r[i]); \ + if (i != s - 1 || is_long) { \ + res += separator; \ + } \ + } \ + release_pva_read(r); \ + \ + if (is_long) { \ + res += str(int64_t(arr.size()) - s) + " more items..."; \ + } \ + \ + return res + " ]"; \ + } + +POOLARRAYS_STR_ARR(PoolByteArray); +POOLARRAYS_STR_ARR(PoolIntArray); +POOLARRAYS_STR_ARR(PoolRealArray); +POOLARRAYS_STR_ARR(PoolStringArray); +POOLARRAYS_STR_ARR(PoolVector2Array); +POOLARRAYS_STR_ARR(PoolVector3Array); +POOLARRAYS_STR_ARR(PoolColorArray); + +#undef POOLARRAYS_STR_ARR +#endif + +static PoolByteArray get_packet_header() { + return _grutils_data->internal_PACKET_HEADER; +} + +static PoolByteArray get_gr_version() { + return _grutils_data->internal_VERSION; +} + +static void set_log_level(int lvl) { + _grutils_data->current_loglevel = lvl; +} + +template +inline void calculate_avg_min_max_values(const iterable_queue &v, float *avg_val, float *min_val, float *max_val, float(modifier)(double)) { + if (v.size() > 0) { + double sum = 0; + *min_val = (float)v.back(); + *max_val = (float)v.back(); + + for (T i : v) { + sum += i; + if (i < *min_val) + *min_val = (float)i; + else if (i > *max_val) + *max_val = (float)i; + } + *avg_val = modifier(sum / v.size()); + *min_val = modifier(*min_val); + *max_val = modifier(*max_val); + } else { + *avg_val = 0; + *min_val = 0; + *max_val = 0; + } +} + +template +inline void vec_remove_idx(std::vector &v, const T &item) { + v.erase(std::remove(v.begin(), v.end(), item), v.end()); +} + +template +static Dictionary map_to_dict(std::map m) { + Dictionary res; + for (auto p : m) { + res[p.first] = p.second; + } + return res; +} + +template +static std::map dict_to_map(Dictionary d) { + std::map res; + Array keys = d.keys(); + Array values = d.values(); + for (int i = 0; i < keys.size(); i++) { + res[keys[i]] = values[i]; + } + keys.clear(); + values.clear(); + return res; +} + +template +static Array vec_to_arr(std::vector v) { + Array res; + res.resize((int)v.size()); + for (int i = 0; i < v.size(); i++) { + res[i] = v[i]; + } + return res; +} + +template +static std::vector arr_to_vec(Array a) { + std::vector res; + res.resize(a.size()); + for (int i = 0; i < a.size(); i++) { + res[i] = a[i]; + } + return res; +} + +#ifndef GDNATIVE_LIBRARY +extern Vector vec_args(const std::vector &args); + +#else +extern Array vec_args(const std::vector &args); + +extern String _gdn_get_file_as_string(String path, Error *ret_err); +extern Variant _gdn_dictionary_get_key_at_index(Dictionary d, int idx); +extern Variant _gdn_dictionary_get_value_at_index(Dictionary d, int idx); +extern Ref _gdn_thread_create(Object *instance, String func_name, const Object *user_data); +extern Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false); +#endif + +}; // namespace GRUtils + +#endif // !GRUTILS_H diff --git a/modules/godot_remote/godot_remote/GRVersion.h b/modules/godot_remote/godot_remote/GRVersion.h new file mode 100644 index 0000000..37c6bc9 --- /dev/null +++ b/modules/godot_remote/godot_remote/GRVersion.h @@ -0,0 +1 @@ +GR_VERSION(1, 0, 2); \ No newline at end of file diff --git a/modules/godot_remote/godot_remote/GodotRemote.cpp b/modules/godot_remote/godot_remote/GodotRemote.cpp new file mode 100644 index 0000000..4b0dfdf --- /dev/null +++ b/modules/godot_remote/godot_remote/GodotRemote.cpp @@ -0,0 +1,665 @@ +/* GodotRemote.cpp */ +#include "GodotRemote.h" +#include "GRClient.h" +#include "GRServer.h" + +#ifndef GDNATIVE_LIBRARY +#include "core/os/os.h" +#include "core/project_settings.h" +#include "editor/editor_node.h" +#include "scene/main/scene_tree.h" +#include "scene/main/timer.h" +#include "scene/main/viewport.h" +#else +#include +#include +#include +#include +#include +#include +#include +using namespace godot; +#endif + +GodotRemote *GodotRemote::singleton = nullptr; +bool GodotRemote::is_init_completed = false; + +using namespace GRUtils; + +GR_PS_NAME_TYPE GodotRemote::ps_general_autoload_name = "debug/godot_remote/general/autostart"; +GR_PS_NAME_TYPE GodotRemote::ps_general_port_name = "debug/godot_remote/general/port"; +GR_PS_NAME_TYPE GodotRemote::ps_general_loglevel_name = "debug/godot_remote/general/log_level"; + +GR_PS_NAME_TYPE GodotRemote::ps_notifications_enabled_name = "debug/godot_remote/notifications/notifications_enabled"; +GR_PS_NAME_TYPE GodotRemote::ps_noticications_position_name = "debug/godot_remote/notifications/notifications_position"; +GR_PS_NAME_TYPE GodotRemote::ps_notifications_duration_name = "debug/godot_remote/notifications/notifications_duration"; + +GR_PS_NAME_TYPE GodotRemote::ps_server_config_adb_name = "debug/godot_remote/server/configure_adb_on_play"; +GR_PS_NAME_TYPE GodotRemote::ps_server_stream_skip_frames_name = "debug/godot_remote/server/skip_frames"; +GR_PS_NAME_TYPE GodotRemote::ps_server_stream_enabled_name = "debug/godot_remote/server/video_stream_enabled"; +GR_PS_NAME_TYPE GodotRemote::ps_server_compression_type_name = "debug/godot_remote/server/compression_type"; +GR_PS_NAME_TYPE GodotRemote::ps_server_jpg_quality_name = "debug/godot_remote/server/jpg_quality"; +GR_PS_NAME_TYPE GodotRemote::ps_server_jpg_buffer_mb_size_name = "debug/godot_remote/server/jpg_compress_buffer_size_mbytes"; +GR_PS_NAME_TYPE GodotRemote::ps_server_auto_adjust_scale_name = "debug/godot_remote/server/auto_adjust_scale"; +GR_PS_NAME_TYPE GodotRemote::ps_server_scale_of_sending_stream_name = "debug/godot_remote/server/scale_of_sending_stream"; +GR_PS_NAME_TYPE GodotRemote::ps_server_password_name = "debug/godot_remote/server/password"; + +GR_PS_NAME_TYPE GodotRemote::ps_server_custom_input_scene_name = "debug/godot_remote/server_custom_input_scene/custom_input_scene"; +GR_PS_NAME_TYPE GodotRemote::ps_server_custom_input_scene_compressed_name = "debug/godot_remote/server_custom_input_scene/send_custom_input_scene_compressed"; +GR_PS_NAME_TYPE GodotRemote::ps_server_custom_input_scene_compression_type_name = "debug/godot_remote/server_custom_input_scene/custom_input_scene_compression_type"; + +GodotRemote *GodotRemote::get_singleton() { + return singleton; +} + +void GodotRemote::_init() { + if (!singleton) + singleton = this; + + register_and_load_settings(); + LEAVE_IF_EDITOR(); + + GRUtils::init(); + + call_deferred("_create_notification_manager"); + if (is_autostart) + call_deferred("create_and_start_device", DeviceType::DEVICE_AUTO); + +#ifndef GDNATIVE_LIBRARY +#ifdef TOOLS_ENABLED + call_deferred("_prepare_editor"); +#endif +#endif +} + +void GodotRemote::_deinit() { + LEAVE_IF_EDITOR(); + remove_remote_device(); + _remove_notifications_manager(); + +#ifndef GDNATIVE_LIBRARY +#ifdef TOOLS_ENABLED + call_deferred("_adb_start_timer_timeout"); +#endif +#endif + if (singleton == this) { + singleton = nullptr; + } + GRUtils::deinit(); +} + +#ifndef GDNATIVE_LIBRARY + +void GodotRemote::_bind_methods() { + ClassDB::bind_method(D_METHOD("_create_notification_manager"), &GodotRemote::_create_notification_manager); + + ClassDB::bind_method(D_METHOD("create_and_start_device", "device_type"), &GodotRemote::create_and_start_device, DEFVAL(DeviceType::DEVICE_AUTO)); + ClassDB::bind_method(D_METHOD("create_remote_device", "device_type"), &GodotRemote::create_remote_device, DEFVAL(DeviceType::DEVICE_AUTO)); + ClassDB::bind_method(D_METHOD("start_remote_device"), &GodotRemote::start_remote_device); + ClassDB::bind_method(D_METHOD("remove_remote_device"), &GodotRemote::remove_remote_device); +#ifdef TOOLS_ENABLED + ClassDB::bind_method(D_METHOD("_adb_port_forwarding"), &GodotRemote::_adb_port_forwarding); + ClassDB::bind_method(D_METHOD("_run_emitted"), &GodotRemote::_run_emitted); + ClassDB::bind_method(D_METHOD("_prepare_editor"), &GodotRemote::_prepare_editor); + ClassDB::bind_method(D_METHOD("_adb_start_timer_timeout"), &GodotRemote::_adb_start_timer_timeout); +#endif + + ClassDB::bind_method(D_METHOD("get_device"), &GodotRemote::get_device); + ClassDB::bind_method(D_METHOD("get_version"), &GodotRemote::get_version); + ClassDB::bind_method(D_METHOD("is_gdnative"), &GodotRemote::is_gdnative); + + // GRNotifications + ClassDB::bind_method(D_METHOD("get_notification", "title"), &GodotRemote::get_notification); + ClassDB::bind_method(D_METHOD("get_all_notifications"), &GodotRemote::get_all_notifications); + ClassDB::bind_method(D_METHOD("get_notifications_with_title", "title"), &GodotRemote::get_notifications_with_title); + + ClassDB::bind_method(D_METHOD("add_notification_or_append_string", "title", "text", "icon", "add_to_new_line", "duration_multiplier"), &GodotRemote::add_notification_or_append_string, DEFVAL(true), DEFVAL(1.f)); + ClassDB::bind_method(D_METHOD("add_notification_or_update_line", "title", "id", "text", "icon", "duration_multiplier"), &GodotRemote::add_notification_or_update_line, DEFVAL(1.f)); + ClassDB::bind_method(D_METHOD("add_notification", "title", "text", "notification_icon", "update_existing", "duration_multiplier"), &GodotRemote::add_notification, DEFVAL((int)GRNotifications::NotificationIcon::ICON_NONE), DEFVAL(true), DEFVAL(1.f)); + ClassDB::bind_method(D_METHOD("remove_notification", "title", "is_all_entries"), &GodotRemote::remove_notification, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("remove_notification_exact", "notification"), &GodotRemote::remove_notification_exact); + ClassDB::bind_method(D_METHOD("clear_notifications"), &GodotRemote::clear_notifications); + + ClassDB::bind_method(D_METHOD("set_notifications_layer", "position"), &GodotRemote::set_notifications_layer); + ClassDB::bind_method(D_METHOD("set_notifications_position", "position"), &GodotRemote::set_notifications_position); + ClassDB::bind_method(D_METHOD("set_notifications_enabled", "enabled"), &GodotRemote::set_notifications_enabled); + ClassDB::bind_method(D_METHOD("set_notifications_duration", "duration"), &GodotRemote::set_notifications_duration); + ClassDB::bind_method(D_METHOD("set_notifications_style", "style"), &GodotRemote::set_notifications_style); + + ClassDB::bind_method(D_METHOD("get_notifications_layer"), &GodotRemote::get_notifications_layer); + ClassDB::bind_method(D_METHOD("get_notifications_position"), &GodotRemote::get_notifications_position); + ClassDB::bind_method(D_METHOD("get_notifications_enabled"), &GodotRemote::get_notifications_enabled); + ClassDB::bind_method(D_METHOD("get_notifications_duration"), &GodotRemote::get_notifications_duration); + ClassDB::bind_method(D_METHOD("get_notifications_style"), &GodotRemote::get_notifications_style); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "notifications_layer"), "set_notifications_layer", "get_notifications_layer"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "notifications_position"), "set_notifications_position", "get_notifications_position"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "notifications_enabled"), "set_notifications_enabled", "get_notifications_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "notifications_duration"), "set_notifications_duration", "get_notifications_duration"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "notifications_style"), "set_notifications_style", "get_notifications_style"); + + ADD_SIGNAL(MethodInfo("device_added")); + ADD_SIGNAL(MethodInfo("device_removed")); + + BIND_ENUM_CONSTANT(DEVICE_AUTO); + BIND_ENUM_CONSTANT(DEVICE_SERVER); + BIND_ENUM_CONSTANT(DEVICE_CLIENT); + + // GRUtils + + BIND_ENUM_CONSTANT(LL_NONE); + BIND_ENUM_CONSTANT(LL_DEBUG); + BIND_ENUM_CONSTANT(LL_NORMAL); + BIND_ENUM_CONSTANT(LL_WARNING); + BIND_ENUM_CONSTANT(LL_ERROR); + + ClassDB::bind_method(D_METHOD("set_log_level", "level"), &GodotRemote::set_log_level); + + ClassDB::bind_method(D_METHOD("set_gravity", "value"), &GodotRemote::set_gravity); + ClassDB::bind_method(D_METHOD("set_accelerometer", "value"), &GodotRemote::set_accelerometer); + ClassDB::bind_method(D_METHOD("set_magnetometer", "value"), &GodotRemote::set_magnetometer); + ClassDB::bind_method(D_METHOD("set_gyroscope", "value"), &GodotRemote::set_gyroscope); + + // Other Enums +} + +#else + +void GodotRemote::_register_methods() { + METHOD_REG(GodotRemote, _notification); + + METHOD_REG(GodotRemote, _create_notification_manager); + + METHOD_REG(GodotRemote, create_and_start_device); + METHOD_REG(GodotRemote, create_remote_device); + METHOD_REG(GodotRemote, start_remote_device); + METHOD_REG(GodotRemote, remove_remote_device); + + METHOD_REG(GodotRemote, get_device); + METHOD_REG(GodotRemote, get_version); + METHOD_REG(GodotRemote, is_gdnative); + + // GRNotifications + METHOD_REG(GodotRemote, get_notification); + + METHOD_REG(GodotRemote, get_all_notifications); + METHOD_REG(GodotRemote, get_notifications_with_title); + + METHOD_REG(GodotRemote, add_notification_or_append_string); + METHOD_REG(GodotRemote, add_notification_or_update_line); + METHOD_REG(GodotRemote, add_notification); + METHOD_REG(GodotRemote, remove_notification); + METHOD_REG(GodotRemote, remove_notification_exact); + METHOD_REG(GodotRemote, clear_notifications); + + METHOD_REG(GodotRemote, set_notifications_layer); + METHOD_REG(GodotRemote, set_notifications_position); + METHOD_REG(GodotRemote, set_notifications_enabled); + METHOD_REG(GodotRemote, set_notifications_duration); + METHOD_REG(GodotRemote, set_notifications_style); + + METHOD_REG(GodotRemote, get_notifications_layer); + METHOD_REG(GodotRemote, get_notifications_position); + METHOD_REG(GodotRemote, get_notifications_enabled); + METHOD_REG(GodotRemote, get_notifications_duration); + METHOD_REG(GodotRemote, get_notifications_style); + + register_property("notifications_layer", &GodotRemote::set_notifications_layer, &GodotRemote::get_notifications_layer, 128); + register_property("notifications_position", &GodotRemote::set_notifications_position, &GodotRemote::get_notifications_position, GRNotifications::NotificationsPosition::TOP_CENTER); + register_property("notifications_enabled", &GodotRemote::set_notifications_enabled, &GodotRemote::get_notifications_enabled, true); + register_property("notifications_duration", &GodotRemote::set_notifications_duration, &GodotRemote::get_notifications_duration, 3.f); + register_property >("notifications_style", &GodotRemote::set_notifications_style, &GodotRemote::get_notifications_style, nullptr); + + register_signal("device_added", Dictionary::make()); + register_signal("device_removed", Dictionary::make()); + + METHOD_REG(GodotRemote, set_log_level); + + METHOD_REG(GodotRemote, set_gravity); + METHOD_REG(GodotRemote, set_accelerometer); + METHOD_REG(GodotRemote, set_magnetometer); + METHOD_REG(GodotRemote, set_gyroscope); + + CONST_FAKE_REG(GodotRemote); + + // GodotRemote + CONST_REG(GodotRemote, DeviceType, DEVICE_AUTO); + CONST_REG(GodotRemote, DeviceType, DEVICE_SERVER); + CONST_REG(GodotRemote, DeviceType, DEVICE_CLIENT); + + CONST_REG(GodotRemote, LogLevel, LL_NONE); + CONST_REG(GodotRemote, LogLevel, LL_DEBUG); + CONST_REG(GodotRemote, LogLevel, LL_NORMAL); + CONST_REG(GodotRemote, LogLevel, LL_WARNING); + CONST_REG(GodotRemote, LogLevel, LL_ERROR); + + // GRNotifications + CONST_REG(GRNotifications, NotificationIcon, ICON_NONE); + CONST_REG(GRNotifications, NotificationIcon, ICON_ERROR); + CONST_REG(GRNotifications, NotificationIcon, ICON_WARNING); + CONST_REG(GRNotifications, NotificationIcon, ICON_SUCCESS); + CONST_REG(GRNotifications, NotificationIcon, ICON_FAIL); + + CONST_REG(GRNotifications, NotificationsPosition, TOP_LEFT); + CONST_REG(GRNotifications, NotificationsPosition, TOP_CENTER); + CONST_REG(GRNotifications, NotificationsPosition, TOP_RIGHT); + CONST_REG(GRNotifications, NotificationsPosition, BOTTOM_LEFT); + CONST_REG(GRNotifications, NotificationsPosition, BOTTOM_CENTER); + CONST_REG(GRNotifications, NotificationsPosition, BOTTOM_RIGHT); + + // GRInputData + CONST_REG(GRInputData, InputType, _NoneIT); + CONST_REG(GRInputData, InputType, _InputDeviceSensors); + CONST_REG(GRInputData, InputType, _InputEvent); + CONST_REG(GRInputData, InputType, _InputEventAction); + CONST_REG(GRInputData, InputType, _InputEventGesture); + CONST_REG(GRInputData, InputType, _InputEventJoypadButton); + CONST_REG(GRInputData, InputType, _InputEventJoypadMotion); + CONST_REG(GRInputData, InputType, _InputEventKey); + CONST_REG(GRInputData, InputType, _InputEventMagnifyGesture); + CONST_REG(GRInputData, InputType, _InputEventMIDI); + CONST_REG(GRInputData, InputType, _InputEventMouse); + CONST_REG(GRInputData, InputType, _InputEventMouseButton); + CONST_REG(GRInputData, InputType, _InputEventMouseMotion); + CONST_REG(GRInputData, InputType, _InputEventPanGesture); + CONST_REG(GRInputData, InputType, _InputEventScreenDrag); + CONST_REG(GRInputData, InputType, _InputEventScreenTouch); + CONST_REG(GRInputData, InputType, _InputEventWithModifiers); + CONST_REG(GRInputData, InputType, _InputEventMAX); + + // GRPacket + CONST_REG(GRPacket, PacketType, NonePacket); + CONST_REG(GRPacket, PacketType, SyncTime); + CONST_REG(GRPacket, PacketType, ImageData); + CONST_REG(GRPacket, PacketType, InputData); + CONST_REG(GRPacket, PacketType, ServerSettings); + CONST_REG(GRPacket, PacketType, MouseModeSync); + CONST_REG(GRPacket, PacketType, CustomInputScene); + CONST_REG(GRPacket, PacketType, ClientStreamOrientation); + CONST_REG(GRPacket, PacketType, ClientStreamAspect); + CONST_REG(GRPacket, PacketType, CustomUserData); + CONST_REG(GRPacket, PacketType, Ping); + CONST_REG(GRPacket, PacketType, Pong); + + // GRDevice + CONST_REG(GRDevice, TypesOfServerSettings, SERVER_SETTINGS_USE_INTERNAL); + CONST_REG(GRDevice, TypesOfServerSettings, SERVER_SETTINGS_VIDEO_STREAM_ENABLED); + CONST_REG(GRDevice, TypesOfServerSettings, SERVER_SETTINGS_COMPRESSION_TYPE); + CONST_REG(GRDevice, TypesOfServerSettings, SERVER_SETTINGS_JPG_QUALITY); + CONST_REG(GRDevice, TypesOfServerSettings, SERVER_SETTINGS_SKIP_FRAMES); + CONST_REG(GRDevice, TypesOfServerSettings, SERVER_SETTINGS_RENDER_SCALE); + + CONST_REG(GRDevice, ImageCompressionType, COMPRESSION_UNCOMPRESSED); + CONST_REG(GRDevice, ImageCompressionType, COMPRESSION_JPG); + CONST_REG(GRDevice, ImageCompressionType, COMPRESSION_PNG); + + CONST_REG(GRDevice, Subsampling, SUBSAMPLING_Y_ONLY); + CONST_REG(GRDevice, Subsampling, SUBSAMPLING_H1V1); + CONST_REG(GRDevice, Subsampling, SUBSAMPLING_H2V1); + CONST_REG(GRDevice, Subsampling, SUBSAMPLING_H2V2); + + CONST_REG(GRDevice, WorkingStatus, STATUS_STARTING); + CONST_REG(GRDevice, WorkingStatus, STATUS_STOPPING); + CONST_REG(GRDevice, WorkingStatus, STATUS_WORKING); + CONST_REG(GRDevice, WorkingStatus, STATUS_STOPPED); + +#ifndef NO_GODOTREMOTE_CLIENT + // GRClient + CONST_REG(GRClient, ConnectionType, CONNECTION_ADB); + CONST_REG(GRClient, ConnectionType, CONNECTION_WiFi); + + CONST_REG(GRClient, StretchMode, STRETCH_KEEP_ASPECT); + CONST_REG(GRClient, StretchMode, STRETCH_FILL); + + CONST_REG(GRClient, StreamState, STREAM_NO_SIGNAL); + CONST_REG(GRClient, StreamState, STREAM_ACTIVE); + CONST_REG(GRClient, StreamState, STREAM_NO_IMAGE); +#endif // !NO_GODOTREMOTE_CLIENT +} +#endif + +void GodotRemote::_notification(int p_notification) { + switch (p_notification) { + case NOTIFICATION_POSTINITIALIZE: +#ifndef GDNATIVE_LIBRARY + _init(); +#endif + break; + case NOTIFICATION_PREDELETE: + _deinit(); + break; + } +} + +GRDevice *GodotRemote::get_device() { + return device; +} + +String GodotRemote::get_version() { + PoolByteArray ver = get_gr_version(); + return str(ver[0]) + "." + str(ver[1]) + "." + str(ver[2]); +} + +bool GodotRemote::is_gdnative() { +#ifndef GDNATIVE_LIBRARY + return false; +#else + return true; +#endif +} + +bool GodotRemote::create_remote_device(ENUM_ARG(DeviceType) type) { + if (!ST()) return false; + remove_remote_device(); + + GRDevice *d = nullptr; + + switch (type) { + // automatically start server if it not a standalone build + case DeviceType::DEVICE_AUTO: + if (!OS::get_singleton()->has_feature("standalone")) { +#ifndef NO_GODOTREMOTE_SERVER + d = memnew(GRServer); +#else + ERR_FAIL_V_MSG(false, "Server not included in this build!"); +#endif + } + break; + case DeviceType::DEVICE_SERVER: +#ifndef NO_GODOTREMOTE_SERVER + d = memnew(GRServer); +#else + ERR_FAIL_V_MSG(false, "Server not included in this build!"); +#endif + break; + case DeviceType::DEVICE_CLIENT: +#ifndef NO_GODOTREMOTE_CLIENT + d = memnew(GRClient); +#else + ERR_FAIL_V_MSG(false, "Client not included in this build!"); +#endif + break; + default: + ERR_FAIL_V_MSG(false, "Not allowed type!"); + break; + } + + if (d) { + device = d; + call_deferred("emit_signal", "device_added"); + ST()->get_root()->call_deferred("add_child", device); + ST()->get_root()->call_deferred("move_child", device, 0); + return true; + } + + return false; +} + +bool GodotRemote::start_remote_device() { + if (device && !device->is_queued_for_deletion()) { + device->start(); + return true; + } + return false; +} + +bool GodotRemote::remove_remote_device() { + if (device && !device->is_queued_for_deletion()) { + device->stop(); + device->queue_del(); + device = nullptr; + call_deferred("emit_signal", "device_removed"); + return true; + } + return false; +} + +void GodotRemote::register_and_load_settings() { +#ifndef GDNATIVE_LIBRARY +#define DEF_SET(var, name, def_val, info_type, info_hint_type, info_hint_string) \ + var = GLOBAL_DEF(name, def_val); \ + ProjectSettings::get_singleton()->set_custom_property_info(name, PropertyInfo(info_type, name, info_hint_type, info_hint_string)) +#define DEF_SET_ENUM(var, type, name, def_val, info_type, info_hint_type, info_hint_string) \ + var = (type)(int)GLOBAL_DEF(name, def_val); \ + ProjectSettings::get_singleton()->set_custom_property_info(name, PropertyInfo(info_type, name, info_hint_type, info_hint_string)) +#define DEF_(name, def_val, info_type, info_hint_type, info_hint_string) \ + GLOBAL_DEF(name, def_val); \ + ProjectSettings::get_singleton()->set_custom_property_info(name, PropertyInfo(info_type, name, info_hint_type, info_hint_string)) + +#else + +#define DEF_SET(var, name, def_val, info_type, info_hint_type, info_hint_string) \ + { \ + Dictionary d; \ + d["name"] = name; \ + d["type"] = info_type; \ + d["hint"] = GlobalConstants::info_hint_type; \ + d["hint_string"] = info_hint_string; \ + var = GLOBAL_DEF(name, def_val); \ + ProjectSettings::get_singleton()->add_property_info(d); \ + } +#define DEF_SET_ENUM(var, type, name, def_val, info_type, info_hint_type, info_hint_string) \ + { \ + Dictionary d; \ + d["name"] = name; \ + d["type"] = info_type; \ + d["hint"] = GlobalConstants::info_hint_type; \ + d["hint_string"] = info_hint_string; \ + var = (type)(int)GLOBAL_DEF(name, def_val); \ + ProjectSettings::get_singleton()->add_property_info(d); \ + } +#define DEF_(name, def_val, info_type, info_hint_type, info_hint_string) \ + { \ + Dictionary d; \ + d["name"] = name; \ + d["type"] = info_type; \ + d["hint"] = GlobalConstants::info_hint_type; \ + d["hint_string"] = info_hint_string; \ + GLOBAL_DEF(name, def_val); \ + ProjectSettings::get_singleton()->add_property_info(d); \ + } + +#endif + + DEF_SET(is_autostart, ps_general_autoload_name, true, Variant::BOOL, PROPERTY_HINT_NONE, ""); + DEF_(ps_general_port_name, 52341, Variant::INT, PROPERTY_HINT_RANGE, "0,65535"); + DEF_(ps_general_loglevel_name, LogLevel::LL_NORMAL, Variant::INT, PROPERTY_HINT_ENUM, "Debug,Normal,Warning,Error,None"); + + DEF_(ps_notifications_enabled_name, true, Variant::BOOL, PROPERTY_HINT_NONE, ""); + DEF_(ps_noticications_position_name, GRNotifications::NotificationsPosition::TOP_CENTER, Variant::INT, PROPERTY_HINT_ENUM, "TopLeft,TopCenter,TopRight,BottomLeft,BottomCenter,BottomRight"); + DEF_(ps_notifications_duration_name, 3.f, Variant::REAL, PROPERTY_HINT_RANGE, "0,100, 0.01"); + + // const server settings + DEF_(ps_server_config_adb_name, false, Variant::BOOL, PROPERTY_HINT_NONE, ""); + DEF_(ps_server_custom_input_scene_name, "", Variant::STRING, PROPERTY_HINT_FILE, "*.tscn,*.scn"); +#ifndef GDNATIVE_LIBRARY + DEF_(ps_server_custom_input_scene_compressed_name, true, Variant::BOOL, PROPERTY_HINT_NONE, ""); + DEF_(ps_server_custom_input_scene_compression_type_name, 0, Variant::INT, PROPERTY_HINT_ENUM, "FastLZ,DEFLATE,zstd,gzip"); +#endif + DEF_(ps_server_jpg_buffer_mb_size_name, 4, Variant::INT, PROPERTY_HINT_RANGE, "1,128"); + + // only server can change this settings + DEF_(ps_server_password_name, "", Variant::STRING, PROPERTY_HINT_NONE, ""); + + // client can change this settings + DEF_(ps_server_stream_enabled_name, true, Variant::BOOL, PROPERTY_HINT_NONE, ""); + DEF_(ps_server_compression_type_name, 1 /*GRServer::ImageCompressionType::JPG*/, Variant::INT, PROPERTY_HINT_ENUM, "Uncompressed,JPG,PNG"); + DEF_(ps_server_stream_skip_frames_name, 0, Variant::INT, PROPERTY_HINT_RANGE, "0,1000"); + DEF_(ps_server_scale_of_sending_stream_name, 0.3f, Variant::REAL, PROPERTY_HINT_RANGE, "0,1,0.01"); + DEF_(ps_server_jpg_quality_name, 80, Variant::INT, PROPERTY_HINT_RANGE, "0,100"); + DEF_(ps_server_auto_adjust_scale_name, false, Variant::BOOL, PROPERTY_HINT_NONE, ""); + +#undef DEF_SET +#undef DEF_SET_ENUM +#undef DEF_ +} + +void GodotRemote::_create_notification_manager() { + if (ST()) { + GRNotifications *notif = memnew(GRNotifications); + ST()->get_root()->add_child(notif); + ST()->get_root()->move_child(notif, 0); + } +} + +void GodotRemote::_remove_notifications_manager() { + GRNotificationPanel::clear_styles(); + if (GRNotifications::get_singleton() && !GRNotifications::get_singleton()->is_queued_for_deletion()) { + ST()->get_root()->remove_child(GRNotifications::get_singleton()); + memdelete(GRNotifications::get_singleton()); + } +} + +void GodotRemote::create_and_start_device(ENUM_ARG(DeviceType) type) { + create_remote_device(type); + start_remote_device(); +} + +#ifndef GDNATIVE_LIBRARY +#ifdef TOOLS_ENABLED +// TODO need to try get every device IDs and setup forwarding for each +#include "editor/editor_export.h" +#include "editor/editor_settings.h" + +void GodotRemote::_prepare_editor() { + if (Engine::get_singleton() && Engine::get_singleton()->is_editor_hint()) { + if (EditorNode::get_singleton()) + EditorNode::get_singleton()->connect("play_pressed", this, "_run_emitted"); + } +} + +void GodotRemote::_run_emitted() { + // call_deferred because debugger can't connect to game if process blocks thread on start + if ((bool)GET_PS(ps_server_config_adb_name)) + call_deferred("_adb_port_forwarding"); +} + +void GodotRemote::_adb_port_forwarding() { + String adb = EditorSettings::get_singleton()->get_setting("export/android/adb"); + + if (!adb.empty()) { + if (!adb_start_timer || adb_start_timer->is_queued_for_deletion()) { + adb_start_timer = memnew(Timer); + SceneTree::get_singleton()->get_root()->add_child(adb_start_timer); + adb_start_timer->set_one_shot(true); + adb_start_timer->set_autostart(false); + adb_start_timer->connect("timeout", this, "_adb_start_timer_timeout"); + } + + adb_start_timer->start(4.f); + } else { + _log("ADB path not specified.", LogLevel::LL_DEBUG); + } +} + +void GodotRemote::_adb_start_timer_timeout() { + String adb = EditorSettings::get_singleton()->get_setting("export/android/adb"); + List args; + args.push_back("reverse"); + args.push_back("--no-rebind"); + args.push_back("tcp:" + str(GET_PS(ps_general_port_name))); + args.push_back("tcp:" + str(GET_PS(ps_general_port_name))); + + Error err = OS::get_singleton()->execute(adb, args, true); // TODO freezes editor process on closing!!!! + + if (err) { + String start_url = String("\"{0}\" reverse --no-rebind tcp:{1} tcp:{2}").format(varray(adb, GET_PS(ps_general_port_name), GET_PS(ps_general_port_name))); + _log("Can't execute adb port forwarding: '" + start_url + "' error code: " + str(err), LogLevel::LL_ERROR); + } else { + _log("ADB port configuring completed", LogLevel::LL_NORMAL); + } + + if (adb_start_timer && !adb_start_timer->is_queued_for_deletion() && adb_start_timer->is_inside_tree()) { + adb_start_timer->queue_del(); + adb_start_timer = nullptr; + } +} + +#endif +#endif + +////////////////////////////////////////////////////////////////////////// +// EXTERNAL FUNCTIONS + +GRNotificationPanel *GodotRemote::get_notification(String title) { + return GRNotifications::get_notification(title); +} + +// GRNotifications +Array GodotRemote::get_all_notifications() { + return GRNotifications::get_all_notifications(); +} +Array GodotRemote::get_notifications_with_title(String title) { + return GRNotifications::get_notifications_with_title(title); +} +void GodotRemote::set_notifications_layer(int layer) { + if (GRNotifications::get_singleton()) + GRNotifications::get_singleton()->set_layer(layer); +} +int GodotRemote::get_notifications_layer() { + if (GRNotifications::get_singleton()) + return (int)GRNotifications::get_singleton()->get_layer(); + return 0; +} +void GodotRemote::set_notifications_position(ENUM_ARG(GRNotifications::NotificationsPosition) positon) { + GRNotifications::set_notifications_position((GRNotifications::NotificationsPosition)positon); +} +ENUM_ARG(GRNotifications::NotificationsPosition) +GodotRemote::get_notifications_position() { + return GRNotifications::get_notifications_position(); +} +void GodotRemote::set_notifications_enabled(bool _enabled) { + GRNotifications::set_notifications_enabled(_enabled); +} +bool GodotRemote::get_notifications_enabled() { + return GRNotifications::get_notifications_enabled(); +} +void GodotRemote::set_notifications_duration(float _duration) { + GRNotifications::set_notifications_duration(_duration); +} +float GodotRemote::get_notifications_duration() { + return GRNotifications::get_notifications_duration(); +} +void GodotRemote::set_notifications_style(Ref _style) { + GRNotifications::set_notifications_style(_style); +} +Ref GodotRemote::get_notifications_style() { + return GRNotifications::get_notifications_style(); +} +void GodotRemote::add_notification_or_append_string(String title, String text, ENUM_ARG(GRNotifications::NotificationIcon) icon, bool new_string, float duration_multiplier) { + GRNotifications::add_notification_or_append_string(title, text, (GRNotifications::NotificationIcon)icon, new_string, duration_multiplier); +} +void GodotRemote::add_notification_or_update_line(String title, String id, String text, ENUM_ARG(GRNotifications::NotificationIcon) icon, float duration_multiplier) { + GRNotifications::add_notification_or_update_line(title, id, text, (GRNotifications::NotificationIcon)icon, duration_multiplier); +} +void GodotRemote::add_notification(String title, String text, ENUM_ARG(GRNotifications::NotificationIcon) icon, bool update_existing, float duration_multiplier) { + GRNotifications::add_notification(title, text, (GRNotifications::NotificationIcon)icon, update_existing, duration_multiplier); +} +void GodotRemote::remove_notification(String title, bool all_entries) { + GRNotifications::remove_notification(title, all_entries); +} +void GodotRemote::remove_notification_exact(Node *_notif) { + GRNotifications::remove_notification_exact(_notif); +} +void GodotRemote::clear_notifications() { + GRNotifications::clear_notifications(); +} +// GRNotifications end + +// GRUtils functions binds for GDScript +void GodotRemote::set_log_level(ENUM_ARG(LogLevel) lvl) { + GRUtils::set_log_level((LogLevel)lvl); +} +void GodotRemote::set_gravity(const Vector3 &p_gravity) { + GRUtils::set_gravity(p_gravity); +} +void GodotRemote::set_accelerometer(const Vector3 &p_accel) { + GRUtils::set_accelerometer(p_accel); +} +void GodotRemote::set_magnetometer(const Vector3 &p_magnetometer) { + GRUtils::set_magnetometer(p_magnetometer); +} +void GodotRemote::set_gyroscope(const Vector3 &p_gyroscope) { + GRUtils::set_gyroscope(p_gyroscope); +} +// GRUtils end diff --git a/modules/godot_remote/godot_remote/GodotRemote.h b/modules/godot_remote/godot_remote/GodotRemote.h new file mode 100644 index 0000000..d7dc658 --- /dev/null +++ b/modules/godot_remote/godot_remote/GodotRemote.h @@ -0,0 +1,271 @@ +/* GodotRemote.h */ +#pragma once + +#include "GRDevice.h" +#include "GRNotifications.h" +#include "GRUtils.h" + +#ifndef GDNATIVE_LIBRARY +#include "core/image.h" +#include "core/pool_vector.h" +#include "core/reference.h" + +#else +#include "GRClient.h" + +#include +#include +#include +#include +#include +#include +#include +using namespace godot; +#endif + +using namespace GRUtils; + +#ifndef GDNATIVE_LIBRARY +class GodotRemote : public Object { + GD_CLASS(GodotRemote, Object); +#else +class GodotRemote : public Node { + GD_CLASS(GodotRemote, Node); +#endif + + friend class GRDevice; + static GodotRemote *singleton; + static bool is_init_completed; + +public: +#ifndef GDNATIVE_LIBRARY +#define GR_PS_NAME_TYPE String +#else +#define GR_PS_NAME_TYPE const char * +#endif + + enum DeviceType : int { + DEVICE_AUTO = 0, + DEVICE_SERVER = 1, + DEVICE_CLIENT = 2, + }; + + enum LogLevel : int { + LL_DEBUG = 0, + LL_NORMAL = 1, + LL_WARNING = 2, + LL_ERROR = 3, + LL_NONE, + }; + + static GR_PS_NAME_TYPE ps_general_autoload_name; + static GR_PS_NAME_TYPE ps_general_port_name; + static GR_PS_NAME_TYPE ps_general_loglevel_name; + + static GR_PS_NAME_TYPE ps_notifications_enabled_name; + static GR_PS_NAME_TYPE ps_noticications_position_name; + static GR_PS_NAME_TYPE ps_notifications_duration_name; + + static GR_PS_NAME_TYPE ps_server_config_adb_name; + static GR_PS_NAME_TYPE ps_server_stream_skip_frames_name; + static GR_PS_NAME_TYPE ps_server_stream_enabled_name; + static GR_PS_NAME_TYPE ps_server_compression_type_name; + static GR_PS_NAME_TYPE ps_server_jpg_quality_name; + static GR_PS_NAME_TYPE ps_server_jpg_buffer_mb_size_name; + static GR_PS_NAME_TYPE ps_server_auto_adjust_scale_name; + static GR_PS_NAME_TYPE ps_server_scale_of_sending_stream_name; + static GR_PS_NAME_TYPE ps_server_password_name; + + static GR_PS_NAME_TYPE ps_server_custom_input_scene_name; + static GR_PS_NAME_TYPE ps_server_custom_input_scene_compressed_name; + static GR_PS_NAME_TYPE ps_server_custom_input_scene_compression_type_name; + +private: + bool is_autostart = false; + bool is_notifications_enabled = true; + + class GRDevice *device = nullptr; + + void register_and_load_settings(); +#ifndef GDNATIVE_LIBRARY +#endif + + void _create_notification_manager(); + void _remove_notifications_manager(); + +#ifndef GDNATIVE_LIBRARY +#ifdef TOOLS_ENABLED + int64_t adb_pid = 0; + class Timer *adb_start_timer = nullptr; + + void _prepare_editor(); + void _run_emitted(); + void _adb_port_forwarding(); + void _adb_start_timer_timeout(); +#endif +#endif + +protected: +#ifndef GDNATIVE_LIBRARY + static void _bind_methods(); +#else +public: + static void _register_methods(); + + CONST_FAKE_SET(); + + // GodotRemote + CONST_GET(GodotRemote, DeviceType, DEVICE_AUTO); + CONST_GET(GodotRemote, DeviceType, DEVICE_SERVER); + CONST_GET(GodotRemote, DeviceType, DEVICE_CLIENT); + + CONST_GET(GodotRemote, LogLevel, LL_NONE); + CONST_GET(GodotRemote, LogLevel, LL_DEBUG); + CONST_GET(GodotRemote, LogLevel, LL_NORMAL); + CONST_GET(GodotRemote, LogLevel, LL_WARNING); + CONST_GET(GodotRemote, LogLevel, LL_ERROR); + + // GRNotivications + CONST_GET(GRNotifications, NotificationIcon, ICON_NONE); + CONST_GET(GRNotifications, NotificationIcon, ICON_ERROR); + CONST_GET(GRNotifications, NotificationIcon, ICON_WARNING); + CONST_GET(GRNotifications, NotificationIcon, ICON_SUCCESS); + CONST_GET(GRNotifications, NotificationIcon, ICON_FAIL); + + CONST_GET(GRNotifications, NotificationsPosition, TOP_LEFT); + CONST_GET(GRNotifications, NotificationsPosition, TOP_CENTER); + CONST_GET(GRNotifications, NotificationsPosition, TOP_RIGHT); + CONST_GET(GRNotifications, NotificationsPosition, BOTTOM_LEFT); + CONST_GET(GRNotifications, NotificationsPosition, BOTTOM_CENTER); + CONST_GET(GRNotifications, NotificationsPosition, BOTTOM_RIGHT); + + // GRInputData + CONST_GET(GRInputData, InputType, _NoneIT); + CONST_GET(GRInputData, InputType, _InputDeviceSensors); + CONST_GET(GRInputData, InputType, _InputEvent); + CONST_GET(GRInputData, InputType, _InputEventAction); + CONST_GET(GRInputData, InputType, _InputEventGesture); + CONST_GET(GRInputData, InputType, _InputEventJoypadButton); + CONST_GET(GRInputData, InputType, _InputEventJoypadMotion); + CONST_GET(GRInputData, InputType, _InputEventKey); + CONST_GET(GRInputData, InputType, _InputEventMagnifyGesture); + CONST_GET(GRInputData, InputType, _InputEventMIDI); + CONST_GET(GRInputData, InputType, _InputEventMouse); + CONST_GET(GRInputData, InputType, _InputEventMouseButton); + CONST_GET(GRInputData, InputType, _InputEventMouseMotion); + CONST_GET(GRInputData, InputType, _InputEventPanGesture); + CONST_GET(GRInputData, InputType, _InputEventScreenDrag); + CONST_GET(GRInputData, InputType, _InputEventScreenTouch); + CONST_GET(GRInputData, InputType, _InputEventWithModifiers); + CONST_GET(GRInputData, InputType, _InputEventMAX); + + // GRPacket + CONST_GET(GRPacket, PacketType, NonePacket); + CONST_GET(GRPacket, PacketType, SyncTime); + CONST_GET(GRPacket, PacketType, ImageData); + CONST_GET(GRPacket, PacketType, InputData); + CONST_GET(GRPacket, PacketType, ServerSettings); + CONST_GET(GRPacket, PacketType, MouseModeSync); + CONST_GET(GRPacket, PacketType, CustomInputScene); + CONST_GET(GRPacket, PacketType, ClientStreamOrientation); + CONST_GET(GRPacket, PacketType, ClientStreamAspect); + CONST_GET(GRPacket, PacketType, CustomUserData); + CONST_GET(GRPacket, PacketType, Ping); + CONST_GET(GRPacket, PacketType, Pong); + + // GRDevice + CONST_GET(GRDevice, TypesOfServerSettings, SERVER_SETTINGS_USE_INTERNAL); + CONST_GET(GRDevice, TypesOfServerSettings, SERVER_SETTINGS_VIDEO_STREAM_ENABLED); + CONST_GET(GRDevice, TypesOfServerSettings, SERVER_SETTINGS_COMPRESSION_TYPE); + CONST_GET(GRDevice, TypesOfServerSettings, SERVER_SETTINGS_JPG_QUALITY); + CONST_GET(GRDevice, TypesOfServerSettings, SERVER_SETTINGS_SKIP_FRAMES); + CONST_GET(GRDevice, TypesOfServerSettings, SERVER_SETTINGS_RENDER_SCALE); + + CONST_GET(GRDevice, ImageCompressionType, COMPRESSION_UNCOMPRESSED); + CONST_GET(GRDevice, ImageCompressionType, COMPRESSION_JPG); + CONST_GET(GRDevice, ImageCompressionType, COMPRESSION_PNG); + + CONST_GET(GRDevice, Subsampling, SUBSAMPLING_Y_ONLY); + CONST_GET(GRDevice, Subsampling, SUBSAMPLING_H1V1); + CONST_GET(GRDevice, Subsampling, SUBSAMPLING_H2V1); + CONST_GET(GRDevice, Subsampling, SUBSAMPLING_H2V2); + + CONST_GET(GRDevice, WorkingStatus, STATUS_STOPPED); + CONST_GET(GRDevice, WorkingStatus, STATUS_WORKING); + CONST_GET(GRDevice, WorkingStatus, STATUS_STOPPING); + CONST_GET(GRDevice, WorkingStatus, STATUS_STARTING); + +#ifndef NO_GODOTREMOTE_CLIENT + // GRClient + CONST_GET(GRClient, ConnectionType, CONNECTION_ADB); + CONST_GET(GRClient, ConnectionType, CONNECTION_WiFi); + + CONST_GET(GRClient, StretchMode, STRETCH_KEEP_ASPECT); + CONST_GET(GRClient, StretchMode, STRETCH_FILL); + + CONST_GET(GRClient, StreamState, STREAM_NO_SIGNAL); + CONST_GET(GRClient, StreamState, STREAM_ACTIVE); + CONST_GET(GRClient, StreamState, STREAM_NO_IMAGE); +#endif // !NO_GODOTREMOTE_CLIENT + +protected: +#endif + + void _notification(int p_notification); + +public: + // GRNotifications + class GRNotificationPanel *get_notification(String title); + Array get_all_notifications(); + Array get_notifications_with_title(String title); + + void set_notifications_layer(int layer); + int get_notifications_layer(); + + void set_notifications_position(ENUM_ARG(GRNotifications::NotificationsPosition) positon); + ENUM_ARG(GRNotifications::NotificationsPosition) get_notifications_position(); + + void set_notifications_enabled(bool _enabled); + bool get_notifications_enabled(); + + void set_notifications_duration(float _duration); + float get_notifications_duration(); + + void set_notifications_style(Ref _style); + Ref get_notifications_style(); + + void add_notification_or_append_string(String title, String text, ENUM_ARG(GRNotifications::NotificationIcon) icon, bool new_string DEF_ARG(= true), float duration_multiplier DEF_ARG(= 1.f)); + void add_notification_or_update_line(String title, String id, String text, ENUM_ARG(GRNotifications::NotificationIcon) icon, float duration_multiplier DEF_ARG(= 1.f)); + void add_notification(String title, String text, ENUM_ARG(GRNotifications::NotificationIcon) icon, bool update_existing DEF_ARG(= true), float duration_multiplier DEF_ARG(= 1.f)); + void remove_notification(String title, bool all_entries = true); + void remove_notification_exact(Node *_notif); + void clear_notifications(); + // GRNotifications end + + // GRUtils functions binds for GDScript + void set_log_level(ENUM_ARG(LogLevel) lvl); + void set_gravity(const Vector3 &p_gravity); + void set_accelerometer(const Vector3 &p_accel); + void set_magnetometer(const Vector3 &p_magnetometer); + void set_gyroscope(const Vector3 &p_gyroscope); + // GRUtils end + + GRDevice *get_device(); + String get_version(); + bool is_gdnative(); + + // must be call_deffered + void create_and_start_device(ENUM_ARG(DeviceType) type DEF_ARG(= DeviceType::DEVICE_AUTO)); + bool create_remote_device(ENUM_ARG(DeviceType) type DEF_ARG(= DeviceType::DEVICE_AUTO)); + bool start_remote_device(); + bool remove_remote_device(); + + static GodotRemote *get_singleton(); + void _init(); + void _deinit(); +}; + +#ifndef GDNATIVE_LIBRARY +VARIANT_ENUM_CAST(GodotRemote::DeviceType) +VARIANT_ENUM_CAST(GodotRemote::LogLevel) +#endif diff --git a/modules/godot_remote/godot_remote/SCsub b/modules/godot_remote/godot_remote/SCsub new file mode 100644 index 0000000..93c38d5 --- /dev/null +++ b/modules/godot_remote/godot_remote/SCsub @@ -0,0 +1,31 @@ +# SCsub +Import('env') + +module_env = env.Clone() + +if ARGUMENTS.get('godot_remote_no_default_resources', 'no') == 'yes': + module_env.Append(CPPDEFINES=['NO_GODOTREMOTE_DEFAULT_RESOURCES']) +if ARGUMENTS.get('godot_remote_disable_server', 'no') == 'yes': + module_env.Append(CPPDEFINES=['NO_GODOTREMOTE_SERVER']) +if ARGUMENTS.get('godot_remote_disable_client', 'no') == 'yes': + module_env.Append(CPPDEFINES=['NO_GODOTREMOTE_CLIENT']) + +if env['platform'] == 'windows': + module_env.add_source_files(env.modules_sources, '*.cpp') +else: + module_env.Append(CXXFLAGS=['-std=c++14']) # Flags for C++ code only + module_env.Append(CCFLAGS=['-O2']) # Flags for C and C++ code + + if ARGUMENTS.get('godot_remote_shared', 'no') == 'yes': + sources = [] + module_env.add_source_files(sources, '*.cpp') + module_env.Append(CCFLAGS=['-fPIC']) # Flags for C and C++ code + module_env['LIBS'] = [] + module_env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = True + shared_lib = module_env.SharedLibrary(target='#bin/godot_remote', source=sources) + + shared_lib_shim = shared_lib[0].name.rsplit('.', 1)[0] + env.Append(LIBS=[shared_lib_shim]) + env.Append(LIBPATH=['#bin']) + else: + module_env.add_source_files(env.modules_sources, '*.cpp') diff --git a/modules/godot_remote/godot_remote/config.py b/modules/godot_remote/godot_remote/config.py new file mode 100644 index 0000000..c1c0259 --- /dev/null +++ b/modules/godot_remote/godot_remote/config.py @@ -0,0 +1,7 @@ +# config.py + +def can_build(env, platform): + return True + +def configure(env): + pass \ No newline at end of file diff --git a/modules/godot_remote/godot_remote/jpge.cpp b/modules/godot_remote/godot_remote/jpge.cpp new file mode 100644 index 0000000..f21044a --- /dev/null +++ b/modules/godot_remote/godot_remote/jpge.cpp @@ -0,0 +1,1078 @@ +// jpge.cpp - C++ class for JPEG compression. Richard Geldreich +// Supports grayscale, H1V1, H2V1, and H2V2 chroma subsampling factors, one or two pass Huffman table optimization, libjpeg-style quality 1-100 quality factors. +// Also supports using luma quantization tables for chroma. +// +// Released under two licenses. You are free to choose which license you want: +// License 1: +// Public Domain +// +// License 2: +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// v1.01, Dec. 18, 2010 - Initial release +// v1.02, Apr. 6, 2011 - Removed 2x2 ordered dither in H2V1 chroma subsampling method load_block_16_8_8(). (The rounding factor was 2, when it should have been 1. Either way, it wasn't helping.) +// v1.03, Apr. 16, 2011 - Added support for optimized Huffman code tables, optimized dynamic memory allocation down to only 1 alloc. +// Also from Alex Evans: Added RGBA support, linear memory allocator (no longer needed in v1.03). +// v1.04, May. 19, 2012: Forgot to set m_pFile ptr to NULL in cfile_stream::close(). Thanks to Owen Kaluza for reporting this bug. +// Code tweaks to fix VS2008 static code analysis warnings (all looked harmless). +// Code review revealed method load_block_16_8_8() (used for the non-default H2V1 sampling mode to downsample chroma) somehow didn't get the rounding factor fix from v1.02. +// v1.05, March 25, 2020: Added Apache 2.0 alternate license + +#include "jpge.h" + +#include +#include +#include + +#define JPGE_MAX(a,b) (((a)>(b))?(a):(b)) +#define JPGE_MIN(a,b) (((a)<(b))?(a):(b)) + +namespace jpge { + + static inline void* jpge_malloc(size_t nSize) { return malloc(nSize); } + static inline void jpge_free(void* p) { free(p); } + + // Various JPEG enums and tables. + enum { M_SOF0 = 0xC0, M_DHT = 0xC4, M_SOI = 0xD8, M_EOI = 0xD9, M_SOS = 0xDA, M_DQT = 0xDB, M_APP0 = 0xE0 }; + enum { DC_LUM_CODES = 12, AC_LUM_CODES = 256, DC_CHROMA_CODES = 12, AC_CHROMA_CODES = 256, MAX_HUFF_SYMBOLS = 257, MAX_HUFF_CODESIZE = 32 }; + + static uint8 s_zag[64] = { 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 }; + static int16 s_std_lum_quant[64] = { 16,11,12,14,12,10,16,14,13,14,18,17,16,19,24,40,26,24,22,22,24,49,35,37,29,40,58,51,61,60,57,51,56,55,64,72,92,78,64,68,87,69,55,56,80,109,81,87,95,98,103,104,103,62,77,113,121,112,100,120,92,101,103,99 }; + static int16 s_std_croma_quant[64] = { 17,18,18,24,21,24,47,26,26,47,99,66,56,66,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99 }; + + // Table from http://www.imagemagick.org/discourse-server/viewtopic.php?f=22&t=20333&p=98008#p98008 + // This is mozjpeg's default table, in zag order. + static int16 s_alt_quant[64] = { 16,16,16,16,17,16,18,20,20,18,25,27,24,27,25,37,34,31,31,34,37,56,40,43,40,43,40,56,85,53,62,53,53,62,53,85,75,91,74,69,74,91,75,135,106,94,94,106,135,156,131,124,131,156,189,169,169,189,238,226,238,311,311,418 }; + + static uint8 s_dc_lum_bits[17] = { 0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0 }; + static uint8 s_dc_lum_val[DC_LUM_CODES] = { 0,1,2,3,4,5,6,7,8,9,10,11 }; + static uint8 s_ac_lum_bits[17] = { 0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d }; + static uint8 s_ac_lum_val[AC_LUM_CODES] = + { + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0, + 0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49, + 0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5, + 0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8, + 0xf9,0xfa + }; + static uint8 s_dc_chroma_bits[17] = { 0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0 }; + static uint8 s_dc_chroma_val[DC_CHROMA_CODES] = { 0,1,2,3,4,5,6,7,8,9,10,11 }; + static uint8 s_ac_chroma_bits[17] = { 0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77 }; + static uint8 s_ac_chroma_val[AC_CHROMA_CODES] = + { + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0, + 0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48, + 0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3, + 0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8, + 0xf9,0xfa + }; + + // Low-level helper functions. + template inline void clear_obj(T& obj) { memset(&obj, 0, sizeof(obj)); } + + const int YR = 19595, YG = 38470, YB = 7471, CB_R = -11059, CB_G = -21709, CB_B = 32768, CR_R = 32768, CR_G = -27439, CR_B = -5329; + static inline uint8 clamp(int i) { if (static_cast(i) > 255U) { if (i < 0) i = 0; else if (i > 255) i = 255; } return static_cast(i); } + + static inline int left_shifti(int val, uint32 bits) + { + return static_cast(static_cast(val) << bits); + } + + static void RGB_to_YCC(uint8* pDst, const uint8* pSrc, int num_pixels) + { + for (; num_pixels; pDst += 3, pSrc += 3, num_pixels--) + { + const int r = pSrc[0], g = pSrc[1], b = pSrc[2]; + pDst[0] = static_cast((r * YR + g * YG + b * YB + 32768) >> 16); + pDst[1] = clamp(128 + ((r * CB_R + g * CB_G + b * CB_B + 32768) >> 16)); + pDst[2] = clamp(128 + ((r * CR_R + g * CR_G + b * CR_B + 32768) >> 16)); + } + } + + static void RGB_to_Y(uint8* pDst, const uint8* pSrc, int num_pixels) + { + for (; num_pixels; pDst++, pSrc += 3, num_pixels--) + pDst[0] = static_cast((pSrc[0] * YR + pSrc[1] * YG + pSrc[2] * YB + 32768) >> 16); + } + + static void RGBA_to_YCC(uint8* pDst, const uint8* pSrc, int num_pixels) + { + for (; num_pixels; pDst += 3, pSrc += 4, num_pixels--) + { + const int r = pSrc[0], g = pSrc[1], b = pSrc[2]; + pDst[0] = static_cast((r * YR + g * YG + b * YB + 32768) >> 16); + pDst[1] = clamp(128 + ((r * CB_R + g * CB_G + b * CB_B + 32768) >> 16)); + pDst[2] = clamp(128 + ((r * CR_R + g * CR_G + b * CR_B + 32768) >> 16)); + } + } + + static void RGBA_to_Y(uint8* pDst, const uint8* pSrc, int num_pixels) + { + for (; num_pixels; pDst++, pSrc += 4, num_pixels--) + pDst[0] = static_cast((pSrc[0] * YR + pSrc[1] * YG + pSrc[2] * YB + 32768) >> 16); + } + + static void Y_to_YCC(uint8* pDst, const uint8* pSrc, int num_pixels) + { + for (; num_pixels; pDst += 3, pSrc++, num_pixels--) { pDst[0] = pSrc[0]; pDst[1] = 128; pDst[2] = 128; } + } + + // Forward DCT - DCT derived from jfdctint. + enum { CONST_BITS = 13, ROW_BITS = 2 }; +#define DCT_DESCALE(x, n) (((x) + (((int32)1) << ((n) - 1))) >> (n)) +#define DCT_MUL(var, c) (static_cast(var) * static_cast(c)) +#define DCT1D(s0, s1, s2, s3, s4, s5, s6, s7) \ + int32 t0 = s0 + s7, t7 = s0 - s7, t1 = s1 + s6, t6 = s1 - s6, t2 = s2 + s5, t5 = s2 - s5, t3 = s3 + s4, t4 = s3 - s4; \ + int32 t10 = t0 + t3, t13 = t0 - t3, t11 = t1 + t2, t12 = t1 - t2; \ + int32 u1 = DCT_MUL(t12 + t13, 4433); \ + s2 = u1 + DCT_MUL(t13, 6270); \ + s6 = u1 + DCT_MUL(t12, -15137); \ + u1 = t4 + t7; \ + int32 u2 = t5 + t6, u3 = t4 + t6, u4 = t5 + t7; \ + int32 z5 = DCT_MUL(u3 + u4, 9633); \ + t4 = DCT_MUL(t4, 2446); t5 = DCT_MUL(t5, 16819); \ + t6 = DCT_MUL(t6, 25172); t7 = DCT_MUL(t7, 12299); \ + u1 = DCT_MUL(u1, -7373); u2 = DCT_MUL(u2, -20995); \ + u3 = DCT_MUL(u3, -16069); u4 = DCT_MUL(u4, -3196); \ + u3 += z5; u4 += z5; \ + s0 = t10 + t11; s1 = t7 + u1 + u4; s3 = t6 + u2 + u3; s4 = t10 - t11; s5 = t5 + u2 + u4; s7 = t4 + u1 + u3; + + static void DCT2D(int32* p) + { + int32 c, * q = p; + for (c = 7; c >= 0; c--, q += 8) + { + int32 s0 = q[0], s1 = q[1], s2 = q[2], s3 = q[3], s4 = q[4], s5 = q[5], s6 = q[6], s7 = q[7]; + DCT1D(s0, s1, s2, s3, s4, s5, s6, s7); + q[0] = left_shifti(s0, ROW_BITS); q[1] = DCT_DESCALE(s1, CONST_BITS - ROW_BITS); q[2] = DCT_DESCALE(s2, CONST_BITS - ROW_BITS); q[3] = DCT_DESCALE(s3, CONST_BITS - ROW_BITS); + q[4] = left_shifti(s4, ROW_BITS); q[5] = DCT_DESCALE(s5, CONST_BITS - ROW_BITS); q[6] = DCT_DESCALE(s6, CONST_BITS - ROW_BITS); q[7] = DCT_DESCALE(s7, CONST_BITS - ROW_BITS); + } + for (q = p, c = 7; c >= 0; c--, q++) + { + int32 s0 = q[0 * 8], s1 = q[1 * 8], s2 = q[2 * 8], s3 = q[3 * 8], s4 = q[4 * 8], s5 = q[5 * 8], s6 = q[6 * 8], s7 = q[7 * 8]; + DCT1D(s0, s1, s2, s3, s4, s5, s6, s7); + q[0 * 8] = DCT_DESCALE(s0, ROW_BITS + 3); q[1 * 8] = DCT_DESCALE(s1, CONST_BITS + ROW_BITS + 3); q[2 * 8] = DCT_DESCALE(s2, CONST_BITS + ROW_BITS + 3); q[3 * 8] = DCT_DESCALE(s3, CONST_BITS + ROW_BITS + 3); + q[4 * 8] = DCT_DESCALE(s4, ROW_BITS + 3); q[5 * 8] = DCT_DESCALE(s5, CONST_BITS + ROW_BITS + 3); q[6 * 8] = DCT_DESCALE(s6, CONST_BITS + ROW_BITS + 3); q[7 * 8] = DCT_DESCALE(s7, CONST_BITS + ROW_BITS + 3); + } + } + + struct sym_freq { uint m_key, m_sym_index; }; + + // Radix sorts sym_freq[] array by 32-bit key m_key. Returns ptr to sorted values. + static inline sym_freq* radix_sort_syms(uint num_syms, sym_freq* pSyms0, sym_freq* pSyms1) + { + const uint cMaxPasses = 4; + uint32 hist[256 * cMaxPasses]; clear_obj(hist); + for (uint i = 0; i < num_syms; i++) { uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; hist[256 * 2 + ((freq >> 16) & 0xFF)]++; hist[256 * 3 + ((freq >> 24) & 0xFF)]++; } + sym_freq* pCur_syms = pSyms0, * pNew_syms = pSyms1; + uint total_passes = cMaxPasses; while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; + for (uint pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) + { + const uint32* pHist = &hist[pass << 8]; + uint offsets[256], cur_ofs = 0; + for (uint i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } + for (uint i = 0; i < num_syms; i++) + pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; + sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; + } + return pCur_syms; + } + + // calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. + static void calculate_minimum_redundancy(sym_freq* A, int n) + { + int root, leaf, next, avbl, used, dpth; + if (n == 0) return; else if (n == 1) { A[0].m_key = 1; return; } + A[0].m_key += A[1].m_key; root = 0; leaf = 2; + for (next = 1; next < n - 1; next++) + { + if (leaf >= n || A[root].m_key < A[leaf].m_key) { A[next].m_key = A[root].m_key; A[root++].m_key = next; } + else A[next].m_key = A[leaf++].m_key; + if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) { A[next].m_key += A[root].m_key; A[root++].m_key = next; } + else A[next].m_key += A[leaf++].m_key; + } + A[n - 2].m_key = 0; + for (next = n - 3; next >= 0; next--) A[next].m_key = A[A[next].m_key].m_key + 1; + avbl = 1; used = dpth = 0; root = n - 2; next = n - 1; + while (avbl > 0) + { + while (root >= 0 && (int)A[root].m_key == dpth) { used++; root--; } + while (avbl > used) { A[next--].m_key = dpth; avbl--; } + avbl = 2 * used; dpth++; used = 0; + } + } + + // Limits canonical Huffman code table's max code size to max_code_size. + static void huffman_enforce_max_code_size(int* pNum_codes, int code_list_len, int max_code_size) + { + if (code_list_len <= 1) return; + + for (int i = max_code_size + 1; i <= MAX_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; + + uint32 total = 0; + for (int i = max_code_size; i > 0; i--) + total += (((uint32)pNum_codes[i]) << (max_code_size - i)); + + while (total != (1UL << max_code_size)) + { + pNum_codes[max_code_size]--; + for (int i = max_code_size - 1; i > 0; i--) + { + if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } + } + total--; + } + } + + // Generates an optimized offman table. + void jpeg_encoder::optimize_huffman_table(int table_num, int table_len) + { + sym_freq syms0[MAX_HUFF_SYMBOLS], syms1[MAX_HUFF_SYMBOLS]; + syms0[0].m_key = 1; syms0[0].m_sym_index = 0; // dummy symbol, assures that no valid code contains all 1's + int num_used_syms = 1; + const uint32* pSym_count = &m_huff_count[table_num][0]; + for (int i = 0; i < table_len; i++) + if (pSym_count[i]) { syms0[num_used_syms].m_key = pSym_count[i]; syms0[num_used_syms++].m_sym_index = i + 1; } + sym_freq* pSyms = radix_sort_syms(num_used_syms, syms0, syms1); + calculate_minimum_redundancy(pSyms, num_used_syms); + + // Count the # of symbols of each code size. + int num_codes[1 + MAX_HUFF_CODESIZE]; clear_obj(num_codes); + for (int i = 0; i < num_used_syms; i++) + num_codes[pSyms[i].m_key]++; + + const uint JPGE_CODE_SIZE_LIMIT = 16; // the maximum possible size of a JPEG Huffman code (valid range is [9,16] - 9 vs. 8 because of the dummy symbol) + huffman_enforce_max_code_size(num_codes, num_used_syms, JPGE_CODE_SIZE_LIMIT); + + // Compute m_huff_bits array, which contains the # of symbols per code size. + clear_obj(m_huff_bits[table_num]); + for (int i = 1; i <= (int)JPGE_CODE_SIZE_LIMIT; i++) + m_huff_bits[table_num][i] = static_cast(num_codes[i]); + + // Remove the dummy symbol added above, which must be in largest bucket. + for (int i = JPGE_CODE_SIZE_LIMIT; i >= 1; i--) + { + if (m_huff_bits[table_num][i]) { m_huff_bits[table_num][i]--; break; } + } + + // Compute the m_huff_val array, which contains the symbol indices sorted by code size (smallest to largest). + for (int i = num_used_syms - 1; i >= 1; i--) + m_huff_val[table_num][num_used_syms - 1 - i] = static_cast(pSyms[i].m_sym_index - 1); + } + + // JPEG marker generation. + void jpeg_encoder::emit_byte(uint8 i) + { + m_all_stream_writes_succeeded = m_all_stream_writes_succeeded && m_pStream->put_obj(i); + } + + void jpeg_encoder::emit_word(uint i) + { + emit_byte(uint8(i >> 8)); emit_byte(uint8(i & 0xFF)); + } + + void jpeg_encoder::emit_marker(int marker) + { + emit_byte(uint8(0xFF)); emit_byte(uint8(marker)); + } + + // Emit JFIF marker + void jpeg_encoder::emit_jfif_app0() + { + emit_marker(M_APP0); + emit_word(2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); + emit_byte(0x4A); emit_byte(0x46); emit_byte(0x49); emit_byte(0x46); /* Identifier: ASCII "JFIF" */ + emit_byte(0); + emit_byte(1); /* Major version */ + emit_byte(1); /* Minor version */ + emit_byte(0); /* Density unit */ + emit_word(1); + emit_word(1); + emit_byte(0); /* No thumbnail image */ + emit_byte(0); + } + + // Emit quantization tables + void jpeg_encoder::emit_dqt() + { + for (int i = 0; i < ((m_num_components == 3) ? 2 : 1); i++) + { + emit_marker(M_DQT); + emit_word(64 + 1 + 2); + emit_byte(static_cast(i)); + for (int j = 0; j < 64; j++) + emit_byte(static_cast(m_quantization_tables[i][j])); + } + } + + // Emit start of frame marker + void jpeg_encoder::emit_sof() + { + emit_marker(M_SOF0); /* baseline */ + emit_word(3 * m_num_components + 2 + 5 + 1); + emit_byte(8); /* precision */ + emit_word(m_image_y); + emit_word(m_image_x); + emit_byte(m_num_components); + for (int i = 0; i < m_num_components; i++) + { + emit_byte(static_cast(i + 1)); /* component ID */ + emit_byte((m_comp_h_samp[i] << 4) + m_comp_v_samp[i]); /* h and v sampling */ + emit_byte(i > 0); /* quant. table num */ + } + } + + // Emit Huffman table. + void jpeg_encoder::emit_dht(uint8* bits, uint8* val, int index, bool ac_flag) + { + emit_marker(M_DHT); + + int length = 0; + for (int i = 1; i <= 16; i++) + length += bits[i]; + + emit_word(length + 2 + 1 + 16); + emit_byte(static_cast(index + (ac_flag << 4))); + + for (int i = 1; i <= 16; i++) + emit_byte(bits[i]); + + for (int i = 0; i < length; i++) + emit_byte(val[i]); + } + + // Emit all Huffman tables. + void jpeg_encoder::emit_dhts() + { + emit_dht(m_huff_bits[0 + 0], m_huff_val[0 + 0], 0, false); + emit_dht(m_huff_bits[2 + 0], m_huff_val[2 + 0], 0, true); + if (m_num_components == 3) + { + emit_dht(m_huff_bits[0 + 1], m_huff_val[0 + 1], 1, false); + emit_dht(m_huff_bits[2 + 1], m_huff_val[2 + 1], 1, true); + } + } + + // emit start of scan + void jpeg_encoder::emit_sos() + { + emit_marker(M_SOS); + emit_word(2 * m_num_components + 2 + 1 + 3); + emit_byte(m_num_components); + for (int i = 0; i < m_num_components; i++) + { + emit_byte(static_cast(i + 1)); + if (i == 0) + emit_byte((0 << 4) + 0); + else + emit_byte((1 << 4) + 1); + } + emit_byte(0); /* spectral selection */ + emit_byte(63); + emit_byte(0); + } + + // Emit all markers at beginning of image file. + void jpeg_encoder::emit_markers() + { + emit_marker(M_SOI); + emit_jfif_app0(); + emit_dqt(); + emit_sof(); + emit_dhts(); + emit_sos(); + } + + // Compute the actual canonical Huffman codes/code sizes given the JPEG huff bits and val arrays. + void jpeg_encoder::compute_huffman_table(uint* codes, uint8* code_sizes, uint8* bits, uint8* val) + { + int i, l, last_p, si; + uint8 huff_size[257]; + uint huff_code[257]; + uint code; + + int p = 0; + for (l = 1; l <= 16; l++) + for (i = 1; i <= bits[l]; i++) + huff_size[p++] = (char)l; + + huff_size[p] = 0; last_p = p; // write sentinel + + code = 0; si = huff_size[0]; p = 0; + + while (huff_size[p]) + { + while (huff_size[p] == si) + huff_code[p++] = code++; + code <<= 1; + si++; + } + + memset(codes, 0, sizeof(codes[0]) * 256); + memset(code_sizes, 0, sizeof(code_sizes[0]) * 256); + for (p = 0; p < last_p; p++) + { + codes[val[p]] = huff_code[p]; + code_sizes[val[p]] = huff_size[p]; + } + } + + // Quantization table generation. + void jpeg_encoder::compute_quant_table(int32* pDst, int16* pSrc) + { + int32 q; + if (m_params.m_quality < 50) + q = 5000 / m_params.m_quality; + else + q = 200 - m_params.m_quality * 2; + for (int i = 0; i < 64; i++) + { + int32 j = *pSrc++; j = (j * q + 50L) / 100L; + *pDst++ = JPGE_MIN(JPGE_MAX(j, 1), 255); + } + } + + // Higher-level methods. + void jpeg_encoder::first_pass_init() + { + m_bit_buffer = 0; m_bits_in = 0; + memset(m_last_dc_val, 0, 3 * sizeof(m_last_dc_val[0])); + m_mcu_y_ofs = 0; + m_pass_num = 1; + } + + bool jpeg_encoder::second_pass_init() + { + compute_huffman_table(&m_huff_codes[0 + 0][0], &m_huff_code_sizes[0 + 0][0], m_huff_bits[0 + 0], m_huff_val[0 + 0]); + compute_huffman_table(&m_huff_codes[2 + 0][0], &m_huff_code_sizes[2 + 0][0], m_huff_bits[2 + 0], m_huff_val[2 + 0]); + if (m_num_components > 1) + { + compute_huffman_table(&m_huff_codes[0 + 1][0], &m_huff_code_sizes[0 + 1][0], m_huff_bits[0 + 1], m_huff_val[0 + 1]); + compute_huffman_table(&m_huff_codes[2 + 1][0], &m_huff_code_sizes[2 + 1][0], m_huff_bits[2 + 1], m_huff_val[2 + 1]); + } + first_pass_init(); + emit_markers(); + m_pass_num = 2; + return true; + } + + bool jpeg_encoder::jpg_open(int p_x_res, int p_y_res, int src_channels) + { + m_num_components = 3; + switch (m_params.m_subsampling) + { + case Y_ONLY: + { + m_num_components = 1; + m_comp_h_samp[0] = 1; m_comp_v_samp[0] = 1; + m_mcu_x = 8; m_mcu_y = 8; + break; + } + case H1V1: + { + m_comp_h_samp[0] = 1; m_comp_v_samp[0] = 1; + m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1; + m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1; + m_mcu_x = 8; m_mcu_y = 8; + break; + } + case H2V1: + { + m_comp_h_samp[0] = 2; m_comp_v_samp[0] = 1; + m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1; + m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1; + m_mcu_x = 16; m_mcu_y = 8; + break; + } + case H2V2: + { + m_comp_h_samp[0] = 2; m_comp_v_samp[0] = 2; + m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1; + m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1; + m_mcu_x = 16; m_mcu_y = 16; + } + } + + m_image_x = p_x_res; m_image_y = p_y_res; + m_image_bpp = src_channels; + m_image_bpl = m_image_x * src_channels; + m_image_x_mcu = (m_image_x + m_mcu_x - 1) & (~(m_mcu_x - 1)); + m_image_y_mcu = (m_image_y + m_mcu_y - 1) & (~(m_mcu_y - 1)); + m_image_bpl_xlt = m_image_x * m_num_components; + m_image_bpl_mcu = m_image_x_mcu * m_num_components; + m_mcus_per_row = m_image_x_mcu / m_mcu_x; + + if ((m_mcu_lines[0] = static_cast(jpge_malloc(m_image_bpl_mcu * m_mcu_y))) == NULL) return false; + for (int i = 1; i < m_mcu_y; i++) + m_mcu_lines[i] = m_mcu_lines[i - 1] + m_image_bpl_mcu; + + if (m_params.m_use_std_tables) + { + compute_quant_table(m_quantization_tables[0], s_std_lum_quant); + compute_quant_table(m_quantization_tables[1], m_params.m_no_chroma_discrim_flag ? s_std_lum_quant : s_std_croma_quant); + } + else + { + compute_quant_table(m_quantization_tables[0], s_alt_quant); + memcpy(m_quantization_tables[1], m_quantization_tables[0], sizeof(m_quantization_tables[1])); + } + + m_out_buf_left = JPGE_OUT_BUF_SIZE; + m_pOut_buf = m_out_buf; + + if (m_params.m_two_pass_flag) + { + clear_obj(m_huff_count); + first_pass_init(); + } + else + { + memcpy(m_huff_bits[0 + 0], s_dc_lum_bits, 17); memcpy(m_huff_val[0 + 0], s_dc_lum_val, DC_LUM_CODES); + memcpy(m_huff_bits[2 + 0], s_ac_lum_bits, 17); memcpy(m_huff_val[2 + 0], s_ac_lum_val, AC_LUM_CODES); + memcpy(m_huff_bits[0 + 1], s_dc_chroma_bits, 17); memcpy(m_huff_val[0 + 1], s_dc_chroma_val, DC_CHROMA_CODES); + memcpy(m_huff_bits[2 + 1], s_ac_chroma_bits, 17); memcpy(m_huff_val[2 + 1], s_ac_chroma_val, AC_CHROMA_CODES); + if (!second_pass_init()) return false; // in effect, skip over the first pass + } + return m_all_stream_writes_succeeded; + } + + void jpeg_encoder::load_block_8_8_grey(int x) + { + uint8* pSrc; + sample_array_t* pDst = m_sample_array; + x <<= 3; + for (int i = 0; i < 8; i++, pDst += 8) + { + pSrc = m_mcu_lines[i] + x; + pDst[0] = pSrc[0] - 128; pDst[1] = pSrc[1] - 128; pDst[2] = pSrc[2] - 128; pDst[3] = pSrc[3] - 128; + pDst[4] = pSrc[4] - 128; pDst[5] = pSrc[5] - 128; pDst[6] = pSrc[6] - 128; pDst[7] = pSrc[7] - 128; + } + } + + void jpeg_encoder::load_block_8_8(int x, int y, int c) + { + uint8* pSrc; + sample_array_t* pDst = m_sample_array; + x = (x * (8 * 3)) + c; + y <<= 3; + for (int i = 0; i < 8; i++, pDst += 8) + { + pSrc = m_mcu_lines[y + i] + x; + pDst[0] = pSrc[0 * 3] - 128; pDst[1] = pSrc[1 * 3] - 128; pDst[2] = pSrc[2 * 3] - 128; pDst[3] = pSrc[3 * 3] - 128; + pDst[4] = pSrc[4 * 3] - 128; pDst[5] = pSrc[5 * 3] - 128; pDst[6] = pSrc[6 * 3] - 128; pDst[7] = pSrc[7 * 3] - 128; + } + } + + void jpeg_encoder::load_block_16_8(int x, int c) + { + uint8* pSrc1, * pSrc2; + sample_array_t* pDst = m_sample_array; + x = (x * (16 * 3)) + c; + for (int i = 0; i < 16; i += 2, pDst += 8) + { + pSrc1 = m_mcu_lines[i + 0] + x; + pSrc2 = m_mcu_lines[i + 1] + x; + pDst[0] = ((pSrc1[0 * 3] + pSrc1[1 * 3] + pSrc2[0 * 3] + pSrc2[1 * 3] + 2) >> 2) - 128; pDst[1] = ((pSrc1[2 * 3] + pSrc1[3 * 3] + pSrc2[2 * 3] + pSrc2[3 * 3] + 2) >> 2) - 128; + pDst[2] = ((pSrc1[4 * 3] + pSrc1[5 * 3] + pSrc2[4 * 3] + pSrc2[5 * 3] + 2) >> 2) - 128; pDst[3] = ((pSrc1[6 * 3] + pSrc1[7 * 3] + pSrc2[6 * 3] + pSrc2[7 * 3] + 2) >> 2) - 128; + pDst[4] = ((pSrc1[8 * 3] + pSrc1[9 * 3] + pSrc2[8 * 3] + pSrc2[9 * 3] + 2) >> 2) - 128; pDst[5] = ((pSrc1[10 * 3] + pSrc1[11 * 3] + pSrc2[10 * 3] + pSrc2[11 * 3] + 2) >> 2) - 128; + pDst[6] = ((pSrc1[12 * 3] + pSrc1[13 * 3] + pSrc2[12 * 3] + pSrc2[13 * 3] + 2) >> 2) - 128; pDst[7] = ((pSrc1[14 * 3] + pSrc1[15 * 3] + pSrc2[14 * 3] + pSrc2[15 * 3] + 2) >> 2) - 128; + } + } + + void jpeg_encoder::load_block_16_8_8(int x, int c) + { + uint8* pSrc1; + sample_array_t* pDst = m_sample_array; + x = (x * (16 * 3)) + c; + for (int i = 0; i < 8; i++, pDst += 8) + { + pSrc1 = m_mcu_lines[i + 0] + x; + pDst[0] = ((pSrc1[0 * 3] + pSrc1[1 * 3] + 1) >> 1) - 128; pDst[1] = ((pSrc1[2 * 3] + pSrc1[3 * 3] + 1) >> 1) - 128; + pDst[2] = ((pSrc1[4 * 3] + pSrc1[5 * 3] + 1) >> 1) - 128; pDst[3] = ((pSrc1[6 * 3] + pSrc1[7 * 3] + 1) >> 1) - 128; + pDst[4] = ((pSrc1[8 * 3] + pSrc1[9 * 3] + 1) >> 1) - 128; pDst[5] = ((pSrc1[10 * 3] + pSrc1[11 * 3] + 1) >> 1) - 128; + pDst[6] = ((pSrc1[12 * 3] + pSrc1[13 * 3] + 1) >> 1) - 128; pDst[7] = ((pSrc1[14 * 3] + pSrc1[15 * 3] + 1) >> 1) - 128; + } + } + + void jpeg_encoder::load_quantized_coefficients(int component_num) + { + int32* q = m_quantization_tables[component_num > 0]; + int16* pDst = m_coefficient_array; + for (int i = 0; i < 64; i++) + { + sample_array_t j = m_sample_array[s_zag[i]]; + if (j < 0) + { + if ((j = -j + (*q >> 1)) < *q) + *pDst++ = 0; + else + *pDst++ = static_cast(-(j / *q)); + } + else + { + if ((j = j + (*q >> 1)) < *q) + *pDst++ = 0; + else + *pDst++ = static_cast((j / *q)); + } + q++; + } + } + + void jpeg_encoder::flush_output_buffer() + { + if (m_out_buf_left != JPGE_OUT_BUF_SIZE) + m_all_stream_writes_succeeded = m_all_stream_writes_succeeded && m_pStream->put_buf(m_out_buf, JPGE_OUT_BUF_SIZE - m_out_buf_left); + m_pOut_buf = m_out_buf; + m_out_buf_left = JPGE_OUT_BUF_SIZE; + } + + void jpeg_encoder::put_bits(uint bits, uint len) + { + m_bit_buffer |= ((uint32)bits << (24 - (m_bits_in += len))); + while (m_bits_in >= 8) + { + uint8 c; +#define JPGE_PUT_BYTE(c) { *m_pOut_buf++ = (c); if (--m_out_buf_left == 0) flush_output_buffer(); } + JPGE_PUT_BYTE(c = (uint8)((m_bit_buffer >> 16) & 0xFF)); + if (c == 0xFF) JPGE_PUT_BYTE(0); + m_bit_buffer <<= 8; + m_bits_in -= 8; + } + } + + void jpeg_encoder::code_coefficients_pass_one(int component_num) + { + if (component_num >= 3) return; // just to shut up static analysis + int i, run_len, nbits, temp1; + int16* src = m_coefficient_array; + uint32* dc_count = component_num ? m_huff_count[0 + 1] : m_huff_count[0 + 0], * ac_count = component_num ? m_huff_count[2 + 1] : m_huff_count[2 + 0]; + + temp1 = src[0] - m_last_dc_val[component_num]; + m_last_dc_val[component_num] = src[0]; + if (temp1 < 0) temp1 = -temp1; + + nbits = 0; + while (temp1) + { + nbits++; temp1 >>= 1; + } + + dc_count[nbits]++; + for (run_len = 0, i = 1; i < 64; i++) + { + if ((temp1 = m_coefficient_array[i]) == 0) + run_len++; + else + { + while (run_len >= 16) + { + ac_count[0xF0]++; + run_len -= 16; + } + if (temp1 < 0) temp1 = -temp1; + nbits = 1; + while (temp1 >>= 1) nbits++; + ac_count[(run_len << 4) + nbits]++; + run_len = 0; + } + } + if (run_len) ac_count[0]++; + } + + void jpeg_encoder::code_coefficients_pass_two(int component_num) + { + int i, j, run_len, nbits, temp1, temp2; + int16* pSrc = m_coefficient_array; + uint* codes[2]; + uint8* code_sizes[2]; + + if (component_num == 0) + { + codes[0] = m_huff_codes[0 + 0]; codes[1] = m_huff_codes[2 + 0]; + code_sizes[0] = m_huff_code_sizes[0 + 0]; code_sizes[1] = m_huff_code_sizes[2 + 0]; + } + else + { + codes[0] = m_huff_codes[0 + 1]; codes[1] = m_huff_codes[2 + 1]; + code_sizes[0] = m_huff_code_sizes[0 + 1]; code_sizes[1] = m_huff_code_sizes[2 + 1]; + } + + temp1 = temp2 = pSrc[0] - m_last_dc_val[component_num]; + m_last_dc_val[component_num] = pSrc[0]; + + if (temp1 < 0) + { + temp1 = -temp1; temp2--; + } + + nbits = 0; + while (temp1) + { + nbits++; temp1 >>= 1; + } + + put_bits(codes[0][nbits], code_sizes[0][nbits]); + if (nbits) put_bits(temp2 & ((1 << nbits) - 1), nbits); + + for (run_len = 0, i = 1; i < 64; i++) + { + if ((temp1 = m_coefficient_array[i]) == 0) + run_len++; + else + { + while (run_len >= 16) + { + put_bits(codes[1][0xF0], code_sizes[1][0xF0]); + run_len -= 16; + } + if ((temp2 = temp1) < 0) + { + temp1 = -temp1; + temp2--; + } + nbits = 1; + while (temp1 >>= 1) + nbits++; + j = (run_len << 4) + nbits; + put_bits(codes[1][j], code_sizes[1][j]); + put_bits(temp2 & ((1 << nbits) - 1), nbits); + run_len = 0; + } + } + if (run_len) + put_bits(codes[1][0], code_sizes[1][0]); + } + + void jpeg_encoder::code_block(int component_num) + { + DCT2D(m_sample_array); + load_quantized_coefficients(component_num); + if (m_pass_num == 1) + code_coefficients_pass_one(component_num); + else + code_coefficients_pass_two(component_num); + } + + void jpeg_encoder::process_mcu_row() + { + if (m_num_components == 1) + { + for (int i = 0; i < m_mcus_per_row; i++) + { + load_block_8_8_grey(i); code_block(0); + } + } + else if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 1)) + { + for (int i = 0; i < m_mcus_per_row; i++) + { + load_block_8_8(i, 0, 0); code_block(0); load_block_8_8(i, 0, 1); code_block(1); load_block_8_8(i, 0, 2); code_block(2); + } + } + else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 1)) + { + for (int i = 0; i < m_mcus_per_row; i++) + { + load_block_8_8(i * 2 + 0, 0, 0); code_block(0); load_block_8_8(i * 2 + 1, 0, 0); code_block(0); + load_block_16_8_8(i, 1); code_block(1); load_block_16_8_8(i, 2); code_block(2); + } + } + else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 2)) + { + for (int i = 0; i < m_mcus_per_row; i++) + { + load_block_8_8(i * 2 + 0, 0, 0); code_block(0); load_block_8_8(i * 2 + 1, 0, 0); code_block(0); + load_block_8_8(i * 2 + 0, 1, 0); code_block(0); load_block_8_8(i * 2 + 1, 1, 0); code_block(0); + load_block_16_8(i, 1); code_block(1); load_block_16_8(i, 2); code_block(2); + } + } + } + + bool jpeg_encoder::terminate_pass_one() + { + optimize_huffman_table(0 + 0, DC_LUM_CODES); optimize_huffman_table(2 + 0, AC_LUM_CODES); + if (m_num_components > 1) + { + optimize_huffman_table(0 + 1, DC_CHROMA_CODES); optimize_huffman_table(2 + 1, AC_CHROMA_CODES); + } + return second_pass_init(); + } + + bool jpeg_encoder::terminate_pass_two() + { + put_bits(0x7F, 7); + flush_output_buffer(); + emit_marker(M_EOI); + m_pass_num++; // purposely bump up m_pass_num, for debugging + return true; + } + + bool jpeg_encoder::process_end_of_image() + { + if (m_mcu_y_ofs) + { + if (m_mcu_y_ofs < 16) // check here just to shut up static analysis + { + for (int i = m_mcu_y_ofs; i < m_mcu_y; i++) + memcpy(m_mcu_lines[i], m_mcu_lines[m_mcu_y_ofs - 1], m_image_bpl_mcu); + } + + process_mcu_row(); + } + + if (m_pass_num == 1) + return terminate_pass_one(); + else + return terminate_pass_two(); + } + + void jpeg_encoder::load_mcu(const void* pSrc) + { + const uint8* Psrc = reinterpret_cast(pSrc); + + uint8* pDst = m_mcu_lines[m_mcu_y_ofs]; // OK to write up to m_image_bpl_xlt bytes to pDst + + if (m_num_components == 1) + { + if (m_image_bpp == 4) + RGBA_to_Y(pDst, Psrc, m_image_x); + else if (m_image_bpp == 3) + RGB_to_Y(pDst, Psrc, m_image_x); + else + memcpy(pDst, Psrc, m_image_x); + } + else + { + if (m_image_bpp == 4) + RGBA_to_YCC(pDst, Psrc, m_image_x); + else if (m_image_bpp == 3) + RGB_to_YCC(pDst, Psrc, m_image_x); + else + Y_to_YCC(pDst, Psrc, m_image_x); + } + + // Possibly duplicate pixels at end of scanline if not a multiple of 8 or 16 + if (m_num_components == 1) + memset(m_mcu_lines[m_mcu_y_ofs] + m_image_bpl_xlt, pDst[m_image_bpl_xlt - 1], m_image_x_mcu - m_image_x); + else + { + const uint8 y = pDst[m_image_bpl_xlt - 3 + 0], cb = pDst[m_image_bpl_xlt - 3 + 1], cr = pDst[m_image_bpl_xlt - 3 + 2]; + uint8* q = m_mcu_lines[m_mcu_y_ofs] + m_image_bpl_xlt; + for (int i = m_image_x; i < m_image_x_mcu; i++) + { + *q++ = y; *q++ = cb; *q++ = cr; + } + } + + if (++m_mcu_y_ofs == m_mcu_y) + { + process_mcu_row(); + m_mcu_y_ofs = 0; + } + } + + void jpeg_encoder::clear() + { + m_mcu_lines[0] = NULL; + m_pass_num = 0; + m_all_stream_writes_succeeded = true; + } + + jpeg_encoder::jpeg_encoder() + { + clear(); + } + + jpeg_encoder::~jpeg_encoder() + { + deinit(); + } + + bool jpeg_encoder::init(output_stream* pStream, int width, int height, int src_channels, const params& comp_params) + { + deinit(); + if (((!pStream) || (width < 1) || (height < 1)) || ((src_channels != 1) && (src_channels != 3) && (src_channels != 4)) || (!comp_params.check())) return false; + m_pStream = pStream; + m_params = comp_params; + return jpg_open(width, height, src_channels); + } + + void jpeg_encoder::deinit() + { + jpge_free(m_mcu_lines[0]); + clear(); + } + + bool jpeg_encoder::process_scanline(const void* pScanline) + { + if ((m_pass_num < 1) || (m_pass_num > 2)) return false; + if (m_all_stream_writes_succeeded) + { + if (!pScanline) + { + if (!process_end_of_image()) return false; + } + else + { + load_mcu(pScanline); + } + } + return m_all_stream_writes_succeeded; + } + + // Higher level wrappers/examples (optional). + /* +#include + + class cfile_stream : public output_stream + { + cfile_stream(const cfile_stream&); + cfile_stream& operator= (const cfile_stream&); + + FILE* m_pFile; + bool m_bStatus; + + public: + cfile_stream() : m_pFile(NULL), m_bStatus(false) { } + + virtual ~cfile_stream() + { + close(); + } + + bool open(const char* pFilename) + { + close(); + m_pFile = fopen(pFilename, "wb"); + m_bStatus = (m_pFile != NULL); + return m_bStatus; + } + + bool close() + { + if (m_pFile) + { + if (fclose(m_pFile) == EOF) + { + m_bStatus = false; + } + m_pFile = NULL; + } + return m_bStatus; + } + + virtual bool put_buf(const void* pBuf, int len) + { + m_bStatus = m_bStatus && (fwrite(pBuf, len, 1, m_pFile) == 1); + return m_bStatus; + } + + uint get_size() const + { + return m_pFile ? ftell(m_pFile) : 0; + } + }; + + // Writes JPEG image to file. + bool compress_image_to_jpeg_file(const char* pFilename, int width, int height, int num_channels, const uint8* pImage_data, const params& comp_params) + { + cfile_stream dst_stream; + if (!dst_stream.open(pFilename)) + return false; + + jpge::jpeg_encoder dst_image; + if (!dst_image.init(&dst_stream, width, height, num_channels, comp_params)) + return false; + + for (uint pass_index = 0; pass_index < dst_image.get_total_passes(); pass_index++) + { + for (int i = 0; i < height; i++) + { + const uint8* pBuf = pImage_data + i * width * num_channels; + if (!dst_image.process_scanline(pBuf)) + return false; + } + if (!dst_image.process_scanline(NULL)) + return false; + } + + dst_image.deinit(); + + return dst_stream.close(); + } + */ + + class memory_stream : public output_stream + { + memory_stream(const memory_stream&); + memory_stream& operator= (const memory_stream&); + + uint8* m_pBuf; + uint m_buf_size, m_buf_ofs; + + public: + memory_stream(void* pBuf, uint buf_size) : m_pBuf(static_cast(pBuf)), m_buf_size(buf_size), m_buf_ofs(0) { } + + virtual ~memory_stream() { } + + virtual bool put_buf(const void* pBuf, int len) + { + uint buf_remaining = m_buf_size - m_buf_ofs; + if ((uint)len > buf_remaining) + return false; + memcpy(m_pBuf + m_buf_ofs, pBuf, len); + m_buf_ofs += len; + return true; + } + + uint get_size() const + { + return m_buf_ofs; + } + }; + + bool compress_image_to_jpeg_file_in_memory(void* pDstBuf, int& buf_size, int width, int height, int num_channels, const uint8* pImage_data, const params& comp_params) + { + if ((!pDstBuf) || (!buf_size)) + return false; + + memory_stream dst_stream(pDstBuf, buf_size); + + buf_size = 0; + + jpge::jpeg_encoder dst_image; + if (!dst_image.init(&dst_stream, width, height, num_channels, comp_params)) + return false; + + for (uint pass_index = 0; pass_index < dst_image.get_total_passes(); pass_index++) + { + for (int i = 0; i < height; i++) + { + const uint8* pScanline = pImage_data + i * width * num_channels; + if (!dst_image.process_scanline(pScanline)) + return false; + } + if (!dst_image.process_scanline(NULL)) + return false; + } + + dst_image.deinit(); + + buf_size = dst_stream.get_size(); + return true; + } + +} // namespace jpge diff --git a/modules/godot_remote/godot_remote/jpge.h b/modules/godot_remote/godot_remote/jpge.h new file mode 100644 index 0000000..b98a4a6 --- /dev/null +++ b/modules/godot_remote/godot_remote/jpge.h @@ -0,0 +1,173 @@ +// jpge.h - C++ class for JPEG compression. +// Public Domain or Apache 2.0, Richard Geldreich +// Alex Evans: Added RGBA support, linear memory allocator. +#ifndef JPEG_ENCODER_H +#define JPEG_ENCODER_H + +namespace jpge +{ + typedef unsigned char uint8; + typedef signed short int16; + typedef signed int int32; + typedef unsigned short uint16; + typedef unsigned int uint32; + typedef unsigned int uint; + + // JPEG chroma subsampling factors. Y_ONLY (grayscale images) and H2V2 (color images) are the most common. + enum subsampling_t { Y_ONLY = 0, H1V1 = 1, H2V1 = 2, H2V2 = 3 }; + + // JPEG compression parameters structure. + struct params + { + inline params() : m_quality(85), m_subsampling(H2V2), m_no_chroma_discrim_flag(false), m_two_pass_flag(false), m_use_std_tables(false) { } + + inline bool check() const + { + if ((m_quality < 1) || (m_quality > 100)) return false; + if ((uint)m_subsampling > (uint)H2V2) return false; + return true; + } + + // Quality: 1-100, higher is better. Typical values are around 50-95. + int m_quality; + + // m_subsampling: + // 0 = Y (grayscale) only + // 1 = YCbCr, no subsampling (H1V1, YCbCr 1x1x1, 3 blocks per MCU) + // 2 = YCbCr, H2V1 subsampling (YCbCr 2x1x1, 4 blocks per MCU) + // 3 = YCbCr, H2V2 subsampling (YCbCr 4x1x1, 6 blocks per MCU-- very common) + subsampling_t m_subsampling; + + // Disables CbCr discrimination - only intended for testing. + // If true, the Y quantization table is also used for the CbCr channels. + bool m_no_chroma_discrim_flag; + + bool m_two_pass_flag; + + // By default we use the same quantization tables as mozjpeg's default. + // Set to true to use the traditional tables from JPEG Annex K. + bool m_use_std_tables; + }; + + // Writes JPEG image to a file. + // num_channels must be 1 (Y) or 3 (RGB), image pitch must be width*num_channels. + bool compress_image_to_jpeg_file(const char* pFilename, int width, int height, int num_channels, const uint8* pImage_data, const params& comp_params = params()); + + // Writes JPEG image to memory buffer. + // On entry, buf_size is the size of the output buffer pointed at by pBuf, which should be at least ~1024 bytes. + // If return value is true, buf_size will be set to the size of the compressed data. + bool compress_image_to_jpeg_file_in_memory(void* pBuf, int& buf_size, int width, int height, int num_channels, const uint8* pImage_data, const params& comp_params = params()); + + // Output stream abstract class - used by the jpeg_encoder class to write to the output stream. + // put_buf() is generally called with len==JPGE_OUT_BUF_SIZE bytes, but for headers it'll be called with smaller amounts. + class output_stream + { + public: + virtual ~output_stream() { }; + virtual bool put_buf(const void* Pbuf, int len) = 0; + template inline bool put_obj(const T& obj) { return put_buf(&obj, sizeof(T)); } + }; + + // Lower level jpeg_encoder class - useful if more control is needed than the above helper functions. + class jpeg_encoder + { + public: + jpeg_encoder(); + ~jpeg_encoder(); + + // Initializes the compressor. + // pStream: The stream object to use for writing compressed data. + // params - Compression parameters structure, defined above. + // width, height - Image dimensions. + // channels - May be 1, or 3. 1 indicates grayscale, 3 indicates RGB source data. + // Returns false on out of memory or if a stream write fails. + bool init(output_stream* pStream, int width, int height, int src_channels, const params& comp_params = params()); + + const params& get_params() const { return m_params; } + + // Deinitializes the compressor, freeing any allocated memory. May be called at any time. + void deinit(); + + uint get_total_passes() const { return m_params.m_two_pass_flag ? 2 : 1; } + inline uint get_cur_pass() { return m_pass_num; } + + // Call this method with each source scanline. + // width * src_channels bytes per scanline is expected (RGB or Y format). + // You must call with NULL after all scanlines are processed to finish compression. + // Returns false on out of memory or if a stream write fails. + bool process_scanline(const void* pScanline); + + private: + jpeg_encoder(const jpeg_encoder&); + jpeg_encoder& operator =(const jpeg_encoder&); + + typedef int32 sample_array_t; + + output_stream* m_pStream; + params m_params; + uint8 m_num_components; + uint8 m_comp_h_samp[3], m_comp_v_samp[3]; + int m_image_x, m_image_y, m_image_bpp, m_image_bpl; + int m_image_x_mcu, m_image_y_mcu; + int m_image_bpl_xlt, m_image_bpl_mcu; + int m_mcus_per_row; + int m_mcu_x, m_mcu_y; + uint8* m_mcu_lines[16]; + uint8 m_mcu_y_ofs; + sample_array_t m_sample_array[64]; + int16 m_coefficient_array[64]; + int32 m_quantization_tables[2][64]; + uint m_huff_codes[4][256]; + uint8 m_huff_code_sizes[4][256]; + uint8 m_huff_bits[4][17]; + uint8 m_huff_val[4][256]; + uint32 m_huff_count[4][256]; + int m_last_dc_val[3]; + enum { JPGE_OUT_BUF_SIZE = 2048 }; + uint8 m_out_buf[JPGE_OUT_BUF_SIZE]; + uint8* m_pOut_buf; + uint m_out_buf_left; + uint32 m_bit_buffer; + uint m_bits_in; + uint8 m_pass_num; + bool m_all_stream_writes_succeeded; + + void optimize_huffman_table(int table_num, int table_len); + void emit_byte(uint8 i); + void emit_word(uint i); + void emit_marker(int marker); + void emit_jfif_app0(); + void emit_dqt(); + void emit_sof(); + void emit_dht(uint8* bits, uint8* val, int index, bool ac_flag); + void emit_dhts(); + void emit_sos(); + void emit_markers(); + void compute_huffman_table(uint* codes, uint8* code_sizes, uint8* bits, uint8* val); + void compute_quant_table(int32* dst, int16* src); + void adjust_quant_table(int32* dst, int32* src); + void first_pass_init(); + bool second_pass_init(); + bool jpg_open(int p_x_res, int p_y_res, int src_channels); + void load_block_8_8_grey(int x); + void load_block_8_8(int x, int y, int c); + void load_block_16_8(int x, int c); + void load_block_16_8_8(int x, int c); + void load_quantized_coefficients(int component_num); + void flush_output_buffer(); + void put_bits(uint bits, uint len); + void code_coefficients_pass_one(int component_num); + void code_coefficients_pass_two(int component_num); + void code_block(int component_num); + void process_mcu_row(); + bool terminate_pass_one(); + bool terminate_pass_two(); + bool process_end_of_image(); + void load_mcu(const void* src); + void clear(); + void init(); + }; + +} // namespace jpge + +#endif // JPEG_ENCODER diff --git a/modules/godot_remote/godot_remote/register_types.cpp b/modules/godot_remote/godot_remote/register_types.cpp new file mode 100644 index 0000000..cacd0bc --- /dev/null +++ b/modules/godot_remote/godot_remote/register_types.cpp @@ -0,0 +1,182 @@ +/* register_types.cpp */ + +#include "register_types.h" + +#include "GRClient.h" +#include "GRDevice.h" +#include "GRNotifications.h" +#include "GRPacket.h" +#include "GRServer.h" +#include "GRUtils.h" +#include "GodotRemote.h" + +// clumsy settings to test +// outbound and ip.DstAddr >= 127.0.0.1 and ip.DstAddr <= 127.255.255.255 and (tcp.DstPort == 52341 or tcp.SrcPort == 52341) + +#ifndef GDNATIVE_LIBRARY +#include "core/class_db.h" +#include "core/engine.h" +#include "core/project_settings.h" + +void register_godot_remote_types() { + ClassDB::register_class(); + ClassDB::register_class(); + Engine::get_singleton()->add_singleton(Engine::Singleton("GodotRemote", memnew(GodotRemote))); + //GRUtils::init(); + + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + + ClassDB::register_virtual_class(); + +#ifndef NO_GODOTREMOTE_SERVER + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); +#endif + +#ifndef NO_GODOTREMOTE_CLIENT + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); +#endif + + // Packets + ClassDB::register_virtual_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + + ClassDB::register_class(); + ClassDB::register_class(); + + // Input Data + ClassDB::register_virtual_class(); + ClassDB::register_class(); + ClassDB::register_class(); + + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); +} + +void unregister_godot_remote_types() { + memdelete(GodotRemote::get_singleton()); + GRUtils::deinit(); +} + +#else +#include +#include + +using namespace godot; + +/** GDNative Initialize **/ +extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options * o) { + Godot::gdnative_init(o); +} + +/** GDNative Terminate **/ +extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options * o) { + Godot::gdnative_terminate(o); +} + +/** NativeScript Initialize **/ +extern "C" void GDN_EXPORT godot_nativescript_init(void* handle) { + Godot::nativescript_init(handle); + + register_class(); + register_class(); + //Engine::get_singleton()->add_singleton(Engine::Singleton("GodotRemote", memnew(GodotRemote))); + //GRUtils::init(); // moved to GodotRemote::init() + + register_class(); + register_class(); + register_class(); + register_class(); + + register_class(); + + /////////////////////////////////////// + /////////////////////////////////////// + // must be registered to instantiate + + // Packets + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + + register_class(); + register_class(); + + // Input Data + register_class(); + register_class(); + register_class(); + + register_class(); + register_class(); + register_class(); + + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + + ////////////////////////////////////// + ////////////////////////////////////// + +#ifndef NO_GODOTREMOTE_SERVER + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); +#endif + +#ifndef NO_GODOTREMOTE_CLIENT + register_class(); + register_class(); + register_class(); + register_class(); + register_class(); +#endif + + //register_class(); +} +#endif diff --git a/modules/godot_remote/godot_remote/register_types.h b/modules/godot_remote/godot_remote/register_types.h new file mode 100644 index 0000000..c5ea6fd --- /dev/null +++ b/modules/godot_remote/godot_remote/register_types.h @@ -0,0 +1,4 @@ +/* register_types.h */ + +void register_godot_remote_types(); +void unregister_godot_remote_types(); \ No newline at end of file diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/AndroidAppIcon.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/AndroidAppIcon.png new file mode 100644 index 0000000..89ff80e Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/AndroidAppIcon.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/AndroidAppIcon.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/AndroidAppIcon.png.import new file mode 100644 index 0000000..bac2eea --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/AndroidAppIcon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/AndroidAppIcon.png-674d71a28d7c39d35fe7b76a77d29a54.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/AndroidAppIcon.png" +dest_files=[ "res://.import/AndroidAppIcon.png-674d71a28d7c39d35fe7b76a77d29a54.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/AndroidAppIconBackground.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/AndroidAppIconBackground.png new file mode 100644 index 0000000..a3a8d6e Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/AndroidAppIconBackground.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/AndroidAppIconBackground.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/AndroidAppIconBackground.png.import new file mode 100644 index 0000000..ffdc8b7 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/AndroidAppIconBackground.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/AndroidAppIconBackground.png-bb8807ecf2cf36776bc2487a6c6b3245.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/AndroidAppIconBackground.png" +dest_files=[ "res://.import/AndroidAppIconBackground.png-bb8807ecf2cf36776bc2487a6c6b3245.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Fonts/Roboto-Bold.ttf b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Fonts/Roboto-Bold.ttf new file mode 100644 index 0000000..d3f01ad Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Fonts/Roboto-Bold.ttf differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Fonts/Roboto-Light.ttf b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Fonts/Roboto-Light.ttf new file mode 100644 index 0000000..219063a Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Fonts/Roboto-Light.ttf differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Icon.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Icon.png new file mode 100644 index 0000000..e567815 Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Icon.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Icon.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Icon.png.import new file mode 100644 index 0000000..2ea2311 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Icon.png-f8ab72e53ef6b618ded111693841ae83.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Icon.png" +dest_files=[ "res://.import/Icon.png-f8ab72e53ef6b618ded111693841ae83.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scenes/CustomPopupTextInput.tscn b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scenes/CustomPopupTextInput.tscn new file mode 100644 index 0000000..770efd3 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scenes/CustomPopupTextInput.tscn @@ -0,0 +1,63 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Scripts/CustomPopupTextInput.gd" type="Script" id=1] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Styles/MainTheme.tres" type="Theme" id=2] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Styles/CustomTouchLineEdit.tres" type="StyleBox" id=3] + +[sub_resource type="StyleBoxFlat" id=1] +bg_color = Color( 0.0901961, 0.117647, 0.137255, 0.941176 ) + +[node name="CustomPopupTextInput" type="Panel"] +anchor_right = 1.0 +anchor_bottom = 1.0 +theme = ExtResource( 2 ) +custom_styles/panel = SubResource( 1 ) +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Box" type="VBoxContainer" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 32.0 +margin_top = 32.0 +margin_right = -32.0 +margin_bottom = -32.0 +alignment = 1 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Top" type="Control" parent="Box"] +margin_right = 736.0 +margin_bottom = 316.0 +focus_mode = 2 +size_flags_vertical = 3 + +[node name="Label" type="Label" parent="Box"] +margin_top = 320.0 +margin_right = 736.0 +margin_bottom = 366.0 +text = "TITLE" + +[node name="LineEdit" type="LineEdit" parent="Box" groups=[ +"IgnoreTouchInput", +]] +margin_top = 370.0 +margin_right = 736.0 +margin_bottom = 416.0 +custom_styles/normal = ExtResource( 3 ) +text = "Text" +max_length = 128 +caret_blink = true + +[node name="Bottom" type="Control" parent="Box"] +margin_top = 420.0 +margin_right = 736.0 +margin_bottom = 736.0 +focus_mode = 2 +size_flags_vertical = 3 +[connection signal="focus_exited" from="Box/LineEdit" to="." method="_on_LineEdit_focus_exited"] +[connection signal="text_changed" from="Box/LineEdit" to="." method="_on_LineEdit_text_changed"] +[connection signal="text_entered" from="Box/LineEdit" to="." method="_on_LineEdit_text_entered"] diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scenes/GRSettings.tscn b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scenes/GRSettings.tscn new file mode 100644 index 0000000..3095fce --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scenes/GRSettings.tscn @@ -0,0 +1,845 @@ +[gd_scene load_steps=13 format=2] + +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Styles/MainTheme.tres" type="Theme" id=1] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Styles/NormalSettings.tres" type="DynamicFont" id=2] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Scripts/GRSettings.gd" type="Script" id=3] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Styles/EmptySep.tres" type="StyleBox" id=4] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Styles/VersionFont.tres" type="DynamicFont" id=5] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/ADB_icon.png" type="Texture" id=6] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/WiFi_icon.png" type="Texture" id=7] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon_48px.png" type="Texture" id=8] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Styles/NormalBoldSmaller.tres" type="DynamicFont" id=9] + +[sub_resource type="StyleBoxFlat" id=1] +bg_color = Color( 0.054902, 0.0588235, 0.0627451, 0.243137 ) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color( 0.0862745, 0.0941176, 0.101961, 1 ) + +[sub_resource type="StyleBoxFlat" id=2] +bg_color = Color( 0.219608, 0.247059, 0.266667, 1 ) +draw_center = false +border_width_top = 2 +border_width_bottom = 2 +border_color = Color( 0.219608, 0.247059, 0.266667, 1 ) +shadow_color = Color( 0, 0, 0, 0.572549 ) +shadow_size = 2 + +[sub_resource type="GDScript" id=3] +script/source = "extends PopupMenu + +func _process(_delta: float) -> void: + if get_parent().visible: + if Input.is_key_pressed(KEY_F1) and Input.is_key_pressed(KEY_SHIFT): + popup_centered() +" + +[node name="GRSettings" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_bottom = 1494.0 +grow_horizontal = 0 +grow_vertical = 0 +focus_mode = 2 +theme = ExtResource( 1 ) +script = ExtResource( 3 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Timer" type="Timer" parent="."] +wait_time = 0.25 +one_shot = true + +[node name="Background" type="ColorRect" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +color = Color( 0, 0, 0, 0.698039 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="H" type="HBoxContainer" parent="."] +anchor_right = 1.0 +margin_left = 8.0 +margin_top = 8.0 +margin_right = -8.0 +margin_bottom = 67.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="StartStop" type="Button" parent="H" groups=[ +"buttons_to_disable", +]] +margin_right = 150.0 +margin_bottom = 59.0 +text = "StartStop" +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="VSeparator" type="VSeparator" parent="H"] +margin_left = 154.0 +margin_right = 166.0 +margin_bottom = 59.0 +rect_min_size = Vector2( 12, 0 ) +custom_styles/separator = ExtResource( 4 ) + +[node name="Donations" type="ToolButton" parent="H"] +margin_left = 170.0 +margin_right = 301.0 +margin_bottom = 59.0 +mouse_filter = 1 +size_flags_horizontal = 3 +size_flags_vertical = 5 +custom_fonts/font = ExtResource( 5 ) +custom_colors/font_color = Color( 0.384314, 0.407843, 0.423529, 1 ) +text = "Points: 100" + +[node name="empty" type="Control" parent="H"] +margin_left = 305.0 +margin_right = 437.0 +margin_bottom = 59.0 +mouse_filter = 1 +size_flags_horizontal = 3 +size_flags_vertical = 5 + +[node name="Version" type="ToolButton" parent="H"] +margin_left = 441.0 +margin_right = 634.0 +margin_bottom = 59.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +custom_fonts/font = ExtResource( 5 ) +custom_colors/font_color = Color( 0.384314, 0.407843, 0.423529, 1 ) +text = "GR version: 1.0.14" +align = 2 + +[node name="VSeparator2" type="VSeparator" parent="H"] +margin_left = 638.0 +margin_right = 720.0 +margin_bottom = 59.0 +size_flags_horizontal = 3 +size_flags_stretch_ratio = 0.63 +custom_styles/separator = ExtResource( 4 ) + +[node name="Close" type="Button" parent="H"] +margin_left = 724.0 +margin_right = 783.0 +margin_bottom = 59.0 +grow_horizontal = 0 +grow_vertical = 0 +rect_min_size = Vector2( 59, 59 ) +size_flags_horizontal = 8 +icon = ExtResource( 8 ) +expand_icon = true +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Scroll" type="ScrollContainer" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 20.0 +margin_top = 76.0 +margin_right = -20.0 +margin_bottom = -20.0 +custom_styles/bg = SubResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="H" type="HBoxContainer" parent="Scroll"] +margin_left = 2.0 +margin_top = 2.0 +margin_right = 746.0 +margin_bottom = 2218.0 +grow_horizontal = 0 +grow_vertical = 0 +size_flags_horizontal = 3 + +[node name="Grid" type="GridContainer" parent="Scroll/H"] +margin_right = 732.0 +margin_bottom = 2216.0 +size_flags_horizontal = 3 +custom_constants/vseparation = 24 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="DeviceID" type="VBoxContainer" parent="Scroll/H/Grid"] +margin_right = 732.0 +margin_bottom = 96.0 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Scroll/H/Grid/DeviceID"] +margin_right = 732.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +text = "Device ID" +valign = 1 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="ID" type="LineEdit" parent="Scroll/H/Grid/DeviceID" groups=[ +"nodes_that_should_be_higher", +]] +margin_top = 50.0 +margin_right = 732.0 +margin_bottom = 96.0 +size_flags_horizontal = 3 +text = "ABRACADABRA" +max_length = 128 + +[node name="ConnectionType" type="VBoxContainer" parent="Scroll/H/Grid"] +margin_top = 120.0 +margin_right = 732.0 +margin_bottom = 216.0 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Scroll/H/Grid/ConnectionType"] +margin_right = 732.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +text = "Connection Type" +valign = 1 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Type" type="OptionButton" parent="Scroll/H/Grid/ConnectionType" groups=[ +"nodes_that_should_be_higher", +]] +margin_top = 50.0 +margin_right = 732.0 +margin_bottom = 96.0 +size_flags_horizontal = 3 +text = "WiFi" +icon = ExtResource( 7 ) +align = 1 +items = [ "WiFi", ExtResource( 7 ), false, 1, null, "ADB", ExtResource( 6 ), false, 1, null ] +selected = 0 + +[node name="WiFi" type="VBoxContainer" parent="Scroll/H/Grid"] +margin_top = 240.0 +margin_right = 732.0 +margin_bottom = 336.0 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Scroll/H/Grid/WiFi"] +margin_right = 732.0 +margin_bottom = 46.0 +text = "Server Address" +valign = 1 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Address" type="HBoxContainer" parent="Scroll/H/Grid/WiFi"] +margin_top = 50.0 +margin_right = 732.0 +margin_bottom = 96.0 + +[node name="IP" type="LineEdit" parent="Scroll/H/Grid/WiFi/Address" groups=[ +"nodes_that_should_be_higher", +]] +margin_right = 566.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +custom_fonts/font = ExtResource( 2 ) +text = "255.255.255.255" +align = 1 +max_length = 128 +placeholder_text = "e.g. 192.168.1.1" +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Port" type="SpinBox" parent="Scroll/H/Grid/WiFi/Address" groups=[ +"nodes_that_should_be_higher", +]] +margin_left = 570.0 +margin_right = 732.0 +margin_bottom = 46.0 +rect_min_size = Vector2( 162, 0 ) +max_value = 65535.0 +value = 65535.0 +align = 1 + +[node name="SetWiFiAddress" type="Button" parent="Scroll/H/Grid" groups=[ +"buttons_to_disable", +"nodes_that_should_be_higher", +]] +margin_top = 360.0 +margin_right = 732.0 +margin_bottom = 406.0 +focus_mode = 1 +mouse_filter = 1 +size_flags_horizontal = 3 +size_flags_vertical = 8 +enabled_focus_mode = 1 +text = " Set Type and Address " +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="ADB" type="VBoxContainer" parent="Scroll/H/Grid"] +margin_top = 430.0 +margin_right = 732.0 +margin_bottom = 526.0 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Scroll/H/Grid/ADB"] +margin_right = 732.0 +margin_bottom = 46.0 +text = "Server Port" +valign = 1 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Port" type="SpinBox" parent="Scroll/H/Grid/ADB" groups=[ +"nodes_that_should_be_higher", +]] +margin_top = 50.0 +margin_right = 732.0 +margin_bottom = 96.0 +rect_min_size = Vector2( 128, 0 ) +size_flags_horizontal = 3 +max_value = 65535.0 +value = 65535.0 +align = 1 + +[node name="SetADBPort" type="Button" parent="Scroll/H/Grid" groups=[ +"buttons_to_disable", +"nodes_that_should_be_higher", +]] +margin_top = 550.0 +margin_right = 732.0 +margin_bottom = 596.0 +focus_mode = 1 +mouse_filter = 1 +size_flags_horizontal = 3 +size_flags_vertical = 8 +enabled_focus_mode = 1 +text = " Set Type and Port " +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Empty6" type="HSeparator" parent="Scroll/H/Grid"] +margin_top = 620.0 +margin_right = 732.0 +margin_bottom = 624.0 +mouse_filter = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 +custom_styles/separator = SubResource( 2 ) + +[node name="Empty9" type="Control" parent="Scroll/H/Grid"] +margin_top = 648.0 +margin_right = 732.0 +margin_bottom = 660.0 +rect_min_size = Vector2( 0, 12 ) +mouse_filter = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 + +[node name="OutFps" type="HBoxContainer" parent="Scroll/H/Grid"] +margin_top = 684.0 +margin_right = 732.0 +margin_bottom = 730.0 + +[node name="Label" type="Label" parent="Scroll/H/Grid/OutFps" groups=[ +"nodes_that_should_be_higher", +]] +margin_right = 364.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +text = "Output FPS" +valign = 1 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="FPS" type="SpinBox" parent="Scroll/H/Grid/OutFps" groups=[ +"nodes_that_should_be_higher", +]] +margin_left = 368.0 +margin_right = 732.0 +margin_bottom = 46.0 +rect_min_size = Vector2( 128, 0 ) +size_flags_horizontal = 3 +size_flags_vertical = 5 +min_value = 1.0 +max_value = 1000.0 +value = 60.0 +align = 1 + +[node name="PassRow" type="HBoxContainer" parent="Scroll/H/Grid"] +margin_top = 754.0 +margin_right = 732.0 +margin_bottom = 800.0 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Scroll/H/Grid/PassRow" groups=[ +"nodes_that_should_be_higher", +]] +margin_right = 364.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +text = "Password" +valign = 1 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Pass" type="LineEdit" parent="Scroll/H/Grid/PassRow" groups=[ +"nodes_that_should_be_higher", +]] +margin_left = 368.0 +margin_right = 732.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +text = "asdadfhsd" +max_length = 128 +secret = true +placeholder_text = "Password" + +[node name="Filtering" type="CheckButton" parent="Scroll/H/Grid" groups=[ +"nodes_that_should_be_higher", +]] +margin_top = 824.0 +margin_right = 732.0 +margin_bottom = 872.0 +rect_min_size = Vector2( 128, 0 ) +focus_mode = 1 +mouse_filter = 1 +pressed = true +enabled_focus_mode = 1 +text = "Texture Filtering" + +[node name="StretchMode" type="HBoxContainer" parent="Scroll/H/Grid"] +margin_top = 896.0 +margin_right = 732.0 +margin_bottom = 942.0 + +[node name="Label" type="Label" parent="Scroll/H/Grid/StretchMode" groups=[ +"nodes_that_should_be_higher", +]] +margin_right = 364.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +text = "Stretch Mode" +valign = 1 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Type" type="OptionButton" parent="Scroll/H/Grid/StretchMode" groups=[ +"nodes_that_should_be_higher", +]] +margin_left = 368.0 +margin_right = 732.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +size_flags_vertical = 5 +text = "Keep Aspect" +align = 1 +items = [ "Keep Aspect", null, false, 0, null, "Fill", null, false, 1, null ] +selected = 0 + +[node name="ShowStats" type="HBoxContainer" parent="Scroll/H/Grid"] +margin_top = 966.0 +margin_right = 732.0 +margin_bottom = 1012.0 + +[node name="Label" type="Label" parent="Scroll/H/Grid/ShowStats" groups=[ +"nodes_that_should_be_higher", +]] +margin_right = 364.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +text = "Show Stats" +valign = 1 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Type" type="OptionButton" parent="Scroll/H/Grid/ShowStats" groups=[ +"nodes_that_should_be_higher", +]] +margin_left = 368.0 +margin_right = 732.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +size_flags_vertical = 5 +text = "Hidden" +align = 1 +items = [ "Hidden", null, false, 0, null, "Simple", null, false, 1, null, "Detailed", null, false, 2, null ] +selected = 0 + +[node name="KeepScreen" type="CheckButton" parent="Scroll/H/Grid" groups=[ +"nodes_that_should_be_higher", +]] +margin_top = 1036.0 +margin_right = 732.0 +margin_bottom = 1084.0 +focus_mode = 1 +mouse_filter = 1 +size_flags_vertical = 4 +pressed = true +enabled_focus_mode = 1 +text = "Keep Screen On" +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="CaptureInput" type="CheckButton" parent="Scroll/H/Grid" groups=[ +"nodes_that_should_be_higher", +]] +margin_top = 1108.0 +margin_right = 732.0 +margin_bottom = 1156.0 +focus_mode = 1 +mouse_filter = 1 +size_flags_vertical = 4 +custom_fonts/font = ExtResource( 9 ) +pressed = true +enabled_focus_mode = 1 +text = "Capture pointer when custom scene active" +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="TouchesToOpenSettings" type="HBoxContainer" parent="Scroll/H/Grid"] +margin_top = 1180.0 +margin_right = 732.0 +margin_bottom = 1226.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Label" type="Label" parent="Scroll/H/Grid/TouchesToOpenSettings" groups=[ +"nodes_that_should_be_higher", +]] +margin_top = 4.0 +margin_right = 520.0 +margin_bottom = 41.0 +size_flags_horizontal = 3 +custom_fonts/font = ExtResource( 9 ) +text = "Number of touches to open settings" +valign = 1 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Type" type="OptionButton" parent="Scroll/H/Grid/TouchesToOpenSettings" groups=[ +"nodes_that_should_be_higher", +]] +margin_left = 524.0 +margin_right = 732.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +size_flags_vertical = 5 +size_flags_stretch_ratio = 0.4 +text = "3" +align = 1 +items = [ "3", null, false, 3, null, "4", null, false, 4, null, "5", null, false, 5, null, "6", null, false, 6, null, "7", null, false, 7, null, "8", null, false, 8, null, "9", null, false, 9, null, "10", null, false, 10, null ] +selected = 0 + +[node name="SyncOrientation" type="CheckButton" parent="Scroll/H/Grid" groups=[ +"nodes_that_should_be_higher", +]] +margin_top = 1250.0 +margin_right = 732.0 +margin_bottom = 1298.0 +focus_mode = 1 +mouse_filter = 1 +size_flags_vertical = 4 +pressed = true +enabled_focus_mode = 1 +text = "Sync Viewport Orientation" +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="SyncAspect" type="CheckButton" parent="Scroll/H/Grid" groups=[ +"nodes_that_should_be_higher", +]] +margin_top = 1322.0 +margin_right = 732.0 +margin_bottom = 1370.0 +focus_mode = 1 +mouse_filter = 1 +size_flags_vertical = 4 +pressed = true +enabled_focus_mode = 1 +text = "Sync Viewport Aspect" +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Empty7" type="HSeparator" parent="Scroll/H/Grid"] +margin_top = 1394.0 +margin_right = 732.0 +margin_bottom = 1398.0 +mouse_filter = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 +custom_styles/separator = SubResource( 2 ) + +[node name="Empty10" type="Control" parent="Scroll/H/Grid"] +margin_top = 1422.0 +margin_right = 732.0 +margin_bottom = 1422.0 +mouse_filter = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 + +[node name="OverrideServerSetting" type="CheckButton" parent="Scroll/H/Grid" groups=[ +"nodes_that_should_be_higher", +]] +margin_top = 1446.0 +margin_right = 732.0 +margin_bottom = 1494.0 +focus_mode = 1 +mouse_filter = 1 +pressed = true +enabled_focus_mode = 1 +text = "Override Server Settings" + +[node name="SyncServerSettings" type="CheckButton" parent="Scroll/H/Grid" groups=[ +"nodes_that_should_be_higher", +]] +margin_top = 1518.0 +margin_right = 732.0 +margin_bottom = 1566.0 +focus_mode = 1 +mouse_filter = 1 +enabled_focus_mode = 1 +text = "Sync Server Settings" + +[node name="Empty5" type="HSeparator" parent="Scroll/H/Grid"] +margin_top = 1590.0 +margin_right = 732.0 +margin_bottom = 1594.0 +mouse_filter = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 +custom_styles/separator = SubResource( 2 ) + +[node name="Empty8" type="Control" parent="Scroll/H/Grid"] +margin_top = 1618.0 +margin_right = 732.0 +margin_bottom = 1618.0 +mouse_filter = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 + +[node name="ServerSettings" type="Label" parent="Scroll/H/Grid"] +margin_top = 1642.0 +margin_right = 732.0 +margin_bottom = 1688.0 +size_flags_horizontal = 3 +text = "Server Settings:" +align = 1 +valign = 1 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Empty2" type="Control" parent="Scroll/H/Grid"] +margin_top = 1712.0 +margin_right = 732.0 +margin_bottom = 1712.0 +mouse_filter = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 + +[node name="VideoStream" type="CheckButton" parent="Scroll/H/Grid" groups=[ +"nodes_that_should_be_higher", +]] +margin_top = 1736.0 +margin_right = 732.0 +margin_bottom = 1784.0 +focus_mode = 1 +mouse_filter = 1 +pressed = true +enabled_focus_mode = 1 +text = "Video Stream" +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Empty4" type="Control" parent="Scroll/H/Grid"] +margin_top = 1808.0 +margin_right = 732.0 +margin_bottom = 1808.0 +mouse_filter = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 + +[node name="JPG_Quality" type="VBoxContainer" parent="Scroll/H/Grid"] +margin_top = 1832.0 +margin_right = 732.0 +margin_bottom = 1930.0 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Scroll/H/Grid/JPG_Quality"] +margin_right = 732.0 +margin_bottom = 46.0 +text = "JPG Quality" +valign = 1 + +[node name="Quality" type="HSlider" parent="Scroll/H/Grid/JPG_Quality" groups=[ +"nodes_that_should_be_higher", +]] +margin_top = 50.0 +margin_right = 732.0 +margin_bottom = 98.0 +rect_min_size = Vector2( 0, 32 ) +size_flags_horizontal = 3 +min_value = 1.0 +value = 50.0 +tick_count = 5 + +[node name="RenderScale" type="VBoxContainer" parent="Scroll/H/Grid"] +margin_top = 1954.0 +margin_right = 732.0 +margin_bottom = 2052.0 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Scroll/H/Grid/RenderScale"] +margin_right = 732.0 +margin_bottom = 46.0 +text = "Render Scale" +valign = 1 + +[node name="Scale" type="HSlider" parent="Scroll/H/Grid/RenderScale" groups=[ +"nodes_that_should_be_higher", +]] +margin_top = 50.0 +margin_right = 732.0 +margin_bottom = 98.0 +rect_min_size = Vector2( 0, 32 ) +size_flags_horizontal = 3 +min_value = 0.05 +max_value = 1.0 +step = 0.01 +value = 0.53 +tick_count = 5 + +[node name="HBoxContainer" type="HBoxContainer" parent="Scroll/H/Grid"] +margin_top = 2076.0 +margin_right = 732.0 +margin_bottom = 2122.0 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Scroll/H/Grid/HBoxContainer" groups=[ +"nodes_that_should_be_higher", +]] +margin_right = 364.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +text = "Skip Frames" +valign = 1 + +[node name="SKIP" type="SpinBox" parent="Scroll/H/Grid/HBoxContainer" groups=[ +"nodes_that_should_be_higher", +]] +margin_left = 368.0 +margin_right = 732.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +size_flags_vertical = 5 +max_value = 1000.0 +align = 1 + +[node name="HBoxContainer2" type="HBoxContainer" parent="Scroll/H/Grid"] +margin_top = 2146.0 +margin_right = 732.0 +margin_bottom = 2192.0 +size_flags_horizontal = 3 + +[node name="Label" type="Label" parent="Scroll/H/Grid/HBoxContainer2" groups=[ +"nodes_that_should_be_higher", +]] +margin_right = 364.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +text = "Compression" + +[node name="State2" type="OptionButton" parent="Scroll/H/Grid/HBoxContainer2" groups=[ +"nodes_that_should_be_higher", +]] +margin_left = 368.0 +margin_right = 732.0 +margin_bottom = 46.0 +rect_min_size = Vector2( 0, 32 ) +size_flags_horizontal = 3 +text = "JPG" +align = 1 +items = [ "Uncompressed", null, false, 0, null, "JPG", null, false, 1, null, "PNG", null, false, 2, null ] +selected = 1 + +[node name="Empty3" type="Control" parent="Scroll/H/Grid"] +margin_top = 2216.0 +margin_right = 732.0 +margin_bottom = 2216.0 +mouse_filter = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 + +[node name="VSeparator" type="VSeparator" parent="Scroll/H"] +margin_left = 736.0 +margin_right = 744.0 +margin_bottom = 2216.0 +rect_min_size = Vector2( 8, 0 ) +custom_styles/separator = ExtResource( 4 ) + +[node name="LogLevelPopupMenu" type="PopupMenu" parent="."] +margin_left = -161.635 +margin_top = 6.73477 +margin_right = -9.63458 +margin_bottom = 275.735 +items = [ "Log Level", null, 0, false, true, -1, 0, null, "", false, "Debug", null, 0, false, false, 0, 0, null, "", false, "Normal", null, 0, false, false, 1, 0, null, "", false, "Warning", null, 0, false, false, 2, 0, null, "", false, "Error", null, 0, false, false, 3, 0, null, "", false, "None", null, 0, false, false, 4, 0, null, "", false ] +script = SubResource( 3 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[connection signal="resized" from="." to="." method="_on_GRSettings_resized"] +[connection signal="visibility_changed" from="." to="." method="_on_GRSettings_visibility_changed"] +[connection signal="timeout" from="Timer" to="." method="_on_button_disable_Timer_timeout"] +[connection signal="pressed" from="H/StartStop" to="." method="_on_StartStop_pressed"] +[connection signal="pressed" from="H/Donations" to="." method="_on_Donations_pressed"] +[connection signal="pressed" from="H/Version" to="." method="_on_Version_pressed"] +[connection signal="pressed" from="H/Close" to="." method="_on_Close_pressed"] +[connection signal="text_changed" from="Scroll/H/Grid/DeviceID/ID" to="." method="_on_Device_ID_text_changed"] +[connection signal="item_selected" from="Scroll/H/Grid/ConnectionType/Type" to="." method="_on_con_Type_item_selected"] +[connection signal="text_entered" from="Scroll/H/Grid/WiFi/Address/IP" to="." method="_on_wifi_IP_text_entered"] +[connection signal="pressed" from="Scroll/H/Grid/SetWiFiAddress" to="." method="_on_wifi_SetAddress_pressed"] +[connection signal="pressed" from="Scroll/H/Grid/SetADBPort" to="." method="_on_adb_SetAddress_pressed"] +[connection signal="value_changed" from="Scroll/H/Grid/OutFps/FPS" to="." method="_on_FPS_value_changed"] +[connection signal="text_changed" from="Scroll/H/Grid/PassRow/Pass" to="." method="_on_Password_text_changed"] +[connection signal="toggled" from="Scroll/H/Grid/Filtering" to="." method="_on_texture_Filtering_toggled"] +[connection signal="item_selected" from="Scroll/H/Grid/StretchMode/Type" to="." method="_on_stretch_Type_item_selected"] +[connection signal="item_selected" from="Scroll/H/Grid/ShowStats/Type" to="." method="_on_stats_State_selected_id"] +[connection signal="toggled" from="Scroll/H/Grid/KeepScreen" to="." method="_on_keep_screen_CheckButton_toggled"] +[connection signal="toggled" from="Scroll/H/Grid/CaptureInput" to="." method="_on_CaptureInput_toggled"] +[connection signal="item_selected" from="Scroll/H/Grid/TouchesToOpenSettings/Type" to="." method="_on_touches_to_open_item_selected"] +[connection signal="toggled" from="Scroll/H/Grid/SyncOrientation" to="." method="_on_SyncOrientation_toggled"] +[connection signal="toggled" from="Scroll/H/Grid/SyncAspect" to="." method="_on_SyncAspect_toggled"] +[connection signal="toggled" from="Scroll/H/Grid/OverrideServerSetting" to="." method="_on_override_settings_State_toggled"] +[connection signal="toggled" from="Scroll/H/Grid/SyncServerSettings" to="." method="_on_SyncServerSettings_toggled"] +[connection signal="toggled" from="Scroll/H/Grid/VideoStream" to="." method="_on_video_stream_Enabled_toggled"] +[connection signal="value_changed" from="Scroll/H/Grid/JPG_Quality/Quality" to="." method="_on_server_Quality_value_changed"] +[connection signal="value_changed" from="Scroll/H/Grid/RenderScale/Scale" to="." method="_on_server_render_Scale_value_changed"] +[connection signal="value_changed" from="Scroll/H/Grid/HBoxContainer/SKIP" to="." method="_on_server_send_FPS_value_changed"] +[connection signal="item_selected" from="Scroll/H/Grid/HBoxContainer2/State2" to="." method="_on_compression_type_item_selected"] +[connection signal="id_pressed" from="LogLevelPopupMenu" to="." method="_on_LogLevelPopupMenu_id_pressed"] diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scenes/GRStats.tscn b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scenes/GRStats.tscn new file mode 100644 index 0000000..39827be --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scenes/GRStats.tscn @@ -0,0 +1,86 @@ +[gd_scene load_steps=6 format=2] + +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Fonts/Roboto-Bold.ttf" type="DynamicFontData" id=1] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Scripts/GRStats.gd" type="Script" id=2] + +[sub_resource type="DynamicFont" id=1] +size = 20 +outline_size = 1 +outline_color = Color( 0, 0, 0, 1 ) +use_filter = true +extra_spacing_top = -1 +extra_spacing_bottom = -1 +font_data = ExtResource( 1 ) + +[sub_resource type="Theme" id=2] +default_font = SubResource( 1 ) + +[sub_resource type="StyleBoxFlat" id=3] +content_margin_left = 2.0 +bg_color = Color( 0, 0, 0, 0.34902 ) +corner_detail = 1 + +[node name="GRStats" type="PanelContainer"] +margin_right = 151.0 +margin_bottom = 44.0 +mouse_filter = 2 +theme = SubResource( 2 ) +custom_styles/panel = SubResource( 3 ) +script = ExtResource( 2 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Grid" type="GridContainer" parent="."] +margin_left = 2.0 +margin_right = 151.0 +margin_bottom = 44.0 +mouse_filter = 2 +size_flags_horizontal = 0 +size_flags_vertical = 0 +custom_constants/vseparation = 0 +custom_constants/hseparation = 4 +columns = 3 + +[node name="FPS" type="Label" parent="Grid"] +margin_right = 86.0 +margin_bottom = 22.0 +size_flags_vertical = 1 +text = "FPS:231" + +[node name="FPS_min" type="Label" parent="Grid"] +margin_left = 90.0 +margin_right = 112.0 +margin_bottom = 22.0 +size_flags_vertical = 1 +text = "21" + +[node name="FPS_max" type="Label" parent="Grid"] +margin_left = 116.0 +margin_right = 149.0 +margin_bottom = 22.0 +size_flags_vertical = 1 +text = "124" + +[node name="Ping" type="Label" parent="Grid"] +margin_top = 22.0 +margin_right = 86.0 +margin_bottom = 44.0 +size_flags_vertical = 1 +text = "PING:321" + +[node name="Ping_min" type="Label" parent="Grid"] +margin_left = 90.0 +margin_top = 22.0 +margin_right = 112.0 +margin_bottom = 44.0 +size_flags_vertical = 1 +text = "12" + +[node name="Ping_max" type="Label" parent="Grid"] +margin_left = 116.0 +margin_top = 22.0 +margin_right = 149.0 +margin_bottom = 44.0 +size_flags_vertical = 1 +text = "333" diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scenes/GUI.tscn b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scenes/GUI.tscn new file mode 100644 index 0000000..537f9e3 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scenes/GUI.tscn @@ -0,0 +1,395 @@ +[gd_scene load_steps=15 format=2] + +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Scripts/GodotRemoteClient.gd" type="Script" id=1] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Styles/NormalLight.tres" type="DynamicFont" id=2] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Scenes/GRStats.tscn" type="PackedScene" id=3] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Styles/MainTheme.tres" type="Theme" id=4] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/tap_screen.png" type="Texture" id=5] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Scenes/GRSettings.tscn" type="PackedScene" id=6] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Scenes/CustomPopupTextInput.tscn" type="PackedScene" id=7] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Scripts/PlsRatePopup.gd" type="Script" id=8] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Scripts/PlsSupportPopup.gd" type="Script" id=9] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Scripts/Changelog.gd" type="Script" id=10] + +[sub_resource type="StyleBoxFlat" id=1] +bg_color = Color( 0.133333, 0.164706, 0.188235, 0.815686 ) +border_width_left = 4 +border_width_top = 4 +border_width_right = 4 +border_width_bottom = 4 +border_color = Color( 0.0901961, 0.109804, 0.12549, 0.847059 ) +corner_detail = 1 + +[sub_resource type="Theme" id=2] +default_font = ExtResource( 2 ) + +[sub_resource type="GDScript" id=3] +script/source = "extends Button + +func _pressed() -> void: + OS.shell_open(\"https://github.com/DmitriySalnikov/GodotRemote#godot-remote\") +" + +[sub_resource type="GDScript" id=4] +script/source = "extends Button + +func _pressed() -> void: + get_parent().get_parent().hide() +" + +[node name="GodotRemote" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +mouse_filter = 2 +theme = ExtResource( 4 ) +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="BackgroundTouchHint" type="Control" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +mouse_filter = 2 +__meta__ = { +"_edit_lock_": true, +"_edit_use_anchors_": false +} + +[node name="Panel" type="Panel" parent="BackgroundTouchHint"] +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 0 +grow_vertical = 0 +mouse_filter = 2 +custom_styles/panel = SubResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="TextureRect" type="TextureRect" parent="BackgroundTouchHint/Panel"] +self_modulate = Color( 0.921569, 0.921569, 0.921569, 1 ) +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 33.0 +margin_top = 33.0 +margin_right = -33.0 +margin_bottom = -33.0 +grow_horizontal = 0 +grow_vertical = 0 +texture = ExtResource( 5 ) +stretch_mode = 4 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Stream" type="Control" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 0 +grow_vertical = 0 +focus_mode = 2 +mouse_filter = 1 +theme = SubResource( 2 ) +__meta__ = { +"_edit_lock_": true, +"_edit_use_anchors_": false +} + +[node name="Stats" type="Control" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +mouse_filter = 2 +__meta__ = { +"_edit_lock_": true, +"_edit_use_anchors_": false +} + +[node name="GRStats" parent="Stats" instance=ExtResource( 3 )] +margin_right = 96.0 +margin_bottom = 64.0 + +[node name="GRSettings" parent="." instance=ExtResource( 6 )] +visible = false +margin_bottom = 0.0 + +[node name="CustomPopupTextInput" parent="." instance=ExtResource( 7 )] +visible = false + +[node name="PlsSupportPopup" type="WindowDialog" parent="."] +visible = true +margin_left = -838.665 +margin_top = 424.185 +margin_right = -138.665 +margin_bottom = 559.185 +rect_min_size = Vector2( 500, 135 ) +window_title = "Do you like this app?" +script = ExtResource( 9 ) +__meta__ = { +"_edit_lock_": true, +"_edit_use_anchors_": false +} + +[node name="HBoxContainer" type="VBoxContainer" parent="PlsSupportPopup"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 16.0 +margin_top = 16.0 +margin_right = -16.0 +margin_bottom = -16.0 +__meta__ = { +"_edit_lock_": true, +"_edit_use_anchors_": false +} + +[node name="Label" type="Label" parent="PlsSupportPopup/HBoxContainer"] +margin_top = 1.0 +margin_right = 668.0 +margin_bottom = 47.0 +size_flags_vertical = 6 +text = "Please support the developer" +align = 1 +valign = 1 + +[node name="Control" type="Control" parent="PlsSupportPopup/HBoxContainer"] +margin_top = 53.0 +margin_right = 668.0 +margin_bottom = 53.0 + +[node name="HBoxContainer" type="HBoxContainer" parent="PlsSupportPopup/HBoxContainer"] +margin_top = 57.0 +margin_right = 668.0 +margin_bottom = 103.0 + +[node name="Button" type="Button" parent="PlsSupportPopup/HBoxContainer/HBoxContainer"] +margin_right = 332.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +text = "Support" + +[node name="Button2" type="Button" parent="PlsSupportPopup/HBoxContainer/HBoxContainer"] +margin_left = 336.0 +margin_right = 668.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +text = "Not now" + +[node name="Changelog" type="PopupPanel" parent="."] +visible = true +margin_left = -1562.0 +margin_top = 101.0 +margin_right = -873.0 +margin_bottom = 641.0 +rect_min_size = Vector2( 500, 540 ) +popup_exclusive = true +script = ExtResource( 10 ) +__meta__ = { +"_edit_lock_": true +} + +[node name="HBoxContainer" type="VBoxContainer" parent="Changelog"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 16.0 +margin_top = 16.0 +margin_right = -16.0 +margin_bottom = -16.0 +__meta__ = { +"_edit_lock_": true, +"_edit_use_anchors_": false +} + +[node name="Label" type="Label" parent="Changelog/HBoxContainer"] +margin_right = 657.0 +margin_bottom = 46.0 +text = "Godot Remote Updated" +align = 1 + +[node name="Control" type="ScrollContainer" parent="Changelog/HBoxContainer"] +margin_top = 50.0 +margin_right = 657.0 +margin_bottom = 458.0 +size_flags_vertical = 3 + +[node name="ListOfChanges" type="Label" parent="Changelog/HBoxContainer/Control"] +margin_right = 657.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +size_flags_vertical = 1 +custom_fonts/font = ExtResource( 2 ) +text = " don't forget to write a changelog..." +autowrap = true + +[node name="HBoxContainer" type="HBoxContainer" parent="Changelog/HBoxContainer"] +margin_top = 462.0 +margin_right = 657.0 +margin_bottom = 508.0 + +[node name="Button" type="Button" parent="Changelog/HBoxContainer/HBoxContainer"] +margin_right = 240.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +text = "Okay, I get it!" + +[node name="Button2" type="Button" parent="Changelog/HBoxContainer/HBoxContainer"] +margin_left = 244.0 +margin_right = 657.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +text = "How do I update the server?" + +[node name="PlsRatePopup" type="WindowDialog" parent="."] +visible = true +margin_left = -839.331 +margin_top = 100.887 +margin_right = -141.331 +margin_bottom = 362.887 +rect_min_size = Vector2( 500, 135 ) +popup_exclusive = true +window_title = "Rate This App" +script = ExtResource( 8 ) +__meta__ = { +"_edit_lock_": true, +"_edit_use_anchors_": false +} + +[node name="HBoxContainer" type="VBoxContainer" parent="PlsRatePopup"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 16.0 +margin_top = 16.0 +margin_right = -16.0 +margin_bottom = -16.0 +__meta__ = { +"_edit_lock_": true, +"_edit_use_anchors_": false +} + +[node name="Label" type="Label" parent="PlsRatePopup/HBoxContainer"] +margin_top = 65.0 +margin_right = 666.0 +margin_bottom = 111.0 +size_flags_vertical = 6 +text = "Do you want to rate this app?" +align = 1 +valign = 1 + +[node name="Control" type="Control" parent="PlsRatePopup/HBoxContainer"] +margin_top = 180.0 +margin_right = 666.0 +margin_bottom = 180.0 + +[node name="HBoxContainer" type="HBoxContainer" parent="PlsRatePopup/HBoxContainer"] +margin_top = 184.0 +margin_right = 666.0 +margin_bottom = 230.0 + +[node name="yes" type="Button" parent="PlsRatePopup/HBoxContainer/HBoxContainer"] +margin_right = 219.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +text = "Yes" + +[node name="no" type="Button" parent="PlsRatePopup/HBoxContainer/HBoxContainer"] +margin_left = 223.0 +margin_right = 442.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +text = "No, thanks" + +[node name="later" type="Button" parent="PlsRatePopup/HBoxContainer/HBoxContainer"] +margin_left = 446.0 +margin_right = 666.0 +margin_bottom = 46.0 +size_flags_horizontal = 3 +text = "Not now" + +[node name="FirstLaunchHint" type="PopupPanel" parent="."] +visible = true +margin_left = -1558.0 +margin_top = 699.0 +margin_right = -430.0 +margin_bottom = 1368.0 +rect_min_size = Vector2( 700, 503 ) +popup_exclusive = true +__meta__ = { +"_edit_lock_": true +} + +[node name="VBox" type="VBoxContainer" parent="FirstLaunchHint"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 8.0 +margin_top = 8.0 +margin_right = -8.0 +margin_bottom = -8.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Label" type="Label" parent="FirstLaunchHint/VBox"] +margin_right = 1112.0 +margin_bottom = 46.0 +grow_horizontal = 0 +grow_vertical = 0 +text = "Welcome" +align = 1 +valign = 1 +autowrap = true +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Label3" type="Label" parent="FirstLaunchHint/VBox"] +margin_top = 110.0 +margin_right = 1112.0 +margin_bottom = 238.0 +grow_horizontal = 0 +grow_vertical = 0 +size_flags_vertical = 6 +text = "THIS IS NOT A GAME! +Godot Remote gives you ability to control your Godot Engine projects remotely over WiFi or USB." +align = 1 +valign = 1 +autowrap = true +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Button" type="Button" parent="FirstLaunchHint/VBox"] +margin_top = 303.0 +margin_right = 1112.0 +margin_bottom = 349.0 +text = "Open the documentation page" +script = SubResource( 3 ) + +[node name="Label2" type="Label" parent="FirstLaunchHint/VBox"] +margin_top = 434.0 +margin_right = 1112.0 +margin_bottom = 521.0 +grow_horizontal = 0 +grow_vertical = 0 +size_flags_vertical = 6 +text = "To reopen this screen, click on the 'Godot Remote' version in settings. +To open app settings touch the screen with %d fingers at once." +align = 1 +valign = 1 +autowrap = true +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Button2" type="Button" parent="FirstLaunchHint/VBox"] +margin_top = 607.0 +margin_right = 1112.0 +margin_bottom = 653.0 +text = "Okay, I get it!" +script = SubResource( 4 ) + +[connection signal="pressed" from="PlsSupportPopup/HBoxContainer/HBoxContainer/Button" to="PlsSupportPopup" method="_on_Button_pressed"] +[connection signal="pressed" from="PlsSupportPopup/HBoxContainer/HBoxContainer/Button2" to="PlsSupportPopup" method="_on_Button2_pressed"] +[connection signal="pressed" from="Changelog/HBoxContainer/HBoxContainer/Button" to="Changelog" method="_on_Button_pressed"] +[connection signal="pressed" from="Changelog/HBoxContainer/HBoxContainer/Button2" to="Changelog" method="_on_Button2_pressed"] +[connection signal="pressed" from="PlsRatePopup/HBoxContainer/HBoxContainer/yes" to="PlsRatePopup" method="_on_yes_pressed"] +[connection signal="pressed" from="PlsRatePopup/HBoxContainer/HBoxContainer/no" to="PlsRatePopup" method="_on_no_pressed"] +[connection signal="pressed" from="PlsRatePopup/HBoxContainer/HBoxContainer/later" to="PlsRatePopup" method="_on_later_pressed"] diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/Changelog.gd b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/Changelog.gd new file mode 100644 index 0000000..255d676 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/Changelog.gd @@ -0,0 +1,68 @@ +extends PopupPanel + +var changelog : Dictionary = { +"1.0.2.0" : +"""Client: +Added detailed ping and fps stats. +Added the ability to change the number of touches to open the settings. +Changed the 'Welcome' screen to be more clear. Now it can be reopened by clicking on 'Godot Remote' version in the settings. +Module: +Fixed multithreading issues. +Improved fps and ping counters. +Most enums have been renamed and moved. +Exposed all classes in GDScript, but did not expose their methods. +Custom input scenes now adding '.md5' files from '.import' folder. +""", +} + +func _ready() -> void: + if G.VersionChanged: + var text = "Current version: %s\nPrevious version: %s\n\n" % [G.get_version(), G.PreviousVersion] + + var prev = _get_version_sum(G.PreviousVersion.split(".")) + var curr = _get_version_sum(G.get_version().split(".")) + + if curr < prev: + return + + var found_logs = false + for k in changelog.keys(): + var v = _get_version_sum(k.split(".")) + if v > prev and v <= curr: + text += "[%s]\n%s\n" % [k, changelog[k]] + found_logs = true + + if not found_logs: + text += "No changes were found between these versions." + + $HBoxContainer/Control/ListOfChanges.text = text + $HBoxContainer/HBoxContainer/Button2.visible = _check_need_update_server(G.PreviousVersion, G.get_version()) + call_deferred("popup_centered_ratio", 1) + get_parent().connect("item_rect_changed", self, "viewport_size_changed") + +func viewport_size_changed() -> void: + if visible: + rect_size = get_viewport_rect().size + +func _get_version_sum(v : PoolStringArray) -> int: + var major = int(v[0]) << 32 + var minor = int(v[1]) << 24 + var patch = int(v[2]) << 16 + # 16 bits for mobile versions will be enough + var mobile = 0 + if(v.size() > 3): + mobile = int(v[3]) + + return major + minor + patch + mobile + +func _check_need_update_server(prev : String, current : String) -> bool: + var p = prev.split(".") + var c = current.split(".") + return int(p[0]) != int(c[0]) || int(p[1]) != int(c[1]) + +func _on_Button_pressed() -> void: + hide() + +func _on_Button2_pressed() -> void: + OS.shell_open("https://github.com/DmitriySalnikov/GodotRemote#download") + hide() diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/Constants.gd b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/Constants.gd new file mode 100644 index 0000000..873c87f --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/Constants.gd @@ -0,0 +1,183 @@ +extends Node + +var GodotRemote_DEVICE_AUTO : int +var GodotRemote_DEVICE_SERVER : int +var GodotRemote_DEVICE_CLIENT : int + +var GodotRemote_LL_NONE : int +var GodotRemote_LL_DEBUG : int +var GodotRemote_LL_NORMAL : int +var GodotRemote_LL_WARNING : int +var GodotRemote_LL_ERROR : int + +var GRNotifications_NOTIFICATION_ICON_NONE : int +var GRNotifications_NOTIFICATION_ICON_ERROR : int +var GRNotifications_NOTIFICATION_ICON_WARNING : int +var GRNotifications_NOTIFICATION_ICON_SUCCESS : int +var GRNotifications_NOTIFICATION_ICON_FAIL : int + +var GRNotifications_NOTIFICATIONS_POSITION_TOP_LEFT : int +var GRNotifications_NOTIFICATIONS_POSITION_TOP_CENTER : int +var GRNotifications_NOTIFICATIONS_POSITION_TOP_RIGHT : int +var GRNotifications_NOTIFICATIONS_POSITION_BOTTOM_LEFT : int +var GRNotifications_NOTIFICATIONS_POSITION_BOTTOM_CENTER : int +var GRNotifications_NOTIFICATIONS_POSITION_BOTTOM_RIGHT : int + +var GRInputData_InputTypeNone : int +var GRInputData_InputDeviceSensors : int +var GRInputData_InputEvent : int +var GRInputData_InputEventAction : int +var GRInputData_InputEventGesture : int +var GRInputData_InputEventJoypadButton : int +var GRInputData_InputEventJoypadMotion : int +var GRInputData_InputEventKey : int +var GRInputData_InputEventMagnifyGesture : int +var GRInputData_InputEventMIDI : int +var GRInputData_InputEventMouse : int +var GRInputData_InputEventMouseButton : int +var GRInputData_InputEventMouseMotion : int +var GRInputData_InputEventPanGesture : int +var GRInputData_InputEventScreenDrag : int +var GRInputData_InputEventScreenTouch : int +var GRInputData_InputEventWithModifiers : int +var GRInputData_InputEventMAX : int + +var GRPacket_NonePacket : int +var GRPacket_SyncTime : int +var GRPacket_ImageData : int +var GRPacket_InputData : int +var GRPacket_ServerSettings : int +var GRPacket_MouseModeSync : int +var GRPacket_CustomInputScene : int +var GRPacket_ClientStreamOrientation : int +var GRPacket_ClientStreamAspect : int +var GRPacket_CustomUserData : int +var GRPacket_Ping : int +var GRPacket_Pong : int + +var GRDevice_STATUS_STARTING : int +var GRDevice_STATUS_STOPPING : int +var GRDevice_STATUS_WORKING : int +var GRDevice_STATUS_STOPPED : int + +var GRDevice_SS_Y_ONLY : int +var GRDevice_SS_H1V1 : int +var GRDevice_SS_H2V1 : int +var GRDevice_SS_H2V2 : int + +var GRDevice_USE_INTERNAL_SERVER_SETTINGS : int +var GRDevice_SERVER_PARAM_VIDEO_STREAM_ENABLED : int +var GRDevice_SERVER_PARAM_COMPRESSION_TYPE : int +var GRDevice_SERVER_PARAM_JPG_QUALITY : int +var GRDevice_SERVER_PARAM_SKIP_FRAMES : int +var GRDevice_SERVER_PARAM_RENDER_SCALE : int + +var GRDevice_IMAGE_COMPRESSION_UNCOMPRESSED : int +var GRDevice_IMAGE_COMPRESSION_JPG : int +var GRDevice_IMAGE_COMPRESSION_PNG : int + +var GRClient_CONNECTION_ADB : int +var GRClient_CONNECTION_WiFi : int + +var GRClient_STRETCH_KEEP_ASPECT : int +var GRClient_STRETCH_FILL : int + +var GRClient_STREAM_NO_SIGNAL : int +var GRClient_STREAM_ACTIVE : int +var GRClient_STREAM_NO_IMAGE : int + +func _enter_tree() -> void: + _setup_constants() + +func _setup_constants(): + GodotRemote_DEVICE_AUTO = get_enum_constant("GodotRemote", "DeviceType", "DEVICE_AUTO"); + GodotRemote_DEVICE_SERVER = get_enum_constant("GodotRemote", "DeviceType", "DEVICE_SERVER"); + GodotRemote_DEVICE_CLIENT = get_enum_constant("GodotRemote", "DeviceType", "DEVICE_CLIENT"); + + GodotRemote_LL_NONE = get_enum_constant("GodotRemote", "LogLevel", "LL_NONE"); + GodotRemote_LL_DEBUG = get_enum_constant("GodotRemote", "LogLevel", "LL_DEBUG"); + GodotRemote_LL_NORMAL = get_enum_constant("GodotRemote", "LogLevel", "LL_NORMAL"); + GodotRemote_LL_WARNING = get_enum_constant("GodotRemote", "LogLevel", "LL_WARNING"); + GodotRemote_LL_ERROR = get_enum_constant("GodotRemote", "LogLevel", "LL_ERROR"); + + GRNotifications_NOTIFICATION_ICON_NONE = get_enum_constant("GRNotifications", "NotificationIcon", "ICON_NONE"); + GRNotifications_NOTIFICATION_ICON_ERROR = get_enum_constant("GRNotifications", "NotificationIcon", "ICON_ERROR"); + GRNotifications_NOTIFICATION_ICON_WARNING = get_enum_constant("GRNotifications", "NotificationIcon", "ICON_WARNING"); + GRNotifications_NOTIFICATION_ICON_SUCCESS = get_enum_constant("GRNotifications", "NotificationIcon", "ICON_SUCCESS"); + GRNotifications_NOTIFICATION_ICON_FAIL = get_enum_constant("GRNotifications", "NotificationIcon", "ICON_FAIL"); + + GRNotifications_NOTIFICATIONS_POSITION_TOP_LEFT = get_enum_constant("GRNotifications", "NotificationsPosition", "TOP_LEFT"); + GRNotifications_NOTIFICATIONS_POSITION_TOP_CENTER = get_enum_constant("GRNotifications", "NotificationsPosition", "TOP_CENTER"); + GRNotifications_NOTIFICATIONS_POSITION_TOP_RIGHT = get_enum_constant("GRNotifications", "NotificationsPosition", "TOP_RIGHT"); + GRNotifications_NOTIFICATIONS_POSITION_BOTTOM_LEFT = get_enum_constant("GRNotifications", "NotificationsPosition", "BOTTOM_LEFT"); + GRNotifications_NOTIFICATIONS_POSITION_BOTTOM_CENTER = get_enum_constant("GRNotifications", "NotificationsPosition", "BOTTOM_CENTER"); + GRNotifications_NOTIFICATIONS_POSITION_BOTTOM_RIGHT = get_enum_constant("GRNotifications", "NotificationsPosition", "BOTTOM_RIGHT"); + + GRInputData_InputTypeNone = get_enum_constant("GRInputData", "InputType", "_NoneIT"); + GRInputData_InputDeviceSensors = get_enum_constant("GRInputData", "InputType", "_InputDeviceSensors"); + GRInputData_InputEvent = get_enum_constant("GRInputData", "InputType", "_InputEvent"); + GRInputData_InputEventAction = get_enum_constant("GRInputData", "InputType", "_InputEventAction"); + GRInputData_InputEventGesture = get_enum_constant("GRInputData", "InputType", "_InputEventGesture"); + GRInputData_InputEventJoypadButton = get_enum_constant("GRInputData", "InputType", "_InputEventJoypadButton"); + GRInputData_InputEventJoypadMotion = get_enum_constant("GRInputData", "InputType", "_InputEventJoypadMotion"); + GRInputData_InputEventKey = get_enum_constant("GRInputData", "InputType", "_InputEventKey"); + GRInputData_InputEventMagnifyGesture = get_enum_constant("GRInputData", "InputType", "_InputEventMagnifyGesture"); + GRInputData_InputEventMIDI = get_enum_constant("GRInputData", "InputType", "_InputEventMIDI"); + GRInputData_InputEventMouse = get_enum_constant("GRInputData", "InputType", "_InputEventMouse"); + GRInputData_InputEventMouseButton = get_enum_constant("GRInputData", "InputType", "_InputEventMouseButton"); + GRInputData_InputEventMouseMotion = get_enum_constant("GRInputData", "InputType", "_InputEventMouseMotion"); + GRInputData_InputEventPanGesture = get_enum_constant("GRInputData", "InputType", "_InputEventPanGesture"); + GRInputData_InputEventScreenDrag = get_enum_constant("GRInputData", "InputType", "_InputEventScreenDrag"); + GRInputData_InputEventScreenTouch = get_enum_constant("GRInputData", "InputType", "_InputEventScreenTouch"); + GRInputData_InputEventWithModifiers = get_enum_constant("GRInputData", "InputType", "_InputEventWithModifiers"); + GRInputData_InputEventMAX = get_enum_constant("GRInputData", "InputType", "_InputEventMAX"); + + GRPacket_NonePacket = get_enum_constant("GRPacket", "PacketType", "NonePacket"); + GRPacket_SyncTime = get_enum_constant("GRPacket", "PacketType", "SyncTime"); + GRPacket_ImageData = get_enum_constant("GRPacket", "PacketType", "ImageData"); + GRPacket_InputData = get_enum_constant("GRPacket", "PacketType", "InputData"); + GRPacket_ServerSettings = get_enum_constant("GRPacket", "PacketType", "ServerSettings"); + GRPacket_MouseModeSync = get_enum_constant("GRPacket", "PacketType", "MouseModeSync"); + GRPacket_CustomInputScene = get_enum_constant("GRPacket", "PacketType", "CustomInputScene"); + GRPacket_ClientStreamOrientation = get_enum_constant("GRPacket", "PacketType", "ClientStreamOrientation"); + GRPacket_ClientStreamAspect = get_enum_constant("GRPacket", "PacketType", "ClientStreamAspect"); + GRPacket_CustomUserData = get_enum_constant("GRPacket", "PacketType", "CustomUserData"); + GRPacket_Ping = get_enum_constant("GRPacket", "PacketType", "Ping"); + GRPacket_Pong = get_enum_constant("GRPacket", "PacketType", "Pong"); + + GRDevice_USE_INTERNAL_SERVER_SETTINGS = get_enum_constant("GRDevice", "TypesOfServerSettings", "SERVER_SETTINGS_USE_INTERNAL"); + GRDevice_SERVER_PARAM_VIDEO_STREAM_ENABLED = get_enum_constant("GRDevice", "TypesOfServerSettings", "SERVER_SETTINGS_VIDEO_STREAM_ENABLED"); + GRDevice_SERVER_PARAM_COMPRESSION_TYPE = get_enum_constant("GRDevice", "TypesOfServerSettings", "SERVER_SETTINGS_COMPRESSION_TYPE"); + GRDevice_SERVER_PARAM_JPG_QUALITY = get_enum_constant("GRDevice", "TypesOfServerSettings", "SERVER_SETTINGS_JPG_QUALITY"); + GRDevice_SERVER_PARAM_SKIP_FRAMES = get_enum_constant("GRDevice", "TypesOfServerSettings", "SERVER_SETTINGS_SKIP_FRAMES"); + GRDevice_SERVER_PARAM_RENDER_SCALE = get_enum_constant("GRDevice", "TypesOfServerSettings", "SERVER_SETTINGS_RENDER_SCALE"); + + GRDevice_IMAGE_COMPRESSION_UNCOMPRESSED = get_enum_constant("GRDevice", "ImageCompressionType", "COMPRESSION_UNCOMPRESSED"); + GRDevice_IMAGE_COMPRESSION_JPG = get_enum_constant("GRDevice", "ImageCompressionType", "COMPRESSION_JPG"); + GRDevice_IMAGE_COMPRESSION_PNG = get_enum_constant("GRDevice", "ImageCompressionType", "COMPRESSION_PNG"); + + GRDevice_SS_Y_ONLY = get_enum_constant("GRDevice", "Subsampling", "SUBSAMPLING_Y_ONLY"); + GRDevice_SS_H1V1 = get_enum_constant("GRDevice", "Subsampling", "SUBSAMPLING_H1V1"); + GRDevice_SS_H2V1 = get_enum_constant("GRDevice", "Subsampling", "SUBSAMPLING_H2V1"); + GRDevice_SS_H2V2 = get_enum_constant("GRDevice", "Subsampling", "SUBSAMPLING_H2V2"); + + GRDevice_STATUS_STARTING = get_enum_constant("GRDevice", "WorkingStatus", "STATUS_STARTING"); + GRDevice_STATUS_STOPPING = get_enum_constant("GRDevice", "WorkingStatus", "STATUS_STOPPING"); + GRDevice_STATUS_WORKING = get_enum_constant("GRDevice", "WorkingStatus", "STATUS_WORKING"); + GRDevice_STATUS_STOPPED = get_enum_constant("GRDevice", "WorkingStatus", "STATUS_STOPPED"); + + GRClient_CONNECTION_ADB = get_enum_constant("GRClient", "ConnectionType", "CONNECTION_ADB"); + GRClient_CONNECTION_WiFi = get_enum_constant("GRClient", "ConnectionType", "CONNECTION_WiFi"); + + GRClient_STRETCH_KEEP_ASPECT = get_enum_constant("GRClient", "StretchMode", "STRETCH_KEEP_ASPECT"); + GRClient_STRETCH_FILL = get_enum_constant("GRClient", "StretchMode", "STRETCH_FILL"); + + GRClient_STREAM_NO_SIGNAL = get_enum_constant("GRClient", "StreamState", "STREAM_NO_SIGNAL"); + GRClient_STREAM_ACTIVE = get_enum_constant("GRClient", "StreamState", "STREAM_ACTIVE"); + GRClient_STREAM_NO_IMAGE = get_enum_constant("GRClient", "StreamState", "STREAM_NO_IMAGE"); + +func get_enum_constant(_class : String, _enum : String, _value : String) -> int: + if GodotRemote.is_gdnative(): + return int(GodotRemote.call("_get_%s_%s_%s"%[_class, _enum, _value])) + else: + return ClassDB.class_get_integer_constant(_class, _value) diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/CustomPopupTextInput.gd b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/CustomPopupTextInput.gd new file mode 100644 index 0000000..63353f1 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/CustomPopupTextInput.gd @@ -0,0 +1,132 @@ +tool +class_name CustomPopupTextInput +extends Control + +onready var label := $Box/Label +onready var line := $Box/LineEdit + +var Title := "" setget _set_title +var IsSecret := false setget _set_is_secret +var Text := "" setget _set_text +var Placeholder := "" setget _set_placeholder +var MaxLength := 128 setget _set_max_length +var LineFont : Font setget _set_line_font + +var LineEditToReturn : LineEdit + +var is_ready := false +var is_shown := false +var force_close := false +var _is_mobile := false +var line_style : StyleBoxFlat + +func _ready(): + is_ready = true + _is_mobile = OS.has_feature("mobile") # G.IsMobile not valid for this cause PC dont have virtual keyboard like Android/iOS + + set_process(false) + if not Engine.editor_hint: + visible = false + line_style = line.get_stylebox("normal") + +func _process(_delta): + if _is_mobile: + var h := OS.get_virtual_keyboard_height() + if h > 0 and not force_close: + var vp_s := get_tree().root.get_visible_rect().size + rect_size = vp_s - Vector2(0, h) * (vp_s / OS.window_size) + + if not is_shown: + is_shown = true + visible = true + else: + if is_shown or force_close: + is_shown = false + visible = false + + if LineEditToReturn: + LineEditToReturn.text = line.text + LineEditToReturn.emit_signal("text_changed", line.text) + if LineEditToReturn.get_parent() is SpinBox: + LineEditToReturn.emit_signal("text_entered", line.text) + + LineEditToReturn = null + set_process(false) + else: + if force_close: + is_shown = false + visible = false + + if LineEditToReturn: + LineEditToReturn.text = line.text + LineEditToReturn.emit_signal("text_changed", line.text) + if LineEditToReturn.get_parent() is SpinBox: + LineEditToReturn.emit_signal("text_entered", line.text) + + LineEditToReturn = null + set_process(false) + +func popup_text_edit(title : String, line_to_return : LineEdit): + LineEditToReturn = line_to_return + self.Title = title + self.IsSecret = line_to_return.secret + self.Text = line_to_return.text + self.Placeholder = line_to_return.placeholder_text + self.LineFont = line_to_return.get_font("font") + self.MaxLength = line_to_return.max_length + + line.caret_position = line.text.length() + + var f = get_font("font").get_height() + line.rect_min_size = Vector2(0, f * 2.5) + line_style.content_margin_left = f * 0.75 + line_style.content_margin_right = -f * 0.75 + + force_close = false + is_shown = false + + if not _is_mobile: + visible = true + + line.grab_focus() + set_process(true) + +func _set_is_secret(val : bool): + if is_ready: + IsSecret = val + line.secret = val + +func _set_title(val : String): + if is_ready: + Title = val + label.text = val + +func _set_text(val : String): + if is_ready: + Text = val + line.text = val + +func _set_placeholder(val : String): + if is_ready: + Placeholder = val + line.placeholder_text = val + +func _set_max_length(val : int): + if is_ready: + MaxLength = val + line.max_length = val + +func _set_line_font(val : Font): + if is_ready: + LineFont = val + line.add_font_override("font", val) + +func _on_LineEdit_text_changed(new_text): + if LineEditToReturn: + LineEditToReturn.text = new_text + +func _on_LineEdit_text_entered(_new_text): + force_close = true + +func _on_LineEdit_focus_exited(): + force_close = true diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/GRSettings.gd b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/GRSettings.gd new file mode 100644 index 0000000..632eb23 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/GRSettings.gd @@ -0,0 +1,374 @@ +extends Control + +onready var timer = $Timer +onready var start_stop = $H/StartStop +onready var version = $H/Version +onready var empty_top = $H/empty +onready var donations = $H/Donations + +onready var scroll = $Scroll +onready var grid = $Scroll/H/Grid +onready var wifi = $Scroll/H/Grid/WiFi +onready var adb = $Scroll/H/Grid/ADB + +onready var device_id = $Scroll/H/Grid/DeviceID/ID +onready var con_type_menu = $Scroll/H/Grid/ConnectionType/Type +onready var adb_port_line = $Scroll/H/Grid/ADB/Port +onready var adb_set_port = $Scroll/H/Grid/SetADBPort + +onready var wifi_port_line = $Scroll/H/Grid/WiFi/Address/Port +onready var wifi_ip_line = $Scroll/H/Grid/WiFi/Address/IP +onready var wifi_set_address = $Scroll/H/Grid/SetWiFiAddress + +onready var fps = $Scroll/H/Grid/OutFps/FPS +onready var password = $Scroll/H/Grid/PassRow/Pass +onready var filtering = $Scroll/H/Grid/Filtering +onready var stretch_mode = $Scroll/H/Grid/StretchMode/Type +onready var stats = $Scroll/H/Grid/ShowStats/Type +onready var sync_orient = $Scroll/H/Grid/SyncOrientation +onready var sync_aspect = $Scroll/H/Grid/SyncAspect +onready var keepscreen = $Scroll/H/Grid/KeepScreen +onready var captureinput = $Scroll/H/Grid/CaptureInput +onready var touches_to_open = $Scroll/H/Grid/TouchesToOpenSettings/Type + +onready var enabled_server_settings = $Scroll/H/Grid/OverrideServerSetting +onready var sync_server_settings = $Scroll/H/Grid/SyncServerSettings +onready var video_stream = $Scroll/H/Grid/VideoStream +onready var jpg_quality = $Scroll/H/Grid/JPG_Quality/Quality +onready var render_scale = $Scroll/H/Grid/RenderScale/Scale +onready var skip_frames = $Scroll/H/Grid/HBoxContainer/SKIP +onready var compression = $Scroll/H/Grid/HBoxContainer2/State2 + +# Names of LineEdits in custom touch input menu +onready var line_edits_to_touch_input = [ + [device_id, "Device ID:"], + [adb_port_line.get_line_edit(), "Server port:"], + [wifi_ip_line, "Server address:"], + [wifi_port_line.get_line_edit(), "Server port:"], + [fps.get_line_edit(), "Output data FPS:"], + [password, "Server password:"], + [skip_frames.get_line_edit(), "Skip frames:"], + ] + +var updated_by_code := false + +func _ready(): + scroll.get_v_scrollbar().rect_min_size.x = 24 + scroll.get_h_scrollbar().rect_min_size.y = 24 + donations.visible = false + #empty_top.visible = true + + version.text = "GR version: " + GodotRemote.get_version() + var d = GodotRemote.get_device() + d.connect("connection_state_changed", self, "_connection_changed") + d.connect("status_changed", self, "_status_changed") + d.connect("server_settings_received", self, "_server_settings_received") + update_values() + _set_buttons_disabled(false) + _update_start_stop() + _init_mobile_touch_input() + _resize_for_mobile() + _init_point() + +func _notification(what): + match what: + NOTIFICATION_WM_GO_BACK_REQUEST: + if visible: # TODO maybe try to open settings by this back button + visible = false + NOTIFICATION_WM_QUIT_REQUEST: + grab_focus() + +func _resize_for_mobile(): + if G.IsMobile: + var nodes = get_tree().get_nodes_in_group("nodes_that_should_be_higher") + for n in nodes: + if n is Control: + n.rect_min_size = Vector2(n.rect_min_size.x, 64 if n.rect_min_size.y < 64 else n.rect_min_size.y) + +func _init_mobile_touch_input(): + for p in line_edits_to_touch_input: + TIM.set_title(p[0], p[1]) + +func _init_point(): + if G.Billings: + yield(G.Billings, "billings_ready") + donations.visible = G.Billings != null + #empty_top.visible = G.Billings == null + G.Billings.connect("points_updated", self, "_points_update") + _points_update(G.Billings.get_purchased_points()) + +func _points_update(points): + donations.text = "Points: " + str(points) + +func _on_GRSettings_resized(): + var cols = 2 if (rect_size.x / rect_size.y > 1.3) else 1 + if cols != grid.columns: + grid.columns = cols + +func _server_settings_visibility(val : bool): + var pos = enabled_server_settings.get_position_in_parent() + 1 + var childr = grid.get_children() + + for i in range(pos, childr.size()): + var o = childr[i] + if o is Control: + o.visible = val + +func _on_GRSettings_visibility_changed(): + _update_start_stop() + if visible: + update_values() + grab_focus() + + yield(get_tree(), "idle_frame") + get_tree().set_quit_on_go_back(false) + GodotRemote.get_device().capture_input = false + else: + # yield needs to wait next frame and not instant close app + yield(get_tree(), "idle_frame") + get_tree().set_quit_on_go_back(true) + GodotRemote.get_device().capture_input = true + +func update_values(): + var d = GodotRemote.get_device() + + device_id.text = d.device_id + con_type_menu.selected = d.connection_type + adb_port_line.value = d.port + wifi_port_line.value = d.port + wifi_ip_line.text = d.get_address() + stretch_mode.selected = d.stretch_mode + fps.value = d.target_send_fps + stats.selected = G.show_stats + filtering.pressed = G.texture_filtering + password.text = G.password + sync_orient.pressed = G.sync_viewport_orientation + sync_aspect.pressed = G.sync_viewport_aspect_ratio + keepscreen.pressed = G.keepscreenon + captureinput.pressed = G.capture_input_when_custom_scene + touches_to_open.selected = G.TouchesToOpenSettings - 3 + + enabled_server_settings.pressed = G.override_server_settings + sync_server_settings.pressed = G.sync_server_settings + _server_settings_visibility(G.override_server_settings) + + jpg_quality.value = G.server_jpg_quality + render_scale.value = G.server_render_scale + skip_frames.value = G.server_skip_fps + compression.select(G.server_compression_type) + video_stream.pressed = G.server_video_stream + + _set_all_server_settings() + _on_con_Type_item_selected(con_type_menu.selected) + +func _set_all_server_settings(): + var d = GodotRemote.get_device() + if G.override_server_settings and d.is_connected_to_host(): + d.set_server_setting(C.GRDevice_SERVER_PARAM_JPG_QUALITY, jpg_quality.value) + d.set_server_setting(C.GRDevice_SERVER_PARAM_RENDER_SCALE, render_scale.value) + d.set_server_setting(C.GRDevice_SERVER_PARAM_SKIP_FRAMES, skip_frames.value) + d.set_server_setting(C.GRDevice_SERVER_PARAM_COMPRESSION_TYPE, compression.selected) + d.set_server_setting(C.GRDevice_SERVER_PARAM_VIDEO_STREAM_ENABLED, video_stream.pressed) + +func _status_changed(_status : int): + if timer.is_stopped(): + _set_buttons_disabled(_status == C.GRDevice_STATUS_STARTING or _status == C.GRDevice_STATUS_STOPPING) + _update_start_stop() + +func _connection_changed(connected : bool): + if connected: + _set_all_server_settings() + else: + pass + +func _server_settings_received(_settings : Dictionary): + updated_by_code = true + + var k = _settings.keys() + for kk in k: + var v = _settings[kk] + match kk: + C.GRDevice_SERVER_PARAM_JPG_QUALITY: jpg_quality.value = v + C.GRDevice_SERVER_PARAM_RENDER_SCALE: render_scale.value = v + C.GRDevice_SERVER_PARAM_SKIP_FRAMES: skip_frames.value = v + C.GRDevice_SERVER_PARAM_COMPRESSION_TYPE: compression.selected = v + C.GRDevice_SERVER_PARAM_VIDEO_STREAM_ENABLED: video_stream.pressed = v + + updated_by_code = false + +func _on_LogLevelPopupMenu_id_pressed(id: int) -> void: + GodotRemote.set_log_level(id) + +func _on_button_disable_Timer_timeout(): + var _status = GodotRemote.get_device().get_status() + _set_buttons_disabled(_status == C.GRDevice_STATUS_STARTING or _status == C.GRDevice_STATUS_STOPPING) + +func _update_start_stop(): + match GodotRemote.get_device().get_status(): + C.GRDevice_STATUS_STARTING: + start_stop.text = " Starting Client " + C.GRDevice_STATUS_STOPPING: + start_stop.text = " Stopping Client " + C.GRDevice_STATUS_WORKING: + start_stop.text = " Stop Client " + C.GRDevice_STATUS_STOPPED: + start_stop.text = " Launch Client " + +func _set_buttons_disabled(state : bool): + if is_inside_tree(): + for b in get_tree().get_nodes_in_group("buttons_to_disable"): + if b is Button: + b.disabled = state + +func _disable_buttons_by_timer(): + _set_buttons_disabled(true) + timer.start() + +func _on_Close_pressed(): + if get_parent().has_method("_hide_settings"): + get_parent()._hide_settings() + else: + visible = false + +func _on_Donations_pressed(): + get_parent().show_support_window() + +func _on_Version_pressed(): + get_parent().popup_welcome_screen() + +func _on_StartStop_pressed(): + var d = GodotRemote.get_device() + + _disable_buttons_by_timer() + match d.get_status(): + C.GRDevice_STATUS_STARTING: pass + C.GRDevice_STATUS_STOPPING: pass + C.GRDevice_STATUS_WORKING: + _set_buttons_disabled(true) + d.stop() + C.GRDevice_STATUS_STOPPED: + _set_buttons_disabled(true) + d.start() + +func _on_Device_ID_text_changed(new_text : String): + if !new_text.empty(): + GodotRemote.get_device().device_id = new_text + G.device_id = new_text + else: + G.device_id = G.get_random_hash() + GodotRemote.get_device().device_id = G.device_id + +func _on_wifi_IP_text_entered(_new_text): + _on_wifi_SetAddress_pressed() + +func _on_wifi_SetAddress_pressed(): + _disable_buttons_by_timer() + GodotRemote.get_device().connection_type = con_type_menu.selected + var address = wifi_ip_line.text.replace("http://", "").replace("https://", "").strip_edges() + if GodotRemote.get_device().set_address_port(address, wifi_port_line.value): + G.ip = address + wifi_ip_line.text = address + G.port = wifi_port_line.value + G.connection_type = con_type_menu.selected + +func _on_adb_SetAddress_pressed(): + _disable_buttons_by_timer() + GodotRemote.get_device().connection_type = con_type_menu.selected + GodotRemote.get_device().port = adb_port_line.value + G.port = adb_port_line.value + G.connection_type = con_type_menu.selected + +func _on_con_Type_item_selected(index): + match index: + 0: + wifi.visible = true + wifi_set_address.visible = true + adb.visible = false + adb_set_port.visible = false + 1: + wifi.visible = false + wifi_set_address.visible = false + adb.visible = true + adb_set_port.visible = true + +func _on_stretch_Type_item_selected(index): + GodotRemote.get_device().stretch_mode = index + G.stretch_mode = index + +func _on_stats_State_selected_id(id : int): + G.show_stats = id + +func _on_FPS_value_changed(value): + GodotRemote.get_device().target_send_fps = value + G.target_send_fps = value + +func _on_texture_Filtering_toggled(button_pressed): + G.texture_filtering = button_pressed + GodotRemote.get_device().texture_filtering = button_pressed + +func _on_Password_text_changed(new_text): + G.password = new_text + GodotRemote.get_device().password = new_text + +func _on_SyncOrientation_toggled(button_pressed): + G.sync_viewport_orientation = button_pressed + GodotRemote.get_device().viewport_orientation_syncing = button_pressed + +func _on_SyncAspect_toggled(button_pressed): + G.sync_viewport_aspect_ratio = button_pressed + GodotRemote.get_device().viewport_aspect_ratio_syncing = button_pressed + +func _on_keep_screen_CheckButton_toggled(button_pressed): + G.keepscreenon = button_pressed + if !GodotRemote.get_device().is_stream_active(): + OS.keep_screen_on = button_pressed + +func _on_CaptureInput_toggled(button_pressed: bool) -> void: + G.capture_input_when_custom_scene = button_pressed + if GodotRemote.get_device().get_custom_input_scene(): + GodotRemote.get_device().capture_pointer = button_pressed + +func _on_touches_to_open_item_selected(index: int) -> void: + G.TouchesToOpenSettings = index + 3 + +func _on_override_settings_State_toggled(button_pressed): + G.override_server_settings = button_pressed + _server_settings_visibility(G.override_server_settings) + if button_pressed: + _set_all_server_settings() + else: + GodotRemote.get_device().disable_overriding_server_settings() + +func _on_SyncServerSettings_toggled(button_pressed): + G.sync_server_settings = button_pressed + GodotRemote.get_device().server_settings_syncing = button_pressed + +func _on_server_Quality_value_changed(value): + if not updated_by_code: + if G.override_server_settings: + GodotRemote.get_device().set_server_setting(C.GRDevice_SERVER_PARAM_JPG_QUALITY, value) + G.server_jpg_quality = value + +func _on_server_render_Scale_value_changed(value): + if not updated_by_code: + if G.override_server_settings: + GodotRemote.get_device().set_server_setting(C.GRDevice_SERVER_PARAM_RENDER_SCALE, value) + G.server_render_scale = value + +func _on_server_send_FPS_value_changed(value): + if not updated_by_code: + if G.override_server_settings: + GodotRemote.get_device().set_server_setting(C.GRDevice_SERVER_PARAM_SKIP_FRAMES, value) + G.server_skip_fps = value + +func _on_compression_type_item_selected(index): + if not updated_by_code: + if G.override_server_settings: + GodotRemote.get_device().set_server_setting(C.GRDevice_SERVER_PARAM_COMPRESSION_TYPE, index) + G.server_compression_type = index + +func _on_video_stream_Enabled_toggled(button_pressed): + if not updated_by_code: + if G.override_server_settings: + GodotRemote.get_device().set_server_setting(C.GRDevice_SERVER_PARAM_VIDEO_STREAM_ENABLED, button_pressed) + G.server_video_stream = button_pressed diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/GRStats.gd b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/GRStats.gd new file mode 100644 index 0000000..ba7a563 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/GRStats.gd @@ -0,0 +1,52 @@ +extends PanelContainer + +onready var grid = $Grid +onready var fps = $Grid/FPS +onready var fps_min = $Grid/FPS_min +onready var fps_max = $Grid/FPS_max +onready var ping = $Grid/Ping +onready var ping_min = $Grid/Ping_min +onready var ping_max = $Grid/Ping_max +var stat_state : int = 0 + +onready var detailed_labels = [ + ping_max, ping_min, + fps_max, fps_min, +] + +func _ready(): + G.connect("show_stats_changed", self, "show_stats_changed") + show_stats_changed(G.show_stats) + +func _process(_delta): + if GodotRemote.get_device(): + if stat_state > G.StatInfoState.Hidden: + fps.text = "FPS: %.1f" % GodotRemote.get_device().get_avg_fps() + ping.text = "PING: %.1f" % GodotRemote.get_device().get_avg_ping() + + if stat_state > G.StatInfoState.Simple: + fps_min.text = "%.1f" % GodotRemote.get_device().get_min_fps() + fps_max.text = "%.1f" % GodotRemote.get_device().get_max_fps() + + ping_min.text = "%.1f" % GodotRemote.get_device().get_min_ping() + ping_max.text = "%.1f" % GodotRemote.get_device().get_max_ping() + + rect_size = grid.rect_size + +func change_detailed_label_visibility(state : bool): + for l in detailed_labels: + l.visible = state + +func show_stats_changed(state): + stat_state = state + match state: + G.StatInfoState.Hidden: + visible = false + G.StatInfoState.Simple: + visible = true + change_detailed_label_visibility(false) + grid.columns = 1 + G.StatInfoState.Detailed: + visible = true + change_detailed_label_visibility(true) + grid.columns = 3 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/Global.gd b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/Global.gd new file mode 100644 index 0000000..90a1cfc --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/Global.gd @@ -0,0 +1,332 @@ +extends Node + +enum RateState{ + NotNow = 0, + No = 1, + Yes = 2, +} + +enum StatInfoState{ + Hidden = 0, + Simple = 1, + Detailed = 2, +} + +signal show_stats_changed(state) + +const CLIENT_VERSION := 0 +const SAVE_FILE := "user://settings.json" + +var IsMobile : bool = false +var Billings : Node = null + +var VersionChanged : bool = false +var PreviousVersion : String = "" +var AppRuns : int = 0 +var TotalAppRuns : int = 0 +var TouchesToOpenSettings : int = 5 setget set_touches_to_open_settings +var UserRateState : int = RateState.NotNow setget set_user_rate_state + +var device_id : String = "" setget set_device_id +var connection_type : int = 0 setget set_con_type +var ip : String = "127.0.0.1" setget set_ip +var port : int = 52341 setget set_port +var stretch_mode : int = 0 setget set_stretch_mode +var target_send_fps : int = 60 setget set_target_send_fps +var texture_filtering : bool = true setget set_texture_filtering +var password : String = "" setget set_password +var sync_viewport_orientation : bool = true setget set_sync_viewport_orientation +var sync_viewport_aspect_ratio : bool = true setget set_sync_viewport_aspect_ratio +var keepscreenon : bool = false setget set_keep_screen_on +var capture_input_when_custom_scene : bool = false setget set_capture_input_when_custom_scene + +var show_stats : int = StatInfoState.Hidden setget set_show_stats + +var override_server_settings : bool = false setget set_override_settings +var sync_server_settings : bool = false setget set_sync_server_settings +var server_video_stream : bool = true setget set_server_video_stream +var server_compression_type : int = 1 setget set_server_compression_type +var server_jpg_quality : int = 80 setget set_server_jpg_quality +var server_render_scale : float = 0.3 setget set_server_render_scale +var server_skip_fps : int = 0 setget set_server_skip_fps + +func get_random_hash(length : int = 6) -> String: + return str(randi() * randi()).md5_text().substr(0,length) + +func _enter_tree(): + IsMobile = OS.has_feature("mobile") + #IsMobile = true + + var d = Directory.new() + d.open("res://") # godot in some versions print error if derectory not opened + var f = "res://An0therUn1queN@meOfF0lderForSecur1tyPurp0ses/AndroidBilling.gd" + var fc = f+"c" + if OS.has_feature("Android") and OS.has_feature("billing") and (d.file_exists(f) or d.file_exists(fc)): + var b = load(f) + if b: + print("Android Billings Loaded") + Billings = b.new() + add_child(Billings) + +func _ready(): + randomize() + device_id = get_random_hash() + + if OS.has_feature("standalone") and not OS.has_feature("mobile"): + OS.window_size = Vector2(1280, 720) + + _load_settings() + + GodotRemote.create_remote_device(C.GodotRemote_DEVICE_CLIENT) + + var d = GodotRemote.get_device() + d.capture_when_hover = false + + _set_all_values() + _setup_notifications_style() + _add_runs() + #GodotRemote.set_log_level(GodotRemote.LL_Debug) + + yield(get_tree(), "idle_frame") + if Billings: + Billings._init_billings() + +func _add_runs(): + AppRuns += 1 + TotalAppRuns += 1 + _save_settings() + +func _setup_notifications_style(): + yield(get_tree(), "idle_frame") + var s = GodotRemote.notifications_style + s.panel_style = load("res://AssetsInSuperSecureAndUn1queF0lder/Styles/NotificationPanelStyle.tres") + s.close_button_theme = load("res://AssetsInSuperSecureAndUn1queF0lder/Styles/MainTheme.tres") + s.title_font = load("res://AssetsInSuperSecureAndUn1queF0lder/Styles/NotificationPanelTitleStyle.tres") + s.text_font = load("res://AssetsInSuperSecureAndUn1queF0lder/Styles/NotificationPanelTextStyle.tres") + + s.close_button_icon = load("res://AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Close_icon.png") + s.set_notification_icon(C.GRNotifications_NOTIFICATION_ICON_SUCCESS, load("res://AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Connected_icon.png")) + s.set_notification_icon(C.GRNotifications_NOTIFICATION_ICON_FAIL, load("res://AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Disconnected_icon.png")) + s.set_notification_icon(C.GRNotifications_NOTIFICATION_ICON_ERROR, load("res://AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Error_icon.png")) + s.set_notification_icon(C.GRNotifications_NOTIFICATION_ICON_WARNING, load("res://AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Warning_icon.png")) + + GodotRemote.notifications_style = s + +func _notification(what): + match what: + NOTIFICATION_WM_QUIT_REQUEST: + _save_settings() + +func _set_all_values(): + var dev = GodotRemote.get_device() + var i_w : int = dev.get_status() + if i_w == C.GRDevice_STATUS_WORKING: + dev.stop() + + dev.device_id = device_id + dev.set_address_port(ip, port) + dev.connection_type = connection_type + dev.stretch_mode = stretch_mode + dev.target_send_fps = target_send_fps + dev.texture_filtering = texture_filtering + dev.password = password + dev.server_settings_syncing = sync_server_settings + dev.viewport_orientation_syncing = sync_viewport_orientation + dev.viewport_aspect_ratio_syncing = sync_viewport_aspect_ratio + OS.keep_screen_on = keepscreenon + + if override_server_settings: + dev.set_server_setting(C.GRDevice_SERVER_PARAM_VIDEO_STREAM_ENABLED, server_video_stream) + dev.set_server_setting(C.GRDevice_SERVER_PARAM_COMPRESSION_TYPE, server_compression_type) + dev.set_server_setting(C.GRDevice_SERVER_PARAM_JPG_QUALITY, server_jpg_quality) + dev.set_server_setting(C.GRDevice_SERVER_PARAM_RENDER_SCALE, server_render_scale) + dev.set_server_setting(C.GRDevice_SERVER_PARAM_SKIP_FRAMES, server_skip_fps) + + if i_w: + dev.start() + +func _save_settings(): + var d = Dictionary() + + d["m_version"] = get_version() + d["app_runs"] = AppRuns + d["total_app_runs"] = TotalAppRuns + d["touches_to_open_settings"] = TouchesToOpenSettings + d["user_rate_state"] = UserRateState + d["device_id"] = device_id + d["con_type"] = connection_type + d["ip"] = ip + d["port"] = port + d["stretch"] = stretch_mode + d["stats"] = show_stats + d["target_fps"] = target_send_fps + d["t_filter"] = texture_filtering + d["password"] = password + d["v_orient"] = sync_viewport_orientation + d["v_aspect"] = sync_viewport_aspect_ratio + d["keepscreenon"] = keepscreenon + d["capture_input_when_custom_scene"] = capture_input_when_custom_scene + + d["ov_s_settings"] = override_server_settings + d["sync_s_settings"] = sync_server_settings + d["s_video_stream"] = server_video_stream + d["s_jpg_quality"] = server_jpg_quality + d["s_render_scale"] = server_render_scale + d["s_skip_fps"] = server_skip_fps + d["s_compression_type"] = server_compression_type + + var dir = Directory.new() + + dir.open("user://") + if dir.file_exists(SAVE_FILE): + var err = dir.remove(SAVE_FILE) + if err != OK: + return + + var f = File.new() + + var err = f.open(SAVE_FILE, File.WRITE) + if err == OK: + f.store_string(to_json(d)) + f.close() + +func _load_settings(): + var f = File.new() + + if f.file_exists(SAVE_FILE): + var err = f.open(SAVE_FILE, File.READ) + + if err == OK: + var txt = f.get_as_text() + f.close() + var d = parse_json(txt) + + PreviousVersion = _safe_get_from_dict(d, "m_version", get_version()) + VersionChanged = PreviousVersion != get_version() + if VersionChanged: + AppRuns = 0 + else: + AppRuns = _safe_get_from_dict(d, "app_runs", AppRuns) + + TotalAppRuns = _safe_get_from_dict(d, "total_app_runs", TotalAppRuns) + TouchesToOpenSettings = _safe_get_from_dict(d, "touches_to_open_settings", TouchesToOpenSettings) + UserRateState = _safe_get_from_dict(d, "user_rate_state", UserRateState) + + device_id = _safe_get_from_dict(d, "device_id", device_id) + connection_type = _safe_get_from_dict(d, "con_type", connection_type) + ip = _safe_get_from_dict(d, "ip", ip) + port = _safe_get_from_dict(d, "port", port) + stretch_mode = _safe_get_from_dict(d, "stretch", stretch_mode) + show_stats = _safe_get_from_dict(d, "stats", show_stats) + target_send_fps = _safe_get_from_dict(d, "target_fps", target_send_fps) + texture_filtering = _safe_get_from_dict(d, "t_filter", texture_filtering) + password = _safe_get_from_dict(d, "password", password) + sync_viewport_orientation = _safe_get_from_dict(d, "v_orient", sync_viewport_orientation) + sync_viewport_aspect_ratio = _safe_get_from_dict(d, "v_aspect", sync_viewport_aspect_ratio) + keepscreenon = _safe_get_from_dict(d, "keepscreenon", keepscreenon) + capture_input_when_custom_scene = _safe_get_from_dict(d, "capture_input_when_custom_scene", capture_input_when_custom_scene) + + override_server_settings = _safe_get_from_dict(d, "ov_s_settings", override_server_settings) + sync_server_settings = _safe_get_from_dict(d, "sync_s_settings", sync_server_settings) + server_video_stream = _safe_get_from_dict(d, "s_video_stream", server_video_stream) + server_jpg_quality = _safe_get_from_dict(d, "s_jpg_quality", server_jpg_quality) + server_render_scale = _safe_get_from_dict(d, "s_render_scale", server_render_scale) + server_skip_fps = _safe_get_from_dict(d, "s_skip_fps", server_skip_fps) + server_compression_type = _safe_get_from_dict(d, "s_compression_type", server_compression_type) + +func _safe_get_from_dict(dict:Dictionary, val, def): + if dict.has(val): + return dict[val] + return def + +func get_version() -> String: + return "%s.%d" % [GodotRemote.get_version(), CLIENT_VERSION] + +func set_touches_to_open_settings(val : int): + TouchesToOpenSettings = val + _save_settings() + +func set_user_rate_state(val : int): + UserRateState = val + _save_settings() + +func set_device_id(val : String): + device_id = val + _save_settings() + +func set_con_type(val : int): + connection_type = val + _save_settings() + +func set_ip(val : String): + ip = val + _save_settings() + +func set_port(val : int): + port = val + _save_settings() + +func set_stretch_mode(val : int): + stretch_mode = val + _save_settings() + +func set_show_stats(val : int): + show_stats = val + _save_settings() + emit_signal("show_stats_changed", val) + +func set_target_send_fps(val : int): + target_send_fps = val + _save_settings() + +func set_texture_filtering(val : bool): + texture_filtering = val + _save_settings() + +func set_password(val : String): + password = val + _save_settings() + +func set_sync_viewport_orientation(val : bool): + sync_viewport_orientation = val + _save_settings() + +func set_sync_viewport_aspect_ratio(val : bool): + sync_viewport_aspect_ratio = val + _save_settings() + +func set_keep_screen_on(val : bool): + keepscreenon = val + _save_settings() + +func set_capture_input_when_custom_scene(val : bool): + capture_input_when_custom_scene = val + _save_settings() + +func set_override_settings(val : bool): + override_server_settings = val + _save_settings() + +func set_sync_server_settings(val : bool): + sync_server_settings = val + _save_settings() + +func set_server_video_stream(val : bool): + server_video_stream = val + _save_settings() + +func set_server_compression_type(val : int): + server_compression_type = val + _save_settings() + +func set_server_jpg_quality(val : int): + server_jpg_quality = val + _save_settings() + +func set_server_render_scale(val : float): + server_render_scale = val + _save_settings() + +func set_server_skip_fps(val : int): + server_skip_fps = val + _save_settings() diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/GodotRemoteClient.gd b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/GodotRemoteClient.gd new file mode 100644 index 0000000..2a6c826 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/GodotRemoteClient.gd @@ -0,0 +1,132 @@ +extends Control + +var touches : Dictionary = {} +var mouse_mode : = Input.MOUSE_MODE_VISIBLE +var support : Control = null +var orig_welcome_text : String = "" + +func _ready(): + var d = Directory.new() + d.open("res://") # godot in some versions print error if derectory not opened + var f = "res://An0therUn1queN@meOfF0lderForSecur1tyPurp0ses/Support.tscn" + if d.file_exists(f): + support = load(f).instance() + call_deferred("add_child", support) + + TIM.InputPopup = $CustomPopupTextInput + + GodotRemote.get_device().set_control_to_show_in($Stream) + GodotRemote.get_device().connect("custom_input_scene_added", self, "_custom_input_scene_added") + GodotRemote.get_device().connect("custom_input_scene_removed", self, "_custom_input_scene_removed") + GodotRemote.get_device().connect("stream_state_changed", self, "_stream_state_changed") + GodotRemote.get_device().connect("mouse_mode_changed", self, "_mouse_mode_changed") + GodotRemote.connect("device_removed", self, "_device_removed") + + $Stats.visible = false + $BackgroundTouchHint.visible = false + _hide_settings() + + GodotRemote.get_device().start() + + connect("item_rect_changed", self, "viewport_size_changed") + orig_welcome_text = $FirstLaunchHint/VBox/Label2.text + if G.TotalAppRuns == 1: + popup_welcome_screen() + +func popup_welcome_screen(): + $FirstLaunchHint/VBox/Label2.text = orig_welcome_text % G.TouchesToOpenSettings + $FirstLaunchHint.popup_centered(get_viewport_rect().size) + +func viewport_size_changed() -> void: + if $FirstLaunchHint.visible: + $FirstLaunchHint.rect_size = get_viewport_rect().size + +func _mouse_mode_changed(_mode): + mouse_mode = _mode + + if not $GRSettings.visible: + Input.set_mouse_mode(mouse_mode) + +func _custom_input_scene_added(): + $BackgroundTouchHint/Panel/TextureRect.visible = false + GodotRemote.get_device().capture_pointer = G.capture_input_when_custom_scene + +func _custom_input_scene_removed(): + $BackgroundTouchHint/Panel/TextureRect.visible = true + GodotRemote.get_device().capture_pointer = true + +func _stream_state_changed(_is_connected): + match _is_connected: + C.GRClient_STREAM_NO_SIGNAL: + OS.keep_screen_on = G.keepscreenon + $Stats.visible = false + $BackgroundTouchHint.visible = false + + C.GRClient_STREAM_ACTIVE: + OS.keep_screen_on = true + $Stats.visible = not $GRSettings.visible + $BackgroundTouchHint.visible = false + + C.GRClient_STREAM_NO_IMAGE: + $Stats.visible = not $GRSettings.visible + $BackgroundTouchHint.visible = true + $BackgroundTouchHint/Panel/TextureRect.visible = GodotRemote.get_device().get_custom_input_scene() == null + +func _device_removed(): + $Stats.visible = false + $BackgroundTouchHint.visible = true + +func _toggle_settings(): + $GRSettings.update_values() + if $GRSettings.visible: + _hide_settings() + else: + _show_settings() + +func _show_settings(): + $GRSettings.visible = true + $Stats.visible = false + Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) + +func _hide_settings(): + $GRSettings.visible = false + $Stats.visible = GodotRemote.get_device().is_stream_active() + Input.set_mouse_mode(mouse_mode) + +func _count_pressed_touches() -> int: + var res = 0 + for k in touches: + res += int(touches[k]) + return res + +func _release_sceen_touches(count : int): + for x in range(count): + var ev = InputEventScreenTouch.new() + ev.pressed = false + ev.index = x + Input.parse_input_event(ev) + +func _input(e): + if e is InputEventKey: + if e.pressed: + match e.scancode: + KEY_F2: GodotRemote.set_log_level(C.GodotRemote_LL_NONE) + KEY_F3: GodotRemote.set_log_level(C.GodotRemote_LL_NORMAL) + KEY_F4: GodotRemote.set_log_level(C.GodotRemote_LL_DEBUG) + KEY_ESCAPE: + if TIM.IsVisible: + TIM.hide() + else: + _toggle_settings() + + if e is InputEventScreenTouch: + touches[e.index] = e.pressed + if e.pressed: + var pressed_count = _count_pressed_touches() + if pressed_count >= G.TouchesToOpenSettings: + _show_settings() + _release_sceen_touches(pressed_count) + +func show_support_window(): + if support: + support.visible = true diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/JoyMappings.gd b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/JoyMappings.gd new file mode 100644 index 0000000..4890817 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/JoyMappings.gd @@ -0,0 +1,10 @@ +extends Node + + +var CustomMappings : = [ + "03000000ac0500002c02000000000000,ipega Bluetooth Gamepad,platform:Windows,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b8,rightshoulder:b9,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,-rightx:a3~,+rightx:a4,-righty:a5,+righty:a4,lefttrigger:b6,righttrigger:b7,", +] + +func _ready(): + for m in CustomMappings: + Input.add_joy_mapping(m); diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/PlsRatePopup.gd b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/PlsRatePopup.gd new file mode 100644 index 0000000..5b05807 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/PlsRatePopup.gd @@ -0,0 +1,22 @@ +extends WindowDialog + +func _is_ready_to_show() -> bool: + return (G.Billings and ((G.AppRuns == 7 or (G.AppRuns > 9 and G.AppRuns % 9 == 0)) and G.UserRateState == G.RateState.NotNow)) and !G.VersionChanged + +func _ready(): + if _is_ready_to_show(): + call_deferred("popup_centered") + +func _on_yes_pressed() -> void: + hide() + G.UserRateState = G.RateState.Yes + #if G.Billings: + OS.shell_open("https://play.google.com/store/apps/details?id=com.dmitriysalnikov.godotremote") + +func _on_no_pressed() -> void: + hide() + G.UserRateState = G.RateState.No + +func _on_later_pressed() -> void: + hide() + G.UserRateState = G.RateState.NotNow diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/PlsSupportPopup.gd b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/PlsSupportPopup.gd new file mode 100644 index 0000000..f23b8cb --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/PlsSupportPopup.gd @@ -0,0 +1,34 @@ +extends WindowDialog + +var has_billings = false +var shown = false + +func _enter_tree(): + if G.Billings: + has_billings = true + G.Billings.connect("billings_ready", self, "_billings_ready") + +func _is_ready_to_show() -> bool: + return (G.AppRuns != 0 and G.AppRuns % 5 == 0) and !G.VersionChanged + +func _ready(): + if not has_billings and not shown: + shown = true + if _is_ready_to_show(): + call_deferred("popup_centered") + +func _billings_ready(): + if G.Billings.get_purchased_points() == 0 and not shown: + shown = true + if _is_ready_to_show(): + call_deferred("popup_centered") + +func _on_Button2_pressed(): + hide() + +func _on_Button_pressed(): + hide() + if has_billings: + get_parent().show_support_window() + else: + OS.shell_open("https://github.com/DmitriySalnikov/GodotRemote#godot-remote") diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/TouchInputManager.gd b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/TouchInputManager.gd new file mode 100644 index 0000000..7421bfe --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Scripts/TouchInputManager.gd @@ -0,0 +1,60 @@ +extends Node + +signal visibility_changed(_visible) + +var InputPopup : CustomPopupTextInput setget _set_input_popup + +var IsVisible : bool = false + +var _lines_titles : Dictionary = {} + +func _enter_tree(): + if not Engine.editor_hint: + get_tree().connect("node_added", self, "_node_added_to_scene") + get_tree().connect("node_removed", self, "_node_removed_from_scene") + +func hide(): + InputPopup.force_close = true + +func set_title(line : LineEdit, title : String): + if _lines_titles.has(line): + _lines_titles[line] = title + +func _node_added_to_scene(node : Node): + if G.IsMobile: + if node is LineEdit: + if not node.is_in_group("IgnoreTouchInput"): + _register_line_edit(node, "") + +func _node_removed_from_scene(node : Node): + if G.IsMobile: + if node is LineEdit: + if _lines_titles.has(node): + _lines_titles.erase(node) + +func _set_input_popup(val): + InputPopup = val + InputPopup.connect("visibility_changed", self, "_input_visibility_changed") + +func _input_visibility_changed(): + emit_signal("visibility_changed", InputPopup.visible) + IsVisible = InputPopup.visible + +func _register_line_edit(line : LineEdit, title : String): + if G.IsMobile: + line.focus_mode = Control.FOCUS_NONE + else: + line.focus_mode = Control.FOCUS_CLICK + #line.editable = false + line.connect("gui_input", self, "_on_touch_line_edit_gui_input", [line]) + + _lines_titles[line] = title + +func _on_touch_line_edit_gui_input(event : InputEvent, line : LineEdit): + if event is InputEventMouseButton: + if event.button_index == BUTTON_LEFT: + if not event.pressed and Rect2(Vector2(), line.rect_size).intersects(Rect2(event.position, Vector2())): + _show_touch_input(line) + +func _show_touch_input(line : LineEdit): + InputPopup.popup_text_edit(_lines_titles[line], line) diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/BoldSettings.tres b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/BoldSettings.tres new file mode 100644 index 0000000..7790997 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/BoldSettings.tres @@ -0,0 +1,8 @@ +[gd_resource type="DynamicFont" load_steps=2 format=2] + +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Fonts/Roboto-Bold.ttf" type="DynamicFontData" id=1] + +[resource] +size = 32 +use_filter = true +font_data = ExtResource( 1 ) diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/CustomTouchLineEdit.tres b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/CustomTouchLineEdit.tres new file mode 100644 index 0000000..00512d6 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/CustomTouchLineEdit.tres @@ -0,0 +1,13 @@ +[gd_resource type="StyleBoxFlat" format=2] + +[resource] +content_margin_left = 6.0 +content_margin_right = 6.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.135, 0.165, 0.1875, 1 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.1125, 0.1375, 0.15625, 1 ) diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/EmptySep.tres b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/EmptySep.tres new file mode 100644 index 0000000..a417515 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/EmptySep.tres @@ -0,0 +1,3 @@ +[gd_resource type="StyleBoxEmpty" format=2] + +[resource] diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/MainTheme.tres b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/MainTheme.tres new file mode 100644 index 0000000..0c305e9 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/MainTheme.tres @@ -0,0 +1,1634 @@ +[gd_resource type="Theme" load_steps=169 format=2] + +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Styles/NormalBold.tres" type="DynamicFont" id=1] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_toggle_off.png" type="Texture" id=2] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_spinbox_updown.png" type="Texture" id=3] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_toggle_on.png" type="Texture" id=4] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_slider_grabber_hl.png" type="Texture" id=5] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_slider_grabber.png" type="Texture" id=6] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Fonts/Roboto-Bold.ttf" type="DynamicFontData" id=7] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_option_arrow.png" type="Texture" id=8] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_radio_unchecked.png" type="Texture" id=9] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_arrow_right.png" type="Texture" id=10] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_checked.png" type="Texture" id=11] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_radio_checked.png" type="Texture" id=12] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_unchecked.png" type="Texture" id=13] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_hidden.png" type="Texture" id=14] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_visible.png" type="Texture" id=15] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_xray.png" type="Texture" id=16] +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon.png" type="Texture" id=17] + +[sub_resource type="StyleBoxFlat" id=1] +content_margin_left = 6.0 +content_margin_right = 6.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.162, 0.198, 0.225, 1 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.126, 0.154, 0.175, 1 ) + +[sub_resource type="StyleBoxFlat" id=2] +content_margin_left = 6.0 +content_margin_right = 6.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.135, 0.165, 0.1875, 1 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.11, 1, 0.6, 1 ) + +[sub_resource type="StyleBoxFlat" id=3] +content_margin_left = 6.0 +content_margin_right = 6.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.135, 0.165, 0.1875, 1 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.385, 0.415, 0.4375, 1 ) + +[sub_resource type="StyleBoxFlat" id=4] +content_margin_left = 6.0 +content_margin_right = 6.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.135, 0.165, 0.1875, 1 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.1125, 0.1375, 0.15625, 1 ) + +[sub_resource type="StyleBoxFlat" id=5] +content_margin_left = 6.0 +content_margin_right = 6.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.135, 0.165, 0.1875, 1 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.11, 1, 0.6, 1 ) + +[sub_resource type="Image" id=6] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 212, 212, 212, 0, 221, 221, 221, 0, 221, 221, 221, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 221, 221, 221, 0, 221, 221, 221, 0, 212, 212, 212, 0, 0, 0, 0, 0, 212, 212, 212, 0, 212, 212, 212, 6, 221, 221, 221, 30, 221, 221, 221, 46, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 46, 221, 221, 221, 30, 212, 212, 212, 6, 212, 212, 212, 0, 221, 221, 221, 0, 221, 221, 221, 30, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 30, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 45, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 60, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 45, 221, 221, 221, 0, 222, 222, 222, 0, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 105, 223, 223, 223, 243, 223, 223, 223, 105, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 105, 223, 223, 223, 248, 224, 224, 224, 255, 223, 223, 223, 186, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 220, 220, 220, 104, 223, 223, 223, 248, 224, 224, 224, 255, 223, 223, 223, 193, 225, 225, 225, 51, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 47, 222, 222, 222, 47, 217, 217, 217, 48, 224, 224, 224, 66, 222, 222, 222, 47, 222, 222, 222, 47, 220, 220, 220, 103, 223, 223, 223, 248, 224, 224, 224, 255, 223, 223, 223, 193, 220, 220, 220, 52, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 47, 217, 217, 217, 48, 223, 223, 223, 178, 222, 222, 222, 231, 220, 220, 220, 74, 222, 222, 222, 102, 223, 223, 223, 248, 224, 224, 224, 255, 222, 222, 222, 194, 220, 220, 220, 52, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 47, 219, 219, 219, 64, 223, 223, 223, 225, 224, 224, 224, 255, 224, 224, 224, 233, 223, 223, 223, 248, 224, 224, 224, 255, 222, 222, 222, 195, 220, 220, 220, 52, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 47, 222, 222, 222, 47, 218, 218, 218, 69, 223, 223, 223, 224, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 196, 220, 220, 220, 52, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 217, 217, 217, 68, 223, 223, 223, 224, 222, 222, 222, 196, 220, 220, 220, 52, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 0, 221, 221, 221, 0, 221, 221, 221, 45, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 224, 224, 224, 66, 221, 221, 221, 53, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 45, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 30, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 30, 221, 221, 221, 0, 212, 212, 212, 0, 212, 212, 212, 6, 221, 221, 221, 30, 221, 221, 221, 46, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 46, 221, 221, 221, 30, 212, 212, 212, 6, 212, 212, 212, 0, 0, 0, 0, 0, 212, 212, 212, 0, 221, 221, 221, 0, 221, 221, 221, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 221, 221, 221, 0, 221, 221, 221, 0, 212, 212, 212, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=7] +flags = 0 +flags = 0 +image = SubResource( 6 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=8] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 220, 220, 220, 0, 223, 223, 223, 0, 218, 218, 218, 0, 218, 218, 218, 0, 223, 223, 223, 0, 220, 220, 220, 0, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 167, 167, 167, 0, 127, 127, 127, 2, 220, 220, 220, 22, 223, 223, 223, 32, 218, 218, 218, 42, 218, 218, 218, 42, 223, 223, 223, 32, 220, 220, 220, 22, 127, 127, 127, 2, 167, 167, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 208, 208, 0, 208, 208, 208, 11, 223, 223, 223, 40, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 40, 208, 208, 208, 11, 208, 208, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 167, 167, 167, 0, 208, 208, 208, 11, 221, 221, 221, 46, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 46, 208, 208, 208, 11, 167, 167, 167, 0, 0, 0, 0, 0, 127, 127, 127, 0, 127, 127, 127, 2, 223, 223, 223, 40, 222, 222, 222, 47, 222, 222, 222, 47, 218, 218, 218, 69, 223, 223, 223, 184, 224, 224, 224, 233, 224, 224, 224, 233, 221, 221, 221, 184, 218, 218, 218, 69, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 40, 127, 127, 127, 2, 127, 127, 127, 0, 218, 218, 218, 0, 218, 218, 218, 21, 222, 222, 222, 47, 222, 222, 222, 47, 217, 217, 217, 68, 223, 223, 223, 238, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 238, 217, 217, 217, 68, 222, 222, 222, 47, 222, 222, 222, 47, 218, 218, 218, 21, 218, 218, 218, 0, 223, 223, 223, 0, 223, 223, 223, 32, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 179, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 179, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 32, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 41, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 230, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 230, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 41, 223, 223, 223, 0, 218, 218, 218, 0, 218, 218, 218, 42, 222, 222, 222, 47, 222, 222, 222, 47, 224, 224, 224, 234, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 230, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 41, 223, 223, 223, 0, 216, 216, 216, 0, 216, 216, 216, 33, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 181, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 180, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 32, 223, 223, 223, 0, 220, 220, 220, 0, 220, 220, 220, 22, 222, 222, 222, 47, 222, 222, 222, 47, 218, 218, 218, 69, 223, 223, 223, 238, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 238, 218, 218, 218, 69, 222, 222, 222, 47, 222, 222, 222, 47, 220, 220, 220, 22, 220, 220, 220, 0, 127, 127, 127, 0, 127, 127, 127, 2, 223, 223, 223, 40, 222, 222, 222, 47, 222, 222, 222, 47, 218, 218, 218, 69, 223, 223, 223, 184, 224, 224, 224, 233, 224, 224, 224, 233, 223, 223, 223, 184, 218, 218, 218, 69, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 40, 127, 127, 127, 2, 127, 127, 127, 0, 0, 0, 0, 0, 167, 167, 167, 0, 208, 208, 208, 11, 221, 221, 221, 46, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 46, 208, 208, 208, 11, 167, 167, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 208, 208, 0, 208, 208, 208, 11, 223, 223, 223, 40, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 40, 208, 208, 208, 11, 208, 208, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 167, 167, 167, 0, 127, 127, 127, 2, 220, 220, 220, 22, 223, 223, 223, 32, 218, 218, 218, 42, 218, 218, 218, 42, 223, 223, 223, 32, 220, 220, 220, 22, 127, 127, 127, 2, 167, 167, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 220, 220, 220, 0, 223, 223, 223, 0, 218, 218, 218, 0, 218, 218, 218, 0, 223, 223, 223, 0, 220, 220, 220, 0, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=9] +flags = 0 +flags = 0 +image = SubResource( 8 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=10] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 220, 220, 220, 0, 223, 223, 223, 0, 218, 218, 218, 0, 218, 218, 218, 0, 223, 223, 223, 0, 220, 220, 220, 0, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 167, 167, 167, 0, 127, 127, 127, 2, 220, 220, 220, 22, 223, 223, 223, 32, 218, 218, 218, 42, 218, 218, 218, 42, 223, 223, 223, 32, 220, 220, 220, 22, 127, 127, 127, 2, 167, 167, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 208, 208, 0, 208, 208, 208, 11, 223, 223, 223, 40, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 40, 208, 208, 208, 11, 208, 208, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 167, 167, 167, 0, 208, 208, 208, 11, 221, 221, 221, 46, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 46, 208, 208, 208, 11, 167, 167, 167, 0, 0, 0, 0, 0, 127, 127, 127, 0, 127, 127, 127, 2, 223, 223, 223, 40, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 40, 127, 127, 127, 2, 127, 127, 127, 0, 218, 218, 218, 0, 218, 218, 218, 21, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 218, 218, 218, 21, 218, 218, 218, 0, 223, 223, 223, 0, 223, 223, 223, 32, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 32, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 41, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 41, 223, 223, 223, 0, 218, 218, 218, 0, 218, 218, 218, 42, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 41, 223, 223, 223, 0, 216, 216, 216, 0, 216, 216, 216, 33, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 32, 223, 223, 223, 0, 220, 220, 220, 0, 220, 220, 220, 22, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 220, 220, 220, 22, 220, 220, 220, 0, 127, 127, 127, 0, 127, 127, 127, 2, 223, 223, 223, 40, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 40, 127, 127, 127, 2, 127, 127, 127, 0, 0, 0, 0, 0, 167, 167, 167, 0, 208, 208, 208, 11, 221, 221, 221, 46, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 46, 208, 208, 208, 11, 167, 167, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 208, 208, 0, 208, 208, 208, 11, 223, 223, 223, 40, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 223, 223, 223, 40, 208, 208, 208, 11, 208, 208, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 167, 167, 167, 0, 127, 127, 127, 2, 220, 220, 220, 22, 223, 223, 223, 32, 218, 218, 218, 42, 218, 218, 218, 42, 223, 223, 223, 32, 220, 220, 220, 22, 127, 127, 127, 2, 167, 167, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 220, 220, 220, 0, 223, 223, 223, 0, 218, 218, 218, 0, 218, 218, 218, 0, 223, 223, 223, 0, 220, 220, 220, 0, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=11] +flags = 0 +flags = 0 +image = SubResource( 10 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=12] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 212, 212, 212, 0, 221, 221, 221, 0, 221, 221, 221, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 221, 221, 221, 0, 221, 221, 221, 0, 212, 212, 212, 0, 0, 0, 0, 0, 212, 212, 212, 0, 212, 212, 212, 6, 221, 221, 221, 30, 221, 221, 221, 46, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 46, 221, 221, 221, 30, 212, 212, 212, 6, 212, 212, 212, 0, 221, 221, 221, 0, 221, 221, 221, 30, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 30, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 45, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 45, 221, 221, 221, 0, 222, 222, 222, 0, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 0, 221, 221, 221, 0, 221, 221, 221, 45, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 45, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 30, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 30, 221, 221, 221, 0, 212, 212, 212, 0, 212, 212, 212, 6, 221, 221, 221, 30, 221, 221, 221, 46, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 222, 222, 222, 47, 221, 221, 221, 46, 221, 221, 221, 30, 212, 212, 212, 6, 212, 212, 212, 0, 0, 0, 0, 0, 212, 212, 212, 0, 221, 221, 221, 0, 221, 221, 221, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 222, 222, 222, 0, 221, 221, 221, 0, 221, 221, 221, 0, 212, 212, 212, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=13] +flags = 0 +flags = 0 +image = SubResource( 12 ) +size = Vector2( 16, 16 ) + +[sub_resource type="StyleBoxFlat" id=14] +content_margin_left = 4.0 +content_margin_right = 4.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.135, 0.165, 0.1875, 1 ) +draw_center = false +border_color = Color( 0.1125, 0.1375, 0.15625, 1 ) + +[sub_resource type="Image" id=15] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "LumAlpha8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=16] +flags = 4 +flags = 4 +image = SubResource( 15 ) +size = Vector2( 16, 16 ) + +[sub_resource type="StyleBoxFlat" id=17] +content_margin_left = 6.0 +content_margin_right = 6.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.135, 0.165, 0.1875, 1 ) +draw_center = false +border_color = Color( 0.1125, 0.1375, 0.15625, 1 ) + +[sub_resource type="Image" id=18] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=19] +flags = 0 +flags = 0 +image = SubResource( 18 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=20] +data = { +"data": PoolByteArray( 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 85, 85, 86, 188, 0, 0, 3, 255, 0, 0, 2, 125, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 86, 86, 88, 188, 0, 0, 3, 255, 0, 0, 2, 126, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 88, 88, 89, 188, 0, 0, 3, 255, 0, 0, 2, 127, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 89, 89, 90, 188, 0, 0, 3, 255, 0, 0, 1, 128, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 92, 92, 93, 188, 0, 0, 3, 255, 0, 0, 1, 130, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 92, 92, 93, 188, 0, 0, 3, 255, 0, 0, 1, 130, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 93, 93, 94, 188, 0, 0, 3, 255, 0, 0, 1, 131, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 94, 94, 96, 188, 0, 0, 3, 255, 0, 0, 1, 132, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 96, 96, 97, 188, 0, 0, 3, 255, 0, 0, 1, 133, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 99, 101, 189, 0, 0, 3, 255, 0, 0, 1, 135, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 255, 0, 0, 1, 135, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 136, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=21] +flags = 0 +flags = 0 +image = SubResource( 20 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=22] +data = { +"data": PoolByteArray( 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=23] +flags = 0 +flags = 0 +image = SubResource( 22 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=24] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 223, 223, 223, 0, 223, 223, 223, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 60, 223, 223, 223, 202, 223, 223, 223, 201, 221, 221, 221, 60, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 200, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 199, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 223, 223, 223, 0, 223, 223, 223, 0, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 218, 222, 222, 222, 70, 222, 222, 222, 70, 223, 223, 223, 218, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 65, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 65, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=25] +flags = 0 +flags = 0 +image = SubResource( 24 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=26] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 180, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 180, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 70, 223, 223, 223, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 223, 223, 223, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 180, 223, 223, 223, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 223, 223, 223, 0, 223, 223, 223, 180, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 180, 223, 223, 223, 0, 0, 0, 0, 0, 223, 223, 223, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=27] +flags = 0 +flags = 0 +image = SubResource( 26 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=28] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 218, 218, 0, 222, 222, 222, 0, 222, 222, 222, 0, 218, 218, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 218, 218, 0, 218, 218, 218, 21, 222, 222, 222, 199, 222, 222, 222, 198, 218, 218, 218, 21, 218, 218, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 218, 218, 0, 218, 218, 218, 21, 223, 223, 223, 211, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 209, 218, 218, 218, 21, 217, 217, 217, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 217, 217, 217, 0, 218, 218, 218, 21, 223, 223, 223, 210, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 209, 216, 216, 216, 20, 215, 215, 215, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 216, 216, 0, 216, 216, 216, 20, 223, 223, 223, 209, 223, 223, 223, 254, 222, 222, 222, 206, 223, 223, 223, 254, 223, 223, 223, 251, 222, 222, 222, 207, 223, 223, 223, 254, 223, 223, 223, 209, 214, 214, 214, 19, 214, 214, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 193, 223, 223, 223, 254, 222, 222, 222, 206, 214, 214, 214, 19, 223, 223, 223, 254, 223, 223, 223, 249, 214, 214, 214, 19, 223, 223, 223, 208, 223, 223, 223, 254, 223, 223, 223, 193, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 176, 223, 223, 223, 192, 214, 214, 214, 19, 217, 217, 217, 0, 223, 223, 223, 254, 223, 223, 223, 249, 217, 217, 217, 0, 214, 214, 214, 19, 223, 223, 223, 192, 223, 223, 223, 176, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 0, 214, 214, 214, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 249, 223, 223, 223, 0, 214, 214, 214, 0, 223, 223, 223, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 249, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 176, 223, 223, 223, 176, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=29] +flags = 0 +flags = 0 +image = SubResource( 28 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=30] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 223, 223, 223, 0, 223, 223, 223, 98, 223, 223, 223, 177, 223, 223, 223, 228, 223, 223, 223, 228, 223, 223, 223, 177, 223, 223, 223, 98, 223, 223, 223, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 23, 223, 223, 223, 185, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 185, 221, 221, 221, 23, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 223, 223, 223, 185, 223, 223, 223, 254, 223, 223, 223, 225, 221, 221, 221, 83, 223, 223, 223, 24, 223, 223, 223, 24, 221, 221, 221, 84, 223, 223, 223, 225, 223, 223, 223, 254, 223, 223, 223, 185, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 94, 223, 223, 223, 254, 223, 223, 223, 225, 210, 210, 210, 17, 215, 215, 215, 0, 223, 223, 223, 0, 223, 223, 223, 0, 215, 215, 215, 0, 210, 210, 210, 17, 223, 223, 223, 225, 223, 223, 223, 254, 222, 222, 222, 94, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 174, 223, 223, 223, 254, 222, 222, 222, 87, 216, 216, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 216, 216, 0, 222, 222, 222, 87, 223, 223, 223, 254, 222, 222, 222, 174, 222, 222, 222, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 224, 223, 223, 223, 254, 223, 223, 223, 24, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 24, 223, 223, 223, 254, 223, 223, 223, 224, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 147, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 161, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 24, 223, 223, 223, 254, 223, 223, 223, 224, 223, 223, 223, 0, 212, 212, 212, 0, 212, 212, 212, 6, 223, 223, 223, 205, 223, 223, 223, 254, 223, 223, 223, 254, 222, 222, 222, 214, 204, 204, 204, 10, 204, 204, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 216, 216, 0, 222, 222, 222, 85, 223, 223, 223, 254, 223, 223, 223, 178, 223, 223, 223, 0, 0, 0, 0, 0, 214, 214, 214, 0, 217, 217, 217, 34, 223, 223, 223, 240, 223, 223, 223, 245, 218, 218, 218, 42, 211, 211, 211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 215, 215, 215, 0, 210, 210, 210, 17, 223, 223, 223, 224, 223, 223, 223, 254, 223, 223, 223, 96, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 219, 219, 219, 0, 221, 221, 221, 84, 223, 223, 223, 97, 220, 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 24, 221, 221, 221, 83, 223, 223, 223, 225, 223, 223, 223, 254, 223, 223, 223, 186, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 185, 221, 221, 221, 23, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 228, 223, 223, 223, 177, 221, 221, 221, 99, 222, 222, 222, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=31] +flags = 0 +flags = 0 +image = SubResource( 30 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=32] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 223, 223, 223, 0, 222, 222, 222, 0, 222, 222, 222, 0, 223, 223, 223, 0, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 218, 218, 0, 221, 221, 221, 0, 221, 221, 221, 92, 223, 223, 223, 185, 222, 222, 222, 231, 222, 222, 222, 231, 223, 223, 223, 186, 222, 222, 222, 95, 222, 222, 222, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 0, 218, 218, 218, 35, 222, 222, 222, 207, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 209, 223, 223, 223, 41, 220, 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 175, 175, 175, 0, 223, 223, 223, 32, 223, 223, 223, 226, 223, 223, 223, 254, 223, 223, 223, 225, 221, 221, 221, 83, 223, 223, 223, 24, 223, 223, 223, 24, 221, 221, 221, 84, 223, 223, 223, 225, 223, 223, 223, 254, 223, 223, 223, 228, 218, 218, 218, 35, 194, 194, 194, 0, 0, 0, 0, 0, 127, 127, 127, 0, 127, 127, 127, 2, 223, 223, 223, 213, 223, 223, 223, 254, 223, 223, 223, 225, 210, 210, 210, 17, 217, 217, 217, 0, 223, 223, 223, 0, 223, 223, 223, 0, 217, 217, 217, 0, 210, 210, 210, 17, 223, 223, 223, 225, 223, 223, 223, 254, 223, 223, 223, 217, 170, 170, 170, 3, 170, 170, 170, 0, 223, 223, 223, 0, 223, 223, 223, 89, 223, 223, 223, 254, 223, 223, 223, 254, 222, 222, 222, 87, 217, 217, 217, 0, 220, 220, 220, 59, 223, 223, 223, 200, 223, 223, 223, 200, 220, 220, 220, 59, 217, 217, 217, 0, 222, 222, 222, 87, 223, 223, 223, 254, 223, 223, 223, 254, 222, 222, 222, 93, 222, 222, 222, 0, 223, 223, 223, 0, 223, 223, 223, 209, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 24, 222, 222, 222, 0, 222, 222, 222, 198, 223, 223, 223, 254, 223, 223, 223, 254, 222, 222, 222, 198, 222, 222, 222, 0, 223, 223, 223, 24, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 209, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 209, 223, 223, 223, 254, 223, 223, 223, 254, 214, 214, 214, 19, 218, 218, 218, 0, 222, 222, 222, 199, 223, 223, 223, 254, 223, 223, 223, 254, 222, 222, 222, 199, 222, 222, 222, 0, 223, 223, 223, 24, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 209, 223, 223, 223, 0, 222, 222, 222, 0, 222, 222, 222, 94, 223, 223, 223, 254, 223, 223, 223, 254, 221, 221, 221, 84, 217, 217, 217, 0, 220, 220, 220, 59, 223, 223, 223, 201, 223, 223, 223, 200, 220, 220, 220, 59, 217, 217, 217, 0, 222, 222, 222, 85, 223, 223, 223, 254, 223, 223, 223, 254, 222, 222, 222, 94, 222, 222, 222, 0, 170, 170, 170, 0, 170, 170, 170, 3, 223, 223, 223, 222, 223, 223, 223, 254, 223, 223, 223, 224, 210, 210, 210, 17, 217, 217, 217, 0, 223, 223, 223, 0, 223, 223, 223, 0, 217, 217, 217, 0, 210, 210, 210, 17, 223, 223, 223, 224, 223, 223, 223, 254, 223, 223, 223, 222, 170, 170, 170, 3, 170, 170, 170, 0, 0, 0, 0, 0, 196, 196, 196, 0, 223, 223, 223, 41, 223, 223, 223, 232, 223, 223, 223, 254, 223, 223, 223, 225, 221, 221, 221, 83, 223, 223, 223, 24, 223, 223, 223, 24, 221, 221, 221, 83, 223, 223, 223, 225, 223, 223, 223, 254, 223, 223, 223, 232, 223, 223, 223, 41, 196, 196, 196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 220, 220, 220, 44, 223, 223, 223, 216, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 254, 223, 223, 223, 216, 220, 220, 220, 44, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 173, 173, 0, 127, 127, 127, 2, 223, 223, 223, 98, 222, 222, 222, 190, 223, 223, 223, 232, 223, 223, 223, 232, 222, 222, 222, 190, 223, 223, 223, 98, 127, 127, 127, 2, 173, 173, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 223, 223, 223, 0, 222, 222, 222, 0, 223, 223, 223, 0, 223, 223, 223, 0, 222, 222, 222, 0, 223, 223, 223, 0, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=33] +flags = 0 +flags = 0 +image = SubResource( 32 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=34] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 49, 0, 0, 0, 69, 0, 0, 0, 89, 0, 0, 0, 89, 0, 0, 0, 69, 0, 0, 0, 49, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 22, 22, 22, 102, 157, 157, 157, 175, 191, 191, 191, 208, 214, 214, 214, 239, 214, 214, 214, 239, 191, 191, 191, 208, 157, 157, 157, 175, 22, 22, 22, 102, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 101, 101, 101, 138, 211, 211, 211, 234, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 211, 211, 211, 234, 101, 101, 101, 138, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 100, 100, 100, 137, 223, 223, 223, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 254, 100, 100, 100, 137, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 14, 22, 22, 22, 101, 211, 211, 211, 233, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 210, 210, 210, 233, 22, 22, 22, 101, 0, 0, 0, 14, 0, 0, 0, 49, 153, 153, 153, 171, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 153, 153, 153, 171, 0, 0, 0, 49, 0, 0, 0, 68, 189, 189, 189, 206, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 189, 189, 189, 206, 0, 0, 0, 68, 0, 0, 0, 88, 212, 212, 212, 236, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 212, 212, 212, 236, 0, 0, 0, 88, 0, 0, 0, 88, 215, 215, 215, 239, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 212, 212, 212, 236, 0, 0, 0, 88, 0, 0, 0, 68, 192, 192, 192, 209, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 192, 192, 192, 208, 0, 0, 0, 68, 0, 0, 0, 49, 158, 158, 158, 174, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 158, 158, 158, 174, 0, 0, 0, 49, 0, 0, 0, 14, 22, 22, 22, 101, 212, 212, 212, 234, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 211, 211, 211, 234, 22, 22, 22, 101, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 43, 103, 103, 103, 138, 223, 223, 223, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 254, 103, 103, 103, 138, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 103, 103, 103, 138, 212, 212, 212, 234, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 211, 211, 211, 234, 101, 101, 101, 138, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 22, 22, 22, 102, 157, 157, 157, 175, 191, 191, 191, 208, 214, 214, 214, 239, 214, 214, 214, 239, 191, 191, 191, 208, 157, 157, 157, 175, 22, 22, 22, 102, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 49, 0, 0, 0, 69, 0, 0, 0, 89, 0, 0, 0, 89, 0, 0, 0, 69, 0, 0, 0, 49, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=35] +flags = 0 +flags = 0 +image = SubResource( 34 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=36] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 49, 0, 0, 0, 69, 0, 0, 0, 89, 0, 0, 0, 89, 0, 0, 0, 69, 0, 0, 0, 49, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 22, 22, 22, 102, 157, 157, 157, 175, 191, 191, 191, 208, 214, 214, 214, 239, 214, 214, 214, 239, 191, 191, 191, 208, 157, 157, 157, 175, 22, 22, 22, 102, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 101, 101, 101, 138, 211, 211, 211, 234, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 211, 211, 211, 234, 101, 101, 101, 138, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 100, 100, 100, 137, 223, 223, 223, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 254, 100, 100, 100, 137, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 14, 22, 22, 22, 101, 211, 211, 211, 233, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 210, 210, 210, 233, 22, 22, 22, 101, 0, 0, 0, 14, 0, 0, 0, 49, 153, 153, 153, 171, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 153, 153, 153, 171, 0, 0, 0, 49, 0, 0, 0, 68, 189, 189, 189, 206, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 189, 189, 189, 206, 0, 0, 0, 68, 0, 0, 0, 88, 212, 212, 212, 236, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 212, 212, 212, 236, 0, 0, 0, 88, 0, 0, 0, 88, 215, 215, 215, 239, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 212, 212, 212, 236, 0, 0, 0, 88, 0, 0, 0, 68, 192, 192, 192, 209, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 192, 192, 192, 208, 0, 0, 0, 68, 0, 0, 0, 49, 158, 158, 158, 174, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 158, 158, 158, 174, 0, 0, 0, 49, 0, 0, 0, 14, 22, 22, 22, 101, 212, 212, 212, 234, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 211, 211, 211, 234, 22, 22, 22, 101, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 43, 103, 103, 103, 138, 223, 223, 223, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 254, 103, 103, 103, 138, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 103, 103, 103, 138, 212, 212, 212, 234, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 211, 211, 211, 234, 101, 101, 101, 138, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 22, 22, 22, 102, 157, 157, 157, 175, 191, 191, 191, 208, 214, 214, 214, 239, 214, 214, 214, 239, 191, 191, 191, 208, 157, 157, 157, 175, 22, 22, 22, 102, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 49, 0, 0, 0, 69, 0, 0, 0, 89, 0, 0, 0, 89, 0, 0, 0, 69, 0, 0, 0, 49, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=37] +flags = 0 +flags = 0 +image = SubResource( 36 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=38] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 49, 0, 0, 0, 69, 0, 0, 0, 89, 0, 0, 0, 89, 0, 0, 0, 69, 0, 0, 0, 49, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 22, 22, 22, 102, 157, 157, 157, 175, 191, 191, 191, 208, 214, 214, 214, 239, 214, 214, 214, 239, 191, 191, 191, 208, 157, 157, 157, 175, 22, 22, 22, 102, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 101, 101, 101, 138, 211, 211, 211, 234, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 211, 211, 211, 234, 101, 101, 101, 138, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 100, 100, 100, 137, 223, 223, 223, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 254, 100, 100, 100, 137, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 14, 22, 22, 22, 101, 211, 211, 211, 233, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 201, 201, 201, 221, 78, 78, 78, 127, 112, 112, 112, 143, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 210, 210, 210, 233, 22, 22, 22, 101, 0, 0, 0, 14, 0, 0, 0, 49, 153, 153, 153, 171, 224, 224, 224, 255, 224, 224, 224, 255, 220, 220, 220, 250, 153, 153, 153, 171, 2, 2, 2, 101, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 153, 153, 153, 171, 0, 0, 0, 49, 0, 0, 0, 68, 189, 189, 189, 206, 224, 224, 224, 255, 224, 224, 224, 255, 189, 189, 189, 205, 0, 0, 0, 100, 2, 2, 2, 101, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 189, 189, 189, 206, 0, 0, 0, 68, 0, 0, 0, 88, 212, 212, 212, 236, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 152, 152, 152, 169, 201, 201, 201, 220, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 212, 212, 212, 236, 0, 0, 0, 88, 0, 0, 0, 88, 215, 215, 215, 239, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 212, 212, 212, 236, 0, 0, 0, 88, 0, 0, 0, 68, 192, 192, 192, 209, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 192, 192, 192, 208, 0, 0, 0, 68, 0, 0, 0, 49, 158, 158, 158, 174, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 158, 158, 158, 174, 0, 0, 0, 49, 0, 0, 0, 14, 22, 22, 22, 101, 212, 212, 212, 234, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 100, 0, 0, 0, 100, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 211, 211, 211, 234, 22, 22, 22, 101, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 43, 103, 103, 103, 138, 223, 223, 223, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 254, 103, 103, 103, 138, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 103, 103, 103, 138, 212, 212, 212, 234, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 211, 211, 211, 234, 101, 101, 101, 138, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 22, 22, 22, 102, 157, 157, 157, 175, 191, 191, 191, 208, 214, 214, 214, 239, 214, 214, 214, 239, 191, 191, 191, 208, 157, 157, 157, 175, 22, 22, 22, 102, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 49, 0, 0, 0, 69, 0, 0, 0, 89, 0, 0, 0, 89, 0, 0, 0, 69, 0, 0, 0, 49, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=39] +flags = 0 +flags = 0 +image = SubResource( 38 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=40] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 18, 255, 255, 255, 115, 255, 255, 255, 156, 255, 255, 255, 156, 255, 255, 255, 114, 255, 255, 255, 18, 255, 255, 255, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 160, 255, 255, 255, 174, 255, 255, 255, 174, 255, 255, 255, 174, 255, 255, 255, 174, 255, 255, 255, 160, 255, 255, 255, 17, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 255, 255, 255, 0, 255, 255, 255, 110, 255, 255, 255, 174, 255, 255, 255, 131, 255, 255, 255, 35, 255, 255, 255, 35, 255, 255, 255, 131, 255, 255, 255, 174, 255, 255, 255, 110, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 255, 255, 255, 0, 255, 255, 255, 153, 255, 255, 255, 174, 255, 255, 255, 34, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 34, 255, 255, 255, 174, 255, 255, 255, 153, 255, 255, 255, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 255, 255, 255, 0, 255, 255, 255, 174, 255, 255, 255, 174, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 174, 255, 255, 255, 174, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 255, 255, 255, 0, 255, 255, 255, 174, 255, 255, 255, 174, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 174, 255, 255, 255, 174, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 0, 224, 224, 224, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=41] +flags = 0 +flags = 0 +image = SubResource( 40 ) +size = Vector2( 16, 16 ) + +[sub_resource type="StyleBoxFlat" id=42] +content_margin_left = 4.0 +content_margin_right = 4.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.135, 0.165, 0.1875, 1 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.09, 0.11, 0.125, 1 ) + +[sub_resource type="Image" id=43] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 76, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 76, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 76, 255, 255, 255, 228, 255, 255, 255, 188, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 188, 255, 255, 255, 228, 255, 255, 255, 76, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 18, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 187, 255, 255, 255, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 187, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 18, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 185, 255, 255, 255, 17, 255, 255, 255, 17, 255, 255, 255, 186, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 190, 255, 255, 255, 229, 255, 255, 255, 185, 255, 255, 255, 185, 255, 255, 255, 229, 255, 255, 255, 189, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 191, 255, 255, 255, 229, 255, 255, 255, 229, 255, 255, 255, 190, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 187, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 187, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 18, 255, 255, 255, 19, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 186, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 185, 255, 255, 255, 229, 255, 255, 255, 189, 255, 255, 255, 19, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 189, 255, 255, 255, 229, 255, 255, 255, 185, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 76, 255, 255, 255, 229, 255, 255, 255, 190, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 190, 255, 255, 255, 229, 255, 255, 255, 76, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 77, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 77, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=44] +flags = 0 +flags = 0 +image = SubResource( 43 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=45] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 60, 255, 255, 255, 177, 255, 255, 255, 229, 255, 255, 255, 229, 255, 255, 255, 177, 255, 255, 255, 60, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 119, 255, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 119, 255, 255, 255, 0, 255, 255, 255, 59, 255, 255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255, 58, 255, 255, 255, 175, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 175, 255, 255, 255, 225, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 225, 255, 255, 255, 226, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 225, 255, 255, 255, 175, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 175, 255, 255, 255, 59, 255, 255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255, 59, 255, 255, 255, 0, 255, 255, 255, 119, 255, 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 255, 119, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 60, 255, 255, 255, 177, 255, 255, 255, 229, 255, 255, 255, 229, 255, 255, 255, 177, 255, 255, 255, 60, 255, 255, 255, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 10, +"mipmaps": false, +"width": 10 +} + +[sub_resource type="ImageTexture" id=46] +flags = 0 +flags = 0 +image = SubResource( 45 ) +size = Vector2( 10, 10 ) + +[sub_resource type="Image" id=47] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 105, 255, 255, 255, 105, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 105, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 105, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 105, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=48] +flags = 0 +flags = 0 +image = SubResource( 47 ) +size = Vector2( 16, 16 ) + +[sub_resource type="StyleBoxFlat" id=49] +content_margin_left = 28.0 +content_margin_right = 28.0 +content_margin_top = 24.0 +content_margin_bottom = 5.0 +bg_color = Color( 0, 0, 0, 0.9 ) +draw_center = false +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 1, 0.87, 0.4, 1 ) +shadow_color = Color( 1, 0.87, 0.4, 0.1 ) +shadow_size = 8 + +[sub_resource type="StyleBoxFlat" id=50] +content_margin_left = 28.0 +content_margin_right = 28.0 +content_margin_top = 24.0 +content_margin_bottom = 5.0 +bg_color = Color( 0, 0, 0, 0.3 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 1, 1, 1, 0.9 ) + +[sub_resource type="StyleBoxFlat" id=51] +content_margin_left = 28.0 +content_margin_right = 28.0 +content_margin_top = 24.0 +content_margin_bottom = 5.0 +bg_color = Color( 0, 0, 0, 0.4 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 1, 1, 1, 0.9 ) + +[sub_resource type="StyleBoxFlat" id=52] +content_margin_left = 28.0 +content_margin_right = 28.0 +content_margin_top = 24.0 +content_margin_bottom = 5.0 +bg_color = Color( 0, 0, 0, 0.7 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 1, 1, 1, 0.9 ) + +[sub_resource type="StyleBoxFlat" id=53] +content_margin_left = 28.0 +content_margin_right = 28.0 +content_margin_top = 24.0 +content_margin_bottom = 5.0 +bg_color = Color( 0, 0, 0, 0.9 ) +draw_center = false +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 1, 0.47, 0.42, 1 ) +shadow_color = Color( 1, 0.47, 0.42, 0.2 ) +shadow_size = 8 + +[sub_resource type="StyleBoxFlat" id=54] +content_margin_left = 28.0 +content_margin_right = 28.0 +content_margin_top = 24.0 +content_margin_bottom = 5.0 +bg_color = Color( 0, 0, 0, 0.9 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.11, 1, 0.6, 0.9 ) +shadow_color = Color( 0, 0, 0, 0.3 ) +shadow_size = 8 + +[sub_resource type="StyleBoxFlat" id=55] +content_margin_left = 28.0 +content_margin_right = 28.0 +content_margin_top = 24.0 +content_margin_bottom = 5.0 +bg_color = Color( 0, 0, 0, 0.7 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 1, 1, 1, 0.9 ) + +[sub_resource type="StyleBoxFlat" id=56] +content_margin_left = 28.0 +content_margin_right = 28.0 +content_margin_top = 24.0 +content_margin_bottom = 5.0 +bg_color = Color( 0, 0, 0, 0.9 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.11, 1, 0.6, 0.9 ) +shadow_color = Color( 0, 0, 0, 0.3 ) +shadow_size = 8 + +[sub_resource type="ImageTexture" id=57] + +[sub_resource type="Image" id=58] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 16, 255, 255, 255, 55, 255, 255, 255, 55, 255, 255, 255, 16, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 54, 255, 255, 255, 70, 255, 255, 255, 70, 255, 255, 255, 54, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 54, 255, 255, 255, 70, 255, 255, 255, 70, 255, 255, 255, 54, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 16, 255, 255, 255, 55, 255, 255, 255, 55, 255, 255, 255, 16, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 12, +"mipmaps": false, +"width": 12 +} + +[sub_resource type="ImageTexture" id=59] +flags = 0 +flags = 0 +image = SubResource( 58 ) +size = Vector2( 12, 12 ) + +[sub_resource type="StyleBoxTexture" id=60] +content_margin_left = 2.0 +content_margin_right = 2.0 +content_margin_top = 2.0 +content_margin_bottom = 2.0 +texture = SubResource( 59 ) +region_rect = Rect2( 0, 0, 12, 12 ) +margin_left = 6.0 +margin_right = 6.0 +margin_top = 6.0 +margin_bottom = 6.0 + +[sub_resource type="Image" id=61] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 191, 191, 0, 247, 247, 247, 0, 248, 248, 248, 0, 248, 248, 248, 0, 247, 247, 247, 0, 191, 191, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 191, 191, 0, 191, 191, 191, 4, 247, 247, 247, 98, 248, 248, 248, 167, 248, 248, 248, 167, 247, 247, 247, 98, 191, 191, 191, 4, 191, 191, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 247, 247, 0, 247, 247, 247, 97, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 247, 247, 247, 97, 247, 247, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 248, 248, 0, 248, 248, 248, 164, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 164, 248, 248, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 248, 248, 0, 248, 248, 248, 164, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 164, 248, 248, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 247, 247, 0, 247, 247, 247, 97, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 248, 248, 248, 186, 247, 247, 247, 97, 247, 247, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 191, 191, 0, 191, 191, 191, 4, 247, 247, 247, 98, 248, 248, 248, 167, 248, 248, 248, 167, 247, 247, 247, 98, 191, 191, 191, 4, 191, 191, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 191, 191, 0, 247, 247, 247, 0, 248, 248, 248, 0, 248, 248, 248, 0, 247, 247, 247, 0, 191, 191, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 12, +"mipmaps": false, +"width": 12 +} + +[sub_resource type="ImageTexture" id=62] +flags = 0 +flags = 0 +image = SubResource( 61 ) +size = Vector2( 12, 12 ) + +[sub_resource type="StyleBoxTexture" id=63] +content_margin_left = 2.0 +content_margin_right = 2.0 +content_margin_top = 2.0 +content_margin_bottom = 2.0 +texture = SubResource( 62 ) +region_rect = Rect2( 0, 0, 12, 12 ) +margin_left = 5.0 +margin_right = 5.0 +margin_top = 5.0 +margin_bottom = 5.0 + +[sub_resource type="Image" id=64] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 173, 173, 173, 0, 173, 173, 173, 0, 173, 173, 173, 0, 173, 173, 173, 0, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 127, 127, 127, 4, 173, 173, 173, 97, 173, 173, 173, 166, 173, 173, 173, 166, 173, 173, 173, 97, 127, 127, 127, 4, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 172, 172, 0, 172, 172, 172, 96, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 172, 172, 172, 96, 172, 172, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 173, 173, 0, 173, 173, 173, 163, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 163, 173, 173, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 173, 173, 0, 173, 173, 173, 163, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 163, 173, 173, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 172, 172, 0, 172, 172, 172, 96, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 173, 173, 173, 185, 172, 172, 172, 96, 172, 172, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 127, 127, 127, 4, 173, 173, 173, 97, 173, 173, 173, 166, 173, 173, 173, 166, 173, 173, 173, 97, 127, 127, 127, 4, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 0, 173, 173, 173, 0, 173, 173, 173, 0, 173, 173, 173, 0, 173, 173, 173, 0, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 12, +"mipmaps": false, +"width": 12 +} + +[sub_resource type="ImageTexture" id=65] +flags = 0 +flags = 0 +image = SubResource( 64 ) +size = Vector2( 12, 12 ) + +[sub_resource type="StyleBoxTexture" id=66] +content_margin_left = 2.0 +content_margin_right = 2.0 +content_margin_top = 2.0 +content_margin_bottom = 2.0 +texture = SubResource( 65 ) +region_rect = Rect2( 0, 0, 12, 12 ) +margin_left = 6.0 +margin_right = 6.0 +margin_top = 6.0 +margin_bottom = 6.0 + +[sub_resource type="Image" id=67] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 12, +"mipmaps": false, +"width": 12 +} + +[sub_resource type="ImageTexture" id=68] +flags = 0 +flags = 0 +image = SubResource( 67 ) +size = Vector2( 12, 12 ) + +[sub_resource type="StyleBoxTexture" id=69] +content_margin_left = 0.0 +content_margin_right = 0.0 +content_margin_top = 0.0 +content_margin_bottom = 0.0 +texture = SubResource( 68 ) +region_rect = Rect2( 0, 0, 12, 12 ) +margin_left = 5.0 +margin_right = 5.0 +margin_top = 5.0 +margin_bottom = 5.0 + +[sub_resource type="StyleBoxTexture" id=70] +content_margin_left = 0.0 +content_margin_right = 0.0 +content_margin_top = 0.0 +content_margin_bottom = 0.0 +texture = SubResource( 68 ) +region_rect = Rect2( 0, 0, 12, 12 ) +margin_left = 5.0 +margin_right = 5.0 +margin_top = 5.0 +margin_bottom = 5.0 + +[sub_resource type="StyleBoxLine" id=71] +color = Color( 1, 1, 1, 0.1 ) + +[sub_resource type="StyleBoxFlat" id=72] +content_margin_left = 0.0 +content_margin_right = 0.0 +content_margin_top = 2.0 +content_margin_bottom = 2.0 +bg_color = Color( 0.385, 0.415, 0.4375, 1 ) + +[sub_resource type="StyleBoxFlat" id=73] +content_margin_left = 0.0 +content_margin_right = 0.0 +content_margin_top = 2.0 +content_margin_bottom = 2.0 +bg_color = Color( 0.385, 0.415, 0.4375, 1 ) + +[sub_resource type="StyleBoxFlat" id=74] +content_margin_left = 0.0 +content_margin_right = 0.0 +content_margin_top = 2.0 +content_margin_bottom = 2.0 +bg_color = Color( 0.09, 0.11, 0.125, 1 ) + +[sub_resource type="Image" id=75] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 49, 255, 255, 255, 49, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 49, 255, 255, 255, 49, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 64, +"mipmaps": false, +"width": 8 +} + +[sub_resource type="ImageTexture" id=76] +flags = 0 +flags = 0 +image = SubResource( 75 ) +size = Vector2( 8, 64 ) + +[sub_resource type="StyleBoxTexture" id=77] +texture = SubResource( 16 ) +region_rect = Rect2( 0, 0, 16, 16 ) +margin_left = 1.0 +margin_right = 1.0 +margin_top = 1.0 +margin_bottom = 1.0 + +[sub_resource type="StyleBoxFlat" id=78] +content_margin_left = 4.0 +content_margin_right = 4.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.135, 0.165, 0.1875, 1 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.09, 0.11, 0.125, 1 ) + +[sub_resource type="StyleBoxFlat" id=79] +content_margin_left = 4.0 +content_margin_right = 4.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.18, 0.22, 0.25, 1 ) +draw_center = false +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.4875, 0.5125, 0.53125, 1 ) + +[sub_resource type="StyleBoxFlat" id=80] +content_margin_left = 4.0 +content_margin_right = 4.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.18, 0.22, 0.25, 1 ) +draw_center = false +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 1, 1, 1, 0.2 ) + +[sub_resource type="StyleBoxFlat" id=81] +content_margin_left = 4.0 +content_margin_right = 4.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 1, 1, 1, 0.2 ) +border_color = Color( 0.18, 0.22, 0.25, 1 ) + +[sub_resource type="StyleBoxFlat" id=82] +content_margin_left = 4.0 +content_margin_right = 4.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 1, 1, 1, 0.2 ) +border_color = Color( 0.18, 0.22, 0.25, 1 ) + +[sub_resource type="StyleBoxEmpty" id=83] +content_margin_left = 4.0 +content_margin_right = 4.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 + +[sub_resource type="Image" id=84] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 76, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 76, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 76, 255, 255, 255, 228, 255, 255, 255, 188, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 188, 255, 255, 255, 228, 255, 255, 255, 76, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 18, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 187, 255, 255, 255, 17, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 187, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 18, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 185, 255, 255, 255, 17, 255, 255, 255, 17, 255, 255, 255, 186, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 190, 255, 255, 255, 229, 255, 255, 255, 185, 255, 255, 255, 185, 255, 255, 255, 229, 255, 255, 255, 189, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 191, 255, 255, 255, 229, 255, 255, 255, 229, 255, 255, 255, 190, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 187, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 187, 255, 255, 255, 229, 255, 255, 255, 188, 255, 255, 255, 18, 255, 255, 255, 19, 255, 255, 255, 188, 255, 255, 255, 229, 255, 255, 255, 186, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 17, 255, 255, 255, 185, 255, 255, 255, 229, 255, 255, 255, 189, 255, 255, 255, 19, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 189, 255, 255, 255, 229, 255, 255, 255, 185, 255, 255, 255, 17, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 76, 255, 255, 255, 229, 255, 255, 255, 190, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 190, 255, 255, 255, 229, 255, 255, 255, 76, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 77, 255, 255, 255, 19, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 19, 255, 255, 255, 77, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=85] +flags = 0 +flags = 0 +image = SubResource( 84 ) +size = Vector2( 16, 16 ) + +[sub_resource type="StyleBoxFlat" id=86] +content_margin_left = 6.0 +content_margin_right = 6.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.135, 0.165, 0.1875, 1 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.1125, 0.1375, 0.15625, 1 ) + +[sub_resource type="StyleBoxFlat" id=87] +content_margin_left = 6.0 +content_margin_right = 6.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.135, 0.165, 0.1875, 1 ) + +[sub_resource type="StyleBoxFlat" id=88] +content_margin_left = 8.0 +content_margin_right = 8.0 +content_margin_top = 8.0 +content_margin_bottom = 8.0 +bg_color = Color( 0.18, 0.22, 0.25, 1 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.385, 0.415, 0.4375, 1 ) +shadow_color = Color( 0, 0, 0, 0.3 ) +shadow_size = 4 + +[sub_resource type="StyleBoxFlat" id=89] +content_margin_left = 6.0 +content_margin_right = 6.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.135, 0.165, 0.1875, 1 ) +border_color = Color( 0.1125, 0.1375, 0.15625, 1 ) + +[sub_resource type="StyleBoxLine" id=90] +color = Color( 1, 1, 1, 0.1 ) +grow_begin = 7.0 + +[sub_resource type="StyleBoxLine" id=91] +color = Color( 1, 1, 1, 0.1 ) +grow_end = 7.0 + +[sub_resource type="StyleBoxLine" id=92] +color = Color( 1, 1, 1, 0.1 ) +grow_begin = 7.0 +grow_end = 7.0 + +[sub_resource type="Image" id=93] +data = { +"data": PoolByteArray( 221, 221, 221, 23, 222, 222, 222, 78, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 222, 222, 222, 78, 221, 221, 221, 23, 221, 221, 221, 77, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 77, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 222, 222, 222, 78, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 222, 222, 222, 78, 221, 221, 221, 23, 222, 222, 222, 78, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 222, 222, 222, 78, 221, 221, 221, 23 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=94] +flags = 0 +flags = 0 +image = SubResource( 93 ) +size = Vector2( 16, 16 ) + +[sub_resource type="StyleBoxTexture" id=95] +content_margin_left = 0.0 +content_margin_right = 0.0 +content_margin_top = 0.0 +content_margin_bottom = 0.0 +texture = SubResource( 94 ) +region_rect = Rect2( 0, 0, 16, 16 ) +margin_left = 4.0 +margin_right = 4.0 +margin_top = 4.0 +margin_bottom = 4.0 + +[sub_resource type="Image" id=96] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 70, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 222, 222, 222, 70, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 70, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 221, 221, 221, 100, 222, 222, 222, 70, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 221, 221, 221, 0, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=97] +flags = 0 +flags = 0 +image = SubResource( 96 ) +size = Vector2( 16, 16 ) + +[sub_resource type="StyleBoxTexture" id=98] +content_margin_left = 2.0 +content_margin_right = 2.0 +content_margin_top = 1.0 +content_margin_bottom = 1.0 +texture = SubResource( 97 ) +region_rect = Rect2( 0, 0, 16, 16 ) +margin_left = 6.0 +margin_right = 6.0 +margin_top = 6.0 +margin_bottom = 6.0 + +[sub_resource type="StyleBoxFlat" id=99] +content_margin_left = 8.0 +content_margin_right = 8.0 +content_margin_top = 8.0 +content_margin_bottom = 8.0 +bg_color = Color( 0.1125, 0.1375, 0.15625, 1 ) +border_width_left = 1 +border_width_top = 24 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.1125, 0.1375, 0.15625, 1 ) +expand_margin_top = 24.0 +shadow_color = Color( 0, 0, 0, 0.3 ) +shadow_size = 4 + +[sub_resource type="StyleBoxEmpty" id=100] + +[sub_resource type="Image" id=101] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 212, 212, 212, 0, 222, 222, 222, 0, 221, 221, 221, 77, 223, 223, 223, 138, 223, 223, 223, 178, 223, 223, 223, 178, 223, 223, 223, 138, 221, 221, 221, 77, 222, 222, 222, 0, 212, 212, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 212, 212, 212, 0, 212, 212, 212, 18, 223, 223, 223, 145, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 145, 212, 212, 212, 18, 212, 212, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 145, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 181, 220, 220, 220, 44, 221, 221, 221, 54, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 145, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 74, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 181, 223, 223, 223, 32, 221, 221, 221, 0, 219, 219, 219, 43, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 74, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 136, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 181, 216, 216, 216, 33, 221, 221, 221, 0, 223, 223, 223, 32, 222, 222, 222, 181, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 136, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 175, 222, 222, 222, 199, 222, 222, 222, 199, 220, 220, 220, 44, 219, 219, 219, 0, 223, 223, 223, 32, 223, 223, 223, 180, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 175, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 179, 222, 222, 222, 199, 222, 222, 222, 199, 219, 219, 219, 43, 221, 221, 221, 0, 223, 223, 223, 32, 222, 222, 222, 181, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 175, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 140, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 181, 223, 223, 223, 32, 221, 221, 221, 0, 216, 216, 216, 33, 222, 222, 222, 181, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 139, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 76, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 180, 223, 223, 223, 32, 219, 219, 219, 0, 220, 220, 220, 44, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 221, 221, 221, 75, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 223, 223, 223, 145, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 180, 218, 218, 218, 42, 221, 221, 221, 54, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 145, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 214, 214, 214, 0, 214, 214, 214, 19, 223, 223, 223, 145, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 145, 212, 212, 212, 18, 212, 212, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 214, 214, 214, 0, 222, 222, 222, 0, 222, 222, 222, 78, 223, 223, 223, 138, 223, 223, 223, 178, 223, 223, 223, 178, 223, 223, 223, 138, 222, 222, 222, 78, 222, 222, 222, 0, 212, 212, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=102] +flags = 0 +flags = 0 +image = SubResource( 101 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=103] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 222, 222, 222, 0, 221, 221, 221, 99, 223, 223, 223, 178, 223, 223, 223, 229, 223, 223, 223, 229, 223, 223, 223, 178, 221, 221, 221, 99, 222, 222, 222, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 24, 223, 223, 223, 186, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 186, 223, 223, 223, 24, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 223, 223, 223, 186, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 233, 223, 223, 223, 57, 222, 222, 222, 70, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 186, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 95, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 233, 218, 218, 218, 42, 220, 220, 220, 0, 223, 223, 223, 56, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 95, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 175, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 233, 219, 219, 219, 43, 218, 218, 218, 0, 218, 218, 218, 42, 223, 223, 223, 232, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 175, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 225, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 57, 220, 220, 220, 0, 218, 218, 218, 42, 222, 222, 222, 231, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 225, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 230, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 56, 219, 219, 219, 0, 218, 218, 218, 42, 223, 223, 223, 233, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 225, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 180, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 232, 218, 218, 218, 42, 218, 218, 218, 0, 219, 219, 219, 43, 223, 223, 223, 233, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 179, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 98, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 231, 218, 218, 218, 42, 220, 220, 220, 0, 223, 223, 223, 57, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 97, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 187, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 231, 221, 221, 221, 54, 222, 222, 222, 70, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 187, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 214, 214, 214, 0, 214, 214, 214, 25, 223, 223, 223, 186, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 186, 223, 223, 223, 24, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 214, 214, 214, 0, 222, 222, 222, 0, 221, 221, 221, 100, 223, 223, 223, 178, 223, 223, 223, 229, 223, 223, 223, 229, 223, 223, 223, 178, 221, 221, 221, 100, 222, 222, 222, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=104] +flags = 0 +flags = 0 +image = SubResource( 103 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=105] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 212, 212, 212, 0, 222, 222, 222, 0, 221, 221, 221, 77, 223, 223, 223, 138, 223, 223, 223, 178, 223, 223, 223, 178, 223, 223, 223, 138, 221, 221, 221, 77, 222, 222, 222, 0, 212, 212, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 212, 212, 212, 0, 212, 212, 212, 18, 223, 223, 223, 145, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 145, 212, 212, 212, 18, 212, 212, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 145, 222, 222, 222, 199, 222, 222, 222, 199, 221, 221, 221, 54, 220, 220, 220, 44, 222, 222, 222, 181, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 145, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 74, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 219, 219, 219, 43, 221, 221, 221, 0, 223, 223, 223, 32, 222, 222, 222, 181, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 74, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 136, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 181, 223, 223, 223, 32, 221, 221, 221, 0, 216, 216, 216, 33, 222, 222, 222, 181, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 136, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 175, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 180, 223, 223, 223, 32, 219, 219, 219, 0, 220, 220, 220, 44, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 175, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 179, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 181, 223, 223, 223, 32, 221, 221, 221, 0, 219, 219, 219, 43, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 175, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 140, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 181, 223, 223, 223, 32, 223, 223, 223, 0, 223, 223, 223, 32, 222, 222, 222, 181, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 139, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 76, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 220, 220, 220, 44, 221, 221, 221, 0, 223, 223, 223, 32, 223, 223, 223, 180, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 221, 221, 221, 75, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 223, 223, 223, 145, 222, 222, 222, 199, 222, 222, 222, 199, 221, 221, 221, 54, 218, 218, 218, 42, 223, 223, 223, 180, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 145, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 214, 214, 214, 0, 214, 214, 214, 19, 223, 223, 223, 145, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 222, 222, 222, 199, 223, 223, 223, 145, 212, 212, 212, 18, 212, 212, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 214, 214, 214, 0, 222, 222, 222, 0, 222, 222, 222, 78, 223, 223, 223, 138, 223, 223, 223, 178, 223, 223, 223, 178, 223, 223, 223, 138, 222, 222, 222, 78, 222, 222, 222, 0, 212, 212, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=106] +flags = 0 +flags = 0 +image = SubResource( 105 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=107] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 222, 222, 222, 0, 221, 221, 221, 99, 223, 223, 223, 178, 223, 223, 223, 229, 223, 223, 223, 229, 223, 223, 223, 178, 221, 221, 221, 99, 222, 222, 222, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 24, 223, 223, 223, 186, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 186, 223, 223, 223, 24, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 223, 223, 223, 186, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 70, 223, 223, 223, 57, 223, 223, 223, 233, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 186, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 95, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 56, 220, 220, 220, 0, 218, 218, 218, 42, 223, 223, 223, 233, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 95, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 175, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 232, 218, 218, 218, 42, 218, 218, 218, 0, 219, 219, 219, 43, 223, 223, 223, 233, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 175, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 225, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 231, 218, 218, 218, 42, 220, 220, 220, 0, 223, 223, 223, 57, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 225, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 230, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 233, 218, 218, 218, 42, 219, 219, 219, 0, 223, 223, 223, 56, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 225, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 180, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 233, 218, 218, 218, 42, 218, 218, 218, 0, 218, 218, 218, 42, 223, 223, 223, 232, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 179, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 98, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 57, 220, 220, 220, 0, 218, 218, 218, 42, 222, 222, 222, 231, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 97, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 187, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 70, 222, 222, 222, 55, 222, 222, 222, 231, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 187, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 214, 214, 214, 0, 214, 214, 214, 25, 223, 223, 223, 186, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 186, 223, 223, 223, 24, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 214, 214, 214, 0, 222, 222, 222, 0, 221, 221, 221, 100, 223, 223, 223, 178, 223, 223, 223, 229, 223, 223, 223, 229, 223, 223, 223, 178, 221, 221, 221, 100, 222, 222, 222, 0, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 223, 223, 223, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=108] +flags = 0 +flags = 0 +image = SubResource( 107 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=109] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 23, 255, 255, 255, 78, 255, 255, 255, 78, 255, 255, 255, 23, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 78, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 78, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 78, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 78, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 23, 255, 255, 255, 79, 255, 255, 255, 78, 255, 255, 255, 23, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 23, 255, 255, 255, 78, 255, 255, 255, 78, 255, 255, 255, 23, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 78, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 78, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 78, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 78, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 23, 255, 255, 255, 79, 255, 255, 255, 78, 255, 255, 255, 23, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 23, 255, 255, 255, 78, 255, 255, 255, 78, 255, 255, 255, 23, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 78, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 78, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 78, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 78, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 23, 255, 255, 255, 79, 255, 255, 255, 78, 255, 255, 255, 23, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=110] +flags = 0 +flags = 0 +image = SubResource( 109 ) +size = Vector2( 16, 16 ) + +[sub_resource type="Image" id=111] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 60, 223, 223, 223, 201, 223, 223, 223, 201, 221, 221, 221, 60, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 199, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 199, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 200, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 200, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 60, 223, 223, 223, 202, 223, 223, 223, 201, 221, 221, 221, 60, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 223, 223, 223, 0, 223, 223, 223, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 223, 223, 223, 0, 223, 223, 223, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 60, 223, 223, 223, 201, 223, 223, 223, 201, 221, 221, 221, 60, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 199, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 199, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 200, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 200, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 60, 223, 223, 223, 202, 223, 223, 223, 201, 221, 221, 221, 60, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 223, 223, 223, 0, 223, 223, 223, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 223, 223, 223, 0, 223, 223, 223, 0, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 60, 223, 223, 223, 201, 223, 223, 223, 201, 221, 221, 221, 60, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 222, 222, 0, 222, 222, 222, 199, 224, 224, 224, 255, 224, 224, 224, 255, 222, 222, 222, 199, 222, 222, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 223, 223, 0, 223, 223, 223, 200, 224, 224, 224, 255, 224, 224, 224, 255, 223, 223, 223, 200, 223, 223, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 221, 221, 0, 221, 221, 221, 60, 223, 223, 223, 202, 223, 223, 223, 201, 221, 221, 221, 60, 221, 221, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id=112] +flags = 0 +flags = 0 +image = SubResource( 111 ) +size = Vector2( 16, 16 ) + +[sub_resource type="StyleBoxFlat" id=113] +content_margin_left = 5.0 +content_margin_right = 5.0 +content_margin_top = 5.0 +content_margin_bottom = 5.0 +bg_color = Color( 0.18, 0.22, 0.25, 1 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.09, 0.11, 0.125, 1 ) + +[sub_resource type="StyleBoxFlat" id=114] +content_margin_left = 10.0 +content_margin_right = 10.0 +content_margin_top = 5.0 +content_margin_bottom = 5.0 +bg_color = Color( 0.135, 0.165, 0.1875, 1 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_color = Color( 0.1125, 0.1375, 0.15625, 1 ) +expand_margin_bottom = 1.0 + +[sub_resource type="StyleBoxFlat" id=115] +content_margin_left = 10.0 +content_margin_right = 10.0 +content_margin_top = 5.0 +content_margin_bottom = 5.0 +bg_color = Color( 0.162, 0.198, 0.225, 1 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_color = Color( 0.126, 0.154, 0.175, 1 ) +expand_margin_bottom = 1.0 + +[sub_resource type="StyleBoxFlat" id=116] +content_margin_left = 10.0 +content_margin_right = 10.0 +content_margin_top = 5.0 +content_margin_bottom = 5.0 +bg_color = Color( 0.18, 0.22, 0.25, 1 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_color = Color( 0.09, 0.11, 0.125, 1 ) +expand_margin_bottom = 1.0 + +[sub_resource type="Image" id=117] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 56, 255, 255, 255, 72, 255, 255, 255, 7, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 7, 255, 255, 255, 72, 255, 255, 255, 56, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 66, 255, 255, 255, 100, 255, 255, 255, 82, 255, 255, 255, 7, 255, 255, 255, 7, 255, 255, 255, 82, 255, 255, 255, 100, 255, 255, 255, 66, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 8, 255, 255, 255, 82, 255, 255, 255, 100, 255, 255, 255, 81, 255, 255, 255, 81, 255, 255, 255, 100, 255, 255, 255, 82, 255, 255, 255, 8, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 8, 255, 255, 255, 82, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 82, 255, 255, 255, 8, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 8, 255, 255, 255, 72, 255, 255, 255, 72, 255, 255, 255, 8, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 12, +"mipmaps": false, +"width": 12 +} + +[sub_resource type="ImageTexture" id=118] +flags = 0 +flags = 0 +image = SubResource( 117 ) +size = Vector2( 12, 12 ) + +[sub_resource type="Image" id=119] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 56, 255, 255, 255, 72, 255, 255, 255, 7, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 66, 255, 255, 255, 100, 255, 255, 255, 82, 255, 255, 255, 7, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 8, 255, 255, 255, 82, 255, 255, 255, 100, 255, 255, 255, 81, 255, 255, 255, 7, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 8, 255, 255, 255, 82, 255, 255, 255, 100, 255, 255, 255, 66, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 7, 255, 255, 255, 82, 255, 255, 255, 100, 255, 255, 255, 66, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 7, 255, 255, 255, 81, 255, 255, 255, 100, 255, 255, 255, 82, 255, 255, 255, 8, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 66, 255, 255, 255, 100, 255, 255, 255, 82, 255, 255, 255, 8, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 56, 255, 255, 255, 72, 255, 255, 255, 8, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 12, +"mipmaps": false, +"width": 12 +} + +[sub_resource type="ImageTexture" id=120] +flags = 0 +flags = 0 +image = SubResource( 119 ) +size = Vector2( 12, 12 ) + +[sub_resource type="Image" id=121] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 14, 255, 255, 255, 14, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 13, 255, 255, 255, 49, 255, 255, 255, 49, 255, 255, 255, 13, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 14, 255, 255, 255, 49, 255, 255, 255, 49, 255, 255, 255, 13, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 14, 255, 255, 255, 14, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 8, +"mipmaps": false, +"width": 8 +} + +[sub_resource type="ImageTexture" id=122] +flags = 0 +flags = 0 +image = SubResource( 121 ) +size = Vector2( 8, 8 ) + +[sub_resource type="Image" id=123] +data = { +"data": PoolByteArray( 255, 255, 255, 35, 255, 255, 255, 38, 255, 255, 255, 3, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 50, 255, 255, 255, 50, 255, 255, 255, 38, 255, 255, 255, 50, 255, 255, 255, 41, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 50, 255, 255, 255, 50, 255, 255, 255, 4, 255, 255, 255, 41, 255, 255, 255, 50, 255, 255, 255, 40, 255, 255, 255, 3, 255, 255, 255, 0, 255, 255, 255, 50, 255, 255, 255, 50, 255, 255, 255, 0, 255, 255, 255, 4, 255, 255, 255, 41, 255, 255, 255, 50, 255, 255, 255, 37, 255, 255, 255, 0, 255, 255, 255, 50, 255, 255, 255, 50, 255, 255, 255, 0, 255, 255, 255, 3, 255, 255, 255, 41, 255, 255, 255, 50, 255, 255, 255, 38, 255, 255, 255, 0, 255, 255, 255, 50, 255, 255, 255, 50, 255, 255, 255, 3, 255, 255, 255, 41, 255, 255, 255, 50, 255, 255, 255, 41, 255, 255, 255, 4, 255, 255, 255, 0, 255, 255, 255, 50, 255, 255, 255, 50, 255, 255, 255, 37, 255, 255, 255, 50, 255, 255, 255, 41, 255, 255, 255, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 50, 255, 255, 255, 50, 255, 255, 255, 35, 255, 255, 255, 38, 255, 255, 255, 4, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 50, 255, 255, 255, 50 ), +"format": "RGBA8", +"height": 8, +"mipmaps": false, +"width": 8 +} + +[sub_resource type="ImageTexture" id=124] +flags = 0 +flags = 0 +image = SubResource( 123 ) +size = Vector2( 8, 8 ) + +[sub_resource type="StyleBoxFlat" id=125] +content_margin_left = 1.0 +content_margin_right = 1.0 +content_margin_top = 1.0 +content_margin_bottom = 1.0 +bg_color = Color( 1, 1, 1, 0.9 ) +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 1, 1, 1, 1 ) +shadow_color = Color( 0, 0, 0, 0.3 ) +shadow_size = 4 + +[sub_resource type="Image" id=126] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 84, 255, 255, 255, 108, 255, 255, 255, 11, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 11, 255, 255, 255, 108, 255, 255, 255, 84, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 100, 255, 255, 255, 150, 255, 255, 255, 123, 255, 255, 255, 11, 255, 255, 255, 11, 255, 255, 255, 123, 255, 255, 255, 150, 255, 255, 255, 100, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 12, 255, 255, 255, 123, 255, 255, 255, 150, 255, 255, 255, 122, 255, 255, 255, 122, 255, 255, 255, 150, 255, 255, 255, 123, 255, 255, 255, 12, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 12, 255, 255, 255, 123, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 123, 255, 255, 255, 12, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 12, 255, 255, 255, 109, 255, 255, 255, 108, 255, 255, 255, 12, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 14, +"mipmaps": false, +"width": 14 +} + +[sub_resource type="ImageTexture" id=127] +flags = 0 +flags = 0 +image = SubResource( 126 ) +size = Vector2( 14, 14 ) + +[sub_resource type="Image" id=128] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 11, 255, 255, 255, 115, 255, 255, 255, 114, 255, 255, 255, 11, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 11, 255, 255, 255, 123, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 123, 255, 255, 255, 11, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 11, 255, 255, 255, 122, 255, 255, 255, 150, 255, 255, 255, 123, 255, 255, 255, 123, 255, 255, 255, 150, 255, 255, 255, 122, 255, 255, 255, 11, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 113, 255, 255, 255, 150, 255, 255, 255, 123, 255, 255, 255, 12, 255, 255, 255, 12, 255, 255, 255, 123, 255, 255, 255, 150, 255, 255, 255, 113, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 105, 255, 255, 255, 115, 255, 255, 255, 12, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 12, 255, 255, 255, 115, 255, 255, 255, 105, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 105, 255, 255, 255, 114, 255, 255, 255, 11, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 11, 255, 255, 255, 115, 255, 255, 255, 105, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 114, 255, 255, 255, 150, 255, 255, 255, 123, 255, 255, 255, 11, 255, 255, 255, 11, 255, 255, 255, 123, 255, 255, 255, 150, 255, 255, 255, 114, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 12, 255, 255, 255, 123, 255, 255, 255, 150, 255, 255, 255, 122, 255, 255, 255, 122, 255, 255, 255, 150, 255, 255, 255, 123, 255, 255, 255, 12, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 12, 255, 255, 255, 123, 255, 255, 255, 150, 255, 255, 255, 150, 255, 255, 255, 123, 255, 255, 255, 12, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 12, 255, 255, 255, 116, 255, 255, 255, 115, 255, 255, 255, 12, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 14, +"mipmaps": false, +"width": 14 +} + +[sub_resource type="ImageTexture" id=129] +flags = 0 +flags = 0 +image = SubResource( 128 ) +size = Vector2( 14, 14 ) + +[sub_resource type="StyleBoxFlat" id=130] +content_margin_left = 4.0 +content_margin_right = 4.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.385, 0.415, 0.4375, 1 ) +border_color = Color( 0.18, 0.22, 0.25, 1 ) + +[sub_resource type="StyleBoxFlat" id=131] +content_margin_left = 4.0 +content_margin_right = 4.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.18, 0.22, 0.25, 1 ) +draw_center = false +border_width_left = 1 +border_width_top = 1 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.385, 0.415, 0.4375, 1 ) + +[sub_resource type="StyleBoxEmpty" id=132] + +[sub_resource type="StyleBoxEmpty" id=133] + +[sub_resource type="StyleBoxFlat" id=134] +content_margin_left = 4.0 +content_margin_right = 4.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 1, 1, 1, 0.08 ) +border_color = Color( 0.18, 0.22, 0.25, 1 ) + +[sub_resource type="StyleBoxFlat" id=135] +content_margin_left = 4.0 +content_margin_right = 4.0 +content_margin_top = 4.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.09, 0.11, 0.125, 1 ) +border_color = Color( 0.18, 0.22, 0.25, 1 ) + +[sub_resource type="StyleBoxTexture" id=136] +content_margin_left = 2.0 +content_margin_right = 2.0 +content_margin_top = 2.0 +content_margin_bottom = 2.0 +texture = SubResource( 59 ) +region_rect = Rect2( 0, 0, 12, 12 ) +margin_left = 6.0 +margin_right = 6.0 +margin_top = 6.0 +margin_bottom = 6.0 + +[sub_resource type="StyleBoxTexture" id=137] +content_margin_left = 2.0 +content_margin_right = 2.0 +content_margin_top = 2.0 +content_margin_bottom = 2.0 +texture = SubResource( 62 ) +region_rect = Rect2( 0, 0, 12, 12 ) +margin_left = 5.0 +margin_right = 5.0 +margin_top = 5.0 +margin_bottom = 5.0 + +[sub_resource type="StyleBoxTexture" id=138] +content_margin_left = 2.0 +content_margin_right = 2.0 +content_margin_top = 2.0 +content_margin_bottom = 2.0 +texture = SubResource( 65 ) +region_rect = Rect2( 0, 0, 12, 12 ) +margin_left = 6.0 +margin_right = 6.0 +margin_top = 6.0 +margin_bottom = 6.0 + +[sub_resource type="StyleBoxTexture" id=139] +content_margin_left = 0.0 +content_margin_right = 0.0 +content_margin_top = 0.0 +content_margin_bottom = 0.0 +texture = SubResource( 68 ) +region_rect = Rect2( 0, 0, 12, 12 ) +margin_left = 5.0 +margin_right = 5.0 +margin_top = 5.0 +margin_bottom = 5.0 + +[sub_resource type="StyleBoxTexture" id=140] +content_margin_left = 0.0 +content_margin_right = 0.0 +content_margin_top = 0.0 +content_margin_bottom = 0.0 +texture = SubResource( 68 ) +region_rect = Rect2( 0, 0, 12, 12 ) +margin_left = 5.0 +margin_right = 5.0 +margin_top = 5.0 +margin_bottom = 5.0 + +[sub_resource type="StyleBoxLine" id=141] +color = Color( 1, 1, 1, 0.1 ) +grow_begin = 0.0 +grow_end = 0.0 +vertical = true + +[sub_resource type="StyleBoxFlat" id=142] +content_margin_left = 2.0 +content_margin_right = 2.0 +content_margin_top = 0.0 +content_margin_bottom = 0.0 +bg_color = Color( 0.385, 0.415, 0.4375, 1 ) + +[sub_resource type="StyleBoxFlat" id=143] +content_margin_left = 2.0 +content_margin_right = 2.0 +content_margin_top = 0.0 +content_margin_bottom = 0.0 +bg_color = Color( 0.385, 0.415, 0.4375, 1 ) + +[sub_resource type="StyleBoxFlat" id=144] +content_margin_left = 2.0 +content_margin_right = 2.0 +content_margin_top = 0.0 +content_margin_bottom = 0.0 +bg_color = Color( 0.09, 0.11, 0.125, 1 ) + +[sub_resource type="Image" id=145] +data = { +"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 49, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 49, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 49, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 100, 255, 255, 255, 49, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), +"format": "RGBA8", +"height": 8, +"mipmaps": false, +"width": 64 +} + +[sub_resource type="ImageTexture" id=146] +flags = 0 +flags = 0 +image = SubResource( 145 ) +size = Vector2( 64, 8 ) + +[sub_resource type="Image" id=147] +data = { +"data": PoolByteArray( 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24 ), +"format": "RGBA8", +"height": 8, +"mipmaps": false, +"width": 8 +} + +[sub_resource type="ImageTexture" id=148] +flags = 0 +flags = 0 +image = SubResource( 147 ) +size = Vector2( 8, 8 ) + +[sub_resource type="StyleBoxTexture" id=149] +texture = SubResource( 148 ) +region_rect = Rect2( 0, 0, 8, 8 ) +margin_left = 1.0 +margin_right = 1.0 +margin_top = 1.0 +margin_bottom = 1.0 + +[sub_resource type="DynamicFont" id=150] +size = 40 +use_filter = true +font_data = ExtResource( 7 ) + +[sub_resource type="StyleBoxFlat" id=151] +content_margin_left = 8.0 +content_margin_right = 8.0 +content_margin_top = 8.0 +content_margin_bottom = 8.0 +bg_color = Color( 0.18, 0.22, 0.25, 1 ) +border_width_left = 1 +border_width_top = 24 +border_width_right = 1 +border_width_bottom = 1 +border_color = Color( 0.18, 0.22, 0.25, 1 ) +expand_margin_top = 35.0 +shadow_color = Color( 0, 0, 0, 0.3 ) +shadow_size = 4 + +[resource] +default_font = ExtResource( 1 ) +BoxContainer/constants/separation = 4 +Button/colors/font_color = Color( 0.795, 0.805, 0.8125, 1 ) +Button/colors/font_color_disabled = Color( 1, 1, 1, 0.3 ) +Button/colors/font_color_hover = Color( 0.877, 0.883, 0.8875, 1 ) +Button/colors/font_color_pressed = Color( 0.11, 1, 0.6, 1 ) +Button/colors/icon_color_hover = Color( 1.15, 1.15, 1.15, 1 ) +Button/colors/icon_color_pressed = Color( 0.1265, 1.15, 0.69, 1 ) +Button/styles/disabled = SubResource( 1 ) +Button/styles/focus = SubResource( 2 ) +Button/styles/hover = SubResource( 3 ) +Button/styles/normal = SubResource( 4 ) +Button/styles/pressed = SubResource( 5 ) +CheckBox/colors/font_color = Color( 0.795, 0.805, 0.8125, 1 ) +CheckBox/colors/font_color_disabled = Color( 1, 1, 1, 0.3 ) +CheckBox/colors/font_color_hover = Color( 0.877, 0.883, 0.8875, 1 ) +CheckBox/colors/font_color_pressed = Color( 0.11, 1, 0.6, 1 ) +CheckBox/colors/icon_color_hover = Color( 1.15, 1.15, 1.15, 1 ) +CheckBox/constants/check_vadjust = 0 +CheckBox/constants/hseparation = 4 +CheckBox/icons/checked = SubResource( 7 ) +CheckBox/icons/radio_checked = SubResource( 9 ) +CheckBox/icons/radio_unchecked = SubResource( 11 ) +CheckBox/icons/unchecked = SubResource( 13 ) +CheckBox/styles/disabled = SubResource( 14 ) +CheckBox/styles/hover = SubResource( 14 ) +CheckBox/styles/normal = SubResource( 14 ) +CheckBox/styles/pressed = SubResource( 14 ) +CheckButton/colors/font_color = Color( 0.795, 0.805, 0.8125, 1 ) +CheckButton/colors/font_color_disabled = Color( 1, 1, 1, 0.3 ) +CheckButton/colors/font_color_hover = Color( 0.877, 0.883, 0.8875, 1 ) +CheckButton/colors/font_color_pressed = Color( 0.11, 1, 0.6, 1 ) +CheckButton/colors/icon_color_hover = Color( 1.15, 1.15, 1.15, 1 ) +CheckButton/constants/check_vadjust = 0 +CheckButton/constants/hseparation = 4 +CheckButton/icons/off = ExtResource( 2 ) +CheckButton/icons/off_disabled = SubResource( 16 ) +CheckButton/icons/on = ExtResource( 4 ) +CheckButton/icons/on_disabled = SubResource( 16 ) +CheckButton/styles/disabled = SubResource( 17 ) +CheckButton/styles/hover = SubResource( 17 ) +CheckButton/styles/normal = SubResource( 17 ) +CheckButton/styles/pressed = SubResource( 17 ) +ColorPicker/constants/h_width = 30 +ColorPicker/constants/label_width = 10 +ColorPicker/constants/margin = 8 +ColorPicker/constants/sv_height = 256 +ColorPicker/constants/sv_width = 256 +ColorPicker/icons/add_preset = SubResource( 19 ) +ColorPicker/icons/overbright_indicator = SubResource( 21 ) +ColorPicker/icons/preset_bg = SubResource( 23 ) +ColorPicker/icons/screen_picker = SubResource( 25 ) +ColorPickerButton/icons/bg = SubResource( 23 ) +FileDialog/colors/files_disabled = Color( 1, 1, 1, 0.3 ) +FileDialog/colors/folder_icon_modulate = Color( 0.377, 1, 0.72, 1 ) +FileDialog/icons/folder = SubResource( 27 ) +FileDialog/icons/parent_folder = SubResource( 29 ) +FileDialog/icons/reload = SubResource( 31 ) +FileDialog/icons/toggle_hidden = SubResource( 33 ) +GraphEdit/colors/activity = Color( 0.11, 1, 0.6, 1 ) +GraphEdit/colors/grid_major = Color( 1, 1, 1, 0.15 ) +GraphEdit/colors/grid_minor = Color( 1, 1, 1, 0.07 ) +GraphEdit/colors/selection_fill = Color( 0.11, 1, 0.6, 0.3 ) +GraphEdit/colors/selection_stroke = Color( 0.11, 1, 0.6, 0.8 ) +GraphEdit/constants/bezier_len_neg = 160 +GraphEdit/constants/bezier_len_pos = 80 +GraphEdit/icons/minus = SubResource( 35 ) +GraphEdit/icons/more = SubResource( 37 ) +GraphEdit/icons/reset = SubResource( 39 ) +GraphEdit/icons/snap = SubResource( 41 ) +GraphEdit/styles/bg = SubResource( 42 ) +GraphNode/colors/close_color = Color( 1, 1, 1, 0.7 ) +GraphNode/colors/resizer_color = Color( 1, 1, 1, 0.7 ) +GraphNode/colors/title_color = Color( 1, 1, 1, 1 ) +GraphNode/constants/close_h_offset = 20 +GraphNode/constants/close_offset = 20 +GraphNode/constants/port_offset = 14 +GraphNode/constants/separation = 1 +GraphNode/constants/title_h_offset = -16 +GraphNode/constants/title_offset = 20 +GraphNode/icons/close = SubResource( 44 ) +GraphNode/icons/port = SubResource( 46 ) +GraphNode/icons/resizer = SubResource( 48 ) +GraphNode/styles/breakpoint = SubResource( 49 ) +GraphNode/styles/comment = SubResource( 50 ) +GraphNode/styles/commentfocus = SubResource( 51 ) +GraphNode/styles/frame = SubResource( 52 ) +GraphNode/styles/position = SubResource( 53 ) +GraphNode/styles/selectedframe = SubResource( 54 ) +GraphNode/styles/state_machine_frame = SubResource( 55 ) +GraphNode/styles/state_machine_selectedframe = SubResource( 56 ) +GridContainer/constants/hseparation = 4 +GridContainer/constants/vseparation = 4 +HBoxContainer/constants/separation = 4 +HScrollBar/icons/decrement = SubResource( 57 ) +HScrollBar/icons/decrement_highlight = SubResource( 57 ) +HScrollBar/icons/increment = SubResource( 57 ) +HScrollBar/icons/increment_highlight = SubResource( 57 ) +HScrollBar/styles/grabber = SubResource( 60 ) +HScrollBar/styles/grabber_highlight = SubResource( 63 ) +HScrollBar/styles/grabber_pressed = SubResource( 66 ) +HScrollBar/styles/scroll = SubResource( 69 ) +HScrollBar/styles/scroll_focus = SubResource( 70 ) +HSeparator/styles/separator = SubResource( 71 ) +HSlider/icons/grabber = ExtResource( 6 ) +HSlider/icons/grabber_highlight = ExtResource( 5 ) +HSlider/styles/grabber_area = SubResource( 72 ) +HSlider/styles/grabber_area_highlight = SubResource( 73 ) +HSlider/styles/slider = SubResource( 74 ) +HSplitContainer/constants/separation = 8 +HSplitContainer/icons/grabber = SubResource( 76 ) +HSplitContainer/styles/bg = SubResource( 77 ) +ItemList/colors/font_color = Color( 0.795, 0.805, 0.8125, 1 ) +ItemList/colors/font_color_selected = Color( 1, 1, 1, 1 ) +ItemList/colors/guide_color = Color( 1, 1, 1, 0.05 ) +ItemList/constants/hseparation = 3 +ItemList/constants/icon_margin = 4 +ItemList/constants/line_separation = 3 +ItemList/constants/vseparation = 3 +ItemList/styles/bg = SubResource( 78 ) +ItemList/styles/bg_focus = SubResource( 79 ) +ItemList/styles/cursor = SubResource( 80 ) +ItemList/styles/cursor_unfocused = SubResource( 80 ) +ItemList/styles/selected = SubResource( 81 ) +ItemList/styles/selected_focus = SubResource( 82 ) +Label/colors/font_color = Color( 0.795, 0.805, 0.8125, 1 ) +Label/colors/font_color_shadow = Color( 0, 0, 0, 0 ) +Label/constants/line_spacing = 3 +Label/constants/shadow_as_outline = 0 +Label/constants/shadow_offset_x = 1 +Label/constants/shadow_offset_y = 1 +Label/styles/normal = SubResource( 83 ) +LineEdit/colors/clear_button_color = Color( 0.795, 0.805, 0.8125, 1 ) +LineEdit/colors/clear_button_color_pressed = Color( 0.11, 1, 0.6, 1 ) +LineEdit/colors/cursor_color = Color( 0.795, 0.805, 0.8125, 1 ) +LineEdit/colors/font_color = Color( 0.795, 0.805, 0.8125, 1 ) +LineEdit/colors/font_color_selected = Color( 1, 1, 1, 1 ) +LineEdit/colors/read_only = Color( 1, 1, 1, 0.3 ) +LineEdit/colors/selection_color = Color( 0.11, 1, 0.6, 0.4 ) +LineEdit/icons/clear = SubResource( 85 ) +LineEdit/styles/focus = SubResource( 2 ) +LineEdit/styles/normal = SubResource( 86 ) +LineEdit/styles/read_only = SubResource( 1 ) +LinkButton/colors/font_color = Color( 0.795, 0.805, 0.8125, 1 ) +LinkButton/colors/font_color_disabled = Color( 1, 1, 1, 0.3 ) +LinkButton/colors/font_color_hover = Color( 0.877, 0.883, 0.8875, 1 ) +LinkButton/colors/font_color_pressed = Color( 0.11, 1, 0.6, 1 ) +LinkButton/styles/focus = SubResource( 83 ) +MarginContainer/constants/margin_bottom = 0 +MarginContainer/constants/margin_left = 0 +MarginContainer/constants/margin_right = 0 +MarginContainer/constants/margin_top = 0 +MenuButton/colors/font_color = Color( 0.795, 0.805, 0.8125, 1 ) +MenuButton/colors/font_color_hover = Color( 0.877, 0.883, 0.8875, 1 ) +MenuButton/styles/disabled = SubResource( 17 ) +MenuButton/styles/focus = SubResource( 17 ) +MenuButton/styles/hover = SubResource( 17 ) +MenuButton/styles/normal = SubResource( 17 ) +MenuButton/styles/pressed = SubResource( 17 ) +OptionButton/colors/font_color = Color( 0.795, 0.805, 0.8125, 1 ) +OptionButton/colors/font_color_disabled = Color( 1, 1, 1, 0.3 ) +OptionButton/colors/font_color_hover = Color( 0.877, 0.883, 0.8875, 1 ) +OptionButton/colors/font_color_pressed = Color( 0.11, 1, 0.6, 1 ) +OptionButton/colors/icon_color_hover = Color( 1.15, 1.15, 1.15, 1 ) +OptionButton/constants/arrow_margin = 4 +OptionButton/constants/hseparation = 4 +OptionButton/constants/modulate_arrow = 1 +OptionButton/icons/arrow = ExtResource( 8 ) +OptionButton/styles/disabled = SubResource( 1 ) +OptionButton/styles/focus = SubResource( 2 ) +OptionButton/styles/hover = SubResource( 3 ) +OptionButton/styles/normal = SubResource( 4 ) +OptionButton/styles/pressed = SubResource( 5 ) +Panel/styles/panel = SubResource( 87 ) +PanelContainer/styles/panel = SubResource( 17 ) +PopupDialog/styles/panel = SubResource( 88 ) +PopupMenu/colors/font_color = Color( 0.795, 0.805, 0.8125, 1 ) +PopupMenu/colors/font_color_accel = Color( 1, 1, 1, 0.3 ) +PopupMenu/colors/font_color_disabled = Color( 1, 1, 1, 0.3 ) +PopupMenu/colors/font_color_hover = Color( 0.877, 0.883, 0.8875, 1 ) +PopupMenu/constants/vseparation = 5 +PopupMenu/icons/checked = ExtResource( 11 ) +PopupMenu/icons/radio_checked = ExtResource( 12 ) +PopupMenu/icons/radio_unchecked = ExtResource( 9 ) +PopupMenu/icons/submenu = ExtResource( 10 ) +PopupMenu/icons/unchecked = ExtResource( 13 ) +PopupMenu/icons/visibility_hidden = ExtResource( 14 ) +PopupMenu/icons/visibility_visible = ExtResource( 15 ) +PopupMenu/icons/visibility_xray = ExtResource( 16 ) +PopupMenu/styles/disabled = SubResource( 17 ) +PopupMenu/styles/focus = SubResource( 17 ) +PopupMenu/styles/hover = SubResource( 89 ) +PopupMenu/styles/labeled_separator_left = SubResource( 90 ) +PopupMenu/styles/labeled_separator_right = SubResource( 91 ) +PopupMenu/styles/normal = SubResource( 17 ) +PopupMenu/styles/panel = SubResource( 88 ) +PopupMenu/styles/pressed = SubResource( 17 ) +PopupMenu/styles/separator = SubResource( 92 ) +PopupPanel/styles/panel = SubResource( 88 ) +ProgressBar/colors/font_color = Color( 0.795, 0.805, 0.8125, 1 ) +ProgressBar/styles/bg = SubResource( 95 ) +ProgressBar/styles/fg = SubResource( 98 ) +ProjectSettingsEditor/styles/panel = SubResource( 99 ) +RichTextLabel/colors/default_color = Color( 0.795, 0.805, 0.8125, 1 ) +RichTextLabel/colors/font_color_shadow = Color( 0, 0, 0, 0 ) +RichTextLabel/constants/shadow_as_outline = 0 +RichTextLabel/constants/shadow_offset_x = 1 +RichTextLabel/constants/shadow_offset_y = 1 +RichTextLabel/styles/focus = SubResource( 100 ) +RichTextLabel/styles/normal = SubResource( 42 ) +SpinBox/icons/updown = ExtResource( 3 ) +TabContainer/colors/font_color_bg = Color( 1, 1, 1, 0.3 ) +TabContainer/colors/font_color_fg = Color( 0.795, 0.805, 0.8125, 1 ) +TabContainer/constants/side_margin = 0 +TabContainer/icons/decrement = SubResource( 102 ) +TabContainer/icons/decrement_highlight = SubResource( 104 ) +TabContainer/icons/increment = SubResource( 106 ) +TabContainer/icons/increment_highlight = SubResource( 108 ) +TabContainer/icons/menu = SubResource( 110 ) +TabContainer/icons/menu_highlight = SubResource( 112 ) +TabContainer/styles/panel = SubResource( 113 ) +TabContainer/styles/tab_bg = SubResource( 114 ) +TabContainer/styles/tab_disabled = SubResource( 115 ) +TabContainer/styles/tab_fg = SubResource( 116 ) +Tabs/colors/font_color_bg = Color( 1, 1, 1, 0.3 ) +Tabs/colors/font_color_fg = Color( 0.795, 0.805, 0.8125, 1 ) +Tabs/constants/hseparation = 4 +Tabs/icons/close = SubResource( 85 ) +Tabs/icons/decrement = SubResource( 102 ) +Tabs/icons/decrement_highlight = SubResource( 104 ) +Tabs/icons/increment = SubResource( 106 ) +Tabs/icons/increment_highlight = SubResource( 108 ) +Tabs/styles/button = SubResource( 17 ) +Tabs/styles/button_pressed = SubResource( 17 ) +Tabs/styles/tab_bg = SubResource( 114 ) +Tabs/styles/tab_disabled = SubResource( 115 ) +Tabs/styles/tab_fg = SubResource( 116 ) +TextEdit/colors/caret_color = Color( 0.795, 0.805, 0.8125, 1 ) +TextEdit/colors/font_color = Color( 0.795, 0.805, 0.8125, 1 ) +TextEdit/colors/selection_color = Color( 0.11, 1, 0.6, 0.4 ) +TextEdit/icons/fold = SubResource( 118 ) +TextEdit/icons/folded = SubResource( 120 ) +TextEdit/icons/space = SubResource( 122 ) +TextEdit/icons/tab = SubResource( 124 ) +TextEdit/styles/focus = SubResource( 3 ) +TextEdit/styles/normal = SubResource( 4 ) +TextEdit/styles/read_only = SubResource( 1 ) +ToolButton/colors/font_color = Color( 0.795, 0.805, 0.8125, 1 ) +ToolButton/colors/font_color_hover = Color( 0.877, 0.883, 0.8875, 1 ) +ToolButton/colors/font_color_pressed = Color( 0.11, 1, 0.6, 1 ) +ToolButton/styles/disabled = SubResource( 17 ) +ToolButton/styles/focus = SubResource( 17 ) +ToolButton/styles/hover = SubResource( 17 ) +ToolButton/styles/normal = SubResource( 17 ) +ToolButton/styles/pressed = SubResource( 17 ) +TooltipLabel/colors/font_color = Color( 0.205, 0.195, 0.1875, 1 ) +TooltipLabel/colors/font_color_shadow = Color( 0, 0, 0, 0.1 ) +TooltipPanel/styles/panel = SubResource( 125 ) +Tree/colors/custom_button_font_highlight = Color( 0.877, 0.883, 0.8875, 1 ) +Tree/colors/drop_position_color = Color( 0.11, 1, 0.6, 1 ) +Tree/colors/font_color = Color( 0.795, 0.805, 0.8125, 1 ) +Tree/colors/font_color_selected = Color( 1, 1, 1, 1 ) +Tree/colors/guide_color = Color( 1, 1, 1, 0.05 ) +Tree/colors/relationship_line_color = Color( 1, 1, 1, 0.1 ) +Tree/colors/title_button_color = Color( 0.795, 0.805, 0.8125, 1 ) +Tree/constants/button_margin = 4 +Tree/constants/draw_guides = 0 +Tree/constants/draw_relationship_lines = 1 +Tree/constants/hseparation = 4 +Tree/constants/item_margin = 12 +Tree/constants/scroll_border = 40 +Tree/constants/scroll_speed = 12 +Tree/constants/vseparation = 4 +Tree/icons/arrow = SubResource( 118 ) +Tree/icons/arrow_collapsed = SubResource( 120 ) +Tree/icons/checked = SubResource( 7 ) +Tree/icons/select_arrow = SubResource( 127 ) +Tree/icons/unchecked = SubResource( 13 ) +Tree/icons/updown = SubResource( 129 ) +Tree/styles/bg = SubResource( 42 ) +Tree/styles/bg_focus = SubResource( 79 ) +Tree/styles/button_pressed = SubResource( 130 ) +Tree/styles/cursor = SubResource( 131 ) +Tree/styles/cursor_unfocused = SubResource( 131 ) +Tree/styles/custom_button = SubResource( 132 ) +Tree/styles/custom_button_hover = SubResource( 4 ) +Tree/styles/custom_button_pressed = SubResource( 133 ) +Tree/styles/hover = SubResource( 134 ) +Tree/styles/selected = SubResource( 81 ) +Tree/styles/selected_focus = SubResource( 82 ) +Tree/styles/title_button_hover = SubResource( 135 ) +Tree/styles/title_button_normal = SubResource( 135 ) +Tree/styles/title_button_pressed = SubResource( 135 ) +VBoxContainer/constants/separation = 4 +VScrollBar/icons/decrement = SubResource( 57 ) +VScrollBar/icons/decrement_highlight = SubResource( 57 ) +VScrollBar/icons/increment = SubResource( 57 ) +VScrollBar/icons/increment_highlight = SubResource( 57 ) +VScrollBar/styles/grabber = SubResource( 136 ) +VScrollBar/styles/grabber_highlight = SubResource( 137 ) +VScrollBar/styles/grabber_pressed = SubResource( 138 ) +VScrollBar/styles/scroll = SubResource( 139 ) +VScrollBar/styles/scroll_focus = SubResource( 140 ) +VSeparator/styles/separator = SubResource( 141 ) +VSlider/icons/grabber = ExtResource( 6 ) +VSlider/icons/grabber_highlight = ExtResource( 5 ) +VSlider/styles/grabber_area = SubResource( 142 ) +VSlider/styles/grabber_area_highlight = SubResource( 143 ) +VSlider/styles/slider = SubResource( 144 ) +VSplitContainer/constants/separation = 8 +VSplitContainer/icons/grabber = SubResource( 146 ) +VSplitContainer/styles/bg = SubResource( 149 ) +WindowDialog/colors/title_color = Color( 0.427451, 0.494118, 0.509804, 1 ) +WindowDialog/constants/close_h_ofs = 32 +WindowDialog/constants/close_v_ofs = 32 +WindowDialog/constants/title_height = 34 +WindowDialog/fonts/title_font = SubResource( 150 ) +WindowDialog/icons/close = ExtResource( 17 ) +WindowDialog/icons/close_highlight = ExtResource( 17 ) +WindowDialog/styles/panel = SubResource( 151 ) diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NormalBold.tres b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NormalBold.tres new file mode 100644 index 0000000..7790997 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NormalBold.tres @@ -0,0 +1,8 @@ +[gd_resource type="DynamicFont" load_steps=2 format=2] + +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Fonts/Roboto-Bold.ttf" type="DynamicFontData" id=1] + +[resource] +size = 32 +use_filter = true +font_data = ExtResource( 1 ) diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NormalBoldSmaller.tres b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NormalBoldSmaller.tres new file mode 100644 index 0000000..78c8a18 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NormalBoldSmaller.tres @@ -0,0 +1,8 @@ +[gd_resource type="DynamicFont" load_steps=2 format=2] + +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Fonts/Roboto-Bold.ttf" type="DynamicFontData" id=1] + +[resource] +size = 24 +use_filter = true +font_data = ExtResource( 1 ) diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NormalLight.tres b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NormalLight.tres new file mode 100644 index 0000000..10b6c8e --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NormalLight.tres @@ -0,0 +1,8 @@ +[gd_resource type="DynamicFont" load_steps=2 format=2] + +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Fonts/Roboto-Light.ttf" type="DynamicFontData" id=1] + +[resource] +size = 32 +use_filter = true +font_data = ExtResource( 1 ) diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NormalSettings.tres b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NormalSettings.tres new file mode 100644 index 0000000..10b6c8e --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NormalSettings.tres @@ -0,0 +1,8 @@ +[gd_resource type="DynamicFont" load_steps=2 format=2] + +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Fonts/Roboto-Light.ttf" type="DynamicFontData" id=1] + +[resource] +size = 32 +use_filter = true +font_data = ExtResource( 1 ) diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NotificationPanelStyle.tres b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NotificationPanelStyle.tres new file mode 100644 index 0000000..66a1fa7 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NotificationPanelStyle.tres @@ -0,0 +1,14 @@ +[gd_resource type="StyleBoxFlat" format=2] + +[resource] +content_margin_left = 4.0 +content_margin_right = 4.0 +content_margin_top = 5.0 +content_margin_bottom = 4.0 +bg_color = Color( 0.180392, 0.219608, 0.25098, 0.686275 ) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color( 0.384314, 0.415686, 0.439216, 0.686275 ) +shadow_size = 2 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NotificationPanelTextStyle.tres b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NotificationPanelTextStyle.tres new file mode 100644 index 0000000..2ef6722 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NotificationPanelTextStyle.tres @@ -0,0 +1,8 @@ +[gd_resource type="DynamicFont" load_steps=2 format=2] + +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Fonts/Roboto-Light.ttf" type="DynamicFontData" id=1] + +[resource] +size = 20 +use_filter = true +font_data = ExtResource( 1 ) diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NotificationPanelTitleStyle.tres b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NotificationPanelTitleStyle.tres new file mode 100644 index 0000000..9fc572a --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/NotificationPanelTitleStyle.tres @@ -0,0 +1,8 @@ +[gd_resource type="DynamicFont" load_steps=2 format=2] + +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Fonts/Roboto-Bold.ttf" type="DynamicFontData" id=1] + +[resource] +size = 20 +use_filter = true +font_data = ExtResource( 1 ) diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/VersionFont.tres b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/VersionFont.tres new file mode 100644 index 0000000..f1b91ee --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Styles/VersionFont.tres @@ -0,0 +1,8 @@ +[gd_resource type="DynamicFont" load_steps=2 format=2] + +[ext_resource path="res://AssetsInSuperSecureAndUn1queF0lder/Fonts/Roboto-Bold.ttf" type="DynamicFontData" id=1] + +[resource] +size = 22 +use_filter = true +font_data = ExtResource( 1 ) diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/ADB_icon.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/ADB_icon.png new file mode 100644 index 0000000..23149f6 Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/ADB_icon.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/ADB_icon.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/ADB_icon.png.import new file mode 100644 index 0000000..226c39c --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/ADB_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/ADB_icon.png-f64610e5a3509210952be800ae31a1e4.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/ADB_icon.png" +dest_files=[ "res://.import/ADB_icon.png-f64610e5a3509210952be800ae31a1e4.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Bug_icon.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Bug_icon.png new file mode 100644 index 0000000..39eef3d Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Bug_icon.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Bug_icon.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Bug_icon.png.import new file mode 100644 index 0000000..a0a709e --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Bug_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Bug_icon.png-25ad97a76f5f16692548174641cc308e.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Bug_icon.png" +dest_files=[ "res://.import/Bug_icon.png-25ad97a76f5f16692548174641cc308e.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon.png new file mode 100644 index 0000000..bafd2e0 Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon.png.import new file mode 100644 index 0000000..3ffadde --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Close_cross_icon.png-2b8a53bad18cd4eb8b24acdff511c4d2.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon.png" +dest_files=[ "res://.import/Close_cross_icon.png-2b8a53bad18cd4eb8b24acdff511c4d2.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon_48px.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon_48px.png new file mode 100644 index 0000000..b627cfc Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon_48px.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon_48px.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon_48px.png.import new file mode 100644 index 0000000..6db776e --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon_48px.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Close_cross_icon_48px.png-5c6b29014399c348976d5869abaf089d.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon_48px.png" +dest_files=[ "res://.import/Close_cross_icon_48px.png-5c6b29014399c348976d5869abaf089d.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon_64px.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon_64px.png.import new file mode 100644 index 0000000..30c635d --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Close_cross_icon_64px.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Close_cross_icon_64px.png-2f0c6dfc07e345f624b803758f0b6927.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Textures/Close_cross_icon_64px.png" +dest_files=[ "res://.import/Close_cross_icon_64px.png-2f0c6dfc07e345f624b803758f0b6927.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Connected_icon.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Connected_icon.png new file mode 100644 index 0000000..d7983bc Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Connected_icon.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Connected_icon.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Connected_icon.png.import new file mode 100644 index 0000000..1d80953 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Connected_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Connected_icon.png-a17b0edfbb071ce2e554244cda87abf4.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Connected_icon.png" +dest_files=[ "res://.import/Connected_icon.png-a17b0edfbb071ce2e554244cda87abf4.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Disconnected_icon.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Disconnected_icon.png new file mode 100644 index 0000000..d030686 Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Disconnected_icon.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Disconnected_icon.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Disconnected_icon.png.import new file mode 100644 index 0000000..799e364 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Disconnected_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Disconnected_icon.png-2073a7b7ae57dd3c7fa67653cfdc2c37.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Disconnected_icon.png" +dest_files=[ "res://.import/Disconnected_icon.png-2073a7b7ae57dd3c7fa67653cfdc2c37.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Error_icon.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Error_icon.png new file mode 100644 index 0000000..de3639d Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Error_icon.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Error_icon.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Error_icon.png.import new file mode 100644 index 0000000..8260f86 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Error_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Error_icon.png-c891f8a08ac15b6fd187eae295a8c1db.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Error_icon.png" +dest_files=[ "res://.import/Error_icon.png-c891f8a08ac15b6fd187eae295a8c1db.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Close_icon.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Close_icon.png new file mode 100644 index 0000000..fe3e4f0 Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Close_icon.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Close_icon.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Close_icon.png.import new file mode 100644 index 0000000..0c06d2f --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Close_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Close_icon.png-8a9b8b62cb23c1e46e9a7a44b7e4e6da.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Close_icon.png" +dest_files=[ "res://.import/Close_icon.png-8a9b8b62cb23c1e46e9a7a44b7e4e6da.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Connected_icon.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Connected_icon.png new file mode 100644 index 0000000..5e389c4 Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Connected_icon.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Connected_icon.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Connected_icon.png.import new file mode 100644 index 0000000..5e362cf --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Connected_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Connected_icon.png-37808d735f156c916de12ceef3364a30.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Connected_icon.png" +dest_files=[ "res://.import/Connected_icon.png-37808d735f156c916de12ceef3364a30.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Disconnected_icon.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Disconnected_icon.png new file mode 100644 index 0000000..d038080 Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Disconnected_icon.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Disconnected_icon.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Disconnected_icon.png.import new file mode 100644 index 0000000..0faae60 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Disconnected_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Disconnected_icon.png-2587c3db853f4786cc60dd070529e8f3.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Disconnected_icon.png" +dest_files=[ "res://.import/Disconnected_icon.png-2587c3db853f4786cc60dd070529e8f3.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Error_icon.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Error_icon.png new file mode 100644 index 0000000..269499b Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Error_icon.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Error_icon.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Error_icon.png.import new file mode 100644 index 0000000..46d2466 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Error_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Error_icon.png-c40e835a1c91f40bdf959cb14d64af58.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Error_icon.png" +dest_files=[ "res://.import/Error_icon.png-c40e835a1c91f40bdf959cb14d64af58.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Warning_icon.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Warning_icon.png new file mode 100644 index 0000000..e89c982 Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Warning_icon.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Warning_icon.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Warning_icon.png.import new file mode 100644 index 0000000..ffcbc17 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Warning_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Warning_icon.png-3a024a9b49433f368b4979b20837bf26.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Notifications/Warning_icon.png" +dest_files=[ "res://.import/Warning_icon.png-3a024a9b49433f368b4979b20837bf26.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/.gdignore b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/.gdignore new file mode 100644 index 0000000..e69de29 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_checked.svg b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_checked.svg new file mode 100644 index 0000000..8d00eca --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_checked.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_option_arrow.svg b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_option_arrow.svg new file mode 100644 index 0000000..28435e0 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_option_arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_radio_checked.svg b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_radio_checked.svg new file mode 100644 index 0000000..447b57f --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_radio_checked.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_radio_unchecked.svg b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_radio_unchecked.svg new file mode 100644 index 0000000..1e8117b --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_radio_unchecked.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_slider_grabber.svg b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_slider_grabber.svg new file mode 100644 index 0000000..dd751ea --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_slider_grabber.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_slider_grabber_hl.svg b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_slider_grabber_hl.svg new file mode 100644 index 0000000..90d6293 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_slider_grabber_hl.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_spinbox_updown.svg b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_spinbox_updown.svg new file mode 100644 index 0000000..a677672 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_spinbox_updown.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_toggle_off.svg b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_toggle_off.svg new file mode 100644 index 0000000..46f13d1 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_toggle_off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_toggle_on.svg b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_toggle_on.svg new file mode 100644 index 0000000..0316680 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_toggle_on.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_unchecked.svg b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_unchecked.svg new file mode 100644 index 0000000..9575422 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_unchecked.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_visibility_hidden.svg b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_visibility_hidden.svg new file mode 100644 index 0000000..1d1e61d --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_visibility_hidden.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_visibility_visible.svg b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_visibility_visible.svg new file mode 100644 index 0000000..2e56f57 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_visibility_visible.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_visibility_xray.svg b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_visibility_xray.svg new file mode 100644 index 0000000..241ff3e --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_GUI_visibility_xray.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_arrow_right.svg b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_arrow_right.svg new file mode 100644 index 0000000..7895158 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/SVG/icon_arrow_right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_checked.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_checked.png new file mode 100644 index 0000000..57d00f5 Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_checked.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_checked.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_checked.png.import new file mode 100644 index 0000000..e423317 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_checked.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon_GUI_checked.png-d01e7adbe0f40c71a4d22048a30104f5.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_checked.png" +dest_files=[ "res://.import/icon_GUI_checked.png-d01e7adbe0f40c71a4d22048a30104f5.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_option_arrow.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_option_arrow.png new file mode 100644 index 0000000..3a94eae Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_option_arrow.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_option_arrow.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_option_arrow.png.import new file mode 100644 index 0000000..589528f --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_option_arrow.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon_GUI_option_arrow.png-3fb49a98e8c66b69844ae98edd50a110.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_option_arrow.png" +dest_files=[ "res://.import/icon_GUI_option_arrow.png-3fb49a98e8c66b69844ae98edd50a110.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_radio_checked.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_radio_checked.png new file mode 100644 index 0000000..480fe7c Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_radio_checked.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_radio_checked.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_radio_checked.png.import new file mode 100644 index 0000000..e380843 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_radio_checked.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon_GUI_radio_checked.png-47c5731e0ae3a50c25593e1641bbb10a.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_radio_checked.png" +dest_files=[ "res://.import/icon_GUI_radio_checked.png-47c5731e0ae3a50c25593e1641bbb10a.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_radio_unchecked.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_radio_unchecked.png new file mode 100644 index 0000000..8d75e91 Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_radio_unchecked.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_radio_unchecked.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_radio_unchecked.png.import new file mode 100644 index 0000000..5785846 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_radio_unchecked.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon_GUI_radio_unchecked.png-cfd91c75057a2a0cd3f9086615cdb2b7.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_radio_unchecked.png" +dest_files=[ "res://.import/icon_GUI_radio_unchecked.png-cfd91c75057a2a0cd3f9086615cdb2b7.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_slider_grabber.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_slider_grabber.png new file mode 100644 index 0000000..6c7591f Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_slider_grabber.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_slider_grabber.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_slider_grabber.png.import new file mode 100644 index 0000000..b5f3164 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_slider_grabber.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon_GUI_slider_grabber.png-f487bfe424db12f8bd48824ae2255d0c.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_slider_grabber.png" +dest_files=[ "res://.import/icon_GUI_slider_grabber.png-f487bfe424db12f8bd48824ae2255d0c.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_slider_grabber_hl.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_slider_grabber_hl.png new file mode 100644 index 0000000..d59eb0a Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_slider_grabber_hl.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_slider_grabber_hl.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_slider_grabber_hl.png.import new file mode 100644 index 0000000..9700500 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_slider_grabber_hl.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon_GUI_slider_grabber_hl.png-c3853805fee0143eed7d8f06e1db90cf.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_slider_grabber_hl.png" +dest_files=[ "res://.import/icon_GUI_slider_grabber_hl.png-c3853805fee0143eed7d8f06e1db90cf.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_spinbox_updown.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_spinbox_updown.png new file mode 100644 index 0000000..5d25539 Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_spinbox_updown.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_spinbox_updown.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_spinbox_updown.png.import new file mode 100644 index 0000000..889e5a7 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_spinbox_updown.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon_GUI_spinbox_updown.png-1e1e758912b0b87cfdcc560abf40d1d2.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_spinbox_updown.png" +dest_files=[ "res://.import/icon_GUI_spinbox_updown.png-1e1e758912b0b87cfdcc560abf40d1d2.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_toggle_off.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_toggle_off.png new file mode 100644 index 0000000..f533c20 Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_toggle_off.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_toggle_off.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_toggle_off.png.import new file mode 100644 index 0000000..8e1fedc --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_toggle_off.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon_GUI_toggle_off.png-6fe17867fe7c2506ea5f8a7874c28226.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_toggle_off.png" +dest_files=[ "res://.import/icon_GUI_toggle_off.png-6fe17867fe7c2506ea5f8a7874c28226.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_toggle_on.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_toggle_on.png new file mode 100644 index 0000000..ca81bfd Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_toggle_on.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_toggle_on.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_toggle_on.png.import new file mode 100644 index 0000000..b54ec52 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_toggle_on.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon_GUI_toggle_on.png-696e47c3aece978aa5ebefa588af32dd.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_toggle_on.png" +dest_files=[ "res://.import/icon_GUI_toggle_on.png-696e47c3aece978aa5ebefa588af32dd.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_unchecked.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_unchecked.png new file mode 100644 index 0000000..01fa7dc Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_unchecked.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_unchecked.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_unchecked.png.import new file mode 100644 index 0000000..1cab874 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_unchecked.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon_GUI_unchecked.png-30f3022671e3605573ecb38a7226180a.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_unchecked.png" +dest_files=[ "res://.import/icon_GUI_unchecked.png-30f3022671e3605573ecb38a7226180a.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_hidden.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_hidden.png new file mode 100644 index 0000000..683cdb1 Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_hidden.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_hidden.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_hidden.png.import new file mode 100644 index 0000000..6f5f70d --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_hidden.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon_GUI_visibility_hidden.png-ed7da31f63f771d64b460f697fe204ac.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_hidden.png" +dest_files=[ "res://.import/icon_GUI_visibility_hidden.png-ed7da31f63f771d64b460f697fe204ac.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_visible.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_visible.png new file mode 100644 index 0000000..90a3b07 Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_visible.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_visible.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_visible.png.import new file mode 100644 index 0000000..8263086 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_visible.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon_GUI_visibility_visible.png-9dad7b05674846791e4c3150fbdeff99.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_visible.png" +dest_files=[ "res://.import/icon_GUI_visibility_visible.png-9dad7b05674846791e4c3150fbdeff99.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_xray.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_xray.png new file mode 100644 index 0000000..7add4dc Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_xray.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_xray.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_xray.png.import new file mode 100644 index 0000000..f7bce39 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_xray.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon_GUI_visibility_xray.png-65cf1ac7fc82b1edb4b706697307486f.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_GUI_visibility_xray.png" +dest_files=[ "res://.import/icon_GUI_visibility_xray.png-65cf1ac7fc82b1edb4b706697307486f.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_arrow_right.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_arrow_right.png new file mode 100644 index 0000000..836065e Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_arrow_right.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_arrow_right.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_arrow_right.png.import new file mode 100644 index 0000000..3e92e74 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_arrow_right.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon_arrow_right.png-33999948619bc39c67e65867487a7934.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Theme/icon_arrow_right.png" +dest_files=[ "res://.import/icon_arrow_right.png-33999948619bc39c67e65867487a7934.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Warning_icon.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Warning_icon.png new file mode 100644 index 0000000..825567a Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Warning_icon.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Warning_icon.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Warning_icon.png.import new file mode 100644 index 0000000..f9b91ee --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/Warning_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Warning_icon.png-3d707fd0f388bf3bea43c63b030df952.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/Warning_icon.png" +dest_files=[ "res://.import/Warning_icon.png-3d707fd0f388bf3bea43c63b030df952.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/WiFi_icon.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/WiFi_icon.png new file mode 100644 index 0000000..9e4c636 Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/WiFi_icon.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/WiFi_icon.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/WiFi_icon.png.import new file mode 100644 index 0000000..7f0f556 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/WiFi_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/WiFi_icon.png-c824b06ebbc83aa329879f0b60ca7b48.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/WiFi_icon.png" +dest_files=[ "res://.import/WiFi_icon.png-c824b06ebbc83aa329879f0b60ca7b48.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/tap_screen.png b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/tap_screen.png new file mode 100644 index 0000000..1924bec Binary files /dev/null and b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/tap_screen.png differ diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/tap_screen.png.import b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/tap_screen.png.import new file mode 100644 index 0000000..4c18088 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/Textures/tap_screen.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/tap_screen.png-ac8a89fa659fab3cf5b03ef32382532e.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://AssetsInSuperSecureAndUn1queF0lder/Textures/tap_screen.png" +dest_files=[ "res://.import/tap_screen.png-ac8a89fa659fab3cf5b03ef32382532e.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/default_env.tres b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/default_env.tres new file mode 100644 index 0000000..4f63af5 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/AssetsInSuperSecureAndUn1queF0lder/default_env.tres @@ -0,0 +1,3 @@ +[gd_resource type="Environment" format=2] + +[resource] diff --git a/modules/godot_remote/godot_remote_client/project.godot b/modules/godot_remote/godot_remote_client/project.godot new file mode 100644 index 0000000..18d8195 --- /dev/null +++ b/modules/godot_remote/godot_remote_client/project.godot @@ -0,0 +1,63 @@ +; 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=4 + +_global_script_classes=[ { +"base": "Control", +"class": "CustomPopupTextInput", +"language": "GDScript", +"path": "res://AssetsInSuperSecureAndUn1queF0lder/Scripts/CustomPopupTextInput.gd" +} ] +_global_script_class_icons={ +"CustomPopupTextInput": "" +} + +[application] + +config/name="Godot Remote" +run/main_scene="res://AssetsInSuperSecureAndUn1queF0lder/Scenes/GUI.tscn" +config/icon="res://AssetsInSuperSecureAndUn1queF0lder/Icon.png" + +[autoload] + +C="*res://AssetsInSuperSecureAndUn1queF0lder/Scripts/Constants.gd" +G="*res://AssetsInSuperSecureAndUn1queF0lder/Scripts/Global.gd" +TIM="*res://AssetsInSuperSecureAndUn1queF0lder/Scripts/TouchInputManager.gd" +JoyMappings="*res://AssetsInSuperSecureAndUn1queF0lder/Scripts/JoyMappings.gd" + +[debug] + +settings/stdout/verbose_stdout=true +gdscript/warnings/return_value_discarded=false +godot_remote/general/autostart=false +godot_remote/notifications/notifications_duration=4.5 + +[display] + +window/size/width=800 +window/size/height=800 +window/size/test_width=1365 +window/size/test_height=800 +window/vsync/vsync_via_compositor=true +window/handheld/orientation="sensor" +window/stretch/mode="2d" +window/stretch/aspect="expand" + +[network] + +limits/tcp/connect_timeout_seconds=1 + +[rendering] + +quality/driver/driver_name="GLES2" +threads/thread_model=2 +vram_compression/import_etc=true +vram_compression/import_etc2=false +environment/default_environment="res://AssetsInSuperSecureAndUn1queF0lder/default_env.tres" +environment/default_clear_color.standalone=Color( 0, 0, 0, 1 ) diff --git a/modules/godot_remote/jni/Application.mk b/modules/godot_remote/jni/Application.mk new file mode 100644 index 0000000..502c699 --- /dev/null +++ b/modules/godot_remote/jni/Application.mk @@ -0,0 +1,10 @@ +# Application.mk +APP_STL := c++_static + +APP_ABI := all +#APP_ABI := arm64-v8a + +APP_DEBUG := true + +APP_CFLAGS := \ +-DGDNATIVE_LIBRARY \ No newline at end of file diff --git a/modules/godot_remote/place api.json here b/modules/godot_remote/place api.json here new file mode 100644 index 0000000..e69de29 diff --git a/omgeving/Floor.tres b/omgeving/Floor.tres new file mode 100644 index 0000000..d6e402e --- /dev/null +++ b/omgeving/Floor.tres @@ -0,0 +1,56 @@ +[gd_resource type="TileSet" load_steps=5 format=2] + +[ext_resource path="res://pictures/tileset_images/TilesetGodotVloer.png" type="Texture" id=1] + + + +[sub_resource type="ConcavePolygonShape2D" id=1] +segments = PoolVector2Array( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) + +[sub_resource type="ConvexPolygonShape2D" id=2] +points = PoolVector2Array( 0, 0, 32, 0, 32, 0, 0, 0 ) + +[sub_resource type="ConvexPolygonShape2D" id=3] +points = PoolVector2Array( 0, 0, 32, 0, 32, 0, 0, 0 ) + +[resource] +0/name = "Floor 0" +0/texture = ExtResource( 1 ) +0/tex_offset = Vector2( 0, 0 ) +0/modulate = Color( 1, 1, 1, 1 ) +0/region = Rect2( 0, 0, 2496, 32 ) +0/tile_mode = 2 +0/autotile/icon_coordinate = Vector2( 0, 0 ) +0/autotile/tile_size = Vector2( 32, 32 ) +0/autotile/spacing = 0 +0/autotile/occluder_map = [ ] +0/autotile/navpoly_map = [ ] +0/autotile/priority_map = [ ] +0/autotile/z_index_map = [ ] +0/occluder_offset = Vector2( 0, 0 ) +0/navigation_offset = Vector2( 0, 0 ) +0/shape_offset = Vector2( 0, 0 ) +0/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +0/shape = SubResource( 1 ) +0/shape_one_way = false +0/shape_one_way_margin = 1.0 +0/shapes = [ { +"autotile_coord": Vector2( 39, 0 ), +"one_way": false, +"one_way_margin": 1.0, +"shape": SubResource( 1 ), +"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 ) +}, { +"autotile_coord": Vector2( 39, 0 ), +"one_way": false, +"one_way_margin": 1.0, +"shape": SubResource( 2 ), +"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 ) +}, { +"autotile_coord": Vector2( 40, 0 ), +"one_way": false, +"one_way_margin": 1.0, +"shape": SubResource( 3 ), +"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 ) +} ] +0/z_index = 0 diff --git a/pictures/tileset_images/TilesetGodotVloer.png b/pictures/tileset_images/TilesetGodotVloer.png new file mode 100644 index 0000000..2a27e30 Binary files /dev/null and b/pictures/tileset_images/TilesetGodotVloer.png differ diff --git a/pictures/tileset_images/TilesetGodotVloer.png.import b/pictures/tileset_images/TilesetGodotVloer.png.import new file mode 100644 index 0000000..6c19115 --- /dev/null +++ b/pictures/tileset_images/TilesetGodotVloer.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/TilesetGodotVloer.png-2e66900e5d210b7c82ab6bb578fc651f.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://pictures/tileset_images/TilesetGodotVloer.png" +dest_files=[ "res://.import/TilesetGodotVloer.png-2e66900e5d210b7c82ab6bb578fc651f.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/pictures/tileset_images/interaction_map.png b/pictures/tileset_images/interaction_map.png new file mode 100644 index 0000000..da29039 Binary files /dev/null and b/pictures/tileset_images/interaction_map.png differ diff --git a/pictures/tileset_images/interaction_map.png.import b/pictures/tileset_images/interaction_map.png.import new file mode 100644 index 0000000..95bd087 --- /dev/null +++ b/pictures/tileset_images/interaction_map.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/interaction_map.png-337b1745c7c0aa5b0f3ad144fd106a05.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://pictures/tileset_images/interaction_map.png" +dest_files=[ "res://.import/interaction_map.png-337b1745c7c0aa5b0f3ad144fd106a05.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/pictures/tileset_images/vegetation.png b/pictures/tileset_images/vegetation.png new file mode 100644 index 0000000..78ae8dc Binary files /dev/null and b/pictures/tileset_images/vegetation.png differ diff --git a/pictures/tileset_images/vegetation.png.import b/pictures/tileset_images/vegetation.png.import new file mode 100644 index 0000000..607665a --- /dev/null +++ b/pictures/tileset_images/vegetation.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/vegetation.png-38fb7e420053644e9b92d0341dd0fa99.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://pictures/tileset_images/vegetation.png" +dest_files=[ "res://.import/vegetation.png-38fb7e420053644e9b92d0341dd0fa99.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/project.godot b/project.godot index 8ff733a..8a39e63 100644 --- a/project.godot +++ b/project.godot @@ -105,6 +105,11 @@ open_inventory={ pointing/emulate_touch_from_mouse=true +[rendering] + +quality/driver/driver_name="GLES2" +vram_compression/import_etc=true + [tiled_importer] enable_json_format=true diff --git a/river_intersection_home2.tscn b/river_intersection_home2.tscn index 347a03d..f13fcad 100644 --- a/river_intersection_home2.tscn +++ b/river_intersection_home2.tscn @@ -1,11 +1,11 @@ -[gd_scene load_steps=23 format=2] +[gd_scene load_steps=25 format=2] -[ext_resource path="res://Floor.tres" type="TileSet" id=1] -[ext_resource path="res://vegetation.png" type="Texture" id=2] +[ext_resource path="res://omgeving/Floor.tres" type="TileSet" id=1] +[ext_resource path="res://pictures/tileset_images/vegetation.png" type="Texture" id=2] [ext_resource path="res://pictures/gui/buttons/LeftButton.png" type="Texture" id=3] [ext_resource path="res://kbscene/char.png" type="Texture" id=4] -[ext_resource path="res://KinematicBody2D.gd" type="Script" id=5] -[ext_resource path="res://TouchScreenButton.gd" type="Script" id=6] +[ext_resource path="res://MiscCodes/KinematicBody2D.gd" type="Script" id=5] +[ext_resource path="res://MiscCodes/TouchScreenButton.gd" type="Script" id=6] [ext_resource path="res://pictures/gui/buttons/LeftButtonPressed.png" type="Texture" id=7] [ext_resource path="res://pictures/gui/buttons/TopButtonPressed.png" type="Texture" id=8] [ext_resource path="res://pictures/gui/buttons/TopButton.png" type="Texture" id=9] @@ -15,9 +15,9 @@ [ext_resource path="res://pictures/gui/buttons/instellingen2.png" type="Texture" id=13] [ext_resource path="res://pictures/gui/buttons/quick_item_button.png" type="Texture" id=14] [ext_resource path="res://pictures/gui/buttons/map.png" type="Texture" id=15] -[ext_resource path="res://Tilemap_CameraView.gd" type="Script" id=16] -[ext_resource path="res://background_script.gd" type="Script" id=17] -[ext_resource path="res://interaction_map.png" type="Texture" id=18] +[ext_resource path="res://MiscCodes/Tilemap_CameraView.gd" type="Script" id=16] +[ext_resource path="res://MiscCodes/background_script.gd" type="Script" id=17] +[ext_resource path="res://pictures/tileset_images/interaction_map.png" type="Texture" id=18] [sub_resource type="TileSet" id=1] 0/name = "vegetation.png 0" @@ -42,12 +42,18 @@ 0/shapes = [ ] 0/z_index = 0 +[sub_resource type="OccluderPolygon2D" id=6] +polygon = PoolVector2Array( 0, 0, 32, 0, 32, 96, 0, 96 ) + +[sub_resource type="ConvexPolygonShape2D" id=5] +points = PoolVector2Array( 0, 0, 32, 0, 32, 96, 0, 96 ) + [sub_resource type="TileSet" id=2] 0/name = "interaction_map.png 0" 0/texture = ExtResource( 18 ) 0/tex_offset = Vector2( 0, 0 ) 0/modulate = Color( 1, 1, 1, 1 ) -0/region = Rect2( 0, 0, 32, 32 ) +0/region = Rect2( 0, 64, 32, 32 ) 0/tile_mode = 0 0/occluder_offset = Vector2( 0, 0 ) 0/navigation_offset = Vector2( 0, 0 ) @@ -61,7 +67,7 @@ 1/texture = ExtResource( 18 ) 1/tex_offset = Vector2( 0, 0 ) 1/modulate = Color( 1, 1, 1, 1 ) -1/region = Rect2( 32, 0, 32, 32 ) +1/region = Rect2( 32, 64, 32, 32 ) 1/tile_mode = 0 1/occluder_offset = Vector2( 0, 0 ) 1/navigation_offset = Vector2( 0, 0 ) @@ -75,7 +81,7 @@ 2/texture = ExtResource( 18 ) 2/tex_offset = Vector2( 0, 0 ) 2/modulate = Color( 1, 1, 1, 1 ) -2/region = Rect2( 64, 0, 32, 32 ) +2/region = Rect2( 64, 64, 32, 32 ) 2/tile_mode = 0 2/occluder_offset = Vector2( 0, 0 ) 2/navigation_offset = Vector2( 0, 0 ) @@ -85,6 +91,70 @@ 2/shape_one_way_margin = 0.0 2/shapes = [ ] 2/z_index = 0 +3/name = "interaction_map.png 3" +3/texture = ExtResource( 18 ) +3/tex_offset = Vector2( 0, 0 ) +3/modulate = Color( 1, 1, 1, 1 ) +3/region = Rect2( 96, 0, 32, 96 ) +3/tile_mode = 0 +3/occluder_offset = Vector2( 0, 0 ) +3/navigation_offset = Vector2( 0, 0 ) +3/shape_offset = Vector2( 0, 0 ) +3/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +3/shape_one_way = false +3/shape_one_way_margin = 0.0 +3/shapes = [ ] +3/z_index = 0 +4/name = "interaction_map.png 4" +4/texture = ExtResource( 18 ) +4/tex_offset = Vector2( 0, 0 ) +4/modulate = Color( 1, 1, 1, 1 ) +4/region = Rect2( 128, 0, 32, 96 ) +4/tile_mode = 0 +4/occluder_offset = Vector2( 0, 0 ) +4/occluder = SubResource( 6 ) +4/navigation_offset = Vector2( 0, 0 ) +4/shape_offset = Vector2( 0, 0 ) +4/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +4/shape = SubResource( 5 ) +4/shape_one_way = false +4/shape_one_way_margin = 1.0 +4/shapes = [ { +"autotile_coord": Vector2( 0, 0 ), +"one_way": false, +"one_way_margin": 1.0, +"shape": SubResource( 5 ), +"shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 ) +} ] +4/z_index = 0 +5/name = "interaction_map.png 5" +5/texture = ExtResource( 18 ) +5/tex_offset = Vector2( 0, 0 ) +5/modulate = Color( 1, 1, 1, 1 ) +5/region = Rect2( 160, 64, 32, 32 ) +5/tile_mode = 0 +5/occluder_offset = Vector2( 0, 0 ) +5/navigation_offset = Vector2( 0, 0 ) +5/shape_offset = Vector2( 0, 0 ) +5/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +5/shape_one_way = false +5/shape_one_way_margin = 0.0 +5/shapes = [ ] +5/z_index = 0 +6/name = "interaction_map.png 6" +6/texture = ExtResource( 18 ) +6/tex_offset = Vector2( 0, 0 ) +6/modulate = Color( 1, 1, 1, 1 ) +6/region = Rect2( 192, 64, 32, 32 ) +6/tile_mode = 0 +6/occluder_offset = Vector2( 0, 0 ) +6/navigation_offset = Vector2( 0, 0 ) +6/shape_offset = Vector2( 0, 0 ) +6/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) +6/shape_one_way = false +6/shape_one_way_margin = 0.0 +6/shapes = [ ] +6/z_index = 0 [sub_resource type="CapsuleShape2D" id=3] radius = 20.0 @@ -111,8 +181,9 @@ tile_data = PoolIntArray( 1179654, 0, 8, 1179655, 0, 0, 1245190, 0, 4, 1245191, tile_set = SubResource( 2 ) cell_size = Vector2( 32, 32 ) cell_custom_transform = Transform2D( 16, 0, 0, 16, 0, 0 ) +centered_textures = true format = 1 -tile_data = PoolIntArray( 2293773, 2, 0, 2293774, 2, 0, 2293775, 2, 0, 2359308, 2, 0, 2359309, 2, 0, 2359310, 2, 0, 2359311, 2, 0, 2424843, 2, 0, 2424844, 2, 0, 2424845, 2, 0, 2424846, 2, 0, 2424847, 2, 0, 2490380, 2, 0, 2490381, 2, 0 ) +tile_data = PoolIntArray( 2293767, 4, 0, 2293773, 2, 0, 2359308, 2, 0, 2359309, 2, 0, 2359310, 2, 0, 2424844, 2, 0, 2424845, 2, 0, 2490381, 2, 0, 2752538, 6, 0, 2752539, 5, 0 ) [node name="player_interaction" type="TileMap" parent="."] tile_set = ExtResource( 10 )