Compare commits

..

7 Commits

Author SHA1 Message Date
d055090dd2
Add ruff pre-commit hook
Add configuration for pre-commit, ruff as a hook and configuration to
run ruff whenever a pull request is opened or code is pushed.
2024-08-24 10:54:26 +02:00
c49d4eedd0
Lint and format Python files using ruff
To improve quality und uniformity of the included Python code this
lints and formats the included Python files with ruff.
2024-08-24 10:54:26 +02:00
8519eb9b86
Reduce time needed for STUN
In my tests this reduced the time necessary for starting to host a game
or joining a hosted game by ~180ms.
2024-08-23 21:00:15 +02:00
0efaf5ac4b Add common IDE temporary files to gitignore 2024-08-23 19:29:28 +02:00
eeb0f1cce6
Make checkrefs and called scripts return an error 2024-08-23 17:54:56 +02:00
2a06eea08a
Fix checkrefs.py for python 3.12
Fixes #6898
Reported by: @Itms
2024-08-23 15:59:36 +02:00
393ad6c8a6
Improve windows pipeline 2024-08-23 13:08:04 +02:00
7 changed files with 81 additions and 39 deletions

5
.gitignore vendored
View File

@ -96,3 +96,8 @@ Thumbs.db
# macOS specific data
.DS_Store
# IDE files
/.vs/
/.vscode/
/.idea/

View File

@ -518,8 +518,13 @@ enabled = true ; The STUN protocol allows hosting games wi
; If STUN is disabled, the game relies on direct connection, UPnP and port forwarding.
server = "lobby.wildfiregames.com" ; Address of the STUN server.
port = 3478 ; Port of the STUN server.
delay = 200 ; Duration in milliseconds that is waited between STUN messages.
; Smaller numbers speed up joins but also become less stable.
delay = 10 ; Duration in milliseconds that is waited between checking for retrieved STUN responses.
; Smaller numbers speed up joins but may make them less stable, if max_tries isn't increased proportionally as well.
max_tries = 100 ; Maximum number of tries for receiving STUN responses.
[lobby.fw_punch]
delay = 200 ; Duration in milliseconds between sending hole punching messages.
num_msg = 3 ; Number of hole punching messages to send.
[mod]
enabledmods = "mod public"

View File

