└── addons └── FileAccessWeb ├── core └── file_access_web.gd ├── examples ├── upload_file_example.gd ├── upload_file_example.tscn ├── upload_image_example.gd ├── upload_image_example.tscn ├── upload_to_server_example.gd └── upload_to_server_example.tscn └── plugin.cfg /addons/FileAccessWeb/core/file_access_web.gd: -------------------------------------------------------------------------------- 1 | class_name FileAccessWeb 2 | extends RefCounted 3 | 4 | signal load_started(file_name: String) 5 | signal loaded(file_name: String, file_type: String, base64_data: String) 6 | signal progress(current_bytes: int, total_bytes: int) 7 | signal error() 8 | signal upload_cancelled() 9 | 10 | var _file_uploading: JavaScriptObject 11 | 12 | var _on_file_load_start_callback: JavaScriptObject 13 | var _on_file_loaded_callback: JavaScriptObject 14 | var _on_file_progress_callback: JavaScriptObject 15 | var _on_file_error_callback: JavaScriptObject 16 | var _on_file_cancelled_callback: JavaScriptObject 17 | 18 | func _init() -> void: 19 | if _is_not_web(): 20 | _notify_error() 21 | return 22 | 23 | JavaScriptBridge.eval(js_source_code, true) 24 | _file_uploading = JavaScriptBridge.get_interface("godotFileAccessWeb") 25 | 26 | _on_file_load_start_callback = JavaScriptBridge.create_callback(_on_file_load_start) 27 | _on_file_loaded_callback = JavaScriptBridge.create_callback(_on_file_loaded) 28 | _on_file_progress_callback = JavaScriptBridge.create_callback(_on_file_progress) 29 | _on_file_error_callback = JavaScriptBridge.create_callback(_on_file_error) 30 | _on_file_cancelled_callback = JavaScriptBridge.create_callback(_on_file_cancelled) 31 | 32 | _file_uploading.setLoadStartCallback(_on_file_load_start_callback) 33 | _file_uploading.setLoadedCallback(_on_file_loaded_callback) 34 | _file_uploading.setProgressCallback(_on_file_progress_callback) 35 | _file_uploading.setErrorCallback(_on_file_error_callback) 36 | _file_uploading.setCancelledCallback(_on_file_cancelled_callback) 37 | 38 | func open(accept_files: String = "*") -> void: 39 | if _is_not_web(): 40 | _notify_error() 41 | return 42 | 43 | _file_uploading.setAcceptFiles(accept_files) 44 | _file_uploading.open() 45 | 46 | func _is_not_web() -> bool: 47 | return OS.get_name() != "Web" 48 | 49 | func _notify_error() -> void: 50 | push_error("File Access Web worked only for HTML5 platform export!") 51 | 52 | func _on_file_load_start(args: Array) -> void: 53 | var file_name: String = args[0] 54 | load_started.emit(file_name) 55 | 56 | func _on_file_loaded(args: Array) -> void: 57 | var file_name: String = args[0] 58 | var splitted_args: PackedStringArray = args[1].split(",", true, 1) 59 | var file_type: String = splitted_args[0].get_slice(":", 1). get_slice(";", 0) 60 | var base64_data: String = splitted_args[1] 61 | loaded.emit(file_name, file_type, base64_data) 62 | 63 | func _on_file_progress(args: Array) -> void: 64 | var current_bytes: int = args[0] 65 | var total_bytes: int = args[1] 66 | progress.emit(current_bytes, total_bytes) 67 | 68 | func _on_file_error(args: Array) -> void: 69 | error.emit() 70 | 71 | func _on_file_cancelled(args: Array) -> void: 72 | upload_cancelled.emit() 73 | 74 | const js_source_code = """ 75 | function godotFileAccessWebStart() { 76 | var loadedCallback; 77 | var progressCallback; 78 | var errorCallback; 79 | var loadStartCallback; 80 | var cancelledCallback; 81 | 82 | var input = document.createElement("input"); 83 | input.setAttribute("type", "file"); 84 | 85 | var interface = { 86 | setLoadedCallback: (loaded) => loadedCallback = loaded, 87 | setProgressCallback: (progress) => progressCallback = progress, 88 | setErrorCallback: (error) => errorCallback = error, 89 | setLoadStartCallback: (start) => loadStartCallback = start, 90 | setCancelledCallback: (cancelled) => cancelledCallback = cancelled, 91 | 92 | setAcceptFiles: (files) => input.setAttribute("accept", files), 93 | open: () => input.click() 94 | } 95 | 96 | input.onchange = (event) => { 97 | var file = event.target.files[0]; 98 | 99 | var reader = new FileReader(); 100 | reader.readAsDataURL(file); 101 | 102 | reader.onloadstart = (loadStartEvent) => { 103 | loadStartCallback(file.name); 104 | } 105 | 106 | reader.onload = (readerEvent) => { 107 | if (readerEvent.target.readyState === FileReader.DONE) { 108 | loadedCallback(file.name, readerEvent.target.result); 109 | } 110 | } 111 | 112 | reader.onprogress = (progressEvent) => { 113 | if (progressEvent.lengthComputable) 114 | progressCallback(progressEvent.loaded, progressEvent.total); 115 | } 116 | 117 | reader.onerror = (errorEvent) => { 118 | errorCallback(); 119 | } 120 | } 121 | 122 | input.addEventListener('cancel', () => { 123 | cancelledCallback(); 124 | }); 125 | 126 | return interface; 127 | } 128 | 129 | var godotFileAccessWeb = godotFileAccessWebStart(); 130 | """ 131 | -------------------------------------------------------------------------------- /addons/FileAccessWeb/examples/upload_file_example.gd: -------------------------------------------------------------------------------- 1 | class_name UploadFileExample 2 | extends Control 3 | 4 | @onready var upload_button: Button = %"Upload Button" as Button 5 | @onready var progress: ProgressBar = %"Progress Bar" as ProgressBar 6 | @onready var success_label: Label = %"Success Label" as Label 7 | 8 | var file_access_web: FileAccessWeb = FileAccessWeb.new() 9 | 10 | func _ready() -> void: 11 | upload_button.pressed.connect(_on_upload_pressed) 12 | file_access_web.load_started.connect(_on_file_load_started) 13 | file_access_web.loaded.connect(_on_file_loaded) 14 | file_access_web.progress.connect(_on_progress) 15 | file_access_web.error.connect(_on_error) 16 | 17 | func _on_file_load_started(file_name: String) -> void: 18 | progress.visible = true 19 | success_label.visible = false 20 | 21 | func _on_upload_pressed() -> void: 22 | file_access_web.open() 23 | 24 | func _on_progress(current_bytes: int, total_bytes: int) -> void: 25 | var percentage: float = float(current_bytes) / float(total_bytes) * 100 26 | progress.value = percentage 27 | 28 | func _on_file_loaded(file_name: String, type: String, base64_data: String) -> void: 29 | progress.visible = false 30 | success_label.visible = true 31 | 32 | func _on_error() -> void: 33 | push_error("Error!") 34 | 35 | -------------------------------------------------------------------------------- /addons/FileAccessWeb/examples/upload_file_example.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=10 format=3 uid="uid://cfw0x112dbwyj"] 2 | 3 | [ext_resource type="Script" path="res://addons/FileAccessWeb/examples/upload_file_example.gd" id="1_s6dap"] 4 | 5 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3h46t"] 6 | bg_color = Color(0, 0, 0, 1) 7 | border_width_left = 1 8 | border_width_top = 1 9 | border_width_right = 1 10 | border_width_bottom = 1 11 | 12 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_k6sdq"] 13 | bg_color = Color(0, 0, 0, 1) 14 | border_width_left = 1 15 | border_width_top = 1 16 | border_width_right = 1 17 | border_width_bottom = 1 18 | 19 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_v0hm0"] 20 | bg_color = Color(0.168627, 0.168627, 0.168627, 1) 21 | border_width_left = 1 22 | border_width_top = 1 23 | border_width_right = 1 24 | border_width_bottom = 1 25 | 26 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_eqd2r"] 27 | bg_color = Color(0.372549, 0.372549, 0.372549, 1) 28 | 29 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_owjfu"] 30 | draw_center = false 31 | 32 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_t5wel"] 33 | bg_color = Color(0, 0, 0, 1) 34 | 35 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_yx3xo"] 36 | bg_color = Color(0.196078, 0.396078, 0.721569, 1) 37 | 38 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_fwgxq"] 39 | draw_center = false 40 | border_width_left = 1 41 | border_width_top = 1 42 | border_width_right = 1 43 | border_width_bottom = 1 44 | 45 | [node name="Upload File Example" type="Control"] 46 | layout_mode = 3 47 | anchors_preset = 15 48 | anchor_right = 1.0 49 | anchor_bottom = 1.0 50 | grow_horizontal = 2 51 | grow_vertical = 2 52 | script = ExtResource("1_s6dap") 53 | 54 | [node name="Window Background" type="Panel" parent="."] 55 | layout_mode = 1 56 | anchors_preset = 8 57 | anchor_left = 0.5 58 | anchor_top = 0.5 59 | anchor_right = 0.5 60 | anchor_bottom = 0.5 61 | offset_left = -128.0 62 | offset_top = -128.0 63 | offset_right = 128.0 64 | offset_bottom = -68.0 65 | grow_horizontal = 2 66 | grow_vertical = 2 67 | theme_override_styles/panel = SubResource("StyleBoxFlat_3h46t") 68 | 69 | [node name="Margin Container" type="MarginContainer" parent="Window Background"] 70 | layout_mode = 1 71 | anchors_preset = 15 72 | anchor_right = 1.0 73 | anchor_bottom = 1.0 74 | grow_horizontal = 2 75 | grow_vertical = 2 76 | theme_override_constants/margin_left = 10 77 | theme_override_constants/margin_top = 10 78 | theme_override_constants/margin_right = 10 79 | theme_override_constants/margin_bottom = 10 80 | 81 | [node name="VBoxContainer" type="VBoxContainer" parent="Window Background/Margin Container"] 82 | layout_mode = 2 83 | 84 | [node name="Upload Button" type="Button" parent="Window Background/Margin Container/VBoxContainer"] 85 | unique_name_in_owner = true 86 | custom_minimum_size = Vector2(0, 40) 87 | layout_mode = 2 88 | theme_override_styles/normal = SubResource("StyleBoxFlat_k6sdq") 89 | theme_override_styles/hover = SubResource("StyleBoxFlat_v0hm0") 90 | theme_override_styles/pressed = SubResource("StyleBoxFlat_eqd2r") 91 | theme_override_styles/focus = SubResource("StyleBoxFlat_owjfu") 92 | text = "Upload File" 93 | 94 | [node name="Progress Bar" type="ProgressBar" parent="Window Background"] 95 | unique_name_in_owner = true 96 | visible = false 97 | custom_minimum_size = Vector2(256, 0) 98 | layout_mode = 1 99 | anchors_preset = 2 100 | anchor_top = 1.0 101 | anchor_bottom = 1.0 102 | offset_top = 7.0 103 | offset_right = 256.0 104 | offset_bottom = 34.0 105 | grow_vertical = 0 106 | theme_override_styles/background = SubResource("StyleBoxFlat_t5wel") 107 | theme_override_styles/fill = SubResource("StyleBoxFlat_yx3xo") 108 | 109 | [node name="Borders" type="Panel" parent="Window Background/Progress Bar"] 110 | layout_mode = 1 111 | anchors_preset = 15 112 | anchor_right = 1.0 113 | anchor_bottom = 1.0 114 | grow_horizontal = 2 115 | grow_vertical = 2 116 | theme_override_styles/panel = SubResource("StyleBoxFlat_fwgxq") 117 | 118 | [node name="Success Label" type="Label" parent="Window Background"] 119 | unique_name_in_owner = true 120 | visible = false 121 | layout_mode = 1 122 | anchors_preset = 2 123 | anchor_top = 1.0 124 | anchor_bottom = 1.0 125 | offset_left = 92.0 126 | offset_top = 7.0 127 | offset_right = 157.0 128 | offset_bottom = 33.0 129 | grow_vertical = 0 130 | theme_override_colors/font_color = Color(0, 0.964706, 0, 1) 131 | text = "Success!" 132 | -------------------------------------------------------------------------------- /addons/FileAccessWeb/examples/upload_image_example.gd: -------------------------------------------------------------------------------- 1 | class_name UploadImageExample 2 | extends Control 3 | 4 | @onready var upload_button: Button = %"Upload Button" as Button 5 | @onready var canvas: TextureRect = %Canvas as TextureRect 6 | @onready var progress: ProgressBar = %"Progress Bar" as ProgressBar 7 | 8 | var file_access_web: FileAccessWeb = FileAccessWeb.new() 9 | var image_type: String = ".jpg" 10 | 11 | func _ready() -> void: 12 | upload_button.pressed.connect(_on_upload_pressed) 13 | file_access_web.loaded.connect(_on_file_loaded) 14 | file_access_web.progress.connect(_on_progress) 15 | file_access_web.upload_cancelled.connect(_on_upload_cancelled) 16 | 17 | func _on_upload_pressed() -> void: 18 | file_access_web.open(image_type) 19 | 20 | func _on_upload_cancelled() -> void: 21 | print("user cancelled the file upload") 22 | 23 | func _on_progress(current_bytes: int, total_bytes: int) -> void: 24 | var percentage: float = float(current_bytes) / float(total_bytes) * 100 25 | progress.value = percentage 26 | 27 | func _on_file_loaded(file_name: String, type: String, base64_data: String) -> void: 28 | var raw_data: PackedByteArray = Marshalls.base64_to_raw(base64_data) 29 | raw_draw(type, raw_data) 30 | 31 | func raw_draw(type: String, data: PackedByteArray) -> void: 32 | var image := Image.new() 33 | var error: int = _load_image(image, type, data) 34 | 35 | if not error: 36 | canvas.texture = _create_texture_from(image) 37 | else: 38 | push_error("Error %s id" % error) 39 | 40 | func _load_image(image: Image, type: String, data: PackedByteArray) -> int: 41 | match type: 42 | "image/png": 43 | return image.load_png_from_buffer(data) 44 | "image/jpeg": 45 | return image.load_jpg_from_buffer(data) 46 | "image/webp": 47 | return image.load_webp_from_buffer(data) 48 | _: 49 | return Error.FAILED 50 | 51 | func _create_texture_from(image: Image) -> ImageTexture: 52 | var texture = ImageTexture.new() 53 | texture.set_image(image) 54 | return texture 55 | 56 | -------------------------------------------------------------------------------- /addons/FileAccessWeb/examples/upload_image_example.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=12 format=3 uid="uid://bjeu7kpe7vi6g"] 2 | 3 | [ext_resource type="Script" path="res://addons/FileAccessWeb/examples/upload_image_example.gd" id="1_f62sm"] 4 | 5 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3h46t"] 6 | bg_color = Color(0, 0, 0, 1) 7 | border_width_left = 1 8 | border_width_top = 1 9 | border_width_right = 1 10 | border_width_bottom = 1 11 | 12 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_7ifsm"] 13 | bg_color = Color(0, 0, 0, 1) 14 | border_width_left = 1 15 | border_width_top = 1 16 | border_width_right = 1 17 | border_width_bottom = 1 18 | 19 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_k6sdq"] 20 | bg_color = Color(0, 0, 0, 1) 21 | border_width_left = 1 22 | border_width_top = 1 23 | border_width_right = 1 24 | border_width_bottom = 1 25 | 26 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_v0hm0"] 27 | bg_color = Color(0.168627, 0.168627, 0.168627, 1) 28 | border_width_left = 1 29 | border_width_top = 1 30 | border_width_right = 1 31 | border_width_bottom = 1 32 | 33 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_eqd2r"] 34 | bg_color = Color(0.372549, 0.372549, 0.372549, 1) 35 | 36 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_owjfu"] 37 | draw_center = false 38 | 39 | [sub_resource type="ImageTexture" id="ImageTexture_yurbi"] 40 | 41 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_t5wel"] 42 | bg_color = Color(0, 0, 0, 1) 43 | 44 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_yx3xo"] 45 | bg_color = Color(0.196078, 0.396078, 0.721569, 1) 46 | 47 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_fwgxq"] 48 | draw_center = false 49 | border_width_left = 1 50 | border_width_top = 1 51 | border_width_right = 1 52 | border_width_bottom = 1 53 | 54 | [node name="Upload Image Example" type="Control"] 55 | layout_mode = 3 56 | anchors_preset = 15 57 | anchor_right = 1.0 58 | anchor_bottom = 1.0 59 | grow_horizontal = 2 60 | grow_vertical = 2 61 | script = ExtResource("1_f62sm") 62 | 63 | [node name="Window Background" type="Panel" parent="."] 64 | layout_mode = 1 65 | anchors_preset = 8 66 | anchor_left = 0.5 67 | anchor_top = 0.5 68 | anchor_right = 0.5 69 | anchor_bottom = 0.5 70 | offset_left = -128.0 71 | offset_top = -128.0 72 | offset_right = 128.0 73 | offset_bottom = 128.0 74 | grow_horizontal = 2 75 | grow_vertical = 2 76 | theme_override_styles/panel = SubResource("StyleBoxFlat_3h46t") 77 | 78 | [node name="Margin Container" type="MarginContainer" parent="Window Background"] 79 | layout_mode = 1 80 | anchors_preset = 8 81 | anchor_left = 0.5 82 | anchor_top = 0.5 83 | anchor_right = 0.5 84 | anchor_bottom = 0.5 85 | offset_left = -128.0 86 | offset_top = -128.0 87 | offset_right = 128.0 88 | offset_bottom = 128.0 89 | grow_horizontal = 2 90 | grow_vertical = 2 91 | theme_override_constants/margin_left = 10 92 | theme_override_constants/margin_top = 10 93 | theme_override_constants/margin_right = 10 94 | theme_override_constants/margin_bottom = 10 95 | 96 | [node name="Content Background" type="Panel" parent="Window Background/Margin Container"] 97 | clip_contents = true 98 | layout_mode = 2 99 | theme_override_styles/panel = SubResource("StyleBoxFlat_7ifsm") 100 | 101 | [node name="MarginContainer" type="MarginContainer" parent="Window Background/Margin Container/Content Background"] 102 | layout_mode = 1 103 | anchors_preset = 15 104 | anchor_right = 1.0 105 | anchor_bottom = 1.0 106 | grow_horizontal = 2 107 | grow_vertical = 2 108 | theme_override_constants/margin_left = 10 109 | theme_override_constants/margin_top = 10 110 | theme_override_constants/margin_right = 10 111 | theme_override_constants/margin_bottom = 10 112 | 113 | [node name="VBoxContainer" type="VBoxContainer" parent="Window Background/Margin Container/Content Background/MarginContainer"] 114 | layout_mode = 2 115 | 116 | [node name="Upload Button" type="Button" parent="Window Background/Margin Container/Content Background/MarginContainer/VBoxContainer"] 117 | unique_name_in_owner = true 118 | custom_minimum_size = Vector2(0, 40) 119 | layout_mode = 2 120 | theme_override_styles/normal = SubResource("StyleBoxFlat_k6sdq") 121 | theme_override_styles/hover = SubResource("StyleBoxFlat_v0hm0") 122 | theme_override_styles/pressed = SubResource("StyleBoxFlat_eqd2r") 123 | theme_override_styles/focus = SubResource("StyleBoxFlat_owjfu") 124 | text = "Upload File" 125 | 126 | [node name="Canvas" type="TextureRect" parent="Window Background/Margin Container/Content Background/MarginContainer/VBoxContainer"] 127 | unique_name_in_owner = true 128 | layout_mode = 2 129 | size_flags_vertical = 3 130 | texture = SubResource("ImageTexture_yurbi") 131 | expand_mode = 3 132 | 133 | [node name="Progress Bar" type="ProgressBar" parent="Window Background"] 134 | unique_name_in_owner = true 135 | custom_minimum_size = Vector2(256, 0) 136 | layout_mode = 0 137 | offset_top = 265.0 138 | offset_right = 256.0 139 | offset_bottom = 292.0 140 | theme_override_styles/background = SubResource("StyleBoxFlat_t5wel") 141 | theme_override_styles/fill = SubResource("StyleBoxFlat_yx3xo") 142 | 143 | [node name="Borders" type="Panel" parent="Window Background/Progress Bar"] 144 | layout_mode = 1 145 | anchors_preset = 15 146 | anchor_right = 1.0 147 | anchor_bottom = 1.0 148 | grow_horizontal = 2 149 | grow_vertical = 2 150 | theme_override_styles/panel = SubResource("StyleBoxFlat_fwgxq") 151 | -------------------------------------------------------------------------------- /addons/FileAccessWeb/examples/upload_to_server_example.gd: -------------------------------------------------------------------------------- 1 | class_name UploadToServerExample 2 | extends Control 3 | 4 | @onready var upload_image_example: UploadImageExample = $"Upload Image Example" as UploadImageExample 5 | @onready var http: HTTPRequest = $HTTPRequest as HTTPRequest 6 | 7 | var url: String = "http://localhost:5072/images" 8 | 9 | func _ready() -> void: 10 | upload_image_example.file_access_web.loaded.connect(_on_file_loaded) 11 | http.request_completed.connect(_on_request_completed) 12 | 13 | func _on_file_loaded(file_name: String, type: String, base64_data: String) -> void: 14 | _send_to_server(file_name, type, base64_data) 15 | 16 | func _on_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray) -> void: 17 | print(body.get_string_from_ascii()) 18 | 19 | func _send_to_server(file_name: String, file_type: String, file_base64: String) -> void: 20 | const boundary: String = "GodotFileUploadBoundaryZ29kb3RmaWxl" 21 | var headers = [ "Content-Type: multipart/form-data; boundary=%s" % boundary] 22 | var body = _form_data_packet(boundary, "image", file_name, file_type, file_base64) 23 | http.request_raw(url, headers, HTTPClient.METHOD_PUT, body) 24 | 25 | func _form_data_packet(boundary: String, endpoint_argument_name: String, file_name: String, file_type: String, file_base64: String) -> PackedByteArray: 26 | var packet := PackedByteArray() 27 | var boundary_start = ("\r\n--%s" % boundary).to_utf8_buffer() 28 | var disposition = ("\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"" % [endpoint_argument_name, file_name]).to_utf8_buffer() 29 | var content_type = ("\r\nContent-Type: %s\r\n\r\n" % file_type).to_utf8_buffer() 30 | var boundary_end = ("\r\n--%s--\r\n" % boundary).to_utf8_buffer() 31 | 32 | packet.append_array(boundary_start) 33 | packet.append_array(disposition) 34 | packet.append_array(content_type) 35 | packet.append_array(Marshalls.base64_to_raw(file_base64)) 36 | packet.append_array(boundary_end) 37 | return packet 38 | -------------------------------------------------------------------------------- /addons/FileAccessWeb/examples/upload_to_server_example.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=3 uid="uid://bv4keuf4xqvs4"] 2 | 3 | [ext_resource type="Script" path="res://addons/FileAccessWeb/examples/upload_to_server_example.gd" id="1_0rfwi"] 4 | [ext_resource type="PackedScene" uid="uid://bjeu7kpe7vi6g" path="res://addons/FileAccessWeb/examples/upload_image_example.tscn" id="2_gtj23"] 5 | 6 | [node name="Upload To Server Example" type="Control"] 7 | layout_mode = 3 8 | anchors_preset = 15 9 | anchor_right = 1.0 10 | anchor_bottom = 1.0 11 | grow_horizontal = 2 12 | grow_vertical = 2 13 | script = ExtResource("1_0rfwi") 14 | 15 | [node name="Upload Image Example" parent="." instance=ExtResource("2_gtj23")] 16 | layout_mode = 1 17 | 18 | [node name="HTTPRequest" type="HTTPRequest" parent="."] 19 | -------------------------------------------------------------------------------- /addons/FileAccessWeb/plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="File Access Web" 4 | description="Addon for upload files to HTML5 (WebGL) on Godot 4." 5 | author="Scrawach" 6 | version="1.2" 7 | script="" 8 | --------------------------------------------------------------------------------