Compare commits

..

No commits in common. "trunk" and "story/td-18-matchmaking" have entirely different histories.

37 changed files with 1825 additions and 911 deletions

View file

@ -3,9 +3,9 @@ _choose:
lint:
-gdlint .
-gdformat .
-gdformat -d .
api_version := "v0.0.0-rc.8"
api_version := "v0.0.0-rc.4"
api_location := "scripts/api-client"
generate:
#!/bin/sh

View file

@ -37,7 +37,7 @@ loop-variable-name: _?[a-z][a-z0-9]*(_[a-z0-9]+)*
max-file-lines: 1000
max-line-length: 80
max-public-methods: 20
max-returns: 20
max-returns: 6
mixed-tabs-and-spaces: null
no-elif-return: null
no-else-return: null

View file

@ -18,14 +18,6 @@ config/icon="res://textures/icon.svg"
[autoload]
ConnectionChannel="*res://scripts/channel/connection/connection_channel.gd"
MatchmakingChannel="*res://scripts/channel/matchmaking/matchmaking_channel.gd"
MatchChannel="*res://scripts/channel/match/match_channel.gd"
CurrentMatch="*res://scripts/match/current_match.gd"
[display]
window/size/viewport_width=1920
window/size/viewport_height=1080
[editor_plugins]
@ -35,14 +27,6 @@ enabled=PackedStringArray("res://addons/format_on_save/plugin.cfg")
theme/custom="res://ui/theme.tres"
[input]
place={
"deadzone": 0.0,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null)
]
}
[rendering]
renderer/rendering_method="gl_compatibility"

View file

