From e7aa87e3756fbf4b44aa572dbd8d00fc6c8a50ac Mon Sep 17 00:00:00 2001 From: Alex Karle Date: Mon, 20 Apr 2020 00:11:53 -0400 Subject: [PATCH] Euchre::Dealer: Add force join_game option to take over hand This is crucial to support dropped players. While it is definitely prone to "euchre.live bombing" (in the parlance of our times), where someone could guess a player+game combo and take over the hand, we'll trust our beta testers (read: family) for now to be good citizens. The mechanism works by adding a force flag to join_game. If present, and if the username is already in the game, we hot-swap the player's WS object and ID. Name/hand/game all stay the same. Works for both players and spectators :) --- lib/Euchre/Dealer.pm | 59 +++++++++++++++++++++++++++++++++++++++++++++-------------- public/debug.html | 7 ++++--- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/lib/Euchre/Dealer.pm b/lib/Euchre/Dealer.pm index 9278c59..59c8fb7 100644 --- a/lib/Euchre/Dealer.pm +++ b/lib/Euchre/Dealer.pm @@ -134,6 +134,7 @@ sub pong { # player_name # game_id +# force sub join_game { my ($p, $msg) = @_; @@ -156,31 +157,36 @@ sub join_game { }; } - # Handle full game case - if ($GAMES{$id}->{phase} ne 'lobby') { - send_error($p, 'Game already in progress'); - } else { - my $game = $GAMES{$id}; + my $game = $GAMES{$id}; + + # Make sure name is unique to game + my @all_names = map { $_->{name} } + grep { defined } + (@{$game->{players}}, @{$game->{spectators}}); - # Make sure name is unique to game - my @all_names = map { $_->{name} } - grep { defined } - (@{$game->{players}}, @{$game->{spectators}}); + my $player_exists = grep { $_ eq $msg->{player_name} } @all_names; - if (grep { $_ eq $msg->{player_name} } @all_names) { - send_error($p, 'Username not unique'); + if ($player_exists) { + if (!$msg->{force}) { + send_error($p, 'Username not unique; is this you?'); + return; + } + $p->{name} = $msg->{player_name}; + swap_player($game, $p, 'players') || swap_player($game, $p, 'spectators'); + } else { + if ($game->{phase} ne 'lobby') { + send_error($p, 'Cant join as new player mid game'); return; } - # Add player object to Game # All players start as spectators and have to take a seat explicitly $p->{name} = $msg->{player_name}; $p->{hand} = []; $p->{game} = $game; push @{$game->{spectators}}, $p; - - broadcast_gamestate($game); } + + broadcast_gamestate($game); } # seat @@ -545,4 +551,29 @@ sub take_card { return 0; } +# Returns 0 or 1 on success +sub swap_player { + my ($game, $new_p, $list) = @_; + + for (my $i = 0; $i < @{$game->{$list}}; $i++) { + next unless defined $game->{$list}->[$i]; # undef potentially in lobby + if ($game->{$list}->[$i]->{name} eq $new_p->{name}) { + # Ye ole switcheroo + # Don't delete the old player cuz we need to preserve the hand, etc. + # Just swap out the WS and ID, and update PLAYERS + my $old_id = $game->{$list}->[$i]->{id}; + $game->{$list}->[$i]->{id} = $new_p->{id}; + $game->{$list}->[$i]->{ws} = $new_p->{ws}; + $PLAYERS{$new_p->{id}} = $game->{$list}->[$i]; + + # NOTE: For now, don't delete from %PLAYERS here... + # the old WS may still be playing ping/pong, so we just + # let them hang out until they close themselves or go + # inactive (and we time them out => delete from %PLAYERS) + return 1; + } + } + return 0; +} + 1; diff --git a/public/debug.html b/public/debug.html index 3dddf0a..e0d93ea 100644 --- a/public/debug.html +++ b/public/debug.html @@ -61,11 +61,11 @@ } }; - function joinGame() { + function joinGame(force) { uname = document.getElementById('username').value; gname = document.getElementById('gamename').value; console.log('U: ' + uname + ' G: ' + gname); - ws.send(JSON.stringify({action:'join_game', player_name: uname, game_id: gname})) + ws.send(JSON.stringify({action:'join_game', player_name: uname, game_id: gname, force: force})) } function sit() { seat = document.getElementById('seat_no').value; @@ -102,7 +102,8 @@ - + +

-- libgit2 1.1.1