corrigindo estado atual da sala, aparentemente, todos os clientes possuem o mesmo estado de sala com steps e samples de áudio
This commit is contained in:
1 parent
6eb81089f7
commit
3f714c88de
3 files changed
+265
-238
No files matched your search
+102
-59
@@ -38,7 +38,9 @@ import {
|
||||
handleLocalProjectReset,
|
||||
syncPatternStateToServer,
|
||||
BLANK_PROJECT_XML,
|
||||
generateXmlFromStateExported,
|
||||
} from "./file.js";
|
||||
|
||||
import { renderAll, showToast } from "./ui.js"; // showToast()
|
||||
import { updateStepUI, renderPatternEditor } from "./pattern/pattern_ui.js";
|
||||
import { PORT_SOCK } from "./config.js";
|
||||
@@ -170,18 +172,17 @@ socket.on("connect_error", (err) => {
|
||||
);
|
||||
});
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Atualizar os artefatos da plataforma
|
||||
// -----------------------------------------------------------------------------
|
||||
socket.on("system_update", (data) => {
|
||||
if (data.type === "RELOAD_SAMPLES") {
|
||||
console.log(
|
||||
`[System Update] Recebida ordem para recarregar samples: ${data.message}`
|
||||
);
|
||||
|
||||
// Certifique-se de que esta função existe e faz o que é esperado:
|
||||
// 1. Fetch dos novos manifestos (metadata/samples-manifest.json etc.)
|
||||
// 2. Renderiza a interface do navegador de samples
|
||||
loadAndRenderSampleBrowser();
|
||||
}
|
||||
// Se houver outras notificações, adicione-as aqui (ex: RELOAD_PROJECTS)
|
||||
});
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -193,11 +194,28 @@ socket.on("load_project_state", async (projectXml) => {
|
||||
if (isLoadingProject) return;
|
||||
isLoadingProject = true;
|
||||
try {
|
||||
await parseMmpContent(projectXml); //
|
||||
// 1. Carrega o XML que veio do servidor (pode estar desatualizado)
|
||||
await parseMmpContent(projectXml);
|
||||
|
||||
// 🔥 CORREÇÃO: Força a restauração da sessão LOCAL logo após carregar o XML
|
||||
// Isso garante que suas alterações locais (BPM, steps) "ganhem" do servidor
|
||||
if (window.ROOM_NAME) {
|
||||
const raw = sessionStorage.getItem(`temp_state_${window.ROOM_NAME}`);
|
||||
if (raw) {
|
||||
const parsed = JSON.parse(raw);
|
||||
const hasLocalAudio = parsed.audioSnapshot?.clips?.length > 0 ||
|
||||
parsed.audioSnapshot?.tracks?.length > 0;
|
||||
if (hasLocalAudio) {
|
||||
console.log("Re-aplicando sessão local sobre o XML do servidor...");
|
||||
await loadStateFromSession();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
renderAll();
|
||||
showToast("🎵 Projeto carregado com sucesso", "success");
|
||||
|
||||
// --- INÍCIO DA CORREÇÃO ---
|
||||
const hasAudio =
|
||||
(appState.audio?.clips?.length || 0) > 0 ||
|
||||
(appState.audio?.tracks?.length || 0) > 0;
|
||||
@@ -207,13 +225,12 @@ socket.on("load_project_state", async (projectXml) => {
|
||||
"Projeto XML carregado, sem áudio. Pedindo snapshot de áudio..."
|
||||
);
|
||||
|
||||
// 🔥 FIX CRÍTICO: Libera a trava IMEDIATAMENTE antes de pedir
|
||||
// Libera a trava IMEDIATAMENTE antes de pedir
|
||||
// Caso contrário, a resposta chega muito rápido e cai no bloqueio "justReset=true"
|
||||
appState.global.justReset = false;
|
||||
|
||||
sendAction({ type: "AUDIO_SNAPSHOT_REQUEST" });
|
||||
}
|
||||
// --- FIM DA CORREÇÃO ---
|
||||
|
||||
} catch (e) {
|
||||
console.error("Erro ao carregar projeto:", e);
|
||||
@@ -301,9 +318,6 @@ export function sendAction(action) {
|
||||
action.__senderId = socket.id;
|
||||
action.__senderName = USER_NAME;
|
||||
|
||||
// =================================================================
|
||||
// 👇 INÍCIO DA CORREÇÃO (Expandir `isTransport` para SET_SYNC_MODE)
|
||||
// =================================================================
|
||||
const isTransport =
|
||||
action.type === "TOGGLE_PLAYBACK" ||
|
||||
action.type === "STOP_PLAYBACK" ||
|
||||
@@ -312,10 +326,7 @@ export function sendAction(action) {
|
||||
action.type === "STOP_AUDIO_PLAYBACK" ||
|
||||
action.type === "SET_LOOP_STATE" ||
|
||||
action.type === "SET_SEEK_TIME" ||
|
||||
action.type === "SET_SYNC_MODE"; // 👈 Adicionado
|
||||
// =================================================================
|
||||
// 👆 FIM DA CORREÇÃO
|
||||
// =================================================================
|
||||
action.type === "SET_SYNC_MODE";
|
||||
|
||||
if (inRoom && isTransport) {
|
||||
const leadTimeMs = 200;
|
||||
@@ -375,12 +386,16 @@ export function sendAction(action) {
|
||||
}, 900);
|
||||
}
|
||||
|
||||
// HELPERS POP-UPS
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// POP-UPS
|
||||
// -----------------------------------------------------------------------------
|
||||
function basenameNoExt(path) {
|
||||
if (!path) return "";
|
||||
const base = String(path).split(/[\\/]/).pop();
|
||||
return base.replace(/\.[^/.]+$/, "");
|
||||
}
|
||||
|
||||
function trackLabel(track, idx) {
|
||||
const name =
|
||||
track?.name ||
|
||||
@@ -389,12 +404,14 @@ function trackLabel(track, idx) {
|
||||
track?.sample?.displayName;
|
||||
return name ? `(Faixa ${idx + 1})` : `Faixa ${idx + 1}`;
|
||||
}
|
||||
|
||||
function actorOf(action) {
|
||||
const n = action.__senderName || action.userName;
|
||||
if (n && typeof n === "string") return n;
|
||||
const sid = action.__senderId ? String(action.__senderId) : "";
|
||||
return `Alicer-${sid.slice(0, 4) || "????"}`;
|
||||
}
|
||||
|
||||
function instrumentLabel(track, tIdx) {
|
||||
const name =
|
||||
track?.name ||
|
||||
@@ -421,7 +438,9 @@ function schedulePatternRerender() {
|
||||
});
|
||||
}
|
||||
|
||||
// RECEBER BROADCAST
|
||||
// -----------------------------------------------------------------------------
|
||||
// BROADCAST
|
||||
// -----------------------------------------------------------------------------
|
||||
socket.on("feedback", (msg) => {
|
||||
console.log("[Servidor]", msg);
|
||||
showToast(msg, "info");
|
||||
@@ -444,7 +463,9 @@ socket.on("action_broadcast", (payload) => {
|
||||
handleActionBroadcast(action);
|
||||
});
|
||||
|
||||
// PROCESSAR AÇÕES RECEBIDAS
|
||||
// -----------------------------------------------------------------------------
|
||||
// PROCESSAR AÇÕES
|
||||
// -----------------------------------------------------------------------------
|
||||
let isLoadingProject = false;
|
||||
async function handleActionBroadcast(action) {
|
||||
if (!action || !action.type) return;
|
||||
@@ -618,26 +639,7 @@ async function handleActionBroadcast(action) {
|
||||
await parseMmpContent(action.xml); //
|
||||
renderAll();
|
||||
showToast("🎶 Projeto sync", "success");
|
||||
|
||||
// --- INÍCIO DA CORREÇÃO ---
|
||||
// O problema é esta chamada. Ela cria um "eco" (SYNC_PATTERN_STATE)
|
||||
// que força um segundo 'parseMmpContent' e quebra o estado.
|
||||
|
||||
// REMOVA ou COMENTE este bloco:
|
||||
/*
|
||||
if (window.ROOM_NAME) {
|
||||
console.log(
|
||||
"LOAD_PROJECT: Sincronizando novo estado com o servidor..."
|
||||
);
|
||||
syncPatternStateToServer(); //
|
||||
}
|
||||
*/
|
||||
|
||||
// EM VEZ DISSO, apenas salve o estado na sessão local.
|
||||
// O `syncPatternStateToServer` agora é responsabilidade do servidor
|
||||
// (que já recebeu o LOAD_PROJECT) ou de outras ações.
|
||||
saveStateToSession();
|
||||
// --- FIM DA CORREÇÃO ---
|
||||
} catch (e) {
|
||||
console.error("Erro LOAD_PROJECT:", e);
|
||||
showToast("❌ Erro projeto", "error");
|
||||
@@ -661,15 +663,9 @@ async function handleActionBroadcast(action) {
|
||||
|
||||
case "RESET_ROOM":
|
||||
console.log("Socket: Recebendo comando de RESET_ROOM do servidor."); //
|
||||
|
||||
// --- INÍCIO DA CORREÇÃO ---
|
||||
// Faltava esta linha para definir quem executou a ação
|
||||
const who = actorOf(action);
|
||||
// --- FIM DA CORREÇÃO ---
|
||||
|
||||
handleLocalProjectReset(); //
|
||||
showToast(`🧹 Reset por ${who}`, "warning"); //
|
||||
|
||||
handleLocalProjectReset();
|
||||
showToast(`🧹 Reset por ${who}`, "warning");
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession(); //
|
||||
break;
|
||||
@@ -768,31 +764,78 @@ async function handleActionBroadcast(action) {
|
||||
|
||||
// Notes
|
||||
case "TOGGLE_NOTE": {
|
||||
const { trackIndex: ti, patternIndex: pi, stepIndex: si, isActive } = action;
|
||||
|
||||
const t = appState.pattern.tracks[ti];
|
||||
if (t) {
|
||||
t.patterns[pi] = t.patterns[pi] || { steps: [] };
|
||||
t.patterns[pi].steps[si] = isActive;
|
||||
|
||||
try { updateStepUI(ti, pi, si, isActive); } catch {}
|
||||
if (!isFromSelf) schedulePatternRerender();
|
||||
}
|
||||
|
||||
// ✔ ADICIONE ISTO
|
||||
if (window.ROOM_NAME && isFromSelf) {
|
||||
const xml = generateXmlFromStateExported();
|
||||
sendAction({
|
||||
type: "SYNC_PATTERN_STATE",
|
||||
xml
|
||||
});
|
||||
}
|
||||
|
||||
saveStateToSession();
|
||||
break;
|
||||
}
|
||||
|
||||
case "UPDATE_PATTERN_NOTES": {
|
||||
const {
|
||||
trackIndex: ti,
|
||||
patternIndex: pi,
|
||||
stepIndex: si,
|
||||
isActive,
|
||||
notes,
|
||||
steps: incomingSteps,
|
||||
} = action;
|
||||
|
||||
const t = appState.pattern.tracks[ti];
|
||||
if (t) {
|
||||
t.patterns[pi] = t.patterns[pi] || { steps: [] };
|
||||
t.patterns[pi].steps[si] = isActive;
|
||||
if (!t) break;
|
||||
|
||||
// Garante o pattern
|
||||
if (!t.patterns[pi]) t.patterns[pi] = { steps: [], notes: [] };
|
||||
|
||||
// 1) Atualiza notas
|
||||
t.patterns[pi].notes = Array.isArray(notes) ? notes : [];
|
||||
|
||||
// 2) Se steps vieram junto, atualiza
|
||||
if (Array.isArray(incomingSteps)) {
|
||||
t.patterns[pi].steps = incomingSteps;
|
||||
}
|
||||
|
||||
// 3) Atualiza interface
|
||||
try {
|
||||
schedulePatternRerender();
|
||||
} catch (e) {
|
||||
console.warn("Erro no render UPDATE_PATTERN_NOTES", e);
|
||||
}
|
||||
|
||||
// 4) Sync online somente se fui EU quem enviei
|
||||
const isFromSelf = action.__senderId === socket.id;
|
||||
if (window.ROOM_NAME && isFromSelf) {
|
||||
try {
|
||||
updateStepUI(ti, pi, si, isActive);
|
||||
} catch {}
|
||||
if (!isFromSelf) {
|
||||
schedulePatternRerender();
|
||||
const xml = generateXmlFromStateExported(); // ← CORREÇÃO
|
||||
sendAction({
|
||||
type: "SYNC_PATTERN_STATE",
|
||||
xml,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("Erro gerando XML UPDATE_PATTERN_NOTES", e);
|
||||
}
|
||||
}
|
||||
const who = actorOf(action);
|
||||
const v = isActive ? "+" : "-";
|
||||
showToast(`🎯 ${who} ${v} nota ${ti + 1}.${pi + 1}.${si + 1}`, "info");
|
||||
// Salva o estado localmente também!
|
||||
|
||||
// 5) Salva no sessionStorage
|
||||
saveStateToSession();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Samples
|
||||
case "SET_TRACK_SAMPLE": {
|
||||
const ti = action.trackIndex;
|
||||
|
||||
Reference in new issue
Block a user