diff --git a/CMakeLists.txt b/CMakeLists.txt index 97a47ba..01d8a13 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 ) diff --git a/README.md b/README.md index a6b299b..1f18053 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/api/perl/ttrts.pm b/api/perl/ttrts.pm index 793269b..6dc279e 100644 --- a/api/perl/ttrts.pm +++ b/api/perl/ttrts.pm @@ -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) { diff --git a/bootstrap.sh b/bootstrap.sh index 701f47b..26e306d 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -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" diff --git a/scripts/gen_manpage.sh b/scripts/gen_manpage.sh index e699063..57ad57c 100755 --- a/scripts/gen_manpage.sh +++ b/scripts/gen_manpage.sh @@ -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 diff --git a/scripts/gen_usage.sh b/scripts/gen_usage.sh index 5e33166..efeab0a 100755 --- a/scripts/gen_usage.sh +++ b/scripts/gen_usage.sh @@ -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 diff --git a/scripts/gen_version_header.sh b/scripts/gen_version_header.sh index aec60e2..907c2be 100755 --- a/scripts/gen_version_header.sh +++ b/scripts/gen_version_header.sh @@ -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" \ No newline at end of file diff --git a/scripts/ttrts_complete b/scripts/ttrts_complete index d257ed4..7b884b7 100755 --- a/scripts/ttrts_complete +++ b/scripts/ttrts_complete @@ -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 diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt deleted file mode 100644 index d73e509..0000000 --- a/source/CMakeLists.txt +++ /dev/null @@ -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 ) \ No newline at end of file diff --git a/source/README.md b/source/README.md index 22b8dea..5ca2d8e 100644 --- a/source/README.md +++ b/source/README.md @@ -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] - -# DESCRIPTION - ttrts is a tiny terminal based RTS that uses text files as order lists to control the units +### test +Test binary, to be compiled and run to test various functionality - This means that any user, program or cat that can read and write to text files can play the game +### gen +Binary to generate example map files -# 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 diff --git a/source/client/CMakeLists.txt b/source/client/CMakeLists.txt index 1ae8054..6549943 100644 --- a/source/client/CMakeLists.txt +++ b/source/client/CMakeLists.txt @@ -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) \ No newline at end of file diff --git a/source/client/README.md b/source/client/README.md new file mode 100644 index 0000000..9e8cf27 --- /dev/null +++ b/source/client/README.md @@ -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. diff --git a/source/client/client.cpp b/source/client/client.cpp deleted file mode 100644 index 116a5a0..0000000 --- a/source/client/client.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include - -#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 "<= 0 ) - { - std::cout<<"TTRTS: Waiting for gamestate"< +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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<(file)),std::istreambuf_iterator()); + + if( gameDescriptor.size() == 0 ) + { + std::cerr<<"Error: failed to read in any information from "<>input; + if( !input.size() || std::tolower(input[0]) != 'y' ) + { + std::cerr<<"Aborting..."<(turnFile)),std::istreambuf_iterator()); + + // Issue the orders to the game + if( game.IssueOrders(player, orders) ) + std::cerr<<"Warning: Orders for player "<<(int) player <<" failed to correctly parse"< \$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 \ No newline at end of file diff --git a/source/local/CMakeLists.txt b/source/local/CMakeLists.txt deleted file mode 100644 index 172b736..0000000 --- a/source/local/CMakeLists.txt +++ /dev/null @@ -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 ) \ No newline at end of file diff --git a/source/local/local.cpp b/source/local/local.cpp deleted file mode 100644 index b2697e7..0000000 --- a/source/local/local.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "game.h" -#include "filesystem.h" -#include "error.h" -#include "net.h" - -#include - -// ===================================================================================================================== -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 "< -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "net.h" -#include "filesystem.h" - -void RunServerForGame(CTTRTSGame &game) -{ - std::cout<<"TTRTS: Setting up server"< players = game.GetPlayers(); - unsigned int numClients = players.size(); - auto player_iterator = players.begin(); - - // game mutex - std::mutex gameMutex; - - // Set of clients - std::vector myClients; - - std::cout<<"TTRTS: Waiting for "< -#include -#include - -//====================================================================================================================== -// Error functions - -// For local fatal errors -inline void fatal_error(const char *msg) -{ - std::cerr< -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -// ===================================================================================================================== -// 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<(file)),std::istreambuf_iterator()); - - 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(turnFile)), std::istreambuf_iterator()); - 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"<>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 < -#include - -#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 \ No newline at end of file diff --git a/source/system/net.cpp b/source/system/net.cpp deleted file mode 100644 index 29c23b9..0000000 --- a/source/system/net.cpp +++ /dev/null @@ -1,261 +0,0 @@ -#include "net.h" -#include "error.h" - -#include - -#include -#include - -#include -#include -#include -#include - -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 "< &myClients, CTTRTSGame &game, std::mutex &gameMutex) -{ - // Spawn threads - std::vector 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 &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 "<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!"< -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#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 &myClients, CTTRTSGame &game, std::mutex &gameMutex); - -// Sends current gamestate to each client -void SendGamestateToClients(std::vector &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 \ No newline at end of file diff --git a/source/test/CMakeLists.txt b/source/test/CMakeLists.txt index 3e6a60c..179f7a8 100644 --- a/source/test/CMakeLists.txt +++ b/source/test/CMakeLists.txt @@ -4,7 +4,8 @@ project( ttrts-test ) include_directories( - ../ttrts + ../ttrts + ../maths ) set( SOURCES diff --git a/source/ttrts/CMakeLists.txt b/source/ttrts/CMakeLists.txt index 93a6d94..b528b3f 100644 --- a/source/ttrts/CMakeLists.txt +++ b/source/ttrts/CMakeLists.txt @@ -5,7 +5,8 @@ project( ttrts ) # Include the maths include_directories( - ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ../maths ) # Add our sources @@ -43,4 +44,4 @@ install( ) # Install the ttrts static lib -install( TARGETS ttrts DESTINATION lib ) +install( TARGETS ttrts DESTINATION lib ) \ No newline at end of file diff --git a/source/ttrts/formatters.cpp b/source/ttrts/formatters.cpp index 332c5ac..6d6d03a 100644 --- a/source/ttrts/formatters.cpp +++ b/source/ttrts/formatters.cpp @@ -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 diff --git a/source/ttrts/game.cpp b/source/ttrts/game.cpp index d649060..96800d5 100644 --- a/source/ttrts/game.cpp +++ b/source/ttrts/game.cpp @@ -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)) { }