So you wanted own communicator in Godot engine 4 like ICQ?

Okay guys, I had an idea to program own communicator in Godot4. The thing is you need to overcome 2 things to bring such program to life. The first thing is to load pictures from devices to your user:// folder in Godot4 Then we need to load such pics into RichTextboxLabel with texts. The second thing is to upload pictures and json to the server file system. Enough of the speaking, lets practice in gd script:

extends Node2D
var fd:FileDialog
var logic=false
func _ready() -> void:
    pass # Replace with function body.
func prnt():
    print("ok")
func save_to_file(content):
    var file = FileAccess.open("user://icon3.png", FileAccess.WRITE)
    file.store_buffer(content)
func load_from_file(path):
    var file = FileAccess.open(path, FileAccess.READ)
    var content = file.get_file_as_bytes(path)
    return content
func _process(delta: float) -> void:
    if Input.is_action_just_released("a"):
        fd = FileDialog.new()
        self.add_child(fd)
        fd.mode=FileDialog.MODE_WINDOWED
        fd.file_mode=FileDialog.FILE_MODE_OPEN_FILE
        fd.access=FileDialog.ACCESS_FILESYSTEM
        fd.popup(Rect2(0,0, 500, 500))
        var image = load("res://icon.svg")
        $RichTextLabel.add_image(image,100,100)
        $RichTextLabel.append_text("\nyour communicator in godot\n")
    if fd:
        if logic==false and "icon2" in fd.current_path:
            print(fd.current_path)
            save_to_file(load_from_file(fd.current_path))
            if FileAccess.file_exists("user://icon3.png"):
                print("file exists")
            var image2 = Image.new()
            var err = image2.load("user://icon3.png")
            var texture2=ImageTexture.create_from_image(image2)
            if err != OK:
                print("File not loaded:",err)
            else:
                $RichTextLabel.add_image(texture2,100,100)
            logic=true

extends Node2D


# Called when the node enters the scene tree for the first time.
func _ready() -> void:
    _upload_png("user://icon3.png")
    #send_image_binary()


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
    pass


func send_image_binary() -> void:
    # Create some random bytes to generate our boundary value
    var crypto = Crypto.new()
    var random_bytes = crypto.generate_random_bytes(16)
    var boundary = '--GODOT%s' % random_bytes.hex_encode()

    # Setup the header Content-Type with our bundary
    var headers := PackedStringArray()
    headers.append("Content-Type: multipart/form-data;boundary=\"WebKitFormBoundaryePkpFF7tjBAqx29L\"")

    # Load the image and get the png buffer
    var image = load("res://icon3.png").get_image() as Image
    var buffer = image.save_png_to_buffer()

    # Create our body
    var body = PackedByteArray()
    append_line(body, "--{{boundary}}".format({"boundary": boundary}, "{{_}}"))
    append_line(body, 'Content-Disposition: form-data; name="api_key"')
    append_line(body, '')
    append_line(body, "MY_API_KEY") # The API key you have
    append_line(body, "--{{boundary}}".format({"boundary": boundary}, "{{_}}"))
    append_line(body, 'Content-Disposition: form-data; name="image"; filename="my_image.png"')
    append_line(body, 'Content-Type: image/png')
    append_line(body, 'Content-Transfer-Encoding: binary')
    append_line(body, '')
    append_bytes(body, buffer)
    append_line(body, "--{{boundary}}--".format({"boundary": boundary}, "{{_}}"))
    var http = HTTPClient.new()
    http.set_blocking_mode(true)
    http.connect_to_host( "https://hrubos.tech", 443 )
    var err = http.request_raw(HTTPClient.METHOD_POST, "/commie/upload_pic.php" , headers, body)

    while http.get_status() == HTTPClient.STATUS_CONNECTING or http.get_status() == HTTPClient.STATUS_RESOLVING:

        http.poll()
        OS.delay_msec(500)

        print("connecting...")

    if http.get_status() != HTTPClient.STATUS_CONNECTED:
        print("not connected ", http.get_status())
        return


    while http.get_status() == HTTPClient.STATUS_REQUESTING:

        print("requesting")

        http.poll()

        if not OS.has_feature("web"):
            OS.delay_msec(500)
        else:
            await Engine.get_main_loop().idle_frame
    # -------------------------------------------------------------------------------------

    # IF THERE A RESPONSE -----------------------------------------------------------------
    if http.has_response():

        #headers = http.get_response_headers_as_dictionary() # Get response headers.
        print("code: ", http.get_response_code())           # Show response code.
        #print("headers: ", headers)                     # Show headers.

        # Getting the HTTP Body
        if http.is_response_chunked():
            # Does it use chunks?
            print("Response is Chunked!")
        else:
            # Or just plain Content-Length
            var bl = http.get_response_body_length()
            print("Response Length: ", bl)

        # This method works for both anyway
        var resp_body := PackedByteArray()

        while http.get_status() == HTTPClient.STATUS_BODY:

            # While there is body left to be read
            http.poll()

            # Get a chunk.
            var chunk = http.read_response_body_chunk()

            if chunk.size() == 0:
                if not OS.has_feature("web"):
                    OS.delay_usec(1000)
                    print("OS has no feature web")
                else:
                    await Engine.get_main_loop().idle_frame
            else:
                resp_body = resp_body + chunk

        # Done!
        var text := resp_body.get_string_from_utf8().strip_edges()
        print(text)


