2020-08-25 13:21:57 -06:00
#!/usr/bin/perl -w
use strict ;
use warnings ;
2020-09-02 10:19:17 -06:00
use POSIX ;
2020-08-25 13:21:57 -06:00
use Net::WebSocket::Server ;
use JSON ;
2020-09-03 11:50:24 -06:00
use Data::Dumper ; # For debuging only, REMOVE WHEN INITIAL CODE IS FINISH
2020-09-02 15:26:46 -06:00
#########################Game Logic starts here##########################
2020-08-25 13:21:57 -06:00
my % sessions = ( ) ;
sub generateSession {
my $ newSession = shift ;
2020-09-07 08:53:16 -06:00
unless ( defined $ newSession ) { my $ uniquifyer = sprintf ( "%.0f" , rand ( ) * 1000 ) ; $ newSession = time . $ uniquifyer ; }
2020-08-25 13:21:57 -06:00
if ( grep ( /$newSession/ , keys % sessions ) ) {
2020-09-07 08:53:16 -06:00
return 0 #failur to create session
2020-08-25 13:21:57 -06:00
} else {
print "Adding session " . $ newSession . " to database\n" ;
2020-09-07 08:53:16 -06:00
$ sessions { $ newSession } = {
"id" = > $ newSession ,
2020-09-09 10:42:27 -06:00
"connections" = > { } ,
2020-09-07 08:53:16 -06:00
"users" = > { } ,
"decks" = > { } ,
"pools" = > { } ,
} ;
2020-08-25 13:21:57 -06:00
}
return $ newSession ;
}
2020-09-04 23:59:47 -06:00
sub generateSingle {
my $ DDF = shift ;
my @ cards = ( "" ) ;
for ( @$ DDF ) {
my @ tempcards = ( ) ;
my % datablock = %$ _ ;
for ( @ cards ) {
my $ current = $ _ ;
for ( @ { $ datablock { data } } ) {
push ( @ tempcards , $ current . $ _ ) ;
}
}
@ cards = @ tempcards ;
}
return @ cards ;
}
2020-09-02 15:26:46 -06:00
sub generateDeck {
2020-09-03 12:05:01 -06:00
my $ DDF = from_json ( shift ) ;
2020-09-04 23:59:47 -06:00
if ( "ARRAY" eq ref ( $ DDF - > [ 0 ] ) ) {
my @ deck = ( ) ;
for ( @$ DDF ) {
push ( @ deck , generateSingle ( $ _ ) ) ;
}
return @ deck ;
} else {
return generateSingle ( $ DDF ) ;
}
2020-09-02 15:26:46 -06:00
}
2020-09-03 11:50:24 -06:00
sub shuffle {
2020-09-02 15:26:46 -06:00
my @ deck = @ _ ;
my $ index = 0 ;
for ( @ deck ) {
my $ swapCardIndex = floor ( rand ( ) * @ deck ) ;
2020-09-03 12:05:01 -06:00
my $ swapCard = $ deck [ $ swapCardIndex ] ;
$ deck [ $ swapCardIndex ] = $ _ ;
2020-09-02 15:26:46 -06:00
$ deck [ $ index ] = $ swapCard ;
$ index + + ;
2020-08-25 13:21:57 -06:00
}
2020-09-07 08:53:16 -06:00
return \ @ deck ;
}
sub shuffleDeck {
my ( $ sessionID , $ deckID ) = @ _ ;
my @ cards = @ { $ sessions { $ sessionID } { "decks" } { $ deckID } - > { cards } } ;
$ sessions { $ sessionID } { "decks" } { $ deckID } - > { cards } = shuffle ( @ cards ) ;
}
sub shufflePool {
my ( $ sessionID , $ poolID ) = @ _ ;
my @ cards = @ { $ sessions { $ sessionID } { "pools" } { $ poolID } - > { cards } } ;
@ { $ sessions { $ sessionID } { "pools" } { $ poolID } - > { cards } } = shuffle ( @ cards ) ; ;
}
sub shuffleHand {
my ( $ sessionID , $ userID , $ handID ) = @ _ ;
my @ cards = @ { $ sessions { $ sessionID } { "users" } { $ userID } - > { hands } { $ handID } - > { cards } } ;
$ sessions { $ sessionID } { "users" } { $ userID } - > { hands } { $ handID } - > { cards } = shuffle ( @ cards ) ;
2020-08-25 13:21:57 -06:00
}
2020-09-02 15:26:46 -06:00
sub addUser {
my ( $ sessionID , $ userID ) = @ _ ;
2020-09-10 11:07:07 -06:00
if ( grep ( /$userID/ , keys % { $ sessions { $ sessionID } { "users" } } ) ) { print "ERROR: Duplicate user\n" ; return 0 ; }
2020-09-07 08:53:16 -06:00
$ sessions { $ sessionID } { "users" } { $ userID } = {
2020-09-03 11:50:24 -06:00
name = > "$userID" ,
2020-09-07 08:53:16 -06:00
hands = > { }
} ;
addHand ( $ sessionID , $ userID , "default" ) ;
2020-09-09 16:00:55 -06:00
return 1 ;
2020-09-02 15:26:46 -06:00
}
sub addCards {
2020-09-03 11:50:24 -06:00
my ( $ sessionID , $ deckID , $ cards ) = @ _ ;
push ( @ { $ sessions { $ sessionID } { "decks" } { $ deckID } - > { cards } } , @$ cards ) ;
2020-09-02 15:26:46 -06:00
}
sub addDeck {
my ( $ sessionID , $ deckID ) = @ _ ;
2020-09-07 08:53:16 -06:00
$ sessions { $ sessionID } { "decks" } { $ deckID } = { name = > "$deckID" , cards = > [] } ;
2020-09-02 15:26:46 -06:00
}
sub delDeck {
my ( $ sessionID , $ deckID ) = @ _ ;
2020-09-07 08:53:16 -06:00
delete ( $ sessions { $ sessionID } { "decks" } { $ deckID } ) ;
2020-09-02 15:26:46 -06:00
}
2020-09-02 10:19:17 -06:00
2020-09-03 11:50:24 -06:00
sub uploadDDF {
my ( $ sessionID , $ deckID , $ DDF ) = @ _ ;
addCards ( $ sessionID , $ deckID , \ @ { generateDeck ( $ DDF ) } ) ;
}
sub addPool {
my ( $ sessionID , $ poolID ) = @ _ ;
2020-09-07 08:53:16 -06:00
$ sessions { $ sessionID } { "pools" } { $ poolID } = { name = > "$poolID" , cards = > [] } ;
2020-09-03 11:50:24 -06:00
}
sub delPool {
my ( $ sessionID , $ poolID ) = @ _ ;
2020-09-14 15:10:19 -06:00
my @ reapedCards = splice ( @ { $ sessions { $ sessionID } { "pools" } { $ poolID } { cards } } ) ;
2020-09-07 08:53:16 -06:00
delete ( $ sessions { $ sessionID } { "pools" } { $ poolID } ) ;
2020-09-03 11:50:24 -06:00
return @ reapedCards ;
}
2020-09-02 15:26:46 -06:00
2020-09-03 11:50:24 -06:00
sub getUsers {
2020-09-03 12:05:01 -06:00
my $ sessionID = $ _ [ 0 ] ;
return keys % { $ sessions { $ sessionID } { "users" } } ;
2020-09-03 11:50:24 -06:00
}
2020-09-02 15:26:46 -06:00
2020-09-03 11:50:24 -06:00
sub getDecks {
2020-09-03 12:05:01 -06:00
my $ sessionID = $ _ [ 0 ] ;
return keys % { $ sessions { $ sessionID } { "decks" } } ;
2020-09-03 11:50:24 -06:00
}
sub getPools {
2020-09-03 12:05:01 -06:00
my $ sessionID = $ _ [ 0 ] ;
return keys % { $ sessions { $ sessionID } { "pools" } } ;
2020-09-03 11:50:24 -06:00
}
2020-09-07 09:12:41 -06:00
sub getDeckName {
my ( $ sessionID , $ deckID ) = @ _ ;
return $ sessions { $ sessionID } { "decks" } { $ deckID } { name } ;
}
sub getUserName {
my ( $ sessionID , $ userID ) = @ _ ;
return $ sessions { $ sessionID } { "users" } { $ userID } { name } ;
}
sub getPoolName {
my ( $ sessionID , $ poolID ) = @ _ ;
return $ sessions { $ sessionID } { "pools" } { $ poolID } { name } ;
}
sub renameDeck {
my ( $ sessionID , $ deckID , $ newName ) = @ _ ;
unless ( defined ( $ newName ) ) { return print "ERROR: No name provided" ; }
$ sessions { $ sessionID } { "decks" } { $ deckID } { name } = $ newName ;
}
sub renameUser {
my ( $ sessionID , $ userID , $ newName ) = @ _ ;
unless ( defined ( $ newName ) ) { return print "ERROR: No name provided" ; }
$ sessions { $ sessionID } { "users" } { $ userID } { name } = $ newName ;
}
sub renamePool {
my ( $ sessionID , $ poolID , $ newName ) = @ _ ;
unless ( defined ( $ newName ) ) { return print "ERROR: No name provided" ; }
$ sessions { $ sessionID } { "pools" } { $ poolID } { name } = $ newName ;
}
2020-09-03 11:50:24 -06:00
sub addHand {
my ( $ sessionID , $ userID , $ handID ) = @ _ ;
2020-09-07 08:53:16 -06:00
$ sessions { $ sessionID } { "users" } { $ userID } { hands } { $ handID } = { cards = > [] } ;
2020-09-03 11:50:24 -06:00
}
sub delHand {
my ( $ sessionID , $ userID , $ handID ) = @ _ ;
2020-09-14 15:10:19 -06:00
my @ leftoverCards = splice ( @ { $ sessions { $ sessionID } { "users" } { $ userID } - > { hands } { $ handID } - > { cards } } ) ;
2020-09-07 08:53:16 -06:00
delete ( $ sessions { $ sessionID } { "users" } { $ userID } { hands } { $ handID } ) ;
2020-09-03 11:50:24 -06:00
return @ leftoverCards ;
}
sub getHands {
my ( $ sessionID , $ userID ) = @ _ ;
2020-09-07 08:53:16 -06:00
return keys % { $ sessions { $ sessionID } { "users" } { $ userID } { hands } } ;
2020-09-03 11:50:24 -06:00
}
sub moveCard {
my ( $ originStackRef , $ originIndex , $ destStackRef , $ destIndex ) = @ _ ;
2020-09-07 08:53:16 -06:00
unless ( defined ( $ originStackRef ) ) { return print "ERROR: No Origin Stack\n" ; }
unless ( defined ( $ originIndex ) ) { return print "ERROR: No Origin Index\n" ; }
unless ( defined ( $ destStackRef ) ) { return print "ERROR: No Destination Stack\n" ; }
unless ( defined ( $ destIndex ) ) { return print "ERROR: No Destination Index\n" ; }
2020-09-04 09:04:42 -06:00
my $ card = splice ( @$ originStackRef , $ originIndex , 1 ) ;
2020-09-07 08:53:16 -06:00
unless ( defined ( $ card ) ) { return print "ERROR: No Card available to be pulled\n" ; }
2020-09-04 09:04:42 -06:00
splice ( @$ destStackRef , $ destIndex , 0 , $ card ) ;
2020-09-03 11:50:24 -06:00
}
sub drawCard {
my ( $ sessionID , $ deckID , $ userID , $ handID ) = @ _ ;
moveCard (
2020-09-07 08:53:16 -06:00
$ sessions { $ sessionID } { "decks" } { $ deckID } - > { cards } , 0 ,
$ sessions { $ sessionID } { "users" } { $ userID } - > { hands } { $ handID } - > { cards } , 0
2020-09-03 11:50:24 -06:00
) ;
}
sub playCard {
my ( $ sessionID , $ userID , $ handID , $ cardIndex , $ poolID ) = @ _ ;
moveCard (
\ @ { $ sessions { $ sessionID } { "users" } { $ userID } - > { hands } { $ handID } - > { cards } } , $ cardIndex ,
\ @ { $ sessions { $ sessionID } { "pools" } { $ poolID } - > { cards } } , 0
) ;
}
sub delUser {
my ( $ sessionID , $ userID ) = @ _ ;
2020-09-07 08:53:16 -06:00
my @ hands = getHands ( $ sessionID , $ userID ) ;
my @ reaped = ( ) ;
2020-09-03 11:50:24 -06:00
for ( @ hands ) {
2020-09-07 08:53:16 -06:00
push ( @ reaped , delHand ( $ sessionID , $ userID , $ _ ) ) ;
2020-09-03 11:50:24 -06:00
}
2020-09-07 08:53:16 -06:00
delete ( $ sessions { $ sessionID } { "users" } { $ userID } ) ;
return @ reaped ;
2020-09-03 11:50:24 -06:00
}
sub getDeckSize {
my ( $ sessionID , $ deckID ) = @ _ ;
2020-09-14 15:10:19 -06:00
return scalar @ { $ sessions { $ sessionID } { "decks" } { $ deckID } - > { cards } } ;
2020-09-03 11:50:24 -06:00
}
2020-09-02 15:26:46 -06:00
2020-09-10 11:07:07 -06:00
sub getPoolTop {
my ( $ sessionID , $ poolID ) = @ _ ;
return @ { $ sessions { $ sessionID } { "pools" } { $ poolID } - > { cards } } [ 0 ] ;
}
2020-09-02 15:26:46 -06:00
########################Game Logic ends here#############################
#########################Server Logic below##############################
my $ origin = 'ws://localhost' ;
sub joinSession {
2020-09-09 10:42:27 -06:00
my ( $ sessionID , $ userID ) = @ _ ;
unless ( defined ( $ sessions { $ sessionID } ) ) {
print $ sessionID . " does not exsist, attempting to create...\n" ;
if ( generateSession ( $ sessionID ) ) {
print "Session " . $ sessionID . " has been created.\n" ;
} else {
print "ERROR: Could not create session " . $ sessionID . "\n" ;
return 0 ;
}
}
2020-09-09 16:00:55 -06:00
unless ( addUser ( $ sessionID , $ userID ) ) {
#assume rejoining user
}
2020-09-09 10:42:27 -06:00
return 1 ;
2020-09-02 15:26:46 -06:00
}
my $ server = Net::WebSocket::Server - > new (
2020-08-25 13:21:57 -06:00
listen = > 8080 ,
on_connect = > sub {
my ( $ serv , $ conn ) = @ _ ;
$ conn - > on (
handshake = > sub {
2020-09-11 17:58:11 -06:00
my ( $ conn , $ handshake ) = @ _ ;
2020-08-25 13:21:57 -06:00
$ conn - > { "initHand" } = $ handshake ;
} ,
ready = > sub {
2020-09-11 17:58:11 -06:00
my ( $ conn ) = @ _ ;
2020-09-09 10:42:27 -06:00
$ conn - > send_utf8 ( '{"request":"user"}' ) ;
$ conn - > send_utf8 ( '{"request":"session"}' ) ;
2020-08-25 13:21:57 -06:00
} ,
utf8 = > sub {
2020-09-11 17:58:11 -06:00
my ( $ conn , $ msg ) = @ _ ;
2020-08-25 13:21:57 -06:00
my $ sessionID = $ conn - > { "currentSession" } { "id" } ;
my $ messageData = "" ;
eval { $ messageData = from_json ( $ msg ) } ;
2020-09-09 10:42:27 -06:00
if ( $@ ) { $ conn - > send_utf8 ( '{"error":100, "message":"ERROR: Invalid json"}' ) ; return 0 ; }
if ( defined ( $ messageData - > { user } ) ) {
$ conn - > { user } = $ messageData - > { user } ;
2020-09-09 16:00:55 -06:00
# Need to check if userID is unique
2020-09-09 10:42:27 -06:00
$ conn - > send_utf8 ( '{"info":"user success"}' ) ;
}
if ( defined ( $ messageData - > { session } ) ) {
2020-09-11 12:12:08 -06:00
unless ( defined ( $ conn - > { user } ) ) { $ conn - > send_utf8 ( '{"error":200, "message":"Could not join session, no user defined", "request":"user"}' ) ; $ conn - > send_utf8 ( '{"request":"session"}' ) ; return 0 ; }
2020-09-09 10:42:27 -06:00
$ conn - > { session } = $ messageData - > { session } ;
$ conn - > send_utf8 ( '{"info":"session success", "request":"join"}' ) ;
}
if ( defined ( $ messageData - > { action } ) ) {
2020-09-10 11:07:07 -06:00
if ( $ messageData - > { action } =~ /join/ ) { if ( joinSession ( $ conn - > { session } , $ conn - > { user } ) ) { $ conn - > send_utf8 ( '{"info":"join success", "request":"update"}' ) ; } }
if ( $ messageData - > { action } =~ /update/ ) { my $ sessionID = $ conn - > { session } ; for ( $ conn - > server - > connections ) { if ( $ _ - > { session } == $ conn - > { session } ) {
#This might be a lot to do at once, might need to break it up in the future.
2020-09-09 16:00:55 -06:00
# Update all connections joined to this session.
# User List
my @ users = getUsers ( $ sessionID ) ;
2020-09-10 11:07:07 -06:00
my @ userNames ;
my $ current = $ _ ;
2020-09-09 16:00:55 -06:00
for ( @ users ) {
2020-09-10 11:07:07 -06:00
push ( @ userNames , getUserName ( $ sessionID , $ _ ) ) ;
2020-09-09 16:00:55 -06:00
}
2020-09-10 11:07:07 -06:00
$ current - > send_utf8 ( '{"users":["' . join ( '","' , @ userNames ) . '"]}' ) ;
2020-09-09 16:00:55 -06:00
# Deck List
my @ decks = getDecks ( $ sessionID ) ;
2020-09-10 11:07:07 -06:00
my % deckStats = ( ) ;
2020-09-09 16:00:55 -06:00
for ( @ decks ) {
2020-09-10 11:07:07 -06:00
$ deckStats { $ _ } { name } = $ sessions { $ sessionID } { "decks" } { $ _ } { name } ;
$ deckStats { $ _ } { size } = getDeckSize ( $ sessionID , $ _ ) ;
2020-09-09 16:00:55 -06:00
}
2020-09-10 11:07:07 -06:00
$ current - > send_utf8 ( '{"decks":' . to_json ( \ % deckStats ) . '}' ) ;
2020-09-09 16:00:55 -06:00
# Pool List
2020-09-10 11:07:07 -06:00
my @ pools = getPools ( $ sessionID ) ;
my % poolStats = ( ) ;
for ( @ pools ) {
$ poolStats { $ _ } { name } = $ sessions { $ sessionID } { "pools" } { $ _ } { name } ;
$ poolStats { $ _ } { top } = getPoolTop ( $ sessionID , $ _ ) ;
}
$ current - > send_utf8 ( '{"pools":' . to_json ( \ % poolStats ) . '}' ) ;
2020-09-09 16:00:55 -06:00
# Users Hands
2020-09-14 15:10:19 -06:00
my @ hands = getHands ( $ sessionID , $ _ - > { user } ) ;
2020-09-11 12:12:08 -06:00
my % handStats = ( ) ;
for ( @ hands ) {
$ handStats { $ _ } { name } = $ _ ;
$ handStats { $ _ } { cards } = [] ;
}
$ current - > send_utf8 ( '{"hands":' . to_json ( \ % handStats ) . '}' ) ;
2020-09-10 11:07:07 -06:00
# for each hand
for ( @ hands ) {
my $ handID = $ _ ;
2020-09-14 15:10:19 -06:00
my @ hand = @ { $ sessions { $ sessionID } { "users" } { $ current - > { user } } { hands } { $ handID } { cards } } ;
2020-09-10 11:07:07 -06:00
# each card (so we scale better)
if ( @ hand ) { for ( @ hand ) {
my $ card = $ _ ;
$ current - > send_utf8 ( '{"action":"addCard","hand":"' . $ handID . '", "card":"' . $ card . '"}' ) ;
} }
}
2020-09-09 16:00:55 -06:00
} } }
2020-09-14 15:10:19 -06:00
if ( $ messageData - > { action } =~ /draw/ ) {
drawCard ( $ conn - > { session } , $ messageData - > { deck } , $ conn - > { user } , $ messageData - > { hand } ) ;
$ conn - > send_utf8 ( '{"info":"card drawn", "request":"update"}' ) ;
}
if ( $ messageData - > { action } =~ /play/ ) {
playCard ( $ conn - > { session } , $ conn - > { user } , $ messageData - > { hand } , $ messageData - > { cardID } , $ messageData - > { pool } ) ;
$ conn - > send_utf8 ( '{"info":"card played", "request":"update"}' ) ;
}
if ( $ messageData - > { action } =~ /clear/ ) {
my @ cards = delPool ( $ conn - > { session } , $ messageData - > { pool } ) ;
addCards ( $ conn - > { session } , $ messageData - > { deck } , \ @ cards ) ;
addPool ( $ conn - > { session } , $ messageData - > { pool } ) ;
$ conn - > send_utf8 ( '{"info":"pool cleared", "request":"update"}' ) ;
}
2020-09-09 10:42:27 -06:00
}
2020-08-25 13:21:57 -06:00
} ,
2020-09-02 15:26:46 -06:00
disconnect = > sub {
my ( $ conn , $ code , $ reason ) = @ _ ;
}
2020-09-03 12:05:01 -06:00
) ;
}
2020-09-02 15:26:46 -06:00
) ;
2020-09-10 11:07:07 -06:00
my $ ses = generateSession ( 50 ) ;
addDeck ( $ ses , "default" ) ;
my @ tCards = generateDeck ( '[{"data":["Male ","Female "]},{"data":["Ardvark ","Platipus ","Cat "]},{"data":["Jumping","Falling","Flying"]}]' ) ;
addCards ( $ ses , "default" , \ @ tCards ) ;
addPool ( $ ses , "default" ) ;
addUser ( $ ses , "Sergiy" ) ;
drawCard ( $ ses , "default" , "Sergiy" , "default" ) ;
drawCard ( $ ses , "default" , "Sergiy" , "default" ) ;
playCard ( $ ses , "Sergiy" , "default" , 0 , "default" ) ;
2020-09-02 15:26:46 -06:00
$ server - > start ;