@ -1,107 +0,0 @@
[gd_scene load_steps=7 format=4 uid="uid://co1x3hlc2efr6"]
[ext_resource type="Script" path="res://scripts/match/ui/opponent_name.gd" id="1_saby1"]
[ext_resource type="Script" path="res://scripts/match/ui/player_money.gd" id="2_3jcub"]
[ext_resource type="TileSet" uid="uid://cvp867israfjk" path="res://tile_set.tres" id="3_0etcd"]
[ext_resource type="Script" path="res://scripts/match/ui/player_hitpoints.gd" id="3_oc5vk"]
[ext_resource type="Script" path="res://scripts/match/map.gd" id="4_4c550"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_86u83"]
bg_color = Color(0.198848, 0.584132, 0.720474, 1)
[node name="Game" type="Node2D"]
[node name="UI" type="CanvasLayer" parent="."]
[node name="HUD" type="Control" parent="UI"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Opponent Name" type="RichTextLabel" parent="UI/HUD"]
layout_mode = 1
anchors_preset = 5
anchor_left = 0.5
anchor_right = 0.5
offset_left = -0.5
offset_right = 0.5
offset_bottom = 45.0
grow_horizontal = 2
text = "Unknown"
fit_content = true
scroll_active = false
autowrap_mode = 0
script = ExtResource("1_saby1")
[node name="Money" type="RichTextLabel" parent="UI/HUD"]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -582.0
offset_top = -529.0
offset_right = -436.0
offset_bottom = -484.0
grow_horizontal = 2
grow_vertical = 2
text = "Test"
fit_content = true
scroll_active = false
autowrap_mode = 0
script = ExtResource("2_3jcub")
[node name="Hitpoints" type="RichTextLabel" parent="UI/HUD"]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -946.0
offset_top = 479.0
offset_right = -800.0
offset_bottom = 524.0
grow_horizontal = 2
grow_vertical = 2
text = "HP
"
fit_content = true
scroll_active = false
autowrap_mode = 0
script = ExtResource("3_oc5vk")
[node name="Seperator" type="Panel" parent="UI/HUD"]
custom_minimum_size = Vector2(4, 0)
layout_mode = 1
anchors_preset = 13
anchor_left = 0.5
anchor_right = 0.5
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_86u83")
[node name="Camera" type="Camera2D" parent="."]
[node name="Map" type="Node2D" parent="." node_paths=PackedStringArray("player_map", "player_tower_map", "opponent_map", "opponent_tower_map", "camera")]
script = ExtResource("4_4c550")
tile_set = ExtResource("3_0etcd")
player_map = NodePath("PlayerMap")
player_tower_map = NodePath("PlayerMap/Tower")
opponent_map = NodePath("OpentMap")
opponent_tower_map = NodePath("OpentMap/Tower")
camera = NodePath("../Camera")
[node name="PlayerMap" type="Node2D" parent="Map"]
[node name="Tower" type="TileMapLayer" parent="Map/PlayerMap"]
[node name="OpentMap" type="Node2D" parent="Map"]
[node name="Tower" type="TileMapLayer" parent="Map/OpentMap"]
tile_map_data = PackedByteArray("AAAAAAAAAQAAAAAAAAAAAAEAAQAAAAAAAAAAAAIAAQAAAAAAAAAAAAMAAQAAAAAAAAAAAAQAAQAAAAAAAAAAAAUAAQAAAAAAAAAAAAYAAQAAAAAAAAAAAAcAAQAAAAAAAAAAAAgAAQAAAAAAAAAAAAkAAQAAAAAAAAAAAAoAAQAAAAAAAAAAAAsAAQAAAAAAAAAAAAwAAQAAAAAAAAAAAA0AAQAAAAAAAAAAAA4AAQAAAAAAAAAAAA8AAQAAAAAAAAAAABAAAQAAAAAAAAAAABEAAQAAAAAAAAAAABIAAQAAAAAAAAAAABMAAQAAAAAAAAABAAAAAQAAAAAAAAABABMAAQAAAAAAAAACAAAAAQAAAAAAAAACABMAAQAAAAAAAAADAAAAAQAAAAAAAAADABMAAQAAAAAAAAAEAAAAAQAAAAAAAAAEABMAAQAAAAAAAAAFAAAAAQAAAAAAAAAFABMAAQAAAAAAAAAGAAAAAQAAAAAAAAAGABMAAQAAAAAAAAAHAAAAAQAAAAAAAAAHABMAAQAAAAAAAAAIAAAAAQAAAAAAAAAIABMAAQAAAAAAAAAJAAAAAQAAAAAAAAAJAAEAAQAAAAAAAAAJAAIAAQAAAAAAAAAJAAMAAQAAAAAAAAAJAAQAAQAAAAAAAAAJAAUAAQAAAAAAAAAJAAYAAQAAAAAAAAAJAAcAAQAAAAAAAAAJAAgAAQAAAAAAAAAJAAkAAQAAAAAAAAAJAAoAAQAAAAAAAAAJAAsAAQAAAAAAAAAJAAwAAQAAAAAAAAAJAA0AAQAAAAAAAAAJAA4AAQAAAAAAAAAJAA8AAQAAAAAAAAAJABAAAQAAAAAAAAAJABEAAQAAAAAAAAAJABIAAQAAAAAAAAAJABMAAQAAAAAAAAA=")

86
scenes/login.tscn Normal file
View file

@ -0,0 +1,86 @@
[gd_scene load_steps=4 format=3 uid="uid://dtaaw31x3n22f"]
[ext_resource type="Script" path="res://scripts/ui/login.gd" id="1_12w35"]
[ext_resource type="Resource" uid="uid://cdixdbu3sqgjn" path="res://config/api_config.tres" id="2_60hb8"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_d0bbp"]
[node name="Login" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Panel" type="Panel" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_d0bbp")
[node name="VBoxContainer" type="VBoxContainer" parent="Panel"]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -150.0
offset_top = -108.0
offset_right = 150.0
offset_bottom = 108.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/separation = 16
[node name="Header" type="RichTextLabel" parent="Panel/VBoxContainer"]
layout_mode = 2
theme_override_font_sizes/normal_font_size = 30
text = "Login"
fit_content = true
scroll_active = false
autowrap_mode = 0
[node name="InputContainer" type="VBoxContainer" parent="Panel/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 8
[node name="UsernameContainer" type="VBoxContainer" parent="Panel/VBoxContainer/InputContainer"]
layout_mode = 2
[node name="UsernameLabel" type="RichTextLabel" parent="Panel/VBoxContainer/InputContainer/UsernameContainer"]
layout_mode = 2
text = "Username:
"
fit_content = true
scroll_active = false
[node name="UsernameInput" type="LineEdit" parent="Panel/VBoxContainer/InputContainer/UsernameContainer"]
layout_mode = 2
[node name="PasswordContainer" type="VBoxContainer" parent="Panel/VBoxContainer/InputContainer"]
layout_mode = 2
[node name="PaswordLabel" type="RichTextLabel" parent="Panel/VBoxContainer/InputContainer/PasswordContainer"]
layout_mode = 2
text = "Password:"
fit_content = true
scroll_active = false
[node name="PasswordInput" type="LineEdit" parent="Panel/VBoxContainer/InputContainer/PasswordContainer"]
layout_mode = 2
secret = true
[node name="Button" type="Button" parent="Panel/VBoxContainer" node_paths=PackedStringArray("username_field", "password_field")]
layout_mode = 2
text = "Login"
script = ExtResource("1_12w35")
username_field = NodePath("../InputContainer/UsernameContainer/UsernameInput")
password_field = NodePath("../InputContainer/PasswordContainer/PasswordInput")
api_config = ExtResource("2_60hb8")
[node name="HTTPRequest" type="HTTPRequest" parent="Panel/VBoxContainer/Button"]

View file

@ -1,24 +1,7 @@
[gd_scene load_steps=12 format=3 uid="uid://bqfijb7bk2g7j"]
[gd_scene load_steps=3 format=3 uid="uid://bqfijb7bk2g7j"]
[ext_resource type="Theme" uid="uid://bt4hxdwromnxs" path="res://ui/theme.tres" id="1_6qgep"]
[ext_resource type="Script" path="res://scripts/ui/login/show_banner_on_error.gd" id="2_1tbi1"]
[ext_resource type="Script" path="res://scripts/ui/swap_menu.gd" id="2_c477a"]
[ext_resource type="Script" path="res://scripts/ui/login/login.gd" id="3_33cgr"]
[ext_resource type="Resource" uid="uid://cdixdbu3sqgjn" path="res://config/api_config.tres" id="4_5vuod"]
[ext_resource type="Script" path="res://scripts/ui/quit.gd" id="6_cixwl"]
[ext_resource type="Script" path="res://scripts/ui/lobby/search_match.gd" id="7_dmfpl"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_q2pxx"]
bg_color = Color(0.52, 0.52, 0.52, 1)
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_socr1"]
bg_color = Color(0.74463, 0.147328, 0, 1)
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_fh0xh"]
bg_color = Color(0.135012, 0.135012, 0.135012, 1)
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_x4jly"]
bg_color = Color(7.89344e-06, 0.65411, 0.87403, 1)
[ext_resource type="Script" path="res://scripts/ui/switch_to_scene.gd" id="2_c477a"]
[node name="Root" type="Panel"]
anchors_preset = 15
@ -29,26 +12,22 @@ offset_right = -1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("1_6qgep")
theme_override_styles/panel = SubResource("StyleBoxFlat_q2pxx")
[node name="Screens" type="TabContainer" parent="."]
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -180.5
offset_top = -44.0
offset_right = 180.5
offset_bottom = 44.0
grow_horizontal = 2
grow_vertical = 2
current_tab = 0
tabs_visible = false
[node name="Start" type="CenterContainer" parent="Screens"]
layout_mode = 2
metadata/_tab_index = 0
[node name="V" type="VBoxContainer" parent="Screens/Start"]
layout_mode = 2
[node name="Title" type="RichTextLabel" parent="Screens/Start/V"]
[node name="Text" type="RichTextLabel" parent="VBoxContainer"]
clip_contents = false
layout_mode = 2
size_flags_stretch_ratio = 7.45
@ -58,141 +37,14 @@ fit_content = true
scroll_active = false
autowrap_mode = 0
[node name="Login" type="Button" parent="Screens/Start/V" node_paths=PackedStringArray("menu")]
[node name="Button" type="Button" parent="VBoxContainer"]
layout_mode = 2
text = "Login"
script = ExtResource("2_c477a")
menu = NodePath("../../../Login")
scene_name = "login"
[node name="Settings" type="Button" parent="Screens/Start/V"]
[node name="Button2" type="Button" parent="VBoxContainer"]
layout_mode = 2
text = "Settings"
text = "Testszene"
script = ExtResource("2_c477a")
[node name="Quit" type="Button" parent="Screens/Start/V"]
layout_mode = 2
text = "Quit"
script = ExtResource("6_cixwl")
[node name="Login" type="VBoxContainer" parent="Screens"]
visible = false
layout_mode = 2
metadata/_tab_index = 1
[node name="Banner" type="PanelContainer" parent="Screens/Login" node_paths=PackedStringArray("login", "text")]
layout_mode = 2
script = ExtResource("2_1tbi1")
login = NodePath("../CenterContainer/VBoxContainer/Actions/Login")
text = NodePath("CenterContainer/MarginContainer/RichTextLabel")
[node name="Panel" type="Panel" parent="Screens/Login/Banner"]
layout_mode = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_socr1")
[node name="CenterContainer" type="CenterContainer" parent="Screens/Login/Banner"]
layout_mode = 2
[node name="MarginContainer" type="MarginContainer" parent="Screens/Login/Banner/CenterContainer"]
layout_mode = 2
theme_override_constants/margin_top = 8
theme_override_constants/margin_bottom = 8
[node name="RichTextLabel" type="RichTextLabel" parent="Screens/Login/Banner/CenterContainer/MarginContainer"]
layout_mode = 2
text = "Keine Verbindung"
fit_content = true
autowrap_mode = 0
[node name="CenterContainer" type="CenterContainer" parent="Screens/Login"]
layout_mode = 2
size_flags_vertical = 3
[node name="VBoxContainer" type="VBoxContainer" parent="Screens/Login/CenterContainer"]
custom_minimum_size = Vector2(500, 0)
layout_mode = 2
theme_override_constants/separation = 16
[node name="UsernameInput" type="LineEdit" parent="Screens/Login/CenterContainer/VBoxContainer"]
layout_mode = 2
placeholder_text = "username"
[node name="PasswordInput" type="LineEdit" parent="Screens/Login/CenterContainer/VBoxContainer"]
layout_mode = 2
placeholder_text = "password"
secret = true
[node name="Actions" type="HBoxContainer" parent="Screens/Login/CenterContainer/VBoxContainer"]
layout_mode = 2
[node name="Back" type="Button" parent="Screens/Login/CenterContainer/VBoxContainer/Actions" node_paths=PackedStringArray("menu")]
layout_mode = 2
size_flags_horizontal = 3
text = "Back"
script = ExtResource("2_c477a")
menu = NodePath("../../../../../Start")
[node name="Login" type="Button" parent="Screens/Login/CenterContainer/VBoxContainer/Actions" node_paths=PackedStringArray("username_field", "password_field", "next_view")]
layout_mode = 2
size_flags_horizontal = 3
text = "Login"
script = ExtResource("3_33cgr")
username_field = NodePath("../../UsernameInput")
password_field = NodePath("../../PasswordInput")
api_config = ExtResource("4_5vuod")
next_view = NodePath("../../../../../Lobby")
[node name="HTTPRequest" type="HTTPRequest" parent="Screens/Login/CenterContainer/VBoxContainer/Actions/Login"]
[node name="Lobby" type="CenterContainer" parent="Screens" node_paths=PackedStringArray("popup", "search_button", "abort_button", "accept_button", "decline_button", "time_bar", "login")]
visible = false
layout_mode = 2
script = ExtResource("7_dmfpl")
popup = NodePath("Popup")
search_button = NodePath("Search")
abort_button = NodePath("Abort")
accept_button = NodePath("Popup/MarginContainer/HBoxContainer/Accept")
decline_button = NodePath("Popup/MarginContainer/HBoxContainer/Decline")
time_bar = NodePath("Popup/Time Bar")
login = NodePath("../Login/CenterContainer/VBoxContainer/Actions/Login")
metadata/_tab_index = 2
[node name="Search" type="Button" parent="Screens/Lobby"]
layout_mode = 2
text = "Search"
[node name="Abort" type="Button" parent="Screens/Lobby"]
visible = false
layout_mode = 2
text = "Abort"
[node name="Popup" type="PanelContainer" parent="Screens/Lobby"]
visible = false
layout_mode = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_fh0xh")
[node name="MarginContainer" type="MarginContainer" parent="Screens/Lobby/Popup"]
layout_mode = 2
theme_override_constants/margin_left = 16
theme_override_constants/margin_top = 16
theme_override_constants/margin_right = 16
theme_override_constants/margin_bottom = 16
[node name="HBoxContainer" type="HBoxContainer" parent="Screens/Lobby/Popup/MarginContainer"]
layout_mode = 2
theme_override_constants/separation = 16
[node name="Accept" type="Button" parent="Screens/Lobby/Popup/MarginContainer/HBoxContainer"]
layout_mode = 2
text = "Accept
"
[node name="Decline" type="Button" parent="Screens/Lobby/Popup/MarginContainer/HBoxContainer"]
layout_mode = 2
text = "Decline"
[node name="Time Bar" type="ProgressBar" parent="Screens/Lobby/Popup"]
layout_mode = 2
size_flags_vertical = 8
theme_override_styles/fill = SubResource("StyleBoxFlat_x4jly")
value = 100.0
show_percentage = false
scene_name = "theme_test"

1644
scenes/theme_test.tscn Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,13 +0,0 @@
class_name InvalidPlacementMessage
extends Message
enum Reason { OUT_OF_BOUNDS, LOCATION_USED }
const MESSAGE_ID: String = "InvalidPlacement"
@export var x: int
@export var y: int
@export var reason: Reason
func get_message_id() -> String:
return MESSAGE_ID

View file

@ -1,49 +0,0 @@
extends Channel
signal on_match_update(msg: TowerPlacedMessage)
signal on_invalid_placing(msg: InvalidPlacementMessage)
signal on_money_update(msg: PlayerMoneyMessage)
signal on_hitpoints_update(msg: PlayerHitpointsMessage)
func get_channel_location() -> String:
return "match"
func _process(_delta: float) -> void:
self.socket.poll()
if self.socket.get_ready_state() != WebSocketPeer.STATE_OPEN:
return
while self.socket.get_available_packet_count():
var msg: Message = (
Message
. deserialize(
self.socket.get_packet().get_string_from_utf8(),
[
TowerPlacedMessage,
InvalidPlacementMessage,
PlayerMoneyMessage,
PlayerHitpointsMessage,
],
)
)
match msg.get_message_id():
TowerPlacedMessage.MESSAGE_ID:
on_match_update.emit(msg)
InvalidPlacementMessage.MESSAGE_ID:
on_invalid_placing.emit(msg)
PlayerMoneyMessage.MESSAGE_ID:
on_money_update.emit(msg)
PlayerHitpointsMessage.MESSAGE_ID:
on_hitpoints_update.emit(msg)
_:
continue
func send_request_place(x: int, y: int) -> void:
if self.socket.get_ready_state() != WebSocketPeer.STATE_OPEN:
return
var msg := RequestTowerPlacingMessage.new()
msg.x = x
msg.y = y
self.socket.send_text(Message.serialize(msg))

View file

@ -1,11 +0,0 @@
class_name PlayerHitpointsMessage
extends Message
const MESSAGE_ID: String = "PlayerHitpoints"
# gdlint:ignore = class-variable-name
@export var playerHitpoints: int
func get_message_id() -> String:
return MESSAGE_ID

View file

@ -1,11 +0,0 @@
class_name PlayerMoneyMessage
extends Message
const MESSAGE_ID: String = "PlayerMoney"
# gdlint:ignore = class-variable-name
@export var playerMoney: int
func get_message_id() -> String:
return MESSAGE_ID

View file

@ -1,11 +0,0 @@
class_name RequestTowerPlacingMessage
extends Message
const MESSAGE_ID: String = "RequestTowerPlacing"
@export var x: int
@export var y: int
func get_message_id() -> String:
return MESSAGE_ID

View file

@ -1,13 +0,0 @@
class_name TowerPlacedMessage
extends Message
enum GamePlayerMaps { PLAYER, OPPONENT }
const MESSAGE_ID: String = "TowerPlaced"
@export var x: int
@export var y: int
@export var map: GamePlayerMaps
func get_message_id() -> String:
return MESSAGE_ID

View file

@ -1,11 +0,0 @@
class_name MatchAbortedMessage
extends Message
const MESSAGE_ID := "MatchAborted"
# gdlint:ignore = class-variable-name
@export var matchId: String
func get_message_id() -> String:
return MESSAGE_ID

View file

@ -1,10 +0,0 @@
class_name MatchAcceptedMessage
extends Message
# gdlint:ignore = class-variable-name
@export var matchId: String
@export var accepted: bool
func get_message_id() -> String:
return "MatchAccepted"

View file

@ -1,14 +0,0 @@
class_name MatchEstablishedMessage
extends Message
const MESSAGE_ID := "MatchEstablished"
# gdlint:ignore = class-variable-name
@export var matchId: String
# gdlint:ignore = class-variable-name
@export var opponentName: String
@export var token: String
func get_message_id() -> String:
return MESSAGE_ID

View file

@ -1,13 +0,0 @@
class_name MatchFoundMessage
extends Message
const MESSAGE_ID := "MatchFound"
# gdlint:ignore = class-variable-name
@export var matchId: String
@export var created: int
@export var ttl: int
func get_message_id() -> String:
return MESSAGE_ID

View file

@ -1,10 +0,0 @@
class_name MatchSetSearchStateMessage
extends Message
const MESSAGE_ID := "MatchSetSearchState"
@export var searching: bool
func get_message_id() -> String:
return MESSAGE_ID

View file

@ -1,57 +0,0 @@
extends Channel
signal on_match_set_search_state(msg: MatchSetSearchStateMessage)
signal on_match_found(msg: MatchFoundMessage)
signal on_match_aborted
signal on_match_established(msg: MatchEstablishedMessage)
func get_channel_location() -> String:
return "matchmaking"
func _process(_delta: float) -> void:
self.socket.poll()
if self.socket.get_ready_state() != WebSocketPeer.STATE_OPEN:
return
while self.socket.get_available_packet_count():
var msg := (
Message
. deserialize(
self.socket.get_packet().get_string_from_utf8(),
[
MatchSetSearchStateMessage,
MatchFoundMessage,
MatchAbortedMessage,
MatchEstablishedMessage,
]
)
)
match msg.get_message_id():
MatchSetSearchStateMessage.MESSAGE_ID:
on_match_set_search_state.emit(msg)
MatchFoundMessage.MESSAGE_ID:
on_match_found.emit(msg)
MatchAbortedMessage.MESSAGE_ID:
on_match_aborted.emit()
MatchEstablishedMessage.MESSAGE_ID:
on_match_established.emit(msg)
_:
continue
func send_search_state(searching: bool) -> void:
if self.socket.get_ready_state() != WebSocketPeer.STATE_OPEN:
return
var msg := MatchSetSearchStateMessage.new()
msg.searching = searching
self.socket.send_text(Message.serialize(msg))
func send_match_accepted(accepted: bool, match_id: String) -> void:
if self.socket.get_ready_state() != WebSocketPeer.STATE_OPEN:
return
var msg := MatchAcceptedMessage.new()
msg.accepted = accepted
msg.matchId = match_id
self.socket.send_text(Message.serialize(msg))

View file

@ -1,6 +1,6 @@
class_name Message
enum Channels { CONNECTION, MATCHMAKING }
enum Channels { CONNECTION, TIME }
func get_message_id() -> String:

View file

@ -0,0 +1,8 @@
class_name CurrentUnixTimeMessage
extends Message
var time: int
func get_message_id() -> String:
return "CurrentUnixTime"

View file

@ -1,13 +0,0 @@
extends Node
enum State { NONE, RUNNING, WON, LOST }
var state: State = State.NONE
var opponent_name: String = ""
func start_game(msg: MatchEstablishedMessage) -> void:
self.opponent_name = msg.opponentName
self.state = State.RUNNING
MatchChannel.connect_socket(msg.token)
get_tree().change_scene_to_file("res://scenes/game.tscn")

View file

@ -1,65 +0,0 @@
extends Node2D
@export var tile_set: TileSet
@export var player_map: Node2D
@export var player_tower_map: TileMapLayer
@export var opponent_map: Node2D
@export var opponent_tower_map: TileMapLayer
@export var map_size := Vector2i(10, 20)
@export var camera: Camera2D
var clicked: bool = false
var clicked_pos: Vector2
func _ready() -> void:
player_tower_map.tile_set = tile_set
opponent_tower_map.tile_set = tile_set
player_tower_map.clear()
opponent_tower_map.clear()
MatchChannel.connect("on_match_update", on_match_update)
func _process(_delta: float) -> void:
# gdlint:ignore = max-line-length
var new_zoom := float(get_window().size.y) / float(map_size.y * tile_set.tile_size.y)
camera.zoom = Vector2(new_zoom, new_zoom)
var new_base_postion := get_window().size / 2 / new_zoom
camera.position = new_base_postion
self.position.x = new_base_postion.x - map_size.x * tile_set.tile_size.x
opponent_map.position.x = map_size.x * tile_set.tile_size.x
func _input(_event) -> void:
if Input.is_action_just_pressed("place"):
clicked_pos = get_global_mouse_position()
clicked = true
func _physics_process(_delta: float) -> void:
if clicked:
clicked = false
var pos: Vector2i = world_to_game_pos(clicked_pos)
if pos == Vector2i(-1, -1):
return
MatchChannel.send_request_place(pos.x, pos.y)
func on_match_update(msg: TowerPlacedMessage) -> void:
if msg.map == TowerPlacedMessage.GamePlayerMaps.PLAYER:
player_tower_map.set_cell(Vector2i(msg.x, msg.y), 1, Vector2i(0, 0))
else:
opponent_tower_map.set_cell(Vector2i(msg.x, msg.y), 1, Vector2i(0, 0))
func world_to_game_pos(world_pos: Vector2) -> Vector2i:
if (
world_pos.x < self.position.x
|| world_pos.x > self.position.x + map_size.x * tile_set.tile_size.x
):
return Vector2i(-1, -1)
return Vector2i(
(world_pos.x - self.position.x) / tile_set.tile_size.x,
world_pos.y / tile_set.tile_size.y,
)

View file

@ -1,5 +0,0 @@
extends RichTextLabel
func _ready() -> void:
self.text = CurrentMatch.opponent_name

View file

@ -1,10 +0,0 @@
extends RichTextLabel
func _ready() -> void:
MatchChannel.connect("on_hitpoints_update", on_hitpoints_update)
func on_hitpoints_update(msg: PlayerHitpointsMessage) -> void:
print(msg.playerHitpoints, "test")
self.text = str(msg.playerHitpoints, "HP")

View file

@ -1,10 +0,0 @@
extends RichTextLabel
func _ready() -> void:
MatchChannel.connect("on_money_update", on_money_update)
func on_money_update(msg: PlayerMoneyMessage) -> void:
print(msg.playerMoney, "test")
self.text = str(msg.playerMoney)

View file

@ -1,162 +0,0 @@
extends Control
@export var popup: PanelContainer
@export var search_button: Button
@export var abort_button: Button
@export var accept_button: Button
@export var decline_button: Button
@export var time_bar: ProgressBar
@export var login: Login
var searching: bool = false
var sent_accept_message: bool = false
var found_match: MatchFoundMessage
func _ready() -> void:
if !export_valid():
return
login.connect("login_successful", on_login)
# Websockets
(
ConnectionChannel
. connect(
"on_channel_token_received",
on_channel_token_received,
)
)
(
MatchmakingChannel
. connect(
"on_match_set_search_state",
on_match_set_search_state,
)
)
MatchmakingChannel.connect("on_match_found", on_match_found)
MatchmakingChannel.connect("on_match_aborted", on_match_aborted)
MatchmakingChannel.connect("on_match_established", on_match_established)
# UI
search_button.connect("pressed", on_search_pressed)
abort_button.connect("pressed", on_abort_pressed)
accept_button.connect("pressed", on_accept_pressed)
decline_button.connect("pressed", on_decline_pressed)
popup.visible = false
func _process(_delta: float) -> void:
if found_match:
var now := int(Time.get_unix_time_from_system() * 1000)
time_bar.max_value = found_match.ttl
time_bar.value = found_match.ttl - (now - found_match.created)
# gdlint:ignore = max-public-methods
func export_valid() -> bool:
if not popup:
push_error("Popup not Set")
return false
if not search_button:
push_error("Search Button not Set")
return false
if not abort_button:
push_error("Abort Button not Set")
return false
if not accept_button:
push_error("Accept Button not Set")
return false
if not decline_button:
push_error("Decline Button not Set")
return false
if not time_bar:
push_error("Time Bar not Set")
return false
if not login:
push_error("No login configured")
return false
return true
func on_login(_session: PlayerLoginSession) -> void:
ConnectionChannel.request_channel_token(Message.Channels.MATCHMAKING)
##############################
# Websocket Interactions #
##############################
func on_channel_token_received(msg: ProvidedConnectionTokenMessage) -> void:
if msg.channel != Message.Channels.MATCHMAKING:
return
MatchmakingChannel.connect_socket(msg.token)
func on_match_set_search_state(msg: MatchSetSearchStateMessage) -> void:
set_searching_ui(msg.searching)
func on_match_found(msg: MatchFoundMessage) -> void:
set_match_accptance_ui(true)
set_accaptence_buttons_enabled(true)
found_match = msg
func on_match_aborted() -> void:
set_match_accptance_ui(false)
set_searching_ui(false)
found_match = null
func on_match_established(msg: MatchEstablishedMessage) -> void:
CurrentMatch.start_game(msg)
#############################
# UI Interactions #
#############################
func on_search_pressed() -> void:
if searching:
return
set_searching_ui(true)
MatchmakingChannel.send_search_state(true)
func on_abort_pressed() -> void:
if not searching:
return
set_searching_ui(false)
MatchmakingChannel.send_search_state(false)
func on_accept_pressed() -> void:
set_accaptence_buttons_enabled(false)
MatchmakingChannel.send_match_accepted(true, found_match.matchId)
func on_decline_pressed() -> void:
set_accaptence_buttons_enabled(false)
MatchmakingChannel.send_match_accepted(false, found_match.matchId)
#############################
# UI Management #
#############################
func set_searching_ui(new_searching: bool) -> void:
searching = new_searching
search_button.visible = !new_searching
abort_button.visible = new_searching
func set_accaptence_buttons_enabled(enabled: bool) -> void:
accept_button.disabled = !enabled
decline_button.disabled = !enabled
func set_match_accptance_ui(vissible: bool) -> void:
popup.visible = vissible

View file

@ -2,12 +2,10 @@ class_name Login
extends Button
signal login_successful(session: PlayerLoginSession)
signal login_error(error: ApiError)
@export var username_field: LineEdit
@export var password_field: LineEdit
@export var api_config: ApiConfig
@export var next_view: Control
var api: ServerApi
@ -21,9 +19,6 @@ func _ready() -> void:
if not api_config:
push_error("No API Configuration provided")
return
if not next_view:
push_error("No next view configured")
return
api = ServerApi.new(api_config)
connect("pressed", login)
username_field.connect("text_submitted", login_wrapper)
@ -42,10 +37,8 @@ func login() -> void:
func on_success(response: ApiResponse) -> void:
ConnectionChannel.connect_to_channel(response.data.token)
next_view.visible = true
login_successful.emit(response.data)
func on_error(error: ApiError) -> void:
login_error.emit(error)
print("Error: ", error.message)

View file

@ -1,45 +0,0 @@
extends Control
@export var login: Login
@export var text: RichTextLabel
func _ready() -> void:
if not login:
push_error("No Login connectd")
return
if not text:
push_error("No Text label connectd")
return
login.connect("login_successful", on_successful)
login.connect("login_error", on_error)
hide_banner()
func on_successful(_session: PlayerLoginSession) -> void:
hide_banner()
func on_error(error: ApiError) -> void:
if error.identifier == "apibee.request.no_response":
return
show_banner()
var msg: String = ""
if error.identifier == "apibee.connect_to_host.status_failure":
msg = "Server nicht ereichbar"
if error.response_code == HTTPClient.RESPONSE_UNAUTHORIZED:
msg = "Falscher Benutzername oder Passwort"
if msg == "":
msg = error.message
text.text = msg
func hide_banner() -> void:
self.modulate = Color.TRANSPARENT
func show_banner() -> void:
self.modulate = Color.WHITE

View file

@ -1,9 +0,0 @@
extends Button
func _ready() -> void:
connect("pressed", on_pressed)
func on_pressed() -> void:
get_tree().quit()

View file

@ -1,14 +0,0 @@
extends Button
@export var menu: Control
func _ready() -> void:
connect("pressed", _on_Button_pressed)
func _on_Button_pressed() -> void:
if not menu:
push_error("Menu to swap to not configgured")
return
menu.visible = true

View file

@ -0,0 +1,14 @@
extends Button
@export var scene_name: String
func _ready() -> void:
connect("pressed", _on_Button_pressed)
func _on_Button_pressed() -> void:
if not scene_name:
push_error("Scene to switch to is not configured")
return
get_tree().change_scene_to_file("res://scenes/" + scene_name + ".tscn")

View file

@ -0,0 +1,50 @@
extends RichTextLabel
@export var login: Login
@export var api_config: ApiConfig
var api := ServerApi.new(api_config)
# docs.redotengine.org/en/stable/tutorials/networking/websocket.html
var time_channel = WebSocketPeer.new()
func _ready() -> void:
login.connect("login_successful", on_login)
(
ConnectionChannel
. connect(
"on_channel_token_received",
on_channel_token_received,
)
)
func on_login(session: PlayerLoginSession):
ConnectionChannel.connect_to_channel(session.token)
ConnectionChannel.request_channel_token(Message.Channels.TIME)
func on_channel_token_received(msg: ProvidedConnectionTokenMessage) -> void:
if time_channel.get_ready_state() != WebSocketPeer.STATE_CLOSED:
return
if msg.channel != Message.Channels.TIME:
return
time_channel.handshake_headers = PackedStringArray(
["Authorization: " + msg.token],
)
time_channel.connect_to_url("ws://localhost:8080/ws/time")
func _process(_delta: float) -> void:
time_channel.poll()
var state = time_channel.get_ready_state()
if state != WebSocketPeer.STATE_OPEN:
return
while time_channel.get_available_packet_count():
var msg: CurrentUnixTimeMessage = Message.deserialize(
time_channel.get_packet().get_string_from_utf8(), [CurrentUnixTimeMessage]
)
if msg == null:
continue
self.text = str(msg.time)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 B

View file

@ -1,34 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bj8jwha8g5y8n"
path="res://.godot/imported/tower.png-afe2561faadc2586f630d8a5c5939231.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://textures/tiles/tower.png"
dest_files=["res://.godot/imported/tower.png-afe2561faadc2586f630d8a5c5939231.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View file

@ -1,12 +0,0 @@
[gd_resource type="TileSet" load_steps=3 format=3 uid="uid://cvp867israfjk"]
[ext_resource type="Texture2D" uid="uid://bj8jwha8g5y8n" path="res://textures/tiles/tower.png" id="1_4stpq"]
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_tivyh"]
texture = ExtResource("1_4stpq")
texture_region_size = Vector2i(32, 32)
0:0/0 = 0
[resource]
tile_size = Vector2i(32, 32)
sources/1 = SubResource("TileSetAtlasSource_tivyh")

View file

@ -16,7 +16,6 @@ Button/colors/icon_normal_color = Color(1, 1, 1, 0)
Button/colors/icon_pressed_color = Color(1, 1, 1, 1)
Button/constants/h_separation = 4
Button/constants/icon_max_width = 8
Button/font_sizes/font_size = 32
Button/icons/icon = ExtResource("1_2gn16")
Button/styles/focus = ExtResource("2_deyos")
Button/styles/hover = ExtResource("3_nfsuc")
@ -43,10 +42,3 @@ ColorPickerButton/styles/hover = ExtResource("3_nfsuc")
ColorPickerButton/styles/hover_pressed = ExtResource("6_vlfw3")
ColorPickerButton/styles/normal = ExtResource("4_wi0tw")
ColorPickerButton/styles/pressed = ExtResource("5_kgc35")
Label/font_sizes/font_size = 32
LineEdit/font_sizes/font_size = 32
RichTextLabel/font_sizes/normal_font_size = 32
TabBar/font_sizes/font_size = 32
TabContainer/font_sizes/font_size = 32
TextEdit/font_sizes/font_size = 32
Tree/font_sizes/font_size = 32