Major networking refactoring to allow for snapshot filtering outside of netcode

This commit is contained in:
2016-02-09 13:22:21 +01:00
parent 2b4e00e4b0
commit d3bc48f5f7
28 changed files with 382 additions and 198 deletions
+7 -3
View File
@@ -1,6 +1,6 @@
project(TacticalZ-Game)
find_package(Boost REQUIRED COMPONENTS system filesystem thread chrono)
find_package(Boost REQUIRED COMPONENTS system filesystem thread chrono program_options)
set(INCLUDE_PATH ${CMAKE_SOURCE_DIR}/include/Game)
include_directories(
@@ -22,13 +22,17 @@ file(GLOB SOURCE_FILES_Events
)
source_group(Events FILES ${SOURCE_FILES_Events})
file(GLOB SOURCE_FILES_Network
"${INCLUDE_PATH}/Network/*.h"
"Network/*.cpp"
)
source_group(Network FILES ${SOURCE_FILES_Network})
set(SOURCE_FILES
${SOURCE_FILES}
"Game.cpp"
${SOURCE_FILES_Systems}
${SOURCE_FILES_Events}
${SOURCE_FILES_Network}
)
set(LIBRARIES
+56 -14
View File
@@ -13,10 +13,13 @@
#include "Game/Systems/WeaponSystem.h"
#include "Game/Systems/PlayerHUDSystem.h"
#include "Game/Systems/LifetimeSystem.h"
#include "../Engine/Rendering/AnimationSystem.h"
#include "Rendering/AnimationSystem.h"
#include "Network/MultiplayerSnapshotFilter.h"
Game::Game(int argc, char* argv[])
{
parseArgs(argc, argv);
ResourceManager::RegisterType<ConfigFile>("ConfigFile");
ResourceManager::RegisterType<Sound>("Sound");
ResourceManager::RegisterType<Model>("Model");
@@ -73,15 +76,14 @@ Game::Game(int argc, char* argv[])
// Initialize network
if (m_Config->Get<bool>("Networking.StartNetwork", false)) {
bool isServer = m_Config->Get<bool>("Networking.IsServer", false);
if (isServer) {
m_Network = new Server();
m_IsServer = true;
} else {
m_Network = new Client(m_Config);
m_IsClient = true;
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<MultiplayerSnapshotFilter>(m_EventBroker));
m_NetworkClient->Connect(m_NetworkAddress, m_NetworkPort);
m_Renderer->SetWindowTitle(m_Renderer->WindowTitle() + " CLIENT");
}
m_Network->Start(m_World, m_EventBroker);
}
// Create Octrees
@@ -132,8 +134,11 @@ Game::~Game()
delete m_OctreeFrustrumCulling;
delete m_OctreeCollision;
delete m_OctreeTrigger;
if (m_Network != nullptr) {
delete m_Network;
if (m_NetworkClient != nullptr) {
delete m_NetworkClient;
}
if (m_NetworkServer != nullptr) {
delete m_NetworkServer;
}
delete m_World;
delete m_FrameStack;
@@ -163,8 +168,12 @@ void Game::Tick()
m_EventBroker->Swap();
// Update network
if (m_Network != nullptr) {
m_Network->Update();
m_EventBroker->Process<MultiplayerSnapshotFilter>();
if (m_NetworkClient != nullptr) {
m_NetworkClient->Update();
}
if (m_NetworkServer != nullptr) {
m_NetworkServer->Update();
}
// Iterate through systems and update world!
@@ -176,4 +185,37 @@ void Game::Tick()
m_RenderFrame->Clear();
m_EventBroker->Swap();
m_EventBroker->Clear();
}
}
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<std::string>(&m_NetworkAddress)->default_value(""), "Connect to this address in client mode")
("port,p", po::value<int>(&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);
}
if (vm.count("connect")) {
m_IsClient = true;
}
return 0;
}
@@ -0,0 +1,27 @@
#include "Network/MultiplayerSnapshotFilter.h"
MultiplayerSnapshotFilter::MultiplayerSnapshotFilter(EventBroker* eventBroker)
: m_EventBroker(eventBroker)
{
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &MultiplayerSnapshotFilter::OnPlayerSpawned);
}
bool MultiplayerSnapshotFilter::FilterComponent(EntityWrapper entity, SharedComponentWrapper& component)
{
if (entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer)) {
return false;
}
if (component.Info.Name == "Transform") {
m_EventBroker->Publish(Events::Interpolate(entity, component));
return false;
}
return true;
}
bool MultiplayerSnapshotFilter::OnPlayerSpawned(Events::PlayerSpawned ePlayerSpawned)
{
m_LocalPlayer = ePlayerSpawned.Player;
return true;
}
@@ -0,0 +1,14 @@
#include "Systems/ExplosionEffectSystem.h"
void ExplosionEffectSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt)
{
if ((double)component["TimeSinceDeath"] > (double)component["ExplosionDuration"]) {
(double)component["TimeSinceDeath"] = 0.f;
}
(double&)component["TimeSinceDeath"] += dt;
//if ((bool)Component["Gravity"] == true) {
// (bool)Component["ExponentialAccelaration"] = false;
//}
}
+20 -28
View File
@@ -17,6 +17,7 @@ void InterpolationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrappe
return;
}
//return;
if (m_NextTransform.find(transform.EntityID) != m_NextTransform.end()) { // Exists in map
m_NextTransform[transform.EntityID].interpolationTime += static_cast<float>(dt);
Transform sTransform = m_NextTransform[transform.EntityID];
@@ -32,21 +33,14 @@ void InterpolationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrappe
}
}
if (transform.Info.Name == "Transform") {
bool isLocalPlayer = entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer);
// Position
glm::vec3 nextPosition = sTransform.Position;
glm::vec3 currentPosition = static_cast<glm::vec3>(transform["Position"]);
// HACK: Don't force position for players
if (!isLocalPlayer) {
(glm::vec3&)transform["Position"] += vectorInterpolation<glm::vec3>(currentPosition, nextPosition, sTransform.interpolationTime);
}
(glm::vec3&)transform["Position"] += vectorInterpolation<glm::vec3>(currentPosition, nextPosition, sTransform.interpolationTime);
// Orientation
// Don't force orientation for players
if (!isLocalPlayer) {
glm::quat nextOrientation = sTransform.Orientation;
glm::quat currentOrientation = glm::quat(static_cast<glm::vec3>(transform["Orientation"]));
(glm::vec3&)transform["Orientation"] = glm::eulerAngles(glm::slerp<float>(currentOrientation, nextOrientation, sTransform.interpolationTime / m_SnapshotInterval));
}
glm::quat nextOrientation = sTransform.Orientation;
glm::quat currentOrientation = glm::quat(static_cast<glm::vec3>(transform["Orientation"]));
(glm::vec3&)transform["Orientation"] = glm::eulerAngles(glm::slerp<float>(currentOrientation, nextOrientation, glm::max(sTransform.interpolationTime / m_SnapshotInterval, 1.f)));
// Scale
glm::vec3 nextScale = sTransform.Scale;
glm::vec3 currentScale = static_cast<glm::vec3>(transform["Scale"]);
@@ -61,24 +55,22 @@ bool InterpolationSystem::OnPlayerSpawned(Events::PlayerSpawned& e)
return true;
}
bool InterpolationSystem::OnInterpolate(const Events::Interpolate & e)
bool InterpolationSystem::OnInterpolate(Events::Interpolate& e)
{
Transform transform;
int offset = 0;
// Read the data
memcpy(&transform.Position, e.DataArray.get() + offset, sizeof(glm::vec3));
offset += sizeof(glm::vec3);
glm::vec3 tempOrientation;
memcpy(&tempOrientation, e.DataArray.get() + offset, sizeof(glm::vec3));
transform.Orientation = glm::quat(tempOrientation);
offset += sizeof(glm::vec3);
memcpy(&transform.Scale, e.DataArray.get() + offset, sizeof(glm::vec3));
transform.interpolationTime = 0.0f;
// TODO: Make this work for arbitrary component types
if (e.Component.Info.Name == "Transform") {
Transform transform;
transform.Position = e.Component["Position"];
transform.Orientation = glm::quat((glm::vec3)e.Component["Orientation"]);
transform.Scale = e.Component["Scale"];
transform.interpolationTime = 0.0f;
if (m_NextTransform.find(e.Entity) != m_NextTransform.end()) { // Did exist
m_LastReceivedTransform[e.Entity] = transform;
} else { // Did not
m_NextTransform[e.Entity] = transform;
if (m_NextTransform.find(e.Entity.ID) != m_NextTransform.end()) { // Did exist
m_LastReceivedTransform[e.Entity.ID] = transform;
} else { // Did not
m_NextTransform[e.Entity.ID] = transform;
}
}
return false;
return true;
}