ready up feature now launches the game frame
This commit is contained in:
253
client.py
253
client.py
@@ -7,15 +7,19 @@ import json
|
|||||||
|
|
||||||
class ClientVCKO(wx.App):
|
class ClientVCKO(wx.App):
|
||||||
def OnInit(self):
|
def OnInit(self):
|
||||||
self.debug_frame = DebugFrame(self)
|
|
||||||
self.debug_frame.Show()
|
|
||||||
self.start_frame = StartFrame(self)
|
|
||||||
self.debug_frame.Show()
|
|
||||||
self.connection_status = False
|
self.connection_status = False
|
||||||
self.in_lobby = False
|
|
||||||
self.player_id = ""
|
self.player_id = ""
|
||||||
self.debug_frame.set_connection_status()
|
self.player_name = ""
|
||||||
self.lobby = []
|
self.lobby = []
|
||||||
|
self.in_lobby = False
|
||||||
|
self.in_game = False
|
||||||
|
self.game_id = ""
|
||||||
|
self.debug_frame = DebugFrame(self)
|
||||||
|
self.start_frame = StartFrame(self)
|
||||||
|
self.lobby_frame = LobbyFrame(self)
|
||||||
|
self.game_frame = GameFrame(self)
|
||||||
|
self.last_lobby_state = ""
|
||||||
|
self.debug_frame.set_connection_status()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def parse_response(self, response):
|
def parse_response(self, response):
|
||||||
@@ -24,73 +28,118 @@ class ClientVCKO(wx.App):
|
|||||||
full_command = response.split()
|
full_command = response.split()
|
||||||
match first_word:
|
match first_word:
|
||||||
case "lobby":
|
case "lobby":
|
||||||
full_command = response.split()
|
|
||||||
if full_command[1] == "joined" and len(full_command) == 3:
|
if full_command[1] == "joined" and len(full_command) == 3:
|
||||||
self.player_id = full_command[2]
|
self.player_id = full_command[2]
|
||||||
self.in_lobby = True
|
self.in_lobby = True
|
||||||
self.start_frame.show_list_view(None)
|
self.start_frame.enter_lobby(None)
|
||||||
elif full_command[1] == "state":
|
elif full_command[1] == "state":
|
||||||
json_response = ' '.join(full_command[2:])
|
json_response = ' '.join(full_command[2:])
|
||||||
print(json_response)
|
new_lobby_state = json.loads(json_response)
|
||||||
self.lobby = json.loads(json_response)
|
if new_lobby_state != self.lobby:
|
||||||
|
self.lobby = new_lobby_state
|
||||||
|
self.lobby_frame.get_lobby_status()
|
||||||
else:
|
else:
|
||||||
print("Couldn't understand that response")
|
print("Couldn't understand that response")
|
||||||
case _:
|
case "game":
|
||||||
print(full_command[1])
|
if full_command[1] == "joined" and len(full_command) == 3:
|
||||||
|
self.game_id = full_command[2]
|
||||||
|
self.in_game = True
|
||||||
|
self.in_lobby = False
|
||||||
|
self.lobby_frame.enter_game()
|
||||||
|
|
||||||
|
def update_lobby_status(self):
|
||||||
|
return self.in_lobby
|
||||||
|
|
||||||
|
|
||||||
class DebugFrame(wx.Frame):
|
class GameFrame(wx.Frame):
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
super().__init__(parent=None, title='VCKO Debug Console', size=Constants.default_window_size)
|
super().__init__(parent=None, title='VCK Online', size=Constants.default_window_size)
|
||||||
|
self.app = app
|
||||||
|
self.panel = wx.Panel(self)
|
||||||
|
self.SetMinSize(Constants.minimum_window_size)
|
||||||
|
|
||||||
|
|
||||||
|
class LobbyFrame(wx.Frame):
|
||||||
|
def __init__(self, app):
|
||||||
|
super().__init__(parent=None, title='VCK Online Lobby', size=(250, 300))
|
||||||
self.app = app
|
self.app = app
|
||||||
self.panel = wx.Panel(self)
|
self.panel = wx.Panel(self)
|
||||||
self.vertical_sizer = wx.BoxSizer(wx.VERTICAL)
|
self.vertical_sizer = wx.BoxSizer(wx.VERTICAL)
|
||||||
self.status_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
self.last_lobby_state = []
|
||||||
self.message_field = wx.TextCtrl(self.panel, style=wx.TE_PROCESS_ENTER)
|
self.current_player_index = None
|
||||||
self.connection_status_indicator = wx.StaticText(self.panel, label="Connection Status")
|
# Create the list control and columns
|
||||||
self.my_btn = wx.Button(self.panel, label="Send call")
|
self.list_ctrl = wx.ListCtrl(self.panel, style=wx.LC_REPORT)
|
||||||
self.my_btn.Bind(wx.EVT_BUTTON, self.on_press)
|
self.list_ctrl.InsertColumn(0, "Player Name")
|
||||||
self.message_field.Bind(wx.EVT_TEXT_ENTER, self.on_text_enter)
|
self.list_ctrl.InsertColumn(1, "Ready Status", format=wx.LIST_FORMAT_RIGHT)
|
||||||
# Create a horizontal sizer to hold the connection_status StaticText
|
self.get_lobby_status()
|
||||||
self.status_sizer.AddStretchSpacer()
|
# Create the ready button
|
||||||
self.status_sizer.Add(wx.StaticText(self.panel), 0, wx.EXPAND | wx.RIGHT, 5)
|
ready_button = wx.Button(self.panel, label="Ready Up")
|
||||||
self.status_sizer.Add(self.connection_status_indicator, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
|
ready_button.Bind(wx.EVT_BUTTON, self.on_ready_up)
|
||||||
self.status_sizer.Add(wx.StaticText(self.panel), 0, wx.EXPAND | wx.LEFT, 5)
|
self.list_ctrl.Bind(wx.EVT_LIST_ITEM_SELECTED, self.highlight_current_player)
|
||||||
# Add the text field, button, and status sizer to the vertical sizer
|
# Add the list control and ready button to the vertical sizer
|
||||||
self.vertical_sizer.Add(self.message_field, 0, wx.ALL | wx.EXPAND, 5)
|
self.vertical_sizer.Add(self.list_ctrl, 1, wx.ALL | wx.EXPAND, 5)
|
||||||
self.vertical_sizer.Add(self.my_btn, 0, wx.ALL | wx.CENTER, 5)
|
self.vertical_sizer.Add(ready_button, 0, wx.ALL | wx.CENTER, 5)
|
||||||
self.vertical_sizer.AddStretchSpacer()
|
|
||||||
self.vertical_sizer.Add(self.status_sizer, 0, wx.ALIGN_LEFT | wx.BOTTOM, 5)
|
|
||||||
self.panel.SetSizer(self.vertical_sizer)
|
self.panel.SetSizer(self.vertical_sizer)
|
||||||
self.SetMinSize(Constants.minimum_window_size)
|
self.SetMinSize(Constants.minimum_window_size)
|
||||||
self.Show()
|
|
||||||
# Create a timer to call the connection_check method every 2 seconds
|
# Bind the size event to adjust the column widths
|
||||||
|
self.Bind(wx.EVT_SIZE, self.on_size)
|
||||||
|
self.Bind(wx.EVT_CLOSE, self.on_close)
|
||||||
|
|
||||||
self.timer = wx.Timer(self)
|
self.timer = wx.Timer(self)
|
||||||
self.Bind(wx.EVT_TIMER, self.set_connection_status, self.timer)
|
self.Bind(wx.EVT_TIMER, self.get_lobby_status, self.timer)
|
||||||
self.timer.Start(5000)
|
self.timer.Start(500)
|
||||||
|
|
||||||
def set_connection_status(self, event=None):
|
def on_size(self, event):
|
||||||
if connection_check():
|
# Calculate the width of each column based on the width of the list control
|
||||||
self.connection_status_indicator.SetLabel("Connected")
|
width = self.list_ctrl.GetSize()[0]
|
||||||
self.connection_status_indicator.SetForegroundColour(Constants.green)
|
col_width = width // 2
|
||||||
|
self.list_ctrl.SetColumnWidth(0, col_width)
|
||||||
|
self.list_ctrl.SetColumnWidth(1, col_width)
|
||||||
|
event.Skip()
|
||||||
|
|
||||||
|
def get_lobby_status(self, event=None):
|
||||||
|
if connection_check() and self.app.in_lobby:
|
||||||
|
self.app.parse_response(send(f"lobby get_status {self.app.player_id}"))
|
||||||
|
if self.app.lobby == self.last_lobby_state:
|
||||||
|
# If the current lobby state is the same as the last one, don't update the list control
|
||||||
|
return
|
||||||
|
self.list_ctrl.DeleteAllItems()
|
||||||
|
for index, player in enumerate(self.app.lobby):
|
||||||
|
self.list_ctrl.InsertItem(index, player['name'])
|
||||||
|
self.list_ctrl.SetItem(index, 1, "Ready" if player['is_ready'] else "Not Ready")
|
||||||
|
if player['player_id'] == self.app.player_id:
|
||||||
|
self.current_player_index = index
|
||||||
|
self.list_ctrl.SetItemState(index, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
|
||||||
else:
|
else:
|
||||||
self.connection_status_indicator.SetLabel("Not Connected")
|
self.list_ctrl.SetItemState(index, 0, wx.LIST_STATE_SELECTED)
|
||||||
self.connection_status_indicator.SetForegroundColour(Constants.red)
|
# Save the new lobby state
|
||||||
|
self.last_lobby_state = self.app.lobby
|
||||||
|
|
||||||
def on_press(self, event):
|
def highlight_current_player(self):
|
||||||
message = self.message_field.GetValue()
|
if self.current_player_index is not None:
|
||||||
if not message:
|
self.list_ctrl.Select(self.current_player_index)
|
||||||
print("You didn't enter anything!")
|
|
||||||
else:
|
else:
|
||||||
self.api_call(message)
|
self.list_ctrl.Select(-1)
|
||||||
|
|
||||||
def on_text_enter(self, event):
|
def on_ready_up(self, event):
|
||||||
self.on_press(event)
|
for player in self.app.lobby:
|
||||||
|
if player['player_id'] == self.app.player_id:
|
||||||
def api_call(self, message):
|
if player['is_ready']:
|
||||||
if connection_check():
|
if connection_check():
|
||||||
self.app.parse_response(send(message))
|
self.app.parse_response(send(f"lobby unready {self.app.player_id}"))
|
||||||
self.message_field.SetValue("")
|
else:
|
||||||
|
if connection_check():
|
||||||
|
self.app.parse_response(send(f"lobby ready {self.app.player_id}"))
|
||||||
|
break
|
||||||
|
|
||||||
|
def enter_game(self, event=None):
|
||||||
|
self.app.game_frame.Show()
|
||||||
|
self.Hide()
|
||||||
|
|
||||||
|
def on_close(self, event):
|
||||||
|
self.app.parse_response(send(f"lobby leave {self.app.player_id}"))
|
||||||
|
self.Destroy()
|
||||||
|
|
||||||
|
|
||||||
class StartFrame(wx.Frame):
|
class StartFrame(wx.Frame):
|
||||||
@@ -126,11 +175,8 @@ class StartFrame(wx.Frame):
|
|||||||
def on_text_enter(self, event):
|
def on_text_enter(self, event):
|
||||||
self.on_submit(event)
|
self.on_submit(event)
|
||||||
|
|
||||||
def show_list_view(self, event):
|
def enter_lobby(self, event):
|
||||||
list_frame = LobbyFrame(self.app)
|
self.app.lobby_frame.Show()
|
||||||
list_frame.Show()
|
|
||||||
|
|
||||||
# Refresh the layout of the original panel
|
|
||||||
self.Hide()
|
self.Hide()
|
||||||
|
|
||||||
def api_call(self, message):
|
def api_call(self, message):
|
||||||
@@ -138,72 +184,59 @@ class StartFrame(wx.Frame):
|
|||||||
self.app.parse_response(send(message))
|
self.app.parse_response(send(message))
|
||||||
self.name_field.SetValue("")
|
self.name_field.SetValue("")
|
||||||
|
|
||||||
class LobbyFrame(wx.Frame):
|
|
||||||
|
class DebugFrame(wx.Frame):
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
super().__init__(parent=None, title='VCK Online Lobby', size=(250, 300))
|
super().__init__(parent=None, title='VCKO Debug Console', size=Constants.default_window_size)
|
||||||
self.app = app
|
self.app = app
|
||||||
self.panel = wx.Panel(self)
|
self.panel = wx.Panel(self)
|
||||||
self.vertical_sizer = wx.BoxSizer(wx.VERTICAL)
|
self.vertical_sizer = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
self.status_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
# Create the list control and columns
|
self.message_field = wx.TextCtrl(self.panel, style=wx.TE_PROCESS_ENTER)
|
||||||
self.list_ctrl = wx.ListCtrl(self.panel, style=wx.LC_REPORT)
|
self.connection_status_indicator = wx.StaticText(self.panel, label="Connection Status")
|
||||||
self.list_ctrl.InsertColumn(0, "Player Name")
|
self.my_btn = wx.Button(self.panel, label="Send call")
|
||||||
self.list_ctrl.InsertColumn(1, "Ready Status", format=wx.LIST_FORMAT_RIGHT)
|
self.my_btn.Bind(wx.EVT_BUTTON, self.on_press)
|
||||||
self.get_lobby_status()
|
self.message_field.Bind(wx.EVT_TEXT_ENTER, self.on_text_enter)
|
||||||
# Create the ready button
|
# Create a horizontal sizer to hold the connection_status StaticText
|
||||||
ready_button = wx.Button(self.panel, label="Ready Up")
|
self.status_sizer.AddStretchSpacer()
|
||||||
ready_button.Bind(wx.EVT_BUTTON, self.on_ready_up)
|
self.status_sizer.Add(wx.StaticText(self.panel), 0, wx.EXPAND | wx.RIGHT, 5)
|
||||||
|
self.status_sizer.Add(self.connection_status_indicator, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
|
||||||
# Add the list control and ready button to the vertical sizer
|
self.status_sizer.Add(wx.StaticText(self.panel), 0, wx.EXPAND | wx.LEFT, 5)
|
||||||
self.vertical_sizer.Add(self.list_ctrl, 1, wx.ALL | wx.EXPAND, 5)
|
# Add the text field, button, and status sizer to the vertical sizer
|
||||||
self.vertical_sizer.Add(ready_button, 0, wx.ALL | wx.CENTER, 5)
|
self.vertical_sizer.Add(self.message_field, 0, wx.ALL | wx.EXPAND, 5)
|
||||||
|
self.vertical_sizer.Add(self.my_btn, 0, wx.ALL | wx.CENTER, 5)
|
||||||
|
self.vertical_sizer.AddStretchSpacer()
|
||||||
|
self.vertical_sizer.Add(self.status_sizer, 0, wx.ALIGN_LEFT | wx.BOTTOM, 5)
|
||||||
self.panel.SetSizer(self.vertical_sizer)
|
self.panel.SetSizer(self.vertical_sizer)
|
||||||
self.SetMinSize(Constants.minimum_window_size)
|
self.SetMinSize(Constants.minimum_window_size)
|
||||||
|
|
||||||
# Bind the size event to adjust the column widths
|
|
||||||
self.Bind(wx.EVT_SIZE, self.on_size)
|
|
||||||
self.Bind(wx.EVT_CLOSE, self.on_close)
|
|
||||||
|
|
||||||
self.Show()
|
self.Show()
|
||||||
|
# Create a timer to call the connection_check method every 2 seconds
|
||||||
self.timer = wx.Timer(self)
|
self.timer = wx.Timer(self)
|
||||||
self.Bind(wx.EVT_TIMER, self.get_lobby_status, self.timer)
|
self.Bind(wx.EVT_TIMER, self.set_connection_status, self.timer)
|
||||||
self.timer.Start(1000)
|
self.timer.Start(10000)
|
||||||
|
|
||||||
def on_size(self, event):
|
def set_connection_status(self, event=None):
|
||||||
# Calculate the width of each column based on the width of the list control
|
|
||||||
width = self.list_ctrl.GetSize()[0]
|
|
||||||
col_width = width // 2
|
|
||||||
self.list_ctrl.SetColumnWidth(0, col_width)
|
|
||||||
self.list_ctrl.SetColumnWidth(1, col_width)
|
|
||||||
|
|
||||||
event.Skip()
|
|
||||||
|
|
||||||
def get_lobby_status(self, event=None):
|
|
||||||
if connection_check():
|
if connection_check():
|
||||||
self.app.parse_response(send("lobby get_status"))
|
self.connection_status_indicator.SetLabel("Connected")
|
||||||
# Clear the list control
|
self.connection_status_indicator.SetForegroundColour(Constants.green)
|
||||||
self.list_ctrl.DeleteAllItems()
|
|
||||||
|
|
||||||
# Populate the list control with the contents of the lobby
|
|
||||||
for index, player in enumerate(self.app.lobby):
|
|
||||||
self.list_ctrl.InsertItem(index, player['name'])
|
|
||||||
self.list_ctrl.SetItem(index, 1, "Ready" if player['is_ready'] else "Not Ready")
|
|
||||||
|
|
||||||
def on_ready_up(self, event):
|
|
||||||
for player in self.app.lobby:
|
|
||||||
if player['player_id'] == self.app.player_id:
|
|
||||||
if player['is_ready']:
|
|
||||||
if connection_check():
|
|
||||||
self.app.parse_response(send(f"lobby unready {self.app.player_id}"))
|
|
||||||
else:
|
else:
|
||||||
|
self.connection_status_indicator.SetLabel("Not Connected")
|
||||||
|
self.connection_status_indicator.SetForegroundColour(Constants.red)
|
||||||
|
|
||||||
|
def on_press(self, event):
|
||||||
|
message = self.message_field.GetValue()
|
||||||
|
if not message:
|
||||||
|
print("You didn't enter anything!")
|
||||||
|
else:
|
||||||
|
self.api_call(message)
|
||||||
|
|
||||||
|
def on_text_enter(self, event):
|
||||||
|
self.on_press(event)
|
||||||
|
|
||||||
|
def api_call(self, message):
|
||||||
if connection_check():
|
if connection_check():
|
||||||
self.app.parse_response(send(f"lobby ready {self.app.player_id}"))
|
self.app.parse_response(send(message))
|
||||||
break
|
self.message_field.SetValue("")
|
||||||
|
|
||||||
def on_close(self, event):
|
|
||||||
self.app.parse_response(send(f"lobby leave {self.app.player_id}"))
|
|
||||||
self.Destroy()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def connection_check():
|
def connection_check():
|
||||||
|
|||||||
45
server.py
45
server.py
@@ -13,6 +13,7 @@ class ServerVCKO:
|
|||||||
self.server_socket.bind((self.host, Constants.port))
|
self.server_socket.bind((self.host, Constants.port))
|
||||||
self.game_list = []
|
self.game_list = []
|
||||||
self.lobby = []
|
self.lobby = []
|
||||||
|
self.gamers = []
|
||||||
|
|
||||||
def handle_client(self, conn, addr):
|
def handle_client(self, conn, addr):
|
||||||
print(f"Connection from: {addr}")
|
print(f"Connection from: {addr}")
|
||||||
@@ -44,18 +45,49 @@ class ServerVCKO:
|
|||||||
temp_lobby.append(player)
|
temp_lobby.append(player)
|
||||||
self.lobby = temp_lobby
|
self.lobby = temp_lobby
|
||||||
self.send_lobby_state(conn)
|
self.send_lobby_state(conn)
|
||||||
elif full_command[1] == "get_status" and len(full_command) == 2:
|
elif full_command[1] == "get_status" and len(full_command) == 3:
|
||||||
|
found = False
|
||||||
|
for player in self.lobby:
|
||||||
|
if full_command[2] == player.player_id:
|
||||||
self.send_lobby_state(conn)
|
self.send_lobby_state(conn)
|
||||||
|
found = True
|
||||||
|
for player in self.gamers:
|
||||||
|
if full_command[2] == player.player_id:
|
||||||
|
message = f"game joined {player.game_id}"
|
||||||
|
conn.send(message.encode(Constants.text_format))
|
||||||
|
found = True
|
||||||
|
# this only runs if we somehow receive an invalid player id
|
||||||
|
if not found:
|
||||||
|
message = f"Unable to find any player with player id: {full_command[2]}"
|
||||||
|
conn.send(message.encode(Constants.text_format))
|
||||||
elif full_command[1] == "ready" and len(full_command) > 2:
|
elif full_command[1] == "ready" and len(full_command) > 2:
|
||||||
|
ready_check = 0
|
||||||
for player in self.lobby:
|
for player in self.lobby:
|
||||||
if player.player_id == full_command[2]:
|
if player.player_id == full_command[2]:
|
||||||
player.is_ready = True
|
player.is_ready = True
|
||||||
|
if player.is_ready:
|
||||||
|
ready_check += 1
|
||||||
|
print(f"ready check: {ready_check}")
|
||||||
|
if ready_check == len(self.lobby):
|
||||||
|
new_game_id = str(uuid.uuid4())
|
||||||
|
for player in self.lobby:
|
||||||
|
print(f"lobby player: {player.name}")
|
||||||
|
players_to_remove = []
|
||||||
|
for player in self.lobby:
|
||||||
|
if player.is_ready:
|
||||||
|
new_gamer = GameMember(player.player_id, player.name, new_game_id)
|
||||||
|
self.gamers.append(new_gamer)
|
||||||
|
players_to_remove.append(player)
|
||||||
|
for player in players_to_remove:
|
||||||
|
self.lobby.remove(player)
|
||||||
|
message = f"game joined {new_game_id}"
|
||||||
|
conn.send(message.encode(Constants.text_format))
|
||||||
|
else:
|
||||||
self.send_lobby_state(conn)
|
self.send_lobby_state(conn)
|
||||||
elif full_command[1] == "unready" and len(full_command) > 2:
|
elif full_command[1] == "unready" and len(full_command) > 2:
|
||||||
for player in self.lobby:
|
for player in self.lobby:
|
||||||
if player.player_id == full_command[2]:
|
if player.player_id == full_command[2]:
|
||||||
player.is_ready = False
|
player.is_ready = False
|
||||||
|
|
||||||
self.send_lobby_state(conn)
|
self.send_lobby_state(conn)
|
||||||
else:
|
else:
|
||||||
conn.send("invalid message".encode(Constants.text_format))
|
conn.send("invalid message".encode(Constants.text_format))
|
||||||
@@ -72,7 +104,7 @@ class ServerVCKO:
|
|||||||
conn, addr = self.server_socket.accept()
|
conn, addr = self.server_socket.accept()
|
||||||
thread = threading.Thread(target=self.handle_client, args=(conn, addr))
|
thread = threading.Thread(target=self.handle_client, args=(conn, addr))
|
||||||
thread.start()
|
thread.start()
|
||||||
print(f"Active threads: {threading.active_count() - 1}")
|
print(f"\nActive threads: {threading.active_count() - 1}")
|
||||||
|
|
||||||
def send_lobby_state(self, conn):
|
def send_lobby_state(self, conn):
|
||||||
lobby_data = []
|
lobby_data = []
|
||||||
@@ -94,6 +126,13 @@ class LobbyMember:
|
|||||||
self.is_ready = False
|
self.is_ready = False
|
||||||
|
|
||||||
|
|
||||||
|
class GameMember:
|
||||||
|
def __init__(self, player_id, player_name, game_id):
|
||||||
|
self.name = player_name
|
||||||
|
self.player_id = player_id
|
||||||
|
self.game_id = game_id
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
print("server starting")
|
print("server starting")
|
||||||
server = ServerVCKO()
|
server = ServerVCKO()
|
||||||
|
|||||||
Reference in New Issue
Block a user