WIP: Multiplayer broken state
This commit is contained in:
parent
e59a36a922
commit
cd8befccba
|
@ -1,6 +1,9 @@
|
||||||
[gd_scene load_steps=2 format=3 uid="uid://ug3u6jf36dst"]
|
[gd_scene load_steps=3 format=3 uid="uid://ug3u6jf36dst"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://j1oei8suq5sj" path="res://scenes/morse_banner.gd" id="1_a1ve8"]
|
[ext_resource type="Script" uid="uid://b1k6j1jti114u" path="res://scenes/multi_morse_banner.gd" id="1_a1ve8"]
|
||||||
|
|
||||||
|
[sub_resource type="AudioStreamGenerator" id="AudioStreamGenerator_a1ve8"]
|
||||||
|
mix_rate = 22050.0
|
||||||
|
|
||||||
[node name="MorseBanner" type="Control"]
|
[node name="MorseBanner" type="Control"]
|
||||||
custom_minimum_size = Vector2(200, 100)
|
custom_minimum_size = Vector2(200, 100)
|
||||||
|
@ -11,3 +14,8 @@ anchor_bottom = 1.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
script = ExtResource("1_a1ve8")
|
script = ExtResource("1_a1ve8")
|
||||||
|
|
||||||
|
[node name="Player" type="AudioStreamPlayer" parent="."]
|
||||||
|
stream = SubResource("AudioStreamGenerator_a1ve8")
|
||||||
|
volume_db = -100.0
|
||||||
|
stream_paused = true
|
||||||
|
|
|
@ -78,6 +78,10 @@ text = "Freq:"
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="PlayerContainer" type="VBoxContainer" parent="MorseView/VBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
[node name="MorseButton" type="Button" parent="MorseView/VBoxContainer"]
|
[node name="MorseButton" type="Button" parent="MorseView/VBoxContainer"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
|
@ -87,3 +91,5 @@ text = "MORSE"
|
||||||
[connection signal="pressed" from="ConnectView/VBoxContainer/HBoxContainer/CreateButton" to="." method="_on_create_button_pressed"]
|
[connection signal="pressed" from="ConnectView/VBoxContainer/HBoxContainer/CreateButton" to="." method="_on_create_button_pressed"]
|
||||||
[connection signal="pressed" from="ConnectView/VBoxContainer/RefreshButton" to="." method="_on_refresh_button_pressed"]
|
[connection signal="pressed" from="ConnectView/VBoxContainer/RefreshButton" to="." method="_on_refresh_button_pressed"]
|
||||||
[connection signal="item_clicked" from="ConnectView/VBoxContainer/FreqList" to="." method="_on_freq_list_join"]
|
[connection signal="item_clicked" from="ConnectView/VBoxContainer/FreqList" to="." method="_on_freq_list_join"]
|
||||||
|
[connection signal="button_down" from="MorseView/VBoxContainer/MorseButton" to="." method="_on_morse_button_button_down"]
|
||||||
|
[connection signal="button_up" from="MorseView/VBoxContainer/MorseButton" to="." method="_on_morse_button_button_up"]
|
||||||
|
|
|
@ -1,14 +1,59 @@
|
||||||
@tool
|
@tool
|
||||||
|
class_name MultiMorseBanner
|
||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
|
static var sample_hz := 22050.0
|
||||||
|
static var vol_on := -30
|
||||||
|
var phase := 0.0
|
||||||
|
|
||||||
|
var num: int
|
||||||
|
var tone_hz: int
|
||||||
var color_on := Color(0, 128, 0)
|
var color_on := Color(0, 128, 0)
|
||||||
var color_off := Color(0, 0, 0)
|
var color_off := Color(0, 0, 0)
|
||||||
var last_delta := 0.0
|
var last_delta := 0.0
|
||||||
@export_range(0.1, 120.0) var display_sec := 5.0
|
@export_range(0.1, 120.0) var display_sec := 5.0
|
||||||
@export var stretch_display := false
|
@export var stretch_display := false
|
||||||
|
var playback;
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
$Player.stream.mix_rate = sample_hz
|
||||||
|
$Player.volume_db = -100
|
||||||
|
$Player.play()
|
||||||
|
playback = $Player.get_stream_playback()
|
||||||
|
fill_buffer()
|
||||||
|
|
||||||
var morse_step_perc := 0.45
|
var morse_step_perc := 0.45
|
||||||
|
const MMB_SCENE := preload("res://scenes/MultiMorseBanner.tscn")
|
||||||
|
|
||||||
|
class LocalMorseState:
|
||||||
|
var states: Array[int] = []
|
||||||
|
var curr_state := false
|
||||||
|
var last_change: int = 0
|
||||||
|
var start_time := 0
|
||||||
|
|
||||||
|
func reset() -> void:
|
||||||
|
last_change = Time.get_ticks_msec()
|
||||||
|
start_time = last_change
|
||||||
|
states = []
|
||||||
|
|
||||||
|
func set_state(state: bool) -> void:
|
||||||
|
if state == curr_state:
|
||||||
|
return
|
||||||
|
curr_state = state
|
||||||
|
|
||||||
|
var now := Time.get_ticks_msec()
|
||||||
|
states.push_back(now - last_change)
|
||||||
|
last_change = now
|
||||||
|
|
||||||
|
var morse_state := LocalMorseState.new()
|
||||||
|
|
||||||
|
static func new_banner(num: int, color: Color, tone: int):
|
||||||
|
var mmb = MMB_SCENE.instantiate()
|
||||||
|
mmb.num = num
|
||||||
|
mmb.color_on = color
|
||||||
|
mmb.tone_hz = tone
|
||||||
|
|
||||||
|
return mmb
|
||||||
|
|
||||||
func _draw_morse_rect(x: float, width: float, state: bool):
|
func _draw_morse_rect(x: float, width: float, state: bool):
|
||||||
var rect := Rect2(max(x, 0.0), morse_step_perc * size.y, width, (0.5 - morse_step_perc) * size.y)
|
var rect := Rect2(max(x, 0.0), morse_step_perc * size.y, width, (0.5 - morse_step_perc) * size.y)
|
||||||
|
@ -22,18 +67,18 @@ func _draw():
|
||||||
if Engine.is_editor_hint():
|
if Engine.is_editor_hint():
|
||||||
return
|
return
|
||||||
|
|
||||||
var morse_on := MorseState.curr_state
|
var morse_on := morse_state.curr_state
|
||||||
var first_time := Time.get_ticks_msec() - MorseState.last_change
|
var first_time := Time.get_ticks_msec() - morse_state.last_change
|
||||||
var curr_x := float(size.x)
|
var curr_x := float(size.x)
|
||||||
|
|
||||||
var px_per_s := 0.0
|
var px_per_s := 0.0
|
||||||
if not stretch_display:
|
if not stretch_display:
|
||||||
px_per_s = size.x / display_sec
|
px_per_s = size.x / display_sec
|
||||||
else:
|
else:
|
||||||
px_per_s = size.x / (Time.get_ticks_msec() - MorseState.start_time) * 1000.0
|
px_per_s = size.x / (Time.get_ticks_msec() - morse_state.start_time) * 1000.0
|
||||||
|
|
||||||
for n in [-1] + range(MorseState.states.size() - 1, -1, -1):
|
for n in [-1] + range(morse_state.states.size() - 1, -1, -1):
|
||||||
var duration := first_time if n == -1 else MorseState.states[n]
|
var duration := first_time if n == -1 else morse_state.states[n]
|
||||||
var rect_width: float = min(duration / 1000.0 * px_per_s, curr_x)
|
var rect_width: float = min(duration / 1000.0 * px_per_s, curr_x)
|
||||||
curr_x -= rect_width
|
curr_x -= rect_width
|
||||||
if morse_on:
|
if morse_on:
|
||||||
|
@ -46,3 +91,21 @@ func _draw():
|
||||||
func _process(_delta):
|
func _process(_delta):
|
||||||
last_delta += _delta
|
last_delta += _delta
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
|
fill_buffer()
|
||||||
|
|
||||||
|
func set_morse_state(state: bool) -> void:
|
||||||
|
morse_state.set_state(state)
|
||||||
|
# morse_state = state
|
||||||
|
if state:
|
||||||
|
$Player.volume_db = vol_on
|
||||||
|
else:
|
||||||
|
$Player.volume_db = -100
|
||||||
|
|
||||||
|
func fill_buffer():
|
||||||
|
var increment = tone_hz / sample_hz
|
||||||
|
var frames_available = playback.get_frames_available()
|
||||||
|
|
||||||
|
for i in range(frames_available):
|
||||||
|
playback.push_frame(Vector2.ONE * sin(phase * TAU))
|
||||||
|
phase = fmod(phase + increment, 1.0)
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,32 @@ var server := "localhost"
|
||||||
var port := "3784"
|
var port := "3784"
|
||||||
var ws := WebSocketPeer.new()
|
var ws := WebSocketPeer.new()
|
||||||
|
|
||||||
var mb_scene := preload("res://scenes/MultiMorseBanner.tscn")
|
|
||||||
var available_freqs = []
|
var available_freqs = []
|
||||||
|
var mmb_self: MultiMorseBanner
|
||||||
|
var mmb_others: Dictionary[String, MultiMorseBanner]
|
||||||
|
|
||||||
|
class PlayerData:
|
||||||
|
var num: int
|
||||||
|
var color: Color
|
||||||
|
var tone: int
|
||||||
|
|
||||||
|
func _init(num, color, tone):
|
||||||
|
self.num = num
|
||||||
|
self.color = color
|
||||||
|
self.tone = tone
|
||||||
|
|
||||||
|
var player_data := [
|
||||||
|
PlayerData.new(0, Color( 0, 255, 0), 880),
|
||||||
|
PlayerData.new(1, Color(255, 0, 0), 880),
|
||||||
|
PlayerData.new(2, Color( 0, 0, 255), 880),
|
||||||
|
PlayerData.new(3, Color(255, 0, 255), 880),
|
||||||
|
]
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
# FIXME: connection handling / reconnect
|
||||||
|
# FIXME: status / error messages
|
||||||
|
# FIXME: randomize default join frquency
|
||||||
|
# FIXME: automatic refresh
|
||||||
print("ws://%s:%s" % [server, port])
|
print("ws://%s:%s" % [server, port])
|
||||||
ws.connect_to_url("ws://%s:%s" % [server, port])
|
ws.connect_to_url("ws://%s:%s" % [server, port])
|
||||||
|
|
||||||
|
@ -31,6 +53,9 @@ func _handle_packet() -> void:
|
||||||
print("parsed ", parsed)
|
print("parsed ", parsed)
|
||||||
|
|
||||||
match parsed["type"]:
|
match parsed["type"]:
|
||||||
|
"hello":
|
||||||
|
# fetch frequency list on first join
|
||||||
|
_on_refresh_button_pressed()
|
||||||
"join":
|
"join":
|
||||||
_join_freq(parsed["freq"])
|
_join_freq(parsed["freq"])
|
||||||
|
|
||||||
|
@ -42,7 +67,14 @@ func _handle_packet() -> void:
|
||||||
var idx: int = %FreqList.add_item(text)
|
var idx: int = %FreqList.add_item(text)
|
||||||
%FreqList.set_item_metadata(idx, freq)
|
%FreqList.set_item_metadata(idx, freq)
|
||||||
|
|
||||||
func _join_freq(freq: String):
|
func _join_freq(freq: String, player_id: String, other_players: Array[String]):
|
||||||
|
for child in %PlayerContainer.get_children():
|
||||||
|
%PlayerContainer.remove_child(child)
|
||||||
|
|
||||||
|
mmb_self = make_player(0)
|
||||||
|
for n, player_id in enumeerate(other_players):
|
||||||
|
make_player(n + 1)
|
||||||
|
|
||||||
%FreqLabel.text = "%s MHz" % freq
|
%FreqLabel.text = "%s MHz" % freq
|
||||||
%ConnectView.hide()
|
%ConnectView.hide()
|
||||||
%MorseView.show()
|
%MorseView.show()
|
||||||
|
@ -67,3 +99,25 @@ func _on_freq_list_join(index: int, at_position: Vector2, mouse_button_index: in
|
||||||
var join_cmd := {"cmd": "join", "freq": freq, "type": "cw-generator"}
|
var join_cmd := {"cmd": "join", "freq": freq, "type": "cw-generator"}
|
||||||
ws.send_text(JSON.stringify(join_cmd) + "\n")
|
ws.send_text(JSON.stringify(join_cmd) + "\n")
|
||||||
|
|
||||||
|
func make_player(no: int):
|
||||||
|
var pd: PlayerData
|
||||||
|
if no < player_data.size():
|
||||||
|
pd = player_data[no]
|
||||||
|
else:
|
||||||
|
pd = PlayerData.new(no, Color(randi_range(0, 255), randi_range(0, 255), randi_range(0, 255)), randi_range(440, 440 * 3))
|
||||||
|
|
||||||
|
var mmb = MultiMorseBanner.new_banner(pd.num, pd.color, pd.tone)
|
||||||
|
%PlayerContainer.add_child(mmb)
|
||||||
|
return mmb
|
||||||
|
|
||||||
|
|
||||||
|
func _on_morse_button_button_down() -> void:
|
||||||
|
if not mmb_self:
|
||||||
|
return
|
||||||
|
mmb_self.set_morse_state(true)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_morse_button_button_up() -> void:
|
||||||
|
if not mmb_self:
|
||||||
|
return
|
||||||
|
mmb_self.set_morse_state(false)
|
||||||
|
|
|
@ -92,7 +92,7 @@ class Client:
|
||||||
|
|
||||||
self.curr_freq = freq
|
self.curr_freq = freq
|
||||||
self.freqs[freq] = [self]
|
self.freqs[freq] = [self]
|
||||||
await self._send(type="join", freq=self.curr_freq, others=[])
|
await self._send(type="join", freq=self.curr_freq, self_id=self.id, others=[])
|
||||||
|
|
||||||
async def _join_room(self, data):
|
async def _join_room(self, data):
|
||||||
if self.curr_freq:
|
if self.curr_freq:
|
||||||
|
@ -108,9 +108,12 @@ class Client:
|
||||||
await self._send_error(f"Frequency {freq} not available")
|
await self._send_error(f"Frequency {freq} not available")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self.curr_freq = freq
|
||||||
self.freqs[freq].append(self)
|
self.freqs[freq].append(self)
|
||||||
# FIXME: do we need locking here?
|
# FIXME: do we need locking here?
|
||||||
await self._send(type="join", freq=self.curr_freq, players=[c.id for c in self._others(freq)])
|
print("FREQ", self.curr_freq, freq, self.freqs)
|
||||||
|
await self._send(type="join", freq=self.curr_freq, self_id=self.id, players=[c.id for c in self._others(freq)
|
||||||
|
if not c.id == self.id])
|
||||||
for other in self._others(freq):
|
for other in self._others(freq):
|
||||||
await self._send(type="player-joined", player=self.id)
|
await self._send(type="player-joined", player=self.id)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue