---
# System prepended metadata

title: Godot client websocket
tags: [godot]

---

{%hackmd HkOsb-H_D %}
# Godot client websocket

**目錄**
[TOC]

##  啟動 WebSocket 服務
```gdscript=
var ws = null
func _ready():
    # 建置 ws instance 
    ws = WebSocketClient.new()
    # 監聽 ws 信號
    ws.connect("connection_error", self, "_connection_failed")
    ws.connect("connection_established", self, "_connection_established")
    ws.connect("data_received", self, "_data_received")
```
### 信號狀態
ws.connect(`"接收的信號類型"`, self, `"接收到信號要 call 的 func"`)


| 信號類型 | 說明 |
| -------- | -------- |
| connection_closed | 與server的連接關閉時發出 |
| connection_error | 與server的連接失敗時發出 |
| connection_established | 與server建立連接時發出，protocol將包含與服務器約定的子協議 |
| data_received | 接收到 server WebSocket 的消息時<br>注意：用作多人連線時，不會發出此信號 |
| server_close_request | server的連線關閉時發出 |



## 建立連線
```gdscript=
func connect_server():
    var err = ws.connect_to_url("ws://localhost:3100");
    if err == OK:
        print("連接成功");
        set_process(true);
    else:
        print("連接失敗");
        set_process(false);
```

## 接收 & 回傳訊息

```gdscript=
# server 交握成功回傳給 Server
func _connection_established(protocol):
# 回傳給server "hi"
    ws.get_peer(1).put_var("hi");
    pass

# soket 接收 server 廣播
func _data_received():
	var masg = ws.get_peer(1).get_var()
	print("接收server訊息= ", masg);
	pass
```

:::spoiler Editor 建立連線無回應
:::success
html5 會自動輪詢, editor 需要自行想辦法輪詢
[參考來源](https://godotengine.org/qa/33572/connecting-to-websockets-doesnt-end)
:::

---
## 溫知故新
:::spoiler
[計算機概論](https://web.csie.ndhu.edu.tw/sclo/project/ppt.html)

:::success
* 最小單位: bit, 資料只有 0 和 1
* 1 byte = 8 bit
* 二進制 1111 = 十進制 15 = 十六進制 F
* 1 byte 資料最大值: 二進制 1111 1111 = 十六進制 FF
:::

---

## [PoolByteArray](https://docs.godotengine.org/en/stable/classes/class_poolbytearray.html)
:::warning
這是 call by <font color=#00AA00>**VALUE**</font>
不是 call by <font color=#AA0000>**REFERENCE**</font>
:::

:::info
JavaScript ArrayBuffer, TypedArray and DataView are returned as GDScript PoolByteArray

[官方文件說明](https://docs.godotengine.org/en/stable/tutorials/export/exporting_for_web.html#calling-javascript-from-script)

如果資料讀取是採用小端序 (little endian), 可考慮使用 [StreamPeerBuffer](https://docs.godotengine.org/en/stable/classes/class_streampeerbuffer.html#class-streampeerbuffer-method-seek)
:::

:::info
宣告並建立實體
```gdscript!
var _list: PoolByteArray = []
```

回傳新的實體
```gdscript!
func something() -> PoolByteArray:
    return PoolByteArray()
```
:::

:::info
透過 resize(length: int) 來設定大小
3.x 版本不會重設每個 byte 的資料, 會隨機出現不乾淨的資料

[參考文件](https://docs.godotengine.org/en/stable/classes/class_poolbytearray.html#class-poolbytearray-method-resize)

:::

:::info
[subarray](https://docs.godotengine.org/en/stable/classes/class_poolbytearray.html#class-poolbytearray-method-subarray)
起點和終點 index, 跟一般 array 相同

:::warning
[JS TypedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray) 的 subarray 使用方式比較特別, <font color=#AA0000>結尾 index 是被排除的</font>
使用上需要非常小心

:::

## [PoolIntArray](https://docs.godotengine.org/en/stable/classes/class_poolintarray.html)
:::warning
3.x 只支援 int32 的資料, 但 **[int](https://docs.godotengine.org/en/stable/classes/class_int.html#class-int)** 是 64 bit
如果需要塞入 int64 的資料, 則改用 **[Array](https://docs.godotengine.org/en/stable/classes/class_array.html#class-array)**
:::

## [StreamPeerBuffer](https://docs.godotengine.org/en/stable/classes/class_streampeerbuffer.html#class-streampeerbuffer-method-seek)
繼承 [StreamPeer](https://docs.godotengine.org/en/stable/classes/class_streampeer.html#class-streampeer-method-get-string)

:::info
**big_endian**
true: 大端序
false: 小端序 (little endian)

參考 [位元組順序](https://zh.wikipedia.org/zh-tw/%E5%AD%97%E8%8A%82%E5%BA%8F)

:::warning
只影響到 encode/decode 的部分, 而且僅限於 2 bytes 以上的連續資料
e.g. 假設寫入一筆 uint32 的資料 <font color=#00AA00>1234567890</font> (<font color=#00AA00>**0x499602D2**</font>)
大端序: <font color=#00AA00>**49-96-02-D2**</font>
小端序: <font color=#AA0000>**D2-02-96-49**</font>
:::

:::info
**void seek ( int position )**
設定取資料的起始位置

**int get_position ( )**
取得目前位置

:::warning
執行寫入或讀取,完成後會改變 position

e.g. 假設有一筆 6 bytes 的資料  <font color=#00AA00>00-00-00-00-00-00</font>
position 設成 0, 並讀取 4 bytes, 完成後 position = 4


**00-00-00-00-<font color=red>00</font>-00**
:::

:::info
**int get_available_bytes()**
從目前 position 到結尾的 byte 數量
如果要取得 byte array 總長度, 使用 **data_array.size()**
:::

:::info
**Array get_data ( int bytes )**
* array[0] 是 error code, 0=正常, 其他錯誤編號 [參考文件](https://docs.godotengine.org/en/stable/classes/class_@globalscope.html#enum-globalscope-error)
* array[1] 是 PoolByteArray
:::

---

###### tags: `godot`