Compare commits

..

No commits in common. "master" and "v0.3.2" have entirely different histories.

32 changed files with 436 additions and 1193 deletions

View file

@ -2,18 +2,8 @@ cmake_minimum_required( VERSION 2.8.7 )
# Set version information
set( TTRTS_VERSION_MAJOR 0 )
set( TTRTS_VERSION_MINOR 4 )
set( TTRTS_VERSION_PATCH 0 )
# Set defaults for ttrts variables
set( TTRTS_MAPS "/usr/local/share/ttrts/maps/" )
set( TTRTS_GAMES "/tmp/" )
set( TTRTS_PORT 11715 )
# define these defaults in code
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTTRTS_MAPS=${TTRTS_MAPS}" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTTRTS_GAMES=${TTRTS_GAMES}" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTTRTS_PORT=${TTRTS_PORT}" )
set( TTRTS_VERSION_MINOR 3 )
set( TTRTS_VERSION_PATCH 2 )
# Use c++1y (14)
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++1y" )
@ -36,7 +26,7 @@ install( FILES scripts/ttrts_complete DESTINATION /etc/bash_completion.d/ )
# Run the gen_usage script to generate our usage header
add_custom_target(
ttrts-gen-manpage ALL
${CMAKE_SOURCE_DIR}/scripts/gen_manpage.sh "${TTRTS_VERSION_MAJOR}" "${TTRTS_VERSION_MINOR}" "${TTRTS_VERSION_PATCH}" "ttrts.6" "${CMAKE_SOURCE_DIR}/source/README.md"
${CMAKE_SOURCE_DIR}/scripts/gen_manpage.sh "${TTRTS_VERSION_MAJOR}" "${TTRTS_VERSION_MINOR}" "${TTRTS_VERSION_PATCH}" "ttrts.6" "${CMAKE_SOURCE_DIR}/source/client/README.md"
)
# Install the ttrts man page
@ -51,4 +41,9 @@ endif()
install( FILES "${CMAKE_BINARY_DIR}/ttrts.6" DESTINATION ${MANPAGE_LOC} )
# Subprojects
add_subdirectory( source )
add_subdirectory( source/ttrts )
add_subdirectory( source/client )
# Auxhilary binaries
add_subdirectory( source/test )
add_subdirectory( source/gen )

View file

@ -31,14 +31,6 @@ TTRTS is from the ground up designed to be a fun way to practice programming. An
-----------------------------------------------------------
## Changelog
#### v0.4.0
* Updated with network functionality
* Game can now be hosted with ttrts --server option
* Server can be connected to with ttrts --client
* Updated command line interface with new launcher script
* map file must now be specified with --map=FILE
* Slight refactor of libraries to account for new run targets
#### v0.3.2
* Fix bug when loading map files with walls
* Fix ttrts on OSX

View file

