Show players in lobby
This commit is contained in:
parent
c64535675f
commit
86ffa9726c
14 changed files with 325 additions and 126 deletions
|
@ -3,6 +3,7 @@
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
#[macro_use]
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
extern crate async_std;
|
extern crate async_std;
|
||||||
|
@ -76,7 +77,7 @@ async fn main() {
|
||||||
|
|
||||||
let pool = ThreadPool::new().unwrap();
|
let pool = ThreadPool::new().unwrap();
|
||||||
pool.spawn_ok(fut.map(|_| ()));
|
pool.spawn_ok(fut.map(|_| ()));
|
||||||
let gm = create_game_manager("0.0.0.0:9142", pool.clone());
|
let gm = create_game_manager("0.0.0.0:9142", pool.clone()).await;
|
||||||
|
|
||||||
|
|
||||||
let mut routes = Vec::new();
|
let mut routes = Vec::new();
|
||||||
|
@ -98,12 +99,12 @@ async fn main() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_game_manager(tcp: &str, pool: ThreadPool) -> game::Manager {
|
async fn create_game_manager(tcp: &str, pool: ThreadPool) -> game::Manager {
|
||||||
let addr = tcp.parse::<SocketAddr>().unwrap();
|
let addr = tcp.parse::<SocketAddr>().unwrap();
|
||||||
let (gmb, handle) = game::Manager::builder(pool.clone());
|
let (gmb, handle) = game::Manager::builder(pool.clone());
|
||||||
pool.spawn_ok(handle.map(|_| ()));
|
pool.spawn_ok(handle.map(|_| ()));
|
||||||
let ep = TcpEndpoint::new(addr, pool.clone());
|
let ep = TcpEndpoint::new(addr, pool.clone());
|
||||||
|
|
||||||
let gmb = gmb.add_endpoint(ep, "TCP endpoint");
|
let gmb = gmb.add_endpoint(ep, "TCP endpoint");
|
||||||
gmb.build()
|
gmb.build("games.ini", pool).await.unwrap()
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ pub struct PlanetWarsGame {
|
||||||
log_file: File,
|
log_file: File,
|
||||||
turns: u64,
|
turns: u64,
|
||||||
name: String,
|
name: String,
|
||||||
logged: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlanetWarsGame {
|
impl PlanetWarsGame {
|
||||||
|
@ -47,7 +46,6 @@ impl PlanetWarsGame {
|
||||||
log_file: file,
|
log_file: file,
|
||||||
turns: 0,
|
turns: 0,
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
logged: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,8 +167,8 @@ impl PlanetWarsGame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use ini::Ini;
|
use serde_json::Value;
|
||||||
use std::fs::OpenOptions;
|
|
||||||
impl game::Controller for PlanetWarsGame {
|
impl game::Controller for PlanetWarsGame {
|
||||||
fn start(&mut self) -> Vec<HostMsg> {
|
fn start(&mut self) -> Vec<HostMsg> {
|
||||||
let mut updates = Vec::new();
|
let mut updates = Vec::new();
|
||||||
|
@ -194,31 +192,25 @@ impl game::Controller for PlanetWarsGame {
|
||||||
updates
|
updates
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_done(&mut self) -> bool {
|
fn is_done(&mut self) -> Option<Value> {
|
||||||
if self.state.is_finished() {
|
if self.state.is_finished() {
|
||||||
if !self.logged {
|
Some(json!({
|
||||||
let mut f = match OpenOptions::new()
|
"winners": self.state.living_players(),
|
||||||
.create(true)
|
"turns": self.state.turn_num,
|
||||||
.append(true)
|
"name": self.name.clone(),
|
||||||
.open("games.ini")
|
"file": self.log_file_loc.clone(),
|
||||||
{
|
}))
|
||||||
Err(_) => return true,
|
|
||||||
Ok(f) => f,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut conf = Ini::new();
|
|
||||||
conf.with_section(Some(self.log_file_loc.clone()))
|
|
||||||
.set("name", &self.name)
|
|
||||||
.set("turns", format!("{}", self.turns));
|
|
||||||
|
|
||||||
conf.write_to(&mut f).unwrap();
|
|
||||||
|
|
||||||
self.logged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
} else {
|
} else {
|
||||||
false
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct FinishedState {
|
||||||
|
pub winners: Vec<u64>,
|
||||||
|
pub turns: u64,
|
||||||
|
pub name: String,
|
||||||
|
pub file: String,
|
||||||
|
pub players: Vec<(u64, String)>,
|
||||||
|
}
|
||||||
|
|
|
@ -116,16 +116,22 @@ async fn game_post(game_req: Json<GameReq>, tp: State<'_, ThreadPool>, gm: State
|
||||||
let game_id = gm.start_game(game).await.unwrap();
|
let game_id = gm.start_game(game).await.unwrap();
|
||||||
state.add_game(game_req.name.clone(), game_id);
|
state.add_game(game_req.name.clone(), game_id);
|
||||||
|
|
||||||
if let Some(conns) = gm.get_state(game_id).await {
|
match gm.get_state(game_id).await {
|
||||||
|
Some(Ok(conns)) => {
|
||||||
let players: Vec<u64> = conns.iter().map(|conn| match conn {
|
let players: Vec<u64> = conns.iter().map(|conn| match conn {
|
||||||
Connect::Waiting(_, key) => *key,
|
Connect::Waiting(_, key) => *key,
|
||||||
_ => 0,
|
_ => 0,
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
Ok(Json(GameRes { players }))
|
Ok(Json(GameRes { players }))
|
||||||
} else {
|
},
|
||||||
|
Some(Err(v)) => {
|
||||||
|
Err(serde_json::to_string(&v).unwrap())
|
||||||
|
},
|
||||||
|
None => {
|
||||||
Err(String::from("Fuck the world"))
|
Err(String::from("Fuck the world"))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fuel(routes: &mut Vec<Route>) {
|
pub fn fuel(routes: &mut Vec<Route>) {
|
||||||
|
|
|
@ -9,12 +9,67 @@ pub struct Map {
|
||||||
url: String,
|
url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize, Eq, PartialEq)]
|
||||||
pub struct GameState {
|
pub struct PlayerStatus {
|
||||||
|
waiting: bool,
|
||||||
|
connected: bool,
|
||||||
|
reconnecting: bool,
|
||||||
|
value: String,
|
||||||
|
}
|
||||||
|
impl From<Connect> for PlayerStatus {
|
||||||
|
fn from(value: Connect) -> Self {
|
||||||
|
match value {
|
||||||
|
Connect::Connected(_, name) => PlayerStatus { waiting: false, connected: true, reconnecting: false, value: name },
|
||||||
|
Connect::Reconnecting(_, name) => PlayerStatus { waiting: false, connected: true, reconnecting: true, value: name },
|
||||||
|
Connect::Waiting(_, key) => PlayerStatus { waiting: true, connected: false, reconnecting: false, value: format!("Key: {}", key) },
|
||||||
|
_ => panic!("No playerstatus possible from Connect::Request"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Eq, PartialEq)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
pub enum GameState {
|
||||||
|
Finished {
|
||||||
name: String,
|
name: String,
|
||||||
finished: bool,
|
map: String,
|
||||||
turns: Option<u64>,
|
players: Vec<(String, bool)>,
|
||||||
players: Vec<String>,
|
turns: u64,
|
||||||
|
},
|
||||||
|
Playing {
|
||||||
|
name: String,
|
||||||
|
map: String,
|
||||||
|
players: Vec<PlayerStatus>,
|
||||||
|
connected: usize,
|
||||||
|
total: usize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
impl PartialOrd for GameState {
|
||||||
|
fn partial_cmp(&self, other: &GameState) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for GameState {
|
||||||
|
fn cmp(&self, other: &GameState) -> Ordering {
|
||||||
|
match self {
|
||||||
|
GameState::Finished { name, .. } => {
|
||||||
|
match other {
|
||||||
|
GameState::Finished { name: _name, .. } => name.cmp(_name),
|
||||||
|
_ => Ordering::Greater,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
GameState::Playing { name, .. } => {
|
||||||
|
match other {
|
||||||
|
GameState::Playing { name: _name, .. } => name.cmp(_name),
|
||||||
|
_ => Ordering::Less,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Visualiser game option
|
/// Visualiser game option
|
||||||
|
@ -120,6 +175,7 @@ pub async fn get_games() -> Result<Vec<GameOption>, String> {
|
||||||
Ok(games)
|
Ok(games)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use crate::planetwars::FinishedState;
|
||||||
|
|
||||||
use mozaic::modules::game;
|
use mozaic::modules::game;
|
||||||
use mozaic::util::request::Connect;
|
use mozaic::util::request::Connect;
|
||||||
|
@ -130,34 +186,33 @@ pub async fn get_states(game_ids: &Vec<(String, u64)>, manager: &game::Manager)
|
||||||
|
|
||||||
for (gs, name) in gss {
|
for (gs, name) in gss {
|
||||||
if let Some(state) = gs {
|
if let Some(state) = gs {
|
||||||
let mut players: Vec<String> = state.iter().map(|conn| match conn {
|
match state {
|
||||||
Connect::Waiting(_, key) => format!("Waiting {}", key),
|
Ok(conns) => {
|
||||||
_ => String::from("Some connected player")
|
let players: Vec<PlayerStatus> = conns.iter().cloned().map(|x| x.into()).collect();
|
||||||
}).collect();
|
let connected = players.iter().filter(|x| x.connected).count();
|
||||||
|
|
||||||
players.sort();
|
|
||||||
|
|
||||||
states.push(
|
states.push(
|
||||||
GameState {
|
GameState::Playing { name: name, total: players.len(), players, connected, map: String::new(), }
|
||||||
name,
|
);
|
||||||
turns: None,
|
},
|
||||||
players: players,
|
Err(value) => {
|
||||||
finished: false,
|
let state: FinishedState = serde_json::from_value(value).expect("Shit failed");
|
||||||
}
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
states.push(
|
states.push(
|
||||||
GameState {
|
GameState::Finished {
|
||||||
name,
|
map: String::new(),
|
||||||
turns: None,
|
players: state.players.iter().map(|(id, name)| (name.clone(), state.winners.contains(&id))).collect(),
|
||||||
players: Vec::new(),
|
name: state.name,
|
||||||
finished: true,
|
turns: state.turns,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
states.sort_by_key(|a| a.name.clone());
|
states.sort();
|
||||||
|
println!(
|
||||||
|
"{}", serde_json::to_string_pretty(&states).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
Ok(states)
|
Ok(states)
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: start;
|
||||||
background: black;
|
background: black;
|
||||||
color: #ff7f00;
|
color: #ff7f00;
|
||||||
line-height: 1.5rem;
|
line-height: 1.5rem;
|
||||||
|
@ -66,11 +66,9 @@ body {
|
||||||
.info a {
|
.info a {
|
||||||
/* color: inherit; */
|
/* color: inherit; */
|
||||||
/* filter: saturate(100%); */
|
/* filter: saturate(100%); */
|
||||||
|
|
||||||
/* filter: invert(75%); */
|
/* filter: invert(75%); */
|
||||||
color: #ff7f00;
|
color: #ff7f00;
|
||||||
filter: brightness(0.5);
|
filter: brightness(0.5);
|
||||||
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
@ -88,36 +86,30 @@ body {
|
||||||
color: #ff7f00;
|
color: #ff7f00;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info div p {
|
.info div p {
|
||||||
/* color: #ff7f00; */
|
/* color: #ff7f00; */
|
||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes heartbeat
|
@keyframes heartbeat {
|
||||||
{
|
0% {
|
||||||
0%
|
transform: rotate(-45deg) scale( .75);
|
||||||
{
|
|
||||||
transform: rotate(-45deg) scale( .75 );
|
|
||||||
}
|
}
|
||||||
20%
|
20% {
|
||||||
{
|
transform: rotate(-45deg) scale( 1);
|
||||||
transform: rotate(-45deg) scale( 1 );
|
|
||||||
}
|
}
|
||||||
40%
|
40% {
|
||||||
{
|
transform: rotate(-45deg) scale( .75);
|
||||||
transform: rotate(-45deg) scale( .75 );
|
|
||||||
}
|
}
|
||||||
60%
|
60% {
|
||||||
{
|
transform: rotate(-45deg) scale( 1);
|
||||||
transform: rotate(-45deg) scale( 1 );
|
|
||||||
}
|
}
|
||||||
80%
|
80% {
|
||||||
{
|
transform: rotate(-45deg) scale( .75);
|
||||||
transform: rotate(-45deg) scale( .75 );
|
|
||||||
}
|
}
|
||||||
100%
|
100% {
|
||||||
{
|
transform: rotate(-45deg) scale( .75);
|
||||||
transform: rotate(-45deg) scale( .75 );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,9 +122,7 @@ body {
|
||||||
top: 0;
|
top: 0;
|
||||||
transform: rotate(-45deg);
|
transform: rotate(-45deg);
|
||||||
width: 20px;
|
width: 20px;
|
||||||
|
|
||||||
filter: none;
|
filter: none;
|
||||||
|
|
||||||
animation: heartbeat 2s infinite;
|
animation: heartbeat 2s infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
76
backend/static/style/collapsable.css
Normal file
76
backend/static/style/collapsable.css
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
CSS for the main interaction
|
||||||
|
*/
|
||||||
|
|
||||||
|
.accordion>input[type="checkbox"] {
|
||||||
|
position: absolute;
|
||||||
|
left: -100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion .content {
|
||||||
|
overflow-y: hidden;
|
||||||
|
height: 0;
|
||||||
|
transition: height 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion>input[type="checkbox"]:checked~.content {
|
||||||
|
height: auto;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion label {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Styling
|
||||||
|
*/
|
||||||
|
|
||||||
|
.accordion {
|
||||||
|
margin: 1em;
|
||||||
|
width: 90%;
|
||||||
|
min-width: 250px;
|
||||||
|
max-width: 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion .content {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion>input[type="checkbox"]:checked~.content {
|
||||||
|
background-color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion .handle {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.125em;
|
||||||
|
line-height: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion label {
|
||||||
|
color: #ff7f00;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: normal;
|
||||||
|
padding: 15px;
|
||||||
|
background: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion label:hover,
|
||||||
|
.accordion label:focus {
|
||||||
|
filter: brightness(0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion .handle label:before {
|
||||||
|
font-family: 'fontawesome';
|
||||||
|
content: "\f054";
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 10px;
|
||||||
|
font-size: .58em;
|
||||||
|
line-height: 1.556em;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion>input[type="checkbox"]:checked~.handle label:before {
|
||||||
|
content: "\f078";
|
||||||
|
}
|
|
@ -15,8 +15,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid {
|
.grid {
|
||||||
width: 120vh;
|
width: 85vh;
|
||||||
height: 95vh;
|
height: 85vh;
|
||||||
|
margin: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
52
backend/static/style/state.css
Normal file
52
backend/static/style/state.css
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
.connected::before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
float: left;
|
||||||
|
margin: 0 -20px 0 0;
|
||||||
|
font-family: 'fontawesome';
|
||||||
|
content: "\f1eb";
|
||||||
|
transform: translate(-30px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.waiting::before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
float: left;
|
||||||
|
margin: 0 -20px 0 0;
|
||||||
|
font-family: 'fontawesome';
|
||||||
|
content: "\f084";
|
||||||
|
transform: rotate(180deg) translate(27px, -7px) scaleX(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.reconnecting::before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
float: left;
|
||||||
|
margin: 0 -20px 0 0;
|
||||||
|
font-family: 'fontawesome';
|
||||||
|
content: "\f0e7";
|
||||||
|
transform: translate(-22px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.players {
|
||||||
|
margin: 10px 10px 10px 50px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.winner::before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
float: left;
|
||||||
|
margin: 0 -20px 0 0;
|
||||||
|
font-family: 'fontawesome';
|
||||||
|
content: "\f091";
|
||||||
|
transform: translate(-30px, 0px);
|
||||||
|
}
|
|
@ -20,12 +20,12 @@ body {
|
||||||
right: 25px;
|
right: 25px;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
|
||||||
background-color: #ff7f00;
|
background-color: #ff7f00;
|
||||||
mask-image: url("refresh.svg");
|
mask-image: url("refresh.svg");
|
||||||
-webkit-mask-image: url("refresh.svg");
|
-webkit-mask-image: url("refresh.svg");
|
||||||
animation: spin 2s linear infinite;
|
animation: spin 2s linear infinite;
|
||||||
animation-play-state: paused;
|
animation-play-state: paused;
|
||||||
|
z-index: 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.refresh:hover {
|
.refresh:hover {
|
||||||
|
@ -34,12 +34,15 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
100% {transform: rotate(1turn); }
|
100% {
|
||||||
|
transform: rotate(1turn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.lobby_wrapper {
|
.lobby_wrapper {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
position: relative;;
|
position: relative;
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lobby {
|
.lobby {
|
||||||
|
@ -48,7 +51,7 @@ body {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
height: 100%;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input_container {
|
.input_container {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
{% extends "base" %}
|
{% extends "base" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<link rel="stylesheet" href="/style/collapsable.css">
|
||||||
|
<link rel="stylesheet" href="/style/state.css">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
|
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="lobby_wrapper">
|
<div class="lobby_wrapper">
|
||||||
<div class="refresh" onclick="refresh_state()"></div>
|
<div class="refresh" onclick="refresh_state()"></div>
|
||||||
<div id="lobby" class="lobby">
|
<div id="lobby" class="lobby"></div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="creator">
|
<div class="creator">
|
||||||
<h1>Start new game</h1>
|
<h1>Start new game</h1>
|
||||||
|
|
|
@ -1,14 +1,26 @@
|
||||||
{% for state in games %}
|
{% for state in games %}
|
||||||
<div class="game_state">
|
<section class="accordion">
|
||||||
<div class="info">
|
<input type="checkbox" name="collapse" id="handle_{{loop.index}}">
|
||||||
<p>{{state.name}}</p>
|
<h2 class="handle">
|
||||||
{% if state.finished %}<p>Finished</p> {% endif %}
|
<label for="handle_{{loop.index}}">
|
||||||
{% if state.turns %}<p>Turns: {{ state.turns }} </p> {% endif %}
|
<span>{{state.name}} ({{state.map}})</span>
|
||||||
</div>
|
<span style="float: right">{% if state.type == "Finished" %}Done{% else %}{{ state.connected }}/{{state.total}}{% endif %}</span>
|
||||||
|
</label>
|
||||||
|
</h2>
|
||||||
|
<div class="content">
|
||||||
|
{% if state.type == "Playing" %}
|
||||||
<div class="players">
|
<div class="players">
|
||||||
{% for player in state.players %}
|
{% for player in state.players %}
|
||||||
<p>{{ player }}</p>
|
<p class="{% if player.waiting %}waiting {% endif %}{% if player.connected %}connected {% endif %}{% if player.reconnecting %}reconnecting {% endif %}">{{ player.value }}</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% else %}
|
||||||
|
<div class="players">
|
||||||
|
{% for player in state.players %}
|
||||||
|
<p class="{% if player[1] %}winner{% endif %}">{{ player[0] }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
|
|
||||||
{"nop":2,"name":"Dick But","map":"maps/hex.json","max_turns":2000}
|
{"nop":2,"name":"Bexit","map":"maps/hex.json","max_turns":200}
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
import requests, json, subprocess, os
|
import requests, json, subprocess, os
|
||||||
|
|
||||||
host = os.getenv("HOST") or "localhost:8000"
|
host = os.getenv("HOST") or "localhost:8000"
|
||||||
|
|
||||||
headers = {'content-type': 'application/json'}
|
headers = {'content-type': 'application/json'}
|
||||||
|
|
||||||
r = requests.post(f"http://{host}/lobby", data=open('game_start.json').read(), headers=headers)
|
try:
|
||||||
data = r.json()
|
r = requests.post(f"https://{host}/lobby", data=open('game_start.json').read(), headers=headers)
|
||||||
|
data = r.json()
|
||||||
|
except Exception:
|
||||||
|
r = requests.post(f"http://{host}/lobby", data=open('game_start.json').read(), headers=headers)
|
||||||
|
data = r.json()
|
||||||
|
|
||||||
processes = []
|
processes = []
|
||||||
|
|
||||||
for player in data["players"]:
|
for player in data["players"]:
|
||||||
|
|
|
@ -15,10 +15,9 @@ def execute(cmd):
|
||||||
raise subprocess.CalledProcessError(return_code, cmd)
|
raise subprocess.CalledProcessError(return_code, cmd)
|
||||||
|
|
||||||
def connect(host, port, id):
|
def connect(host, port, id):
|
||||||
print(host, port)
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
s.connect((host, port))
|
s.connect((host, port))
|
||||||
s.sendall(f"{id.strip()}\n".encode("utf8"))
|
s.sendall(f"{json.dumps(id)}\n".encode("utf8"))
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def handle_input(it, socket):
|
def handle_input(it, socket):
|
||||||
|
@ -33,11 +32,13 @@ def main():
|
||||||
help='What host to connect to')
|
help='What host to connect to')
|
||||||
parser.add_argument('--port', '-p', default=6666, type=int,
|
parser.add_argument('--port', '-p', default=6666, type=int,
|
||||||
help='What port to connect to')
|
help='What port to connect to')
|
||||||
|
parser.add_argument('--name', '-n', default="Silvius",
|
||||||
|
help='Who are you?')
|
||||||
parser.add_argument('arguments', nargs=argparse.REMAINDER,
|
parser.add_argument('arguments', nargs=argparse.REMAINDER,
|
||||||
help='How to run the bot')
|
help='How to run the bot')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
sock = connect(args.host, args.port, args.id)
|
sock = connect(args.host, args.port, {"id": int(args.id), "name": args.name})
|
||||||
f = sock.makefile("rw")
|
f = sock.makefile("rw")
|
||||||
|
|
||||||
it = execute(args.arguments)
|
it = execute(args.arguments)
|
||||||
|
@ -48,6 +49,7 @@ def main():
|
||||||
line = f.readline()
|
line = f.readline()
|
||||||
content = "Nothing"
|
content = "Nothing"
|
||||||
while line:
|
while line:
|
||||||
|
print(line)
|
||||||
content = json.loads(line)
|
content = json.loads(line)
|
||||||
if content["type"] == "game_state":
|
if content["type"] == "game_state":
|
||||||
stdin.write(json.dumps(content["content"])+"\n")
|
stdin.write(json.dumps(content["content"])+"\n")
|
||||||
|
|
Loading…
Reference in a new issue