| … | … | @@ -187,4 +187,4 @@ nodes/walk_scale/node = SubResource( "AnimationNodeTimeScale_ox5by" ) |
| 187 | 187 | nodes/walk_scale/position = Vector2(-640, 360) |
| 188 | 188 | nodes/wall_run/node = SubResource( "AnimationNodeTransition_1e0x1" ) |
| 189 | 189 | nodes/wall_run/position = Vector2(720, -60) |
| 190 | node_connections = [&"output", 0, &"wall_run", &"roll", 0, &"air_transition", &"roll", 1, &"roll_scale", &"wall_run", 0, &"Blend2", &"wall_run", 1, &"Blend2 2", &"wall_run", 2, &"roll", &"run_scale", 0, &"Animation 5", &"landing_scale", 0, &"Animation 3", &"Blend2 2", 0, &"Animation 12", &"Blend2 2", 1, &"Animation 10", &"air_transition", 0, &"air_blend", &"air_transition", 1, &"aim_transition", &"roll_scale", 0, &"Animation", &"TimeScale 3", 0, &"strafe", &"Blend2", 0, &"Animation 8", &"Blend2", 1, &"Animation 9", &"air_blend", 0, &"jump_scale", &"air_blend", 1, &"falling_scale", &"air_blend", 2, &"landing_scale", &"jump_scale", 0, &"Animation 6", &"walk_scale", 0, &"Animation 4", &"aim_transition", 0, &"TimeScale 3", &"aim_transition", 1, &"iwr_blend", &"falling_scale", 0, &"Animation 7", &"iwr_blend", 0, &"Animation 2", &"iwr_blend", 1, &"walk_scale", &"iwr_blend", 2, &"run_scale"] | |
| 190 | node_connections = [&"output", 0, &"wall_run", &"roll", 0, &"air_transition", &"roll", 1, &"roll_scale", &"roll_scale", 0, &"Animation", &"air_transition", 0, &"air_blend", &"air_transition", 1, &"aim_transition", &"landing_scale", 0, &"Animation 3", &"falling_scale", 0, &"Animation 7", &"TimeScale 3", 0, &"strafe", &"air_blend", 0, &"jump_scale", &"air_blend", 1, &"falling_scale", &"air_blend", 2, &"landing_scale", &"jump_scale", 0, &"Animation 6", &"run_scale", 0, &"Animation 5", &"wall_run", 0, &"Blend2", &"wall_run", 1, &"Blend2 2", &"wall_run", 2, &"roll", &"walk_scale", 0, &"Animation 4", &"aim_transition", 0, &"TimeScale 3", &"aim_transition", 1, &"iwr_blend", &"Blend2 2", 0, &"Animation 12", &"Blend2 2", 1, &"Animation 10", &"Blend2", 0, &"Animation 8", &"Blend2", 1, &"Animation 9", &"iwr_blend", 0, &"Animation 2", &"iwr_blend", 1, &"walk_scale", &"iwr_blend", 2, &"run_scale"] |
| … | … | @@ -0,0 +1,160 @@ |
| 1 | extends "res://src/ResizeRoot.gd" | |
| 2 | ||
| 3 | const LRU = preload('res://src/utils/LRU.gd') | |
| 4 | ||
| 5 | # Messages are JSON which contain {id, from, username, type, content} | |
| 6 | # All messages have a username and type | |
| 7 | # Some messages contain a `from` for peer that sent the message | |
| 8 | # If no `from` field is visible, it means it's from the sending peer | |
| 9 | # type: 'text` will have `content` of the text message that got sent | |
| 10 | # type: 'identity' will have empty `content`, and is there to notify peers of this users existence | |
| 11 | ||
| 12 | # GET peer list to start registering for extensions | |
| 13 | # Set up list of seen remotePublicKeys | |
| 14 | # Broadcast self after a second of waiting for peers | |
| 15 | # Broadcast self on name change | |
| 16 | # Broadcast self when seeing a new remotePublicKey | |
| 17 | ||
| 18 | export var archiveRoot = 'hyper://blog.mauve.moe/' | |
| 19 | #export var archiveRoot = 'hyper://70338a94d7415990ab4a3160cf98a5d940243d7fa24dd297352e66b52d3ff841/' | |
| 20 | export var extensionName = 'hyperchat-example-1' | |
| 21 | ||
| 22 | var extensionsFolder = archiveRoot + '$/extensions/' | |
| 23 | var extensionPath = extensionsFolder + extensionName | |
| 24 | ||
| 25 | var seen_messages = LRU.new() | |
| 26 | var seen_identities = LRU.new() | |
| 27 | ||
| 28 | onready var eventSource = $HyperGateway/HyperEventSource | |
| 29 | onready var gateway = $HyperGateway | |
| 30 | onready var chatBox = $ScrollContainer/ChatBox | |
| 31 | onready var chatText = $HBoxContainer/ChatInput | |
| 32 | onready var username = $HBoxContainer/Username | |
| 33 | onready var broadcastRequest = $HyperGateway/BroadcastRequest | |
| 34 | onready var listPeersRequest = $HyperGateway/ListPeersRequest | |
| 35 | ||
| 36 | func _ready(): | |
| 37 | # Initialize random number generator | |
| 38 | randomize() | |
| 39 | gateway.start() | |
| 40 | ||
| 41 | func display_item(from, content): | |
| 42 | # Add to item list | |
| 43 | chatBox.text += from + ': ' + content + "\n" | |
| 44 | ||
| 45 | func send_current(): | |
| 46 | var text = chatText.text | |
| 47 | chatText.text = "" | |
| 48 | display_item(get_username(), text) | |
| 49 | broadcast_text(text) | |
| 50 | ||
| 51 | func update_identity(_from, username): | |
| 52 | # Have some sort of sidebar to display known users? | |
| 53 | display_item('System', 'Seen user ' + username) | |
| 54 | pass | |
| 55 | ||
| 56 | func list_peers(): | |
| 57 | listPeersRequest.request(extensionPath) | |
| 58 | ||
| 59 | func _on_text_message(data, _from): | |
| 60 | # TODO: Something fancy with the `from` attribute? | |
| 61 | display_item(data.username, data.content) | |
| 62 | ||
| 63 | func _on_identity_message(_data, from): | |
| 64 | var isNew = !has_seen_identity(from) | |
| 65 | ||
| 66 | # Track identity | |
| 67 | seen_identities.track(from) | |
| 68 | ||
| 69 | # If it's new, broadcast your own identity | |
| 70 | if isNew: | |
| 71 | broadcast_identity() | |
| 72 | ||
| 73 | func _on_unknown_message(data, from): | |
| 74 | # Emit some sort of error? | |
| 75 | printerr("Got unknown message", from, data) | |
| 76 | ||
| 77 | func get_username(): | |
| 78 | return username.text | |
| 79 | ||
| 80 | func broadcast_text(content): | |
| 81 | var username = get_username() | |
| 82 | broadcast_message({ | |
| 83 | 'type': 'text', | |
| 84 | 'content': content, | |
| 85 | 'username': username | |
| 86 | }) | |
| 87 | ||
| 88 | func broadcast_identity(): | |
| 89 | var username = get_username() | |
| 90 | broadcast_message({ | |
| 91 | 'type': 'identity', | |
| 92 | 'username': username | |
| 93 | }) | |
| 94 | ||
| 95 | func broadcast_message(message): | |
| 96 | # POST to extension URL | |
| 97 | if !("id" in message): | |
| 98 | message.id = make_id() | |
| 99 | seen_messages.track(message.id) | |
| 100 | print('Broadcasting message', message, extensionPath) | |
| 101 | var body = JSON.print(message) | |
| 102 | broadcastRequest.request(extensionPath,[], false, HTTPClient.METHOD_POST, body) | |
| 103 | ||
| 104 | func has_seen_identity(from): | |
| 105 | return seen_identities.has(from) | |
| 106 | ||
| 107 | func has_seen_message(id): | |
| 108 | return seen_messages.has(id) | |
| 109 | ||
| 110 | func re_broadcast(message, from): | |
| 111 | if !("from" in message): | |
| 112 | message.from = from | |
| 113 | broadcast_message(message) | |
| 114 | ||
| 115 | func handle_message(message, from): | |
| 116 | var finalFrom = message.from if "from" in message else from | |
| 117 | if !("id" in message): | |
| 118 | return _on_unknown_message(message, finalFrom) | |
| 119 | if has_seen_message(message.id): | |
| 120 | return | |
| 121 | ||
| 122 | re_broadcast(message, finalFrom) | |
| 123 | match message.type: | |
| 124 | 'text': | |
| 125 | _on_text_message(message, finalFrom) | |
| 126 | 'identity': | |
| 127 | _on_identity_message(message, finalFrom) | |
| 128 | _: | |
| 129 | _on_unknown_message(message, finalFrom) | |
| 130 | ||
| 131 | func _on_event(data, _event, id): | |
| 132 | var parsed = JSON.parse(data) | |
| 133 | ||
| 134 | if parsed.error != OK: | |
| 135 | printerr("Unable to parse EventSource content " + parsed.error_line + "\n" + data) | |
| 136 | return | |
| 137 | ||
| 138 | handle_message(parsed.result, id) | |
| 139 | ||
| 140 | func make_id(): | |
| 141 | return str(randi()) + str(randi()) | |
| 142 | ||
| 143 | func start_listening(): | |
| 144 | eventSource.request(extensionsFolder) | |
| 145 | ||
| 146 | func _on_HyperEventSource_event(data, event, id): | |
| 147 | _on_event(data, event, id) | |
| 148 | ||
| 149 | func _on_HyperGateway_started_gateway(_pid): | |
| 150 | start_listening() | |
| 151 | list_peers() | |
| 152 | broadcast_identity() | |
| 153 | ||
| 154 | func _on_SendButton_pressed(): | |
| 155 | send_current() | |
| 156 | pass # Replace with function body. | |
| 157 | ||
| 158 | func _on_ChatInput_text_entered(_new_text): | |
| 159 | send_current() | |
| 160 | pass # Replace with function body. |
| … | … | @@ -0,0 +1,68 @@ |
| 1 | [gd_scene load_steps=5 format=3] | |
| 2 | ||
| 3 | [ext_resource type="Script" path="res://menu/chat/HyperChat/HyperChat.gd" id="1"] | |
| 4 | [ext_resource type="PackedScene" uid="uid://cue2rke35i36o" path="res://hypergodot/hyper_gateway/hyper_gateway.tscn" id="2"] | |
| 5 | [ext_resource type="Script" path="res://hypergodot/hyper_gateway/hyper_gateway.gd" id="3"] | |
| 6 | [ext_resource type="Script" path="res://hypergodot/hyper_request/hyper_request.gd" id="4"] | |
| 7 | ||
| 8 | [node name="Control" type="VBoxContainer"] | |
| 9 | anchor_right = 1.0 | |
| 10 | anchor_bottom = 1.0 | |
| 11 | script = ExtResource( 1 ) | |
| 12 | __meta__ = { | |
| 13 | "_edit_use_anchors_": false | |
| 14 | } | |
| 15 | ||
| 16 | [node name="HBoxContainer" type="HBoxContainer" parent="."] | |
| 17 | margin_right = 666.0 | |
| 18 | margin_bottom = 24.0 | |
| 19 | ||
| 20 | [node name="ChatInput" type="LineEdit" parent="HBoxContainer"] | |
| 21 | margin_right = 487.0 | |
| 22 | margin_bottom = 24.0 | |
| 23 | size_flags_horizontal = 3 | |
| 24 | ||
| 25 | [node name="SendButton" type="Button" parent="HBoxContainer"] | |
| 26 | margin_left = 491.0 | |
| 27 | margin_right = 534.0 | |
| 28 | margin_bottom = 24.0 | |
| 29 | text = "Send" | |
| 30 | ||
| 31 | [node name="Username" type="LineEdit" parent="HBoxContainer"] | |
| 32 | margin_left = 538.0 | |
| 33 | margin_right = 666.0 | |
| 34 | margin_bottom = 24.0 | |
| 35 | rect_min_size = Vector2( 128, 0 ) | |
| 36 | text = "Anonymous" | |
| 37 | ||
| 38 | [node name="ScrollContainer" type="ScrollContainer" parent="."] | |
| 39 | margin_top = 28.0 | |
| 40 | margin_right = 666.0 | |
| 41 | margin_bottom = 666.0 | |
| 42 | size_flags_horizontal = 3 | |
| 43 | size_flags_vertical = 3 | |
| 44 | ||
| 45 | [node name="ChatBox" type="RichTextLabel" parent="ScrollContainer"] | |
| 46 | margin_right = 666.0 | |
| 47 | margin_bottom = 638.0 | |
| 48 | size_flags_horizontal = 3 | |
| 49 | size_flags_vertical = 3 | |
| 50 | text = "System: Enter some text and hit `send` to broadcast it to peers. | |
| 51 | " | |
| 52 | ||
| 53 | [node name="HyperGateway" parent="." instance=ExtResource( 2 )] | |
| 54 | autoStart = false | |
| 55 | ||
| 56 | [node name="HyperEventSource" type="Node" parent="HyperGateway"] | |
| 57 | script = ExtResource( 3 ) | |
| 58 | ||
| 59 | [node name="BroadcastRequest" type="HTTPRequest" parent="HyperGateway"] | |
| 60 | script = ExtResource( 4 ) | |
| 61 | ||
| 62 | [node name="ListPeersRequest" type="HTTPRequest" parent="HyperGateway"] | |
| 63 | script = ExtResource( 4 ) | |
| 64 | ||
| 65 | [connection signal="text_entered" from="HBoxContainer/ChatInput" to="." method="_on_ChatInput_text_entered"] | |
| 66 | [connection signal="pressed" from="HBoxContainer/SendButton" to="." method="_on_SendButton_pressed"] | |
| 67 | [connection signal="started_gateway" from="HyperGateway" to="." method="_on_HyperGateway_started_gateway"] | |
| 68 | [connection signal="event" from="HyperGateway/HyperEventSource" to="." method="_on_HyperEventSource_event"] |