@ -238,13 +238,6 @@ sub PrintGameFromGamestateString
$map[$invalidPos[0]][$invalidPos[1]] = "~";
}
# Fill with walls
foreach my $wall ( $info[8] =~ /\[(\d+,\d+)\]/g )
{
$wall =~ /(\d+),(\d+)/;
$map[$1][$2] = "|";
}
# Fill with units
for my $unit (@units)
{

View file

@ -16,7 +16,7 @@ if [[ $? != 0 ]]; then
exit
fi
echo "TTRTS: Performing install"
echo "Performing install"
sudo make install
if [[ $? != 0 ]]; then
echo "TTRTS: Install failed, check output"

View file

@ -1,13 +1,10 @@
#! /bin/bash
# Used to a man page from markdown
FILE="$4"
TEMP="$FILE.tmp"
echo ".\" Man page for the ttrts project" > $4
echo ".\" this man page is auto-generated, do not edit directly" >> $4
echo ".\" Man page for the ttrts project" > $TEMP
echo ".\" this man page is auto-generated, do not edit directly" >> $TEMP
echo ".TH TTRTS\ v$1.$2.$3 6 $(date +%Y-%m-%d) http://mdiluz.github.io/ttrts/" >> $TEMP
echo ".TH TTRTS\ v$1.$2.$3 6 $(date +%Y-%m-%d) http://mdiluz.github.io/ttrts/" >> $4
# NOTE: For the OSX version of sed we use -E, which on linux appears be an undocumented switch for -r
# we also have to use [A-Za-z] instead of \w for some reason
@ -35,10 +32,4 @@ cat "$5" \
| sed -E 's/-----+//g' \
| sed -E 's/`(.*)`/\\fB\1\\fR/g' \
| sed -E 's/MAPFILE/\\fImapfile\\fR/g' \
| sed -E 's/HOSTNAME/\\fIhostname\\fR/g' \
| sed -E 's/ ttrts -/ ttrts \\-/g' >> $TEMP
if [ ! -e $FILE ] || [ ! -z "$( diff $FILE $TEMP )" ]; then
mv -f $TEMP $FILE
fi
| sed -E 's/ ttrts -/ ttrts \\-/g' >> $4

View file

@ -1,18 +1,10 @@
#! /bin/bash
# Used to generate usage text from markdown
FILE="$1"
TEMP="${FILE}_tmp"
cat README.md \
| sed -E 's/^#+ //g' \
| sed -E 's/^ /\\t/g' \
| sed -E 's/^ /\\t/g' \
| sed -E 's/^/\"/' \
| sed -E 's/$/\\n\"/' \
> $TEMP
# If no difference
if [ ! -e $FILE ] || [ ! -z "$( diff $TEMP $FILE )" ]; then
mv -f $TEMP $FILE
fi
> $1

View file

@ -10,9 +10,4 @@ HEADER="// Auto generated ttrts version header
#endif //_TTRTS_VERSION_H_"
echo "$HEADER" > "version.h.tmp"
# If no difference
if [ ! -e version.h ] || [ ! -z "$( diff version.h version.h.tmp )" ]; then
mv -f version.h.tmp version.h
fi
echo "$HEADER" > "version.h"

View file

@ -5,11 +5,11 @@ test ! -z TTRTS_MAPS && TTRTS_MAPS=/usr/share/ttrts/maps/
have ttrts &&
function _ttrts
{
commandnames="--server --client --host= --host=localhost "
commandnames=""
for filename in ${TTRTS_MAPS}/*
do
map="${filename##*/}"
commandnames+="--map=$map "
commandnames+="$map "
done
local cur prev

View file

@ -1,13 +0,0 @@
# Main libraries
add_subdirectory( ttrts )
add_subdirectory( system )
# Main binaries
add_subdirectory( launcher )
add_subdirectory( client )
add_subdirectory( server )
add_subdirectory( local )
# Auxhilary binaries
add_subdirectory( test )
add_subdirectory( gen )

View file

@ -1,121 +1,13 @@
# NAME
ttrts - Tiny Terminal RTS
# Targets
### client
Main TTRTS binary, runs from the command line and acts as host for games
# SYNOPSIS
ttrts [--server] [--client] [--host=HOSTNAME] [--map=MAPFILE]
### test
Test binary, to be compiled and run to test various functionality
# DESCRIPTION
ttrts is a tiny terminal based RTS that uses text files as order lists to control the units
### gen
Binary to generate example map files
This means that any user, program or cat that can read and write to text files can play the game
# RETURN VALUE
ttrts will return -1 on error, or the winning player on completion
# OPTIONS
--server - Run in server mode, must provide a map file
--client - Run in client mode, must provide a hostname for a running server
--map=MAPFILE - File to read in the initial game state. Local or in ${TTRTS_MAPS}
--host=HOSTNAME - Name of host to connect to in client mode
# USAGE
When invoked, ttrts will set up the game in a directory within ${TTRTS_GAMES} by the name of the map
The files in this directory can be read and interpreted by human, robot or cat
ttrts will then await order files from each participant
Once all order files have been received ttrts will calculate the turn and output a new gamestate file
In server and client mode, the client will output and read in these files while the server simulates the game
This process repeats until the game is over
# ENVIRONMENT
${TTRTS_MAPS} - Map file lookup location, defaults to `/usr/share/ttrts/maps/`
${TTRTS_GAMES} - Game directory for I/O, defaults to `/tmp/`
-----------------------------------------------------------
# FILES
`/usr/share/ttrts/maps/` holds a sample set of maps
## Gamestate File
Turn_{TURNNUMBER}.txt
### Contents
===== ttrts v{MAJOR}.{MINOR}.{PATCH} =====
NAME:{GAMENAME}
SIZE:[{X},{Y}]
TURN:{TURNNUMBER}
WALL:[{X},{Y}][{X},{Y}][{X},{Y}]...{repeat for all walls}
~~~~
UNIT:{ID} pl:{PLAYER} vs:{VIS} dr:{DIR(NESW)} ps:[{X},{Y}]
... {continue for all units}
END
## Order File
Player_{PLAYER_ID}_Turn_{TURN_NUMBER}.txt
### Contents
ORDER:{ORDER_CHAR} id:{UNIT_ID}
... {continue for all orders}
END
-----------------------------------------------------------
# SERVER/CLIENT
When in server or client mode, the game can be played across a network. If desired, a player could design an AI to act as a client instead of using the client mode and intermediary filesystem.
## Protocol
The server is accesible on port 11715
To perform the handshake the server will write to the socket with the format "player PLAYER_ID name GAME_NAME", it will expect this exact information to be written back to in reply.
Once handshake is performed, the server will write to the socket in the form of the Gamestate file as above.
The server will then wait for a new-line delimited and END terminated list of orders
This will be repeated until the game is over
-----------------------------------------------------------
# GAMEPLAY
The game takes place in a series of simultaneous turns on an arbitrarily sized 2D board
Each turn, the client outputs a gamestate file and waits for an order file from each player
All commands are evaluated simultaneously with friendly fire enabled by default
The game is over when any of three conditions are met -
* All remaining units are controlled by a single player
* No units are left (draw)
* All units left are unable to move (draw)
# UNITS
Each unit occupies a single tile on the board, facing in a compass direction (NESW)
Units will only accept orders from their owner
Units can receive only a single order each turn
Units cannot occupy the same tile as other units/walls
# ORDERS
### F - Move unit [F]orward one space, leaving a wall
This wall will remain until the end of the game, blocking movement to that tile
Movement orders have no effect if impossible, eg.
* Attempting to move outside of map
* Attempting to move on to tile occupied by unit/wall
### L/R - Rotate unit [L]eft or [R]ight
Unit will rotate clockwise or counter-clockwise, this order cannot fail
### A - [A]ttack in straight line in front of unit
Attack will continue forward until unit can't progress, all units within the path of the attack are destroyed.
# Libraries
### ttrts
Implementation of the RTS rules and simulation

View file

@ -3,21 +3,40 @@
project( ttrts-client )
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
../system
${CMAKE_CURRENT_BINARY_DIR}
../maths
../ttrts
)
# Add the sources
set( SOURCES
client.cpp
main.cpp
)
# Set defaults for ttrts maps and games
set( TTRTS_MAPS "/usr/local/share/ttrts/maps/" )
set( TTRTS_GAMES "/tmp/" )
# define these defaults in code
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTTRTS_MAPS=${TTRTS_MAPS}" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTTRTS_GAMES=${TTRTS_GAMES}" )
# Add the executable
add_executable( ${PROJECT_NAME} ${SOURCES} )
# Set our output name to ttrts
set_target_properties( ${PROJECT_NAME} PROPERTIES OUTPUT_NAME ttrts )
# dependent on main ttrts libary
target_link_libraries( ${PROJECT_NAME} ttrts ttrts-system )
target_link_libraries( ${PROJECT_NAME} ttrts )
# Installation target
install( TARGETS ${PROJECT_NAME} DESTINATION bin )
# Run the gen_usage script to generate our usage header
add_custom_target(
ttrts-client-usage
cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_SOURCE_DIR}/scripts/gen_usage.sh "${CMAKE_CURRENT_BINARY_DIR}/usage.h"
)
add_dependencies(${PROJECT_NAME} ttrts-client-usage)

98
source/client/README.md Normal file
View file

