Ejemplo n.º 1
0
CScriptValRooted ScriptInterface::ParseJSON(const std::string& string_utf8)
{
	std::wstring attrsW = wstring_from_utf8(string_utf8);
	utf16string string(attrsW.begin(), attrsW.end());

	jsval vp;
	JSONParser* parser = JS_BeginJSONParse(m->m_cx, &vp);
	if (!parser)
	{
		LOGERROR(L"ParseJSON failed to begin");
		return CScriptValRooted();
	}

	if (!JS_ConsumeJSONText(m->m_cx, parser, reinterpret_cast<const jschar*>(string.c_str()), (uint32)string.size()))
	{
		LOGERROR(L"ParseJSON failed to consume");
		return CScriptValRooted();
	}

	if (!JS_FinishJSONParse(m->m_cx, parser, JSVAL_NULL))
	{
		LOGERROR(L"ParseJSON failed to finish");
		return CScriptValRooted();
	}

	return CScriptValRooted(m->m_cx, vp);
}
Ejemplo n.º 2
0
void CComponentManager::RegisterComponentType(InterfaceId iid, ComponentTypeId cid, AllocFunc alloc, DeallocFunc dealloc,
		const char* name, const std::string& schema)
{
	ComponentType c = { CT_Native, iid, alloc, dealloc, name, schema, CScriptValRooted() };
	m_ComponentTypesById.insert(std::make_pair(cid, c));
	m_ComponentTypeIdsByName[name] = cid;
}
Ejemplo n.º 3
0
jsval CMessage::ToJSValCached(ScriptInterface& scriptInterface) const
{
	if (m_Cached.uninitialised())
		m_Cached = CScriptValRooted(scriptInterface.GetContext(), ToJSVal(scriptInterface));

	return m_Cached.get();
}
Ejemplo n.º 4
0
		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;
		}
Ejemplo n.º 5
0
void CGUIManager::PushPage(const CStrW& pageName, CScriptVal initData)
{
	m_PageStack.push_back(SGUIPage());
	m_PageStack.back().name = pageName;
	m_PageStack.back().initData = CScriptValRooted(m_ScriptInterface.GetContext(), initData);
	LoadPage(m_PageStack.back());
}
Ejemplo n.º 6
0
	static std::vector<SimulationCommand> CloneCommandsFromOtherContext(ScriptInterface& oldScript, ScriptInterface& newScript,
		const std::vector<SimulationCommand>& commands)
	{
		std::vector<SimulationCommand> newCommands = commands;
		for (size_t i = 0; i < newCommands.size(); ++i)
		{
			newCommands[i].data = CScriptValRooted(newScript.GetContext(),
				newScript.CloneValueFromOtherContext(oldScript, newCommands[i].data.get()));
		}
		return newCommands;
	}
Ejemplo n.º 7
0
CScriptValRooted ScriptInterface::ReadJSONFile(const VfsPath& path)
{
	if (!VfsFileExists(path))
	{
		LOGERROR(L"File '%ls' does not exist", path.string().c_str());
		return CScriptValRooted();
	}

	CVFSFile file;

	PSRETURN ret = file.Load(g_VFS, path);

	if (ret != PSRETURN_OK)
	{
		LOGERROR(L"Failed to load file '%ls': %hs", path.string().c_str(), GetErrorString(ret));
		return CScriptValRooted();
	}

	std::string content(file.DecodeUTF8()); // assume it's UTF-8

	return ParseJSON(content);
}
Ejemplo n.º 8
0
CMessage* CComponentManager::ConstructMessage(int mtid, CScriptVal data)
{
	if (mtid == MT__Invalid || mtid > (int)m_MessageTypeIdsByName.size()) // (IDs start at 1 so use '>' here)
		LOGERROR(L"PostMessage with invalid message type ID '%d'", mtid);

	if (mtid < MT__LastNative)
	{
		return CMessageFromJSVal(mtid, m_ScriptInterface, data.get());
	}
	else
	{
		return new CMessageScripted(mtid, m_MessageTypeNamesById[mtid],
				CScriptValRooted(m_ScriptInterface.GetContext(), data));
	}
}
Ejemplo n.º 9
0
/**
 * Send GUI message queue when queried.
 */
