27 Commits

Author SHA1 Message Date
949549caff Include itch.io values 2020-05-03 22:30:01 -04:00
3b5ca90cfb Implement Client CI/CD
Enable debug export

Push build dir instead of artifact

Lots of debugging stuff

Use debug export branch

Client pipeline debugging...

Client pipeline debugging...

Client pipeline debugging...

Client pipeline debugging...

Client pipeline debugging...

Client pipeline debugging...

Client pipeline debugging...

Client pipeline debugging...

Client pipeline debugging...

Client pipeline debugging...

Client pipeline debugging...

Cleanup and publish
2020-05-03 22:22:32 -04:00
95d52a8866 Client-side chat changes 2020-05-03 19:35:58 -04:00
3b9e5d2ece Debug chat issues 2020-05-03 19:34:07 -04:00
9145747e20 Implemented basic chat system 2020-05-02 17:25:31 -04:00
ee233c52f0 Added client nameplates 2020-05-02 16:36:51 -04:00
948b379f9d Client environment selection dropdown 2020-05-02 16:19:46 -04:00
ddf5275a37 Fix 2020-05-02 03:20:49 -04:00
ce9afe339c Enable dynamic port routing 2020-05-02 03:12:12 -04:00
fee56c6042 Dockerfile with working healthcheck endpoint 2020-05-02 03:02:06 -04:00
e2a8f446bb Merge 2020-05-02 01:03:29 -04:00
bec4209232 Disable dynamic routing to allow for proper healthchecks 2020-05-02 01:02:28 -04:00
b93240f992 Configure endpoint for healthcheck
Configure endpoint for healthcheck

Update healthcheck to run

HOTFIX: Fix healthcheck protocol

HOTFIX: Expose healthcheck port task

HOTFIX: Make healthcheck UDP & remove TCP endpoint

Reimplement healthcheck without forcing port

Reimplement healthcheck without forcing port
2020-05-02 00:50:16 -04:00
31831ff9d1 Reimplement healthcheck without forcing port 2020-05-02 00:31:34 -04:00
db37a8c924 Reimplement healthcheck without forcing port 2020-05-02 00:16:51 -04:00
11a41fdca7 HOTFIX: Make healthcheck UDP & remove TCP endpoint 2020-05-02 00:02:21 -04:00
f4e1d3a3b8 HOTFIX: Expose healthcheck port task 2020-05-01 23:57:09 -04:00
4caab69266 HOTFIX: Fix healthcheck protocol 2020-05-01 23:52:20 -04:00
15f6a8df22 Update healthcheck to run 2020-05-01 23:45:13 -04:00
fb236647a3 Configure endpoint for healthcheck 2020-05-01 17:43:26 -04:00
5fbbfba593 Configure endpoint for healthcheck 2020-05-01 17:42:59 -04:00
84f6ca7434 Client entity deletion 2020-05-01 02:27:47 -04:00
9a6ba77e72 Additional testing, entity deletion, and player disconnection 2020-05-01 02:24:34 -04:00
b94b469c39 INFRASTRUCTURE FIX: Container port 'tcp' -> 'udp' 2020-05-01 00:15:22 -04:00
6eaa057da8 Rework console input to use iostream 2020-05-01 00:12:57 -04:00
7ca5c63131 Reduce memory reservation 2020-05-01 00:06:06 -04:00
70b8236f4e Implement stage 2020-04-30 23:47:00 -04:00
21 changed files with 498 additions and 82 deletions

84
.github/workflows/build_stage.yml vendored Normal file
View File