@ -0,0 +1,98 @@
# NAME
ttrts - Tiny Terminal RTS
# SYNOPSIS
ttrts MAPFILE
# DESCRIPTION
ttrts is a tiny terminal based RTS that uses text files as order lists to control the units
This means that any user, program or cat that can read and write to text files can play the game
# RETURN VALUE
ttrts will return -1 on error, or the winning player on completion
# OPTIONS
MAPFILE - File to read in the initial game state. Local or in ${TTRTS_MAPS}
# USAGE
When invoked, ttrts will set up the game in a directory within ${TTRTS_GAMES} by the name of the map
The files in this directory can be read and interpreted by human, robot or cat
ttrts will then await order files from each participant
Once all order files have been received ttrts will calculate the turn and output a new gamestate file
This process repeats until the game is over
# ENVIRONMENT
${TTRTS_MAPS} - Map file lookup location, defaults to `/usr/share/ttrts/maps/`
${TTRTS_GAMES} - Game directory for I/O, defaults to `/tmp/`
-----------------------------------------------------------
# FILES
`/usr/share/ttrts/maps/` holds a sample set of maps
## Gamestate File
Turn_{TURNNUMBER}.txt
### Contents
===== ttrts v{MAJOR}.{MINOR}.{PATCH} =====
NAME:{GAMENAME}
SIZE:[{X},{Y}]
TURN:{TURNNUMBER}
WALL:[{X},{Y}][{X},{Y}][{X},{Y}]...{repeat for all walls}
~~~~
UNIT:{ID} pl:{PLAYER} vs:{VIS} dr:{DIR(NESW)} ps:[{X},{Y}]
... {continue for all units}
END
## Order File
Player_{PLAYER_ID}_Turn_{TURN_NUMBER}.txt
### Contents
ORDER:{ORDER_CHAR} id:{UNIT_ID}
... {continue for all orders}
END
-----------------------------------------------------------
# GAMEPLAY
The game takes place in a series of simultaneous turns on an arbitrarily sized 2D board
Each turn, the client outputs a gamestate file and waits for an order file from each player
All commands are evaluated simultaneously with friendly fire enabled by default
The game is over when any of three conditions are met -
* All remaining units are controlled by a single player
* No units are left (draw)
* All units left are unable to move (draw)
# UNITS
Each unit occupies a single tile on the board, facing in a compass direction (NESW)
Units will only accept orders from their owner
Units can receive only a single order each turn
Units cannot occupy the same tile as other units/walls
# ORDERS
### F - Move unit [F]orward one space, leaving a wall
This wall will remain until the end of the game, blocking movement to that tile
Movement orders have no effect if impossible, eg.
* Attempting to move outside of map
* Attempting to move on to tile occupied by unit/wall
### L/R - Rotate unit [L]eft or [R]ight
Unit will rotate clockwise or counter-clockwise, this order cannot fail
### A - [A]ttack in straight line in front of unit
Attack will continue forward until unit can't progress, all units within the path of the attack are destroyed.

View file

@ -1,69 +0,0 @@
#include <iostream>
#include "net.h"
#include "game.h"
#include "error.h"
#include "filesystem.h"
int main(int argc, char* argv[])
{
// must provide information
if (argc < 2)
fatal_error("Usage: ttrts-client HOST");
std::string hostname = argv[1];
sockaddr_in serv_addr; // Server address
memset(&serv_addr,0, sizeof(serv_addr));
// Set the server to AF_INET
serv_addr.sin_family = AF_INET;
// Set our server address port to the port number provided
serv_addr.sin_port = htons(TTRTS_PORT);
std::cout<<"TTRTS: Connecting to "<<hostname<<std::endl;
int sockfd = ConnectToHostServer(hostname, serv_addr);
unsigned int player;
std::string gameNameString;
// Handshake with server to fetch player and gamestring
PerformClientHandshake(sockfd, player, gameNameString);
// output our information
player_t myPlayer = (player_t)player;
std::cout<<"TTRTS: I am player "<<std::to_string((int)myPlayer)<<std::endl;
std::cout<<"TTRTS: Game is "<<gameNameString<<std::endl;
// Clean out the games dir
CreateAndCleanGameDir(gameNameString);
// Buffer for messages
char buffer[1028];
memset(buffer,0,sizeof(buffer));
int n = 0; // return value for read and write calls
while ( n >= 0 )
{
std::cout<<"TTRTS: Waiting for gamestate"<<std::endl;
std::string gamestate = WaitForGamestateMessage(sockfd);
// Output the gamestate file for this game
CTTRTSGame thisGame = GetGameFromString(gamestate);
OutputGameStateFile(thisGame);
// If game over, exit with out winning player and message
if(thisGame.GameOver())
exit( OutputGameEnd(thisGame) );
// Get the order file for this turn`
std::string orders = GetOrdersFromPlayerFile(thisGame,myPlayer);
std::cout<<"TTRTS: Sending orders"<<std::endl;
std::cout<<orders<<std::endl;
// Write to the socket with the buffer
n = SendOrdersToServer(sockfd, orders);
}
return 0;
}

277
source/client/main.cpp Normal file
View file

