Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor game options handling / Issue/#859 game title constraints #992

Merged
merged 6 commits into from
Jan 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ aio_pika = "~=8.2"
aiocron = "*"
aiohttp = "*"
aiomysql = {git = "https://github.com/aio-libs/aiomysql"}
cachetools = "*"
docopt = "*"
humanize = ">=2.6.0"
maxminddb = "*"
Expand Down
11 changes: 10 additions & 1 deletion Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

77 changes: 62 additions & 15 deletions server/game_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
from typing import Optional, Union, ValuesView

import aiocron
from sqlalchemy import select
from cachetools import LRUCache
from sqlalchemy import func, select

from server.config import config

from . import metrics
from .core import Service
from .db import FAFDatabase
from .db.models import game_featuredMods
from .db.models import game_featuredMods, map_version
from .decorators import with_logger
from .exceptions import DisabledError
from .games import (
Expand All @@ -30,6 +31,7 @@
from .message_queue_service import MessageQueueService
from .players import Player
from .rating_service import RatingService
from .types import MAP_DEFAULT, Map, NeroxisGeneratedMap


@with_logger
Expand Down Expand Up @@ -57,12 +59,15 @@
self._allow_new_games = False
self._drain_event = None

# Populated below in really_update_static_ish_data.
# Populated below in update_data.
self.featured_mods = dict()

# A set of mod ids that are allowed in ranked games
self.ranked_mods: set[str] = set()

# A cache of map_version info needed by Game
self.map_info_cache = LRUCache(maxsize=256)

# The set of active games
self._games: dict[int, Game] = dict()

Expand Down Expand Up @@ -96,14 +101,16 @@
time we need, but which can in principle change over time.
"""
async with self._db.acquire() as conn:
rows = await conn.execute(select(
game_featuredMods.c.id,
game_featuredMods.c.gamemod,
game_featuredMods.c.name,
game_featuredMods.c.description,
game_featuredMods.c.publish,
game_featuredMods.c.order
).select_from(game_featuredMods))
rows = await conn.execute(
select(
game_featuredMods.c.id,
game_featuredMods.c.gamemod,
game_featuredMods.c.name,
game_featuredMods.c.description,
game_featuredMods.c.publish,
game_featuredMods.c.order
)
)

for row in rows:
self.featured_mods[row.gamemod] = FeaturedMod(
Expand All @@ -115,11 +122,51 @@
row.order
)

result = await conn.execute("SELECT uid FROM table_mod WHERE ranked = 1")
result = await conn.execute(
"SELECT uid FROM table_mod WHERE ranked = 1"
)

# Turn resultset into a list of uids
self.ranked_mods = {row.uid for row in result}

async def get_map(self, folder_name: str) -> Map:
folder_name = folder_name.lower()
filename = f"maps/{folder_name}.zip"

map = self.map_info_cache.get(filename)

Check warning on line 136 in server/game_service.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

server/game_service.py#L136

Redefining built-in 'map'
if map is not None:
return map

async with self._db.acquire() as conn:
result = await conn.execute(
select(
map_version.c.id,
map_version.c.filename,
map_version.c.ranked,
)
.where(
func.lower(map_version.c.filename) == filename
)
)
row = result.fetchone()
if not row:
# The map requested is not in the database. This is fine as
# players may be using privately shared or generated maps that
# are not in the vault.
return Map(
id=None,
folder_name=folder_name,
ranked=NeroxisGeneratedMap.is_neroxis_map(folder_name),
)

map = Map(
id=row.id,
folder_name=folder_name,
ranked=row.ranked
)
self.map_info_cache[filename] = map
return map

def mark_dirty(self, obj: Union[Game, MatchmakerQueue]):
if isinstance(obj, Game):
self._dirty_games.add(obj)
Expand Down Expand Up @@ -150,7 +197,7 @@
visibility=VisibilityState.PUBLIC,
host: Optional[Player] = None,
name: Optional[str] = None,
mapname: Optional[str] = None,
map: Map = MAP_DEFAULT,

Check warning on line 200 in server/game_service.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

server/game_service.py#L200

Redefining built-in 'map'
password: Optional[str] = None,
matchmaker_queue_id: Optional[int] = None,
**kwargs
Expand All @@ -164,10 +211,10 @@
game_id = self.create_uid()
game_args = {
"database": self._db,
"id_": game_id,
"id": game_id,
"host": host,
"name": name,
"map_": mapname,
"map": map,
"game_mode": game_mode,
"game_service": self,
"game_stats_service": self.game_stats_service,
Expand Down
29 changes: 5 additions & 24 deletions server/gameconnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
GameConnectionState,
GameError,
GameState,
ValidityState,
Victory
ValidityState
)
from .games.typedefs import FA
from .player_service import PlayerService
Expand Down Expand Up @@ -134,7 +133,7 @@ async def _handle_lobby_state(self):
"""
player_state = self.player.state
if player_state == PlayerState.HOSTING:
await self.send_HostGame(self.game.map_folder_name)
await self.send_HostGame(self.game.map.folder_name)
self.game.set_hosted()
# If the player is joining, we connect him to host
# followed by the rest of the players.
Expand Down Expand Up @@ -228,25 +227,7 @@ async def handle_game_option(self, key: str, value: Any):
if not self.is_host():
return

if key == "Victory":
self.game.gameOptions["Victory"] = Victory.__members__.get(
value.upper(), None
)
else:
self.game.gameOptions[key] = value

if key == "Slots":
self.game.max_players = int(value)
elif key == "ScenarioFile":
raw = repr(value)
self.game.map_scenario_path = \
raw.replace("\\", "/").replace("//", "/").replace("'", "")
self.game.map_file_path = "maps/{}.zip".format(
self.game.map_scenario_path.split("/")[2].lower()
)
elif key == "Title":
with contextlib.suppress(ValueError):
self.game.name = value
await self.game.game_options.set_option(key, value)

self._mark_dirty()

Expand Down Expand Up @@ -339,13 +320,13 @@ async def handle_operation_complete(
async with self._db.acquire() as conn:
result = await conn.execute(
select(coop_map.c.id).where(
coop_map.c.filename == self.game.map_file_path
coop_map.c.filename == self.game.map.file_path
)
)
row = result.fetchone()
if not row:
self._logger.debug(
"can't find coop map: %s", self.game.map_file_path
"can't find coop map: %s", self.game.map.file_path
)
return
mission = row.id
Expand Down
3 changes: 2 additions & 1 deletion server/games/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from .coop import CoopGame
from .custom_game import CustomGame
from .game import Game, GameError
from .game import Game, GameError, GameOptions
from .ladder_game import LadderGame
from .typedefs import (
FeaturedModType,
Expand Down Expand Up @@ -37,6 +37,7 @@ class FeaturedMod(NamedTuple):
"Game",
"GameConnectionState",
"GameError",
"GameOptions",
"GameState",
"GameType",
"InitMode",
Expand Down
2 changes: 1 addition & 1 deletion server/games/coop.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

self.validity = ValidityState.COOP_NOT_RANKED
self.gameOptions.update({
self.game_options.update({
"Victory": Victory.SANDBOX,
"TeamSpawn": "fixed",
"RevealedCivilians": "No",
Expand Down
4 changes: 2 additions & 2 deletions server/games/custom_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
init_mode = InitMode.NORMAL_LOBBY
game_type = GameType.CUSTOM

def __init__(self, id_, *args, **kwargs):
def __init__(self, id, *args, **kwargs):

Check warning on line 15 in server/games/custom_game.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

server/games/custom_game.py#L15

Redefining built-in 'id'
new_kwargs = {
"rating_type": RatingType.GLOBAL,
"setup_timeout": 30
}
new_kwargs.update(kwargs)
super().__init__(id_, *args, **new_kwargs)
super().__init__(id, *args, **new_kwargs)

async def _run_pre_rate_validity_checks(self):
limit = len(self.players) * 60
Expand Down
Loading