Index: binaries/data/mods/public/gui/loading/loading.js =================================================================== --- binaries/data/mods/public/gui/loading/loading.js +++ binaries/data/mods/public/gui/loading/loading.js @@ -58,25 +58,28 @@ } Engine.GetGUIObjectByName("progressText").caption = ""; - Engine.GetGUIObjectByName("progressbar").caption = 0; + + let progressbar = Engine.GetGUIObjectByName("progressbar"); + progressbar.caption = 0; + progressbar.onGameLoadProgress = displayProgress; Engine.GetGUIObjectByName("quoteText").caption = translate(pickRandom(Engine.ReadFileLines(g_QuotesFile).filter(line => line))); } -function displayProgress() +function displayProgress(progression, description) { // Make the progessbar finish a little early so that the user can actually see it finish - if (g_Progress >= 100) + if (progression >= 100) return; // Show 100 when it is really 99 - let progress = g_Progress + 1; + let progress = progression + 1; Engine.GetGUIObjectByName("progressbar").caption = progress; // display current progress Engine.GetGUIObjectByName("progressText").caption = progress + "%"; // Displays detailed loading info rather than a percent - // Engine.GetGUIObjectByName("progressText").caption = g_LoadDescription; // display current progess details + // Engine.GetGUIObjectByName("progressText").caption = description; // Keep curved right edge of progress bar in sync with the rest of the progress bar let middle = Engine.GetGUIObjectByName("progressbar"); Index: binaries/data/mods/public/gui/loading/loading.xml =================================================================== --- binaries/data/mods/public/gui/loading/loading.xml +++ binaries/data/mods/public/gui/loading/loading.xml @@ -21,7 +21,6 @@ > - displayProgress(); Index: binaries/data/mods/public/gui/session/messages.js =================================================================== --- binaries/data/mods/public/gui/session/messages.js +++ binaries/data/mods/public/gui/session/messages.js @@ -726,11 +726,13 @@ ); } -function onReplayOutOfSync() +function onReplayOutOfSync(turn, hash, expectedHash) { messageBox( 500, 140, - translate("Out-Of-Sync error!") + "\n" + + sprintf(translate("Out-Of-Sync error on turn %(turn)s."), { + "turn": turn + }) + "\n" + // Translation: This is shown if replay is out of sync translateWithContext("Out-Of-Sync", "The current game state is different from the original game state."), translate("Out of Sync") Index: binaries/data/mods/public/gui/session/session.xml =================================================================== --- binaries/data/mods/public/gui/session/session.xml +++ binaries/data/mods/public/gui/session/session.xml @@ -24,7 +24,7 @@ - onReplayOutOfSync(); + onReplayOutOfSync(arguments[0], arguments[1], arguments[2]); Index: source/gui/CGUI.h =================================================================== --- source/gui/CGUI.h +++ source/gui/CGUI.h @@ -97,6 +97,14 @@ void SendEventToAll(const CStr& EventName); /** + * Sends a specified script event to every object + * + * @param EventName String representation of event name + * @param data A JS::Value that further describes event data + */ + void SendEventToAll(const CStr& EventName, JS::HandleValueArray argv); + + /** * Displays the whole GUI */ void Draw(); Index: source/gui/CGUI.cpp =================================================================== --- source/gui/CGUI.cpp +++ source/gui/CGUI.cpp @@ -274,8 +274,12 @@ // (sending events here) wasn't converting to lower case, // leading to a similar problem. // now fixed; case is irrelevant since all are converted to lower. - GUI::RecurseObject(0, m_BaseObject, - &IGUIObject::ScriptEvent, EventName.LowerCase()); + GUI::RecurseObject(0, m_BaseObject, &IGUIObject::ScriptEvent, EventName.LowerCase()); +} + +void CGUI::SendEventToAll(const CStr& EventName, JS::HandleValueArray argv) +{ + GUI::RecurseObject(0, m_BaseObject, &IGUIObject::ScriptEvent, EventName.LowerCase(), argv); } CGUI::CGUI(const shared_ptr& runtime) Index: source/gui/GUIManager.h =================================================================== --- source/gui/GUIManager.h +++ source/gui/GUIManager.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -111,6 +111,7 @@ * See CGUI::SendEventToAll; applies to the currently active page. */ void SendEventToAll(const CStr& eventName) const; + void SendEventToAll(const CStr& eventName, JS::HandleValueArray data) const; /** * See CGUI::TickObjects; applies to @em all loaded pages. Index: source/gui/GUIManager.cpp =================================================================== --- source/gui/GUIManager.cpp +++ source/gui/GUIManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -357,6 +357,11 @@ top()->SendEventToAll(eventName); } +void CGUIManager::SendEventToAll(const CStr& eventName, JS::HandleValueArray data) const +{ + top()->SendEventToAll(eventName, data); +} + void CGUIManager::TickObjects() { PROFILE3("gui tick"); Index: source/gui/GUIutil.h =================================================================== --- source/gui/GUIutil.h +++ source/gui/GUIutil.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -222,6 +222,7 @@ typedef void (IGUIObject::*void_Object_pFunction_argT)(const T& arg); typedef void (IGUIObject::*void_Object_pFunction_argRefT)(T& arg); typedef void (IGUIObject::*void_Object_pFunction)(); + typedef void (IGUIObject::*void_Object_pFunction_argTJS)(const T& arg, JS::HandleValueArray args); /** * If you want to call a IGUIObject-function @@ -279,6 +280,18 @@ RecurseObject(RR, obj, pFunc, Argument); } + static void RecurseObject(int RR, IGUIObject* pObject, void_Object_pFunction_argTJS pFunc, const T& Argument, JS::HandleValueArray Data) + { + if (CheckIfRestricted(RR, pObject)) + return; + + (pObject->*pFunc)(Argument, Data); + + // Iterate children + for (IGUIObject* const& obj : *pObject) + RecurseObject(RR, obj, pFunc, Argument, Data); + } + /** * With no argument. * Index: source/gui/IGUIObject.h =================================================================== --- source/gui/IGUIObject.h +++ source/gui/IGUIObject.h @@ -394,6 +394,7 @@ * @param Action Name of action */ void ScriptEvent(const CStr& Action); + void ScriptEvent(const CStr& Action, JS::HandleValueArray paramData); /** * Execute the script for a particular action. Index: source/gui/IGUIObject.cpp =================================================================== --- source/gui/IGUIObject.cpp +++ source/gui/IGUIObject.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -490,11 +490,25 @@ JS::RootedObject obj(cx, GetJSObject()); JS::RootedValue handlerVal(cx, JS::ObjectValue(*it->second)); JS::RootedValue result(cx); - bool ok = JS_CallFunctionValue(cx, obj, handlerVal, paramData, &result); - if (!ok) - { + + if (!JS_CallFunctionValue(cx, obj, handlerVal, paramData, &result)) + JS_ReportError(cx, "Errors executing script action \"%s\"", Action.c_str()); +} + +void IGUIObject::ScriptEvent(const CStr& Action, JS::HandleValueArray paramData) +{ + std::map>::iterator it = m_ScriptHandlers.find(Action); + if (it == m_ScriptHandlers.end()) + return; + + JSContext* cx = m_pGUI->GetScriptInterface()->GetContext(); + JSAutoRequest rq(cx); + JS::RootedObject obj(cx, GetJSObject()); + JS::RootedValue handlerVal(cx, JS::ObjectValue(*it->second)); + JS::RootedValue result(cx); + + if (!JS_CallFunctionValue(cx, obj, handlerVal, paramData, &result)) JS_ReportError(cx, "Errors executing script action \"%s\"", Action.c_str()); - } } JSObject* IGUIObject::GetJSObject() Index: source/ps/GameSetup/GameSetup.cpp =================================================================== --- source/ps/GameSetup/GameSetup.cpp +++ source/ps/GameSetup/GameSetup.cpp @@ -183,9 +183,19 @@ // display progress / description in loading screen void GUI_DisplayLoadProgress(int percent, const wchar_t* pending_task) { - g_GUI->GetActiveGUI()->GetScriptInterface()->SetGlobal("g_Progress", percent, true, false, true); - g_GUI->GetActiveGUI()->GetScriptInterface()->SetGlobal("g_LoadDescription", pending_task, true, false, true); - g_GUI->GetActiveGUI()->SendEventToAll("progress"); + const ScriptInterface& scriptInterface = *(g_GUI->GetActiveGUI()->GetScriptInterface()); + JSContext* cx = scriptInterface.GetContext(); + JSAutoRequest rq(cx); + + JS::AutoValueVector argv(cx); + + argv.append(JS::NumberValue(percent)); + + JS::RootedValue valPendingTask(cx); + scriptInterface.ToJSVal(cx, &valPendingTask, pending_task); + argv.append(valPendingTask); + + g_GUI->GetActiveGUI()->SendEventToAll("GameLoadProgress", argv); } void SwapBuffers() Index: source/simulation2/system/ReplayTurnManager.cpp =================================================================== --- source/simulation2/system/ReplayTurnManager.cpp +++ source/simulation2/system/ReplayTurnManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -76,12 +76,29 @@ ENSURE(m_Simulation2.ComputeStateHash(hash, quickHash)); hash = Hexify(hash); - if (hash != expectedHash) - { - m_HasSyncError = true; - LOGERROR("Replay out of sync on turn %d", turn); - g_GUI->SendEventToAll("ReplayOutOfSync"); - } + if (hash == expectedHash) + return; + + m_HasSyncError = true; + LOGERROR("Replay out of sync on turn %d", turn); + + const ScriptInterface& scriptInterface = m_Simulation2.GetScriptInterface(); + JSContext* cx = scriptInterface.GetContext(); + JSAutoRequest rq(cx); + + JS::AutoValueVector argv(cx); + + argv.append(JS::NumberValue(turn)); + + JS::RootedValue hashVal(cx); + scriptInterface.ToJSVal(cx, &hashVal, hash); + argv.append(hashVal); + + JS::RootedValue expectedHashVal(cx); + scriptInterface.ToJSVal(cx, &expectedHashVal, expectedHash); + argv.append(expectedHashVal); + + g_GUI->SendEventToAll("ReplayOutOfSync", argv); } void CReplayTurnManager::DoTurn(u32 turn)