Merge remote-tracking branch 'origin/master' into Importer
# Conflicts: # resources/Schema/Entities/MovementTest.xml # resources/Schema/Entities/Player.xml
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
#ifndef EPlayerSpawned_h__
|
||||
#define EPlayerSpawned_h__
|
||||
|
||||
#include "Core/Event.h"
|
||||
#include "Core/EntityWrapper.h"
|
||||
|
||||
namespace Events
|
||||
{
|
||||
|
||||
struct PlayerSpawned : Event
|
||||
{
|
||||
int PlayerID;
|
||||
EntityWrapper Player;
|
||||
EntityWrapper Spawner;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -25,6 +25,8 @@ struct EntityWrapper
|
||||
|
||||
bool HasComponent(const std::string& componentName);
|
||||
EntityWrapper Parent();
|
||||
EntityWrapper FirstChildByName(const std::string& name);
|
||||
bool IsChildOf(EntityWrapper potentialParent);
|
||||
bool Valid();
|
||||
|
||||
ComponentWrapper operator[](const char* componentName);
|
||||
|
||||
@@ -111,7 +111,7 @@ struct Child
|
||||
std::vector<ContainedObject>& m_StaticObjectsRef;
|
||||
std::vector<ContainedObject>& m_DynamicObjectsRef;
|
||||
|
||||
inline bool hasChildren() const;
|
||||
bool hasChildren() const;
|
||||
int childIndexContainingPoint(const glm::vec3& point) const;
|
||||
std::vector<int> childIndicesContainingBox(const AABB& box) const;
|
||||
};
|
||||
|
||||
@@ -3,13 +3,18 @@
|
||||
|
||||
#include "../GLM.h"
|
||||
#include "World.h"
|
||||
#include "EntityWrapper.h"
|
||||
|
||||
namespace Transform
|
||||
{
|
||||
|
||||
glm::vec3 AbsolutePosition(EntityWrapper entity);
|
||||
glm::vec3 AbsolutePosition(World* world, EntityID entity);
|
||||
glm::quat AbsoluteOrientation(EntityWrapper entity);
|
||||
glm::quat AbsoluteOrientation(World* world, EntityID entity);
|
||||
glm::vec3 AbsoluteScale(EntityWrapper entity);
|
||||
glm::vec3 AbsoluteScale(World* world, EntityID entity);
|
||||
glm::mat4 ModelMatrix(EntityWrapper entity);
|
||||
glm::mat4 ModelMatrix(EntityID entity, World* world);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
#ifndef EditorCameraInputController_h__
|
||||
#define EditorCameraInputController_h__
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
#include "../Input/FirstPersonInputController.h"
|
||||
#include "../Core/EMousePress.h"
|
||||
#include "../Core/EMouseRelease.h"
|
||||
#include "../Core/EMouseScroll.h"
|
||||
#include "../Core/ConfigFile.h"
|
||||
|
||||
template <typename EventContext>
|
||||
class EditorCameraInputController : public FirstPersonInputController<EventContext>
|
||||
{
|
||||
public:
|
||||
EditorCameraInputController(EventBroker* eventBroker, unsigned int playerID)
|
||||
: FirstPersonInputController(eventBroker, playerID)
|
||||
{
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &EditorCameraInputController::OnMousePress);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EMouseRelease, &EditorCameraInputController::OnMouseRelease);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EMouseScroll, &EditorCameraInputController::OnMouseScroll);
|
||||
|
||||
m_Config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||
m_SpeedMultiplier = m_Config->Get<float>("Editor.CameraSpeed", 3.f);
|
||||
}
|
||||
|
||||
virtual const glm::vec3 Movement() const override { return m_Movement * m_SpeedMultiplier; }
|
||||
|
||||
void Enable() { m_Enabled = true; }
|
||||
void Disable() { m_Enabled = false; }
|
||||
|
||||
virtual bool OnCommand(const Events::InputCommand& e) override
|
||||
{
|
||||
if (glm::abs(e.Value) > 0 && !m_MouseLocked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (glm::abs(e.Value) > 0 && (io.WantCaptureKeyboard || io.WantCaptureMouse)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.Command == "Jump") {
|
||||
if (e.Value > 0) {
|
||||
m_Movement.y = glm::max(e.Value, 1.f);
|
||||
} else {
|
||||
m_Movement.y = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
if (e.Command == "Crouch") {
|
||||
if (e.Value > 0) {
|
||||
m_Movement.y = glm::min(-e.Value, -1.f);
|
||||
} else {
|
||||
m_Movement.y = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
if (e.Command == "Sprint") {
|
||||
if (e.Value > 0) {
|
||||
m_SpeedMultiplier *= 2.f;
|
||||
} else {
|
||||
m_SpeedMultiplier /= 2.f;
|
||||
}
|
||||
}
|
||||
|
||||
return FirstPersonInputController::OnCommand(e);
|
||||
}
|
||||
|
||||
protected:
|
||||
ConfigFile* m_Config;
|
||||
bool m_Enabled = false;
|
||||
float m_SpeedMultiplier = 1.f;
|
||||
|
||||
EventRelay<EventContext, Events::MousePress> m_EMousePress;
|
||||
bool OnMousePress(const Events::MousePress& e)
|
||||
{
|
||||
if (!m_Enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.Button == GLFW_MOUSE_BUTTON_2) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (!io.WantCaptureMouse) {
|
||||
LockMouse();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
EventRelay<EventContext, Events::MouseRelease> m_EMouseRelease;
|
||||
bool OnMouseRelease(const Events::MouseRelease& e)
|
||||
{
|
||||
if (!m_Enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.Button == GLFW_MOUSE_BUTTON_2) {
|
||||
UnlockMouse();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
EventRelay<EventContext, Events::MouseScroll> m_EMouseScroll;
|
||||
bool OnMouseScroll(const Events::MouseScroll& e)
|
||||
{
|
||||
if (!m_Enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_SpeedMultiplier += e.DeltaY * (0.1f * m_SpeedMultiplier);
|
||||
m_Config->Set("Editor.CameraSpeed", m_SpeedMultiplier);
|
||||
m_Config->SaveToDisk();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "../Core/System.h"
|
||||
#include "../Rendering/IRenderer.h"
|
||||
#include "../Rendering/Camera.h"
|
||||
#include "../Rendering/DebugCameraInputController.h"
|
||||
#include "../Rendering/ESetCamera.h"
|
||||
#include "../Core/World.h"
|
||||
#include "../Core/SystemPipeline.h"
|
||||
@@ -10,8 +9,10 @@
|
||||
#include "../Core/EntityFileParser.h"
|
||||
#include "../Core/EntityFileWriter.h"
|
||||
#include "../Core/EMousePress.h"
|
||||
#include "../Input/EInputCommand.h"
|
||||
#include "EditorGUI.h"
|
||||
#include "EditorStats.h"
|
||||
#include "EditorCameraInputController.h"
|
||||
|
||||
class EditorSystem : public ImpureSystem
|
||||
{
|
||||
@@ -21,18 +22,24 @@ public:
|
||||
|
||||
void Update(double dt);
|
||||
|
||||
void Enable();
|
||||
void Disable();
|
||||
|
||||
private:
|
||||
IRenderer* m_Renderer;
|
||||
RenderFrame* m_RenderFrame;
|
||||
World* m_EditorWorld;
|
||||
SystemPipeline* m_EditorWorldSystemPipeline;
|
||||
Camera* m_EditorCamera;
|
||||
EntityWrapper m_Camera = EntityWrapper::Invalid;
|
||||
DebugCameraInputController<EditorSystem>* m_DebugCameraInputController;
|
||||
//Camera* m_EditorCamera;
|
||||
EntityWrapper m_EditorCamera = EntityWrapper::Invalid;
|
||||
EntityWrapper m_ActualCamera = EntityWrapper::Invalid;
|
||||
EditorCameraInputController<EditorSystem>* m_EditorCameraInputController;
|
||||
EditorGUI* m_EditorGUI;
|
||||
EditorStats* m_EditorStats;
|
||||
|
||||
// State
|
||||
double m_LastTime = 0.f;
|
||||
bool m_Enabled = true;
|
||||
EditorGUI::WidgetMode m_WidgetMode = EditorGUI::WidgetMode::Translate;
|
||||
EntityWrapper m_Widget = EntityWrapper::Invalid;
|
||||
EntityWrapper m_CurrentSelection = EntityWrapper::Invalid;
|
||||
@@ -56,4 +63,8 @@ private:
|
||||
bool OnMousePress(const Events::MousePress& e);
|
||||
EventRelay<EditorSystem, Events::WidgetDelta> m_EWidgetDelta;
|
||||
bool OnWidgetDelta(const Events::WidgetDelta& e);
|
||||
EventRelay<EditorSystem, Events::InputCommand> m_EInputCommand;
|
||||
bool OnInputCommand(const Events::InputCommand& e);
|
||||
EventRelay<EditorSystem, Events::SetCamera> m_ESetCamera;
|
||||
bool OnSetCamera(const Events::SetCamera& e);
|
||||
};
|
||||
@@ -9,7 +9,7 @@ namespace Events
|
||||
struct InputCommand : Event
|
||||
{
|
||||
/** Numerical ID of the player. */
|
||||
unsigned int PlayerID;
|
||||
int PlayerID;
|
||||
/** The command that was sent. */
|
||||
std::string Command;
|
||||
/** The value of the command. */
|
||||
|
||||
@@ -9,7 +9,34 @@ template <typename EventContext>
|
||||
class FirstPersonInputController : public InputController<EventContext>
|
||||
{
|
||||
public:
|
||||
FirstPersonInputController(EventBroker* eventBroker, unsigned int playerID)
|
||||
FirstPersonInputController(EventBroker* eventBroker, int playerID);
|
||||
|
||||
virtual const glm::vec3 Movement() const { return m_Movement; }
|
||||
virtual const glm::vec3 Rotation() const { return m_Rotation; }
|
||||
virtual bool Jumping() const { return m_Jumping; }
|
||||
virtual bool Crouching() const { return m_Crouching; }
|
||||
|
||||
void LockMouse();
|
||||
void UnlockMouse();
|
||||
virtual bool OnCommand(const Events::InputCommand& e) override;
|
||||
virtual void Reset();
|
||||
|
||||
protected:
|
||||
const int m_PlayerID;
|
||||
bool m_MouseLocked = false;
|
||||
glm::vec3 m_Rotation;
|
||||
glm::vec3 m_Movement;
|
||||
bool m_Jumping = false;
|
||||
bool m_Crouching = false;
|
||||
|
||||
EventRelay<EventContext, Events::LockMouse> m_ELockMouse;
|
||||
bool OnLockMouse(const Events::LockMouse& e);
|
||||
EventRelay<EventContext, Events::UnlockMouse> m_EUnlockMouse;
|
||||
bool OnUnlockMouse(const Events::UnlockMouse& e);
|
||||
};
|
||||
|
||||
template <typename EventContext>
|
||||
FirstPersonInputController<EventContext>::FirstPersonInputController(EventBroker* eventBroker, int playerID)
|
||||
: InputController(eventBroker)
|
||||
, m_PlayerID(playerID)
|
||||
{
|
||||
@@ -17,54 +44,84 @@ public:
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EUnlockMouse, &FirstPersonInputController::OnUnlockMouse);
|
||||
}
|
||||
|
||||
const glm::quat Orientation() const { return m_Orientation; }
|
||||
template <typename EventContext>
|
||||
void FirstPersonInputController<EventContext>::Reset()
|
||||
{
|
||||
m_Rotation = glm::vec3(0.f, 0.f, 0.f);
|
||||
m_Jumping = false;
|
||||
}
|
||||
|
||||
void LockMouse()
|
||||
template <typename EventContext>
|
||||
void FirstPersonInputController<EventContext>::LockMouse()
|
||||
{
|
||||
Events::LockMouse e;
|
||||
m_EventBroker->Publish(e);
|
||||
m_MouseLocked = true;
|
||||
}
|
||||
|
||||
void UnlockMouse()
|
||||
template <typename EventContext>
|
||||
void FirstPersonInputController<EventContext>::UnlockMouse()
|
||||
{
|
||||
Events::UnlockMouse e;
|
||||
m_EventBroker->Publish(e);
|
||||
m_MouseLocked = false;
|
||||
}
|
||||
|
||||
virtual bool OnCommand(const Events::InputCommand& e) override
|
||||
template <typename EventContext>
|
||||
bool FirstPersonInputController<EventContext>::OnCommand(const Events::InputCommand& e)
|
||||
{
|
||||
if (m_PlayerID != e.PlayerID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_MouseLocked) {
|
||||
if (e.Command == "Pitch") {
|
||||
float val = glm::radians(e.Value);
|
||||
m_Orientation = m_Orientation * glm::angleAxis<float>(-val, glm::vec3(1, 0, 0));
|
||||
return true;
|
||||
m_Rotation.x += -val;
|
||||
//m_Rotation.x = glm::clamp(m_Rotation.x, -glm::half_pi<float>(), glm::half_pi<float>());
|
||||
}
|
||||
|
||||
if (e.Command == "Yaw") {
|
||||
float val = glm::radians(e.Value);
|
||||
m_Orientation = glm::angleAxis<float>(-val, glm::vec3(0, 1, 0)) * m_Orientation;
|
||||
m_Rotation.y += -val;
|
||||
}
|
||||
|
||||
if (e.Command == "Forward" || e.Command == "Right") {
|
||||
if (e.Command == "Forward") {
|
||||
float val = glm::clamp(e.Value, -1.f, 1.f);
|
||||
m_Movement.z = -val;
|
||||
}
|
||||
if (e.Command == "Right") {
|
||||
float val = glm::clamp(e.Value, -1.f, 1.f);
|
||||
m_Movement.x = val;
|
||||
}
|
||||
if (glm::length2(m_Movement) > 0) {
|
||||
m_Movement = glm::normalize(m_Movement);
|
||||
}
|
||||
}
|
||||
|
||||
if (e.Command == "Jump") {
|
||||
m_Jumping = e.Value > 0;
|
||||
}
|
||||
|
||||
if (e.Command == "Crouch") {
|
||||
m_Crouching = e.Value > 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename EventContext>
|
||||
bool FirstPersonInputController<EventContext>::OnUnlockMouse(const Events::UnlockMouse& e)
|
||||
{
|
||||
m_MouseLocked = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
template <typename EventContext>
|
||||
bool FirstPersonInputController<EventContext>::OnLockMouse(const Events::LockMouse& e)
|
||||
{
|
||||
m_MouseLocked = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
const unsigned int m_PlayerID;
|
||||
glm::quat m_Orientation;
|
||||
bool m_MouseLocked = false;
|
||||
|
||||
EventRelay<EventContext, Events::LockMouse> m_ELockMouse;
|
||||
bool OnLockMouse(const Events::LockMouse& e) { m_MouseLocked = true; return true; }
|
||||
EventRelay<EventContext, Events::UnlockMouse> m_EUnlockMouse;
|
||||
bool OnUnlockMouse(const Events::UnlockMouse& e) { m_MouseLocked = false; return true; }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "Input/EInputCommand.h"
|
||||
#include "Core/EPlayerDamage.h"
|
||||
#include "Network/EInterpolate.h"
|
||||
#include "Core/EPlayerSpawned.h"
|
||||
|
||||
class Client : public Network
|
||||
{
|
||||
@@ -39,14 +40,14 @@ private:
|
||||
char readBuf[INPUTSIZE] = { 0 };
|
||||
|
||||
// Packet loss logic
|
||||
unsigned int m_PacketID = 0;
|
||||
unsigned int m_PreviousPacketID = 0;
|
||||
unsigned int m_SendPacketID = 0;
|
||||
PacketID m_PacketID = 0;
|
||||
PacketID m_PreviousPacketID = 0;
|
||||
PacketID m_SendPacketID = 0;
|
||||
|
||||
// Game logic
|
||||
World* m_World;
|
||||
std::string m_PlayerName;
|
||||
int m_PlayerID = -1;
|
||||
PlayerID m_PlayerID = -1;
|
||||
EntityID m_ServerEntityID = std::numeric_limits<EntityID>::max();
|
||||
bool m_IsConnected = false;
|
||||
// Server Client Lookup map
|
||||
@@ -57,25 +58,27 @@ private:
|
||||
std::unordered_map<EntityID, EntityID> m_ClientIDToServerID;
|
||||
|
||||
// Network logic
|
||||
PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS];
|
||||
PlayerDefinition m_PlayerDefinitions[8];
|
||||
SnapshotDefinitions m_NextSnapshot;
|
||||
double m_DurationOfPingTime;
|
||||
std::clock_t m_StartPingTime;
|
||||
std::clock_t m_TimeSinceSentInputs;
|
||||
unsigned int m_SendInputIntervalMs;
|
||||
std::vector<Events::InputCommand> m_InputCommandBuffer;
|
||||
|
||||
// Private member functions
|
||||
void readFromServer();
|
||||
int receive(char* data, size_t length);
|
||||
int receive(char* data);
|
||||
void send(Packet& packet);
|
||||
void connect();
|
||||
void disconnect();
|
||||
void ping();
|
||||
void parseMessageType(Packet& packet);
|
||||
void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType);
|
||||
void parseConnect(Packet& packet);
|
||||
void parsePlayerConnected(Packet& packet);
|
||||
void parsePing();
|
||||
void parseServerPing();
|
||||
void parseKick();
|
||||
void parsePlayersSpawned(Packet& packet);
|
||||
void InterpolateFields(Packet & packet, const ComponentInfo & componentInfo, const EntityID & entityID, const std::string & componentType);
|
||||
void parseSnapshot(Packet& packet);
|
||||
void identifyPacketLoss();
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef Events_PlayerDisconnected
|
||||
#define Events_PlayerDisconnected
|
||||
|
||||
#include "Core/EventBroker.h"
|
||||
#include "Core/Entity.h"
|
||||
|
||||
namespace Events
|
||||
{
|
||||
|
||||
struct PlayerDisconnected : public Event
|
||||
{
|
||||
unsigned int PlayerID;
|
||||
EntityID Entity;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -7,14 +7,15 @@ enum class MessageType
|
||||
{
|
||||
Connect,
|
||||
Disconnect,
|
||||
ClientPing,
|
||||
ServerPing,
|
||||
Ping,
|
||||
Message,
|
||||
Snapshot,
|
||||
OnInputCommand,
|
||||
OnPlayerDamage,
|
||||
PlayerConnected,
|
||||
BecomePlayer
|
||||
BecomePlayer,
|
||||
Kick,
|
||||
OnPlayerSpawned
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
#ifndef Network_h__
|
||||
#define Network_h__
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include "Core/World.h"
|
||||
#include "Core/EventBroker.h"
|
||||
#include "Network/Packet.h"
|
||||
#include "Network/NetworkData.h"
|
||||
#include "Core/ResourceManager.h"
|
||||
#include "Core/ConfigFile.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#define MAXCONNECTIONS 8
|
||||
#define INPUTSIZE 4097
|
||||
#define TIMEOUTMS 15000
|
||||
typedef unsigned int PlayerID;
|
||||
typedef unsigned int PacketID;
|
||||
typedef unsigned int UserID;
|
||||
|
||||
class Network
|
||||
{
|
||||
@@ -15,6 +23,17 @@ public:
|
||||
virtual ~Network() { };
|
||||
virtual void Start(World* m_world, EventBroker *eventBroker) = 0;
|
||||
virtual void Update() = 0;
|
||||
protected:
|
||||
// For Debug
|
||||
bool isReadingData = false;
|
||||
NetworkData m_NetworkData;
|
||||
unsigned int m_SaveDataIntervalMs = 1000;
|
||||
std::clock_t m_SaveDataTimer;
|
||||
unsigned int m_MaxConnections;
|
||||
unsigned int m_TimeoutMs;
|
||||
void saveToFile();
|
||||
void updateNetworkData();
|
||||
void initialize();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef NetworkData_h__
|
||||
#define NetworkData_h__
|
||||
#include <vector>
|
||||
|
||||
struct NetworkData {
|
||||
unsigned int TotalTime = 0;
|
||||
unsigned int TotalDataReceived = 0;
|
||||
unsigned int TotalDataSent = 0;
|
||||
unsigned int AmountOfMessagesReceived = 0;
|
||||
unsigned int AmountOfMessagesSent = 0;
|
||||
// Interval based
|
||||
unsigned int DataReceivedThisInterval = 0;
|
||||
unsigned int DataSentThisInterval = 0;
|
||||
// pair: first=reveived, second=send
|
||||
std::vector<std::pair<unsigned int, unsigned int>> BandwidthBytes;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -55,12 +55,14 @@ public:
|
||||
char* Data() { return m_Data; };
|
||||
unsigned int DataReadSize() { return m_ReturnDataOffset; }
|
||||
unsigned int MaxSize() { return m_MaxPacketSize; }
|
||||
unsigned int HeaderSize() { return m_HeaderSize; }
|
||||
|
||||
private:
|
||||
char* m_Data;
|
||||
unsigned int m_ReturnDataOffset = 0;
|
||||
int m_Offset = 0;
|
||||
unsigned int m_MaxPacketSize = 512;
|
||||
unsigned int m_HeaderSize = 0;
|
||||
void resizeData();
|
||||
};
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "../Network/Network.h"
|
||||
#include "Input/EInputCommand.h"
|
||||
#include "Core/EPlayerDamage.h"
|
||||
#include "Network/EPlayerDisconnected.h"
|
||||
#include "Core/EPlayerSpawned.h"
|
||||
|
||||
class Server : public Network
|
||||
{
|
||||
@@ -29,7 +31,7 @@ private:
|
||||
boost::asio::ip::udp::socket m_Socket;
|
||||
|
||||
// Sending messages to client logic
|
||||
PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS];
|
||||
PlayerDefinition m_PlayerDefinitions[8]; //
|
||||
std::vector<PlayerDefinition> m_ConnectedUsers;
|
||||
char readBuffer[INPUTSIZE] = { 0 };
|
||||
int bytesRead = 0;
|
||||
@@ -38,8 +40,8 @@ private:
|
||||
std::clock_t previousSnapshotMessage = std::clock();
|
||||
std::clock_t timOutTimer = std::clock();
|
||||
// How often we send messages (milliseconds)
|
||||
int intervalMs = 1000;
|
||||
int snapshotInterval = 50;
|
||||
int pingIntervalMs;
|
||||
int snapshotInterval;
|
||||
int checkTimeOutInterval = 100;
|
||||
|
||||
//Timers
|
||||
@@ -50,32 +52,36 @@ private:
|
||||
EventBroker* m_EventBroker;
|
||||
|
||||
// Packet loss logic
|
||||
unsigned int m_PacketID = 0;
|
||||
unsigned int m_PreviousPacketID = 0;
|
||||
PacketID m_PacketID = 0;
|
||||
PacketID m_PreviousPacketID = 0;
|
||||
|
||||
// Private member functions
|
||||
int receive(char* data, size_t length);
|
||||
int receive(char* data);
|
||||
void readFromClients();
|
||||
void send(Packet& packet, int playerID);
|
||||
void send(Packet& packet, UserID user);
|
||||
void send(PlayerID player, Packet& packet);
|
||||
void send(Packet& packet);
|
||||
void broadcast(Packet& packet);
|
||||
void sendSnapshot();
|
||||
void sendPing();
|
||||
void checkForTimeOuts();
|
||||
void disconnect(int i);
|
||||
void disconnect(UserID user);
|
||||
void parseMessageType(Packet& packet);
|
||||
void parseOnInputCommand(Packet& packet);
|
||||
void parseOnPlayerDamage(Packet& packet);
|
||||
void parseConnect(Packet& packet);
|
||||
void parseDisconnect();
|
||||
void parseClientPing();
|
||||
void parseServerPing();
|
||||
void parsePing();
|
||||
void identifyPacketLoss();
|
||||
void createPlayer();
|
||||
int GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint);
|
||||
void kick(PlayerID player);
|
||||
PlayerID GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint);
|
||||
// Debug event
|
||||
EventRelay<Server, Events::InputCommand> m_EInputCommand;
|
||||
bool OnInputCommand(const Events::InputCommand& e);
|
||||
EventRelay<Server, Events::PlayerSpawned> m_EPlayerSpawned;
|
||||
bool OnPlayerSpawned(const Events::PlayerSpawned& e);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
#ifndef DebugCameraInputController_h__
|
||||
#define DebugCameraInputController_h__
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
#include "../Input/FirstPersonInputController.h"
|
||||
#include "../Core/EMousePress.h"
|
||||
#include "../Core/EMouseRelease.h"
|
||||
|
||||
template <typename EventContext>
|
||||
class DebugCameraInputController : public FirstPersonInputController<EventContext>
|
||||
{
|
||||
public:
|
||||
DebugCameraInputController(EventBroker* eventBroker, unsigned int playerID)
|
||||
: FirstPersonInputController(eventBroker, playerID)
|
||||
{
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &DebugCameraInputController::OnMousePress);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EMouseRelease, &DebugCameraInputController::OnMouseRelease);
|
||||
}
|
||||
|
||||
void SetPosition(const glm::vec3 position) { m_Position = position; }
|
||||
void SetOrientation(const glm::quat orientation) { m_Orientation = orientation; }
|
||||
|
||||
const glm::vec3 Position() const { return m_Position; }
|
||||
void SetBaseSpeed(float speed) { m_BaseSpeed = speed; }
|
||||
|
||||
virtual bool OnCommand(const Events::InputCommand& e) override
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
if (!io.WantCaptureKeyboard) {
|
||||
if (e.Command == "Right") {
|
||||
float value = std::max(-1.f, std::min(e.Value, 1.f));
|
||||
m_Velocity.x = value;
|
||||
}
|
||||
if (e.Command == "Forward") {
|
||||
float value = std::max(-1.f, std::min(e.Value, 1.f));
|
||||
m_Velocity.z = -value;
|
||||
}
|
||||
if (e.Command == "Sprint") {
|
||||
if (e.Value > 0.f) {
|
||||
m_Speed = m_BaseSpeed * 2.f * (e.Value);
|
||||
} else {
|
||||
m_Speed = m_BaseSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FirstPersonInputController::OnCommand(e);
|
||||
}
|
||||
|
||||
void Update(double dt)
|
||||
{
|
||||
if (glm::length2(m_Velocity) > 0) {
|
||||
m_Position += m_Orientation * (glm::normalize(m_Velocity) * m_Speed * (float)dt);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
glm::vec3 m_Position = glm::vec3(0, 0, 0);
|
||||
glm::vec3 m_Velocity = glm::vec3(0, 0, 0);
|
||||
float m_BaseSpeed = 2.0f;
|
||||
float m_Speed = m_BaseSpeed;
|
||||
EventRelay<EventContext, Events::MousePress> m_EMousePress;
|
||||
bool OnMousePress(const Events::MousePress& e)
|
||||
{
|
||||
if (e.Button == GLFW_MOUSE_BUTTON_2) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (!io.WantCaptureMouse) {
|
||||
LockMouse();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
EventRelay<EventContext, Events::MouseRelease> m_EMouseRelease;
|
||||
bool OnMouseRelease(const Events::MouseRelease& e)
|
||||
{
|
||||
if (e.Button == GLFW_MOUSE_BUTTON_2) {
|
||||
UnlockMouse();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "Renderer.h"
|
||||
#include "PointLightJob.h"
|
||||
#include "../Core/Transform.h"
|
||||
#include "DebugCameraInputController.h"
|
||||
#include "../Core/EPlayerSpawned.h"
|
||||
|
||||
class RenderSystem : public ImpureSystem
|
||||
{
|
||||
@@ -30,6 +30,7 @@ private:
|
||||
RenderFrame* m_RenderFrame;
|
||||
Camera* m_Camera;
|
||||
EntityWrapper m_CurrentCamera = EntityWrapper::Invalid;
|
||||
EntityWrapper m_LocalPlayer = EntityWrapper::Invalid;
|
||||
|
||||
EventRelay<RenderSystem, Events::SetCamera> m_ESetCamera;
|
||||
bool OnSetCamera(Events::SetCamera &event);
|
||||
@@ -41,6 +42,9 @@ private:
|
||||
|
||||
void fillModels(std::list<std::shared_ptr<RenderJob>>& jobs);
|
||||
void fillLight(std::list<std::shared_ptr<RenderJob>>& jobs);
|
||||
|
||||
EventRelay<RenderSystem, Events::PlayerSpawned> m_EPlayerSpawned;
|
||||
bool OnPlayerSpawned(Events::PlayerSpawned& e);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -10,11 +10,12 @@
|
||||
#include "Common.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/EventBroker.h"
|
||||
#include "Core/ResourceManager.h"
|
||||
#include "Core/ConfigFile.h"
|
||||
#include "Core/EPlayerSpawned.h"
|
||||
|
||||
#include "Network/EInterpolate.h"
|
||||
|
||||
#define SNAPSHOTINTERVAL 0.05f
|
||||
|
||||
class InterpolationSystem : public PureSystem
|
||||
{
|
||||
struct Transform
|
||||
@@ -25,29 +26,28 @@ class InterpolationSystem : public PureSystem
|
||||
double interpolationTime;
|
||||
};
|
||||
public:
|
||||
InterpolationSystem(World* world, EventBroker* eventBroker)
|
||||
: System(world, eventBroker)
|
||||
, PureSystem("Transform")
|
||||
{
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EInterpolate, &InterpolationSystem::OnInterpolate);
|
||||
}
|
||||
InterpolationSystem(World* world, EventBroker* eventBroker);
|
||||
~InterpolationSystem() { }
|
||||
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& transform, double dt) override;
|
||||
private:
|
||||
std::unordered_map<EntityID, Transform> m_NextTransform;
|
||||
std::unordered_map<EntityID, Transform> m_LastReceivedTransform;
|
||||
EntityWrapper m_LocalPlayer = EntityWrapper::Invalid;
|
||||
|
||||
//glm::vec3 vectorInterpolation(glm::vec3 prev, glm::vec3 next, double currentTime);
|
||||
template <typename T>
|
||||
T vectorInterpolation(T prev, T next, double currentTime)
|
||||
{
|
||||
T difference = next - prev;
|
||||
T vector = (difference / SNAPSHOTINTERVAL) * static_cast<float>(currentTime);
|
||||
T vector = (difference / m_SnapshotInterval) * static_cast<float>(currentTime);
|
||||
return vector;
|
||||
}
|
||||
float m_SnapshotInterval;
|
||||
|
||||
EventRelay<InterpolationSystem, Events::Interpolate> m_EInterpolate;
|
||||
bool InterpolationSystem::OnInterpolate(const Events::Interpolate& e);
|
||||
EventRelay<InterpolationSystem, Events::PlayerSpawned> m_EPlayerSpawned;
|
||||
bool OnPlayerSpawned(Events::PlayerSpawned& e);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
#include "Common.h"
|
||||
#include "GLM.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/EPlayerSpawned.h"
|
||||
#include "Input/FirstPersonInputController.h"
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
class PlayerMovementSystem : public PureSystem
|
||||
class PlayerMovementSystem : public ImpureSystem, PureSystem
|
||||
{
|
||||
public:
|
||||
PlayerMovementSystem(World* world, EventBroker* eventBroker)
|
||||
: System(world, eventBroker)
|
||||
, PureSystem("Player")
|
||||
{ }
|
||||
PlayerMovementSystem(World* world, EventBroker* eventBroker);
|
||||
~PlayerMovementSystem();
|
||||
|
||||
virtual void Update(double dt) override;
|
||||
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt);
|
||||
|
||||
private:
|
||||
// State
|
||||
std::unordered_map<EntityWrapper, FirstPersonInputController<PlayerMovementSystem>*> m_PlayerInputControllers;
|
||||
|
||||
EventRelay<PlayerMovementSystem, Events::PlayerSpawned> m_EPlayerSpawned;
|
||||
bool OnPlayerSpawned(Events::PlayerSpawned& e);
|
||||
};
|
||||
@@ -2,6 +2,9 @@
|
||||
#include "Input/EInputCommand.h"
|
||||
#include "Systems/SpawnerSystem.h"
|
||||
#include "Events/ESpawnerSpawn.h"
|
||||
#include "Core/EPlayerSpawned.h"
|
||||
#include "Rendering/ESetCamera.h"
|
||||
#include "Core/ConfigFile.h"
|
||||
|
||||
class PlayerSpawnSystem : public ImpureSystem
|
||||
{
|
||||
@@ -11,8 +14,18 @@ public:
|
||||
virtual void Update(double dt) override;
|
||||
|
||||
private:
|
||||
struct SpawnRequest
|
||||
{
|
||||
int PlayerID;
|
||||
ComponentInfo::EnumType Team;
|
||||
};
|
||||
|
||||
bool m_NetworkEnabled = false;
|
||||
std::vector<SpawnRequest> m_SpawnRequests;
|
||||
std::map<int, EntityWrapper> m_PlayerEntities;
|
||||
|
||||
EventRelay<PlayerSpawnSystem, Events::InputCommand> m_OnInputCommand;
|
||||
bool OnInputCommand(const Events::InputCommand& e);
|
||||
|
||||
std::vector<int> m_SpawnRequests;
|
||||
EventRelay<PlayerSpawnSystem, Events::PlayerSpawned> m_OnPlayerSpawnerd;
|
||||
bool OnPlayerSpawned(Events::PlayerSpawned& e);
|
||||
};
|
||||
@@ -1,11 +1,13 @@
|
||||
[Debug]
|
||||
LogLevel=1
|
||||
LoadMap=
|
||||
EditorEnabled=false
|
||||
; if true -> Pool allocation is not used when calling Allocate/Free, just use regular dynamic allocation.
|
||||
; if false -> Use pool allocation.
|
||||
DisableMemoryPool=false
|
||||
|
||||
[Editor]
|
||||
CameraSpeed=3
|
||||
|
||||
[Video]
|
||||
Fullscreen=false
|
||||
VSYNC=false
|
||||
@@ -19,6 +21,11 @@ IsServer=false
|
||||
Name=Bob
|
||||
Address=127.0.0.1
|
||||
Port=13
|
||||
MaxConnections=8
|
||||
SnapshotInterval=0.05
|
||||
SendInputIntervalMs=33
|
||||
PingIntervalMs= 1000
|
||||
TimeoutMs=15000
|
||||
|
||||
[Multithreading]
|
||||
ResourceLoading=true
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||
<Player xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Player.xsd">
|
||||
<Velocity X="0" Y="0" Z="0"/>
|
||||
<Forward>false</Forward>
|
||||
<Left>false</Left>
|
||||
<Back>false</Back>
|
||||
<Right>false</Right>
|
||||
<MovementSpeed>3</MovementSpeed>
|
||||
<CrouchSpeed>1.5</CrouchSpeed>
|
||||
</Player>
|
||||
@@ -9,11 +9,8 @@
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="Velocity" type="t:Vector" minOccurs="0"/>
|
||||
<xs:element name="Forward" type="t:bool" minOccurs="0"/>
|
||||
<xs:element name="Left" type="t:bool" minOccurs="0"/>
|
||||
<xs:element name="Back" type="t:bool" minOccurs="0"/>
|
||||
<xs:element name="Right" type="t:bool" minOccurs="0"/>
|
||||
<xs:element name="MovementSpeed" type="t:float" minOccurs="0"/>
|
||||
<xs:element name="CrouchSpeed" type="t:float" minOccurs="0"/>
|
||||
</xs:all>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||
<Entity xmlns:c="components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd">
|
||||
|
||||
<Components>
|
||||
<c:AABB/>
|
||||
<c:Collidable/>
|
||||
<c:Model>
|
||||
<Resource>Models/Core/UnitCube.obj</Resource>
|
||||
</c:Model>
|
||||
<c:Transform/>
|
||||
</Components>
|
||||
|
||||
<Children/>
|
||||
|
||||
</Entity>
|
||||
@@ -6,66 +6,178 @@
|
||||
</Components>
|
||||
|
||||
<Children>
|
||||
<Entity>
|
||||
<Components>
|
||||
<c:Camera/>
|
||||
<c:Transform/>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
<Entity>
|
||||
<Entity name="Ground">
|
||||
<Components>
|
||||
<c:AABB/>
|
||||
<c:Collidable/>
|
||||
<c:Model>
|
||||
<Resource>Models/Core/UnitCube.mesh</Resource>
|
||||
<Color A="1" B="0.513725519" G="0" R="1"/>
|
||||
<Visible>false</Visible>
|
||||
</c:Model>
|
||||
<c:Transform>
|
||||
<Position X="0" Y="2" Z="0"/>
|
||||
<Scale X="5" Y="1" Z="5"/>
|
||||
<Position X="7" Y="-0.727000058" Z="-1.22800004"/>
|
||||
<Scale X="50" Y="1.45100009" Z="50"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
<Entity name="Player">
|
||||
<Entity name="RedSpawn">
|
||||
<Components>
|
||||
<c:AABB>
|
||||
<Origin X="0" Y="0.773000062" Z="0"/>
|
||||
<Size X="1" Y="1.60000002" Z="1"/>
|
||||
</c:AABB>
|
||||
<c:Collidable/>
|
||||
<c:Physics/>
|
||||
<c:PlayerSpawn/>
|
||||
<c:Spawner>
|
||||
<EntityFile>Schema/Entities/Player.xml</EntityFile>
|
||||
</c:Spawner>
|
||||
<c:Team>
|
||||
<Team>
|
||||
<Red/>
|
||||
</Team>
|
||||
</c:Team>
|
||||
<c:Transform>
|
||||
<Position X="0.300000012" Y="0.0270000007" Z="0"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children>
|
||||
<Entity>
|
||||
<Components>
|
||||
<c:SpawnPoint/>
|
||||
<c:Model>
|
||||
<Resource>Models/Assault.mesh</Resource>
|
||||
<Color A="1" B="1" G="0" R="0"/>
|
||||
<Color A="1" B="0" G="0" R="1"/>
|
||||
</c:Model>
|
||||
<c:Player/>
|
||||
<c:Transform>
|
||||
<Position X="0" Y="2.52699995" Z="0.0542778969"/>
|
||||
<Position X="0.800000012" Y="0" Z="0"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
<Entity>
|
||||
<Components>
|
||||
<c:AABB/>
|
||||
<c:Collidable/>
|
||||
<c:Physics>
|
||||
<Velocity X="0" Y="-0.0934068039" Z="0"/>
|
||||
</c:Physics>
|
||||
<c:SpawnPoint/>
|
||||
<c:Model>
|
||||
<Resource>Models/Core/UnitCube.mesh</Resource>
|
||||
<Color A="1" B="0" G="1" R="1"/>
|
||||
<Resource>Models/Assault.mesh</Resource>
|
||||
<Color A="1" B="0.0117647061" G="0" R="1"/>
|
||||
</c:Model>
|
||||
<c:Player/>
|
||||
<c:Transform>
|
||||
<Position X="0" Y="4.15580511" Z="0"/>
|
||||
<Scale X="0.704558551" Y="0.115156889" Z="1"/>
|
||||
<Position X="-0.600000024" Y="0" Z="0"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
</Children>
|
||||
</Entity>
|
||||
<Entity name="DirectionalLight">
|
||||
<Components>
|
||||
<c:DirectionalLight/>
|
||||
<c:Model>
|
||||
<Resource>Models/DirectionalLightWidget.mesh</Resource>
|
||||
</c:Model>
|
||||
<c:Transform>
|
||||
<Position X="-6.00145912" Y="1.42697716" Z="3.04144025"/>
|
||||
<Orientation X="5.69400024" Y="841.179565" Z="0"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
<Entity name="ObstacleCourse">
|
||||
<Components>
|
||||
<c:Model>
|
||||
<Resource>Models/Test/ObstacleCourse.mesh</Resource>
|
||||
</c:Model>
|
||||
<c:Transform/>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
<Entity name="ObstacleCoursePlayerBox">
|
||||
<Components>
|
||||
<c:AABB/>
|
||||
<c:Collidable/>
|
||||
<c:Model>
|
||||
<Resource>Models/Core/UnitCube.mesh</Resource>
|
||||
<Visible>false</Visible>
|
||||
</c:Model>
|
||||
<c:Transform>
|
||||
<Position X="6.32800007" Y="0.807000041" Z="-2.2750001"/>
|
||||
<Scale X="1" Y="1.60000002" Z="1"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
<Entity name="ObstacleCourse1uHigh">
|
||||
<Components>
|
||||
<c:AABB/>
|
||||
<c:Collidable/>
|
||||
<c:Model>
|
||||
<Resource>Models/Core/UnitCube.mesh</Resource>
|
||||
<Visible>false</Visible>
|
||||
</c:Model>
|
||||
<c:Transform>
|
||||
<Position X="9.11900043" Y="0.5" Z="-2.10900021"/>
|
||||
<Scale X="1" Y="1" Z="8.1960001"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
<Entity name="ObstacleCourseWhoTheFuckKnows">
|
||||
<Components>
|
||||
<c:AABB/>
|
||||
<c:Collidable/>
|
||||
<c:Model>
|
||||
<Resource>Models/Core/UnitCube.mesh</Resource>
|
||||
<Visible>false</Visible>
|
||||
</c:Model>
|
||||
<c:Transform>
|
||||
<Position X="13.2370005" Y="1.28600001" Z="-1.71700013"/>
|
||||
<Scale X="2.58000016" Y="2.58300018" Z="21.1860008"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
<Entity name="BlueSpawn">
|
||||
<Components>
|
||||
<c:PlayerSpawn/>
|
||||
<c:Spawner>
|
||||
<EntityFile>Schema/Entities/Player.xml</EntityFile>
|
||||
</c:Spawner>
|
||||
<c:Team>
|
||||
<Team>
|
||||
<Blue/>
|
||||
</Team>
|
||||
</c:Team>
|
||||
<c:Transform>
|
||||
<Position X="0.300000012" Y="0.0270000007" Z="6.67400026"/>
|
||||
<Orientation X="0" Y="3.20700026" Z="0"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children>
|
||||
<Entity>
|
||||
<Components>
|
||||
<c:SpawnPoint/>
|
||||
<c:Model>
|
||||
<Resource>Models/Assault.mesh</Resource>
|
||||
<Color A="1" B="1" G="0.254901975" R="0"/>
|
||||
</c:Model>
|
||||
<c:Transform>
|
||||
<Position X="0.800000012" Y="0" Z="0"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
<Entity>
|
||||
<Components>
|
||||
<c:SpawnPoint/>
|
||||
<c:Model>
|
||||
<Resource>Models/Assault.mesh</Resource>
|
||||
<Color A="1" B="1" G="0.254901975" R="0"/>
|
||||
</c:Model>
|
||||
<c:Transform>
|
||||
<Position X="-0.600000024" Y="0" Z="0"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
</Children>
|
||||
</Entity>
|
||||
</Children>
|
||||
|
||||
</Entity>
|
||||
|
||||
@@ -2,17 +2,120 @@
|
||||
<Entity name="Player" xmlns:c="components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd">
|
||||
|
||||
<Components>
|
||||
<c:AABB/>
|
||||
<c:Physics/>
|
||||
<c:AABB>
|
||||
<Origin X="0" Y="0.772000015" Z="0"/>
|
||||
<Size X="1" Y="1.60000002" Z="1"/>
|
||||
</c:AABB>
|
||||
<c:Collidable/>
|
||||
<c:Model>
|
||||
<Resource>Models/Core/UnitSphere.mesh</Resource>
|
||||
<Color A="1" B="1" G="0" R="0"/>
|
||||
</c:Model>
|
||||
<c:Player/>
|
||||
<c:Transform/>
|
||||
<c:Model/>
|
||||
<c:Physics>
|
||||
<Velocity X="8.33307467e-09" Y="0" Z="9.82836834e-09"/>
|
||||
</c:Physics>
|
||||
<c:Player>
|
||||
<MovementSpeed>5</MovementSpeed>
|
||||
</c:Player>
|
||||
<c:Team>
|
||||
<Team>
|
||||
<Red/>
|
||||
</Team>
|
||||
</c:Team>
|
||||
<c:Transform>
|
||||
<Position X="2.84928203" Y="0.0264999866" Z="7.31610918"/>
|
||||
<Orientation X="0" Y="2.14675093" Z="0"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
|
||||
<Children>
|
||||
<Entity name="Camera">
|
||||
<Components>
|
||||
<c:Camera/>
|
||||
<c:Transform>
|
||||
<Position X="0" Y="1.37700009" Z="0"/>
|
||||
<Orientation X="0.921535373" Y="0" Z="0"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children>
|
||||
<Entity name="PlayerName">
|
||||
<Components>
|
||||
<c:Text>
|
||||
<Resource>Fonts/DroidSans.ttf,100</Resource>
|
||||
<Color A="1" B="0" G="1" R="0"/>
|
||||
<Visible>false</Visible>
|
||||
</c:Text>
|
||||
<c:Transform>
|
||||
<Position X="0" Y="0.247910097" Z="-0.447844714"/>
|
||||
<Scale X="0.100000001" Y="0.113000005" Z="0.5"/>
|
||||
<Orientation X="0" Y="3.14199996" Z="0"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
<Entity name="CameraModel">
|
||||
<Components>
|
||||
<c:Model>
|
||||
<Resource>Models/Camera.mesh</Resource>
|
||||
</c:Model>
|
||||
<c:Transform>
|
||||
<Position X="0" Y="0.0331346765" Z="-0.0792061687"/>
|
||||
<Scale X="1.30000007" Y="1.50000012" Z="1"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
</Children>
|
||||
</Entity>
|
||||
<Entity name="ThirdPersonCamera">
|
||||
<Components>
|
||||
<c:Camera/>
|
||||
<c:Model>
|
||||
<Resource>Models/Camera.mesh</Resource>
|
||||
<Visible>false</Visible>
|
||||
</c:Model>
|
||||
<c:Transform>
|
||||
<Position X="-0.284000009" Y="1.83800006" Z="1.18900001"/>
|
||||
<Orientation X="5.95600033" Y="0" Z="0"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
<Entity name="PlayerModel">
|
||||
<Components>
|
||||
<c:Model>
|
||||
<Resource>Models/AssaultHeadless.mesh</Resource>
|
||||
</c:Model>
|
||||
<c:Transform>
|
||||
<Orientation X="0" Y="3.14159274" Z="0"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
<Entity name="AABBStanding">
|
||||
<Components>
|
||||
<c:Model>
|
||||
<Resource>Models/Core/UnitCube.mesh</Resource>
|
||||
<Color A="0.427450985" B="1" G="1" R="1"/>
|
||||
<Visible>false</Visible>
|
||||
</c:Model>
|
||||
<c:Transform>
|
||||
<Position X="0" Y="0.772000015" Z="0"/>
|
||||
<Scale X="1" Y="1.60000002" Z="1"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
<Entity name="AABBCrouching">
|
||||
<Components>
|
||||
<c:Model>
|
||||
<Resource>Models/Core/UnitCube.mesh</Resource>
|
||||
<Color A="0.745098054" B="1" G="0" R="1"/>
|
||||
<Visible>false</Visible>
|
||||
</c:Model>
|
||||
<c:Transform>
|
||||
<Position X="0" Y="0.772000015" Z="0"/>
|
||||
</c:Transform>
|
||||
</Components>
|
||||
<Children/>
|
||||
</Entity>
|
||||
</Children>
|
||||
|
||||
</Entity>
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
<xs:simpleType name="double">
|
||||
<xs:restriction base="xs:decimal"></xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="float">
|
||||
<xs:restriction base="xs:decimal"></xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="string">
|
||||
<xs:restriction base="xs:string"></xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
@@ -31,7 +31,7 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c
|
||||
}
|
||||
if (Collision::AABBVsAABB(boxA, boxB, resolutionVector)) {
|
||||
(glm::vec3&)cTransform["Position"] += resolutionVector;
|
||||
cPhysics["Velocity"] = glm::vec3(0, 0, 0);
|
||||
((glm::vec3&)cPhysics["Velocity"]).y = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@ const EntityWrapper EntityWrapper::Invalid = EntityWrapper(nullptr, EntityID_Inv
|
||||
|
||||
bool EntityWrapper::HasComponent(const std::string& componentName)
|
||||
{
|
||||
if (!Valid()) {
|
||||
return false;
|
||||
}
|
||||
return World->HasComponent(ID, componentName);
|
||||
}
|
||||
|
||||
@@ -17,6 +20,34 @@ EntityWrapper EntityWrapper::Parent()
|
||||
}
|
||||
}
|
||||
|
||||
EntityWrapper EntityWrapper::FirstChildByName(const std::string& name)
|
||||
{
|
||||
auto itPair = this->World->GetChildren(this->ID);
|
||||
if (itPair.first == itPair.second) {
|
||||
return EntityWrapper::Invalid;
|
||||
}
|
||||
|
||||
for (auto it = itPair.first; it != itPair.second; ++it) {
|
||||
if (this->World->GetName(it->second) == name) {
|
||||
return EntityWrapper(this->World, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
return EntityWrapper::Invalid;
|
||||
}
|
||||
|
||||
bool EntityWrapper::IsChildOf(EntityWrapper potentialParent)
|
||||
{
|
||||
EntityWrapper entity = *this;
|
||||
while (entity.Parent().Valid()) {
|
||||
entity = entity.Parent();
|
||||
if (entity == potentialParent) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EntityWrapper::Valid()
|
||||
{
|
||||
if (this->World == nullptr) {
|
||||
|
||||
@@ -276,7 +276,7 @@ std::vector<int> Child::childIndicesContainingBox(const AABB& box) const
|
||||
}
|
||||
}
|
||||
|
||||
inline bool Child::hasChildren() const
|
||||
bool Child::hasChildren() const
|
||||
{
|
||||
return m_Children[0] != nullptr;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#include "Core/Transform.h"
|
||||
|
||||
glm::vec3 Transform::AbsolutePosition(EntityWrapper entity)
|
||||
{
|
||||
return AbsolutePosition(entity.World, entity.ID);
|
||||
}
|
||||
|
||||
glm::vec3 Transform::AbsolutePosition(World* world, EntityID entity)
|
||||
{
|
||||
glm::vec3 position;
|
||||
@@ -14,6 +19,11 @@ glm::vec3 Transform::AbsolutePosition(World* world, EntityID entity)
|
||||
return position;
|
||||
}
|
||||
|
||||
glm::quat Transform::AbsoluteOrientation(EntityWrapper entity)
|
||||
{
|
||||
return AbsoluteOrientation(entity.World, entity.ID);
|
||||
}
|
||||
|
||||
glm::quat Transform::AbsoluteOrientation(World* world, EntityID entity)
|
||||
{
|
||||
glm::quat orientation;
|
||||
@@ -27,6 +37,11 @@ glm::quat Transform::AbsoluteOrientation(World* world, EntityID entity)
|
||||
return orientation;
|
||||
}
|
||||
|
||||
glm::vec3 Transform::AbsoluteScale(EntityWrapper entity)
|
||||
{
|
||||
return AbsoluteScale(entity.World, entity.ID);
|
||||
}
|
||||
|
||||
glm::vec3 Transform::AbsoluteScale(World* world, EntityID entity)
|
||||
{
|
||||
glm::vec3 scale(1.f);
|
||||
@@ -40,6 +55,11 @@ glm::vec3 Transform::AbsoluteScale(World* world, EntityID entity)
|
||||
return scale;
|
||||
}
|
||||
|
||||
glm::mat4 Transform::ModelMatrix(EntityWrapper entity)
|
||||
{
|
||||
return ModelMatrix(entity.ID, entity.World);
|
||||
}
|
||||
|
||||
glm::mat4 Transform::ModelMatrix(EntityID entity, World* world)
|
||||
{
|
||||
glm::vec3 position = Transform::AbsolutePosition(world, entity);
|
||||
|
||||
@@ -14,10 +14,11 @@ EditorSystem::EditorSystem(World* world, EventBroker* eventBroker, IRenderer* re
|
||||
m_EditorWorldSystemPipeline->AddSystem<EditorWidgetSystem>(0, m_Renderer);
|
||||
m_EditorWorldSystemPipeline->AddSystem<EditorRenderSystem>(1, m_Renderer, m_RenderFrame);
|
||||
|
||||
m_Camera = importEntity(EntityWrapper(m_EditorWorld, EntityID_Invalid), "Schema/Entities/Empty.xml");
|
||||
m_EditorWorld->AttachComponent(m_Camera.ID, "Transform");
|
||||
m_EditorWorld->AttachComponent(m_Camera.ID, "Camera");
|
||||
m_DebugCameraInputController = new DebugCameraInputController<EditorSystem>(m_EventBroker, -1);
|
||||
m_EditorCamera = importEntity(EntityWrapper(m_EditorWorld, EntityID_Invalid), "Schema/Entities/Empty.xml");
|
||||
m_ActualCamera = m_EditorCamera;
|
||||
m_EditorWorld->AttachComponent(m_EditorCamera.ID, "Transform");
|
||||
m_EditorWorld->AttachComponent(m_EditorCamera.ID, "Camera");
|
||||
m_EditorCameraInputController = new EditorCameraInputController<EditorSystem>(m_EventBroker, -1);
|
||||
|
||||
m_EditorGUI = new EditorGUI(m_World, m_EventBroker);
|
||||
m_EditorGUI->SetEntitySelectedCallback(std::bind(&EditorSystem::OnEntitySelected, this, std::placeholders::_1));
|
||||
@@ -33,38 +34,70 @@ EditorSystem::EditorSystem(World* world, EventBroker* eventBroker, IRenderer* re
|
||||
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &EditorSystem::OnMousePress);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EWidgetDelta, &EditorSystem::OnWidgetDelta);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &EditorSystem::OnInputCommand);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &EditorSystem::OnSetCamera);
|
||||
|
||||
m_EditorStats = new EditorStats();
|
||||
|
||||
Events::SetCamera e;
|
||||
e.CameraEntity = m_Camera;
|
||||
m_EventBroker->Publish(e);
|
||||
if (m_Enabled) {
|
||||
Enable();
|
||||
}
|
||||
}
|
||||
|
||||
EditorSystem::~EditorSystem()
|
||||
{
|
||||
delete m_EditorStats;
|
||||
delete m_EditorGUI;
|
||||
delete m_DebugCameraInputController;
|
||||
delete m_EditorCameraInputController;
|
||||
delete m_EditorWorldSystemPipeline;
|
||||
delete m_EditorWorld;
|
||||
}
|
||||
|
||||
void EditorSystem::Update(double dt)
|
||||
{
|
||||
double now = glfwGetTime();
|
||||
double actualDelta = now - m_LastTime;
|
||||
m_LastTime = now;
|
||||
|
||||
if (m_Enabled) {
|
||||
m_EventBroker->Process<EditorGUI>();
|
||||
m_EditorGUI->Draw();
|
||||
m_EditorStats->Draw(dt);
|
||||
m_EditorStats->Draw(actualDelta);
|
||||
|
||||
if (m_CurrentSelection.Valid() && m_Widget.Valid()) {
|
||||
(glm::vec3&)m_Widget["Transform"]["Position"] = Transform::AbsolutePosition(m_CurrentSelection.World, m_CurrentSelection.ID);
|
||||
}
|
||||
|
||||
m_EditorWorldSystemPipeline->Update(dt);
|
||||
m_EditorWorldSystemPipeline->Update(actualDelta);
|
||||
|
||||
m_DebugCameraInputController->Update(dt);
|
||||
m_Camera["Transform"]["Position"] = m_DebugCameraInputController->Position();
|
||||
m_Camera["Transform"]["Orientation"] = glm::eulerAngles(m_DebugCameraInputController->Orientation());
|
||||
ComponentWrapper& cameraTransform = m_EditorCamera["Transform"];
|
||||
glm::vec3& ori = cameraTransform["Orientation"];
|
||||
ori.x = m_EditorCameraInputController->Rotation().x;
|
||||
ori.y = m_EditorCameraInputController->Rotation().y;
|
||||
glm::vec3& pos = cameraTransform["Position"];
|
||||
pos += m_EditorCameraInputController->Movement() * glm::inverse(glm::quat(ori)) * (float)actualDelta;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorSystem::Enable()
|
||||
{
|
||||
m_EditorCameraInputController->Enable();
|
||||
m_EventBroker->Publish(Events::UnlockMouse());
|
||||
Events::SetCamera e;
|
||||
e.CameraEntity = m_EditorCamera;
|
||||
m_EventBroker->Publish(e);
|
||||
(glm::vec3&)m_EditorCamera["Transform"]["Position"] = Transform::AbsolutePosition(m_ActualCamera);
|
||||
m_Enabled = true;
|
||||
}
|
||||
|
||||
void EditorSystem::Disable()
|
||||
{
|
||||
m_EditorCameraInputController->Disable();
|
||||
m_EventBroker->Publish(Events::LockMouse());
|
||||
Events::SetCamera e;
|
||||
e.CameraEntity = m_ActualCamera;
|
||||
m_EventBroker->Publish(e);
|
||||
m_Enabled = false;
|
||||
}
|
||||
|
||||
void EditorSystem::OnEntitySelected(EntityWrapper entity)
|
||||
@@ -148,6 +181,33 @@ bool EditorSystem::OnWidgetDelta(const Events::WidgetDelta& e)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EditorSystem::OnInputCommand(const Events::InputCommand& e)
|
||||
{
|
||||
if (e.PlayerID != -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.Command == "ToggleEditor" && e.Value > 0) {
|
||||
if (m_Enabled) {
|
||||
Disable();
|
||||
} else {
|
||||
Enable();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EditorSystem::OnSetCamera(const Events::SetCamera& e)
|
||||
{
|
||||
if (m_Enabled && e.CameraEntity != m_EditorCamera) {
|
||||
m_ActualCamera = e.CameraEntity;
|
||||
Events::SetCamera e2;
|
||||
e2.CameraEntity = m_EditorCamera;
|
||||
m_EventBroker->Publish(e2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
EntityWrapper EditorSystem::importEntity(EntityWrapper parent, boost::filesystem::path filePath)
|
||||
{
|
||||
if (parent.World == nullptr) {
|
||||
|
||||
@@ -5,14 +5,20 @@ using namespace boost::asio::ip;
|
||||
|
||||
Client::Client(ConfigFile* config) : m_Socket(m_IOService)
|
||||
{
|
||||
Network::initialize();
|
||||
|
||||
// Asumes root node is EntityID 0
|
||||
insertIntoServerClientMaps(0, 0);
|
||||
// Init timer
|
||||
m_TimeSinceSentInputs = std::clock();
|
||||
// Default is local host
|
||||
std::string address = config->Get<std::string>("Networking.Address", "127.0.0.1");
|
||||
int port = config->Get<int>("Networking.Port", 13);
|
||||
m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port);
|
||||
// Set up network stream
|
||||
m_PlayerName = config->Get<std::string>("Networking.Name", "Raptorcopter");
|
||||
m_SendInputIntervalMs = config->Get<int>("Networking.SendInputIntervalMs", 33);
|
||||
|
||||
}
|
||||
|
||||
Client::~Client()
|
||||
@@ -37,19 +43,24 @@ void Client::Update()
|
||||
readFromServer();
|
||||
if (m_IsConnected) {
|
||||
hasServerTimedOut();
|
||||
// Don't sent 1 input in 1 packet, bunch em up.
|
||||
if (m_SendInputIntervalMs < (1000 * (std::clock() - m_TimeSinceSentInputs) / (double)CLOCKS_PER_SEC)) {
|
||||
sendInputCommands();
|
||||
m_TimeSinceSentInputs = std::clock();
|
||||
}
|
||||
}
|
||||
Network::Update();
|
||||
}
|
||||
|
||||
void Client::readFromServer()
|
||||
{
|
||||
while (m_Socket.available()) {
|
||||
bytesRead = receive(readBuf, INPUTSIZE);
|
||||
bytesRead = receive(readBuf);
|
||||
if (bytesRead > 0) {
|
||||
Packet packet(readBuf, bytesRead);
|
||||
parseMessageType(packet);
|
||||
}
|
||||
}
|
||||
sendInputCommands();
|
||||
}
|
||||
|
||||
void Client::parseMessageType(Packet& packet)
|
||||
@@ -66,12 +77,9 @@ void Client::parseMessageType(Packet& packet)
|
||||
case MessageType::Connect:
|
||||
parseConnect(packet);
|
||||
break;
|
||||
case MessageType::ClientPing:
|
||||
case MessageType::Ping:
|
||||
parsePing();
|
||||
break;
|
||||
case MessageType::ServerPing:
|
||||
parseServerPing();
|
||||
break;
|
||||
case MessageType::Message:
|
||||
break;
|
||||
case MessageType::Snapshot:
|
||||
@@ -81,6 +89,13 @@ void Client::parseMessageType(Packet& packet)
|
||||
break;
|
||||
case MessageType::PlayerConnected:
|
||||
parsePlayerConnected(packet);
|
||||
break;
|
||||
case MessageType::Kick:
|
||||
parseKick();
|
||||
break;
|
||||
case MessageType::OnPlayerSpawned:
|
||||
parsePlayersSpawned(packet);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -99,11 +114,6 @@ void Client::parsePlayerConnected(Packet & packet)
|
||||
}
|
||||
|
||||
void Client::parsePing()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Client::parseServerPing()
|
||||
{
|
||||
// Might miss connect message so set it here instead.
|
||||
m_IsConnected = true;
|
||||
@@ -112,11 +122,26 @@ void Client::parseServerPing()
|
||||
LOG_INFO("%i: response time with ctime(ms): %f", m_PacketID, m_DurationOfPingTime);
|
||||
m_StartPingTime = std::clock();
|
||||
|
||||
Packet packet(MessageType::ServerPing, m_SendPacketID);
|
||||
Packet packet(MessageType::Ping, m_SendPacketID);
|
||||
packet.WriteString("Ping recieved");
|
||||
send(packet);
|
||||
}
|
||||
|
||||
void Client::parseKick()
|
||||
{
|
||||
LOG_WARNING("You have been kicked from the server.");
|
||||
m_IsConnected = false;
|
||||
}
|
||||
|
||||
void Client::parsePlayersSpawned(Packet& packet)
|
||||
{
|
||||
Events::PlayerSpawned e;
|
||||
e.Player = EntityWrapper(m_World, m_ServerIDToClientID[packet.ReadPrimitive<EntityID>()]);
|
||||
e.Spawner = EntityWrapper(m_World, m_ServerIDToClientID[packet.ReadPrimitive<EntityID>()]);
|
||||
e.PlayerID = -1;
|
||||
m_EventBroker->Publish(e);
|
||||
}
|
||||
|
||||
// Fields with strings will not work right now
|
||||
void Client::InterpolateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType)
|
||||
{
|
||||
@@ -153,8 +178,12 @@ void Client::parseSnapshot(Packet& packet)
|
||||
{
|
||||
std::string componentType = packet.ReadString();
|
||||
while (packet.DataReadSize() < packet.Size()) {
|
||||
// HACK
|
||||
std::string entityName = packet.ReadString();
|
||||
// Components EntityID
|
||||
EntityID receivedEntityID = packet.ReadPrimitive<EntityID>();
|
||||
// HACK
|
||||
m_World->SetName(receivedEntityID, entityName);
|
||||
// Parents EntityID
|
||||
EntityID receivedParentEntityID = packet.ReadPrimitive<EntityID>();
|
||||
ComponentInfo componentInfo = m_World->GetComponents(componentType)->ComponentInfo();
|
||||
@@ -211,15 +240,20 @@ void Client::parseSnapshot(Packet& packet)
|
||||
}
|
||||
}
|
||||
|
||||
int Client::receive(char* data, size_t length)
|
||||
int Client::receive(char* data)
|
||||
{
|
||||
boost::system::error_code error;
|
||||
|
||||
int bytesReceived = m_Socket.receive_from(boost
|
||||
::asio::buffer((void*)data, length),
|
||||
::asio::buffer((void*)data, INPUTSIZE),
|
||||
m_ReceiverEndpoint,
|
||||
0, error);
|
||||
|
||||
// Network Debug data
|
||||
if (isReadingData) {
|
||||
m_NetworkData.TotalDataReceived += bytesReceived;
|
||||
m_NetworkData.DataReceivedThisInterval += bytesReceived;
|
||||
m_NetworkData.AmountOfMessagesReceived++;
|
||||
}
|
||||
if (error) {
|
||||
//LOG_ERROR("receive: %s", error.message().c_str());
|
||||
}
|
||||
@@ -232,6 +266,12 @@ void Client::send(Packet& packet)
|
||||
packet.Data(),
|
||||
packet.Size()),
|
||||
m_ReceiverEndpoint, 0);
|
||||
// Network Debug data
|
||||
if (isReadingData) {
|
||||
m_NetworkData.TotalDataSent += packet.Size();
|
||||
m_NetworkData.DataSentThisInterval += packet.Size();
|
||||
m_NetworkData.AmountOfMessagesSent++;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::connect()
|
||||
@@ -250,14 +290,6 @@ void Client::disconnect()
|
||||
send(packet);
|
||||
}
|
||||
|
||||
void Client::ping()
|
||||
{
|
||||
//Packet packet(MessageType::Connect, m_SendPacketID);
|
||||
//packet.WriteString("Ping");
|
||||
//m_StartPingTime = std::clock();
|
||||
//send(packet);
|
||||
}
|
||||
|
||||
bool Client::OnInputCommand(const Events::InputCommand & e)
|
||||
{
|
||||
if (e.Command == "ConnectToServer") { // Connect for now
|
||||
@@ -275,6 +307,15 @@ bool Client::OnInputCommand(const Events::InputCommand & e)
|
||||
if (e.Value > 0) {
|
||||
becomePlayer();
|
||||
}
|
||||
} else if (e.Command == "LogNetworkBandwidth") {
|
||||
if (e.Value > 0) {
|
||||
// Save to file if we no longer want to read data.
|
||||
if (isReadingData) {
|
||||
saveToFile();
|
||||
}
|
||||
isReadingData = !isReadingData;
|
||||
m_SaveDataTimer = std::clock();
|
||||
}
|
||||
} else {
|
||||
m_InputCommandBuffer.push_back(e);
|
||||
//LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
|
||||
@@ -305,7 +346,7 @@ bool Client::hasServerTimedOut()
|
||||
{
|
||||
// Time in ms
|
||||
float timeSincePing = 1000 * (std::clock() - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
|
||||
if (timeSincePing > TIMEOUTMS) {
|
||||
if (timeSincePing > m_TimeoutMs) {
|
||||
// Clear everything and go to menu.
|
||||
LOG_INFO("Server has timed out, returning to menu, Beep Boop.");
|
||||
m_IsConnected = false;
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "Network/Network.h"
|
||||
|
||||
void Network::Update()
|
||||
{
|
||||
updateNetworkData();
|
||||
}
|
||||
|
||||
void Network::saveToFile()
|
||||
{
|
||||
std::ofstream outfile;
|
||||
time_t t = time(0);
|
||||
// get time now
|
||||
struct tm * now = localtime(&t);
|
||||
// Get current time and date
|
||||
std::string dateAndTime = "BandwidthData - " + std::to_string(now->tm_year + 1900) + '-'
|
||||
+ std::to_string(now->tm_mon + 1) + '-'
|
||||
+ std::to_string(now->tm_mday) + '_'
|
||||
+ std::to_string(now->tm_hour) + "h."
|
||||
+ std::to_string(now->tm_min) + "m."
|
||||
+ std::to_string(now->tm_sec) + 's';
|
||||
|
||||
outfile.open(dateAndTime + ".csv");
|
||||
outfile << "Total time," + std::to_string(m_NetworkData.TotalTime) + "\n";
|
||||
outfile << "Total data received," + std::to_string(m_NetworkData.TotalDataReceived) + "\n";
|
||||
outfile << "Total data sent," + std::to_string(m_NetworkData.TotalDataSent) + "\n";
|
||||
outfile << "Total messages received," + std::to_string(m_NetworkData.AmountOfMessagesReceived) + "\n";
|
||||
outfile << "Total messages sent," + std::to_string(m_NetworkData.AmountOfMessagesSent) + "\n";
|
||||
|
||||
float messagesReceivedPerSec = (float)m_NetworkData.AmountOfMessagesReceived / (m_NetworkData.TotalTime / 1000);
|
||||
float messagesSentPerSec = (float)m_NetworkData.AmountOfMessagesSent / (m_NetworkData.TotalTime / 1000);
|
||||
float dataReceivedPerSec = (float)m_NetworkData.TotalDataReceived / (m_NetworkData.TotalTime / 1000);
|
||||
float dataSentPerSec = (float)m_NetworkData.TotalDataSent / (m_NetworkData.TotalTime / 1000);
|
||||
outfile << "Avarage messages received / s: " + std::to_string(messagesReceivedPerSec) + "\n";
|
||||
outfile << "Avarage messages sents / s: " + std::to_string(messagesSentPerSec) + "\n";
|
||||
outfile << "Avarage data received B/s: " + std::to_string(dataReceivedPerSec) + "\n";
|
||||
outfile << "Avarage data sents B/s: " + std::to_string(dataSentPerSec) + "\n";
|
||||
|
||||
outfile << "time, avg receive B, avg send B\n";
|
||||
for (int i = 0; i < m_NetworkData.BandwidthBytes.size(); i++) {
|
||||
outfile << std::to_string(i) + ",";
|
||||
outfile << std::to_string(m_NetworkData.BandwidthBytes[i].first) + ",";
|
||||
outfile << std::to_string(m_NetworkData.BandwidthBytes[i].second) + "\n";
|
||||
}
|
||||
outfile.close();
|
||||
|
||||
}
|
||||
|
||||
void Network::updateNetworkData()
|
||||
{
|
||||
std::clock_t currentTime = std::clock();
|
||||
// Send snapshot
|
||||
if (m_SaveDataIntervalMs < (1000 * (currentTime - m_SaveDataTimer) / (double)CLOCKS_PER_SEC)) {
|
||||
// Set values
|
||||
m_NetworkData.TotalTime += (1000 * (currentTime - m_SaveDataTimer) / (double)CLOCKS_PER_SEC);
|
||||
m_NetworkData.BandwidthBytes.push_back(std::pair<unsigned int, unsigned int>(m_NetworkData.DataReceivedThisInterval, m_NetworkData.DataSentThisInterval));
|
||||
// Reset interval stuff
|
||||
m_SaveDataTimer = std::clock();
|
||||
m_NetworkData.DataSentThisInterval = 0;
|
||||
m_NetworkData.DataReceivedThisInterval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Network::initialize()
|
||||
{
|
||||
ConfigFile* config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||
m_MaxConnections = config->Get<int>("Networking.MaxConnections", 8);
|
||||
m_TimeoutMs = config->Get<int>("Networking.TimeoutMs", 20000);
|
||||
}
|
||||
@@ -39,6 +39,7 @@ void Packet::Init(MessageType type, unsigned int & packetID)
|
||||
Packet::WritePrimitive<int>(messageType);
|
||||
Packet::WritePrimitive<int>(packetID);
|
||||
packetID++;
|
||||
m_HeaderSize = m_Offset;
|
||||
}
|
||||
|
||||
void Packet::WriteString(const std::string& str)
|
||||
|
||||
+112
-37
@@ -1,7 +1,13 @@
|
||||
#include "Network/Server.h"
|
||||
|
||||
Server::Server() : m_Socket(m_IOService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 13))
|
||||
{ }
|
||||
Server::Server() : m_Socket(m_IOService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 27666))
|
||||
{
|
||||
Network::initialize();
|
||||
ConfigFile* config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||
snapshotInterval = 1000 * config->Get<float>("Networking.SnapshotInterval", 0.05);
|
||||
pingIntervalMs = config->Get<float>("Networking.PingIntervalMs", 1000);
|
||||
|
||||
}
|
||||
|
||||
Server::~Server()
|
||||
{
|
||||
@@ -14,7 +20,8 @@ void Server::Start(World* world, EventBroker* eventBroker)
|
||||
m_EventBroker = eventBroker;
|
||||
// Subscribe to events
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Server::OnInputCommand);
|
||||
for (size_t i = 0; i < MAXCONNECTIONS; i++) {
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Server::OnPlayerSpawned);
|
||||
for (size_t i = 0; i < m_MaxConnections; i++) {
|
||||
m_PlayerDefinitions[i].StopTime = std::clock();
|
||||
}
|
||||
LOG_INFO("I am Server. BIP BOP\n");
|
||||
@@ -24,14 +31,17 @@ void Server::Update()
|
||||
{
|
||||
readFromClients();
|
||||
m_EventBroker->Process<Server>();
|
||||
if (isReadingData) {
|
||||
Network::Update();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Server::readFromClients()
|
||||
{
|
||||
while (m_Socket.available()) {
|
||||
try {
|
||||
bytesRead = receive(readBuffer, INPUTSIZE);
|
||||
bytesRead = receive(readBuffer);
|
||||
Packet packet(readBuffer, bytesRead);
|
||||
parseMessageType(packet);
|
||||
} catch (const std::exception& err) {
|
||||
@@ -46,7 +56,7 @@ void Server::readFromClients()
|
||||
}
|
||||
|
||||
// Send pings each
|
||||
if (intervalMs < (1000 * (currentTime - previousePingMessage) / (double)CLOCKS_PER_SEC)) {
|
||||
if (pingIntervalMs < (1000 * (currentTime - previousePingMessage) / (double)CLOCKS_PER_SEC)) {
|
||||
sendPing();
|
||||
previousePingMessage = currentTime;
|
||||
}
|
||||
@@ -70,11 +80,8 @@ void Server::parseMessageType(Packet& packet)
|
||||
case MessageType::Connect:
|
||||
parseConnect(packet);
|
||||
break;
|
||||
case MessageType::ClientPing:
|
||||
//parseClientPing();
|
||||
break;
|
||||
case MessageType::ServerPing:
|
||||
parseServerPing();
|
||||
case MessageType::Ping:
|
||||
parsePing();
|
||||
break;
|
||||
case MessageType::Message:
|
||||
break;
|
||||
@@ -97,21 +104,47 @@ void Server::parseMessageType(Packet& packet)
|
||||
}
|
||||
}
|
||||
|
||||
int Server::receive(char * data, size_t length)
|
||||
int Server::receive(char * data)
|
||||
{
|
||||
length = m_Socket.receive_from(
|
||||
unsigned int length = m_Socket.receive_from(
|
||||
boost::asio::buffer((void*)data
|
||||
, length)
|
||||
, INPUTSIZE)
|
||||
, m_ReceiverEndpoint, 0);
|
||||
// Network Debug data
|
||||
if (isReadingData) {
|
||||
m_NetworkData.TotalDataReceived += length;
|
||||
m_NetworkData.DataReceivedThisInterval += length;
|
||||
m_NetworkData.AmountOfMessagesReceived++;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
void Server::send(Packet& packet, int userID)
|
||||
void Server::send(Packet& packet, UserID user)
|
||||
{
|
||||
int bytesSent = m_Socket.send_to(
|
||||
boost::asio::buffer(packet.Data(), packet.Size()),
|
||||
m_ConnectedUsers[userID].Endpoint,
|
||||
m_ConnectedUsers[user].Endpoint,
|
||||
0);
|
||||
// Network Debug data
|
||||
if (isReadingData) {
|
||||
m_NetworkData.TotalDataSent += packet.Size();
|
||||
m_NetworkData.DataSentThisInterval += packet.Size();
|
||||
m_NetworkData.AmountOfMessagesSent++;
|
||||
}
|
||||
}
|
||||
|
||||
void Server::send(PlayerID player, Packet& packet)
|
||||
{
|
||||
int bytesSent = m_Socket.send_to(
|
||||
boost::asio::buffer(packet.Data(), packet.Size()),
|
||||
m_PlayerDefinitions[player].Endpoint,
|
||||
0);
|
||||
// Network Debug data
|
||||
if (isReadingData) {
|
||||
m_NetworkData.TotalDataSent += packet.Size();
|
||||
m_NetworkData.DataSentThisInterval += packet.Size();
|
||||
m_NetworkData.AmountOfMessagesSent++;
|
||||
}
|
||||
}
|
||||
|
||||
void Server::send(Packet & packet)
|
||||
@@ -122,6 +155,11 @@ void Server::send(Packet & packet)
|
||||
packet.Size()),
|
||||
m_ReceiverEndpoint,
|
||||
0);
|
||||
if (isReadingData) {
|
||||
// Network Debug data
|
||||
m_NetworkData.TotalDataSent += packet.Size();
|
||||
m_NetworkData.DataSentThisInterval += packet.Size();
|
||||
}
|
||||
}
|
||||
|
||||
void Server::broadcast(Packet& packet)
|
||||
@@ -143,9 +181,12 @@ void Server::sendSnapshot()
|
||||
Packet packet(MessageType::Snapshot);
|
||||
ComponentPool* componentPool = it.second;
|
||||
ComponentInfo componentInfo = componentPool->ComponentInfo();
|
||||
|
||||
// Component Type
|
||||
packet.WriteString(componentInfo.Name);
|
||||
for (auto& componentWrapper : *componentPool) {
|
||||
// HACK: Send entity name
|
||||
packet.WriteString(m_World->GetName(componentWrapper.EntityID));
|
||||
// Components EntityID
|
||||
packet.WritePrimitive(componentWrapper.EntityID);
|
||||
// Parents EntityID
|
||||
@@ -160,9 +201,11 @@ void Server::sendSnapshot()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (packet.Size() > packet.HeaderSize() + componentInfo.Name.size()) {
|
||||
broadcast(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Server::sendPing()
|
||||
{
|
||||
@@ -174,7 +217,7 @@ void Server::sendPing()
|
||||
}
|
||||
}
|
||||
// Create ping message
|
||||
Packet packet(MessageType::ServerPing);
|
||||
Packet packet(MessageType::Ping);
|
||||
packet.WriteString("Ping from server");
|
||||
// Time message
|
||||
m_StartPingTime = std::clock();
|
||||
@@ -191,7 +234,7 @@ void Server::checkForTimeOuts()
|
||||
if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) {
|
||||
int stopPing = 1000 * m_ConnectedUsers[i].StopTime /
|
||||
static_cast<double>(CLOCKS_PER_SEC);
|
||||
if (startPing > stopPing + TIMEOUTMS) {
|
||||
if (startPing > stopPing + m_TimeoutMs) {
|
||||
LOG_INFO("User %i timed out!", i);
|
||||
disconnect(i);
|
||||
}
|
||||
@@ -199,35 +242,40 @@ void Server::checkForTimeOuts()
|
||||
}
|
||||
}
|
||||
|
||||
void Server::disconnect(int i)
|
||||
void Server::disconnect(UserID user)
|
||||
{
|
||||
//broadcast("A player disconnected");
|
||||
LOG_INFO("User %s disconnected/timed out", m_PlayerDefinitions[i].Name.c_str());
|
||||
LOG_INFO("User %s disconnected/timed out", m_PlayerDefinitions[user].Name.c_str());
|
||||
// Remove enteties and stuff (When we can remove entity, remove it and tell clients to remove the copy they have)
|
||||
m_PlayerDefinitions[i].Endpoint = boost::asio::ip::udp::endpoint();
|
||||
m_PlayerDefinitions[i].EntityID = -1;
|
||||
m_PlayerDefinitions[i].Name = "";
|
||||
m_PlayerDefinitions[i].PacketID = 0;
|
||||
m_ConnectedUsers.erase(m_ConnectedUsers.begin() + i);
|
||||
Events::PlayerDisconnected e;
|
||||
e.Entity = m_PlayerDefinitions[user].EntityID;
|
||||
e.PlayerID = user;
|
||||
m_EventBroker->Publish(e);
|
||||
|
||||
m_PlayerDefinitions[user].Endpoint = boost::asio::ip::udp::endpoint();
|
||||
m_PlayerDefinitions[user].EntityID = -1;
|
||||
m_PlayerDefinitions[user].Name = "";
|
||||
m_PlayerDefinitions[user].PacketID = 0;
|
||||
m_ConnectedUsers.erase(m_ConnectedUsers.begin() + user);
|
||||
}
|
||||
|
||||
void Server::parseOnInputCommand(Packet& packet)
|
||||
{
|
||||
int playerID = -1;
|
||||
PlayerID player = -1;
|
||||
// Check which player it was who sent the message
|
||||
for (int i = 0; i < MAXCONNECTIONS; i++) {
|
||||
for (int i = 0; i < m_MaxConnections; i++) {
|
||||
// if the player is connected set playerID to the correct PlayerID
|
||||
if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()
|
||||
&& m_PlayerDefinitions[i].Endpoint.port() == m_ReceiverEndpoint.port()) {
|
||||
playerID = i;
|
||||
player = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (playerID != -1) {
|
||||
if (player != -1) {
|
||||
while (packet.DataReadSize() < packet.Size()) {
|
||||
Events::InputCommand e;
|
||||
e.Command = packet.ReadString();
|
||||
e.PlayerID = playerID; // Set correct player id
|
||||
e.PlayerID = player; // Set correct player id
|
||||
e.Value = packet.ReadPrimitive<float>();
|
||||
m_EventBroker->Publish(e);
|
||||
//LOG_INFO("Server::parseOnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
|
||||
@@ -292,17 +340,17 @@ void Server::parseDisconnect()
|
||||
void Server::parseClientPing()
|
||||
{
|
||||
LOG_INFO("%i: Parsing ping", m_PacketID);
|
||||
int playerID = GetPlayerIDFromEndpoint(m_ReceiverEndpoint);
|
||||
if (playerID == -1) {
|
||||
PlayerID player = GetPlayerIDFromEndpoint(m_ReceiverEndpoint);
|
||||
if (player == -1) {
|
||||
return;
|
||||
}
|
||||
// Return ping
|
||||
Packet packet(MessageType::ClientPing, m_PlayerDefinitions[playerID].PacketID);
|
||||
Packet packet(MessageType::Ping, m_PlayerDefinitions[player].PacketID);
|
||||
packet.WriteString("Ping received");
|
||||
send(packet);
|
||||
}
|
||||
|
||||
void Server::parseServerPing()
|
||||
void Server::parsePing()
|
||||
{
|
||||
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
|
||||
if (m_ConnectedUsers[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
|
||||
@@ -328,7 +376,7 @@ void Server::createPlayer()
|
||||
LOG_WARNING("Already connected!");
|
||||
return;
|
||||
}
|
||||
int userIndex;
|
||||
UserID userIndex;
|
||||
for (userIndex = 0; userIndex < m_ConnectedUsers.size(); userIndex++) {
|
||||
if (m_ConnectedUsers[userIndex].Endpoint.address() == m_ReceiverEndpoint.address() &&
|
||||
m_ConnectedUsers[userIndex].Endpoint.port() == m_ReceiverEndpoint.port()) {
|
||||
@@ -340,7 +388,7 @@ void Server::createPlayer()
|
||||
LOG_WARNING("Not a recognized user!");
|
||||
return;
|
||||
}
|
||||
for (int playerIndex = 0; playerIndex < MAXCONNECTIONS; playerIndex++) {
|
||||
for (PlayerID playerIndex = 0; playerIndex < m_MaxConnections; playerIndex++) {
|
||||
if (m_PlayerDefinitions[playerIndex].Endpoint.address() == boost::asio::ip::address()) {
|
||||
m_PlayerDefinitions[playerIndex] = m_ConnectedUsers[userIndex];
|
||||
EntityID entityID = m_World->CreateEntity();
|
||||
@@ -358,9 +406,16 @@ void Server::createPlayer()
|
||||
|
||||
}
|
||||
|
||||
int Server::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint)
|
||||
void Server::kick(PlayerID player)
|
||||
{
|
||||
for (int i = 0; i < MAXCONNECTIONS; i++) {
|
||||
disconnect(player);
|
||||
Packet packet = Packet(MessageType::Kick);
|
||||
send(packet);
|
||||
}
|
||||
|
||||
PlayerID Server::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint)
|
||||
{
|
||||
for (int i = 0; i < m_MaxConnections; i++) {
|
||||
if (m_PlayerDefinitions[i].Endpoint.address() == endpoint.address() &&
|
||||
m_PlayerDefinitions[i].Endpoint.port() == endpoint.port()) {
|
||||
return i;
|
||||
@@ -372,5 +427,25 @@ int Server::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint)
|
||||
bool Server::OnInputCommand(const Events::InputCommand & e)
|
||||
{
|
||||
//LOG_DEBUG("Server::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
|
||||
if (e.Command == "LogNetworkBandwidth" && e.Value > 0) {
|
||||
if (isReadingData) {
|
||||
saveToFile();
|
||||
}
|
||||
isReadingData = !isReadingData;
|
||||
m_SaveDataTimer = std::clock();
|
||||
}
|
||||
if (e.Command == "KickPlayer" && e.Value > 0) {
|
||||
kick(0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Server::OnPlayerSpawned(const Events::PlayerSpawned & e)
|
||||
{
|
||||
Packet packet = Packet(MessageType::OnPlayerSpawned);
|
||||
packet.WritePrimitive<EntityID>(e.Player.ID);
|
||||
packet.WritePrimitive<EntityID>(e.Spawner.ID);
|
||||
send(e.PlayerID, packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ RenderSystem::RenderSystem(World* world, EventBroker* eventBroker, const IRender
|
||||
{
|
||||
EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &RenderSystem::OnSetCamera);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &RenderSystem::OnInputCommand);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &RenderSystem::OnPlayerSpawned);
|
||||
|
||||
m_Camera = new Camera((float)m_Renderer->Resolution().Width / m_Renderer->Resolution().Height, glm::radians(45.f), 0.01f, 5000.f);
|
||||
}
|
||||
@@ -46,6 +47,13 @@ void RenderSystem::fillModels(std::list<std::shared_ptr<RenderJob>>& jobs)
|
||||
continue;
|
||||
}
|
||||
|
||||
EntityWrapper entity(m_World, modelComponent.EntityID);
|
||||
|
||||
// Don't render the local player
|
||||
if (entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Model* model;
|
||||
try {
|
||||
model = ResourceManager::Load<::Model, true>(resource);
|
||||
@@ -68,6 +76,14 @@ void RenderSystem::fillModels(std::list<std::shared_ptr<RenderJob>>& jobs)
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderSystem::OnPlayerSpawned(Events::PlayerSpawned& e)
|
||||
{
|
||||
if (e.PlayerID == -1) {
|
||||
m_LocalPlayer = e.Player;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderSystem::fillPointLights(std::list<std::shared_ptr<RenderJob>>& jobs, World* world)
|
||||
{
|
||||
auto pointLights = m_World->GetComponents("PointLight");
|
||||
@@ -155,11 +171,12 @@ void RenderSystem::Update(double dt)
|
||||
{
|
||||
m_EventBroker->Process<RenderSystem>();
|
||||
|
||||
if (m_CurrentCamera) {
|
||||
ComponentWrapper cameraTransform = m_CurrentCamera["Transform"];
|
||||
m_Camera->SetPosition(cameraTransform["Position"]);
|
||||
m_Camera->SetOrientation(glm::quat((const glm::vec3&)cameraTransform["Orientation"]));
|
||||
// Update the current camera used for rendering
|
||||
if (m_CurrentCamera.Valid()) {
|
||||
m_Camera->SetPosition(Transform::AbsolutePosition(m_CurrentCamera));
|
||||
m_Camera->SetOrientation(Transform::AbsoluteOrientation(m_CurrentCamera));
|
||||
}
|
||||
|
||||
//Only supports opaque geometry atm
|
||||
|
||||
RenderScene scene;
|
||||
|
||||
@@ -1,24 +1,14 @@
|
||||
#include "Systems/InterpolationSystem.h"
|
||||
|
||||
//void InterpolationSystem::UpdateComponent(World * world, ComponentWrapper & transform, double dt)
|
||||
//{
|
||||
// if (m_InterpolationPoints[transform.EntityID].size() > 0) {
|
||||
// Transform& sTransform = m_InterpolationPoints[transform.EntityID].front();
|
||||
// sTransform.interpolationTime += dt;
|
||||
// if (sTransform.interpolationTime > 0.05) {
|
||||
// double time = std::fmod(sTransform.interpolationTime, 0.05f);
|
||||
// m_InterpolationPoints[transform.EntityID].pop();
|
||||
// if (m_InterpolationPoints[transform.EntityID].size() <= 0) {
|
||||
// return;
|
||||
// }
|
||||
// sTransform = m_InterpolationPoints[transform.EntityID].front();
|
||||
// sTransform.interpolationTime = time;
|
||||
// }
|
||||
// glm::vec3 nextPosition = sTransform.Position;
|
||||
// glm::vec3 currentPosition = static_cast<glm::vec3>(transform["Position"]);
|
||||
// transform["Position"] = vectorInterpolation(currentPosition, nextPosition, sTransform.interpolationTime);
|
||||
// }
|
||||
//}
|
||||
InterpolationSystem::InterpolationSystem(World* world, EventBroker* eventBroker)
|
||||
: System(world, eventBroker)
|
||||
, PureSystem("Transform")
|
||||
{
|
||||
ConfigFile* config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||
m_SnapshotInterval = config->Get<float>("Networking.SnapshotInterval", 0.05);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EInterpolate, &InterpolationSystem::OnInterpolate);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &InterpolationSystem::OnPlayerSpawned);
|
||||
}
|
||||
|
||||
void InterpolationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& transform, double dt)
|
||||
{
|
||||
@@ -26,10 +16,10 @@ void InterpolationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrappe
|
||||
m_NextTransform[transform.EntityID].interpolationTime += dt;
|
||||
Transform sTransform = m_NextTransform[transform.EntityID];
|
||||
double time = sTransform.interpolationTime;
|
||||
if (time > SNAPSHOTINTERVAL) {
|
||||
if (time > m_SnapshotInterval) {
|
||||
if (m_LastReceivedTransform.find(transform.EntityID) != m_LastReceivedTransform.end()) {
|
||||
m_NextTransform[transform.EntityID] = m_LastReceivedTransform[transform.EntityID];
|
||||
m_NextTransform[transform.EntityID].interpolationTime = time - SNAPSHOTINTERVAL;
|
||||
m_NextTransform[transform.EntityID].interpolationTime = time - m_SnapshotInterval;
|
||||
sTransform = m_NextTransform[transform.EntityID];
|
||||
m_LastReceivedTransform.erase(transform.EntityID);
|
||||
} else {
|
||||
@@ -37,14 +27,22 @@ 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: Hardcoded tolerance value for player position desync = 1
|
||||
if (isLocalPlayer && glm::length(nextPosition - currentPosition) < 1.f) {
|
||||
return;
|
||||
}
|
||||
(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 / SNAPSHOTINTERVAL));
|
||||
(glm::vec3&)transform["Orientation"] = glm::eulerAngles(glm::slerp<float>(currentOrientation, nextOrientation, sTransform.interpolationTime / m_SnapshotInterval));
|
||||
}
|
||||
// Scale
|
||||
glm::vec3 nextScale = sTransform.Scale;
|
||||
glm::vec3 currentScale = static_cast<glm::vec3>(transform["Scale"]);
|
||||
@@ -53,6 +51,12 @@ void InterpolationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrappe
|
||||
}
|
||||
}
|
||||
|
||||
bool InterpolationSystem::OnPlayerSpawned(Events::PlayerSpawned& e)
|
||||
{
|
||||
m_LocalPlayer = e.Player;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InterpolationSystem::OnInterpolate(const Events::Interpolate & e)
|
||||
{
|
||||
Transform transform;
|
||||
@@ -72,15 +76,5 @@ bool InterpolationSystem::OnInterpolate(const Events::Interpolate & e)
|
||||
} else { // Did not
|
||||
m_NextTransform[e.Entity] = transform;
|
||||
}
|
||||
// Check if queue already exists
|
||||
//if (m_InterpolationPoints.find(e.Entity) != m_InterpolationPoints.end()) { // Did exist, push to queue
|
||||
// m_InterpolationPoints[e.Entity].push(transform);
|
||||
//}
|
||||
|
||||
//else { // Did not exist, create queue
|
||||
// std::queue<Transform> transformQueue;
|
||||
// transformQueue.push(transform);
|
||||
// m_InterpolationPoints[e.Entity] = transformQueue;
|
||||
//}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,132 @@
|
||||
#include "Systems/PlayerMovementSystem.h"
|
||||
|
||||
PlayerMovementSystem::PlayerMovementSystem(World* world, EventBroker* eventBroker)
|
||||
: System(world, eventBroker)
|
||||
, PureSystem("Player")
|
||||
{
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &PlayerMovementSystem::OnPlayerSpawned);
|
||||
}
|
||||
|
||||
PlayerMovementSystem::~PlayerMovementSystem()
|
||||
{
|
||||
for (auto& kv : m_PlayerInputControllers) {
|
||||
delete kv.second;
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerMovementSystem::Update(double dt)
|
||||
{
|
||||
for (auto& kv : m_PlayerInputControllers) {
|
||||
EntityWrapper player = kv.first;
|
||||
auto& controller = kv.second;
|
||||
|
||||
if (!player.Valid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EntityWrapper cameraEntity = player.FirstChildByName("Camera");
|
||||
if (cameraEntity.Valid()) {
|
||||
glm::vec3& cameraOrientation = cameraEntity["Transform"]["Orientation"];
|
||||
cameraOrientation.x += controller->Rotation().x;
|
||||
// Limit camera pitch so we don't break our necks
|
||||
cameraOrientation.x = glm::clamp(cameraOrientation.x, -glm::half_pi<float>(), glm::half_pi<float>());
|
||||
}
|
||||
|
||||
ComponentWrapper& cTransform = player["Transform"];
|
||||
glm::vec3& ori = cTransform["Orientation"];
|
||||
ori.y += controller->Rotation().y;
|
||||
|
||||
if (player.HasComponent("Physics")) {
|
||||
ComponentWrapper cPhysics = player["Physics"];
|
||||
|
||||
glm::vec3 wishDirection = controller->Movement() * glm::inverse(glm::quat(ori));
|
||||
float wishSpeed;
|
||||
if (controller->Crouching()) {
|
||||
wishSpeed = player["Player"]["CrouchSpeed"];
|
||||
} else {
|
||||
wishSpeed = player["Player"]["MovementSpeed"];
|
||||
}
|
||||
glm::vec3& velocity = cPhysics["Velocity"];
|
||||
ImGui::Text("velocity: (%f, %f, %f)", velocity.x, velocity.y, velocity.z);
|
||||
glm::vec3 groundVelocity(0.f, 0.f, 0.f);
|
||||
groundVelocity.x = glm::dot(velocity, glm::vec3(1.f, 0.f, 0.f));
|
||||
groundVelocity.z = glm::dot(velocity, glm::vec3(0.f, 0.f, 1.f));
|
||||
ImGui::Text("groundVelocity: (%f, %f, %f) |%f|", groundVelocity.x, groundVelocity.y, groundVelocity.z, glm::length(wishDirection));
|
||||
ImGui::Text("wishDirection: (%f, %f, %f) |%f|", wishDirection.x, wishDirection.y, wishDirection.z, glm::length(wishDirection));
|
||||
float currentSpeedProj = glm::dot(groundVelocity, wishDirection);
|
||||
float addSpeed = wishSpeed - currentSpeedProj;
|
||||
ImGui::Text("currentSpeedProj: %f", currentSpeedProj);
|
||||
ImGui::Text("wishSpeed: %f", wishSpeed);
|
||||
ImGui::Text("addSpeed: %f", addSpeed);
|
||||
|
||||
if (addSpeed > 0) {
|
||||
static float accel = 15.f;
|
||||
ImGui::InputFloat("accel", &accel);
|
||||
static float airAccel = 0.5f;
|
||||
ImGui::InputFloat("airAccel", &airAccel);
|
||||
float actualAccel = (velocity.y != 0) ? airAccel : accel;
|
||||
static float surfaceFriction = 5.f;
|
||||
ImGui::InputFloat("surfaceFriction", &surfaceFriction);
|
||||
float accelerationSpeed = actualAccel * (float)dt * wishSpeed * surfaceFriction;
|
||||
accelerationSpeed = glm::min(accelerationSpeed, addSpeed);
|
||||
velocity += accelerationSpeed * wishDirection;
|
||||
ImGui::Text("velocity: (%f, %f, %f) |%f|", velocity.x, velocity.y, velocity.z, glm::length(velocity));
|
||||
}
|
||||
|
||||
if (controller->Jumping() && !controller->Crouching() && velocity.y == 0.f) {
|
||||
velocity.y += 4.f;
|
||||
}
|
||||
|
||||
//if (player.HasComponent("AABB")) {
|
||||
// glm::vec3& size = player["AABB"]["Size"];
|
||||
// if (controller->Crouching()) {
|
||||
// size = glm::vec3(1.f, 1.f, 1.f);
|
||||
// } else {
|
||||
// size = glm::vec3(1.f, 1.6f, 1.f);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
controller->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerMovementSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt)
|
||||
{
|
||||
ComponentWrapper& cTransform = entity["Transform"];
|
||||
if (!entity.HasComponent("Physics")) {
|
||||
return;
|
||||
}
|
||||
ComponentWrapper& cPhysics = entity["Physics"];
|
||||
|
||||
ComponentWrapper& cPhysics = entity["Physics"];
|
||||
glm::vec3& velocity = cPhysics["Velocity"];
|
||||
|
||||
// Ground friction
|
||||
float speed = glm::length(velocity);
|
||||
static float groundFriction = 7.f;
|
||||
ImGui::InputFloat("groundFriction", &groundFriction);
|
||||
static float airFriction = 0.f;
|
||||
ImGui::InputFloat("airFriction", &airFriction);
|
||||
float friction = (velocity.y != 0) ? airFriction : groundFriction;
|
||||
if (speed > 0) {
|
||||
float drop = speed * friction * (float)dt;
|
||||
float multiplier = glm::max(speed - drop, 0.f) / speed;
|
||||
velocity.x *= multiplier;
|
||||
velocity.z *= multiplier;
|
||||
}
|
||||
|
||||
if (cPhysics["Gravity"]) {
|
||||
velocity.y -= 9.82 * dt;
|
||||
velocity.y -= 9.82f * (float)dt;
|
||||
}
|
||||
|
||||
glm::vec3& position = cTransform["Position"];
|
||||
position += velocity * (float)dt;
|
||||
}
|
||||
|
||||
bool PlayerMovementSystem::OnPlayerSpawned(Events::PlayerSpawned& e)
|
||||
{
|
||||
// When a player spawns, create an input controller for them
|
||||
m_PlayerInputControllers[e.Player] = new FirstPersonInputController<PlayerMovementSystem>(m_EventBroker, e.PlayerID);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ PlayerSpawnSystem::PlayerSpawnSystem(World* m_World, EventBroker* eventBroker)
|
||||
: System(m_World, eventBroker)
|
||||
{
|
||||
EVENT_SUBSCRIBE_MEMBER(m_OnInputCommand, &PlayerSpawnSystem::OnInputCommand);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_OnPlayerSpawnerd, &PlayerSpawnSystem::OnPlayerSpawned);
|
||||
m_NetworkEnabled = ResourceManager::Load<ConfigFile>("Config.ini")->Get("Networking.StartNetwork", false);
|
||||
}
|
||||
|
||||
void PlayerSpawnSystem::Update(double dt)
|
||||
@@ -13,7 +15,7 @@ void PlayerSpawnSystem::Update(double dt)
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& team : m_SpawnRequests) {
|
||||
for (auto& req : m_SpawnRequests) {
|
||||
for (auto& cPlayerSpawn : *playerSpawns) {
|
||||
EntityWrapper spawner(m_World, cPlayerSpawn.EntityID);
|
||||
if (!spawner.HasComponent("Spawner")) {
|
||||
@@ -22,7 +24,7 @@ void PlayerSpawnSystem::Update(double dt)
|
||||
|
||||
// If the spawner has a team affiliation, check it
|
||||
if (spawner.HasComponent("Team")) {
|
||||
if ((int)spawner["Team"]["Team"] != team) {
|
||||
if ((int)spawner["Team"]["Team"] != req.Team) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -30,7 +32,15 @@ void PlayerSpawnSystem::Update(double dt)
|
||||
// Spawn the player!
|
||||
EntityWrapper player = SpawnerSystem::Spawn(spawner);
|
||||
// Set the player team affiliation
|
||||
player["Team"]["Team"] = team;
|
||||
player["Team"]["Team"] = req.Team;
|
||||
|
||||
// Publish a PlayerSpawned event
|
||||
Events::PlayerSpawned e;
|
||||
e.PlayerID = req.PlayerID;
|
||||
e.Player = player;
|
||||
e.Spawner = spawner;
|
||||
m_EventBroker->Publish(e);
|
||||
|
||||
}
|
||||
}
|
||||
m_SpawnRequests.clear();
|
||||
@@ -42,10 +52,60 @@ bool PlayerSpawnSystem::OnInputCommand(const Events::InputCommand& e)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Team picks should be processed ONLY server-side!
|
||||
// Don't make a spawn request if PlayerID is -1, i.e. we're the client.
|
||||
if (e.PlayerID == -1 && m_NetworkEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.Value != 0) {
|
||||
m_SpawnRequests.push_back((int)e.Value);
|
||||
SpawnRequest req;
|
||||
req.PlayerID = e.PlayerID;
|
||||
req.Team = (ComponentInfo::EnumType)e.Value;
|
||||
m_SpawnRequests.push_back(req);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PlayerSpawnSystem::OnPlayerSpawned(Events::PlayerSpawned& e)
|
||||
{
|
||||
// When a player is actually spawned (since the actual spawning is handled on the server)
|
||||
|
||||
// Check if a player already exists
|
||||
if (m_PlayerEntities.count(e.PlayerID) != 0) {
|
||||
// TODO: Disallow infinite respawning here
|
||||
m_World->DeleteEntity(m_PlayerEntities[e.PlayerID].ID);
|
||||
}
|
||||
|
||||
// Store the player for future reference
|
||||
m_PlayerEntities[e.PlayerID] = e.Player;
|
||||
|
||||
// Set the camera to the correct entity
|
||||
EntityWrapper cameraEntity = e.Player.FirstChildByName("Camera");
|
||||
if (cameraEntity.Valid()) {
|
||||
Events::SetCamera e;
|
||||
e.CameraEntity = cameraEntity;
|
||||
m_EventBroker->Publish(e);
|
||||
}
|
||||
|
||||
// HACK: Set the player model color to team color
|
||||
EntityWrapper playerModel = e.Player.FirstChildByName("PlayerModel");
|
||||
if (playerModel.Valid() && e.Player.HasComponent("Team")) {
|
||||
ComponentWrapper cTeam = e.Player["Team"];
|
||||
ComponentWrapper cModel = playerModel["Model"];
|
||||
if ((ComponentInfo::EnumType)cTeam["Team"] == cTeam["Team"].Enum("Red")) {
|
||||
cModel["Color"] = glm::vec3(1.f, 0.f, 0.f);
|
||||
} else if ((ComponentInfo::EnumType)cTeam["Team"] == cTeam["Team"].Enum("Blue")) {
|
||||
cModel["Color"] = glm::vec3(0.f, 0.25f, 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Set the player name to whatever
|
||||
//EntityWrapper playerName = e.Player.FirstChildByName("PlayerName");
|
||||
//if (playerName.Valid()) {
|
||||
// playerName["Text"]["Content"] = ???;
|
||||
//}
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user