diff --git a/addons/extension/fnc_initSession.sqf b/addons/extension/fnc_initSession.sqf
index a7d7abd..793f841 100644
--- a/addons/extension/fnc_initSession.sqf
+++ b/addons/extension/fnc_initSession.sqf
@@ -154,6 +154,78 @@ addMissionEventHandler ["ExtensionCallback", {
INFO("Mission registered. Starting data send.");
GVAR(sessionReady) = true;
};
+
+ if (_function isEqualTo ":MISSION:SAVED:") exitWith {
+ // Payload shapes:
+ // ["ok", path]
+ // ["partial", path, error]
+ // ["error", error]
+ // Type-check each field: if the extension ever sends something
+ // unexpected, fall back to an empty string rather than crashing
+ // the callback handler with a type error in the switch below.
+ private _status = _data param [0, "", [""]];
+ private _detail = _data param [1, "", [""]];
+ private _extra = _data param [2, "", [""]];
+
+ // finalDiary appends a final status entry to the OCAPInfo diary
+ // subject so the interim "being saved" record from fnc_exportData.sqf
+ // is followed by the authoritative outcome.
+ private _finalDiary = {
+ params ["_diaryHtml"];
+ [[_diaryHtml], {
+ params ["_html"];
+ player createDiaryRecord [
+ "OCAPInfo",
+ ["Status", _html]
+ ];
+ }] remoteExec ["call", [0, -2] select isDedicated, true];
+ };
+
+ switch (_status) do {
+ case "ok": {
+ INFO_1("Mission save complete — path: %1",_detail);
+ GVAR(lastSaveResult) = ["ok", _detail];
+ [
+ format["OCAP saved %1 successfully", briefingName],
+ 2,
+ [0, 0.8, 0, 1]
+ ] remoteExec ["CBA_fnc_notify", [0, -2] select isDedicated];
+ [format[
+ "OCAP capture of %1 has been exported and uploaded successfully.",
+ briefingName
+ ]] call _finalDiary;
+ };
+ case "partial": {
+ WARNING_2("Mission save complete but upload failed — path: %1 error: %2",_detail,_extra);
+ GVAR(lastSaveResult) = ["partial", _detail, _extra];
+ [
+ format["OCAP saved locally (%1) but upload failed: %2", _detail, _extra],
+ 2,
+ [1, 0.8, 0, 1]
+ ] remoteExec ["CBA_fnc_notify", [0, -2] select isDedicated];
+ [format[
+ "OCAP capture of %1 was saved locally to %2, but the upload to the web server failed:
%3",
+ briefingName, _detail, _extra
+ ]] call _finalDiary;
+ };
+ case "error": {
+ ERROR_MSG_1("Mission save failed: %1",_detail);
+ GVAR(lastSaveResult) = ["error", _detail];
+ [
+ format["OCAP save failed: %1", _detail],
+ 2,
+ [1, 0, 0, 1]
+ ] remoteExec ["CBA_fnc_notify", [0, -2] select isDedicated];
+ [format[
+ "OCAP save of %1 failed:
%2",
+ briefingName, _detail
+ ]] call _finalDiary;
+ };
+ default {
+ WARNING_1("Unknown :MISSION:SAVED: status: %1",_status);
+ };
+ };
+ };
}];
diff --git a/addons/recorder/fnc_exportData.sqf b/addons/recorder/fnc_exportData.sqf
index a4654d3..c6f910c 100644
--- a/addons/recorder/fnc_exportData.sqf
+++ b/addons/recorder/fnc_exportData.sqf
@@ -123,14 +123,20 @@ private _endMessage = if (isNil "_message") then {if (_winSide == "") then {"Mis
private _saveTag = if (!isNil "_tag") then {_tag} else {EGVAR(settings,saveTag)};
INFO_3("Saving recording — mission: %1 | frames: %2 | tag: %3",GVAR(missionName),_endFrameNumber,_saveTag);
-private _saveStart = diag_tickTime;
-[":MISSION:SAVE:", []] call EFUNC(extension,sendData);
-INFO_2("Recording saved — took %1 ms | mission: %2",round ((diag_tickTime - _saveStart) * 1000),GVAR(missionName));
-OCAPEXTLOG(ARR4("Saved recording of mission",GVAR(missionName),"with tag",_saveTag));
+// Save is now asynchronous — the extension returns immediately and will fire
+// a :MISSION:SAVED: ExtensionCallback when the write + upload finishes.
+// The final success/failure notification is driven from that callback in
+// fnc_initSession.sqf.
+INFO_2("Mission save queued — mission: %1 | frames: %2",GVAR(missionName),_endFrameNumber);
+[":MISSION:SAVE:", []] call EFUNC(extension,sendData);
+OCAPEXTLOG(ARR4("Queued recording of mission",GVAR(missionName),"with tag",_saveTag));
-// notify players that the recording was saved with a 2 second delay to ensure the "stopped recording" entries populate first
-[format["OCAP saved %1 frames successfully", _endFrameNumber], 1, [1, 1, 1, 1]] remoteExec ["CBA_fnc_notify", [0, -2] select isDedicated];
+// Interim "saving..." toast; the final result comes from :MISSION:SAVED:
+[format["OCAP saving %1 (%2 frames) — upload will follow", briefingName, _endFrameNumber], 1, [1, 1, 1, 1]] remoteExec ["CBA_fnc_notify", [0, -2] select isDedicated];
+// Interim diary record. The final "exported successfully" / "upload failed"
+// record is appended from the :MISSION:SAVED: ExtensionCallback handler in
+// fnc_initSession.sqf once the async save completes.
[[GVAR(missionName), GVAR(captureFrameNo)], {
params ["_missionName", "_endFrame"];
@@ -143,7 +149,7 @@ OCAPEXTLOG(ARR4("Saved recording of mission",GVAR(missionName),"with tag",_saveT
[
"Status",
format[
- "OCAP capture of %1 has been exported with %2 frames saved.
Upload results have been logged.",
+ "OCAP capture of %1 with %2 frames is being saved and uploaded.
Final status will be reported when the upload completes.",
_missionName,
_endFrame
]