@ -0,0 +1,277 @@
#include <iostream>
#include <fstream>
#include <chrono>
#include <thread>
#include <sys/stat.h>
#include <stdio.h>
#include <stdbool.h>
#include <formatters.h>
#include <unistd.h>
#include <stdlib.h>
#include "game.h"
#define STRINGIFY(x) _STRINGIFY(x)
#define _STRINGIFY(x) #x
static const char* sk_usage =
#include "usage.h"
;
// Verbose mode
static const bool env_verbose = getenv("VERBOSE");
// time for waiting between file stats
static const std::chrono::milliseconds sk_waitTime = std::chrono::milliseconds(100);
// Check if a file exists
inline bool FileExists( const std::string& name )
{
struct stat buffer;
return (stat (name.c_str(), &buffer) == 0);
}
// Wait for a file to exist
inline void WaitForFile( const std::string& name, const std::chrono::milliseconds& time )
{
while( !FileExists(name) ) std::this_thread::sleep_for(time);
}
bool OutputGameStateFile(CTTRTSGame &game, std::string &gameDir)
{
char turnFileName[128];
snprintf(turnFileName,128,"%s/Turn_%i.txt",gameDir.c_str(),game.GetTurn());
std::ofstream turnFile(turnFileName, std::ios_base::trunc); // truncate to overwrite if a file exists
if ( turnFile.bad() )
{
return false;
}
// Output the turn description
std::string turnDescriptor = GetStringFromGame(game);
turnFile<<turnDescriptor;
turnFile.close();
return true;
}
// Main program entry point
int main(int argc, char* argv[])
{
// If no args, print usage
if ( argc == 1 )
{
std::cout<<sk_usage<<std::endl;
return -1;
}
// Attempt to open the game file
std::string gameFile = argv[1];
// Default for maps
std::string ttrts_maps_dir = STRINGIFY(TTRTS_MAPS);
if( getenv("TTRTS_MAPS") )
{
ttrts_maps_dir = getenv("TTRTS_MAPS");
// Additional trailing slash
if( ttrts_maps_dir.back() != '/' )
ttrts_maps_dir += "/";
}
// Default for games
std::string ttrts_games_dir = STRINGIFY(TTRTS_GAMES);
if( getenv("TTRTS_GAMES") )
{
ttrts_games_dir = getenv("TTRTS_GAMES");
// Additional trailing slash
if( ttrts_games_dir.back() != '/' )
ttrts_games_dir += "/";
}
// If file path is not local path and file doesn't exist
if( gameFile.find("/") == std::string::npos
&& access( gameFile.c_str(), F_OK ) == -1 )
{
gameFile = ttrts_maps_dir + gameFile;
}
// If still not good
if( access( gameFile.c_str(), F_OK ) == -1 )
{
std::cerr<<"Error: "<<gameFile<<" file not found"<<std::endl;
return -1;
}
std::ifstream file(gameFile);
std::cout<<"Launching TTRTS with "<<gameFile<<std::endl;
std::string gameDescriptor;
// Reserve the string needed up front
file.seekg(0, std::ios::end);
gameDescriptor.reserve(file.tellg());
file.seekg(0, std::ios::beg);
// Grab the string from the file
gameDescriptor.assign((std::istreambuf_iterator<char>(file)),std::istreambuf_iterator<char>());
if( gameDescriptor.size() == 0 )
{
std::cerr<<"Error: failed to read in any information from "<<gameFile<<std::endl;
return -1;
}
// Create the game
CTTRTSGame game = GetGameFromString(gameDescriptor);
// Grab the players involved
auto players = game.GetPlayers();
// Current game directory
std::string gameDir = ttrts_games_dir + game.GetName();
// Empty the current game directory
struct stat info;
int ret = stat( gameDir.c_str(), &info );
if( ret == 0 && info.st_mode & S_IFDIR )
{
std::cout<< gameDir << " game directory already exists"<<std::endl;
std::cout<<"Confirm to delete contents [y/N] ";
std::string input;
std::cin>>input;
if( !input.size() || std::tolower(input[0]) != 'y' )
{
std::cerr<<"Aborting..."<<std::endl;
return -1;
}
}
else if ( ret == 0 )
{
std::cerr<< gameDir << " exists but is not directory \nAborting..."<<std::endl;
return -1;
}
// Create the game directory
char cmd2[128];
snprintf(cmd2,128, "test -d %s || mkdir %s",gameDir.c_str(),gameDir.c_str());
if( system(cmd2) == -1)
{
std::cerr<<"Error: Failed to create the game directory"<<std::endl;
return -1;
}
// Clean out the game directory
char cmd1[128];
snprintf(cmd1,128, "rm -rf %s/*",gameDir.c_str());
if ( system(cmd1) == -1 )
{
std::cerr<<"Error: Failed to clean the game directory"<<std::endl;
return -1;
}
// While the game isn't finished
while ( ! game.GameOver() )
{
std::cout<<"Starting turn "<<game.GetTurn()<<std::endl;
// Create a turn file
if( !OutputGameStateFile(game, gameDir))
{
std::cerr<<"Error: Failed to output new turn file" << std::endl;
return 1;
}
// Wait for order files
for( player_t player : players)
{
// Construct the player order filename
char playerOrderFileName[128];
snprintf(playerOrderFileName, 128, "%s/Player_%i_Turn_%i.txt", gameDir.c_str(), (int) player, game.GetTurn());
// Wait for the player order file to be created
std::cout<<"Waiting for "<< playerOrderFileName <<std::endl;
bool hasOrderFile = false;
while(!hasOrderFile)
{
WaitForFile(playerOrderFileName,sk_waitTime); // Wait for the file
// File must have END
// Method taken from http://stackoverflow.com/questions/11876290/c-fastest-way-to-read-only-last-line-of-text-file
std::ifstream turnFile(playerOrderFileName);
turnFile.seekg(-1,std::ios_base::end);
// Loop back from the end of file
bool keepLooping = true;
while(keepLooping) {
char ch;
turnFile.get(ch); // Get current byte's data
if((int)turnFile.tellg() <= 1) { // If the data was at or before the 0th byte
turnFile.seekg(0); // The first line is the last line
keepLooping = false; // So stop there
}
else if(ch == '\n') { // If the data was a newline
keepLooping = false; // Stop at the current position.
}
else { // If the data was neither a newline nor at the 0 byte
turnFile.seekg(-2,std::ios_base::cur); // Move to the front of that data, then to the front of the data before it
}
}
// Grab this line
std::string lastLine;
std::getline(turnFile,lastLine);
if(lastLine == "END")
hasOrderFile = true;
}
std::ifstream turnFile(playerOrderFileName);
// Reserve the full order string
std::string orders;
turnFile.seekg(0, std::ios::end);
orders.reserve(turnFile.tellg());
turnFile.seekg(0, std::ios::beg);
// Grab the string from the file
orders.assign((std::istreambuf_iterator<char>(turnFile)),std::istreambuf_iterator<char>());
// Issue the orders to the game
if( game.IssueOrders(player, orders) )
std::cerr<<"Warning: Orders for player "<<(int) player <<" failed to correctly parse"<<std::endl;
}
// Simulate turn
std::cout<<"Simulating this turn!"<<std::endl;
if ( game.SimulateToNextTurn() )
{
std::cerr << "Error: Failed to simulate for turn "<<game.GetTurn()<<std::endl;
return -1;
}
}
// Output final gamestate
OutputGameStateFile(game, gameDir);
// Get the winning player
player_t winningPlayer = game.GetWinningPlayer();
// Print the winner!
if ( winningPlayer != player_t::NUM_INVALID )
{
std::cout<<"Game over! Winner:"<<(int) winningPlayer <<std::endl;
}
else
{
std::cout<<"Game over! It was a draw!"<<std::endl;
}
return (int)winningPlayer;
};

View file

