//======================================================================== // BaseScriptComponent.cpp - Component for exposing actors to Lua // // Part of the GameCode4 Application // // GameCode4 is the sample application that encapsulates much of the source code // discussed in "Game Coding Complete - 4th Edition" by Mike McShaffry and David // "Rez" Graham, published by Charles River Media. // ISBN-10: 1133776574 | ISBN-13: 978-1133776574 // // If this source code has found it's way to you, and you think it has helped you // in any way, do the authors a favor and buy a new copy of the book - there are // detailed explanations in it that compliment this code well. Buy a copy at Amazon.com // by clicking here: // http://www.amazon.com/gp/product/1133776574/ref=olp_product_details?ie=UTF8&me=&seller= // // There's a companion web site at http://www.mcshaffry.com/GameCode/ // // The source code is managed and maintained through Google Code: // http://code.google.com/p/gamecode4/ // // (c) Copyright 2012 Michael L. McShaffry and David Graham // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser GPL v3 // as published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See // http://www.gnu.org/licenses/lgpl-3.0.txt for more details. // // You should have received a copy of the GNU Lesser GPL v3 // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // //======================================================================== #include "../Unix/GameCodeStd.h" #include "BaseScriptComponent.h" #include "../LUAScripting/LuaStateManager.h" // This is the name of the metatable where all the function definitions exported to Lua will live. static const char* METATABLE_NAME = "BaseScriptComponentMetaTable"; const char* BaseScriptComponent::g_Name = "BaseScriptComponent"; BaseScriptComponent::BaseScriptComponent(void) { m_scriptObject = sol::object(); m_scriptDestructor = sol::nil; } BaseScriptComponent::~BaseScriptComponent(void) { // call the script destructor if there is one if (m_scriptDestructor.valid()) { m_scriptDestructor(m_scriptObject); } // clear out the script object m_scriptObject = sol::object(); // if we were given a path for this script object, set it to nil if (!m_scriptObjectName.empty()) { m_scriptObjectName += " = nil;"; LuaStateManager::Get()->VExecuteString(m_scriptObjectName.c_str()); } } bool BaseScriptComponent::VInit(TiXmlElement* pData) { LuaStateManager* pStateMgr = LuaStateManager::Get(); GCC_ASSERT(pStateMgr); sol::state_view lua = pStateMgr->GetLuaState(); sol::global_table global_table = pStateMgr->GetGlobalVars(); // load the tag and validate it TiXmlElement* pScriptObjectElement = pData->FirstChildElement("ScriptObject"); if (!pScriptObjectElement) { GCC_ERROR("No tag in XML. This won't be a very useful script component."); return true; // technically it succeeded even though it won't be accessible } // read all the attribute const char* temp = NULL; temp = pScriptObjectElement->Attribute("var"); if (temp) m_scriptObjectName = temp; temp = pScriptObjectElement->Attribute("constructor"); if (temp) m_constructorName = temp; temp = pScriptObjectElement->Attribute("destructor"); if (temp) m_destructorName = temp; // Having a var attribute will export the instance of this object to that name. if (!m_scriptObjectName.empty()) { m_scriptObject = pStateMgr->CreatePath(m_scriptObjectName.c_str()); if (m_scriptObject != sol::nil) { CreateScriptObject(); } } // The scriptConstructor attribute will also cause a Lua object to be created if one wasn't created in // the previous step. The scriptConstructor string is treated as a function of the form f(scriptObject) // and is called. if (!m_constructorName.empty()) { m_scriptConstructor = global_table[m_constructorName.c_str()]; if (m_scriptConstructor.valid()) { // m_scriptObject could be nil if there was no scriptObject attribute. If this is the case, // the Lua object is created here. if (m_scriptObject == sol::nil) { m_scriptObject = lua.create_table(); CreateScriptObject(); } } } // The scriptDestructor attribute is treated as a function in the form of f(scriptObject) and is called // when the C++ ScriptObject instance is destroyed. if (!m_destructorName.empty()) { m_scriptDestructor = global_table[m_destructorName]; } return true; } void BaseScriptComponent::VPostInit(void) { // call the script constructor if one exists if (m_scriptConstructor.valid()) { sol::protected_function_result result = m_scriptConstructor(m_scriptObject); if (!result.valid()) { sol::error err = result; GCC_ERROR(std::string("Script constructor failed: ") + err.what()); } } } TiXmlElement* BaseScriptComponent::VGenerateXml(void) { TiXmlElement* pBaseElement = GCC_NEW TiXmlElement(VGetName()); // ScriptObject TiXmlElement* pScriptObjectElement = GCC_NEW TiXmlElement("ScriptObject"); if (!m_scriptObjectName.empty()) pScriptObjectElement->SetAttribute("var", m_scriptObjectName.c_str()); if (!m_constructorName.empty()) pScriptObjectElement->SetAttribute("constructor", m_constructorName.c_str()); if (!m_destructorName.empty()) pScriptObjectElement->SetAttribute("destructor", m_destructorName.c_str()); pBaseElement->LinkEndChild(pScriptObjectElement); return pBaseElement; } void BaseScriptComponent::CreateScriptObject(void) { sol::state_view lua = LuaStateManager::Get()->GetLuaState(); m_scriptObject = sol::make_object(lua, this); } void BaseScriptComponent::RegisterScriptFunctions(void) { // create the metatable sol::state_view lua = LuaStateManager::Get()->GetLuaState(); lua.new_usertype(METATABLE_NAME, "GetActorId", &BaseScriptComponent::GetActorId//, // "GetPos", &BaseScriptComponent::GetActorId, // "SetPos", &BaseScriptComponent::GetActorId, // "GetLookAt", &BaseScriptComponent::GetActorId, // "GetYOrientationRadians", &BaseScriptComponent::GetActorId, // "RotateY", &BaseScriptComponent::GetActorId, // "Stop", &BaseScriptComponent::GetActorId, // "SetPosition", &BaseScriptComponent::GetActorId, ); } ActorId BaseScriptComponent::GetActorId(void) { return m_pOwner->GetId(); }