Skip to content

Commit 6138b9d

Browse files
committed
2026-01-19T2004Z
1 parent 1b1615f commit 6138b9d

File tree

8 files changed

+172
-116
lines changed

8 files changed

+172
-116
lines changed

Source/launcher/subparsers/args_launch_mode/player.py

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Standard library imports
22
import argparse
3+
import itertools
34
import logger
45

56
# Local application imports
@@ -18,36 +19,36 @@ def _(
1819
subparser.add_argument(
1920
'--rcc_host', '--host', '-rh', '-h',
2021
type=str,
21-
nargs='?',
22-
default=None,
22+
nargs='*',
23+
default=[],
2324
help='Hostname or IP address to connect this program to the RCC server.',
2425
)
2526
subparser.add_argument(
2627
'--rcc_port', '--port', '-rp', '-p',
2728
type=int,
28-
nargs='?',
29-
default=None,
29+
nargs='*',
30+
default=[],
3031
help='Port number to connect this program to the RCC server.',
3132
)
3233
subparser.add_argument(
3334
'--web_host', '--webserver_host', '-wh',
3435
type=str,
35-
nargs='?',
36-
default=None,
36+
nargs='*',
37+
default=[],
3738
help='Hostname or IP address to connect this program to the web server.',
3839
)
3940
subparser.add_argument(
4041
'--web_port', '--webserver_port', '-wp',
4142
type=int,
42-
nargs='?',
43-
default=None,
43+
nargs='*',
44+
default=[],
4445
help='Port number to connect this program to the web server.',
4546
)
4647
subparser.add_argument(
4748
'--user_code', '-u',
4849
type=str,
49-
nargs='?',
50-
default=None,
50+
nargs='*',
51+
default=[],
5152
help='Determines the user code for the player which joins the server.\nUser codes derive a user name, user iden number, and other characteristics of any particular player.',
5253
)
5354
subparser.add_argument(
@@ -58,7 +59,7 @@ def _(
5859
subparser.add_argument(
5960
'--loud',
6061
action='store_true',
61-
help='Makes the client\'s output file log very verbosely.',
62+
help='Makes the client\'s output log file very verbose.',
6263
)
6364

6465

@@ -82,20 +83,6 @@ def _(
8283
args_ns: argparse.Namespace,
8384
) -> list[logic.base_entry]:
8485

85-
web_host: str | None = args_ns.web_host
86-
rcc_host: str | None = args_ns.rcc_host
87-
if web_host is None:
88-
web_host = rcc_host or 'localhost'
89-
if rcc_host is None:
90-
rcc_host = web_host or 'localhost'
91-
92-
web_port: int | None = args_ns.web_port
93-
rcc_port: int | None = args_ns.rcc_port
94-
if web_port is None:
95-
web_port = rcc_port or 2005
96-
if rcc_port is None:
97-
rcc_port = web_port or 2005
98-
9986
log_filter = gen_log_filter(
10087
parser, args_ns,
10188
)
@@ -106,7 +93,12 @@ def _(
10693
rcc_port=rcc_port,
10794
web_host=web_host,
10895
web_port=web_port,
109-
user_code=args_ns.user_code,
96+
user_code=user_code,
11097
logger=log_filter,
111-
),
98+
)
99+
for (
100+
web_host, rcc_host, web_port, rcc_port, user_code,
101+
) in itertools.zip_longest(
102+
args_ns.web_host, args_ns.rcc_host, args_ns.web_port, args_ns.rcc_port, args_ns.user_code,
103+
)
112104
]

Source/launcher/subparsers/args_launch_mode/server.py

Lines changed: 90 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
# Standard library imports
22
import argparse
33
import dataclasses
4+
import itertools
45

56
# Local application imports
67
import game_config as config
78
import logger.flog_table
89
import logger.bcolors
910
import util.resource
11+
import util.const
1012
import logger
1113

1214
from routines import player, rcc, web
@@ -27,41 +29,43 @@ def subparse(
2729
'--config',
2830
'-cp',
2931
type=str,
30-
nargs='?',
31-
default=util.resource.DEFAULT_CONFIG_PATH,
32+
nargs='*',
33+
default=[util.resource.DEFAULT_CONFIG_PATH],
3234
help='Game-specific options; defaults to ./GameConfig.toml. Please review each option before starting a new server up.',
3335
)
3436
place_thing.add_argument(
3537
'--place_path',
3638
'--place',
3739
'-pl',
3840
type=str,
39-
nargs='?',
40-
default=None,
41+
nargs='*',
42+
default=[],
4143
help='Path to the place file to be loaded. Argument `config_path` can\'t be passed in when using this option.',
4244
)
4345
ip_version = subparser.add_mutually_exclusive_group()
4446

4547
ip_version.add_argument(
4648
'--ipv4-only',
4749
action='store_true',
48-
help='Run server using IPv4 only.')
50+
help='Run server using IPv4 only.',
51+
)
4952
ip_version.add_argument(
5053
'--ipv6-only',
5154
action='store_true',
52-
help='Run server using IPv6 only.')
55+
help='Run server using IPv6 only.',
56+
)
5357
subparser.add_argument(
5458
'--rcc_port', '--port', '-rp', '-p',
5559
type=int,
56-
nargs='?',
57-
default=None,
60+
nargs='*',
61+
default=[],
5862
help='Port number for the RCC server to run from.',
5963
)
6064
subparser.add_argument(
6165
'--web_port', '--webserver_port', '-wp',
6266
type=int,
63-
nargs='?',
64-
default=None,
67+
nargs='*',
68+
default=[],
6569
help='Port number for the web server to run from.',
6670
)
6771
subparser.add_argument(
@@ -150,73 +154,88 @@ def _(
150154
parser: argparse.ArgumentParser,
151155
args_ns: argparse.Namespace,
152156
) -> list[logic.base_entry]:
153-
if args_ns.place_path is not None:
154-
game_config = config.generate_config(args_ns.place_path)
157+
if len(args_ns.place_path) > 0:
158+
game_configs = [
159+
config.generate_config(v)
160+
for v in args_ns.place_path
161+
]
155162
else:
156-
game_config = config.get_cached_config(args_ns.config_path)
157-
158-
web_port: int | None = args_ns.web_port
159-
rcc_port: int | None = args_ns.rcc_port
160-
if web_port is None:
161-
web_port = rcc_port or 2005
162-
if rcc_port is None:
163-
rcc_port = web_port or 2005
163+
game_configs = [
164+
config.get_cached_config(v)
165+
for v in args_ns.config_path
166+
]
164167

165168
has_ipv6: bool = not args_ns.ipv4_only
166169
has_ipv4: bool = not args_ns.ipv6_only
167170

171+
web_routine_args = set[logic.base_entry]()
172+
rcc_routine_args = set[logic.base_entry]()
168173
log_filter = gen_log_filter(
169174
parser, args_ns,
170175
)
171176

172-
web_routine_args = []
173-
if has_ipv6:
174-
# IPv6 goes first since `localhost` also resolves first to [::1] on the client.
175-
web_routine_args.append(web.obj_type(
176-
web_port=web_port,
177-
is_ssl=True,
178-
is_ipv6=True,
179-
server_mode=web.SERVER_MODE_TYPE.RCC,
180-
logger=log_filter,
181-
game_config=game_config,
182-
))
183-
if has_ipv4:
184-
web_routine_args.append(web.obj_type(
185-
web_port=web_port,
186-
is_ssl=True,
187-
is_ipv6=False,
188-
server_mode=web.SERVER_MODE_TYPE.RCC,
189-
logger=log_filter,
190-
game_config=game_config,
191-
))
192-
193-
routine_args = []
194-
if not args_ns.skip_web:
195-
routine_args.extend(web_routine_args)
196-
197-
if not args_ns.skip_rcc:
198-
routine_args.append(
199-
rcc.obj_type(
200-
# TODO: add support for RCC to connect to hosts other than `localhost`.
201-
web_host='localhost',
202-
web_port=web_port,
203-
rcc_port=rcc_port,
204-
logger=log_filter,
205-
game_config=game_config,
206-
),
207-
)
208-
209-
if args_ns.run_client:
210-
routine_args.extend([
211-
player.obj_type(
212-
rcc_host='127.0.0.1',
213-
web_host='127.0.0.1',
214-
rcc_port=rcc_port,
215-
web_port=web_port,
216-
user_code=args_ns.user_code,
217-
logger=log_filter,
218-
# Some CoreGUI elements don't render properly if we join too early.
219-
launch_delay=3,
220-
),
221-
])
222-
return routine_args
177+
def gen_next_seq_port(ports: list[int | None]):
178+
last_used = util.const.RFD_DEFAULT_PORT - 1
179+
for p in ports:
180+
if p is not None:
181+
last_used = p
182+
else:
183+
last_used += 1
184+
yield last_used
185+
186+
web_port_gen = gen_next_seq_port(args_ns.web_port)
187+
rcc_port_gen = gen_next_seq_port(args_ns.rcc_port)
188+
189+
for (
190+
web_port, rcc_port, game_config,
191+
) in itertools.zip_longest(
192+
web_port_gen, rcc_port_gen, game_configs,
193+
):
194+
if not args_ns.skip_web:
195+
if has_ipv6:
196+
# IPv6 goes first since `localhost` also resolves first to [::1] on the client.
197+
web_routine_args.add(web.obj_type(
198+
web_port=web_port,
199+
is_ssl=True,
200+
is_ipv6=True,
201+
server_mode=web.SERVER_MODE_TYPE.RCC,
202+
logger=log_filter,
203+
game_config=game_config,
204+
))
205+
if has_ipv4:
206+
web_routine_args.add(web.obj_type(
207+
web_port=web_port,
208+
is_ssl=True,
209+
is_ipv6=False,
210+
server_mode=web.SERVER_MODE_TYPE.RCC,
211+
logger=log_filter,
212+
game_config=game_config,
213+
))
214+
215+
if not args_ns.skip_rcc:
216+
rcc_routine_args.add(
217+
rcc.obj_type(
218+
# TODO: add support for RCC to connect to hosts other than `localhost`.
219+
web_host='localhost',
220+
web_port=web_port,
221+
rcc_port=rcc_port,
222+
logger=log_filter,
223+
game_config=game_config,
224+
),
225+
)
226+
227+
if args_ns.run_client:
228+
rcc_routine_args.add([
229+
player.obj_type(
230+
rcc_host='127.0.0.1',
231+
web_host='127.0.0.1',
232+
rcc_port=rcc_port,
233+
web_port=web_port,
234+
user_code=args_ns.user_code,
235+
logger=log_filter,
236+
# Some CoreGUI elements don't render properly if we join too early.
237+
launch_delay=3,
238+
),
239+
])
240+
241+
return [*web_routine_args, *rcc_routine_args]

Source/routines/_logic.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import game_config as game_config_module
2121
import util.resource
2222
import util.versions
23+
import util.const
2324
import logger
2425
from pretasks import (
2526
download,
@@ -60,6 +61,17 @@ def process(self) -> None:
6061
assert not self._completed
6162
self._completed = True
6263

64+
def __post_init__(self) -> None:
65+
'''
66+
https://stackoverflow.com/a/69944614/6879778
67+
'''
68+
for field in dataclasses.fields(self):
69+
if isinstance(field.default, dataclasses._MISSING_TYPE):
70+
continue
71+
if getattr(self, field.name) is not None:
72+
continue
73+
setattr(self, field.name, field.default)
74+
6375

6476
@dataclasses.dataclass(kw_only=True, unsafe_hash=True)
6577
class popen_entry(base_entry):
@@ -178,7 +190,7 @@ class bin_entry(popen_entry, loggable_entry):
178190
auto_download: bool = False
179191
clear_temp_cache: bool = False
180192
web_host: str = 'localhost'
181-
web_port: int
193+
web_port: int = util.const.RFD_DEFAULT_PORT
182194

183195
@staticmethod
184196
def get_none_ssl() -> ssl.SSLContext:
@@ -188,7 +200,14 @@ def get_none_ssl() -> ssl.SSLContext:
188200
return ctx
189201

190202
@staticmethod
191-
def resolve_host_port(host: str, port: int) -> tuple[str, int]:
203+
def maybe_differenciate_web_and_rcc_stuff[T](web: T, rcc: T | None) -> tuple[T, T]:
204+
has_rcc = rcc is not None
205+
if has_rcc:
206+
return (web, rcc)
207+
return (web, web)
208+
209+
@staticmethod
210+
def maybe_separate_host_and_port(host: str, port: int) -> tuple[str, int]:
192211
if not host.startswith('[') and re.search(r':.*:', host) is not None:
193212
host = '[%s]' % host
194213
return (host, port)
@@ -227,9 +246,10 @@ def get_app_base_url(self) -> str:
227246
DIRS_TO_ADD: ClassVar[list[str]]
228247

229248
def __post_init__(self) -> None:
249+
super().__post_init__()
230250
(
231251
self.web_host, self.web_port,
232-
) = self.resolve_host_port(
252+
) = self.maybe_separate_host_and_port(
233253
self.web_host, self.web_port,
234254
)
235255

0 commit comments

Comments
 (0)