@ -3,7 +3,8 @@
project( ttrts-gen )
include_directories(
../ttrts
../ttrts
../maths
)
set( SOURCES

View file

@ -33,7 +33,7 @@ int main()
//------
{
CTTRTSGame game(6, 6);
game.SetName("Tiny2Player");
game.SetName("Tiny2player");
AddUnitToGame( player_t::Red, '<', uvector2(4, 2), game);
AddUnitToGame( player_t::Red, '<', uvector2(4, 4), game);

View file

@ -1,6 +0,0 @@
# ====================== ttrts =======================
# Project name
project( ttrts-perl-launch )
# Add bash completion to install
install( PROGRAMS ttrts.pl DESTINATION bin RENAME ttrts )

View file

@ -1,44 +0,0 @@
#! /usr/bin/perl
# Main ttrts launcher script
use strict;
use warnings;
use 5.0;
use Getopt::Long qw(GetOptions);
sub print_usage
{
print "Unknown option: @_\n" if ( @_ );
print "Usage: ttrts [--server] [--client] [--host=HOSTNAME] [--map=MAPFILE]\n";
exit;
}
our $VERBOSE = $ENV{"VERBOSE"};
our $server;
our $client;
our $host;
our $map;
print_usage() if ( @ARGV < 1 or
!GetOptions(
'client' => \$client,
'server' => \$server,
'host=s' => \$host,
'map=s' => \$map,
) );
# Verify we have the right parameters
print "Cannot run as both client and server\n" and exit if $client and $server;
print "Client requires hostname\n" and exit if $client and not $host;
print "Server requires mapfile\n" and exit if $server and not $map;
print "Running locally requires mapfile\n" and exit if not $server and not $client and not $map;
# Run client, server or local
my $res = -1;
$res = system("ttrts-client $host") if $client and $host;
$res = system("ttrts-server $map") if $server and $map;
$res = system("ttrts-local $map") if not $server and not $client and $map;
return $res

View file

@ -1,23 +0,0 @@
# ====================== ttrts =======================
# Project name
project( ttrts-local )
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
../system
../ttrts
)
# Add the sources
set( SOURCES
local.cpp
)
# Add the executable
add_executable( ${PROJECT_NAME} ${SOURCES} )
# dependent on main ttrts libary
target_link_libraries( ${PROJECT_NAME} ttrts ttrts-system pthread )
# Installation target
install( TARGETS ${PROJECT_NAME} DESTINATION bin )

View file

@ -1,62 +0,0 @@
#include "game.h"
#include "filesystem.h"
#include "error.h"
#include "net.h"
#include <iostream>
// =====================================================================================================================
int main(int argc, char* argv[])
{
// must provide information
if (argc < 2)
fatal_error("Usage: ttrts-local MAPFILE");
std::string gamefile = argv[1];
std::cout<<"TTRTS: Launching with "<<gamefile<<std::endl;
CTTRTSGame game = GetGameFromFile(gamefile);
// Grab the players involved
auto players = game.GetPlayers();
// Default for games
std::string ttrts_games_dir = getGamesDir();
// Empty the current game directory
if ( CreateAndCleanGameDir(game.GetName()) < 0)
return -1;
// While the game isn't finished
while ( ! game.GameOver() )
{
std::cout<<"TTRTS: Starting turn "<<game.GetTurn()<<std::endl;
// Create a turn file
if( !OutputGameStateFile(game))
fatal_error("Error: Failed to output new turn file");
// Wait for order files
for( player_t player : players)
{
// Construct the player order filename
std::string orders = GetOrdersFromPlayerFile(game, player);
// Issue the orders to the game
if( game.IssueOrders(player, orders) )
std::cerr<<"Warning: Orders for player "<<(int) player <<" failed to correctly parse"<<std::endl;
}
// Simulate turn
std::cout<<"TTRTS: Simulating this turn!"<<std::endl;
if ( game.SimulateToNextTurn() )
fatal_error("Failed to simulate game turn");
}
// Output final gamestate
OutputGameStateFile(game);
return OutputGameEnd( game );
}

View file

@ -1,23 +0,0 @@
# ====================== ttrts =======================
# Project name
project( ttrts-server )
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
../system
../ttrts
)
# Add the sources
set( SOURCES
server.cpp
)
# Add the executable
add_executable( ${PROJECT_NAME} ${SOURCES} )
# dependent on main ttrts libary
target_link_libraries( ${PROJECT_NAME} ttrts ttrts-system pthread )
# Installation target
install( TARGETS ${PROJECT_NAME} DESTINATION bin )

View file

@ -1,98 +0,0 @@
#include "error.h"
#include <thread>
#include <vector>
#include <iostream>
#include <mutex>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include "net.h"
#include "filesystem.h"
void RunServerForGame(CTTRTSGame &game)
{
std::cout<<"TTRTS: Setting up server"<<std::endl;
// Server side information
sockaddr_in serv_addr = GetLocalServerAddress();
// socket File descriptor
int sockfd = SetUpServerListeningSocket(serv_addr);
// Get information about the game
std::vector<player_t> players = game.GetPlayers();
unsigned int numClients = players.size();
auto player_iterator = players.begin();
// game mutex
std::mutex gameMutex;
// Set of clients
std::vector<ClientInfo> myClients;
std::cout<<"TTRTS: Waiting for "<<numClients<<" players"<<std::endl;
// Loop while we're connecting the clients
while ( myClients.size() < numClients )
{
// information for each client
ClientInfo clientInfo;
clientInfo.player = *player_iterator;
player_iterator++;
clientInfo = WaitForClientConnection(sockfd, game.GetName(), clientInfo);
// Add out client info to our list
myClients.push_back(clientInfo);
}
std::cout<<"TTRTS: All players connected"<< std::endl;
std::cout<<"TTRTS: Hit enter to begin...";
std::cin.ignore();
// Loop for each turn
while ( !game.GameOver() )
{
// Send data to clients
std::cout<<"TTRTS: Broadcasting Gamestate"<< std::endl;
SendGamestateToClients(myClients, game, gameMutex);
// Wait for orders from clients
std::cout<<"TTRTS: Waiting for orders from players"<< std::endl;
WaitForOrdersFromClients(myClients, game, gameMutex);
std::cout<<"TTRTS: All orders recieved, simulating turn"<< std::endl;
// Step to the next turn
gameMutex.lock();
game.SimulateToNextTurn();
gameMutex.unlock();
}
// Send final state to all the clients
SendGamestateToClients(myClients, game, gameMutex);
}
int main(int argc, char* argv[])
{
// argv[1] needs to be a valid game file
if( argc < 2 )
fatal_error("Usage: ttrts-server MAPFILE");
// Set up game
CTTRTSGame game = GetGameFromFile(argv[1]);
if(game.GetNumUnits() == 0)
fatal_error("game not valid");
RunServerForGame(game);
// Return winning player and output game end
return OutputGameEnd(game);
}

View file

@ -1,21 +0,0 @@
cmake_minimum_required(VERSION 2.8.7)
# Main ttrts library
project( ttrts-system )
# Include the maths
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
../ttrts
)
# Add our sources
set( SOURCES
net.cpp
filesystem.cpp
)
# Add this library
add_library( ${PROJECT_NAME} ${SOURCES} )
target_link_libraries( ${PROJECT_NAME} ttrts pthread )