@ -0,0 +1,84 @@
name: Build Stage
on:
push:
branches:
- master
jobs:
godot:
runs-on: ubuntu-latest
strategy:
matrix:
platform: [linux]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Download Export Template
env:
PLATFORM: ${{ matrix.platform }}
run: |
mkdir -p client/templates
wget http://godot-enet.cloudsumu.com.s3-website-us-east-1.amazonaws.com/export-templates/debug/$PLATFORM -O client/templates/$PLATFORM
- name: Build
id: build
uses: josephbmanley/build-godot-action@v1.4.0
with:
name: defend-together
preset: ${{ matrix.platform }}
projectDir: client
debugMode: 'true'
package: 'true'
- name: Upload Artifact
uses: actions/upload-artifact@v2
with:
name: Client - ${{ matrix.platform }}
path: ${{ github.workspace }}/${{ steps.build.outputs.build }}
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Push Tag to Docker Hub
uses: opspresso/action-docker@master
with:
args: --docker
env:
USERNAME: ${{ secrets.DOCKER_USERNAME }}
PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
BUILD_PATH: "server"
DOCKERFILE: "server/Dockerfile"
IMAGE_NAME: "josephbmanley/defend-together"
TAG_NAME: "stage"
LATEST: "false"
cloudformation:
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v2.1.0
with:
submodules: 'true'
- name: Ship to S3
uses: jakejarvis/s3-sync-action@master
with:
args: --follow-symlinks --delete
env:
SOURCE_DIR: infrastructure/cloudformation
AWS_REGION: "us-east-1"
DEST_DIR: dt/stage/cloudformation
AWS_S3_BUCKET: sumu-stacks
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Deploy to AWS CloudFormation
uses: aws-actions/aws-cloudformation-github-deploy@v1
with:
name: dt-infrastructure-stage
template: infrastructure/cloudformation/dt/top.yaml
capabilities: "CAPABILITY_NAMED_IAM,CAPABILITY_IAM"
parameter-overrides: VpcId=${{ secrets.VPC_ID }},SubDomain=stage.dt,Domain=${{ secrets.DOMAIN }},environment=stage,DockerTag=stage,release=stage,PublicSubnets=${{ secrets.SUBNET_IDS }}

View File

@ -6,6 +6,46 @@ on:
- created
jobs:
godot:
runs-on: ubuntu-latest
strategy:
matrix:
platform: [linux]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Download Export Template
env:
PLATFORM: ${{ matrix.platform }}
run: |
mkdir -p client/templates
wget http://godot-enet.cloudsumu.com.s3-website-us-east-1.amazonaws.com/export-templates/debug/$PLATFORM -O client/templates/$PLATFORM
- name: Build
id: build
uses: josephbmanley/build-godot-action@v1.4.0
with:
name: defend-together
preset: ${{ matrix.platform }}
projectDir: client
debugMode: 'true'
package: 'true'
- id: get_tag
name: Get Tag
env:
GITHUB_HEAD_REF: $${{ github.head_ref }}
GITHUB_BASE_REF: ${{ github.base_ref }}
run: |
TAG=$(jq --raw-output '.release.tag_name' $GITHUB_EVENT_PATH)
echo ::set-output name=TAG::$TAG
- name: Push to Itch
uses: josephbmanley/butler-publish-itchio-action@v1.0.1
env:
BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }}
CHANNEL: ${{ matrix.platform }}
ITCH_GAME: defend-together
ITCH_USER: josephbmanley
PACKAGE: ${{ github.workspace }}/${{ steps.build.outputs.build }}
VERSION: ${{ steps.get_tag.outputs.TAG }}
docker:
runs-on: ubuntu-latest
steps:

3
client/.gitignore vendored
View File

@ -1 +1,2 @@
builds
builds
templates

View File

@ -1,6 +1,6 @@
[preset.0]
name="Linux/X11"
name="linux"
platform="Linux/X11"
runnable=true
custom_features=""
@ -21,28 +21,5 @@ texture_format/etc2=false
texture_format/no_bptc_fallbacks=true
binary_format/64_bits=true
binary_format/embed_pck=false
custom_template/release="/var/home/vetra/Projects/godot-enet/bin/godot.x11.opt.64"
custom_template/debug="/var/home/vetra/Projects/godot-enet/bin/godot.x11.opt.debug.64"
[preset.1]
name="HTML5"
platform="HTML5"
runnable=true
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path="builds/client.html"
patch_list=PoolStringArray( )
script_export_mode=1
script_encryption_key=""
[preset.1.options]
vram_texture_compression/for_desktop=true
vram_texture_compression/for_mobile=false
html/custom_html_shell=""
html/head_include=""
custom_template/release=""
custom_template/debug=""
custom_template/release="templates/linux"
custom_template/debug="templates/linux"

View File

