#include "Game.h" #include "Collision/FillOctreeSystem.h" #include "Collision/FillFrustumOctreeSystem.h" #include "Collision/EntityAABB.h" #include "Collision/TriggerSystem.h" #include "Collision/CollisionSystem.h" #include "Systems/RaptorCopterSystem.h" #include "Systems/HealthSystem.h" #include "Systems/PlayerMovementSystem.h" #include "Systems/SpawnerSystem.h" #include "Systems/PlayerSpawnSystem.h" #include "Systems/PlayerDeathSystem.h" #include "Systems/FloatingEffectSystem.h" #include "Core/EntityFile.h" #include "Core/EntityXMLFileWriter.h" #include "Game/Systems/CapturePointSystem.h" #include "Game/Systems/CapturePointHUDSystem.h" #include "Game/Systems/PickupSpawnSystem.h" #include "Game/Systems/AmmoPickupSystem.h" #include "Game/Systems/DamageIndicatorSystem.h" #include "Game/Systems/Weapon/AssaultWeaponBehaviour.h" #include "Game/Systems/Weapon/DefenderWeaponBehaviour.h" #include "Game/Systems/Weapon/SidearmWeaponBehaviour.h" #include "Rendering/AnimationSystem.h" #include "Game/Systems/HealthHUDSystem.h" #include "Rendering/BoneAttachmentSystem.h" #include "Game/Systems/LifetimeSystem.h" #include "../Engine/Core/UniformScaleSystem.h" #include "Rendering/AnimationSystem.h" #include "Network/MultiplayerSnapshotFilter.h" #include "Game/Systems/TextFieldReader.h" #include "Game/Systems/AbilityCooldownHUDSystem.h" #include "Game/Systems/CapturePointArrowHUDSystem.h" #include "Game/Systems/KillFeedSystem.h" #include "Game/Systems/BoostSystem.h" #include "Game/Systems/BoostIconsHUDSystem.h" #include "Game/Systems/ScoreScreenSystem.h" #include "Game/Systems/SpectatorCameraSystem.h" #include "GUI/ButtonSystem.h" #include "Game/Systems/MainMenuSystem.h" #include "Game/Systems/ServerListSystem.h" #include "Game/Systems/StartSystem.h" #include "Game/Systems/EndScreenSystem.h" #include "Game/Systems/FadeSystem.h" #include "Rendering/TextureSprite.h" Game::Game(int argc, char* argv[]) { parseArgs(argc, argv); ResourceManager::RegisterType("ConfigFile"); ResourceManager::RegisterType("Sound"); ResourceManager::RegisterType("Model"); ResourceManager::RegisterType("RawModel"); ResourceManager::RegisterType("Texture"); ResourceManager::RegisterType("PNG"); ResourceManager::RegisterType("TextureSprite"); ResourceManager::RegisterType("DDS"); ResourceManager::RegisterType("ShaderProgram"); ResourceManager::RegisterType("EntityFile"); ResourceManager::RegisterType("EntityXMLFile"); ResourceManager::RegisterType("FontFile"); m_Config = ResourceManager::Load("Config.ini"); ResourceManager::UseThreading = m_Config->Get("Multithreading.ResourceLoading", true); DisableMemoryPool::Value = m_Config->Get("Debug.DisableMemoryPool", false); LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get("Debug.LogLevel", 1)); // Create the core event broker m_EventBroker = new EventBroker(); // Create the renderer m_Renderer = new Renderer(m_EventBroker, m_Config); m_Renderer->SetFullscreen(m_Config->Get("Video.Fullscreen", false)); m_Renderer->SetVSYNC(m_Config->Get("Video.VSYNC", false)); m_Renderer->SetResolution(Rectangle::Rectangle( 0, 0, m_Config->Get("Video.Width", 1280), m_Config->Get("Video.Height", 720) )); m_Renderer->Initialize(); //m_Renderer->Camera()->SetFOV(glm::radians(m_Config->Get("Video.FOV", 90.f))); m_RenderFrame = new RenderFrame(); // Create input manager m_InputManager = new InputManager(m_Renderer->Window(), m_EventBroker); m_InputProxy = new InputProxy(m_EventBroker); m_InputProxy->AddHandler(); m_InputProxy->AddHandler(); m_InputProxy->LoadBindings("Input.ini"); // Create a world m_World = new World(m_EventBroker); std::string mapToLoad = m_Config->Get("Debug.LoadMap", ""); if (!mapToLoad.empty()) { auto file = ResourceManager::Load(mapToLoad); file->MergeInto(m_World); } // Create the sound manager m_SoundManager = new SoundManager(m_World, m_EventBroker); // Initialize network if (m_Config->Get("Networking.StartNetwork", false)) { if (m_IsServer) { m_NetworkServer = new Server(m_World, m_EventBroker, m_NetworkPort); m_Renderer->SetWindowTitle(m_Renderer->WindowTitle() + " SERVER"); } else if (m_IsClient) { m_NetworkClient = new Client(m_World, m_EventBroker, std::make_unique(m_EventBroker)); m_NetworkClient->Connect(m_NetworkAddress, m_NetworkPort); m_Renderer->SetWindowTitle(m_Renderer->WindowTitle() + " CLIENT"); } } else { // If network is disabled, pretend we're a server m_IsClient = true; m_IsServer = true; } // Create Octrees // TODO: Perhaps the world bounds should be set in some non-arbitrary way instead of this. AABB boxContainingTheWorld = AABB::FromOriginSize(glm::vec3(0.f, 10.7f, 0.f), glm::vec3(140.f, 31.f, 190.f)); m_OctreeCollision = new Octree(boxContainingTheWorld, 4); m_OctreeTrigger = new Octree(boxContainingTheWorld, 4); m_OctreeFrustrumCulling = new Octree(boxContainingTheWorld, 4); // Create system pipeline m_SystemPipeline = new SystemPipeline(m_World, m_EventBroker, m_IsClient, m_IsServer); // All systems with orderlevel 0 will be updated first. unsigned int updateOrderLevel = 0; m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_OctreeCollision); m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_OctreeCollision); m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_OctreeCollision); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer); m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); // Populate Octree with collidables ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision, "Collidable"); m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeTrigger, "Player"); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); // Collision and TriggerSystem should update after player. ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision); m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeTrigger); // Octree for frustum culling must be updated after collisions, otherwise players frustum may be moved after tree is filled, and wrong things are culled. ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeFrustrumCulling); ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_RenderFrame, m_OctreeFrustrumCulling); ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_RenderFrame); m_LastTime = glfwGetTime(); } Game::~Game() { delete m_SystemPipeline; delete m_OctreeFrustrumCulling; delete m_OctreeCollision; delete m_OctreeTrigger; delete m_SoundManager; if (m_NetworkClient != nullptr) { delete m_NetworkClient; } if (m_NetworkServer != nullptr) { delete m_NetworkServer; } delete m_World; delete m_InputProxy; delete m_InputManager; delete m_RenderFrame; delete m_Renderer; delete m_EventBroker; } void Game::Tick() { glfwPollEvents(); double currentTime = glfwGetTime(); double dt = currentTime - m_LastTime; m_LastTime = currentTime; // Handle input in a weird looking but responsive way m_EventBroker->Process(); m_EventBroker->Swap(); PerformanceTimer::StartTimer("InputManager"); m_InputManager->Update(dt); m_EventBroker->Swap(); PerformanceTimer::StartTimerAndStopPrevious("InputProxy"); m_InputProxy->Update(dt); m_EventBroker->Swap(); m_InputProxy->Process(ImGui::GetIO().WantCaptureKeyboard || ImGui::GetIO().WantCaptureMouse); m_EventBroker->Swap(); PerformanceTimer::StartTimerAndStopPrevious("SoundManager"); if (m_IsClient) { m_SoundManager->Update(dt); } // Update network PerformanceTimer::StartTimerAndStopPrevious("Network"); m_EventBroker->Process(); if (m_NetworkClient != nullptr) { m_NetworkClient->Update(dt); } if (m_NetworkServer != nullptr) { m_NetworkServer->Update(dt); } //m_SoundManager->Update(dt); // Iterate through systems and update world! PerformanceTimer::StartTimerAndStopPrevious("SystemPipeline"); m_EventBroker->Process(); m_SystemPipeline->Update(dt); PerformanceTimer::StartTimerAndStopPrevious("RendererUpdate"); m_Renderer->Update(dt); PerformanceTimer::StartTimerAndStopPrevious("RendererDraw"); m_Renderer->Draw(*m_RenderFrame); PerformanceTimer::StopTimer("RendererDraw"); m_RenderFrame->Clear(); m_EventBroker->Swap(); m_EventBroker->Clear(); //LOG_DEBUG("Recalculated positions: %i", TransformSystem::RecalculatedPositions); //LOG_DEBUG("Recalculated orientations: %i", TransformSystem::RecalculatedOrientations); //LOG_DEBUG("Recalculated scales: %i", TransformSystem::RecalculatedScales); TransformSystem::RecalculatedPositions = 0; TransformSystem::RecalculatedOrientations = 0; TransformSystem::RecalculatedScales = 0; } int Game::parseArgs(int argc, char* argv[]) { namespace po = boost::program_options; po::options_description desc("Options"); desc.add_options() ("help", "Help") ("server,s", po::bool_switch(&m_IsServer), "Launch game in server mode") ("connect", po::value(&m_NetworkAddress)->default_value(""), "Connect to this address in client mode") ("port,p", po::value(&m_NetworkPort), "Port to listen on or connect to"); ; po::variables_map vm; try { po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); } catch (std::exception& e) { LOG_ERROR(e.what()); return 1; } if (vm.count("help")) { std::cout << desc << std::endl; exit(1); } // HACK: Right now, client and server are mutually exclusive m_IsClient = true; if (m_IsServer) { m_IsClient = false; } return 0; }