View file

@ -1,25 +0,0 @@
#ifndef _TTRTS_ERROR_H_
#define _TTRTS_ERROR_H_
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
//======================================================================================================================
// Error functions
// For local fatal errors
inline void fatal_error(const char *msg)
{
std::cerr<<msg<<std::endl;
exit(1);
}
// For system fatal errors (ie. functions that set errno)
inline void fatal_perror(const char *msg)
{
perror(msg);
exit(1);
}
#endif

View file

@ -1,248 +0,0 @@
#include "filesystem.h"
#include "net.h"
#include "error.h"
#include <iostream>
#include <fstream>
#include <chrono>
#include <thread>
#include <sys/stat.h>
#include <stdio.h>
#include <stdbool.h>
#include <formatters.h>
#include <unistd.h>
#include <stdlib.h>
// =====================================================================================================================
// time for waiting between file stats
static const std::chrono::milliseconds sk_waitTime = std::chrono::milliseconds(100);
// Check if a file exists
bool FileExists( const std::string& name )
{
struct stat buffer;
return (stat (name.c_str(), &buffer) == 0);
}
// Wait for a file to exist
void WaitForFile( const std::string& name, const std::chrono::milliseconds& time )
{
while( !FileExists(name) ) std::this_thread::sleep_for(time);
}
bool OutputGameStateFile(CTTRTSGame &game)
{
char turnFileName[128];
snprintf(turnFileName,128,"%s%s/Turn_%i.txt", getGamesDir().c_str(),game.GetName().c_str(),game.GetTurn());
std::ofstream turnFile(turnFileName, std::ios_base::trunc); // truncate to overwrite if a file exists
if ( turnFile.bad() )
{
return false;
}
// Output the turn description
std::string turnDescriptor = GetStringFromGame(game);
turnFile<<turnDescriptor;
turnFile.close();
return true;
}
std::string getMapsDir()
{
std::string maps = STRINGIFY(TTRTS_MAPS);
if( getenv("TTRTS_MAPS") )
{
maps = getenv("TTRTS_MAPS");
// Additional trailing slash
if( maps.back() != '/' )
maps += "/";
}
return maps;
}
std::string getGamesDir()
{
std::string dir = STRINGIFY(TTRTS_GAMES);
if( getenv("TTRTS_GAMES") )
{
dir = getenv("TTRTS_GAMES");
// Additional trailing slash
if( dir.back() != '/' )
dir += "/";
}
return dir;
}
CTTRTSGame GetGameFromFile( const std::string& filename )
{
std::string gamefile = filename;
// Default for maps
std::string ttrts_maps_dir = getMapsDir();
// If file path is not local path and file doesn't exist
if( gamefile.find("/") == std::string::npos
&& access( gamefile.c_str(), F_OK ) == -1 )
{
gamefile = ttrts_maps_dir + gamefile;
}
// If still not good
if( access( gamefile.c_str(), F_OK ) == -1 )
fatal_perror("Could not open game file");
std::ifstream file(gamefile);
std::string gameDescriptor;
// Reserve the string needed up front
file.seekg(0, std::ios::end);
gameDescriptor.reserve(file.tellg());
file.seekg(0, std::ios::beg);
// Grab the string from the file
gameDescriptor.assign((std::istreambuf_iterator<char>(file)),std::istreambuf_iterator<char>());
if( gameDescriptor.size() == 0 )
fatal_error("failed to read in any information from gamefile");
// Create the game
return GetGameFromString(gameDescriptor);
}
std::string GetOrdersFromPlayerFile(const CTTRTSGame &game, player_t &player)
{
std::string gameDir = getGamesDir();
char playerOrderFileName[128];
snprintf(playerOrderFileName, 128, "%s%s/Player_%i_Turn_%i.txt", gameDir.c_str(),game.GetName().c_str(),(int) player, game.GetTurn());
// Wait for the player order file to be created
std::clog<<"TTRTS: Waiting for "<< playerOrderFileName << std::endl;
bool hasOrderFile = false;
while(!hasOrderFile)
{
WaitForFile(playerOrderFileName,sk_waitTime); // Wait for the file
// File must have END
// Method taken from http://stackoverflow.com/questions/11876290/c-fastest-way-to-read-only-last-line-of-text-file
std::ifstream turnFile(playerOrderFileName);
turnFile.seekg(-1, std::ios_base::end);
// Loop back from the end of file
bool keepLooping = true;
while(keepLooping) {
char ch;
turnFile.get(ch); // Get current byte's data
if((int)turnFile.tellg() <= 1) { // If the data was at or before the 0th byte
turnFile.seekg(0); // The first line is the last line
keepLooping = false; // So stop there
}
else if(ch == '\n') { // If the data was a newline
keepLooping = false; // Stop at the current position.
}
else { // If the data was neither a newline nor at the 0 byte
turnFile.seekg(-2, std::ios_base::cur); // Move to the front of that data, then to the front of the data before it
}
}
// Grab this line
std::string lastLine;
getline(turnFile,lastLine);
if(lastLine == "END")
hasOrderFile = true;
}
std::ifstream turnFile(playerOrderFileName);
// Reserve the full order string
std::string orders;
turnFile.seekg(0, std::ios_base::end);
orders.reserve(turnFile.tellg());
turnFile.seekg(0, std::ios_base::beg);
// Grab the string from the file
orders.assign((std::istreambuf_iterator<char>(turnFile)), std::istreambuf_iterator<char>());
return orders;
}
int CreateAndCleanGameDir(const std::string& gameName)
{
std::string gameDir = getGamesDir()+gameName;
struct stat info;
int ret = stat( gameDir.c_str(), &info );
if( ret == 0 && info.st_mode & S_IFDIR )
{
std::cout<<"TTRTS: " << gameDir << " game directory already exists"<<std::endl;
std::cout<<"TTRTS: Confirm to delete contents [y/N] ";
std::string input;
std::cin>>input;
if( !input.size() || std::tolower(input[0]) != 'y' )
return -1;
}
else if ( ret == 0 )
{
fatal_error("TTRTS_GAMES exists but is not directory \nAborting...");
}
// Create the game directory
char cmd2[128];
snprintf(cmd2,128, "test -d %s || mkdir %s",gameDir.c_str(),gameDir.c_str());
if( system(cmd2) == -1)
fatal_error("Error: Failed to create the game directory");
// Clean out the game directory
char cmd1[128];
snprintf(cmd1,128, "rm -rf %s/*",gameDir.c_str());
if ( system(cmd1) == -1 )
fatal_error("Error: Failed to clean the game directory");
return 0;
}
int OutputGameEnd(const CTTRTSGame &game) {
std::cout<<"TTRTS: Game Over!"<< std::endl;
// Get the winning player
player_t winningPlayer = game.GetWinningPlayer();
// Print the winner!
if ( winningPlayer != player_t::NUM_INVALID )
{
std::cout<<"TTRTS: Winner:"<<(int) winningPlayer <<std::endl;
}
else
{
std::cout<<"TTRTS: It was a draw!"<<std::endl;
}
return (int)winningPlayer;
}
int OutputgameEnd(const CTTRTSGame &game) {
std::cout<<"TTRTS: Game Over!"<< std::endl;
// Get the winning player
player_t winningPlayer = game.GetWinningPlayer();
// Print the winner!
if ( winningPlayer != player_t::NUM_INVALID )
{
std::cout<<"TTRTS: Winner:"<<(int) winningPlayer <<std::endl;
}
else
{
std::cout<<"TTRTS: It was a draw!"<<std::endl;
}
return (int)winningPlayer;
}

