fix: sync avatar details and Srtool session
This commit is contained in:
1 parent
dc097d8a0a
commit
fa31704a56
2 files changed
+38
-9
No files matched your search
@@ -111,3 +111,7 @@ GaC-Srtool สื่อสารกับเซิร์ฟเวอร์ GaC-h
|
||||
| `/api/avatar/rank` | POST | เปลี่ยนระดับ Eidolon ของตัวละคร |
|
||||
| `/api/avatar/max_all` | POST | ปรับตัวละครทุกตัวเป็น Max E6 และสกิลเต็ม |
|
||||
| `/api/command` | POST | ส่งคำสั่ง GM ไปยังเซิร์ฟเวอร์ |
|
||||
|
||||
### บันทึกตัวละครและ Traces
|
||||
|
||||
การบันทึกจากหน้ารายละเอียดส่งข้อมูลตัวละครทั้งชุดผ่าน `/api/freesr` ในคำขอเดียว รวมถึง `data.skills` และ `data.skills_by_anchor_type` สำหรับ Traces เพื่อไม่ให้ server sync ข้อมูลระดับ/Eidolon ระหว่างทางก่อนข้อมูล Trace จะถูกบันทึก `saveAvatarDetails(closeModal = true)` ยังรองรับการเรียกจากปุ่ม build ที่ไม่ต้องปิดหน้าต่าง ถ้า server ตอบผิดพลาดจะแสดงข้อความบันทึกไม่สำเร็จแทนการแจ้งว่าสำเร็จ
|
||||
@@ -381,7 +381,8 @@ async function apiCall(endpoint, method = 'GET', data = null) {
|
||||
const options = {
|
||||
method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
'X-GaC-Srtool': '1'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -409,8 +410,34 @@ async function apiCall(endpoint, method = 'GET', data = null) {
|
||||
}
|
||||
}
|
||||
|
||||
// Explicit, expiring custom-battle connection. The backend returns its TTL.
|
||||
let toolSessionTimer = null;
|
||||
let toolSessionConnected = false;
|
||||
let toolSessionGeneration = 0;
|
||||
async function syncToolSession(connected) {
|
||||
const generation = ++toolSessionGeneration;
|
||||
if (toolSessionTimer) { clearTimeout(toolSessionTimer); toolSessionTimer = null; }
|
||||
toolSessionConnected = connected;
|
||||
try {
|
||||
const result = await apiCall('/api/tool-session', 'POST', { connected, client: 'GaC-Srtool' });
|
||||
if (generation === toolSessionGeneration && connected && toolSessionConnected && Number(result.lease_seconds) > 0) {
|
||||
toolSessionTimer = setTimeout(() => syncToolSession(true), Number(result.lease_seconds) * 1000 / 3);
|
||||
}
|
||||
} catch (error) {
|
||||
if (generation === toolSessionGeneration) toolSessionConnected = false;
|
||||
// Older backends remain usable, but cannot enable the custom encounter lease.
|
||||
console.warn('Tool session unavailable:', error.message);
|
||||
}
|
||||
}
|
||||
window.addEventListener('pagehide', () => {
|
||||
if (!toolSessionConnected) return;
|
||||
const base = state.apiUrl.replace(/\/+$/, '');
|
||||
navigator.sendBeacon(`${base}/api/tool-session`, JSON.stringify({ connected: false, client: 'GaC-Srtool' }));
|
||||
});
|
||||
|
||||
// Update connection status UI
|
||||
function setConnectionStatus(connected, extraText = '') {
|
||||
if (connected !== toolSessionConnected) syncToolSession(connected);
|
||||
state.isConnected = connected;
|
||||
if (connected) {
|
||||
el.statusDot.classList.add('connected');
|
||||
@@ -4600,7 +4627,7 @@ async function maxAllBuildForCurrentAvatar() {
|
||||
}
|
||||
|
||||
// Save avatar details from modal
|
||||
async function saveAvatarDetails() {
|
||||
async function saveAvatarDetails(closeModal = true) {
|
||||
if (!state.selectedAvatarDetail) return;
|
||||
const aid = state.selectedAvatarDetail.avatar_id;
|
||||
const level = parseInt(el.modalCharLevel.value, 10) || 80;
|
||||
@@ -4735,15 +4762,13 @@ async function saveAvatarDetails() {
|
||||
|
||||
if (state.isConnected) {
|
||||
try {
|
||||
if (state.serverMode === 'gac') {
|
||||
await apiCall('/api/freesr/avatars', 'POST', { avatar_id: aid, level, promotion, rank });
|
||||
await saveFreesrChangesToServer();
|
||||
} else {
|
||||
await saveFreesrChangesToServer();
|
||||
}
|
||||
// Save the complete avatar record once. The full payload includes skills
|
||||
// and Trace values; a preceding rank-only request can trigger live sync
|
||||
// with an incomplete intermediate state.
|
||||
await saveFreesrChangesToServer();
|
||||
showToast(t('toastCharSaved', { name: getAvatarInfo(aid).name }), 'success');
|
||||
} catch (err) {
|
||||
showToast(t('toastCharSaved', { name: getAvatarInfo(aid).name }), 'info');
|
||||
showToast(`บันทึกไม่สำเร็จ: ${err.message}`, 'error');
|
||||
}
|
||||
} else {
|
||||
showToast(t('toastCharSaved', { name: getAvatarInfo(aid).name }), 'success');
|
||||
|
||||
Reference in new issue
Block a user