Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
95f1df755e | |||
db334fc573 | |||
7f5e6a1fec | |||
4f47f758e7 | |||
bf546793e2 | |||
c980235726 |
10
.github/workflows/build_stage.yml
vendored
10
.github/workflows/build_stage.yml
vendored
@ -70,9 +70,9 @@ jobs:
|
|||||||
args: --follow-symlinks --delete
|
args: --follow-symlinks --delete
|
||||||
env:
|
env:
|
||||||
SOURCE_DIR: infrastructure/cloudformation
|
SOURCE_DIR: infrastructure/cloudformation
|
||||||
AWS_REGION: "us-east-1"
|
AWS_REGION: "us-east-2"
|
||||||
DEST_DIR: dt/stage/cloudformation
|
DEST_DIR: stage/cloudformation
|
||||||
AWS_S3_BUCKET: sumu-stacks
|
AWS_S3_BUCKET: dt-deployment-bucket
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
- name: Configure AWS Credentials
|
- name: Configure AWS Credentials
|
||||||
@ -80,11 +80,11 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
aws-region: us-east-1
|
aws-region: us-east-2
|
||||||
- name: Deploy to AWS CloudFormation
|
- name: Deploy to AWS CloudFormation
|
||||||
uses: aws-actions/aws-cloudformation-github-deploy@v1
|
uses: aws-actions/aws-cloudformation-github-deploy@v1
|
||||||
with:
|
with:
|
||||||
name: dt-infrastructure-stage
|
name: dt-infrastructure-stage
|
||||||
template: infrastructure/cloudformation/dt/top.yaml
|
template: infrastructure/cloudformation/dt/top.yaml
|
||||||
capabilities: "CAPABILITY_NAMED_IAM,CAPABILITY_IAM"
|
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 }}
|
parameter-overrides: VpcId=${{ secrets.VPC_ID }},SubDomain=stage,Domain=${{ secrets.DOMAIN }},environment=stage,DockerTag=stage,release=stage,PublicSubnets=${{ secrets.SUBNET_IDS }}
|
6
.github/workflows/push_dev.yml
vendored
6
.github/workflows/push_dev.yml
vendored
@ -19,8 +19,8 @@ jobs:
|
|||||||
args: --follow-symlinks --delete
|
args: --follow-symlinks --delete
|
||||||
env:
|
env:
|
||||||
SOURCE_DIR: infrastructure/cloudformation
|
SOURCE_DIR: infrastructure/cloudformation
|
||||||
AWS_REGION: "us-east-1"
|
AWS_REGION: "us-east-2"
|
||||||
DEST_DIR: dt/develop/cloudformation
|
DEST_DIR: develop/cloudformation
|
||||||
AWS_S3_BUCKET: sumu-stacks
|
AWS_S3_BUCKET: dt-deployment-bucket
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@ -127,9 +127,9 @@ jobs:
|
|||||||
args: --follow-symlinks --delete
|
args: --follow-symlinks --delete
|
||||||
env:
|
env:
|
||||||
SOURCE_DIR: infrastructure/cloudformation
|
SOURCE_DIR: infrastructure/cloudformation
|
||||||
AWS_REGION: "us-east-1"
|
AWS_REGION: "us-east-2"
|
||||||
DEST_DIR: dt/production/cloudformation
|
DEST_DIR: production/cloudformation
|
||||||
AWS_S3_BUCKET: sumu-stacks
|
AWS_S3_BUCKET: dt-deployment-bucket
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
- name: Configure AWS Credentials
|
- name: Configure AWS Credentials
|
||||||
@ -137,7 +137,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
aws-region: us-east-1
|
aws-region: us-east-2
|
||||||
- name: Deploy to AWS CloudFormation
|
- name: Deploy to AWS CloudFormation
|
||||||
uses: aws-actions/aws-cloudformation-github-deploy@v1
|
uses: aws-actions/aws-cloudformation-github-deploy@v1
|
||||||
with:
|
with:
|
||||||
|
30
README.md
30
README.md
@ -1,9 +1,29 @@
|
|||||||
# ludum-dare-46
|

|
||||||
|

|
||||||
|
|
||||||
## Client
|
# Defend Together
|
||||||
|
|
||||||
The client is build via Godot v3.2.1
|