@ -24,6 +24,14 @@ config/icon="res://icon.png"
MusicManager="*res://nodes/MusicManager.tscn"
NetworkManager="*res://nodes/NetworkManager.tscn"
[input]
send_chat_message={
"deadzone": 0.5,
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777221,"unicode":0,"echo":false,"script":null)
]
}
[rendering]
environment/default_environment="res://default_env.tres"

Binary file not shown.

Binary file not shown.

View File

@ -3,17 +3,21 @@ extends KinematicBody2D
export var user : String = ""
func _ready():
set_username("")
func set_username(username):
print(username)
user = username
$Label.text = user
#$Label.text = $"/root/NetworkManager".username
func _process(delta):
var movePos : Vector2 = Vector2(0,0)
if(Input.is_action_just_pressed("ui_up")):
movePos.y = movePos.y + 1
if(Input.is_action_just_pressed("ui_down")):
movePos.y = movePos.y - 1
if(Input.is_action_just_pressed("ui_down")):
movePos.y = movePos.y + 1
if(Input.is_action_just_pressed("ui_right")):
movePos.x = movePos.x + 1
if(Input.is_action_just_pressed("ui_left")):

View File

@ -1,6 +1,7 @@
extends Node
const SERVER_HOST : String = "192.168.1.34"
var server_host : String = "127.0.0.1"
const SERVER_PORT : int = 7777
signal disconnection
@ -9,6 +10,7 @@ signal error_occured
signal logged_in
signal world_data_recieved
signal chat_message_recieved
var username : String = ""
@ -27,15 +29,17 @@ var connection_timer : Timer
func _init():
server_address = GDNetAddress.new()
server_address.set_host(SERVER_HOST)
server_address.set_port(SERVER_PORT)
client = GDNetHost.new()
client.set_max_channels(2)
client.set_max_peers(1)
client.set_event_wait(250)
client.bind()
func connect_to_server():
if peer:
peer.disconnect_now()
server_address.set_host(server_host)
server_address.set_port(SERVER_PORT)
peer = client.host_connect(server_address)
if not connection_timer:
connection_timer = Timer.new()
@ -50,13 +54,13 @@ func timeout_check():
func request_world_map():
var request_packet : PoolByteArray = "2|".to_ascii()
packetQueue.append(request_packet)
send_packet(request_packet)
func connect_as_user(username : String):
connect_to_server()
var username_packet : PoolByteArray = ("1|" + username).to_ascii()
packetQueue.append(username_packet)
send_packet(username_packet)
func display_error(error = "Unknown error occured!"):
error_info = error
@ -73,18 +77,22 @@ func process_events():
var event_type = event.get_event_type()
if(event_type == GDNetEvent.RECEIVE):
var ascii_data : String = str(event.get_packet().get_string_from_ascii())
if len(ascii_data) > 0:
if ascii_data[0] == '1':
if ascii_data.substr(2,2) == "OK":
username = ascii_data.substr(4)
print("Logged in as: " + username)
emit_signal("logged_in")
else:
display_error("Username not accepted! Reason: " + ascii_data.substr(2))
elif ascii_data[0] == '2':
world_data = ascii_data.substr(2)
emit_signal("world_data_recieved")
if event.get_channel_id() == 0:
var ascii_data : String = str(event.get_packet().get_string_from_ascii())
if len(ascii_data) > 0:
if ascii_data[0] == '1':
if ascii_data.substr(2,2) == "OK":
username = ascii_data.substr(4)
print("Logged in as: " + username)
emit_signal("logged_in")
else:
display_error("Username not accepted! Reason: " + ascii_data.substr(2))
elif ascii_data[0] == '2':
world_data = ascii_data.substr(2)
emit_signal("world_data_recieved")
elif event.get_channel_id() == 1:
var chat_message : String = str(event.get_packet().get_string_from_ascii())
emit_signal("chat_message_recieved", chat_message)
elif(event_type == GDNetEvent.CONNECT):
print("Connected to server with hostname: " + server_address.get_host() + ":" + str(server_address.get_port()))
connected = true
@ -94,16 +102,24 @@ func process_events():
connected = false
emit_signal("disconnection")
func send_chat_message(msg : String):
var pckt : PoolByteArray = (msg + '\n').to_ascii()
send_packet(pckt, 1)
func send_packet(packet : PoolByteArray, channel = 0):
packetQueue.append({'channel':channel, 'packet' : packet})
func move_player(x,y):
var pckt : PoolByteArray = ("3|" + str(x) + "," + str(y)).to_ascii()
packetQueue.append(pckt)
send_packet(pckt)
func _process(delta):
process_events()
if len(packetQueue) > 0 and connected:
peer.send_packet(packetQueue[0], 0, GDNetMessage.RELIABLE)
peer.send_packet(packetQueue[0]['packet'], packetQueue[0]['channel'], GDNetMessage.RELIABLE)
packetQueue.remove(0)

