bool Initialise(bool callConstructor) { if (!LoadScripts(m_AIName)) return false; OsPath path = L"simulation/ai/" + m_AIName + L"/data.json"; CScriptValRooted metadata = m_Worker.LoadMetadata(path); if (metadata.uninitialised()) { LOGERROR(L"Failed to create AI player: can't find %ls", path.string().c_str()); return false; } // Get the constructor name from the metadata std::string constructor; if (!m_ScriptInterface.GetProperty(metadata.get(), "constructor", constructor)) { LOGERROR(L"Failed to create AI player: %ls: missing 'constructor'", path.string().c_str()); return false; } // Get the constructor function from the loaded scripts CScriptVal ctor; if (!m_ScriptInterface.GetProperty(m_ScriptInterface.GetGlobalObject(), constructor.c_str(), ctor) || ctor.undefined()) { LOGERROR(L"Failed to create AI player: %ls: can't find constructor '%hs'", path.string().c_str(), constructor.c_str()); return false; } CScriptVal obj; if (callConstructor) { // Set up the data to pass as the constructor argument CScriptVal settings; m_ScriptInterface.Eval(L"({})", settings); m_ScriptInterface.SetProperty(settings.get(), "player", m_Player, false); ENSURE(m_Worker.m_HasLoadedEntityTemplates); m_ScriptInterface.SetProperty(settings.get(), "templates", m_Worker.m_EntityTemplates, false); obj = m_ScriptInterface.CallConstructor(ctor.get(), settings.get()); } else { // For deserialization, we want to create the object with the correct prototype // but don't want to actually run the constructor again // XXX: actually we don't currently use this path for deserialization - maybe delete it? obj = m_ScriptInterface.NewObjectFromConstructor(ctor.get()); } if (obj.undefined()) { LOGERROR(L"Failed to create AI player: %ls: error calling constructor '%hs'", path.string().c_str(), constructor.c_str()); return false; } m_Obj = CScriptValRooted(m_ScriptInterface.GetContext(), obj); return true; }
/** * Send a request to register a game to the server. * * @param data A JS array of game attributes */ void XmppClient::SendIqRegisterGame(ScriptInterface& scriptInterface, CScriptVal data) { glooxwrapper::JID xpartamuppJid(m_xpartamuppId); jsval dataval = data.get(); // Setup some base stanza attributes GameListQuery* g = new GameListQuery(); g->m_Command = "register"; glooxwrapper::Tag* game = glooxwrapper::Tag::allocate("game"); // Add a fake ip which will be overwritten by the ip stamp XMPP module on the server. game->addAttribute("ip", "fake"); // Iterate through all the properties reported and add them to the stanza. std::vector<std::string> properties; scriptInterface.EnumeratePropertyNamesWithPrefix(dataval, "", properties); for (std::vector<int>::size_type i = 0; i != properties.size(); i++) { std::wstring value; scriptInterface.GetProperty(dataval, properties[i].c_str(), value); game->addAttribute(properties[i], utf8_from_wstring(value)); } // Push the stanza onto the IQ g->m_GameList.push_back(game); // Send IQ glooxwrapper::IQ iq(gloox::IQ::Set, xpartamuppJid); iq.addExtension(g); DbgXMPP("SendIqRegisterGame [" << tag_xml(iq) << "]"); m_client->send(iq); }
/** * Send game report containing numerous game properties to the server. * * @param data A JS array of game statistics */ void XmppClient::SendIqGameReport(ScriptInterface& scriptInterface, CScriptVal data) { glooxwrapper::JID xpartamuppJid(m_xpartamuppId); jsval dataval = data.get(); // Setup some base stanza attributes GameReport* game = new GameReport(); glooxwrapper::Tag* report = glooxwrapper::Tag::allocate("game"); // Iterate through all the properties reported and add them to the stanza. std::vector<std::string> properties; scriptInterface.EnumeratePropertyNamesWithPrefix(dataval, "", properties); for (std::vector<int>::size_type i = 0; i != properties.size(); i++) { std::wstring value; scriptInterface.GetProperty(dataval, properties[i].c_str(), value); report->addAttribute(properties[i], utf8_from_wstring(value)); } // Add stanza to IQ game->m_GameReport.push_back(report); // Send IQ glooxwrapper::IQ iq(gloox::IQ::Set, xpartamuppJid); iq.addExtension(game); DbgXMPP("SendGameReport [" << tag_xml(iq) << "]"); m_client->send(iq); };
CScriptVal ConvertTLBs(ScriptInterface& scriptInterface) { CScriptVal ret; scriptInterface.Eval("[]", ret); for(size_t i = 0; ; i++) { const x86_x64::Cache* ptlb = x86_x64::Caches(x86_x64::TLB+i); if (!ptlb) break; CScriptVal tlb; scriptInterface.Eval("({})", tlb); scriptInterface.SetProperty(tlb.get(), "type", (u32)ptlb->type); scriptInterface.SetProperty(tlb.get(), "level", (u32)ptlb->level); scriptInterface.SetProperty(tlb.get(), "associativity", (u32)ptlb->associativity); scriptInterface.SetProperty(tlb.get(), "pagesize", (u32)ptlb->entrySize); scriptInterface.SetProperty(tlb.get(), "entries", (u32)ptlb->numEntries); scriptInterface.SetPropertyInt(ret.get(), i, tlb); } return ret; }
CScriptVal ConvertCaches(ScriptInterface& scriptInterface, x86_x64::IdxCache idxCache) { CScriptVal ret; scriptInterface.Eval("[]", ret); for (size_t idxLevel = 0; idxLevel < x86_x64::Cache::maxLevels; ++idxLevel) { const x86_x64::Cache* pcache = x86_x64::Caches(idxCache+idxLevel); if (pcache->type == x86_x64::Cache::kNull || pcache->numEntries == 0) continue; CScriptVal cache; scriptInterface.Eval("({})", cache); scriptInterface.SetProperty(cache.get(), "type", (u32)pcache->type); scriptInterface.SetProperty(cache.get(), "level", (u32)pcache->level); scriptInterface.SetProperty(cache.get(), "associativity", (u32)pcache->associativity); scriptInterface.SetProperty(cache.get(), "linesize", (u32)pcache->entrySize); scriptInterface.SetProperty(cache.get(), "sharedby", (u32)pcache->sharedBy); scriptInterface.SetProperty(cache.get(), "totalsize", (u32)pcache->TotalSize()); scriptInterface.SetPropertyInt(ret.get(), idxLevel, cache); } return ret; }
void CConsole::ProcessBuffer(const wchar_t* szLine) { if (szLine == NULL) return; if (wcslen(szLine) <= 0) return; ENSURE(wcslen(szLine) < CONSOLE_BUFFER_SIZE); m_deqBufHistory.push_front(szLine); SaveHistory(); // Do this each line for the moment; if a script causes // a crash it's a useful record. // Process it as JavaScript CScriptVal rval; g_GUI->GetActiveGUI()->GetScriptInterface()->Eval(szLine, rval); if (!rval.undefined()) InsertMessage(L"%ls", g_GUI->GetActiveGUI()->GetScriptInterface()->ToString(rval.get()).c_str()); }
void CComponentManager::Script_RegisterComponentType(void* cbdata, int iid, std::string cname, CScriptVal ctor) { CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata); // Find the C++ component that wraps the interface int cidWrapper = componentManager->GetScriptWrapper(iid); if (cidWrapper == CID__Invalid) { componentManager->m_ScriptInterface.ReportError("Invalid interface id"); return; } const ComponentType& ctWrapper = componentManager->m_ComponentTypesById[cidWrapper]; bool mustReloadComponents = false; // for hotloading ComponentTypeId cid = componentManager->LookupCID(cname); if (cid == CID__Invalid) { // Allocate a new cid number cid = componentManager->m_NextScriptComponentTypeId++; componentManager->m_ComponentTypeIdsByName[cname] = cid; } else { // Component type is already loaded, so do hotloading: if (!componentManager->m_CurrentlyHotloading) { componentManager->m_ScriptInterface.ReportError("Registering component type with already-registered name"); // TODO: report the actual name return; } const ComponentType& ctPrevious = componentManager->m_ComponentTypesById[cid]; // We can only replace scripted component types, not native ones if (ctPrevious.type != CT_Script) { componentManager->m_ScriptInterface.ReportError("Hotloading script component type with same name as native component"); return; } // We don't support changing the IID of a component type (it would require fiddling // around with m_ComponentsByInterface and being careful to guarantee uniqueness per entity) if (ctPrevious.iid != iid) { // ...though it only matters if any components exist with this type if (!componentManager->m_ComponentsByTypeId[cid].empty()) { componentManager->m_ScriptInterface.ReportError("Hotloading script component type mustn't change interface ID"); return; } } // Remove the old component type's message subscriptions std::map<MessageTypeId, std::vector<ComponentTypeId> >::iterator it; for (it = componentManager->m_LocalMessageSubscriptions.begin(); it != componentManager->m_LocalMessageSubscriptions.end(); ++it) { std::vector<ComponentTypeId>& types = it->second; std::vector<ComponentTypeId>::iterator ctit = find(types.begin(), types.end(), cid); if (ctit != types.end()) types.erase(ctit); } for (it = componentManager->m_GlobalMessageSubscriptions.begin(); it != componentManager->m_GlobalMessageSubscriptions.end(); ++it) { std::vector<ComponentTypeId>& types = it->second; std::vector<ComponentTypeId>::iterator ctit = find(types.begin(), types.end(), cid); if (ctit != types.end()) types.erase(ctit); } mustReloadComponents = true; } std::string schema = "<empty/>"; { CScriptValRooted prototype; if (componentManager->m_ScriptInterface.GetProperty(ctor.get(), "prototype", prototype) && componentManager->m_ScriptInterface.HasProperty(prototype.get(), "Schema")) { componentManager->m_ScriptInterface.GetProperty(prototype.get(), "Schema", schema); } } // Construct a new ComponentType, using the wrapper's alloc functions ComponentType ct = { CT_Script, iid, ctWrapper.alloc, ctWrapper.dealloc, cname, schema, CScriptValRooted(componentManager->m_ScriptInterface.GetContext(), ctor) }; componentManager->m_ComponentTypesById[cid] = ct; componentManager->m_CurrentComponent = cid; // needed by Subscribe // Find all the ctor prototype's On* methods, and subscribe to the appropriate messages: CScriptVal proto; if (!componentManager->m_ScriptInterface.GetProperty(ctor.get(), "prototype", proto)) return; // error std::vector<std::string> methods; if (!componentManager->m_ScriptInterface.EnumeratePropertyNamesWithPrefix(proto.get(), "On", methods)) return; // error for (std::vector<std::string>::const_iterator it = methods.begin(); it != methods.end(); ++it) { std::string name = (*it).substr(2); // strip the "On" prefix // Handle "OnGlobalFoo" functions specially bool isGlobal = false; if (name.substr(0, 6) == "Global") { isGlobal = true; name = name.substr(6); } std::map<std::string, MessageTypeId>::const_iterator mit = componentManager->m_MessageTypeIdsByName.find(name); if (mit == componentManager->m_MessageTypeIdsByName.end()) { std::string msg = "Registered component has unrecognised '" + *it + "' message handler method"; componentManager->m_ScriptInterface.ReportError(msg.c_str()); return; } if (isGlobal) componentManager->SubscribeGloballyToMessageType(mit->second); else componentManager->SubscribeToMessageType(mit->second); } componentManager->m_CurrentComponent = CID__Invalid; if (mustReloadComponents) { // For every script component with this cid, we need to switch its // prototype from the old constructor's prototype property to the new one's const std::map<entity_id_t, IComponent*>& comps = componentManager->m_ComponentsByTypeId[cid]; std::map<entity_id_t, IComponent*>::const_iterator eit = comps.begin(); for (; eit != comps.end(); ++eit) { jsval instance = eit->second->GetJSInstance(); if (!JSVAL_IS_NULL(instance)) componentManager->m_ScriptInterface.SetPrototype(instance, proto.get()); } } }
// NOTE: we can't define a jsval specialisation, because that conflicts with integer types template<> jsval ScriptInterface::ToJSVal<CScriptVal>(JSContext* UNUSED(cx), const CScriptVal& val) { return val.get(); }
bool Initialise(bool callConstructor) { // LoadScripts will only load each script once even though we call it for each player if (!m_Worker.LoadScripts(m_AIName)) return false; OsPath path = L"simulation/ai/" + m_AIName + L"/data.json"; CScriptValRooted metadata = m_Worker.LoadMetadata(path); if (metadata.uninitialised()) { LOGERROR(L"Failed to create AI player: can't find %ls", path.string().c_str()); return false; } // Get the constructor name from the metadata // If the AI doesn't use modules, we look for the constructor in the global object // TODO: All AIs should use modules. Remove the condition if this requirement is met. std::string moduleName; std::string constructor; CScriptVal objectWithConstructor; // object that should contain the constructor function CScriptVal ctor; if (!m_ScriptInterface->HasProperty(metadata.get(), "moduleName")) { objectWithConstructor = m_ScriptInterface->GetGlobalObject(); } else { m_ScriptInterface->GetProperty(metadata.get(), "moduleName", moduleName); if(!m_ScriptInterface->GetProperty(m_ScriptInterface->GetGlobalObject(), moduleName.c_str(), objectWithConstructor) || objectWithConstructor.undefined()) { LOGERROR(L"Failed to create AI player: %ls: can't find the module that should contain the constructor: '%hs'", path.string().c_str(), moduleName.c_str()); return false; } } if (!m_ScriptInterface->GetProperty(metadata.get(), "constructor", constructor)) { LOGERROR(L"Failed to create AI player: %ls: missing 'constructor'", path.string().c_str()); return false; } // Get the constructor function from the loaded scripts if (!m_ScriptInterface->GetProperty(objectWithConstructor.get(), constructor.c_str(), ctor) || ctor.undefined()) { LOGERROR(L"Failed to create AI player: %ls: can't find constructor '%hs'", path.string().c_str(), constructor.c_str()); return false; } m_ScriptInterface->GetProperty(metadata.get(), "useShared", m_UseSharedComponent); CScriptVal obj; if (callConstructor) { // Set up the data to pass as the constructor argument CScriptVal settings; m_ScriptInterface->Eval(L"({})", settings); m_ScriptInterface->SetProperty(settings.get(), "player", m_Player, false); m_ScriptInterface->SetProperty(settings.get(), "difficulty", m_Difficulty, false); ENSURE(m_Worker.m_HasLoadedEntityTemplates); m_ScriptInterface->SetProperty(settings.get(), "templates", m_Worker.m_EntityTemplates, false); obj = m_ScriptInterface->CallConstructor(ctor.get(), settings.get()); } else { // For deserialization, we want to create the object with the correct prototype // but don't want to actually run the constructor again // XXX: actually we don't currently use this path for deserialization - maybe delete it? obj = m_ScriptInterface->NewObjectFromConstructor(ctor.get()); } if (obj.undefined()) { LOGERROR(L"Failed to create AI player: %ls: error calling constructor '%hs'", path.string().c_str(), constructor.c_str()); return false; } m_Obj = CScriptValRooted(m_ScriptInterface->GetContext(), obj); return true; }
bool Autostart(const CmdLineArgs& args) { /* * Handle various command-line options, for quick testing of various features: * -autostart=name -- map name for scenario, or rms name for random map * -autostart-ai=1:dummybot -- adds the dummybot AI to player 1 * -autostart-playername=name -- multiplayer player name * -autostart-host -- multiplayer host mode * -autostart-players=2 -- number of players * -autostart-client -- multiplayer client mode * -autostart-ip=127.0.0.1 -- multiplayer connect to 127.0.0.1 * -autostart-random=104 -- random map, optional seed value = 104 (default is 0, random is -1) * -autostart-size=192 -- random map size in tiles = 192 (default is 192) * * Examples: * -autostart=Acropolis -autostart-host -autostart-players=2 -- Host game on Acropolis map, 2 players * -autostart=latium -autostart-random=-1 -- Start single player game on latium random map, random rng seed */ CStr autoStartName = args.Get("autostart"); #if OS_ANDROID // HACK: currently the most convenient way to test maps on Android; // should find a better solution autoStartName = "Oasis"; #endif if (autoStartName.empty()) { return false; } g_Game = new CGame(); ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); CScriptValRooted attrs; scriptInterface.Eval("({})", attrs); CScriptVal settings; scriptInterface.Eval("({})", settings); CScriptVal playerData; scriptInterface.Eval("([])", playerData); // Set different attributes for random or scenario game if (args.Has("autostart-random")) { CStr seedArg = args.Get("autostart-random"); // Default seed is 0 uint32 seed = 0; if (!seedArg.empty()) { if (seedArg.compare("-1") == 0) { // Random seed value seed = rand(); } else { seed = seedArg.ToULong(); } } // Random map definition will be loaded from JSON file, so we need to parse it std::wstring mapPath = L"maps/random/"; std::wstring scriptPath = mapPath + autoStartName.FromUTF8() + L".json"; CScriptValRooted scriptData = scriptInterface.ReadJSONFile(scriptPath); if (!scriptData.undefined() && scriptInterface.GetProperty(scriptData.get(), "settings", settings)) { // JSON loaded ok - copy script name over to game attributes std::wstring scriptFile; scriptInterface.GetProperty(settings.get(), "Script", scriptFile); scriptInterface.SetProperty(attrs.get(), "script", scriptFile); // RMS filename } else { // Problem with JSON file LOGERROR(L"Error reading random map script '%ls'", scriptPath.c_str()); throw PSERROR_Game_World_MapLoadFailed("Error reading random map script.\nCheck application log for details."); } // Get optional map size argument (default 192) uint mapSize = 192; if (args.Has("autostart-size")) { CStr size = args.Get("autostart-size"); mapSize = size.ToUInt(); } scriptInterface.SetProperty(attrs.get(), "map", std::string(autoStartName)); scriptInterface.SetProperty(attrs.get(), "mapPath", mapPath); scriptInterface.SetProperty(attrs.get(), "mapType", std::string("random")); scriptInterface.SetProperty(settings.get(), "Seed", seed); // Random seed scriptInterface.SetProperty(settings.get(), "Size", mapSize); // Random map size (in patches) // Get optional number of players (default 2) size_t numPlayers = 2; if (args.Has("autostart-players")) { CStr num = args.Get("autostart-players"); numPlayers = num.ToUInt(); } // Set up player data for (size_t i = 0; i < numPlayers; ++i) { CScriptVal player; scriptInterface.Eval("({})", player); // We could load player_defaults.json here, but that would complicate the logic // even more and autostart is only intended for developers anyway scriptInterface.SetProperty(player.get(), "Civ", std::string("athen")); scriptInterface.SetPropertyInt(playerData.get(), i, player); } } else { scriptInterface.SetProperty(attrs.get(), "map", std::string(autoStartName)); scriptInterface.SetProperty(attrs.get(), "mapType", std::string("scenario")); } // Set player data for AIs // attrs.settings = { PlayerData: [ { AI: ... }, ... ] }: if (args.Has("autostart-ai")) { std::vector<CStr> aiArgs = args.GetMultiple("autostart-ai"); for (size_t i = 0; i < aiArgs.size(); ++i) { // Instead of overwriting existing player data, modify the array CScriptVal player; if (!scriptInterface.GetPropertyInt(playerData.get(), i, player) || player.undefined()) { scriptInterface.Eval("({})", player); } int playerID = aiArgs[i].BeforeFirst(":").ToInt(); CStr name = aiArgs[i].AfterFirst(":"); scriptInterface.SetProperty(player.get(), "AI", std::string(name)); scriptInterface.SetPropertyInt(playerData.get(), playerID-1, player); } } // Add player data to map settings scriptInterface.SetProperty(settings.get(), "PlayerData", playerData); // Add map settings to game attributes scriptInterface.SetProperty(attrs.get(), "settings", settings); CScriptVal mpInitData; g_GUI->GetScriptInterface().Eval("({isNetworked:true, playerAssignments:{}})", mpInitData); g_GUI->GetScriptInterface().SetProperty(mpInitData.get(), "attribs", CScriptVal(g_GUI->GetScriptInterface().CloneValueFromOtherContext(scriptInterface, attrs.get()))); // Get optional playername CStrW userName = L"anonymous"; if (args.Has("autostart-playername")) { userName = args.Get("autostart-playername").FromUTF8(); } if (args.Has("autostart-host")) { InitPs(true, L"page_loading.xml", mpInitData.get()); size_t maxPlayers = 2; if (args.Has("autostart-players")) { maxPlayers = args.Get("autostart-players").ToUInt(); } g_NetServer = new CNetServer(maxPlayers); g_NetServer->UpdateGameAttributes(attrs.get(), scriptInterface); bool ok = g_NetServer->SetupConnection(); ENSURE(ok); g_NetClient = new CNetClient(g_Game); g_NetClient->SetUserName(userName); g_NetClient->SetupConnection("127.0.0.1"); } else if (args.Has("autostart-client")) { InitPs(true, L"page_loading.xml", mpInitData.get()); g_NetClient = new CNetClient(g_Game); g_NetClient->SetUserName(userName); CStr ip = "127.0.0.1"; if (args.Has("autostart-ip")) { ip = args.Get("autostart-ip"); } bool ok = g_NetClient->SetupConnection(ip); ENSURE(ok); } else { g_Game->SetPlayerID(1); g_Game->StartGame(attrs, ""); LDR_NonprogressiveLoad(); PSRETURN ret = g_Game->ReallyStartGame(); ENSURE(ret == PSRETURN_OK); InitPs(true, L"page_session.xml", JSVAL_VOID); } return true; }