Skip to content

Commit

Permalink
Merge pull request #73 from agentsofthesystem/develop
Browse files Browse the repository at this point in the history
Improvments - New Server Support & Testing
  • Loading branch information
jreed1701 committed Jun 18, 2024
2 parents be78635 + 85a172f commit 26a7d58
Show file tree
Hide file tree
Showing 25 changed files with 871 additions and 18 deletions.
6 changes: 6 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[run]
omit =
*__init__*
tests/*
application/debugger.py
application/alembic/*
5 changes: 5 additions & 0 deletions .github/workflows/develop-branch-actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ jobs:
exclude: "tests/*,doc/*,scripts/*"
max-line-length: "100"

- name: pytest
run: |
coverage run -m pytest
coverage report --fail-under 40
build_develop_windows_exe:

runs-on: windows-latest
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/every-other-branch-actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ jobs:
exclude: "tests/*,doc/*,scripts/*"
max-line-length: "100"

- name: pytest
run: |
coverage run -m pytest
coverage report --fail-under 40
build_other_windows_exe:

runs-on: windows-latest
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/main-branch-after-merge-actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ jobs:
exclude: "tests/*,doc/*,scripts/*"
max-line-length: "100"

- name: pytest
run: |
coverage run -m pytest
coverage report --fail-under 40
- name: Run PyInstaller
run: |
python package.py
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/main-branch-pr-actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ jobs:
exclude: "tests/*,doc/*,scripts/*"
max-line-length: "100"

- name: pytest
run: |
coverage run -m pytest
coverage report --fail-under 40
build_main_pr_windows_exe:

runs-on: windows-latest
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Hidden folder/file types.
.coverage
htmlcov/
venv/*
.env
*__pycache__*
Expand Down
2 changes: 1 addition & 1 deletion application/api/v1/blueprints/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def _get_all(self):
@authorization_required
def get(self, game_name=None, game_arg_id=None, argument_name=None):
page = request.args.get("page", 1, type=int)
per_page = min(request.args.get("per_page", 10, type=int), 10000)
per_page = min(request.args.get("per_page", 1000, type=int), 10000)

if game_arg_id:
qry = self._get_argument(game_arg_id)
Expand Down
20 changes: 14 additions & 6 deletions application/common/authorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@
from application.models.tokens import Tokens


def _get_token(bearer_token: str) -> Tokens:
token_lookup = Tokens.query.filter_by(
token_active=True, token_value=bearer_token
).first()
return token_lookup


def _get_setting(setting_name: str) -> Settings:
setting_lookup = Settings.query.filter_by(setting_name=setting_name).first()
return setting_lookup


def _verify_bearer_token(request: Request) -> int:
"""This is the bearer token gauntlet.
The requests only goal is to get through all of the checks.
Expand All @@ -25,17 +37,13 @@ def _verify_bearer_token(request: Request) -> int:
bearer_token = auth.split("Bearer")[-1].strip()

# Make sure it's there first...
token_lookup = Tokens.query.filter_by(
token_active=True, token_value=bearer_token
).first()
token_lookup = _get_token(bearer_token)

if token_lookup is None:
return 403

# Next decode this bad thing...
secret_obj = Settings.query.filter_by(
setting_name=constants.SETTING_NAME_APP_SECRET
).first()
secret_obj = _get_setting(constants.SETTING_NAME_APP_SECRET)

try:
decoded_token = jwt.decode(
Expand Down
7 changes: 5 additions & 2 deletions application/common/game_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,15 @@ def _get_argument_list(self) -> []:
def _get_argument_dict(self) -> []:
return self._game_args

def _get_command_str(self) -> str:
def _get_command_str(self, args_only=False) -> str:
arg_string = ""
for _, arg in self._game_args.items():
arg_string += str(arg) + " "

return f"{self._game_executable} {arg_string}"
if args_only:
return arg_string
else:
return f"{self._game_executable} {arg_string}"

def _rebuild_arguments_dict(self) -> None:
game_qry = Games.query.filter_by(game_name=self._game_name)
Expand Down
4 changes: 3 additions & 1 deletion application/common/steam_manifest_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ def read_dir(dir: str):

for file in os.listdir(dir):
if file.endswith(".acf"):
acf = read_acf(dir + file)
# acf = read_dir(dir)
acf = read_acf(os.path.join(dir, file))
# acf = read_acf(dir + file)
steamapps[acf["appid"]] = acf

return steamapps
Expand Down
2 changes: 1 addition & 1 deletion application/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class DefaultConfig:

# NGINX Settings
NGINX_DEFAULT_HOSTNAME = "localhost"
NGINX_DEFAULT_PORT = "5312"
NGINX_DEFAULT_PORT = "53128"
NGINX_DEFAULT_ENABLED = True

# Designate where the database file is stored based on platform.
Expand Down
177 changes: 177 additions & 0 deletions application/games/ark_game.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import os
import time

from jinja2 import Environment, FileSystemLoader

from application.common import logger, constants
from application.common.game_argument import GameArgument
from application.common.game_base import BaseGame
from application.common.toolbox import _get_proc_by_name, get_resources_dir
from application.extensions import DATABASE
from application.models.games import Games


class ArkGame(BaseGame):
def __init__(self, defaults_dict: dict = {}) -> None:
super(ArkGame, self).__init__(defaults_dict)

self._game_name = "ark"
self._game_pretty_name = "Ark: Survival Evolved"
self._game_executable = "ShooterGameServer.exe"
self._game_steam_id = "376030"
self._game_info_url = "https://ark.fandom.com/wiki/Dedicated_server_setup"

"""
Reference:
start ShooterGameServer.exe TheIsland?listen?SessionName=<server_name>
?ServerPassword=<join_password>
?ServerAdminPassword=<admin_password>?Port=<port>
?QueryPort=<query_port>?MaxPlayers=<max_players>
exit
"""

# Add Args here, can update later.
self._add_argument(
GameArgument(
"server_name",
value="MyArkServer",
required=True,
use_quotes=False,
is_permanent=True,
)
)

self._add_argument(
GameArgument(
"join_password",
value="abc123",
required=True,
is_permanent=True,
)
)

self._add_argument(
GameArgument(
"admin_password",
value="abc123",
required=True,
is_permanent=True,
)
)

self._add_argument(
GameArgument(
"port",
value=7777,
required=True,
is_permanent=True,
)
)

self._add_argument(
GameArgument(
"query_port",
value=27015,
required=True,
is_permanent=True,
)
)

self._add_argument(
GameArgument(
"max_players",
value=4,
required=True,
is_permanent=True,
)
)

def startup(self) -> None:
# Run base class checks
super().startup()

# Get individual arguments for this game
arguments = self._get_argument_dict()

server_name = arguments["server_name"]._value
join_password = arguments["join_password"]._value
admin_password = arguments["admin_password"]._value
port = arguments["port"]._value
query_port = arguments["query_port"]._value
max_players = arguments["max_players"]._value

# Create a formatted batch file.
env = Environment(loader=FileSystemLoader(get_resources_dir(__file__)))
template = env.get_template("start_ark_server_template.bat.j2")
output_from_parsed_template = template.render(
GAME_STEAM_ID=self._game_steam_id,
GAME_NAME=self._game_name,
server_name=server_name,
join_password=join_password,
admin_password=admin_password,
port=port,
query_port=query_port,
max_players=max_players,
)

# Print the formatted jinja
logger.debug(output_from_parsed_template)

# In theory, the software has already check that the game is installed, so no check/guard
# needed.
game_qry = Games.query.filter_by(game_steam_id=self._game_steam_id)
game_obj = game_qry.first()
game_install_dir = game_obj.game_install_dir

# Need game install location to write batch file.
full_path_startup_script = os.path.join(
game_install_dir, constants.STARTUP_BATCH_FILE_NAME
)

game_working_dir = os.path.join(
game_install_dir, "ShooterGame", "Binaries", "Win64"
)

# If file exists, remove it.
if os.path.exists(full_path_startup_script):
os.remove(full_path_startup_script)

# Write the batch file.
with open(full_path_startup_script, "w") as myfile:
myfile.write(output_from_parsed_template)

# Call the batch file on another process as to not block this one.
command = f'START /MIN CMD.EXE /C "{full_path_startup_script}"'
result = self._run_game(command, game_working_dir)

time.sleep(1)

process = _get_proc_by_name(self._game_executable)

logger.info(result)
logger.info("Process:")
logger.info(process)

update_dict = {"game_pid": int(process.pid)}

game_qry.update(update_dict)
DATABASE.session.commit()

def shutdown(self) -> None:
game_qry = Games.query.filter_by(game_steam_id=self._game_steam_id)
game_obj = game_qry.first()
game_pid = game_obj.game_pid

process = _get_proc_by_name(self._game_executable)

if process:
logger.info(process)
logger.info(game_pid)

process.terminate()
process.wait()

update_dict = {"game_pid": None}
game_qry.update(update_dict)
DATABASE.session.commit()
6 changes: 6 additions & 0 deletions application/games/resources/start_ark_server_template.bat.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@echo off
set SteamAppId=346110
echo "Starting {{GAME_NAME}} Dedicated Server - PRESS CTRL-C to exit"

start ShooterGameServer.exe TheIsland?listen?SessionName={{server_name}}?ServerPassword={{join_password}}?ServerAdminPassword={{admin_password}}?Port={{port}}?QueryPort={{query_port}}?MaxPlayers={{max_players}} -server -log
exit
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@echo off
set SteamAppId=526870
echo "Starting {{GAME_NAME}} Dedicated Server - PRESS CTRL-C to exit"

@echo on
{{GAME_COMMAND}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@echo off
set SteamAppId=892970
echo "Starting {{GAME_NAME}} Dedicated Server - PRESS CTRL-C to exit"\

REM Tip: Make a local copy of this script to avoid it being overwritten by steam.
REM NOTE: Minimum password length is 5 characters & Password cant be in the server name.
REM NOTE: You need to make sure the ports 2456-2458 is being forwarded to your server through your local router & firewall.
valheim_server -nographics -batchmode {{GAME_ARGUMENTS}}
Loading

0 comments on commit 26a7d58

Please sign in to comment.