View File

@ -10,7 +10,10 @@ func _on_world_update():
var data = $"/root/NetworkManager".world_data.split('\n')
for tileUpdate in data:
if len(tileUpdate) > 3:
if ',' in tileUpdate:
if "delete," in tileUpdate:
var delete_data = tileUpdate.substr(len("delete,")).split(':')
delete_entity(delete_data[1],delete_data[0])
elif ',' in tileUpdate:
var tile_data = tileUpdate.split(',')
if ':' in tile_data[2]:
var pos : Vector2 = $Tiles.map_to_world(Vector2(int(tile_data[0]), int(tile_data[1])))
@ -47,3 +50,11 @@ func update_entity(entity_id : String, pos : Vector2, type : String):
display_error("Trying to load entity of type: " + type + ", but failed.")
if entity:
entity.position = pos
if entity.has_method("set_username"):
entity.set_username(entity_id)
func delete_entity(entity_id : String, type : String):
var entity : Node2D = get_node_or_null( str(type + "-" + entity_id))
if entity:
entity.queue_free()

View File

@ -37,6 +37,8 @@ Resources:
NlbTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckProtocol: TCP
HealthCheckPort: 80
Port: 7777
Protocol: TCP_UDP
TargetGroupAttributes:

View File

@ -6,13 +6,23 @@ Parameters:
Description: The AWS CloudWatch log group to output logs to.
Default: "/ecs/dt"
environment:
Type: String
Description: Name of the environment to use in naming.
Default: production
DockerTag:
Description: Tag in DockerHub to deploy
Type: String
Default: "latest"
Resources:
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
RetentionInDays: 7
LogGroupName: !Ref LogGroupName
LogGroupName: !Sub "${LogGroupName}/${environment}"
TaskDefinition:
Type: AWS::ECS::TaskDefinition
@ -20,11 +30,15 @@ Resources:
ContainerDefinitions:
- Name: defend-together
Essential: 'true'
Image: "josephbmanley/defend-together:latest"
MemoryReservation: 800
Image: !Sub "josephbmanley/defend-together:${DockerTag}"
MemoryReservation: 250
PortMappings:
- HostPort: 0
- HostPort: 7777
ContainerPort: 7777
Protocol: udp
- HostPort: 80
ContainerPort: 80
Protocol: tcp
LogConfiguration:
LogDriver: awslogs
Options:

View File

@ -12,11 +12,15 @@ Parameters:
Type: String
Description: Name of the release name of the stack version to use.
Default: production
AllowedValues: ['develop', 'production']
AllowedValues: ['develop', 'stage', 'production']
ConstraintDescription: "Must be a possible release version."
VpcId:
Description: ID of the VPC
Type: AWS::EC2::VPC::Id
DockerTag:
Description: Tag in DockerHub to deploy
Type: String
Default: "latest"
#-----------------
# Load Balancing
@ -95,7 +99,9 @@ Resources:
Properties:
TemplateURL: !Sub 'https://s3.${AWS::Region}.amazonaws.com/sumu-stacks/dt/${release}/cloudformation/dt/task.yaml'
Parameters:
environment: !Ref environment
LogGroupName: !Ref LogGroup
DockerTag: !Ref DockerTag
EcsService:

View File

@ -1,9 +1,15 @@
FROM fedora:32
RUN /bin/bash -c "dnf install g++ enet-devel gtest gmock gmock-devel gtest-devel -y"
# Build and setup app
RUN dnf install g++ enet-devel gtest gmock gmock-devel gtest-devel nginx -y
ADD / /dt
RUN cd /dt; /dt/build.sh
CMD ["/dt/builds/server.out"]
RUN echo "Container is healthy!" > /usr/share/nginx/html/index.html
CMD /usr/sbin/nginx ; /dt/builds/server.out
EXPOSE 80
EXPOSE 7777/udp

