Index: source/graphics/MapGenerator.cpp =================================================================== --- source/graphics/MapGenerator.cpp +++ source/graphics/MapGenerator.cpp @@ -397,7 +397,8 @@ JS::RootedValue returnValue(cx); - self->m_ScriptInterface->CreateObject( + ScriptInterface::CreateObject( + cx, &returnValue, "height", heightmap, "textureNames", textureNames, Index: source/graphics/MapReader.cpp =================================================================== --- source/graphics/MapReader.cpp +++ source/graphics/MapReader.cpp @@ -372,7 +372,7 @@ JSContext* cx = scriptInterface.GetContext(); JSAutoRequest rq(cx); - scriptInterface.CreateObject(ret); + ScriptInterface::CreateObject(cx, ret); if (m_ScriptSettings.empty()) return; Index: source/gui/IGUIObject.cpp =================================================================== --- source/gui/IGUIObject.cpp +++ source/gui/IGUIObject.cpp @@ -407,7 +407,8 @@ const CPos& mousePos = m_pGUI.GetMousePos(); - m_pGUI.GetScriptInterface()->CreateObject( + ScriptInterface::CreateObject( + cx, &mouse, "x", mousePos.x, "y", mousePos.y, Index: source/gui/MiniMap.cpp =================================================================== --- source/gui/MiniMap.cpp +++ source/gui/MiniMap.cpp @@ -245,7 +245,7 @@ GetMouseWorldCoordinates(x, z); JS::RootedValue coords(cx); - g_GUI->GetActiveGUI()->GetScriptInterface()->CreateObject(&coords, "x", x, "z", z); + ScriptInterface::CreateObject(cx, &coords, "x", x, "z", z); JS::AutoValueVector paramData(cx); paramData.append(coords); Index: source/gui/scripting/GuiScriptConversions.cpp =================================================================== --- source/gui/scripting/GuiScriptConversions.cpp +++ source/gui/scripting/GuiScriptConversions.cpp @@ -157,7 +157,7 @@ template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CSize& val) { - ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface->CreateObject(ret, "width", val.cx, "height", val.cy); + CreateObject(cx, ret, "width", val.cx, "height", val.cy); } template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, CSize& out) @@ -185,7 +185,7 @@ template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CPos& val) { - ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface->CreateObject(ret, "x", val.x, "y", val.y); + CreateObject(cx, ret, "x", val.x, "y", val.y); } template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, CPos& out) @@ -213,7 +213,8 @@ template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CRect& val) { - ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface->CreateObject( + CreateObject( + cx, ret, "left", val.left, "right", val.right, Index: source/gui/scripting/JSInterface_IGUIObject.cpp =================================================================== --- source/gui/scripting/JSInterface_IGUIObject.cpp +++ source/gui/scripting/JSInterface_IGUIObject.cpp @@ -102,7 +102,7 @@ } else if (propName == "children") { - pScriptInterface->CreateArray(vp); + ScriptInterface::CreateArray(cx, vp); for (size_t i = 0; i < e->m_Children.size(); ++i) pScriptInterface->SetPropertyInt(vp, i, e->m_Children[i]); Index: source/lobby/XmppClient.h =================================================================== --- source/lobby/XmppClient.h +++ source/lobby/XmppClient.h @@ -91,7 +91,6 @@ void GetPresence(const std::string& nickname, std::string& presence); void GetRole(const std::string& nickname, std::string& role); void GetSubject(std::string& subject); - void GUIGetPlayerList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret); void GUIGetGameList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret); void GUIGetBoardList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret); @@ -99,6 +98,17 @@ void SendStunEndpointToHost(const StunClient::StunEndpoint& stunEndpoint, const std::string& hostJID); + /** + * String conversions. + */ + static void GetPresenceString(const gloox::Presence::PresenceType p, std::string& presence); + static void GetRoleString(const gloox::MUCRoomRole r, std::string& role); + static std::string StanzaErrorToString(gloox::StanzaError err); + static std::string RegistrationResultToString(gloox::RegistrationResult res); + static std::string ConnectionErrorToString(gloox::ConnectionError err); + static std::string CertStatusToString(gloox::CertStatus status); + static std::time_t ComputeTimestamp(const glooxwrapper::Message& msg); + protected: /* Xmpp handlers */ /* MUC handlers */ @@ -138,15 +148,6 @@ virtual void handleSessionAction(gloox::Jingle::Action action, glooxwrapper::Jingle::Session& session, const glooxwrapper::Jingle::Session::Jingle& jingle); virtual void handleSessionInitiation(glooxwrapper::Jingle::Session& session, const glooxwrapper::Jingle::Session::Jingle& jingle); - // Helpers - void GetPresenceString(const gloox::Presence::PresenceType p, std::string& presence) const; - void GetRoleString(const gloox::MUCRoomRole r, std::string& role) const; - std::string TLSErrorToString(gloox::CertStatus status) const; - std::string StanzaErrorToString(gloox::StanzaError err) const; - std::string ConnectionErrorToString(gloox::ConnectionError err) const; - std::string RegistrationResultToString(gloox::RegistrationResult res) const; - std::time_t ComputeTimestamp(const glooxwrapper::Message& msg) const; - public: bool GuiPollPresenceStatusUpdate(); JS::Value GuiPollNewMessage(const ScriptInterface& scriptInterface); @@ -162,8 +163,24 @@ Args const&... args); private: + struct SPlayer { + + SPlayer() + : m_Presence(gloox::Presence::PresenceType::Invalid), m_Rating(), m_Role(gloox::MUCRoomRole::RoleInvalid) + { + } + + SPlayer(const gloox::Presence::PresenceType presence, const glooxwrapper::string& rating, const gloox::MUCRoomRole& role) + : m_Presence(presence), m_Rating(rating), m_Role(role) + { + } + + gloox::Presence::PresenceType m_Presence; + glooxwrapper::string m_Rating; + gloox::MUCRoomRole m_Role; + }; /// Map of players - std::map > m_PlayerMap; + std::map m_PlayerMap; /// List of games std::vector m_GameList; /// List of rankings Index: source/lobby/XmppClient.cpp =================================================================== --- source/lobby/XmppClient.cpp +++ source/lobby/XmppClient.cpp @@ -25,6 +25,7 @@ #endif #include "i18n/L10n.h" +#include "lobby/scripting/GlooxScriptConversions.cpp" #include "lib/external_libraries/enet.h" #include "lib/utf8.h" #include "network/NetServer.h" @@ -37,7 +38,7 @@ #include //debug -#if 1 +#if 0 #define DbgXMPP(x) #else #define DbgXMPP(x) std::cout << x << std::endl; @@ -267,7 +268,7 @@ m_HistoricGuiMessages.clear(); m_isConnected = false; - CreateGUIMessage("system", "disconnected", std::time(nullptr), "reason", ConnectionErrorToString(error)); + CreateGUIMessage("system", "disconnected", std::time(nullptr), "reason", error, "cert_status", m_certStatus); } /** @@ -299,7 +300,7 @@ */ void XmppClient::handleMUCError(glooxwrapper::MUCRoom*, gloox::StanzaError err) { - CreateGUIMessage("system", "error", std::time(nullptr), "text", StanzaErrorToString(err)); + CreateGUIMessage("system", "error", std::time(nullptr), "text", err); } /***************************************************** @@ -486,7 +487,7 @@ if (result == gloox::RegistrationSuccess) CreateGUIMessage("system", "registered", std::time(nullptr)); else - CreateGUIMessage("system", "error", std::time(nullptr), "text", RegistrationResultToString(result)); + CreateGUIMessage("system", "error", std::time(nullptr), "text", result); disconnect(); } @@ -520,19 +521,20 @@ JSContext* cx = scriptInterface.GetContext(); JSAutoRequest rq(cx); - scriptInterface.CreateArray(ret); + ScriptInterface::CreateArray(cx, ret); int j = 0; - for (const std::pair >& p : m_PlayerMap) + for (const std::pair& p : m_PlayerMap) { JS::RootedValue player(cx); - scriptInterface.CreateObject( + ScriptInterface::CreateObject( + cx, &player, - "name", wstring_from_utf8(p.first), - "presence", wstring_from_utf8(p.second[0]), - "rating", wstring_from_utf8(p.second[1]), - "role", wstring_from_utf8(p.second[2])); + "name", p.first, + "presence", p.second.m_Presence, + "rating", p.second.m_Rating, + "role", p.second.m_Role); scriptInterface.SetPropertyInt(ret, j++, player); } @@ -548,7 +550,7 @@ JSContext* cx = scriptInterface.GetContext(); JSAutoRequest rq(cx); - scriptInterface.CreateArray(ret); + ScriptInterface::CreateArray(cx, ret); int j = 0; const char* stats[] = { "name", "ip", "port", "stunIP", "stunPort", "hostUsername", "state", @@ -558,7 +560,7 @@ for(const glooxwrapper::Tag* const& t : m_GameList) { JS::RootedValue game(cx); - scriptInterface.CreateObject(&game); + ScriptInterface::CreateObject(cx, &game); for (size_t i = 0; i < ARRAY_SIZE(stats); ++i) scriptInterface.SetProperty(game, stats[i], wstring_from_utf8(t->findAttribute(stats[i]).to_string())); @@ -577,7 +579,7 @@ JSContext* cx = scriptInterface.GetContext(); JSAutoRequest rq(cx); - scriptInterface.CreateArray(ret); + ScriptInterface::CreateArray(cx, ret); int j = 0; const char* attributes[] = { "name", "rank", "rating" }; @@ -585,7 +587,7 @@ for(const glooxwrapper::Tag* const& t : m_BoardList) { JS::RootedValue board(cx); - scriptInterface.CreateObject(&board); + ScriptInterface::CreateObject(cx, &board); for (size_t i = 0; i < ARRAY_SIZE(attributes); ++i) scriptInterface.SetProperty(board, attributes[i], wstring_from_utf8(t->findAttribute(attributes[i]).to_string())); @@ -604,7 +606,7 @@ JSContext* cx = scriptInterface.GetContext(); JSAutoRequest rq(cx); - scriptInterface.CreateArray(ret); + ScriptInterface::CreateArray(cx, ret); int j = 0; const char* stats[] = { "player", "rating", "totalGamesPlayed", "highestRating", "wins", "losses", "rank" }; @@ -612,7 +614,7 @@ for (const glooxwrapper::Tag* const& t : m_Profile) { JS::RootedValue profile(cx); - scriptInterface.CreateObject(&profile); + ScriptInterface::CreateObject(cx, &profile); for (size_t i = 0; i < ARRAY_SIZE(stats); ++i) scriptInterface.SetProperty(profile, stats[i], wstring_from_utf8(t->findAttribute(stats[i]).to_string())); @@ -651,7 +653,7 @@ JSContext* cx = m_ScriptInterface->GetContext(); JSAutoRequest rq(cx); JS::RootedValue message(cx); - m_ScriptInterface->CreateObject(&message, "type", type, "level", level, "time", static_cast(time)); + ScriptInterface::CreateObject(cx, &message, "type", type, "level", level, "time", static_cast(time)); JS::RootedObject messageObj(cx, message.toObjectOrNull()); SetGUIMessageProperty(cx, messageObj, args...); m_ScriptInterface->FreezeObject(message, true); @@ -694,7 +696,7 @@ JSAutoRequest rq(cx); JS::RootedValue ret(cx); - scriptInterface.CreateArray(&ret); + ScriptInterface::CreateArray(cx, &ret); int j = 0; for (const JS::Heap& message : m_HistoricGuiMessages) @@ -722,8 +724,8 @@ "chat", priv ? "private-message" : "room-message", ComputeTimestamp(msg), - "from", msg.from().resource().to_string(), - "text", msg.body().to_string()); + "from", msg.from().resource(), + "text", msg.body()); } /** @@ -738,8 +740,8 @@ "chat", "private-message", ComputeTimestamp(msg), - "from", msg.from().resource().to_string(), - "text", msg.body().to_string()); + "from", msg.from().resource(), + "text", msg.body()); } /** @@ -782,9 +784,9 @@ { for (const glooxwrapper::Tag* const& t : bq->m_StanzaBoardList) { - std::string name = t->findAttribute("name").to_string(); + glooxwrapper::string name = t->findAttribute("name"); if (m_PlayerMap.find(name) != m_PlayerMap.end()) - m_PlayerMap[name][1] = t->findAttribute("rating").to_string(); + m_PlayerMap.at(name).m_Rating = t->findAttribute("rating"); } CreateGUIMessage("game", "ratinglist", std::time(nullptr)); @@ -819,10 +821,10 @@ } } else if (iq.subtype() == gloox::IQ::Error) - CreateGUIMessage("system", "error", std::time(nullptr), "text", StanzaErrorToString(iq.error_error())); + CreateGUIMessage("system", "error", std::time(nullptr), "text", iq.error_error()); else { - CreateGUIMessage("system", "error", std::time(nullptr), "text", g_L10n.Translate("unknown subtype (see logs)")); + CreateGUIMessage("system", "error", std::time(nullptr), "text", wstring_from_utf8(g_L10n.Translate("unknown subtype (see logs)"))); LOGMESSAGE("unknown subtype '%s'", tag_name(iq).c_str()); } return true; @@ -833,39 +835,52 @@ */ void XmppClient::handleMUCParticipantPresence(glooxwrapper::MUCRoom*, const glooxwrapper::MUCRoomParticipant participant, const glooxwrapper::Presence& presence) { - std::string nick = participant.nick->resource().to_string(); - gloox::Presence::PresenceType presenceType = presence.presence(); - std::string presenceString, roleString; - GetPresenceString(presenceType, presenceString); - GetRoleString(participant.role, roleString); + const glooxwrapper::string& nick = participant.nick->resource(); - if (presenceType == gloox::Presence::Unavailable) + if (presence.presence() == gloox::Presence::Unavailable) { if (!participant.newNick.empty() && (participant.flags & (gloox::UserNickChanged | gloox::UserSelf))) { // we have a nick change - std::string newNick = participant.newNick.to_string(); - m_PlayerMap[newNick].resize(3); - m_PlayerMap[newNick][0] = presenceString; - m_PlayerMap[newNick][2] = roleString; + m_PlayerMap[nick].m_Presence = presence.presence(); + m_PlayerMap[nick].m_Role = participant.role; - DbgXMPP(nick << " is now known as " << participant.newNick.to_string()); - CreateGUIMessage("chat", "nick", std::time(nullptr), "oldnick", nick, "newnick", participant.newNick.to_string()); + DbgXMPP(nick << " is now known as " << participant.newNick); + CreateGUIMessage( + "chat", + "nick", + std::time(nullptr), + "oldnick", nick, + "newnick", participant.newNick); } else if (participant.flags & gloox::UserKicked) { - DbgXMPP(nick << " was kicked. Reason: " << participant.reason.to_string()); - CreateGUIMessage("chat", "kicked", std::time(nullptr), "nick", nick, "reason", participant.reason.to_string()); + DbgXMPP(nick << " was kicked. Reason: " << participant.reason); + CreateGUIMessage( + "chat", + "kicked", + std::time(nullptr), + "nick", nick, + "reason", participant.reason); } else if (participant.flags & gloox::UserBanned) { - DbgXMPP(nick << " was banned. Reason: " << participant.reason.to_string()); - CreateGUIMessage("chat", "banned", std::time(nullptr), "nick", nick, "reason", participant.reason.to_string()); + DbgXMPP(nick << " was banned. Reason: " << participant.reason); + CreateGUIMessage( + "chat", + "banned", + std::time(nullptr), + "nick", nick, + "reason", participant.reason); } else { DbgXMPP(nick << " left the room (flags " << participant.flags << ")"); - CreateGUIMessage("chat", "leave", std::time(nullptr), "nick", nick); + CreateGUIMessage( + "chat", + "leave", + std::time(nullptr), + "nick", nick); } m_PlayerMap.erase(nick); } @@ -877,23 +892,36 @@ */ if (!m_initialLoadComplete) { - if (m_mucRoom->nick().to_string() == nick) + if (m_mucRoom->nick() == nick) m_initialLoadComplete = true; } - else if (m_PlayerMap.find(nick) == m_PlayerMap.end()) - CreateGUIMessage("chat", "join", std::time(nullptr), "nick", nick); - else if (m_PlayerMap[nick][2] != roleString) - CreateGUIMessage("chat", "role", std::time(nullptr), "nick", nick, "oldrole", m_PlayerMap[nick][2], "newrole", roleString); + else if (m_PlayerMap.count(nick) == 0) + { + CreateGUIMessage( + "chat", + "join", + std::time(nullptr), + "nick", nick); + } + else if (m_PlayerMap.at(nick).m_Role != participant.role) + { + CreateGUIMessage( + "chat", + "role", + std::time(nullptr), + "nick", nick, + "oldrole", m_PlayerMap.at(nick).m_Role, + "newrole", participant.role); + } else // Don't create a GUI message for regular presence changes, because // several hundreds of them accumulate during a match, impacting performance terribly and // the only way they are used is to determine whether to update the playerlist. m_PresenceUpdate = true; - DbgXMPP(nick << " is in the room, presence : " << (int)presenceType); - m_PlayerMap[nick].resize(3); - m_PlayerMap[nick][0] = presenceString; - m_PlayerMap[nick][2] = roleString; + DbgXMPP(nick << " is in the room, presence : " << static_cast(presence.presence())); + m_PlayerMap[nick].m_Presence = presence.presence(); + m_PlayerMap[nick].m_Role = participant.role; } } @@ -902,8 +930,14 @@ */ void XmppClient::handleMUCSubject(glooxwrapper::MUCRoom*, const glooxwrapper::string& nick, const glooxwrapper::string& subject) { - m_Subject = subject.c_str(); - CreateGUIMessage("chat", "subject", std::time(nullptr), "nick", nick.c_str(), "subject", m_Subject); + m_Subject = subject.to_string(); + + CreateGUIMessage( + "chat", + "subject", + std::time(nullptr), + "nick", nick, + "subject", subject); } /** @@ -985,7 +1019,7 @@ void XmppClient::GetPresence(const std::string& nick, std::string& presence) { if (m_PlayerMap.find(nick) != m_PlayerMap.end()) - presence = m_PlayerMap[nick][0]; + GetPresenceString(m_PlayerMap.at(nick).m_Presence, presence); else presence = "offline"; } @@ -999,7 +1033,7 @@ void XmppClient::GetRole(const std::string& nick, std::string& role) { if (m_PlayerMap.find(nick) != m_PlayerMap.end()) - role = m_PlayerMap[nick][2]; + GetRoleString(m_PlayerMap.at(nick).m_Role, role); else role = ""; } @@ -1015,7 +1049,7 @@ * * @returns Seconds since the epoch. */ -std::time_t XmppClient::ComputeTimestamp(const glooxwrapper::Message& msg) const +std::time_t XmppClient::ComputeTimestamp(const glooxwrapper::Message& msg) { // Only historic messages contain a timestamp! if (!msg.when()) @@ -1038,7 +1072,7 @@ * @param p Presence to be converted * @param presence Variable to store the converted presence string in */ -void XmppClient::GetPresenceString(const gloox::Presence::PresenceType p, std::string& presence) const +void XmppClient::GetPresenceString(const gloox::Presence::PresenceType p, std::string& presence) { switch(p) { @@ -1065,7 +1099,7 @@ * @param p Role to be converted * @param presence Variable to store the converted role string in */ -void XmppClient::GetRoleString(const gloox::MUCRoomRole r, std::string& role) const +void XmppClient::GetRoleString(const gloox::MUCRoomRole r, std::string& role) { switch(r) { @@ -1086,17 +1120,16 @@ * Translates a gloox certificate error codes, i.e. gloox certificate statuses except CertOk. * Keep in sync with specifications. */ -std::string XmppClient::TLSErrorToString(gloox::CertStatus status) const +std::string XmppClient::CertStatusToString(gloox::CertStatus status) { - // TODO: Use translation std::map certificateErrorStrings = { - { gloox::CertInvalid, ("The certificate is not trusted.") }, - { gloox::CertSignerUnknown, ("The certificate hasn't got a known issuer.") }, - { gloox::CertRevoked, ("The certificate has been revoked.") }, - { gloox::CertExpired, ("The certificate has expired.") }, - { gloox::CertNotActive, ("The certifiacte is not yet active.") }, - { gloox::CertWrongPeer, ("The certificate has not been issued for the peer we're connected to.") }, - { gloox::CertSignerNotCa, ("The signer is not a CA.") } + { gloox::CertInvalid, g_L10n.Translate("The certificate is not trusted.") }, + { gloox::CertSignerUnknown, g_L10n.Translate("The certificate hasn't got a known issuer.") }, + { gloox::CertRevoked, g_L10n.Translate("The certificate has been revoked.") }, + { gloox::CertExpired, g_L10n.Translate("The certificate has expired.") }, + { gloox::CertNotActive, g_L10n.Translate("The certifiacte is not yet active.") }, + { gloox::CertWrongPeer, g_L10n.Translate("The certificate has not been issued for the peer we're connected to.") }, + { gloox::CertSignerNotCa, g_L10n.Translate("The signer is not a CA.") } }; std::string result = ""; @@ -1115,7 +1148,7 @@ * @param err Error to be converted * @return Converted error string */ -std::string XmppClient::StanzaErrorToString(gloox::StanzaError err) const +std::string XmppClient::StanzaErrorToString(gloox::StanzaError err) { #define CASE(X, Y) case gloox::X: return Y #define DEBUG_CASE(X, Y) case gloox::X: return g_L10n.Translate("Error") + " (" + Y + ")" @@ -1159,7 +1192,7 @@ * @param err Error to be converted * @return Converted error string */ -std::string XmppClient::ConnectionErrorToString(gloox::ConnectionError err) const +std::string XmppClient::ConnectionErrorToString(gloox::ConnectionError err) { #define CASE(X, Y) case gloox::X: return Y #define DEBUG_CASE(X, Y) case gloox::X: return g_L10n.Translate("Error") + " (" + Y + ")" @@ -1178,7 +1211,7 @@ CASE(ConnDnsError, g_L10n.Translate("Resolving the server's hostname failed")); CASE(ConnOutOfMemory, g_L10n.Translate("This system is out of memory")); DEBUG_CASE(ConnNoSupportedAuth, "The authentication mechanisms the server offered are not supported or no authentication mechanisms were available"); - CASE(ConnTlsFailed, g_L10n.Translate("The server's certificate could not be verified or the TLS handshake did not complete successfully") + TLSErrorToString(m_certStatus)); + CASE(ConnTlsFailed, g_L10n.Translate("The server's certificate could not be verified or the TLS handshake did not complete successfully")); CASE(ConnTlsNotAvailable, g_L10n.Translate("The server did not offer required TLS encryption")); DEBUG_CASE(ConnCompressionFailed, "Negotiation/initializing compression failed"); CASE(ConnAuthenticationFailed, g_L10n.Translate("Authentication failed. Incorrect password or account does not exist")); @@ -1198,7 +1231,7 @@ * @param err Enum to be converted * @return Converted string */ -std::string XmppClient::RegistrationResultToString(gloox::RegistrationResult res) const +std::string XmppClient::RegistrationResultToString(gloox::RegistrationResult res) { #define CASE(X, Y) case gloox::X: return Y #define DEBUG_CASE(X, Y) case gloox::X: return g_L10n.Translate("Error") + " (" + Y + ")" Index: source/lobby/glooxwrapper/glooxwrapper.h =================================================================== --- source/lobby/glooxwrapper/glooxwrapper.h +++ source/lobby/glooxwrapper/glooxwrapper.h @@ -161,6 +161,9 @@ glooxwrapper_free(m_Data); } + /** + * Gloox strings are UTF encoded, so don't forget to decode it before passing it to the GUI! + */ std::string to_string() const { return std::string(m_Data, m_Size); @@ -181,10 +184,20 @@ return strcmp(m_Data, str) == 0; } + bool operator==(const string& str) const + { + return strcmp(m_Data, str.m_Data) == 0; + } + bool operator!=(const char* str) const { return strcmp(m_Data, str) != 0; } + + bool operator<(const string& str) const + { + return strcmp(m_Data, str.m_Data) < 0; + } }; static inline std::ostream& operator<<(std::ostream& stream, const string& string) Index: source/network/NetClient.h =================================================================== --- source/network/NetClient.h +++ source/network/NetClient.h @@ -161,7 +161,7 @@ JSAutoRequest rq(cx); JS::RootedValue message(cx); - GetScriptInterface().CreateObject(&message, args...); + ScriptInterface::CreateObject(cx, &message, args...); m_GuiMessageQueue.push_back(JS::Heap(message)); } Index: source/network/NetClient.cpp =================================================================== --- source/network/NetClient.cpp +++ source/network/NetClient.cpp @@ -277,15 +277,16 @@ JSAutoRequest rq(cx); JS::RootedValue newAssignments(cx); - GetScriptInterface().CreateObject(&newAssignments); + ScriptInterface::CreateObject(cx, &newAssignments); for (const std::pair& p : m_PlayerAssignments) { JS::RootedValue assignment(cx); - GetScriptInterface().CreateObject( + ScriptInterface::CreateObject( + cx, &assignment, - "name", CStrW(p.second.m_Name), + "name", p.second.m_Name, "player", p.second.m_PlayerID, "status", p.second.m_Status); Index: source/network/StunClient.cpp =================================================================== --- source/network/StunClient.cpp +++ source/network/StunClient.cpp @@ -394,7 +394,7 @@ JSAutoRequest rq(cx); JS::RootedValue stunEndpoint(cx); - scriptInterface.CreateObject(&stunEndpoint, "ip", CStr(ipStr), "port", m_Port); + ScriptInterface::CreateObject(cx, &stunEndpoint, "ip", ipStr, "port", m_Port); return stunEndpoint; } Index: source/network/tests/test_Net.h =================================================================== --- source/network/tests/test_Net.h +++ source/network/tests/test_Net.h @@ -151,7 +151,8 @@ CNetServer server; JS::RootedValue attrs(cx); - scriptInterface.CreateObject( + ScriptInterface::CreateObject( + cx, &attrs, "mapType", "scenario", "map", "maps/scenarios/Saharan Oases", @@ -184,7 +185,8 @@ { JS::RootedValue cmd(cx); - client1.GetScriptInterface().CreateObject( + ScriptInterface::CreateObject( + cx, &cmd, "type", "debug-print", "message", "[>>> client1 test sim command]\\n"); @@ -193,7 +195,8 @@ { JS::RootedValue cmd(cx); - client1.GetScriptInterface().CreateObject( + ScriptInterface::CreateObject( + cx, &cmd, "type", "debug-print", "message", "[>>> client2 test sim command]\\n"); @@ -228,7 +231,8 @@ CNetServer server; JS::RootedValue attrs(cx); - scriptInterface.CreateObject( + ScriptInterface::CreateObject( + cx, &attrs, "mapType", "scenario", "map", "maps/scenarios/Saharan Oases", @@ -265,7 +269,8 @@ { JS::RootedValue cmd(cx); - client1.GetScriptInterface().CreateObject( + ScriptInterface::CreateObject( + cx, &cmd, "type", "debug-print", "message", "[>>> client1 test sim command 1]\\n"); @@ -281,7 +286,8 @@ { JS::RootedValue cmd(cx); - client1.GetScriptInterface().CreateObject( + ScriptInterface::CreateObject( + cx, &cmd, "type", "debug-print", "message", "[>>> client1 test sim command 2]\\n"); @@ -339,7 +345,8 @@ { JS::RootedValue cmd(cx); - client1.GetScriptInterface().CreateObject( + ScriptInterface::CreateObject( + cx, &cmd, "type", "debug-print", "message", "[>>> client1 test sim command 3]\\n"); @@ -355,7 +362,8 @@ { JS::RootedValue cmd(cx); - client1.GetScriptInterface().CreateObject( + ScriptInterface::CreateObject( + cx, &cmd, "type", "debug-print", "message", "[>>> client1 test sim command 4]\\n"); Index: source/network/tests/test_NetMessage.h =================================================================== --- source/network/tests/test_NetMessage.h +++ source/network/tests/test_NetMessage.h @@ -31,7 +31,7 @@ JSAutoRequest rq(cx); JS::RootedValue val(cx); - script.CreateArray(&val); + ScriptInterface::CreateArray(cx, &val); script.SetPropertyInt(val, 0, 4); CSimulationMessage msg(script, 1, 2, 3, val); Index: source/ps/GameSetup/GameSetup.cpp =================================================================== --- source/ps/GameSetup/GameSetup.cpp +++ source/ps/GameSetup/GameSetup.cpp @@ -520,18 +520,19 @@ JSAutoRequest rq(cx); JS::RootedValue playerAssignments(cx); - scriptInterface.CreateObject(&playerAssignments); + ScriptInterface::CreateObject(cx, &playerAssignments); if (!networked) { JS::RootedValue localPlayer(cx); - scriptInterface.CreateObject(&localPlayer, "player", g_Game->GetPlayerID()); + ScriptInterface::CreateObject(cx, &localPlayer, "player", g_Game->GetPlayerID()); scriptInterface.SetProperty(playerAssignments, "local", localPlayer); } JS::RootedValue sessionInitData(cx); - scriptInterface.CreateObject( + ScriptInterface::CreateObject( + cx, &sessionInitData, "attribs", attrs, "playerAssignments", playerAssignments); @@ -1103,8 +1104,7 @@ JS::RootedValue data(cx); if (g_GUI) { - scriptInterface->CreateObject(&data); - scriptInterface->SetProperty(data, "isStartup", true); + ScriptInterface::CreateObject(cx, &data, "isStartup", true); if (!installedMods.empty()) scriptInterface->SetProperty(data, "installedMods", installedMods); } @@ -1266,9 +1266,9 @@ JS::RootedValue settings(cx); JS::RootedValue playerData(cx); - scriptInterface.CreateObject(&attrs); - scriptInterface.CreateObject(&settings); - scriptInterface.CreateArray(&playerData); + ScriptInterface::CreateObject(cx, &attrs); + ScriptInterface::CreateObject(cx, &settings); + ScriptInterface::CreateArray(cx, &playerData); // The directory in front of the actual map name indicates which type // of map is being loaded. Drawback of this approach is the association @@ -1324,7 +1324,7 @@ // We could load player_defaults.json here, but that would complicate the logic // even more and autostart is only intended for developers anyway - scriptInterface.CreateObject(&player, "Civ", std::string("athen")); + ScriptInterface::CreateObject(cx, &player, "Civ", "athen"); scriptInterface.SetPropertyInt(playerData, i, player); } @@ -1354,7 +1354,7 @@ } scriptInterface.SetProperty(attrs, "mapType", mapType); - scriptInterface.SetProperty(attrs, "map", std::string("maps/" + autoStartName)); + scriptInterface.SetProperty(attrs, "map", "maps/" + autoStartName); scriptInterface.SetProperty(settings, "mapType", mapType); scriptInterface.SetProperty(settings, "CheatsEnabled", true); @@ -1408,7 +1408,7 @@ LOGWARNING("Autostart: Invalid player %d in autostart-team option", playerID); continue; } - scriptInterface.CreateObject(&player); + ScriptInterface::CreateObject(cx, &player); } int teamID = civArgs[i].AfterFirst(":").ToInt() - 1; @@ -1439,13 +1439,12 @@ LOGWARNING("Autostart: Invalid player %d in autostart-ai option", playerID); continue; } - scriptInterface.CreateObject(&player); + ScriptInterface::CreateObject(cx, &player); } - CStr name = aiArgs[i].AfterFirst(":"); - scriptInterface.SetProperty(player, "AI", std::string(name)); + scriptInterface.SetProperty(player, "AI", aiArgs[i].AfterFirst(":")); scriptInterface.SetProperty(player, "AIDiff", 3); - scriptInterface.SetProperty(player, "AIBehavior", std::string("balanced")); + scriptInterface.SetProperty(player, "AIBehavior", "balanced"); scriptInterface.SetPropertyInt(playerData, playerID-offset, player); } } @@ -1467,11 +1466,10 @@ LOGWARNING("Autostart: Invalid player %d in autostart-aidiff option", playerID); continue; } - scriptInterface.CreateObject(&player); + ScriptInterface::CreateObject(cx, &player); } - int difficulty = civArgs[i].AfterFirst(":").ToInt(); - scriptInterface.SetProperty(player, "AIDiff", difficulty); + scriptInterface.SetProperty(player, "AIDiff", civArgs[i].AfterFirst(":").ToInt()); scriptInterface.SetPropertyInt(playerData, playerID-offset, player); } } @@ -1495,11 +1493,10 @@ LOGWARNING("Autostart: Invalid player %d in autostart-civ option", playerID); continue; } - scriptInterface.CreateObject(&player); + ScriptInterface::CreateObject(cx, &player); } - CStr name = civArgs[i].AfterFirst(":"); - scriptInterface.SetProperty(player, "Civ", std::string(name)); + scriptInterface.SetProperty(player, "Civ", civArgs[i].AfterFirst(":")); scriptInterface.SetPropertyInt(playerData, playerID-offset, player); } } Index: source/ps/GameSetup/HWDetect.cpp =================================================================== --- source/ps/GameSetup/HWDetect.cpp +++ source/ps/GameSetup/HWDetect.cpp @@ -76,7 +76,7 @@ JSContext* cx = scriptInterface.GetContext(); JSAutoRequest rq(cx); - scriptInterface.CreateArray(ret); + ScriptInterface::CreateArray(cx, ret); for (size_t idxLevel = 0; idxLevel < x86_x64::Cache::maxLevels; ++idxLevel) { @@ -86,7 +86,8 @@ JS::RootedValue cache(cx); - scriptInterface.CreateObject( + ScriptInterface::CreateObject( + cx, &cache, "type", static_cast(pcache->m_Type), "level", static_cast(pcache->m_Level), @@ -104,7 +105,7 @@ JSContext* cx = scriptInterface.GetContext(); JSAutoRequest rq(cx); - scriptInterface.CreateArray(ret); + ScriptInterface::CreateArray(cx, ret); for(size_t i = 0; ; i++) { @@ -114,7 +115,8 @@ JS::RootedValue tlb(cx); - scriptInterface.CreateObject( + ScriptInterface::CreateObject( + cx, &tlb, "type", static_cast(ptlb->m_Type), "level", static_cast(ptlb->m_Level), @@ -247,7 +249,7 @@ // includes some fields that aren't directly useful for the hwdetect script) JS::RootedValue settings(cx); - scriptInterface.CreateObject(&settings); + ScriptInterface::CreateObject(cx, &settings); scriptInterface.SetProperty(settings, "os_unix", OS_UNIX); scriptInterface.SetProperty(settings, "os_bsd", OS_BSD); Index: source/ps/Mod.cpp =================================================================== --- source/ps/Mod.cpp +++ source/ps/Mod.cpp @@ -146,9 +146,10 @@ JS::RootedValue mods(cx, Mod::GetLoadedModsWithVersions(scriptInterface)); JS::RootedValue metainfo(cx); - scriptInterface.CreateObject( + ScriptInterface::CreateObject( + cx, &metainfo, - "engine_version", std::string(engine_version), + "engine_version", engine_version, "mods", mods); scriptInterface.FreezeObject(metainfo, true); Index: source/ps/ProfileViewer.cpp =================================================================== --- source/ps/ProfileViewer.cpp +++ source/ps/ProfileViewer.cpp @@ -505,7 +505,8 @@ JSAutoRequest rq(cx); JS::RootedValue t(cx); - m_ScriptInterface.CreateObject( + ScriptInterface::CreateObject( + cx, &t, "cols", DumpCols(table), "data", DumpRows(table)); @@ -531,14 +532,14 @@ JSAutoRequest rq(cx); JS::RootedValue data(cx); - m_ScriptInterface.CreateObject(&data); + ScriptInterface::CreateObject(cx, &data); const std::vector& columns = table->GetColumns(); for (size_t r = 0; r < table->GetNumberRows(); ++r) { JS::RootedValue row(cx); - m_ScriptInterface.CreateArray(&row); + ScriptInterface::CreateArray(cx, &row); m_ScriptInterface.SetProperty(data, table->GetCellText(r, 0).c_str(), row); Index: source/ps/Replay.cpp =================================================================== --- source/ps/Replay.cpp +++ source/ps/Replay.cpp @@ -68,7 +68,7 @@ m_ScriptInterface.SetProperty(attribs, "timestamp", (double)std::time(nullptr)); // Add engine version and currently loaded mods for sanity checks when replaying - m_ScriptInterface.SetProperty(attribs, "engine_version", CStr(engine_version)); + m_ScriptInterface.SetProperty(attribs, "engine_version", engine_version); JS::RootedValue mods(cx, Mod::GetLoadedModsWithVersions(m_ScriptInterface)); m_ScriptInterface.SetProperty(attribs, "mods", mods); Index: source/ps/SavedGame.cpp =================================================================== --- source/ps/SavedGame.cpp +++ source/ps/SavedGame.cpp @@ -83,9 +83,10 @@ JS::RootedValue metadata(cx); - simulation.GetScriptInterface().CreateObject( + ScriptInterface::CreateObject( + cx, &metadata, - "engine_version", std::string(engine_version), + "engine_version", engine_version, "time", static_cast(now), "playerID", g_Game->GetPlayerID(), "mods", mods, @@ -100,7 +101,8 @@ JS::RootedValue cameraMetadata(cx); - simulation.GetScriptInterface().CreateObject( + ScriptInterface::CreateObject( + cx, &cameraMetadata, "PosX", cameraPosition.X, "PosY", cameraPosition.Y, @@ -232,7 +234,7 @@ JSAutoRequest rq(cx); JS::RootedValue games(cx); - scriptInterface.CreateArray(&games); + ScriptInterface::CreateArray(cx, &games); Status err; @@ -268,7 +270,8 @@ JS::RootedValue metadata(cx, loader.GetMetadata()); JS::RootedValue game(cx); - scriptInterface.CreateObject( + ScriptInterface::CreateObject( + cx, &game, "id", pathnames[i].Basename(), "metadata", metadata); Index: source/ps/VisualReplay.cpp =================================================================== --- source/ps/VisualReplay.cpp +++ source/ps/VisualReplay.cpp @@ -190,7 +190,8 @@ CFileInfo fileInfo; GetFileInfo(replayFile, &fileInfo); - scriptInterface.CreateObject( + ScriptInterface::CreateObject( + cx, &replayData, "directory", directory.string(), "fileSize", static_cast(fileInfo.Size())); @@ -235,7 +236,7 @@ JS::RootedObject replays(cx, ReloadReplayCache(scriptInterface, compareFiles)); // Only take entries with data JS::RootedValue replaysWithoutNullEntries(cx); - scriptInterface.CreateArray(&replaysWithoutNullEntries); + ScriptInterface::CreateArray(cx, &replaysWithoutNullEntries); u32 replaysLength = 0; JS_GetArrayLength(cx, replays, &replaysLength); @@ -405,11 +406,12 @@ // Return the actual data JS::RootedValue replayData(cx); - scriptInterface.CreateObject( + ScriptInterface::CreateObject( + cx, &replayData, "directory", directory.string(), "fileSize", static_cast(fileSize), - "duration", static_cast(duration)); + "duration", duration); scriptInterface.SetProperty(replayData, "attribs", attribs); @@ -431,7 +433,7 @@ JSContext* cx = pCxPrivate->pScriptInterface->GetContext(); JSAutoRequest rq(cx); JS::RootedValue attribs(cx); - pCxPrivate->pScriptInterface->CreateObject(&attribs); + ScriptInterface::CreateObject(cx, &attribs); // Return empty object if file doesn't exist const OsPath replayFile = GetDirectoryPath() / directoryName / L"commands.txt"; Index: source/ps/scripting/JSInterface_ModIo.cpp =================================================================== --- source/ps/scripting/JSInterface_ModIo.cpp +++ source/ps/scripting/JSInterface_ModIo.cpp @@ -92,13 +92,13 @@ const std::vector& availableMods = g_ModIo->GetMods(); JS::RootedValue mods(cx); - scriptInterface->CreateArray(&mods, availableMods.size()); + ScriptInterface::CreateArray(cx, &mods, availableMods.size()); u32 i = 0; for (const ModIoModData& mod : availableMods) { JS::RootedValue m(cx); - scriptInterface->CreateObject(&m); + ScriptInterface::CreateObject(cx, &m); for (const std::pair& prop : mod.properties) scriptInterface->SetProperty(m, prop.first.c_str(), prop.second, true); @@ -139,7 +139,7 @@ const DownloadProgressData& progress = g_ModIo->GetDownloadProgress(); JS::RootedValue progressData(cx); - scriptInterface->CreateObject(&progressData); + ScriptInterface::CreateObject(cx, &progressData); scriptInterface->SetProperty(progressData, "status", statusStrings.at(progress.status), true); scriptInterface->SetProperty(progressData, "progress", progress.progress, true); scriptInterface->SetProperty(progressData, "error", progress.error, true); Index: source/ps/scripting/JSInterface_VFS.cpp =================================================================== --- source/ps/scripting/JSInterface_VFS.cpp +++ source/ps/scripting/JSInterface_VFS.cpp @@ -169,7 +169,7 @@ std::stringstream ss(contents); JS::RootedValue line_array(cx); - scriptInterface.CreateArray(&line_array); + ScriptInterface::CreateArray(cx, &line_array); std::string line; int cur_line = 0; Index: source/scriptinterface/ScriptConversions.cpp =================================================================== --- source/scriptinterface/ScriptConversions.cpp +++ source/scriptinterface/ScriptConversions.cpp @@ -298,6 +298,8 @@ ToJSVal(cx, ret, static_cast(val)); \ } +TOJSVAL_CHAR() + TOJSVAL_CHAR(5) TOJSVAL_CHAR(6) TOJSVAL_CHAR(7) @@ -314,9 +316,11 @@ TOJSVAL_CHAR(18) TOJSVAL_CHAR(19) TOJSVAL_CHAR(20) +TOJSVAL_CHAR(24) TOJSVAL_CHAR(29) TOJSVAL_CHAR(33) TOJSVAL_CHAR(35) +TOJSVAL_CHAR(256) #undef TOJSVAL_CHAR template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, const CStrW& val) Index: source/scriptinterface/ScriptInterface.h =================================================================== --- source/scriptinterface/ScriptInterface.h +++ source/scriptinterface/ScriptInterface.h @@ -132,16 +132,16 @@ /** * Sets the given value to a new plain JS::Object, converts the arguments to JS::Values and sets them as properties. + * This is static so that callers like ToJSVal can use it with the JSContext directly instead of having to obtain the instance using GetScriptInterfaceAndCBData. * Can throw an exception. */ template - bool CreateObject(JS::MutableHandleValue objectValue, Args const&... args) const + static bool CreateObject(JSContext* cx, JS::MutableHandleValue objectValue, Args const&... args) { - JSContext* cx = GetContext(); JSAutoRequest rq(cx); JS::RootedObject obj(cx); - if (!CreateObject_(&obj, args...)) + if (!CreateObject_(cx, &obj, args...)) return false; objectValue.setObject(*obj); @@ -151,7 +151,7 @@ /** * Sets the given value to a new JS object or Null Value in case of out-of-memory. */ - void CreateArray(JS::MutableHandleValue objectValue, size_t length = 0) const; + static void CreateArray(JSContext* cx, JS::MutableHandleValue objectValue, size_t length = 0); JS::Value GetGlobalObject() const; @@ -402,17 +402,16 @@ /** * Careful, the CreateObject_ helpers avoid creation of the JSAutoRequest! */ - bool CreateObject_(JS::MutableHandleObject obj) const; + static bool CreateObject_(JSContext* cx, JS::MutableHandleObject obj); template - bool CreateObject_(JS::MutableHandleObject obj, const char* propertyName, const T& propertyValue, Args const&... args) const + static bool CreateObject_(JSContext* cx, JS::MutableHandleObject obj, const char* propertyName, const T& propertyValue, Args const&... args) { // JSAutoRequest is the responsibility of the caller - JSContext* cx = GetContext(); JS::RootedValue val(cx); AssignOrToJSVal(cx, &val, propertyValue); - return CreateObject_(obj, args...) && JS_DefineProperty(cx, obj, propertyName, val, JSPROP_ENUMERATE); + return CreateObject_(cx, obj, args...) && JS_DefineProperty(cx, obj, propertyName, val, JSPROP_ENUMERATE); } bool CallFunction_(JS::HandleValue val, const char* name, JS::HandleValueArray argv, JS::MutableHandleValue ret) const; Index: source/scriptinterface/ScriptInterface.cpp =================================================================== --- source/scriptinterface/ScriptInterface.cpp +++ source/scriptinterface/ScriptInterface.cpp @@ -567,11 +567,11 @@ return ok; } -bool ScriptInterface::CreateObject_(JS::MutableHandleObject object) const +bool ScriptInterface::CreateObject_(JSContext* cx, JS::MutableHandleObject object) { // JSAutoRequest is the responsibility of the caller - object.set(JS_NewPlainObject(GetContext())); + object.set(JS_NewPlainObject(cx)); if (!object) throw PSERROR_Scripting_CreateObjectFailed(); @@ -579,9 +579,8 @@ return true; } -void ScriptInterface::CreateArray(JS::MutableHandleValue objectValue, size_t length) const +void ScriptInterface::CreateArray(JSContext* cx, JS::MutableHandleValue objectValue, size_t length) { - JSContext* cx = GetContext(); JSAutoRequest rq(cx); objectValue.setObjectOrNull(JS_NewArrayObject(cx, length)); Index: source/simulation2/Simulation2.cpp =================================================================== --- source/simulation2/Simulation2.cpp +++ source/simulation2/Simulation2.cpp @@ -983,7 +983,7 @@ // Build single JSON string with array of AI data JS::RootedValue ais(cx); - if (!scriptInterface.CreateObject(&ais, "AIData", aiData)) + if (!ScriptInterface::CreateObject(cx, &ais, "AIData", aiData)) return std::string(); return scriptInterface.StringifyJSON(&ais); Index: source/simulation2/components/CCmpAIManager.cpp =================================================================== --- source/simulation2/components/CCmpAIManager.cpp +++ source/simulation2/components/CCmpAIManager.cpp @@ -145,7 +145,8 @@ // Set up the data to pass as the constructor argument JS::RootedValue settings(cx); - m_ScriptInterface->CreateObject( + ScriptInterface::CreateObject( + cx, &settings, "player", m_Player, "difficulty", m_Difficulty, @@ -442,7 +443,7 @@ // Set up the data to pass as the constructor argument JS::RootedValue playersID(cx); - m_ScriptInterface->CreateObject(&playersID); + ScriptInterface::CreateObject(cx, &playersID); for (size_t i = 0; i < m_Players.size(); ++i) { @@ -454,7 +455,8 @@ ENSURE(m_HasLoadedEntityTemplates); JS::RootedValue settings(cx); - m_ScriptInterface->CreateObject( + ScriptInterface::CreateObject( + cx, &settings, "players", playersID, "templates", m_EntityTemplates); @@ -635,7 +637,7 @@ m_HasLoadedEntityTemplates = true; - m_ScriptInterface->CreateObject(&m_EntityTemplates); + ScriptInterface::CreateObject(cx, &m_EntityTemplates); JS::RootedValue val(cx); for (size_t i = 0; i < templates.size(); ++i) @@ -1188,7 +1190,7 @@ JSAutoRequest rq(cx); JS::RootedValue classesVal(cx); - scriptInterface.CreateObject(&classesVal); + ScriptInterface::CreateObject(cx, &classesVal); std::map classes; cmpPathfinder->GetPassabilityClasses(classes); Index: source/simulation2/components/ICmpAIManager.cpp =================================================================== --- source/simulation2/components/ICmpAIManager.cpp +++ source/simulation2/components/ICmpAIManager.cpp @@ -64,7 +64,7 @@ std::wstring dirname = GetWstringFromWpath(*it); JS::RootedValue ai(cx); - self->m_ScriptInterface.CreateObject(&ai); + ScriptInterface::CreateObject(cx, &ai); JS::RootedValue data(cx); self->m_ScriptInterface.ReadJSONFile(pathname, &data); Index: source/simulation2/scripting/EngineScriptConversions.cpp =================================================================== --- source/simulation2/scripting/EngineScriptConversions.cpp +++ source/simulation2/scripting/EngineScriptConversions.cpp @@ -114,29 +114,13 @@ template<> void ScriptInterface::ToJSVal(JSContext* cx, JS::MutableHandleValue ret, CColor const& val) { - JSAutoRequest rq(cx); - JS::RootedObject obj(cx, JS_NewPlainObject(cx)); - if (!obj) - { - ret.setUndefined(); - return; - } - - JS::RootedValue r(cx); - JS::RootedValue g(cx); - JS::RootedValue b(cx); - JS::RootedValue a(cx); - ToJSVal(cx, &r, val.r); - ToJSVal(cx, &g, val.g); - ToJSVal(cx, &b, val.b); - ToJSVal(cx, &a, val.a); - - JS_SetProperty(cx, obj, "r", r); - JS_SetProperty(cx, obj, "g", g); - JS_SetProperty(cx, obj, "b", b); - JS_SetProperty(cx, obj, "a", a); - - ret.setObject(*obj); + CreateObject( + cx, + ret, + "r", val.r, + "g", val.g, + "b", val.b, + "a", val.a); } template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, fixed& out) @@ -246,17 +230,12 @@ } JS::RootedValue data(cx, JS::ObjectValue(*objArr)); - JS::RootedValue w(cx); - JS::RootedValue h(cx); - ScriptInterface::ToJSVal(cx, &w, val.m_W); - ScriptInterface::ToJSVal(cx, &h, val.m_H); - - JS::RootedObject obj(cx, JS_NewPlainObject(cx)); - JS_SetProperty(cx, obj, "width", w); - JS_SetProperty(cx, obj, "height", h); - JS_SetProperty(cx, obj, "data", data); - - ret.setObject(*obj); + CreateObject( + cx, + ret, + "width", val.m_W, + "height", val.m_H, + "data", data); } template<> void ScriptInterface::ToJSVal >(JSContext* cx, JS::MutableHandleValue ret, const Grid& val) @@ -273,17 +252,13 @@ } JS::RootedValue data(cx, JS::ObjectValue(*objArr)); - JS::RootedValue w(cx); - JS::RootedValue h(cx); - ScriptInterface::ToJSVal(cx, &w, val.m_W); - ScriptInterface::ToJSVal(cx, &h, val.m_H); - - JS::RootedObject obj(cx, JS_NewPlainObject(cx)); - JS_SetProperty(cx, obj, "width", w); - JS_SetProperty(cx, obj, "height", h); - JS_SetProperty(cx, obj, "data", data); - ret.setObject(*obj); + CreateObject( + cx, + ret, + "width", val.m_W, + "height", val.m_H, + "data", data); } template<> bool ScriptInterface::FromJSVal(JSContext* cx, JS::HandleValue v, TNSpline& out) Index: source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp =================================================================== --- source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp +++ source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp @@ -96,13 +96,14 @@ JS::RootedValue settings(cx); scriptInterface.ParseJSON(*msg->settings, &settings); - scriptInterface.SetProperty(settings, "mapType", std::string("random")); + scriptInterface.SetProperty(settings, "mapType", "random"); JS::RootedValue attrs(cx); - scriptInterface.CreateObject( + ScriptInterface::CreateObject( + cx, &attrs, - "mapType", std::string("random"), - "script", std::wstring(*msg->filename), + "mapType", "random", + "script", *msg->filename, "settings", settings); StartGame(&attrs); @@ -124,26 +125,28 @@ // Set up 8-element array of empty objects to satisfy init JS::RootedValue playerData(cx); - scriptInterface.CreateArray(&playerData); + ScriptInterface::CreateArray(cx, &playerData); for (int i = 0; i < 8; ++i) { JS::RootedValue player(cx); - scriptInterface.CreateObject(&player); + ScriptInterface::CreateObject(cx, &player); scriptInterface.SetPropertyInt(playerData, i, player); } JS::RootedValue settings(cx); - scriptInterface.CreateObject( + ScriptInterface::CreateObject( + cx, &settings, - "mapType", std::string("scenario"), + "mapType", "scenario", "PlayerData", playerData); JS::RootedValue attrs(cx); - scriptInterface.CreateObject( + ScriptInterface::CreateObject( + cx, &attrs, - "mapType", std::string("scenario"), - "map", std::wstring(L"maps/scenarios/_default"), + "mapType", "scenario", + "map", "maps/scenarios/_default", "settings", settings); StartGame(&attrs); @@ -166,10 +169,11 @@ JS::RootedValue attrs(cx); - scriptInterface.CreateObject( + ScriptInterface::CreateObject( + cx, &attrs, - "mapType", std::string("scenario"), - "map", std::wstring(mapBase)); + "mapType", "scenario", + "map", mapBase); StartGame(&attrs); }