Строчные ссылки на файлы модов и своё ожидание готовности
Игра приводит путь к вложенным файлам анимаций в нижний регистр целиком, вместе с именем папки мода. На Linux такие файлы не находятся, и сервер сыплет в лог сотнями FileNotFoundException. Кнопка на вкладке «Моды» раскладывает рядом строчные симлинки: файлы модов не меняются, повторный запуск после докачки безопасен, а на файловых системах без различия регистра кнопка честно говорит, что делать нечего. Ожидание строки о готовности стало настройкой профиля со значением по умолчанию 30 минут вместо общих 15. Сборке на три сотни модов пятнадцати не хватает, и панель объявляла бы работающим сервер, который ещё никого не пустит. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+28
-2
@@ -384,6 +384,19 @@ $("#btn-install").addEventListener("click", async () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Строчные ссылки на файлы модов: лечит FileNotFoundException в анимациях на
|
||||
// файловых системах, различающих регистр. Задача фоновая — вывод идёт в консоль.
|
||||
$("#btn-mods-casefix").addEventListener("click", async () => {
|
||||
if (!confirm(t("mods.caseConfirm"))) return;
|
||||
try {
|
||||
await post("/api/mods/casefix");
|
||||
ok(t("mods.caseStarted"));
|
||||
refreshStatus();
|
||||
} catch (error) {
|
||||
fail(error);
|
||||
}
|
||||
});
|
||||
|
||||
$("#btn-task-cancel").addEventListener("click", async () => {
|
||||
try {
|
||||
await post("/api/task/cancel");
|
||||
@@ -1475,11 +1488,16 @@ $("#btn-mods-save").addEventListener("click", async () => {
|
||||
// Профили серверов
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
let profiles = { list: [], active: "" };
|
||||
let profiles = { list: [], active: "", default_startup_timeout_min: 0 };
|
||||
|
||||
async function loadProfiles() {
|
||||
const data = await get("/api/profiles");
|
||||
profiles = { list: data.profiles || [], active: data.active };
|
||||
profiles = {
|
||||
list: data.profiles || [],
|
||||
active: data.active,
|
||||
// Значение по умолчанию показываем подсказкой в пустом поле.
|
||||
default_startup_timeout_min: data.default_startup_timeout_min || 0,
|
||||
};
|
||||
|
||||
renderProfileSelect();
|
||||
renderProfileCards();
|
||||
@@ -1522,6 +1540,13 @@ function renderProfileCards() {
|
||||
placeholder="${t("profiles.memoryMinPlaceholder")}">
|
||||
<small>${t("profiles.memoryMinHint")}</small>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>${t("profiles.startupTimeout")}</span>
|
||||
<input type="number" min="1" max="180" data-field="startup_timeout_min"
|
||||
value="${escapeHTML(String(p.startup_timeout_min || ""))}"
|
||||
placeholder="${escapeHTML(String(profiles.default_startup_timeout_min || ""))}">
|
||||
<small>${t("profiles.startupTimeoutHint")}</small>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>${t("profiles.adminPassword")}</span>
|
||||
<input type="password" data-field="admin_password" autocomplete="new-password"
|
||||
@@ -1592,6 +1617,7 @@ $("#profile-cards").addEventListener("click", async (event) => {
|
||||
title: field("title"),
|
||||
java_memory: field("java_memory"),
|
||||
java_memory_min: field("java_memory_min"),
|
||||
startup_timeout_min: Number(field("startup_timeout_min")) || 0,
|
||||
admin_password: field("admin_password"),
|
||||
});
|
||||
ok(t("profiles.saved"));
|
||||
|
||||
Reference in New Issue
Block a user