|
||||||
|
|
||||||
## Server
|
Defend Together is a mutiplayer demo game project created in C++ with the [ENet Library](http://enet.bespin.org/) and [Godot v3.2.1](https://godotengine.org/)
|
||||||
|
|
||||||
The server is a C++ app built using ENet
|
See the [wiki](https://github.com/josephbmanley/defend-together/wiki) for project documentation
|
||||||
|
|
||||||
|
Checkout the project on [Itch.io](https://josephbmanley.itch.io/defend-together)
|
||||||
|
|
||||||
|
View nested `ReadMe.md` files:
|
||||||
|
- [Client](blob/master/client)
|
||||||
|
- [Server](blob/master/server)
|
||||||
|
---
|
||||||
|
|
||||||
|
This project highlights the following:
|
||||||
|
|
||||||
|
- Continuous Integration & Continuous Deployment
|
||||||
|
|
||||||
|
- UDP Server Networking
|
||||||
|
|
||||||
|
- Utilization of Cloud Services in development
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|

|
@ -1,4 +1,4 @@
|
|||||||
# LD46 Client
|
# Defend Together Client
|
||||||
|
|
||||||
## Build Requirements
|
## Build Requirements
|
||||||
|
|
||||||
@ -6,4 +6,4 @@ Godot 3.2.1-stable
|
|||||||
|
|
||||||
### Godot Modules
|
### Godot Modules
|
||||||
|
|
||||||
- [GDNet3](https://github.com/perdugames/gdnet3)
|
- [GDNet3](https://github.com/josephbmanley/gdnet3)
|
@ -1,7 +1,8 @@
|
|||||||
[gd_scene load_steps=6 format=2]
|
[gd_scene load_steps=7 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://assets/images/character/iron_player.png" type="Texture" id=1]
|
[ext_resource path="res://assets/images/character/iron_player.png" type="Texture" id=1]
|
||||||
[ext_resource path="res://scripts/entities/Player.gd" type="Script" id=2]
|
[ext_resource path="res://scripts/entities/Player.gd" type="Script" id=2]
|
||||||
|
[ext_resource path="res://scripts/entities/Camera.gd" type="Script" id=3]
|
||||||
|
|
||||||
[sub_resource type="RectangleShape2D" id=1]
|
[sub_resource type="RectangleShape2D" id=1]
|
||||||
|
|
||||||
@ -36,3 +37,4 @@ __meta__ = {
|
|||||||
|
|
||||||
[node name="Camera" type="Camera2D" parent="."]
|
[node name="Camera" type="Camera2D" parent="."]
|
||||||
zoom = Vector2( 0.5, 0.5 )
|
zoom = Vector2( 0.5, 0.5 )
|
||||||
|
script = ExtResource( 3 )
|
||||||
|
35
client/scripts/entities/Camera.gd
Normal file
35
client/scripts/entities/Camera.gd
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
extends Camera2D
|
||||||
|
|
||||||
|
#-------------#
|
||||||
|
# Camera Zoom #
|
||||||
|
#-------------#
|
||||||
|
export var zoomDecelration = 4
|
||||||
|
export var zoomCapSpeed = 0.125
|
||||||
|
|
||||||
|
export var minZoom = 0.25
|
||||||
|
export var maxZoom = 0.5
|
||||||
|
var zoomChange = 0
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
zoom.x = (minZoom + maxZoom) / 2
|
||||||
|
zoom.y = (minZoom + maxZoom) / 2
|
||||||
|
|
||||||
|
func _process(delta):
|
||||||
|
CameraZoom(delta)
|
||||||
|
|
||||||
|
func _input(event):
|
||||||
|
if event is InputEventMouseButton:
|
||||||
|
if event.is_pressed():
|
||||||
|
if event.button_index == BUTTON_WHEEL_UP:
|
||||||
|
zoomChange = -zoomCapSpeed
|
||||||
|
if event.button_index == BUTTON_WHEEL_DOWN:
|
||||||
|
zoomChange = zoomCapSpeed
|
||||||
|
|
||||||
|
func CameraZoom(delta):
|
||||||
|
if(zoomChange > 0):
|
||||||
|
zoomChange = clamp(zoomChange - zoomDecelration * delta, 0, zoomCapSpeed)
|
||||||
|
elif(zoomChange < 0):
|
||||||
|
zoomChange = clamp(zoomChange + zoomDecelration * delta, -zoomCapSpeed, 0)
|
||||||
|
|
||||||
|
zoom.x = clamp(zoom.x + zoomChange, minZoom, maxZoom)
|
||||||
|
zoom.y = clamp(zoom.y + zoomChange, minZoom, maxZoom)
|
@ -23,6 +23,7 @@ var packetQueue = []
|
|||||||
var error_info = ""
|
var error_info = ""
|
||||||
var world_data : String = ""
|
var world_data : String = ""
|
||||||
|
|
||||||
|
var last_move_time = null
|
||||||
|
|
||||||
var connection_timer : Timer
|
var connection_timer : Timer
|
||||||
|
|
||||||
@ -111,9 +112,12 @@ func send_packet(packet : PoolByteArray, channel = 0, pck_type = GDNetMessage.RE
|
|||||||
packetQueue.append({'channel':channel, 'packet' : packet, 'type' : pck_type})
|
packetQueue.append({'channel':channel, 'packet' : packet, 'type' : pck_type})
|
||||||
|
|
||||||
func move_player(x,y):
|
func move_player(x,y):
|
||||||
var pckt : PoolByteArray = ("3|" + str(x) + "," + str(y)).to_ascii()
|
if last_move_time == null || OS.get_ticks_msec() - last_move_time > 50:
|
||||||
|
|
||||||
|
var pckt : PoolByteArray = ("3|" + str(x) + "," + str(y)).to_ascii()
|
||||||
|
|
||||||
send_packet(pckt, 0, GDNetMessage.SEQUENCED)
|
send_packet(pckt, 0, GDNetMessage.SEQUENCED)
|
||||||
|
last_move_time = OS.get_ticks_msec()
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
process_events()
|
process_events()
|
||||||
|
Submodule infrastructure/cloudformation/cluster updated: a7d7961c27...2826c2eb03
@ -61,7 +61,7 @@ Resources:
|
|||||||
Condition: CreateDns
|
Condition: CreateDns
|
||||||
Type: AWS::CloudFormation::Stack
|
Type: AWS::CloudFormation::Stack
|
||||||
Properties:
|
Properties:
|
||||||
TemplateURL: !Sub 'https://s3.${AWS::Region}.amazonaws.com/sumu-stacks/dt/${release}/cloudformation/dt/dns.yaml'
|
TemplateURL: !Sub 'https://s3.${AWS::Region}.amazonaws.com/dt-deployment-bucket/${release}/cloudformation/dt/dns.yaml'
|
||||||
Parameters:
|
Parameters:
|
||||||
environment: !Ref environment
|
environment: !Ref environment
|
||||||
Domain: !Ref Domain
|
Domain: !Ref Domain
|
||||||
@ -74,7 +74,7 @@ Resources:
|
|||||||
LoadBalancing:
|
LoadBalancing:
|
||||||
Type: AWS::CloudFormation::Stack
|
Type: AWS::CloudFormation::Stack
|
||||||
Properties:
|
Properties:
|
||||||
TemplateURL: !Sub 'https://s3.${AWS::Region}.amazonaws.com/sumu-stacks/dt/${release}/cloudformation/dt/load_balancing.yaml'
|
TemplateURL: !Sub 'https://s3.${AWS::Region}.amazonaws.com/dt-deployment-bucket/${release}/cloudformation/dt/load_balancing.yaml'
|
||||||
Parameters:
|
Parameters:
|
||||||
environment: !Ref environment
|
environment: !Ref environment
|
||||||
release: !Ref release
|
release: !Ref release
|
||||||
@ -84,7 +84,7 @@ Resources:
|
|||||||
EcsCluster:
|
EcsCluster:
|
||||||
Type: AWS::CloudFormation::Stack
|
Type: AWS::CloudFormation::Stack
|
||||||
Properties:
|
Properties:
|
||||||
TemplateURL: !Sub 'https://s3.${AWS::Region}.amazonaws.com/sumu-stacks/dt/${release}/cloudformation/cluster/top.yaml'
|
TemplateURL: !Sub 'https://s3.${AWS::Region}.amazonaws.com/dt-deployment-bucket/${release}/cloudformation/cluster/top.yaml'
|
||||||
Parameters:
|
Parameters:
|
||||||
Environment: !Ref environment
|
Environment: !Ref environment
|
||||||
VpcId: !Ref VpcId
|
VpcId: !Ref VpcId
|
||||||
@ -97,7 +97,7 @@ Resources:
|
|||||||
TaskDefinition:
|
TaskDefinition:
|
||||||
Type: AWS::CloudFormation::Stack
|
Type: AWS::CloudFormation::Stack
|
||||||
Properties:
|
Properties:
|
||||||
TemplateURL: !Sub 'https://s3.${AWS::Region}.amazonaws.com/sumu-stacks/dt/${release}/cloudformation/dt/task.yaml'
|
TemplateURL: !Sub 'https://s3.${AWS::Region}.amazonaws.com/dt-deployment-bucket/${release}/cloudformation/dt/task.yaml'
|
||||||
Parameters:
|
Parameters:
|
||||||
environment: !Ref environment
|
environment: !Ref environment
|
||||||
LogGroupName: !Ref LogGroup
|
LogGroupName: !Ref LogGroup
|
||||||
|
@ -1,16 +1,31 @@
|
|||||||
# LD46 Server
|
# Defend Together Server
|
||||||
|
|
||||||
|
Here are the instructions below for running the server locally on linux.
|
||||||
|
|
||||||
## Build Requirements
|
## Build Requirements
|
||||||
|
|
||||||
Enet development files:
|
_Instructions are for Fedora Linux_
|
||||||
|
|
||||||
`dnf install enet-devel`
|
Install dependencies:
|
||||||
|
|
||||||
|
`dnf install enet-devel g++`
|
||||||
G++
|
|
||||||
|
|
||||||
`dnf install g++`
|
|
||||||
|
|
||||||
For testing:
|
For testing:
|
||||||
|
|
||||||
`dnf install gtest gmock gmock-devel gtest-devel`
|
`dnf install gtest gmock gmock-devel gtest-devel`
|
||||||
|
|
||||||
|
## Building Server
|
||||||
|
|
||||||
|
Within the server directory run: `bash build.sh`
|
||||||
|
|
||||||
|
## Running Tests
|
||||||
|
|
||||||
|
Within the server directory run: `bash run_tests.sh`
|
||||||
|
|
||||||
|
## Running Server
|
||||||
|
|
||||||
|
If you have already built the server, you can run the binary location at `builds/server.out`, otherwise within the server directory, you can run `run_build.sh` to build and run the server.
|
||||||
|
|
||||||
|
# Running in Docker
|
||||||
|
|
||||||
|
A `Dockerfile` is provided in this project. So you can run `docker build -t defend-together .` and then `docker run -p 7777:7777 defend-together` to run locally on port `7777` in docker.
|
@ -32,9 +32,25 @@ void * console_logic(void *)
|
|||||||
{
|
{
|
||||||
game_is_running = false;
|
game_is_running = false;
|
||||||
}
|
}
|
||||||
|
else if (input_string.length() > 2 && input_string.substr(0,3) == "say")
|
||||||
|
{
|
||||||
|
if(input_string.length() > 4)
|
||||||
|
{
|
||||||
|
gameserver::BroadcastMessage("Server: " + input_string.substr(4));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "Must pass a valid message!" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cout << "Invalid console command!" << std::endl;
|
std::cout << std::endl
|
||||||
|
<< "Invalid console command!" << std::endl
|
||||||
|
<< "Valid commands are:" << std::endl
|
||||||
|
<< "stop" << std::endl
|
||||||
|
<< "say [message]" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,37 @@ namespace gameserver
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SendPlayerMessage(ENetPeer* peer, std::string message)
|
||||||
|
{
|
||||||
|
const char* data = message.c_str();
|
||||||
|
|
||||||
|
ENetPacket* packet = enet_packet_create(data, strlen(data) + 1, ENET_PACKET_FLAG_RELIABLE);
|
||||||
|
enet_peer_send(peer, 1, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SendPlayerMessage(std::string username, std::string message)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < MAX_PLAYERS; i++)
|
||||||
|
{
|
||||||
|
if(usernames[i] == username)
|
||||||
|
{
|
||||||
|
SendPlayerMessage(&(server->peers[i]), message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BroadcastMessage(std::string message)
|
||||||
|
{
|
||||||
|
const char* data = message.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);
|
||||||
|
}
|
||||||
|
|
||||||
void ProcessChatMessage(ENetEvent* event)
|
void ProcessChatMessage(ENetEvent* event)
|
||||||
{
|
{
|
||||||
int peer_id = event->peer -> incomingPeerID;
|
int peer_id = event->peer -> incomingPeerID;
|
||||||
@ -131,12 +162,8 @@ namespace gameserver
|
|||||||
std::string chat_message;
|
std::string chat_message;
|
||||||
std::getline(ss, chat_message, '\n');
|
std::getline(ss, chat_message, '\n');
|
||||||
std::string resp = "<" + usernames[peer_id] + "> " + chat_message;
|
std::string resp = "<" + usernames[peer_id] + "> " + chat_message;
|
||||||
const char* data = resp.c_str();
|
BroadcastMessage(resp);
|
||||||
|
|
||||||
std::cout << data << std::endl;
|
|
||||||
|
|
||||||
ENetPacket* packet = enet_packet_create(data, strlen(data) + 1, ENET_PACKET_FLAG_RELIABLE);
|
|
||||||
enet_host_broadcast(server, 1, packet);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,7 +211,7 @@ namespace gameserver
|
|||||||
{
|
{
|
||||||
while(game_is_running)
|
while(game_is_running)
|
||||||
{
|
{
|
||||||
usleep(50000);
|
usleep(50000*3);
|
||||||
std::string data_string = "2|"+gamemap.world_tick();
|
std::string data_string = "2|"+gamemap.world_tick();
|
||||||
const char* data = data_string.c_str();
|
const char* data = data_string.c_str();
|
||||||
ENetPacket* packet = enet_packet_create(data, strlen(data), ENET_PACKET_FLAG_UNSEQUENCED);
|
ENetPacket* packet = enet_packet_create(data, strlen(data), ENET_PACKET_FLAG_UNSEQUENCED);
|
||||||
|
Reference in New Issue
Block a user