/****************************************************************************** * Copyright © 2014-2015 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * SuperNET software, including this file may be copied, modified, propagated * * or distributed except according to the terms contained in the LICENSE file * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ #ifdef later #ifdef DEFINES_ONLY #ifndef tourney777_h #define tourney777_h // nonplaying nodeA #include #include #include #include #include "../iguana777.h" struct tourney777_table { uint64_t tableid; union hostnet777 *hn[CARDS777_MAXPLAYERS]; int32_t N,numactive; }; struct tourney777 { struct tourney777_table tables[1024]; char transport[16],ipaddr[64],name[128]; uint32_t started,finished,numtables; uint16_t port; union hostnet777 hn[]; } *Tournament; #define TOURNEY777_TABLESIZE 9 #define TOURNEY777_MINPLAYERS (TOURNEY777_TABLESIZE - 2) #endif #else #ifndef tourney777_c #define tourney777_c #ifndef tourney777_h #define DEFINES_ONLY #include "tourney777.c" #undef DEFINES_ONLY #endif void tourney777_jointable(struct tourney777 *tp,struct tourney777_table *table,union hostnet777 *player) { player->client->tableid = table->tableid; printf("jointable.%llu tableid.%llu\n",(long long)player->client->H.nxt64bits,(long long)table->tableid); } void tourney777_leavetable(struct tourney777 *tp,struct tourney777_table *table,union hostnet777 *player) { printf("leavetable.%llu tableid.%llu\n",(long long)player->client->H.nxt64bits,(long long)table->tableid); player->client->tableid = 0; } void tourney777_createtable(struct tourney777 *tp,union hostnet777 *players[],int32_t num) { int32_t i; uint64_t tableid = rand(); for (i=0; iclient->tableid = tableid; printf("createtable.%llu numplayers.%d\n",(long long)tableid,num); } void tourney777_freetable(struct tourney777 *tp,struct tourney777_table *table) { printf("freetable.%llu numplayers.%d numactives.%d\n",(long long)table->tableid,table->N,table->numactive); } struct tourney777_table *tourney777_findtable(struct tourney777 *tp,uint64_t tableid,struct tourney777_table *avoid) { struct tourney777_table *mintable = 0; int32_t i,minplayers = CARDS777_MAXPLAYERS + 1; if ( tp->numtables > 0 ) { for (i=0; inumtables; i++) { if ( tableid == 0 ) { if ( (avoid == 0 || avoid != &tp->tables[i]) && tp->tables[i].numactive != TOURNEY777_TABLESIZE && tp->tables[i].numactive < minplayers ) { minplayers = tp->tables[i].numactive; mintable = &tp->tables[i]; } } else if ( tp->tables[i].tableid == tableid ) return(&tp->tables[i]); } } return(mintable); } union hostnet777 *tourney777_nextblind(struct tourney777_table *table) { int32_t i,ind,j = (rand() % table->N); for (i=0; iN; i++) { ind = (j + i) % table->N; if ( table->hn[ind] != 0 && table->hn[ind]->client->balance != 0 ) return(table->hn[ind]); } return(0); } void tourney777_rebalance(struct tourney777 *tp,int32_t delta) { int32_t i,j,num,n,pertable,flag,threshold,needs_table = 0; struct hostnet777_server *srv; union hostnet777 *player,*newtable[TOURNEY777_TABLESIZE]; struct tourney777_table *table,*t; srv = tp->hn[0].server; if ( delta < 0 ) { if ( (table= tourney777_findtable(tp,0,0)) != 0 ) { if ( table->numactive < TOURNEY777_MINPLAYERS ) { if ( tp->numtables >= table->numactive ) { for (j=0; jN; j++) tourney777_leavetable(tp,table,table->hn[j]); for (j=0; jN; j++) { if ( (t= tourney777_findtable(tp,0,table)) != 0 ) tourney777_jointable(tp,t,table->hn[j]); else printf("tourney777_rebalance: cant find table with slot\n"); } tourney777_freetable(tp,table); } else { printf("tourney777_rebalance: imbalance tableid.%llu numactive.%d vs total tables.%d\n",(long long)table->tableid,table->numactive,tp->numtables); flag = 0; for (threshold=TOURNEY777_TABLESIZE; threshold>=TOURNEY777_MINPLAYERS+1; threshold--) { for (i=0; inumtables; i++) { if ( tp->tables[i].numactive == threshold ) { if ( (player= tourney777_nextblind(&tp->tables[i])) != 0 ) { tourney777_leavetable(tp,&tp->tables[i],player); tourney777_jointable(tp,table,player); flag = 1; break; } else printf("tourney777_nextblind: cant find nextblind\n"); } } if ( flag != 0 ) break; } if ( flag == 0 ) { printf("tourney777_rebalance: couldnt find donor tableid.%llu numactive.%d vs total tables.%d\n",(long long)table->tableid,table->numactive,tp->numtables); } } } } } else { for (i=1; inum; i++) { player = &tp->hn[i]; if ( player != 0 && player->client->tableid == 0 && player->client->balance != 0 ) { if ( (table= tourney777_findtable(tp,0,0)) != 0 ) tourney777_jointable(tp,table,player); else needs_table++; } } if ( needs_table >= TOURNEY777_TABLESIZE ) { num = (needs_table / TOURNEY777_TABLESIZE); if ( (needs_table % TOURNEY777_TABLESIZE) != 0 ) num++; pertable = (needs_table / num); printf("needs_table.%d pertable.%d num.%d\n",needs_table,pertable,num); for (j=0; jnum; i++) { player = &tp->hn[i]; if ( player != 0 && player->client->tableid == 0 && player->client->balance != 0 ) { newtable[n++] = player; if ( n >= pertable ) break; } } tourney777_createtable(tp,newtable,n); } } } } void tourney777_newhand(union hostnet777 *hn,uint64_t tableid,cJSON *json,uint8_t *data,int32_t datalen) { struct pangea_info *pangea_find(uint64_t tableid,int32_t threadid); char *pangea_dispsummary(struct pangea_info *sp,int32_t verbose,uint8_t *summary,int32_t summarysize,uint64_t tableid,int32_t handid,int32_t numplayers); char *handhist; int32_t i,j,handid,numplayers,n,m,busted,rebuy; cJSON *handjson,*array,*balances,*item; struct tourney777_table *table; handid = juint(json,"handid"); numplayers = juint(json,"numplayers"); if ( (handhist= pangea_dispsummary(pangea_find(tableid,0),1,data,datalen,tableid,handid,numplayers)) != 0 ) { printf("GOT HANDHIST.(%s)\n",handhist); if ( (handjson= cJSON_Parse(handhist)) != 0 ) { if ( (array= jarray(&n,handjson,"hand")) != 0 ) { for (i=0; ihn[j]->client->balance = j64bits(jitem(balances,j),0); } if ( busted != 0 ) tourney777_rebalance(Tournament,-1); } } free_json(handjson); } free(handhist); } } void tourney777_poll(union hostnet777 *hn) { char *jsonstr; uint64_t senderbits,tableid; uint8_t *buf=0; int32_t maxlen,len,senderind; uint32_t timestamp; char *cmdstr,*hexstr; cJSON *json; maxlen = 65536; if ( (buf= malloc(maxlen)) == 0 ) { printf("tourney777_poll: cant allocate buf\n"); return; } if ( (jsonstr= queue_dequeue(&hn->server->H.Q,1)) != 0 ) { printf("tourney slot.%d GOT.(%s)\n",hn->client->H.slot,jsonstr); if ( (json= cJSON_Parse(jsonstr)) != 0 ) { tableid = j64bits(json,"tableid"); if ( tourney777_findtable(Tournament,tableid,0) == 0 ) { free(buf); return; } senderbits = j64bits(json,"sender"); if ( (senderind= juint(json,"myind")) < 0 || senderind >= hn->server->num ) { printf("pangea_poll: illegal senderind.%d cardi.%d turni.%d\n",senderind,juint(json,"cardi"),juint(json,"turni")); goto cleanup; } timestamp = juint(json,"timestamp"); hn->client->H.state = juint(json,"state"); len = juint(json,"n"); cmdstr = jstr(json,"cmd"); if ( (hexstr= jstr(json,"data")) != 0 && strlen(hexstr) == (len<<1) ) { if ( len > maxlen ) { printf("len too big for tourney777_poll\n"); goto cleanup; } decode_hex(buf,len,hexstr); } else if ( hexstr != 0 ) printf("len.%d vs hexlen.%d (%s)\n",len,(int32_t)strlen(hexstr)>>1,hexstr); if ( cmdstr != 0 ) { if ( strcmp(cmdstr,"newhand") == 0 ) tourney777_newhand(hn,tableid,json,buf,len); } cleanup: free_json(json); } free_queueitem(jsonstr); } free(buf); } char *tourney777_start(char *name,cJSON *json) { if ( Tournament != 0 && strcmp(Tournament->name,name) == 0 ) { Tournament->started = (uint32_t)time(NULL); tourney777_rebalance(Tournament,1); return(clonestr("{\"result\":\"tournament started\"}")); } else return(clonestr("{\"error\":\"no matching tournament\"}")); } char *tourney777_register(char *name,bits256 pubkey,cJSON *json) { int32_t i; struct hostnet777_server *srv; if ( Tournament != 0 && strcmp(Tournament->name,name) == 0 && (srv= Tournament->hn[0].server) != 0 ) { if ( Tournament->started != 0 ) return(clonestr("{\"error\":\"tournament already started\"}")); else { for (i=0; inum; i++) if ( memcmp(pubkey.bytes,srv->clients[i].pubkey.bytes,sizeof(bits256)) == 0 ) return(clonestr("{\"error\":\"already registered in tournament\"}")); srv->clients[srv->num].lastcontact = (uint32_t)time(NULL); // get endpoint srv->num++; return(clonestr("{\"result\":\"registered in tournament\"}")); } } else return(clonestr("{\"error\":\"no matching tournament\"}")); } char *tourney777_deregister(char *name,bits256 pubkey,cJSON *json) { int32_t i; struct hostnet777_server *srv; if ( Tournament != 0 && strcmp(Tournament->name,name) == 0 && (srv= Tournament->hn[0].server) != 0 ) { if ( Tournament->started != 0 ) return(clonestr("{\"error\":\"tournament already started\"}")); else { for (i=0; inum; i++) if ( memcmp(pubkey.bytes,srv->clients[i].pubkey.bytes,sizeof(bits256)) == 0 ) { memset(&srv->clients[i],0,sizeof(srv->clients[i])); if ( i == srv->num-1 ) srv->num--; return(clonestr("{\"result\":\"deregistered from tournament\"}")); } return(clonestr("{\"error\":\"not registered in tournament\"}")); } } else return(clonestr("{\"error\":\"no matching tournament\"}")); } struct tourney777 *tourney777_init(char *name,bits256 privkey,char *transport,char *ipaddr,uint16_t port,int32_t maxplayers,cJSON *json) { struct hostnet777_server *srv; bits256 pubkey; struct tourney777 *tourney; int32_t i; char endpoint[128]; tourney = calloc(1,sizeof(*tourney) + sizeof(*tourney->hn)*maxplayers); pubkey = acct777_pubkey(privkey); safecopy(tourney->name,name,sizeof(tourney->name)-1); if ( transport == 0 || transport[0] == 0 ) transport = "tcp"; strcpy(tourney->transport,transport); if ( ipaddr == 0 || ipaddr[0] == 0 ) ipaddr = "127.0.0.1"; strcpy(tourney->ipaddr,ipaddr); if ( port == 0 ) port = 8897; tourney->port = port; if ( (srv= hostnet777_server(privkey,pubkey,tourney->transport,tourney->ipaddr,tourney->port,maxplayers)) == 0 ) { printf("tourney777_init: cant create hostnet777 server\n"); return(0); } srv->H.privkey = privkey, srv->H.pubkey = pubkey; for (i=0; iep.transport,srv->ep.ipaddr,srv->ep.port + i + 1); srv->clients[i].pmsock = nn_createsocket(endpoint,1,"NN_PULL",NN_PULL,srv->ep.port + i + 1,10,10); } srv->H.pollfunc = tourney777_poll; tourney->hn[0].server = srv; // set tournament parameters if ( portable_thread_create((void *)hostnet777_idler,&tourney->hn[0]) == 0 ) printf("error launching server thread\n"); Tournament = tourney; return(tourney); } #endif #endif #endif