View File

@ -7,4 +7,11 @@ if [ -f builds/server.out ]; then
rm builds/server.out
fi
g++ main.cpp -o builds/server.out -lenet -lpthread
g++ main.cpp -o builds/server.out -lenet -lpthread
if [ $? = 0 ]
then
echo "Build successfully!"
else
exit -1
fi

View File

@ -1,9 +1,9 @@
#ifndef CONSOLE_HPP
#define CONSOLE_HPP
#include <stdio.h>
#include <pthread.h>
#include <iostream>
#include <string>
#include <cstring>
@ -22,19 +22,22 @@ class ServerConsole
void * console_logic(void *)
{
printf("Started server console...\n");
std::cout << "Started server console..." << std::endl;
std::string input_string;
while(console_is_running)
{
char c [256];
fgets(c,sizeof(c), stdin);
if(c[0] == 'q')
if(std::getline(std::cin, input_string))
{
console_is_running = false;
}
else
{
printf("Invalid console command!\n");
if(input_string == "stop")
{
console_is_running = false;
}
else
{
std::cout << "Invalid console command!" << std::endl;
}
}
}
return 0;

View File

@ -17,8 +17,13 @@ class GameMap
std::string get_entity_dump(void);
std::string spawn_entity(std::string,std::string,int,int);
std::string move_entity(std::string,std::string,int,int);
int get_entity_pos_x(std::string,std::string);
int get_entity_pos_y(std::string,std::string);
int get_size_x(void);
int get_size_y(void);
bool entity_exists(std::string, std::string);
bool remove_entity(std::string, std::string);
private:
int ** map_data;
int size_x;
@ -66,12 +71,36 @@ std::string GameMap::move_entity(std::string entity_id, std::string entity_type,
{
if(entities[i].get_id() == entity_id && entities[i].get_type() == entity_type)
{
if(map_data[entities[i].get_x() + x][entities[i].get_y() + y] % 2 == 1)
GameEntity* entity = &entities[i];
//if(map_data[entities[i].get_x() + x][entities[i].get_y() + y] % 2 == 1)
//{
if(entity->get_x() + x < 0)
{
entities[i].set_x(entities[i].get_x() + x);
entities[i].set_y(entities[i].get_y() + y);
entity->set_x(0);
}
return entities[i].get_dump();
else if(entity->get_x() + x >= this->get_size_x())
{
entity->set_x(this->get_size_x() - 1);
}
else
{
entity->set_x(entities[i].get_x() + x);
}
if(entity->get_y() + y < 0)
{
entity->set_y(0);
}
else if(entity->get_y() + y >= this->get_size_y())
{
entity->set_y(this->get_size_y() - 1);
}
else
{
entity->set_y(entities[i].get_y() + y);
}
return entity->get_dump();
}
}
return "";
@ -137,4 +166,84 @@ int GameMap::get_size_y(void)
return size_y;
}
bool GameMap::entity_exists(std::string entity_id, std::string entity_type)
{
for(int i = 0; i < entities.size(); i++)
{
GameEntity* entity = &entities[i];
if(entity->get_id() == entity_id)
{
if(entity->get_type() == entity_type)
{
return true;
}
}
}
return false;
}
bool erase(std::vector<GameEntity> &v, GameEntity key)
{
for(auto it = v.begin(); it != v.end();)
{
if (it->get_id() == key.get_id())
{
it = v.erase(it);
return true;
}
else
{
++it;
}
}
return false;
}
bool GameMap::remove_entity(std::string entity_id, std::string entity_type)
{
for(int i = 0; i < entities.size(); i++)
{
if(entities[i].get_id() == entity_id && entities[i].get_type() == entity_type)
{
return erase(entities, entities[i]);
}
}
return false;
}
int GameMap::get_entity_pos_x(std::string entity_id, std::string entity_type)
{
for(int i = 0; i < entities.size(); i++)
{
GameEntity* entity = &entities[i];
if(entity->get_id() == entity_id)
{
if(entity->get_type() == entity_type)
{
return entity->get_x();
}
}
}
return -1;
}
int GameMap::get_entity_pos_y(std::string entity_id, std::string entity_type)
{
for(int i = 0; i < entities.size(); i++)
{
GameEntity* entity = &entities[i];
if(entity->get_id() == entity_id)
{
if(entity->get_type() == entity_type)
{
return entity->get_y();
}
}
}
return -1;
}
#endif

View File

@ -39,7 +39,7 @@ int main (int argc, char ** argv)
address.port = SERVER_PORT;
const int CHANNEL_COUNT = 1;
const int CHANNEL_COUNT = 2;
server = enet_host_create (&address, MAX_PLAYERS, CHANNEL_COUNT, 0, 0);
if (server == NULL)
@ -67,7 +67,8 @@ int main (int argc, char ** argv)
std::cout << "A packet of length " << event.packet -> dataLength << " containing "
<< event.packet -> data << " was received from " << event.peer -> data << " on channel"
<< event.channelID << std::endl;
if (event.channelID == 0)
{
char c [1];
c[0] = event.packet->data[0];
@ -89,19 +90,49 @@ int main (int argc, char ** argv)
std::cout << "Invalid packet recieved!" <<std::endl;
break;
}
//Destroy packet now that it has been used
enet_packet_destroy (event.packet);
}
else if(event.channelID == 1)
{
int peer_id = event.peer -> incomingPeerID;
if(usernames[peer_id] != "")
{
//Parse input string
std::stringstream ss((char*)event.packet->data);
std::string chat_message;
std::getline(ss, chat_message, '\n');
std::string resp = "<" + usernames[peer_id] + "> " + chat_message;
const char* data = resp.c_str();
std::cout << data << std::endl;
ENetPacket* packet = enet_packet_create(data, strlen(data) + 1, ENET_PACKET_FLAG_RELIABLE);
enet_host_broadcast(server, 1, packet);
}
enet_packet_destroy (event.packet);
}
break;
case ENET_EVENT_TYPE_DISCONNECT:
std::cout << event.peer -> data << " disconnected." << std::endl;
//Remove peer data on disconnect
// DELETE ENTITY HERE
//Clear username data and remove entity
std::string username = usernames[event.peer -> incomingPeerID];
if(username != "")
{
std::cout << "Removing '" << username << "'s player data!" << std::endl;
gamemap.remove_entity(username,"player");
usernames[event.peer -> incomingPeerID] = "";
usernames[event.peer -> incomingPeerID] = "";
std::string resp = "2|delete,player:" + username;
const char* data = resp.c_str();
ENetPacket* packet = enet_packet_create(data, strlen(data) + 1, ENET_PACKET_FLAG_RELIABLE);
enet_host_broadcast(server, 0, packet);
}
//Open peer for new connection
event.peer -> data = NULL;
}
}

