| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 |
- //========================================================================
- // BaseGameLogic.cpp : defines game logic class
- //
- // 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 "../EventManager/Events.h" // only for EvtData_Game_State
- #include "../ResourceCache/XmlResource.h"
- #include "../UserInterface/HumanView.h" // [rez] not ideal, but the loading sequence needs to know if this is a human view
- #include "BaseGameLogic.h"
- //========================================================================
- //
- // LevelManager implementation
- //
- //========================================================================
- bool LevelManager::Initialize(std::vector<std::string> &levels)
- {
- std::vector<std::string>::iterator i = levels.begin();
- while (i != levels.end())
- {
- m_Levels.push_back(*i);
- ++i;
- }
- return true;
- }
- //========================================================================
- //
- // BaseGameLogic implementation
- //
- //========================================================================
- BaseGameLogic::BaseGameLogic()
- {
- m_Lifetime = 0;
- m_State = BGS_Initializing;
- m_bProxy = false;
- m_ExpectedPlayers = 0;
- m_ExpectedRemotePlayers = 0;
- m_ExpectedAI = 0;
- m_HumanPlayersAttached = 0;
- m_AIPlayersAttached = 0;
- m_HumanGamesLoaded = 0;
- m_pLevelManager = GCC_NEW LevelManager;
- // GCC_ASSERT(m_pProcessManager && m_pLevelManager);
- // TODO(munnellg) - book passes levels directly, but my compiler doesn't like that. Find out why
- std::vector<std::string> levels = g_pApp->m_ResCache->Match("world/*.xml");
- m_pLevelManager->Initialize(levels);
- }
- BaseGameLogic::~BaseGameLogic()
- {
- // MrMike: 12-Apr-2009
- // Added this to explicitly remove views from the game logic list.
- while (!m_gameViews.empty())
- m_gameViews.pop_front();
- SAFE_DELETE(m_pLevelManager);
- // SAFE_DELETE(m_pProcessManager);
- SAFE_DELETE(m_pActorFactory);
- // destroy all actors
- for (auto it = m_actors.begin(); it != m_actors.end(); ++it)
- it->second->Destroy();
- m_actors.clear();
- // IEventManager::Get()->VRemoveListener(MakeDelegate(this, &BaseGameLogic::RequestDestroyActorDelegate), EvtData_Request_Destroy_Actor::sk_EventType);
- }
- bool BaseGameLogic::Init(void)
- {
- m_pActorFactory = VCreateActorFactory();
- // m_pPathingGraph.reset(CreatePathingGraph());
- // IEventManager::Get()->VAddListener(MakeDelegate(this, &BaseGameLogic::RequestDestroyActorDelegate), EvtData_Request_Destroy_Actor::sk_EventType);
- return true;
- }
- bool BaseGameLogic::VLoadGame(const char* levelResource)
- {
- // Grab the root XML node
- TiXmlElement* pRoot = XmlResourceLoader::LoadAndReturnRootXmlElement(levelResource);
- if (!pRoot)
- {
- GCC_ERROR("Failed to find level resource file: " + std::string(levelResource));
- return false;
- }
- // pre and post load scripts
- const char* preLoadScript = NULL;
- const char* postLoadScript = NULL;
- // parse the pre & post script attributes
- TiXmlElement* pScriptElement = pRoot->FirstChildElement("Script");
- if (pScriptElement)
- {
- preLoadScript = pScriptElement->Attribute("preLoad");
- postLoadScript = pScriptElement->Attribute("postLoad");
- }
- // load the pre-load script if there is one
- if (preLoadScript)
- {
- Resource resource(preLoadScript);
- std::shared_ptr<ResHandle> pResourceHandle = g_pApp->m_ResCache->GetHandle(&resource);
- }
- // load all initial actors
- TiXmlElement* pActorsNode = pRoot->FirstChildElement("StaticActors");
- if (pActorsNode)
- {
- for (TiXmlElement* pNode = pActorsNode->FirstChildElement(); pNode; pNode = pNode->NextSiblingElement())
- {
- const char* actorResource = pNode->Attribute("resource");
- StrongActorPtr pActor = VCreateActor(actorResource, pNode);
- if (pActor)
- {
- // fire an event letting everyone else know that we created a new actor
- std::shared_ptr<EvtData_New_Actor> pNewActorEvent(GCC_NEW EvtData_New_Actor(pActor->GetId()));
- IEventManager::Get()->VQueueEvent(pNewActorEvent);
- }
- }
- }
- // initialize all human views
- for (auto it = m_gameViews.begin(); it != m_gameViews.end(); ++it)
- {
- std::shared_ptr<IGameView> pView = *it;
- if (pView->VGetType() == GameView_Human)
- {
- std::shared_ptr<HumanView> pHumanView = static_pointer_cast<HumanView, IGameView>(pView);
- pHumanView->LoadGame(pRoot);
- }
- }
- // register script events from the engine
- // [mrmike] this was moved to the constructor post-press, since this function can be called when new levels are loaded by the game or editor
- // RegisterEngineScriptEvents();
- // call the delegate load function
- if (!VLoadGameDelegate(pRoot))
- return false; // no error message here because it's assumed VLoadGameDelegate() kicked out the error
- // load the post-load script if there is one
- if (postLoadScript)
- {
- Resource resource(postLoadScript);
- std::shared_ptr<ResHandle> pResourceHandle = g_pApp->m_ResCache->GetHandle(&resource); // this actually loads the XML file from the zip file
- }
- // trigger the Environment Loaded Game event - only then can player actors and AI be spawned!
- if (m_bProxy)
- {
- std::shared_ptr<EvtData_Remote_Environment_Loaded> pNewGameEvent(GCC_NEW EvtData_Remote_Environment_Loaded);
- IEventManager::Get()->VTriggerEvent(pNewGameEvent);
- }
- else
- {
- std::shared_ptr<EvtData_Environment_Loaded> pNewGameEvent(GCC_NEW EvtData_Environment_Loaded);
- IEventManager::Get()->VTriggerEvent(pNewGameEvent);
- }
- return true;
- }
- void BaseGameLogic::VSetProxy()
- {
- m_bProxy = true;
- // IEventManager::Get()->VAddListener(MakeDelegate(this, &BaseGameLogic::RequestNewActorDelegate), EvtData_Request_New_Actor::sk_EventType);
- // m_pPhysics.reset(CreateNullPhysics());
- }
- StrongActorPtr BaseGameLogic::VCreateActor(
- const std::string &actorResource,
- TiXmlElement* overrides,
- std::optional<const glm::mat4> initialTransform,
- const ActorId serversActorId
- ) {
-
- GCC_ASSERT(m_pActorFactory);
- if (!m_bProxy && serversActorId != INVALID_ACTOR_ID)
- return StrongActorPtr();
- if (m_bProxy && serversActorId == INVALID_ACTOR_ID)
- return StrongActorPtr();
- StrongActorPtr pActor = m_pActorFactory->CreateActor(actorResource.c_str(), overrides, initialTransform, serversActorId);
- if (pActor)
- {
- m_actors.insert(std::make_pair(pActor->GetId(), pActor));
- if (!m_bProxy && (m_State==BGS_SpawningPlayersActors || m_State==BGS_Running))
- {
- std::shared_ptr<EvtData_Request_New_Actor> pNewActor(GCC_NEW EvtData_Request_New_Actor(actorResource, initialTransform, pActor->GetId()));
- IEventManager::Get()->VTriggerEvent(pNewActor);
- }
- return pActor;
- }
- else
- {
- return StrongActorPtr();
- }
- }
- void BaseGameLogic::VDestroyActor(const ActorId actorId)
- {
- std::shared_ptr<EvtData_Destroy_Actor> pEvent(GCC_NEW EvtData_Destroy_Actor(actorId));
- IEventManager::Get()->VTriggerEvent(pEvent);
- auto findIt = m_actors.find(actorId);
- if (findIt != m_actors.end())
- {
- findIt->second->Destroy();
- m_actors.erase(findIt);
- }
- }
- WeakActorPtr BaseGameLogic::VGetActor(const ActorId actorId)
- {
- ActorMap::iterator findIt = m_actors.find(actorId);
- if (findIt != m_actors.end())
- return findIt->second;
- return WeakActorPtr();
- }
- void BaseGameLogic::VModifyActor(const ActorId actorId, TiXmlElement *override)
- {
- GCC_ASSERT(m_pActorFactory);
- if (!m_pActorFactory)
- return;
- auto findIt = m_actors.find(actorId);
- if (findIt != m_actors.end())
- {
- m_pActorFactory->ModifyActor(findIt->second, override);
- }
- }
- void BaseGameLogic::VOnUpdate(float time, float elapsedTime)
- {
- int deltaMilliseconds = int(elapsedTime * 1000.0f);
- m_Lifetime += elapsedTime;
- switch(m_State)
- {
- case BGS_Initializing:
- {
- // If we get to here we're ready to attach players
- VChangeState(BGS_MainMenu);
- break;
- }
- case BGS_MainMenu:
- {
- break;
- }
- case BGS_LoadingGameEnvironment:
- {
- /***
- // [mrmike] This was modified a little from what you see in the book - VLoadGame() is now called from
- // BaseGameLogic::VChangeState()
- //
- if (!g_pApp->VLoadGame())
- {
- GCC_ERROR("The game failed to load.");
- g_pApp->AbortGame();
- }
- ***/
- break;
- }
- case BGS_WaitingForPlayersToLoadEnvironment:
- {
- if (m_ExpectedPlayers + m_ExpectedRemotePlayers <= m_HumanGamesLoaded)
- {
- VChangeState(BGS_SpawningPlayersActors);
- }
- break;
- }
- case BGS_SpawningPlayersActors:
- {
- VChangeState(BGS_Running);
- break;
- }
- case BGS_WaitingForPlayers:
- {
- if (m_ExpectedPlayers + m_ExpectedRemotePlayers == m_HumanPlayersAttached)
- {
- // The server sends us the level name as a part of the login message.
- // We have to wait until it arrives before loading the level
- if (!g_pApp->m_Options.m_Level.empty())
- {
- VChangeState(BGS_LoadingGameEnvironment);
- }
- }
- break;
- }
- case BGS_Running:
- {
- // m_pProcessManager->UpdateProcesses(deltaMilliseconds);
- // if (m_pPhysics && !m_bProxy)
- // {
- // m_pPhysics->VOnUpdate(elapsedTime);
- // m_pPhysics->VSyncVisibleScene();
- // }
- break;
- }
- default:
- GCC_ERROR("Unrecognized state.");
- }
- // update all game views
- for (GameViewList::iterator it = m_gameViews.begin(); it != m_gameViews.end(); ++it)
- {
- (*it)->VOnUpdate(deltaMilliseconds);
- }
- // update game actors
- // for (ActorMap::const_iterator it = m_actors.begin(); it != m_actors.end(); ++it)
- // {
- // it->second->Update(deltaMilliseconds);
- // }
- }
- //
- // BaseGameLogic::VChangeState - Chapter 19, page 710
- //
- void BaseGameLogic::VChangeState(BaseGameState newState)
- {
- // TODO(munnellg) - implement
- if (newState==BGS_WaitingForPlayers)
- {
- // Get rid of the Main Menu
- m_gameViews.pop_front();
- // Note: Split screen support would require this to change!
- m_ExpectedPlayers = 1;
- m_ExpectedRemotePlayers = g_pApp->m_Options.m_expectedPlayers - 1;
- m_ExpectedAI = g_pApp->m_Options.m_numAIs;
- if (!g_pApp->m_Options.m_gameHost.empty())
- {
- VSetProxy();
- m_ExpectedAI = 0; // the server will create these
- m_ExpectedRemotePlayers = 0; // the server will create these
- // TODO(munnellg) - implement
- // if (!g_pApp->AttachAsClient())
- // {
- // // Throw up a main menu
- // VChangeState(BGS_MainMenu);
- // return
- // }
- }
- // else if (m_ExpectedRemotePlayers > 0)
- // {
- // TODO(munnellg) - implement for network games
- // }
- }
- else if (newState == BGS_LoadingGameEnvironment)
- {
- m_State = newState;
- if (!g_pApp->VLoadGame())
- {
- GCC_ERROR("The game failed to load.");
- g_pApp->AbortGame();
- }
- else
- {
- VChangeState(BGS_WaitingForPlayersToLoadEnvironment); // we must wait for all human player to report their environments are loaded.
- return;
- }
- }
- m_State = newState;
- }
- // Chapter 19/20 refactor work
- // - move physics pointer into BaseGameLogic
- // - but make the inherited logic choose the implementation
- void BaseGameLogic::VRenderDiagnostics()
- {
- if (m_RenderDiagnostics)
- {
- // TODO(munnellg) - uncomment this when we have physics
- // m_pPhysics->VRenderDiagnostics();
- }
- }
- void BaseGameLogic::VAddView(std::shared_ptr<IGameView> pView, ActorId actorId)
- {
- // This makes sure that all views have a non-zero view id.
- int viewId = static_cast<int>(m_gameViews.size());
- m_gameViews.push_back(pView);
- pView->VOnAttach(viewId, actorId);
- pView->VOnRestore();
- }
- void BaseGameLogic::VRemoveView(std::shared_ptr<IGameView> pView)
- {
- m_gameViews.remove(pView);
- }
- ActorFactory* BaseGameLogic::VCreateActorFactory(void)
- {
- return GCC_NEW ActorFactory;
- }
|