Recognise the coa-bots world server and explain the undo step

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ДмитрийandClaude Sonnet 5.5 committed 2026-10-08 07:12:01 +05:00
1 parent 0a050a40a2
commit d85d86a3dc
9 files changed
+33 -10

No files matched your search

@@ -0,0 +1,7 @@
---
area: manager
type: fixed
audience: admins
title: A world server started from the coa-bots folder is recognised
---
The Manager no longer reports a port conflict when the world server runs from the coa-bots folder inside the server folder, and a failed update now says that undoing it can take several minutes.
+15 -3
View File
@@ -278,12 +278,24 @@ fn uptime_secs(p: &ProcessIdentity) -> Option<u64> {
(now >= p.created).then(|| (now - p.created) / 10_000_000)
}
/// The world server of the `coa-bots` repack folder lives inside the server folder and is started by its own
/// launcher (`coa-bots\Core\worldserver.exe`). It serves the same realm, so it counts as this server's world.
fn world_alternatives(root: &Path) -> Vec<PathBuf> {
vec![root.join("coa-bots").join("Core").join("worldserver.exe")]
}
fn service(root: &Path, name: &'static str, exe: PathBuf, port: u16, listen: &[(u16, u32)]) -> ServiceStatus {
service_with(root, name, exe, &[], port, listen)
}
fn service_with(root: &Path, name: &'static str, exe: PathBuf, alternatives: &[PathBuf], port: u16, listen: &[(u16, u32)]) -> ServiceStatus {
// Prefer the repack's own record when it still matches a live process; otherwise discover by exact exe path.
let norm = |p: &Path| p.to_string_lossy().replace('/', "\\");
let expected: Vec<String> = std::iter::once(&exe).chain(alternatives).map(|p| norm(p)).collect();
let proc = read_state_record(root, name)
.filter(is_alive)
.filter(|r| r.exe.eq_ignore_ascii_case(&exe.to_string_lossy().replace('/', "\\")))
.or_else(|| find_by_exe(&exe).into_iter().next());
.filter(|r| expected.iter().any(|e| r.exe.eq_ignore_ascii_case(e)))
.or_else(|| std::iter::once(&exe).chain(alternatives).find_map(|p| find_by_exe(p).into_iter().next()));
let owner = listen.iter().find(|(p, _)| *p == port).map(|(_, pid)| *pid);
let (state, port_ready, conflict) = match (&proc, owner) {
@@ -319,7 +331,7 @@ pub fn observe(root: &Path, ports: &Ports) -> Observed {
Observed {
mysql: service(root, "mysql", mysql, ports.mysql, &listen),
auth: service(root, "auth", auth, ports.auth, &listen),
world: service(root, "world", world, ports.world, &listen),
world: service_with(root, "world", world, &world_alternatives(root), ports.world, &listen),
secondary_world,
}
}
+5 -1
View File
@@ -492,9 +492,13 @@ pub fn apply(p: &Params, report: &dyn Fn(&str, u8)) -> Result<Outcome> {
Ok(r) if r.failed.is_none() => migrated = Some(r),
Ok(r) => {
let (mid, why) = r.failed.clone().unwrap();
step(report, "Undoing the update", 76);
return fail_after_apply(p, &mut txn, &before, &tree, format!("Database update {mid} failed: {why}"), Some(r));
}
Err(e) => return fail_after_apply(p, &mut txn, &before, &tree, e.to_string(), None),
Err(e) => {
step(report, "Undoing the update", 76);
return fail_after_apply(p, &mut txn, &before, &tree, e.to_string(), None);
}
}
}
+1 -1
View File
@@ -495,7 +495,7 @@ const de: Partial<Record<keyof typeof en, string>> = {
"ustep.Updating the database": "Datenbank wird aktualisiert",
"ustep.Starting the updated server": "Aktualisierter Server wird gestartet",
"ustep.Finishing": "Abschluss",
"ustep.Undoing the update": "Update wird rückgängig gemacht",
"ustep.Undoing the update": "Update wird rückgängig gemacht (das Wiederherstellen der Datenbanken kann mehrere Minuten dauern)",
"ustep.Done": "Fertig",
// Companion sizes
+1 -1
View File
@@ -530,7 +530,7 @@ const en = {
"ustep.Updating the database": "Updating the database",
"ustep.Starting the updated server": "Starting the updated server",
"ustep.Finishing": "Finishing",
"ustep.Undoing the update": "Undoing the update",
"ustep.Undoing the update": "Undoing the update (restoring the databases can take several minutes)",
"ustep.Done": "Done",
// Companion sizes
+1 -1
View File
@@ -495,7 +495,7 @@ const es: Partial<Record<keyof typeof en, string>> = {
"ustep.Updating the database": "Actualizando la base de datos",
"ustep.Starting the updated server": "Iniciando el servidor actualizado",
"ustep.Finishing": "Finalizando",
"ustep.Undoing the update": "Deshaciendo la actualización",
"ustep.Undoing the update": "Deshaciendo la actualización (restaurar las bases de datos puede tardar varios minutos)",
"ustep.Done": "Hecho",
// Companion sizes
+1 -1
View File
@@ -495,7 +495,7 @@ const fr: Partial<Record<keyof typeof en, string>> = {
"ustep.Updating the database": "Mise à jour de la base de données",
"ustep.Starting the updated server": "Démarrage du serveur mis à jour",
"ustep.Finishing": "Finalisation",
"ustep.Undoing the update": "Annulation de la mise à jour",
"ustep.Undoing the update": "Annulation de la mise à jour (la restauration des bases de données peut prendre plusieurs minutes)",
"ustep.Done": "Terminé",
// Companion sizes
+1 -1
View File
@@ -528,7 +528,7 @@ const ru: Partial<Record<keyof typeof en, string>> = {
"ustep.Updating the database": "Обновление базы данных",
"ustep.Starting the updated server": "Запуск обновлённого сервера",
"ustep.Finishing": "Завершение",
"ustep.Undoing the update": "Откат обновления",
"ustep.Undoing the update": "Отмена обновления (восстановление баз данных может занять несколько минут)",
"ustep.Done": "Готово",
// Companion sizes
+1 -1
View File
@@ -507,7 +507,7 @@ const zh = {
"ustep.Updating the database": "正在更新数据库结构",
"ustep.Starting the updated server": "正在启动更新后的服务器",
"ustep.Finishing": "正在收尾完成",
"ustep.Undoing the update": "正在撤销更新并回滚",
"ustep.Undoing the update": "正在撤销更新(恢复数据库可能需要几分钟)",
"ustep.Done": "已完成",
// Companion sizes