10
server/nginx.conf Normal file
View File

@ -0,0 +1,10 @@
server {
location / {
root /usr/share/nginx/html;
}
location /health {
return 200 'alive';
add_header Content-Type text/plain;
}
}

View File

@ -1,4 +1,9 @@
#!/bin/sh
mkdir -p builds
g++ tests.cpp -o builds/tests.out -lgtest
./builds/tests.out
if [ $? = 0 ]
then
./builds/tests.out
else
exit -1
fi

View File

@ -1,6 +1,7 @@
#include <gtest/gtest.h>
#include <string>
#include <iostream>
#include "gameentity.hpp"
#include "gamemap.hpp"
@ -61,6 +62,87 @@ TEST(GameMapTest, CheckMapSize)
EXPECT_EQ(map.get_size_x(), 16);
EXPECT_EQ(map.get_size_y(), 4);
}
TEST(GameMapTest, CreateEntity)
{
GameMap map = CreateMapEntity();
map.spawn_entity(TEST_ENTITY_ID, TEST_ENTITY_TYPE);
EXPECT_TRUE(map.entity_exists(TEST_ENTITY_ID, TEST_ENTITY_TYPE));
}
TEST(GameMapTest, IntialEntityPos)
{
GameMap map = CreateMapEntity();
map.spawn_entity(TEST_ENTITY_ID, TEST_ENTITY_TYPE, 0,0);
EXPECT_EQ(map.get_entity_pos_x(TEST_ENTITY_ID, TEST_ENTITY_TYPE), 0);
EXPECT_EQ(map.get_entity_pos_y(TEST_ENTITY_ID, TEST_ENTITY_TYPE), 0);
}
TEST(GameMapTest, MoveEntityFromZero)
{
GameMap map = CreateMapEntity();
map.spawn_entity(TEST_ENTITY_ID, TEST_ENTITY_TYPE, 0,0);
//Move entity
map.move_entity(TEST_ENTITY_ID, TEST_ENTITY_TYPE, 2, 1);
EXPECT_EQ(map.get_entity_pos_x(TEST_ENTITY_ID, TEST_ENTITY_TYPE), 2);
EXPECT_EQ(map.get_entity_pos_y(TEST_ENTITY_ID, TEST_ENTITY_TYPE), 1);
}
TEST(GameMapTest, MoveEntityRelative)
{
GameMap map = CreateMapEntity();
map.spawn_entity(TEST_ENTITY_ID, TEST_ENTITY_TYPE, 0,0);
//Move entity
map.move_entity(TEST_ENTITY_ID, TEST_ENTITY_TYPE, 2, 1);
//Move entity again!
map.move_entity(TEST_ENTITY_ID, TEST_ENTITY_TYPE, 1, 1);
EXPECT_EQ(map.get_entity_pos_x(TEST_ENTITY_ID, TEST_ENTITY_TYPE), 3);
EXPECT_EQ(map.get_entity_pos_y(TEST_ENTITY_ID, TEST_ENTITY_TYPE), 2);
}
TEST(GameMapTest, MoveEntityNegativeFromZero)
{
GameMap map = CreateMapEntity();
map.spawn_entity(TEST_ENTITY_ID, TEST_ENTITY_TYPE, 0, 0);
//Move entity
map.move_entity(TEST_ENTITY_ID, TEST_ENTITY_TYPE, -1, -1);
EXPECT_EQ(map.get_entity_pos_x(TEST_ENTITY_ID, TEST_ENTITY_TYPE), 0);
EXPECT_EQ(map.get_entity_pos_y(TEST_ENTITY_ID, TEST_ENTITY_TYPE), 0);
}
TEST(GameMapTest, MoveEntityNegativeFromNonZero)
{
GameMap map = CreateMapEntity();
map.spawn_entity(TEST_ENTITY_ID, TEST_ENTITY_TYPE, 1, 1);
//Move entity
std::cout << std::string(map.move_entity(TEST_ENTITY_ID, TEST_ENTITY_TYPE, -2, -2)) << std::endl;
EXPECT_EQ(map.get_entity_pos_x(TEST_ENTITY_ID, TEST_ENTITY_TYPE), 0);
EXPECT_EQ(map.get_entity_pos_y(TEST_ENTITY_ID, TEST_ENTITY_TYPE), 0);
}
TEST(GameMapTest, StopEntityFromMovingOutOfBounds)
{
GameMap map = CreateMapEntity();
map.spawn_entity(TEST_ENTITY_ID, TEST_ENTITY_TYPE, map.get_size_x()-1, map.get_size_y()-1);
//Move entity
map.move_entity(TEST_ENTITY_ID, TEST_ENTITY_TYPE, 2, 2);
EXPECT_EQ(map.get_entity_pos_x(TEST_ENTITY_ID, TEST_ENTITY_TYPE), map.get_size_x() - 1);
EXPECT_EQ(map.get_entity_pos_y(TEST_ENTITY_ID, TEST_ENTITY_TYPE), map.get_size_y() - 1);
}
TEST(GameMapTest, RemoveMapEntity)
{
GameMap map = CreateMapEntity();
map.spawn_entity(TEST_ENTITY_ID, TEST_ENTITY_TYPE);
EXPECT_TRUE(map.remove_entity(TEST_ENTITY_ID, TEST_ENTITY_TYPE));
EXPECT_FALSE(map.entity_exists(TEST_ENTITY_ID, TEST_ENTITY_TYPE));
}
int main(int argc, char* argv[])
{