View file

@ -1,29 +0,0 @@
#ifndef _TTRTS_FILESYSTEM_H_
#define _TTRTS_FILESYSTEM_H_
#include <string>
#include <chrono>
#include "game.h"
#define STRINGIFY(x) _STRINGIFY(x)
#define _STRINGIFY(x) #x
bool FileExists( const std::string& name );
void WaitForFile( const std::string& name, const std::chrono::milliseconds& time );
bool OutputGameStateFile(CTTRTSGame &game);
std::string GetOrdersFromPlayerFile(const CTTRTSGame &game, player_t &player);
CTTRTSGame GetGameFromFile( const std::string& file );
std::string getMapsDir();
std::string getGamesDir();
int runFromFilesystem(int argc, char* argv[]);
int CreateAndCleanGameDir(const std::string& gameName);
#endif

View file

@ -1,261 +0,0 @@
#include "net.h"
#include "error.h"
#include <netdb.h>
#include <iostream>
#include <thread>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void WaitForOrdersFromClient(const ClientInfo info, CTTRTSGame &game, std::mutex &mut)
{
char buffer[1028]; // buffer for orders
std::clog<<"TTRTS: Waiting for player "<<(int)info.player<<" at "<<inet_ntoa(info.cli_addr.sin_addr)<<std::endl;
std::string orders;
while ( orders.find("END") == std::string::npos )
{
memset(buffer,0,sizeof(buffer));
// Read in the new socket
// read will block until the client has called write
// up to the full size of the buffer
if (read(info.clientsockfd,buffer,sizeof(buffer)-1) < 0)
fatal_perror("ERROR reading from client");
// Append the received orders
orders+=buffer;
}
std::clog<<"TTRTS: Recieved orders from "<<inet_ntoa(info.cli_addr.sin_addr)<<std::endl;
mut.lock();
game.IssueOrders(info.player , orders);
mut.unlock();
}
void WaitForOrdersFromClients(std::vector<ClientInfo> &myClients, CTTRTSGame &game, std::mutex &gameMutex)
{
// Spawn threads
std::vector<std::thread> clientThreads;
for(auto client : myClients)
{
std::thread clientThread(WaitForOrdersFromClient, client, std::ref(game), ref(gameMutex));
clientThreads.push_back(move(clientThread));
}
// Join up all the threads
for ( std::thread& thread : clientThreads )
{
thread.join();
}
}
void SendGamestateToClients(std::vector<ClientInfo> &myClients, const CTTRTSGame &game, std::mutex &gameMutex)
{
gameMutex.lock();
std::string gamestate_string = GetStringFromGame(game);
gameMutex.unlock();
for (auto client : myClients)
{
// Write to the socket with the buffer
if ( write( client.clientsockfd, gamestate_string.c_str(), gamestate_string.length() ) < 0 )
fatal_perror("ERROR sending to client");
}
}
void PerformClientHandshake(int sockfd, unsigned int &player, std::string &gameNameString)
{
char handshakeBuffer[128];
memset(handshakeBuffer,0,sizeof(handshakeBuffer));
if (read(sockfd, handshakeBuffer,sizeof(handshakeBuffer)-1) < 0)
fatal_perror("ERROR recieving handshake from server");
std::string handshake(handshakeBuffer);
if ( write( sockfd, handshake.c_str(), handshake.length()+1 ) < 0 )
fatal_perror("ERROR sending handshake to server");
char gameName[64];
if ( sscanf(handshake.c_str(),TTRTS_HANDSHAKE_FORMAT,&player,gameName) < 2 )
fatal_error("Handshake failed");
gameNameString = gameName;
}
void PerformServerHandshake(const ClientInfo &client, const std::string &game)
{
char handshake[64];
snprintf(handshake, sizeof(handshake), TTRTS_HANDSHAKE_FORMAT,(unsigned int)client.player,game.c_str());
// Send handshake
if ( write( client.clientsockfd,handshake,sizeof(handshake) ) < 0 )
fatal_perror("ERROR sending to client");
// Receive handshake
char buffer[64];
if ( read(client.clientsockfd,buffer,sizeof(buffer)-1) < 0 )
fatal_perror("ERROR reading from client");
// Verify handshake
if ( std::string(buffer) != std::string(handshake) )
fatal_error("Error in client handshake");
std::clog<<"TTRTS: Success on handshake with player "<<(int)client.player<< std::endl;
}
void TryBindSocket(int sockfd, const sockaddr_in &serv_addr)
{
std::clog<<"TTRTS: Binding to socket"<< std::endl;
int retry = 1;
while (1)
{
if(retry > 10)
fatal_error("Binding failed");
// Attempt to bind our listening socket
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) >= 0)
break;
std::cerr<<"Warning: Binding failed on try "<<retry<< std::endl;
sleep(retry);
retry++;
}
}
ClientInfo &WaitForClientConnection(int sockfd, const std::string &game, ClientInfo &clientInfo)
{
socklen_t clilen = sizeof(sockaddr_in);
// accept waits for a connection from a client
// it returns a new socket file descriptor for this connection
// client information will be stored in cli_addr
clientInfo.clientsockfd = accept(sockfd, (sockaddr *) &clientInfo.cli_addr, &clilen);
if (clientInfo.clientsockfd < 0)
fatal_perror("ERROR on accept");
std::clog<<"TTRTS: Client connected from "<<inet_ntoa(clientInfo.cli_addr.sin_addr)<<" socket "<<clientInfo.clientsockfd<< std::endl;
// Handshake with client
PerformServerHandshake(clientInfo, game);
return clientInfo;
}
int SetUpServerListeningSocket(const sockaddr_in &serv_addr)
{
int sockfd;
std::clog<<"TTRTS: Opening socket"<< std::endl;
// Create a new socket
// AF_INET is general internet socket domain
// SOCK_STREAM as messages will be read in on this socket, SOCK_DGRAM would be for packets
// 0 is for default protocol
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
fatal_perror("ERROR opening socket");
// bind our socket to this server address
TryBindSocket(sockfd, serv_addr);
// Listen on the socket for messages
// Second param is length of backlog queue, the maximum number of connections
// that can be waiting while the process is handling a single connection
// max is usually set to 5
listen(sockfd,5);
return sockfd;
}
sockaddr_in GetLocalServerAddress()
{
sockaddr_in serv_addr; // Server address
// empty the server address
memset(&serv_addr,0, sizeof(serv_addr));
// Set the server address family to AF_INET
serv_addr.sin_family = AF_INET;
// htons swaps from host byte order to network byte order
serv_addr.sin_port = htons(TTRTS_PORT);
// The host for this address is this current machine's IP, INADDR_ANY fetches this
serv_addr.sin_addr.s_addr = INADDR_ANY;
return serv_addr;
}
int ConnectToHostServer(const std::string &hostname, sockaddr_in &serv_addr)
{
// Create a new socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
fatal_perror("ERROR opening socket");
// Get the hostent information for the host by name
hostent *server = gethostbyname(hostname.c_str());
if (server == NULL)
fatal_error("ERROR, no such host");
// copy the server address into our server_addr struct
memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);
// Attempt to connect to the server using the socket and server address info
if (connect(sockfd, (const sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
fatal_perror("ERROR connecting");
return sockfd;
}
std::string WaitForGamestateMessage(int sockfd)
{
std::string gamestate;
char gamestateBuffer[1028];
while( gamestate.find("END") == std::string::npos )
{
memset(gamestateBuffer,0,sizeof(gamestateBuffer));
// Receive gamestate
if (read(sockfd,gamestateBuffer,sizeof(gamestateBuffer)-1) < 0)
fatal_perror("ERROR reading from client");
gamestate+=gamestateBuffer;
}
return gamestate;
}
int SendOrdersToServer(int sockfd, const std::string &orders)
{
int n = write(sockfd,orders.c_str(),orders.length());
if (n < 0)
fatal_perror("ERROR writing to socket");
return n;
}
int OutputGameEnd( CTTRTSGame& game )
{
std::cout<<"TTRTS: Game Over!"<<std::endl;
// Get the winning player
player_t winningPlayer = game.GetWinningPlayer();
// Print the winner!
if ( winningPlayer != player_t::NUM_INVALID )
{
std::cout<<"TTRTS: Winner:"<<(int) winningPlayer <<std::endl;
}
else
{
std::cout<<"TTRTS: It was a draw!"<<std::endl;
}
return (int)winningPlayer;
}

View file

@ -1,81 +0,0 @@
#ifndef _TTRTS_NET_H_
#define _TTRTS_NET_H_
#include <vector>
#include <mutex>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <game.h>
#include <formatters.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define TTRTS_HANDSHAKE_FORMAT "player %u name %s"
//======================================================================================================================
// Structs for net management
// Struct for net client info
struct ClientInfo
{
sockaddr_in cli_addr;
int clientsockfd;
player_t player;
};
//======================================================================================================================
// Server side function
// Get the address of a local server
sockaddr_in GetLocalServerAddress();
// Set up a new listening socket for the server
int SetUpServerListeningSocket(const sockaddr_in &serv_addr);
// Wait for client connection on listening socket sockfd
// Will fill clientInfo with client information
ClientInfo &WaitForClientConnection(int sockfd, const std::string &game, ClientInfo &clientInfo);
// Wait for orders from a client, will not return until client has send valid orders
// Will automatically add orders to the game
void WaitForOrdersFromClient(const ClientInfo info, CTTRTSGame &game, std::mutex &mut);
// Iterates through a list of clients calling WaitForOrdersFromClient
void WaitForOrdersFromClients(std::vector<ClientInfo> &myClients, CTTRTSGame &game, std::mutex &gameMutex);
// Sends current gamestate to each client
void SendGamestateToClients(std::vector<ClientInfo> &myClients, const CTTRTSGame &game, std::mutex &gameMutex);
// Tries to bind to a socket, will attempt 10 times with longer waits between
void TryBindSocket(int sockfd, const sockaddr_in &serv_addr);
// Perform the server side handshake with a client
void PerformServerHandshake(const ClientInfo &client, const std::string &game);
//======================================================================================================================
// Client side functions
// Connect to the host, returns new socket for communication
int ConnectToHostServer(const std::string &hostname, sockaddr_in &serv_addr);
// Perform the client side handshake with the server
void PerformClientHandshake(int sockfd, unsigned int &player, std::string &gameNameString);
// Wait for gamestate message from host
std::string WaitForGamestateMessage(int sockfd);
// Send orders to the server
int SendOrdersToServer(int sockfd, const std::string &orders);
//======================================================================================================================
// Other functions
int OutputGameEnd( CTTRTSGame& game );
#endif

View file

@ -4,7 +4,8 @@
project( ttrts-test )
include_directories(
../ttrts
../ttrts
../maths
)
set( SOURCES

View file

@ -5,7 +5,8 @@ project( ttrts )
# Include the maths
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}
../maths
)
# Add our sources

View file

@ -92,7 +92,7 @@ CTTRTSGame GetGameFromString( const std::string& input )
size_t pos;
while ( ( pos = walls_str.find(']') ) != std::string::npos )
{
std::string pos_string = walls_str.substr(0,pos+1);
std::string pos_string = walls_str.substr(0,pos);
// Use scanf to extract positions

View file

@ -17,7 +17,6 @@ CTTRTSGame::CTTRTSGame(CTTRTSGame&& game)
, dimensions(std::move(game.dimensions))
, turn(std::move(game.turn))
, name(std::move(game.name))
, m_walls(std::move(game.m_walls))
{
}