WIP: Multiplayer broken state

This commit is contained in:
Sebastian Lohff 2025-04-09 21:50:13 +02:00
parent e59a36a922
commit cd8befccba
5 changed files with 145 additions and 11 deletions

View File

@ -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"]
custom_minimum_size = Vector2(200, 100)
@ -11,3 +14,8 @@ anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_a1ve8")
[node name="Player" type="AudioStreamPlayer" parent="."]
stream = SubResource("AudioStreamGenerator_a1ve8")
volume_db = -100.0
stream_paused = true

View File

@ -78,6 +78,10 @@ text = "Freq:"
unique_name_in_owner = true
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"]
layout_mode = 2
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/RefreshButton" to="." method="_on_refresh_button_pressed"]
[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"]

View File

@ -1,14 +1,59 @@
@tool
class_name MultiMorseBanner
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_off := Color(0, 0, 0)
var last_delta := 0.0
@export_range(0.1, 120.0) var display_sec := 5.0
@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
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):
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():
return
var morse_on := MorseState.curr_state
var first_time := Time.get_ticks_msec() - MorseState.last_change
var morse_on := morse_state.curr_state
var first_time := Time.get_ticks_msec() - morse_state.last_change
var curr_x := float(size.x)
var px_per_s := 0.0
if not stretch_display:
px_per_s = size.x / display_sec
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):
var duration := first_time if n == -1 else MorseState.states[n]
for n in [-1] + range(morse_state.states.size() - 1, -1, -1):
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)
curr_x -= rect_width
if morse_on:
@ -46,3 +91,21 @@ func _draw():
func _process(_delta):
last_delta += _delta
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)

View File

@ -4,10 +4,32 @@ var server := "localhost"
var port := "3784"
var ws := WebSocketPeer.new()
var mb_scene := preload("res://scenes/MultiMorseBanner.tscn")
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:
# FIXME: connection handling / reconnect
# FIXME: status / error messages
# FIXME: randomize default join frquency
# FIXME: automatic refresh
print("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)
match parsed["type"]:
"hello":
# fetch frequency list on first join
_on_refresh_button_pressed()
"join":
_join_freq(parsed["freq"])
@ -42,7 +67,14 @@ func _handle_packet() -> void:
var idx: int = %FreqList.add_item(text)
%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
%ConnectView.hide()
%MorseView.show()
@ -66,4 +98,26 @@ func _on_freq_list_join(index: int, at_position: Vector2, mouse_button_index: in
print("Yop ", index, " metadata ", freq)
var join_cmd := {"cmd": "join", "freq": freq, "type": "cw-generator"}
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)

View File

@ -92,7 +92,7 @@ class Client:
self.curr_freq = freq
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):
if self.curr_freq:
@ -108,9 +108,12 @@ class Client:
await self._send_error(f"Frequency {freq} not available")
return
self.curr_freq = freq
self.freqs[freq].append(self)
# 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):
await self._send(type="player-joined", player=self.id)