CScriptValRooted XmppClient::GuiPollMessage(ScriptInterface& scriptInterface)
{
	if (m_GuiMessageQueue.empty())
		return CScriptValRooted();

	GUIMessage message = m_GuiMessageQueue.front();
	CScriptValRooted messageVal;

	scriptInterface.Eval("({})", messageVal);
	scriptInterface.SetProperty(messageVal.get(), "type", message.type);
	if (!message.from.empty())
		scriptInterface.SetProperty(messageVal.get(), "from", message.from);
	if (!message.text.empty())
		scriptInterface.SetProperty(messageVal.get(), "text", message.text);
	if (!message.level.empty())
		scriptInterface.SetProperty(messageVal.get(), "level", message.level);
	if (!message.message.empty())
		scriptInterface.SetProperty(messageVal.get(), "message", message.message);
	if (!message.data.empty())
		scriptInterface.SetProperty(messageVal.get(), "data", message.data);
	
	m_GuiMessageQueue.pop_front();
	return messageVal;
}
Ejemplo n.º 10
0
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());
		}
	}
}
Ejemplo n.º 11
0
template<> bool ScriptInterface::FromJSVal<CScriptValRooted>(JSContext* cx, jsval v, CScriptValRooted& out)
{
	out = CScriptValRooted(cx, v);
	return true;
}
Ejemplo n.º 12
0
		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;
		}
Ejemplo n.º 13
0
		~CAIPlayer()
		{
			// Clean up rooted objects before destroying their script context
			m_Obj = CScriptValRooted();
			m_Commands.clear();
		}