func append_line(buffer:PackedByteArray, line:String) -> void:
    buffer.append_array(line.to_utf8_buffer())
    buffer.append_array('\r\n'.to_utf8_buffer())


func append_bytes(buffer:PackedByteArray, bytes:PackedByteArray) -> void:
    buffer.append_array(bytes)
    buffer.append_array('\r\n'.to_utf8_buffer())

func _upload_png( path_to_png : String ):

    if !FileAccess.file_exists(path_to_png):
        print("file does not exist in path to send, quitting program!")
        return

    var file_name := path_to_png.get_file()
    var file := FileAccess.open(path_to_png, FileAccess.READ)
    var file_content = file.get_buffer( file.get_length( ) )
    var crypto = Crypto.new()
    var random_bytes = crypto.generate_random_bytes(16)
    var boundary = '--GODOT%s' % random_bytes.hex_encode()
    var body := PackedByteArray()
    var image = load("res://icon3.png").get_image() as Image
    var buffer = image.save_png_to_buffer()
    #body.append_array( "\r\n--WebKitFormBoundaryePkpFF7tjBAqx29L\r\n".to_utf8_buffer() )
    #body.append_array( "Content-Disposition: form-data; name=\"pic3\"; filename=\"pic3.png".to_utf8_buffer() )
    #body.append_array( file_name.to_utf8_buffer() )
    #body.append_array( "\"\r\n".to_utf8_buffer() )
    #body.append_array( "Content-Type: image/png\r\n\r\n".to_utf8_buffer() )
    #body.append_array( file_content )
    #body.append_array( "\r\n--WebKitFormBoundaryePkpFF7tjBAqx29L--\r\n".to_utf8_buffer() )
    append_line(body, "--{{boundary}}".format({"boundary": boundary}, "{{_}}"))
    append_line(body, 'Content-Disposition: form-data; name="api_key"')
    append_line(body, '')
    append_line(body, "MY_API_KEY") # The API key you have
    append_line(body, "--{{boundary}}".format({"boundary": boundary}, "{{_}}"))
    append_line(body, 'Content-Disposition: form-data; name="image"; filename="my_image.png"')
    append_line(body, 'Content-Type: image/png')
    append_line(body, 'Content-Transfer-Encoding: binary')
    append_line(body, '')
    append_bytes(body, buffer)
    append_line(body, "--{{boundary}}--".format({"boundary": boundary}, "{{_}}"))
    #print(file_content)
    var headers := PackedStringArray()
    #headers.append("Content-Type: multipart/form-data;boundary=\"WebKitFormBoundaryePkpFF7tjBAqx29L\"")
    headers.append('Content-Type: multipart/form-data;boundary=%s' % boundary)

    var http = HTTPClient.new()
    http.set_blocking_mode(true)
    http.connect_to_host( "https://hrubos.tech", 443 )

    while http.get_status() == HTTPClient.STATUS_CONNECTING or http.get_status() == HTTPClient.STATUS_RESOLVING:

        http.poll()
        OS.delay_msec(500)

        print("connecting...")

    if http.get_status() != HTTPClient.STATUS_CONNECTED:
        print("not connected ", http.get_status())
        return
    #print(body)
    var err = http.request_raw(HTTPClient.METHOD_POST, "/commie/upload_pic.php" , headers, body)
    #var err = http.request(HTTPClient.METHOD_POST,"/commie/upload_pic.php",headers,body)

    if err != OK:
        print("error sending ", err)
        return

    while http.get_status() == HTTPClient.STATUS_REQUESTING:

        print("requesting")

        http.poll()

        if not OS.has_feature("web"):
            OS.delay_msec(500)
        else:
            await Engine.get_main_loop().idle_frame
    # -------------------------------------------------------------------------------------

    # IF THERE A RESPONSE -----------------------------------------------------------------
    if http.has_response():

        #headers = http.get_response_headers_as_dictionary() # Get response headers.
        print("code: ", http.get_response_code())           # Show response code.
        #print("headers: ", headers)                     # Show headers.

        # Getting the HTTP Body
        if http.is_response_chunked():
            # Does it use chunks?
            print("Response is Chunked!")
        else:
            # Or just plain Content-Length
            var bl = http.get_response_body_length()
            print("Response Length: ", bl)

        # This method works for both anyway
        var resp_body := PackedByteArray()

        while http.get_status() == HTTPClient.STATUS_BODY:

            # While there is body left to be read
            http.poll()

            # Get a chunk.
            var chunk = http.read_response_body_chunk()

            if chunk.size() == 0:
                if not OS.has_feature("web"):
                    OS.delay_usec(1000)
                    print("OS has no feature web")
                else:
                    await Engine.get_main_loop().idle_frame
            else:
                resp_body = resp_body + chunk

        # Done!
        var text := resp_body.get_string_from_utf8().strip_edges()
        print(text)

Some pics of running code are: godot4 upload pic to php server godot4 successfuly uploaded to server the picture godot4 rich text box as a communicator from directory to cache godot4 enter image description here commie specification


Author: AarNoma

The first Slovak cyborg 1 system

Comments “So you wanted own communicator in Godot engine 4 like ICQ?”