@ -43,11 +43,23 @@ pipeline {
}
}
stage("Debug Build") {
steps {
bat("cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Debug ${buildOptions}")
timeout(time: 15) {
bat "cd binaries\\system && test_dbg.exe > cxxtest-debug.xml"
}
}
post {
always {
junit 'binaries/system/cxxtest-debug.xml'
}
}
}
stage ("Release Build") {
steps {
dir('build\\workspaces\\vs2017'){
bat("${visualStudioPath} pyrogenesis.sln /p:Configuration=Release ${buildOptions}")
}
bat("cd build\\workspaces\\vs2017 && ${visualStudioPath} pyrogenesis.sln /p:Configuration=Release ${buildOptions}")
timeout(time: 5) {
bat "cd binaries\\system && test.exe > cxxtest-release.xml"
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2022 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
* Copyright (C) 2013-2016 SuperTuxKart-Team.
* This file is part of 0 A.D.
*
@ -183,12 +183,13 @@ bool ReceiveStunResponse(ENetHost& transactionHost, std::vector<u8>& buffer)
ENetAddress sender = m_StunServer;
int len = enet_socket_receive(transactionHost.socket, &sender, &enetBuffer, 1);
int delay = 200;
int delay = 10;
CFG_GET_VAL("lobby.stun.delay", delay);
int maxTries = 100;
CFG_GET_VAL("lobby.stun.max_tries", maxTries);
// Wait to receive the message because enet sockets are non-blocking
const int max_tries = 5;
for (int count = 0; len <= 0 && (count < max_tries || max_tries == -1); ++count)
for (int count = 0; len <= 0 && (count < maxTries || maxTries == -1); ++count)
{
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
len = enet_socket_receive(transactionHost.socket, &sender, &enetBuffer, 1);
@ -359,10 +360,12 @@ void SendHolePunchingMessages(ENetHost& enetClient, const std::string& serverAdd
enet_address_set_host(&addr, serverAddress.c_str());
int delay = 200;
CFG_GET_VAL("lobby.stun.delay", delay);
CFG_GET_VAL("lobby.fw_punch.delay", delay);
int numMsg = 3;
CFG_GET_VAL("lobby.fw_punch.num_msg", numMsg);
// Send an UDP message from enet host to ip:port
for (int i = 0; i < 3; ++i)
for (int i = 0; i < numMsg || numMsg == -1; ++i)
{
SendStunRequest(enetClient, addr);
std::this_thread::sleep_for(std::chrono::milliseconds(delay));

View File

@ -39,6 +39,7 @@ class CheckRefs:
self.supportedAudioFormats = "ogg"
self.mods = []
self.__init_logger
self.inError = False
@property
def __init_logger(self):
@ -133,13 +134,17 @@ class CheckRefs:
from validate_grammar import RelaxNGValidator
validate = RelaxNGValidator(self.vfs_root, self.mods)
validate.run()
if not validate.run():
self.inError = True
if args.validate_actors:
sys.path.append("../xmlvalidator/")
from validator import Validator
validator = Validator(self.vfs_root, self.mods)
validator.run()
if not validator.run():
self.inError = True
return self.inError
def get_mod_dependencies(self, *mods):
modjsondeps = []
@ -212,7 +217,8 @@ class CheckRefs:
# ignore terrains.xml
if name != "terrains":
if name in terrains:
self.logger.warning(
self.inError = True
self.logger.error(
f"Duplicate terrain name '{name}' (from '{terrains[name]}' and '{ffp}')"
)
terrains[name] = str(fp)
@ -287,11 +293,10 @@ class CheckRefs:
if not str(fp).startswith("template_"):
self.roots.append(str(fp))
if (
entity
and entity.find("VisualActor") is not None
entity.find("VisualActor") is not None
and entity.find("VisualActor").find("Actor") is not None
):
if entity.find("Identity"):
if entity.find("Identity") is not None:
phenotype_tag = entity.find("Identity").find("Phenotype")
phenotypes = split(
r"\s",
@ -309,9 +314,9 @@ class CheckRefs:
actor_path = actor.text
self.deps.append((str(fp), f"art/actors/{actor_path}"))
foundation_actor = entity.find("VisualActor").find("FoundationActor")
if foundation_actor:
if foundation_actor is not None:
self.deps.append((str(fp), f"art/actors/{foundation_actor.text}"))
if entity.find("Sound"):
if entity.find("Sound") is not None:
phenotype_tag = entity.find("Identity").find("Phenotype")
phenotypes = split(
r"\s",
@ -322,18 +327,19 @@ class CheckRefs:
lang_tag = entity.find("Identity").find("Lang")
lang = lang_tag.text if lang_tag is not None and lang_tag.text else "greek"
sound_groups = entity.find("Sound").find("SoundGroups")
for sound_group in sound_groups:
if sound_group.text and sound_group.text.strip():
if "{phenotype}" in sound_group.text:
for phenotype in phenotypes:
# see simulation/components/Sound.js and Identity.js for explanation
sound_path = sound_group.text.replace(
"{phenotype}", phenotype
).replace("{lang}", lang)
if sound_groups is not None and len(sound_groups) > 0:
for sound_group in sound_groups:
if sound_group.text and sound_group.text.strip():
if "{phenotype}" in sound_group.text:
for phenotype in phenotypes:
# see simulation/components/Sound.js and Identity.js for explanation
sound_path = sound_group.text.replace(
"{phenotype}", phenotype
).replace("{lang}", lang)
self.deps.append((str(fp), f"audio/{sound_path}"))
else:
sound_path = sound_group.text.replace("{lang}", lang)
self.deps.append((str(fp), f"audio/{sound_path}"))
else:
sound_path = sound_group.text.replace("{lang}", lang)
self.deps.append((str(fp), f"audio/{sound_path}"))
if entity.find("Identity") is not None:
icon = entity.find("Identity").find("Icon")
if icon is not None and icon.text:
@ -540,7 +546,7 @@ class CheckRefs:
material_elem = ElementTree.parse(ffp).getroot()
for alternative in material_elem.findall("alternative"):
material = alternative.get("material")
if material:
if material is not None:
self.deps.append((str(fp), f"art/materials/{material}"))
def add_particles(self):
@ -550,7 +556,7 @@ class CheckRefs:
self.roots.append(str(fp))
particle = ElementTree.parse(ffp).getroot()
texture = particle.find("texture")
if texture:
if texture is not None:
self.deps.append((str(fp), texture.text))
def add_soundgroups(self):
@ -811,9 +817,8 @@ class CheckRefs:
continue
callers = [str(self.vfs_to_relative_to_mods(ref)) for ref in reverse_deps[dep]]
self.logger.warning(
f"Missing file '{dep}' referenced by: {', '.join(sorted(callers))}"
)
self.logger.error(f"Missing file '{dep}' referenced by: {', '.join(sorted(callers))}")
self.inError = True
if dep.lower() in lower_case_files:
self.logger.warning(
f"### Case-insensitive match (found '{lower_case_files[dep.lower()]}')"
@ -859,4 +864,5 @@ class CheckRefs:
if __name__ == "__main__":
check_ref = CheckRefs()
check_ref.main()
if not check_ref.main():
sys.exit(1)

View File

@ -50,6 +50,7 @@ class RelaxNGValidator:
errorch.setFormatter(Formatter("%(levelname)s - %(message)s"))
logger.addHandler(errorch)
self.logger = logger
self.inError = False
def run(self):
self.validate_actors()
@ -62,13 +63,14 @@ class RelaxNGValidator:
self.validate_soundgroups()
self.validate_terrains()
self.validate_textures()
return self.inError
def main(self):
"""Program entry point, parses command line arguments and launches the validation"""
# ordered uniq mods (dict maintains ordered keys from python 3.6)
self.logger.info(f"Checking {'|'.join(self.mods)}'s integrity.")
self.logger.info(f"The following mods will be loaded: {'|'.join(self.mods)}.")
self.run()
return self.run()
def find_files(self, vfs_root, mods, vfs_path, *ext_list):
"""
@ -207,6 +209,7 @@ class RelaxNGValidator:
self.logger.info(f"{error_count} {name} validation errors")
elif error_count > 0:
self.logger.error(f"{error_count} {name} validation errors")
self.inError = True
def get_mod_dependencies(vfs_root, *mods):
@ -247,4 +250,5 @@ if __name__ == "__main__":
dict.fromkeys([*args.mods, *get_mod_dependencies(args.root, *args.mods), "mod"]).keys()
)
relax_ng_validator = RelaxNGValidator(args.root, mods=mods, verbose=args.verbose)
relax_ng_validator.main()
if not relax_ng_validator.main():
sys.exit(1)

View File

@ -113,6 +113,7 @@ class Validator:
errorch.setFormatter(Formatter("%(levelname)s - %(message)s"))
logger.addHandler(errorch)
self.logger = logger
self.inError = False
def get_mod_path(self, mod_name, vfs_path):
return os.path.join(mod_name, vfs_path)
@ -182,6 +183,7 @@ class Validator:
'"%s": unknown material "%s"'
% (self.get_mod_path(actor.mod_name, actor.vfs_path), actor.material)
)
self.inError = True
if actor.material not in self.materials:
continue
material = self.materials[actor.material]
@ -204,6 +206,7 @@ class Validator:
material.name,
)
)
self.inError = True
extra_textures = ", ".join(
set(
@ -223,6 +226,9 @@ class Validator:
material.name,
)
)
self.inError = True
return self.inError
if __name__ == "__main__":
@ -233,4 +239,5 @@ if __name__ == "__main__":
parser.add_argument("-m", "--mods", action="store", dest="mods", default="mod,public")
args = parser.parse_args()
validator = Validator(args.root, args.mods.split(","))
validator.run()
if not validator.run():
sys.exit(1)