Ejemplo n.º 14
0
void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationCommand>& commands)
{
	PROFILE3("sim update");
	PROFILE2_ATTR("turn %d", (int)m_TurnNumber);

	fixed turnLengthFixed = fixed::FromInt(turnLength) / 1000;

	/*
	 * In serialization test mode, we save the original (primary) simulation state before each turn update.
	 * We run the update, then load the saved state into a secondary context.
	 * We serialize that again and compare to the original serialization (to check that
	 * serialize->deserialize->serialize is equivalent to serialize).
	 * Then we run the update on the secondary context, and check that its new serialized
	 * state matches the primary context after the update (to check that the simulation doesn't depend
	 * on anything that's not serialized).
	 */

	const bool serializationTestDebugDump = false; // set true to save human-readable state dumps before an error is detected, for debugging (but slow)
	const bool serializationTestHash = true; // set true to save and compare hash of state

	SerializationTestState primaryStateBefore;
	if (m_EnableSerializationTest)
	{
		ENSURE(m_ComponentManager.SerializeState(primaryStateBefore.state));
		if (serializationTestDebugDump)
			ENSURE(m_ComponentManager.DumpDebugState(primaryStateBefore.debug, false));
		if (serializationTestHash)
			ENSURE(m_ComponentManager.ComputeStateHash(primaryStateBefore.hash, false));
	}


	UpdateComponents(m_SimContext, turnLengthFixed, commands);


	if (m_EnableSerializationTest)
	{
		// Initialise the secondary simulation
		CTerrain secondaryTerrain;
		CSimContext secondaryContext;
		secondaryContext.m_Terrain = &secondaryTerrain;
		CComponentManager secondaryComponentManager(secondaryContext, m_ComponentManager.GetScriptInterface().GetRuntime());
		secondaryComponentManager.LoadComponentTypes();
		ENSURE(LoadDefaultScripts(secondaryComponentManager, NULL));
		ResetComponentState(secondaryComponentManager, false, false);

		// Load the map into the secondary simulation

		LDR_BeginRegistering();
		CMapReader* mapReader = new CMapReader; // automatically deletes itself

		// TODO: this duplicates CWorld::RegisterInit and could probably be cleaned up a bit
		std::string mapType;
		m_ComponentManager.GetScriptInterface().GetProperty(m_InitAttributes.get(), "mapType", mapType);
		if (mapType == "random")
		{
			// TODO: support random map scripts
			debug_warn(L"Serialization test mode only supports scenarios");
		}
		else
		{
			std::wstring mapFile;
			m_ComponentManager.GetScriptInterface().GetProperty(m_InitAttributes.get(), "map", mapFile);

			VfsPath mapfilename = VfsPath(mapFile).ChangeExtension(L".pmp");
			mapReader->LoadMap(mapfilename, CScriptValRooted(), &secondaryTerrain, NULL, NULL, NULL, NULL, NULL, NULL,
				NULL, NULL, &secondaryContext, INVALID_PLAYER, true); // throws exception on failure
		}
		LDR_EndRegistering();
		ENSURE(LDR_NonprogressiveLoad() == INFO::OK);

		ENSURE(secondaryComponentManager.DeserializeState(primaryStateBefore.state));

		SerializationTestState secondaryStateBefore;
		ENSURE(secondaryComponentManager.SerializeState(secondaryStateBefore.state));
		if (serializationTestDebugDump)
			ENSURE(secondaryComponentManager.DumpDebugState(secondaryStateBefore.debug, false));
		if (serializationTestHash)
			ENSURE(secondaryComponentManager.ComputeStateHash(secondaryStateBefore.hash, false));

		if (primaryStateBefore.state.str() != secondaryStateBefore.state.str() ||
			primaryStateBefore.hash != secondaryStateBefore.hash)
		{
			ReportSerializationFailure(&primaryStateBefore, NULL, &secondaryStateBefore, NULL);
		}

		SerializationTestState primaryStateAfter;
		ENSURE(m_ComponentManager.SerializeState(primaryStateAfter.state));
		if (serializationTestHash)
			ENSURE(m_ComponentManager.ComputeStateHash(primaryStateAfter.hash, false));

		UpdateComponents(secondaryContext, turnLengthFixed,
			CloneCommandsFromOtherContext(m_ComponentManager.GetScriptInterface(), secondaryComponentManager.GetScriptInterface(), commands));

		SerializationTestState secondaryStateAfter;
		ENSURE(secondaryComponentManager.SerializeState(secondaryStateAfter.state));
		if (serializationTestHash)
			ENSURE(secondaryComponentManager.ComputeStateHash(secondaryStateAfter.hash, false));

		if (primaryStateAfter.state.str() != secondaryStateAfter.state.str() ||
			primaryStateAfter.hash != secondaryStateAfter.hash)
		{
			// Only do the (slow) dumping now we know we're going to need to report it
			ENSURE(m_ComponentManager.DumpDebugState(primaryStateAfter.debug, false));
			ENSURE(secondaryComponentManager.DumpDebugState(secondaryStateAfter.debug, false));

			ReportSerializationFailure(&primaryStateBefore, &primaryStateAfter, &secondaryStateBefore, &secondaryStateAfter);
		}
	}

//	if (m_TurnNumber == 0)
//		m_ComponentManager.GetScriptInterface().DumpHeap();

	// Run the GC occasionally
	// (TODO: we ought to schedule this for a frame where we're not
	// running the sim update, to spread the load)
	if (m_TurnNumber % 1 == 0)
		m_ComponentManager.GetScriptInterface().MaybeIncrementalRuntimeGC();

	if (m_EnableOOSLog)
		DumpState();

	// Start computing AI for the next turn
	CmpPtr<ICmpAIManager> cmpAIManager(m_SimContext, SYSTEM_ENTITY);
	if (cmpAIManager)
		cmpAIManager->StartComputation();

	++m_TurnNumber;
}
Ejemplo n.º 15
0
void CStdDeserializer::ScriptVal(const char* UNUSED(name), CScriptValRooted& out)
{
	out = CScriptValRooted(m_ScriptInterface.GetContext(), ReadScriptVal(NULL));
}