Merge branch 'master' into BoxModelCollision

# Conflicts:
#	include/Engine/Core/Octree.h
#	resources/Schema/Entities/CollisionTestLevel.xml
#	src/Engine/Collision/CollisionSystem.cpp
#	src/Engine/Core/Octree.cpp
This commit is contained in:
William Moberg
2016-01-27 10:52:27 +01:00
145 changed files with 6062 additions and 1105 deletions
+1 -1
View File
@@ -27,7 +27,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;
// }
//}
+63
View File
@@ -3,8 +3,16 @@
const EntityWrapper EntityWrapper::Invalid = EntityWrapper(nullptr, EntityID_Invalid);
const std::string EntityWrapper::Name()
{
return World->GetName(ID);
}
bool EntityWrapper::HasComponent(const std::string& componentName)
{
if (!Valid()) {
return false;
}
return World->HasComponent(ID, componentName);
}
@@ -17,6 +25,35 @@ EntityWrapper EntityWrapper::Parent()
}
}
EntityWrapper EntityWrapper::FirstChildByName(const std::string& name)
{
return firstChildByNameRecursive(name, this->ID);
}
EntityWrapper EntityWrapper::FirstParentWithComponent(const std::string& componentType)
{
EntityWrapper entity = *this;
while (entity.Parent().Valid()) {
entity = entity.Parent();
if (entity.HasComponent(componentType)) {
return entity;
}
}
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) {
@@ -65,3 +102,29 @@ EntityWrapper::operator bool()
return this->Valid();
}
EntityWrapper EntityWrapper::firstChildByNameRecursive(const std::string& name, EntityID parent)
{
if (!this->World->ValidEntity(parent)) {
return EntityWrapper::Invalid;
}
auto itPair = this->World->GetChildren(parent);
if (itPair.first == itPair.second) {
return EntityWrapper::Invalid;
}
for (auto it = itPair.first; it != itPair.second; ++it) {
std::string itName = this->World->GetName(it->second);
if (itName == name) {
return EntityWrapper(this->World, it->second);
} else if (it->second != EntityID_Invalid) {
EntityWrapper result = firstChildByNameRecursive(name, it->second);
if (result != EntityWrapper::Invalid) {
return result;
}
}
}
return EntityWrapper::Invalid;
}
+47
View File
@@ -1,5 +1,22 @@
#include "Core/Transform.h"
glm::mat4 Transform::AbsoluteTransformation(EntityWrapper entity)
{
glm::mat4 t = glm::mat4(1.f);
while (entity.Valid()) {
t = glm::translate((glm::vec3&)entity["Transform"]["Position"]) * glm::toMat4(glm::quat((glm::vec3&)entity["Transform"]["Orientation"])) * glm::scale((glm::vec3&)entity["Transform"]["Scale"]) * t;
entity = entity.Parent();
}
return t;
}
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 +31,24 @@ glm::vec3 Transform::AbsolutePosition(World* world, EntityID entity)
return position;
}
glm::vec3 Transform::AbsoluteOrientationEuler(EntityWrapper entity)
{
glm::vec3 orientation;
while (entity.Valid()) {
ComponentWrapper transform = entity["Transform"];
orientation += (glm::vec3)transform["Orientation"];
entity = entity.Parent();
}
return orientation;
}
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 +62,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,8 +80,15 @@ 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)
{
return AbsoluteTransformation(EntityWrapper(world, entity));
glm::vec3 position = Transform::AbsolutePosition(world, entity);
glm::quat orientation = Transform::AbsoluteOrientation(world, entity);
glm::vec3 scale = Transform::AbsoluteScale(world, entity);
+66 -32
View File
@@ -1,4 +1,6 @@
#include "Core/World.h"
#include "Core/EEntityDeleted.h"
#include "Core/EComponentDeleted.h"
World::~World()
{
@@ -21,37 +23,7 @@ EntityID World::CreateEntity(EntityID parent /*= 0*/)
void World::DeleteEntity(EntityID entity)
{
// Delete components
for (auto& pair : m_ComponentPools) {
auto& pool = pair.second;
if (pool->KnowsEntity(entity)) {
auto& c = pool->GetByEntity(entity);
pool->Delete(c);
}
}
// Loop through children
std::vector<EntityID> childrenToDelete;
auto children = m_EntityChildren.equal_range(entity);
for (auto it = children.first; it != children.second; ++it) {
childrenToDelete.push_back(it->second);
}
for (auto& child : childrenToDelete) {
DeleteEntity(child);
}
EntityID parent = m_EntityParents.at(entity);
m_EntityParents.erase(entity);
auto parentChildren = m_EntityChildren.equal_range(parent);
for (auto it = parentChildren.first; it != parentChildren.second; ++it) {
if (it->second == entity) {
m_EntityChildren.erase(it);
break;
}
}
// Erase potential name
m_EntityNames.erase(entity);
deleteEntityRecursive(entity, false);
}
bool World::ValidEntity(EntityID entity) const
@@ -96,7 +68,15 @@ void World::DeleteComponent(EntityID entity, const std::string& componentType)
{
ComponentPool* pool = m_ComponentPools.at(componentType);
ComponentWrapper c = pool->GetByEntity(entity);
return pool->Delete(c);
pool->Delete(c);
if (m_EventBroker != nullptr) {
Events::ComponentDeleted e;
e.Entity = entity;
e.ComponentType = componentType;
e.Cascaded = false;
m_EventBroker->Publish(e);
}
}
const ComponentPool* World::GetComponents(const std::string& componentType)
@@ -155,3 +135,57 @@ EntityID World::generateEntityID()
return m_CurrentEntityID++;
}
void World::deleteEntityRecursive(EntityID entity, bool cascaded /*= false*/)
{
// Don't attempt to delete entities that don't exist anyway
if (!ValidEntity(entity)) {
return;
}
if (m_EventBroker != nullptr) {
Events::EntityDeleted e;
e.DeletedEntity = entity;
e.Cascaded = cascaded;
m_EventBroker->Publish(e);
}
// Delete components
for (auto& pair : m_ComponentPools) {
auto& pool = pair.second;
if (pool->KnowsEntity(entity)) {
auto& c = pool->GetByEntity(entity);
pool->Delete(c);
if (m_EventBroker != nullptr) {
Events::ComponentDeleted e;
e.Entity = entity;
e.ComponentType = pair.first;
e.Cascaded = true;
m_EventBroker->Publish(e);
}
}
}
// Loop through children
std::vector<EntityID> childrenToDelete;
auto children = m_EntityChildren.equal_range(entity);
for (auto it = children.first; it != children.second; ++it) {
childrenToDelete.push_back(it->second);
}
for (auto& child : childrenToDelete) {
deleteEntityRecursive(child, true);
}
EntityID parent = m_EntityParents.at(entity);
m_EntityParents.erase(entity);
auto parentChildren = m_EntityChildren.equal_range(parent);
for (auto it = parentChildren.first; it != parentChildren.second; ++it) {
if (it->second == entity) {
m_EntityChildren.erase(it);
break;
}
}
// Erase potential name
m_EntityNames.erase(entity);
}
+9
View File
@@ -1,4 +1,5 @@
#include "Editor/EditorGUI.h"
#include "Rendering/ESetCamera.h"
EditorGUI::EditorGUI(World* world, EventBroker* eventBroker)
: m_World(world)
@@ -305,6 +306,14 @@ bool EditorGUI::drawComponentNode(EntityWrapper entity, const ComponentInfo& ci)
}
}
if (ci.Name == "Camera") {
if (ImGui::Button("Activate")) {
Events::SetCamera e;
e.CameraEntity = entity;
m_EventBroker->Publish(e);
}
}
return true;
}
+2 -2
View File
@@ -39,7 +39,7 @@ void EditorRenderSystem::Update(double dt)
continue;
} catch (const std::exception&) {
try {
model = ResourceManager::Load<::Model>("Models/Core/Error.obj");
model = ResourceManager::Load<::Model>("Models/Core/Error.mesh");
} catch (const std::exception&) {
continue;
}
@@ -48,7 +48,7 @@ void EditorRenderSystem::Update(double dt)
EntityWrapper entity(m_World, cModel.EntityID);
glm::mat4 modelMatrix = Transform::ModelMatrix(entity.ID, entity.World);
for (auto matGroup : model->MaterialGroups()) {
std::shared_ptr<ModelJob> modelJob = std::make_shared<ModelJob>(model, scene.Camera, modelMatrix, matGroup, cModel, entity.World);
std::shared_ptr<ModelJob> modelJob = std::make_shared<ModelJob>(model, scene.Camera, modelMatrix, matGroup, cModel, entity.World, glm::vec4(0), 0.f);
scene.ForwardJobs.push_back(modelJob);
}
}
+77 -17
View File
@@ -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)
{
m_EventBroker->Process<EditorGUI>();
m_EditorGUI->Draw();
m_EditorStats->Draw(dt);
double now = glfwGetTime();
double actualDelta = now - m_LastTime;
m_LastTime = now;
if (m_CurrentSelection.Valid() && m_Widget.Valid()) {
(glm::vec3&)m_Widget["Transform"]["Position"] = Transform::AbsolutePosition(m_CurrentSelection.World, m_CurrentSelection.ID);
if (m_Enabled) {
m_EventBroker->Process<EditorGUI>();
m_EditorGUI->Draw();
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(actualDelta);
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;
}
}
m_EditorWorldSystemPipeline->Update(dt);
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;
}
m_DebugCameraInputController->Update(dt);
m_Camera["Transform"]["Position"] = m_DebugCameraInputController->Position();
m_Camera["Transform"]["Orientation"] = glm::eulerAngles(m_DebugCameraInputController->Orientation());
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) {
+190 -84
View File
@@ -5,14 +5,20 @@ using namespace boost::asio::ip;
Client::Client(ConfigFile* config) : m_Socket(m_IOService)
{
// Asumes root node is EntityID 0
insertIntoServerClientMaps(0, 0);
Network::initialize();
// Asumes root node is EntityID_Invalid
insertIntoServerClientMaps(EntityID_Invalid, EntityID_Invalid);
// 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);
int port = config->Get<int>("Networking.Port", 27666);
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()
@@ -25,7 +31,8 @@ void Client::Start(World* world, EventBroker* eventBroker)
// Subscribe to events
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Client::OnInputCommand);
EVENT_SUBSCRIBE_MEMBER(m_EPlayeDamage, &Client::OnPlayerDamage);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &Client::OnPlayerDamage);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Client::OnPlayerSpawned);
m_Socket.connect(m_ReceiverEndpoint);
LOG_INFO("I am client. BIP BOP");
@@ -37,19 +44,25 @@ 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();
}
sendLocalPlayerTransform();
}
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 +79,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 +91,19 @@ void Client::parseMessageType(Packet& packet)
break;
case MessageType::PlayerConnected:
parsePlayerConnected(packet);
break;
case MessageType::Kick:
parseKick();
break;
case MessageType::OnPlayerSpawned:
parsePlayersSpawned(packet);
break;
case MessageType::EntityDeleted:
parseEntityDeletion(packet);
break;
case MessageType::ComponentDeleted:
parseComponentDeletion(packet);
break;
default:
break;
}
@@ -99,11 +122,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 +130,49 @@ 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;
e.PlayerName = packet.ReadString();
m_EventBroker->Publish(e);
}
void Client::parseEntityDeletion(Packet & packet)
{
EntityID entityToDelete = packet.ReadPrimitive<EntityID>();
// TODO: What if an entity that didn't previously exist comes as a delete request and later comes in a delayed snapshot?
if (m_ServerIDToClientID.find(entityToDelete) != m_ServerIDToClientID.end()) {
EntityID localEntity = m_ServerIDToClientID.at(entityToDelete);
if (m_World->ValidEntity(localEntity)) {
m_World->DeleteEntity(localEntity);
deleteFromServerClientMaps(entityToDelete, localEntity);
}
}
}
void Client::parseComponentDeletion(Packet & packet)
{
EntityID entity = packet.ReadPrimitive<EntityID>();
std::string componentType = packet.ReadString();
if (m_World->HasComponent(entity, componentType)) {
m_World->DeleteComponent(m_ServerIDToClientID.at(entity), componentType);
}
}
// Fields with strings will not work right now
void Client::InterpolateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType)
{
@@ -151,75 +207,71 @@ void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, co
void Client::parseSnapshot(Packet& packet)
{
std::string componentType = packet.ReadString();
while (packet.DataReadSize() < packet.Size()) {
// Components EntityID
EntityID receivedEntityID = packet.ReadPrimitive<EntityID>();
// Parents EntityID
EntityID receivedParentEntityID = packet.ReadPrimitive<EntityID>();
ComponentInfo componentInfo = m_World->GetComponents(componentType)->ComponentInfo();
// Check if the received EntityID is mapped to one of our local EntityIDs
if (serverClientMapsHasEntity(receivedEntityID)) {
// Get the local EntityID
EntityID entityID = m_ServerIDToClientID.at(receivedEntityID);
// Check if the component exists
if (m_World->HasComponent(entityID, componentType)) {
// If the entity and the component exists update it
if (componentType == "Transform") {
InterpolateFields(packet, componentInfo, entityID, componentType);
EntityID serverEntityID = packet.ReadPrimitive<EntityID>();
EntityID serverParentID = packet.ReadPrimitive<EntityID>();
std::string serverEntityName = packet.ReadString();
int ammountOfComponents = packet.ReadPrimitive<int>();
for (int i = 0; i < ammountOfComponents; i++) {
std::string componentType = packet.ReadString();
ComponentInfo componentInfo = m_World->GetComponents(componentType)->ComponentInfo();
if (serverClientMapsHasEntity(serverEntityID)) {
EntityID localEntityID = m_ServerIDToClientID.at(serverEntityID);
// Update entity
if (m_World->HasComponent(localEntityID, componentType)) {
// Update component
if (componentType == "Transform") {
// Interpolate only transform components
InterpolateFields(packet, componentInfo, localEntityID, componentType);
} else if (componentType == "Physics" && m_World->HasComponent(localEntityID, "Player")) {
// HACK: Ignore velocity of physics
packet.ReadData(componentInfo.Stride);
} else {
// Set component values
updateFields(packet, componentInfo, localEntityID, componentType);
}
} else {
updateFields(packet, componentInfo, entityID, componentType);
// Has entity but no component
m_World->AttachComponent(localEntityID, componentType);
updateFields(packet, componentInfo, localEntityID, componentType);
}
// if entity exists but not the component
} else {
// Create component
m_World->AttachComponent(entityID, componentType);
// Copy data to newly created component
updateFields(packet, componentInfo, entityID, componentType);
// Create Entity and component
EntityID newLocalEntityID;
if (serverParentID == EntityID_Invalid) {
newLocalEntityID = m_World->CreateEntity(EntityID_Invalid);
} else {
newLocalEntityID = m_World->CreateEntity(m_ServerIDToClientID.at(serverParentID));
}
m_World->SetName(newLocalEntityID, serverEntityName);
insertIntoServerClientMaps(serverEntityID, newLocalEntityID);
m_World->AttachComponent(newLocalEntityID, componentType);
updateFields(packet, componentInfo, newLocalEntityID, componentType);
}
// If the entity dosent exist nor the component
} else {
// Create Entity
// If entity dosen't exist
EntityID newEntityID = m_World->CreateEntity();
insertIntoServerClientMaps(receivedEntityID, newEntityID);
// Check if EntityIDs are out of sync
if (newEntityID != receivedEntityID) {
LOG_INFO("Client::parseSnapshot(Packet& packet): Newly created EntityID is not the \
same as the one sent by server (EntityIDs are out of sync)");
}
// Create component
m_World->AttachComponent(newEntityID, componentType);
// Copy data to newly created component
updateFields(packet, componentInfo, newEntityID, componentType);
}
// Parent Logic
// Don't need to check if receivedEntityID is mapped. (It should have been set)
if (receivedParentEntityID != std::numeric_limits<EntityID>::max()) {
if (serverClientMapsHasEntity(receivedParentEntityID)) {
m_World->SetParent(m_ServerIDToClientID.at(receivedEntityID), m_ServerIDToClientID.at(receivedParentEntityID));
// If Parent dosen't exist create one and map receivedParentEntityID to it.
} else {
// Create the new parent and add it to map
EntityID newParentEntityID = m_World->CreateEntity();
insertIntoServerClientMaps(receivedParentEntityID, newParentEntityID);
// Set the newly created Entity as parent.
m_World->SetParent(m_ServerIDToClientID.at(receivedEntityID), newParentEntityID);
}
// Parent logic
// This should be enough beacause we know that the entities arives in pre-order (there will always be a parent)
if (serverParentID != EntityID_Invalid) {
EntityID localEntityID = m_ServerIDToClientID.at(serverEntityID);
m_World->SetParent(localEntityID, m_ServerIDToClientID.at(serverParentID));
}
}
}
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 +284,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 +308,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 +325,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);
@@ -285,13 +344,40 @@ bool Client::OnInputCommand(const Events::InputCommand & e)
bool Client::OnPlayerDamage(const Events::PlayerDamage & e)
{
Packet packet(MessageType::OnInputCommand, m_SendPacketID);
packet.WritePrimitive(e.DamageAmount);
packet.WritePrimitive(e.PlayerDamagedID);
Packet packet(MessageType::OnPlayerDamage, m_SendPacketID);
packet.WritePrimitive(e.Damage);
packet.WritePrimitive(m_ClientIDToServerID.at(e.Player.ID));
send(packet);
return false;
}
bool Client::OnPlayerSpawned(const Events::PlayerSpawned& e)
{
if (e.PlayerID == -1) {
m_LocalPlayer = e.Player;
}
return true;
}
void Client::sendLocalPlayerTransform()
{
if (!m_LocalPlayer.Valid()) {
return;
}
ComponentWrapper cTransform = m_LocalPlayer["Transform"];
glm::vec3& position = cTransform["Position"];
glm::vec3& orientation = cTransform["Orientation"];
Packet packet(MessageType::PlayerTransform, m_SendPacketID);
packet.WritePrimitive(position.x);
packet.WritePrimitive(position.y);
packet.WritePrimitive(position.z);
packet.WritePrimitive(orientation.x);
packet.WritePrimitive(orientation.y);
packet.WritePrimitive(orientation.z);
send(packet);
}
void Client::identifyPacketLoss()
{
// if no packets lost, difference should be equal to 1
@@ -305,7 +391,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;
@@ -319,7 +405,7 @@ EntityID Client::createPlayer()
EntityID entityID = m_World->CreateEntity();
ComponentWrapper transform = m_World->AttachComponent(entityID, "Transform");
ComponentWrapper model = m_World->AttachComponent(entityID, "Model");
model["Resource"] = "Models/Core/UnitSphere.obj";
model["Resource"] = "Models/Core/UnitSphere.mesh";
ComponentWrapper player = m_World->AttachComponent(entityID, "Player");
return entityID;
}
@@ -345,12 +431,26 @@ void Client::becomePlayer()
bool Client::clientServerMapsHasEntity(EntityID clientEntityID)
{
return m_ClientIDToServerID.find(clientEntityID) != m_ClientIDToServerID.end();
if (m_ClientIDToServerID.find(clientEntityID) != m_ClientIDToServerID.end()) {
if (m_World->ValidEntity(clientEntityID)) {
return true;
}
EntityID serverEntityID = m_ClientIDToServerID.at(clientEntityID);
deleteFromServerClientMaps(serverEntityID, clientEntityID);
}
return false;
}
bool Client::serverClientMapsHasEntity(EntityID serverEntityID)
{
return m_ServerIDToClientID.find(serverEntityID) != m_ServerIDToClientID.end();
if (m_ServerIDToClientID.find(serverEntityID) != m_ServerIDToClientID.end()) {
EntityID localEntityID = m_ServerIDToClientID.at(serverEntityID);
if (m_World->ValidEntity(localEntityID)) {
return true;
}
deleteFromServerClientMaps(serverEntityID, localEntityID);
}
return false;
}
void Client::insertIntoServerClientMaps(EntityID serverEntityID, EntityID clientEntityID)
@@ -359,3 +459,9 @@ void Client::insertIntoServerClientMaps(EntityID serverEntityID, EntityID client
m_ClientIDToServerID.insert(std::make_pair(clientEntityID, serverEntityID));
}
void Client::deleteFromServerClientMaps(EntityID serverEntityID, EntityID clientEntityID)
{
m_ServerIDToClientID.erase(serverEntityID);
m_ClientIDToServerID.erase(clientEntityID);
}
+68
View File
@@ -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);
}
+1
View File
@@ -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)
+211 -133
View File
@@ -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,9 +20,9 @@ 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++) {
m_PlayerDefinitions[i].StopTime = std::clock();
}
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Server::OnPlayerSpawned);
EVENT_SUBSCRIBE_MEMBER(m_EEntityDeleted, &Server::OnEntityDeleted);
EVENT_SUBSCRIBE_MEMBER(m_EComponentDeleted, &Server::OnComponentDeleted);
LOG_INFO("I am Server. BIP BOP\n");
}
@@ -24,14 +30,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 +55,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 +79,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;
@@ -89,29 +95,46 @@ void Server::parseMessageType(Packet& packet)
case MessageType::OnPlayerDamage:
parseOnPlayerDamage(packet);
break;
case MessageType::BecomePlayer:
createPlayer();
case MessageType::PlayerTransform:
parsePlayerTransform(packet);
break;
default:
break;
}
}
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(PlayerID player, Packet& packet)
{
int bytesSent = m_Socket.send_to(
boost::asio::buffer(packet.Data(), packet.Size()),
m_ConnectedUsers[userID].Endpoint,
0);
try {
int bytesSent = m_Socket.send_to(
boost::asio::buffer(packet.Data(), packet.Size()),
m_ConnectedPlayers[player].Endpoint,
0);
// Network Debug data
if (isReadingData) {
m_NetworkData.TotalDataSent += packet.Size();
m_NetworkData.DataSentThisInterval += packet.Size();
m_NetworkData.AmountOfMessagesSent++;
}
} catch (const boost::system::system_error& e) {
// TODO: Clean up invalid endpoints out of m_ConnectedPlayers later
m_ConnectedPlayers[player].Endpoint = boost::asio::ip::udp::endpoint();
}
}
void Server::send(Packet & packet)
@@ -122,59 +145,83 @@ 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)
{
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) {
packet.ChangePacketID(m_ConnectedUsers[i].PacketID);
send(packet, i);
}
for (auto& kv : m_ConnectedPlayers) {
packet.ChangePacketID(kv.second.PacketID);
send(kv.first, packet);
}
}
// Send snapshot fields
void Server::sendSnapshot()
{
// Should time this
Packet packet(MessageType::Snapshot);
addChildrenToPacket(packet, EntityID_Invalid);
broadcast(packet);
}
void Server::addChildrenToPacket(Packet & packet, EntityID entityID)
{
auto itPair = m_World->GetChildren(entityID);
std::unordered_map<std::string, ComponentPool*> worldComponentPools = m_World->GetComponentPools();
for (auto& it : worldComponentPools) {
Packet packet(MessageType::Snapshot);
ComponentPool* componentPool = it.second;
ComponentInfo componentInfo = componentPool->ComponentInfo();
// Component Type
packet.WriteString(componentInfo.Name);
for (auto& componentWrapper : *componentPool) {
// Components EntityID
packet.WritePrimitive(componentWrapper.EntityID);
// Parents EntityID
packet.WritePrimitive(m_World->GetParent(componentWrapper.EntityID));
for (auto& componentField : componentWrapper.Info.FieldsInOrder) {
ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(componentField);
if (fieldInfo.Type == "string") {
std::string& value = componentWrapper[componentField];
packet.WriteString(value);
} else {
packet.WriteData(componentWrapper.Data + fieldInfo.Offset, fieldInfo.Stride);
// Loop through every child
for (auto it = itPair.first; it != itPair.second; it++) {
EntityID childEntityID = it->second;
// Write EntityID and parentsID and Entity name
packet.WritePrimitive(childEntityID);
packet.WritePrimitive(entityID);
packet.WriteString(m_World->GetName(childEntityID));
// Write components to child
int numberOfComponents = 0;
for (auto& i : worldComponentPools) {
if (i.second->KnowsEntity(childEntityID)) {
numberOfComponents++;
}
}
// Write how many components should be read
packet.WritePrimitive(numberOfComponents);
for (auto& i : worldComponentPools) {
// If the entity exist in the pool
if (i.second->KnowsEntity(childEntityID)) {
ComponentWrapper componentWrapper = i.second->GetByEntity(childEntityID);
// ComponentType
packet.WriteString(componentWrapper.Info.Name);
// Loop through fields
for (auto& componentField : componentWrapper.Info.FieldsInOrder) {
ComponentInfo::Field_t fieldInfo = componentWrapper.Info.Fields.at(componentField);
if (fieldInfo.Type == "string") {
std::string& value = componentWrapper[componentField];
packet.WriteString(value);
} else {
packet.WriteData(componentWrapper.Data + fieldInfo.Offset, fieldInfo.Stride);
}
}
}
}
broadcast(packet);
// Go to to your children
addChildrenToPacket(packet, childEntityID);
}
}
void Server::sendPing()
{
// Prints connected players ping
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) {
int ping = 1000 * (m_ConnectedUsers[i].StopTime - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
LOG_INFO("Last packetID received %i: User %i's ping: %i", m_ConnectedUsers[i].PacketID, i, std::abs(ping));
}
}
//for (int i = 0; i < m_ConnectedPlayers.size(); i++) {
// if (m_ConnectedPlayers[i].Endpoint.address() != boost::asio::ip::address()) {
// int ping = 1000 * (m_ConnectedPlayers[i].StopTime - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
// LOG_INFO("Last packetID received %i: User %i's ping: %i", m_ConnectedPlayers[i].PacketID, i, std::abs(ping));
// }
//}
// Create ping message
Packet packet(MessageType::ServerPing);
Packet packet(MessageType::Ping);
packet.WriteString("Ping from server");
// Time message
m_StartPingTime = std::clock();
@@ -187,11 +234,11 @@ void Server::checkForTimeOuts()
int startPing = 1000 * m_StartPingTime
/ static_cast<double>(CLOCKS_PER_SEC);
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) {
int stopPing = 1000 * m_ConnectedUsers[i].StopTime /
for (int i = 0; i < m_ConnectedPlayers.size(); i++) {
if (m_ConnectedPlayers[i].Endpoint.address() != boost::asio::ip::address()) {
int stopPing = 1000 * m_ConnectedPlayers[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 +246,30 @@ void Server::checkForTimeOuts()
}
}
void Server::disconnect(int i)
void Server::disconnect(PlayerID playerID)
{
//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_ConnectedPlayers[playerID].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_ConnectedPlayers[playerID].EntityID;
e.PlayerID = playerID;
m_EventBroker->Publish(e);
m_ConnectedPlayers.erase(playerID);
}
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++) {
// 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;
break;
}
}
if (playerID != -1) {
player = GetPlayerIDFromEndpoint(m_ReceiverEndpoint);
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.Player = EntityWrapper(m_World, m_ConnectedPlayers.at(player).EntityID);
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);
@@ -238,8 +280,8 @@ void Server::parseOnInputCommand(Packet& packet)
void Server::parseOnPlayerDamage(Packet & packet)
{
Events::PlayerDamage e;
e.DamageAmount = packet.ReadPrimitive<double>();
e.PlayerDamagedID = packet.ReadPrimitive<EntityID>();
e.Damage = packet.ReadPrimitive<double>();
e.Player = EntityWrapper(m_World, packet.ReadPrimitive<EntityID>());
m_EventBroker->Publish(e);
//LOG_DEBUG("Server::parseOnPlayerDamage: Command is %s. Value is %f. PlayerID is %i.", e.DamageAmount, e.PlayerDamagedID, e.TypeOfDamage.c_str());
}
@@ -251,9 +293,9 @@ void Server::parseConnect(Packet& packet)
if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) {
return;
}
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
if (m_ConnectedUsers[i].Endpoint.address() == m_ReceiverEndpoint.address() &&
m_ConnectedUsers[i].Endpoint.port() == m_ReceiverEndpoint.port()) {
for (auto& kv : m_ConnectedPlayers) {
if (kv.second.Endpoint.address() == m_ReceiverEndpoint.address() &&
kv.second.Endpoint.port() == m_ReceiverEndpoint.port()) {
// Already connected
return;
}
@@ -265,11 +307,11 @@ void Server::parseConnect(Packet& packet)
pd.Name = packet.ReadString();
pd.PacketID = 0;
pd.StopTime = std::clock();
m_ConnectedUsers.push_back(pd);
m_ConnectedPlayers[m_NextPlayerID++] = pd;
LOG_INFO("Spectator \"%s\" connected on IP: %s", pd.Name.c_str(), pd.Endpoint.address().to_string().c_str());
// Send a message to the player that connected
Packet connnectPacket(MessageType::Connect, m_ConnectedUsers[m_ConnectedUsers.size() - 1].PacketID);
Packet connnectPacket(MessageType::Connect, pd.PacketID);
send(connnectPacket);
// Send notification that a player has connected
@@ -281,9 +323,10 @@ void Server::parseDisconnect()
{
LOG_INFO("%i: Parsing disconnect", m_PacketID);
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
if (m_ConnectedUsers[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
disconnect(i);
for (auto& kv : m_ConnectedPlayers) {
if (kv.second.Endpoint.address() == m_ReceiverEndpoint.address() &&
kv.second.Endpoint.port() == m_ReceiverEndpoint.port()) {
disconnect(kv.first);
break;
}
}
@@ -292,21 +335,21 @@ 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_ConnectedPlayers[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()) {
m_ConnectedUsers[i].StopTime = std::clock();
for (int i = 0; i < m_ConnectedPlayers.size(); i++) {
if (m_ConnectedPlayers[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
m_ConnectedPlayers[i].StopTime = std::clock();
break;
}
}
@@ -321,49 +364,19 @@ void Server::identifyPacketLoss()
}
}
void Server::createPlayer()
void Server::kick(PlayerID player)
{
if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) {
// Already connected as player
LOG_WARNING("Already connected!");
return;
}
int 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()) {
// Found user
break;
}
}
if (userIndex == m_ConnectedUsers.size()) {
LOG_WARNING("Not a recognized user!");
return;
}
for (int playerIndex = 0; playerIndex < MAXCONNECTIONS; playerIndex++) {
if (m_PlayerDefinitions[playerIndex].Endpoint.address() == boost::asio::ip::address()) {
m_PlayerDefinitions[playerIndex] = m_ConnectedUsers[userIndex];
EntityID entityID = m_World->CreateEntity();
ComponentWrapper transform = m_World->AttachComponent(entityID, "Transform");
transform["Position"] = glm::vec3(-1.5f, 0.f, 0.f);
ComponentWrapper model = m_World->AttachComponent(entityID, "Model");
model["Resource"] = "Models/Core/UnitSphere.obj";
model["Color"] = glm::vec4(rand()%255 / 255.f, rand()%255 / 255.f, rand() %255 / 255.f, 1.f);
ComponentWrapper player = m_World->AttachComponent(entityID, "Player");
m_PlayerDefinitions[playerIndex].EntityID = entityID;
return;
}
}
LOG_WARNING("Server is full!");
disconnect(player);
Packet packet = Packet(MessageType::Kick);
send(packet);
}
int Server::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint)
PlayerID Server::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint)
{
for (int i = 0; i < MAXCONNECTIONS; i++) {
if (m_PlayerDefinitions[i].Endpoint.address() == endpoint.address() &&
m_PlayerDefinitions[i].Endpoint.port() == endpoint.port()) {
return i;
for (auto& kv : m_ConnectedPlayers) {
if (kv.second.Endpoint.address() == endpoint.address() &&
kv.second.Endpoint.port() == endpoint.port()) {
return kv.first;
}
}
return -1;
@@ -372,5 +385,70 @@ 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)
{
m_ConnectedPlayers[e.PlayerID].EntityID = e.Player.ID;
Packet packet = Packet(MessageType::OnPlayerSpawned);
packet.WritePrimitive<EntityID>(e.Player.ID);
packet.WritePrimitive<EntityID>(e.Spawner.ID);
// We don't send PlayerID here because it will always be set to -1
packet.WriteString(m_ConnectedPlayers[e.PlayerID].Name);
send(e.PlayerID, packet);
return false;
}
bool Server::OnEntityDeleted(const Events::EntityDeleted & e)
{
if (!e.Cascaded) {
Packet packet = Packet(MessageType::EntityDeleted);
packet.WritePrimitive<EntityID>(e.DeletedEntity);
broadcast(packet);
}
return false;
}
bool Server::OnComponentDeleted(const Events::ComponentDeleted & e)
{
if (!e.Cascaded) {
Packet packet = Packet(MessageType::ComponentDeleted);
packet.WritePrimitive<EntityID>(e.Entity);
packet.WriteString(e.ComponentType);
broadcast(packet);
}
return false;
}
void Server::parsePlayerTransform(Packet& packet)
{
glm::vec3 position;
glm::vec3 orientation;
position.x = packet.ReadPrimitive<float>();
position.y = packet.ReadPrimitive<float>();
position.z = packet.ReadPrimitive<float>();
orientation.x = packet.ReadPrimitive<float>();
orientation.y = packet.ReadPrimitive<float>();
orientation.z = packet.ReadPrimitive<float>();
PlayerID playerID = GetPlayerIDFromEndpoint(m_ReceiverEndpoint);
EntityWrapper player(m_World, m_ConnectedPlayers.at(playerID).EntityID);
if (player.Valid()) {
player["Transform"]["Position"] = position;
player["Transform"]["Orientation"] = orientation;
}
}
+47
View File
@@ -0,0 +1,47 @@
#include "Rendering/AnimationSystem.h"
void AnimationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& animationComponent, double dt)
{
if(!entity.HasComponent("Model")) {
return;
}
Model* model;
try {
model = ResourceManager::Load<::Model, true>(entity["Model"]["Resource"]);
} catch (const std::exception&) {
return;
}
Skeleton* skeleton = model->m_RawModel->m_Skeleton;
const Skeleton::Animation* animation = skeleton->GetAnimation(animationComponent["Name"]);
if(animation != nullptr) {
double animationSpeed = (double)animationComponent["Speed"];
if (animationSpeed != 0.0) {
double nextTime = (double)animationComponent["Time"] + animationSpeed * dt;
if (!(bool)animationComponent["Loop"] && glm::abs(nextTime) > animation->Duration) {
(double&)animationComponent["Time"] = glm::sign(nextTime) * animation->Duration;
(double&)animationComponent["Speed"] = 0.0;
Events::AnimationComplete e;
e.Entity = entity;
e.Name = (std::string)animationComponent["Name"];
m_EventBroker->Publish(e);
} else {
if (glm::abs(nextTime) > animation->Duration) {
(double&)animationComponent["Time"] = glm::abs(nextTime) - animation->Duration;
} else {
(double&)animationComponent["Time"] = nextTime;
}
}
}
}
}
+1 -1
View File
@@ -4,7 +4,7 @@ DrawBloomPass::DrawBloomPass(IRenderer* renderer)
{
m_Renderer = renderer;
m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.obj");
m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.mesh");
InitializeTextures();
InitializeBuffers();
@@ -4,8 +4,8 @@ DrawColorCorrectionPass::DrawColorCorrectionPass(IRenderer* renderer)
{
m_Renderer = renderer;
m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.obj");
m_Exposure = 1; //TODO: Renderer: Fixa så att denna går att ändra på genom komponent eller setting.
m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.mesh");
m_Exposure = 0.4; //TODO: Renderer: Fixa så att denna går att ändra på genom komponent eller setting.
InitializeShaderPrograms();
}
+25 -9
View File
@@ -65,6 +65,7 @@ void DrawFinalPass::Draw(RenderScene& scene)
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
glUniform2f(glGetUniformLocation(shaderHandle, "ScreenDimensions"), m_Renderer->Resolution().Width, m_Renderer->Resolution().Height);
//TODO: Render: Add code for more jobs than modeljobs.
for (auto &job : scene.ForwardJobs) {
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
@@ -72,6 +73,11 @@ void DrawFinalPass::Draw(RenderScene& scene)
//TODO: Kolla upp "header/include/common" shader saken så man slipper skicka in asmycket uniforms
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
glUniform4fv(glGetUniformLocation(shaderHandle, "Color"), 1, glm::value_ptr(modelJob->Color));
glUniform4fv(glGetUniformLocation(shaderHandle, "DiffuseColor"), 1, glm::value_ptr(modelJob->DiffuseColor));
glUniform4fv(glGetUniformLocation(shaderHandle, "FillColor"), 1, glm::value_ptr(modelJob->FillColor));
glUniform1f(glGetUniformLocation(shaderHandle, "FillPercentage"), modelJob->FillPercentage);
glActiveTexture(GL_TEXTURE0);
if(modelJob->DiffuseTexture != nullptr) {
@@ -80,22 +86,32 @@ void DrawFinalPass::Draw(RenderScene& scene)
glBindTexture(GL_TEXTURE_2D, m_WhiteTexture->m_Texture);
}
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_BlackTexture->m_Texture);
/*if(modelJob->GlowMap != nullptr) {
glBindTexture(GL_TEXTURE_2D, modelJob->GlowMap->m_Texture);
if (modelJob->IncandescenceTexture != nullptr) {
glBindTexture(GL_TEXTURE_2D, modelJob->IncandescenceTexture->m_Texture);
} else {
glBindTexture(GL_TEXTURE_2D, m_BlackTexture->m_Texture);
}
/*if(modelJob->GlowMap != nullptr) {
glBindTexture(GL_TEXTURE_2D, modelJob->GlowMap->m_Texture);
} else {
glBindTexture(GL_TEXTURE_2D, m_BlackTexture->m_Texture);
}*/
//TODO: Fixa så att modelsJobs kan spela upp olika animationer och så att den kan få in en tid istället för 1.0f - Hälsningar Johan och Andreas :)
if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) {
if (modelJob->Animation != nullptr) {
std::vector<glm::mat4> frameBones = modelJob->Skeleton->GetFrameBones( *modelJob->Animation, modelJob->AnimationTime);
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
}
}
glBindVertexArray(modelJob->Model->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, 0, modelJob->StartIndex);
continue;
glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int)));
}
}
m_FinalPassFrameBuffer.Unbind();
GLERROR("DrawFinalPass::Draw: END");
delete state;
}
@@ -133,4 +149,4 @@ void DrawFinalPass::GenerateMipMapTexture(GLuint* texture, GLenum wrapping, glm:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
GLERROR("MipMap Texture initialization failed");
}
}
+1 -1
View File
@@ -4,7 +4,7 @@ DrawScreenQuadPass::DrawScreenQuadPass(IRenderer* renderer)
{
m_Renderer = renderer;
m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.obj");
m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.mesh");
InitializeShaderPrograms();
}
+4 -9
View File
@@ -15,6 +15,9 @@ Model::Model(std::string fileName)
if (!group.SpecularMapPath.empty()) {
group.SpecularMap = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(group.SpecularMapPath));
}
if (!group.IncandescenceMapPath.empty()) {
group.IncandescenceMap = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(group.IncandescenceMapPath));
}
}
// Generate GL buffers
@@ -32,7 +35,7 @@ Model::Model(std::string fileName)
GLERROR("GLEW: BufferFail4");
glBindBuffer(GL_ARRAY_BUFFER, buffer);
std::vector<int> structSizes = { 3, 3, 3, 3, 2, 4, 4, 4, 4, 4, 4 };
std::vector<int> structSizes = { 3, 3, 3, 3, 2, 4, 4 };
int stride = 0;
for (int size : structSizes) {
stride += size;
@@ -48,10 +51,6 @@ Model::Model(std::string fileName)
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
}
GLERROR("GLEW: BufferFail5");
@@ -62,10 +61,6 @@ Model::Model(std::string fileName)
glEnableVertexAttribArray(4);
glEnableVertexAttribArray(5);
glEnableVertexAttribArray(6);
glEnableVertexAttribArray(7);
glEnableVertexAttribArray(8);
glEnableVertexAttribArray(9);
glEnableVertexAttribArray(10);
GLERROR("GLEW: BufferFail5");
//CreateBuffers();
+16 -8
View File
@@ -48,7 +48,7 @@ void PickingPass::Draw(RenderScene& scene)
PickingPassState* state = new PickingPassState(m_PickingBuffer.GetHandle());
//TODO: Render: Add code for more jobs than modeljobs.
GLuint ShaderHandle = m_PickingProgram->GetHandle();
GLuint shaderHandle = m_PickingProgram->GetHandle();
m_PickingProgram->Bind();
if (scene.ClearDepth) {
@@ -75,22 +75,30 @@ void PickingPass::Draw(RenderScene& scene)
m_EntityColors[std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera)] = glm::ivec2(pickColor[0], pickColor[1]);
if (m_ColorCounter[0] > 255) {
m_ColorCounter[0] = 0;
m_ColorCounter[1]++;
m_ColorCounter[1] += 5;
} else {
m_ColorCounter[0]++;
m_ColorCounter[0] += 50;
}
}
m_PickingColorsToEntity[glm::ivec2(pickColor[0], pickColor[1])] = pickInfo;
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
glUniform2fv(glGetUniformLocation(ShaderHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
glUniform2fv(glGetUniformLocation(shaderHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) {
if (modelJob->Animation != nullptr) {
std::vector<glm::mat4> frameBones = modelJob->Skeleton->GetFrameBones(*modelJob->Animation, modelJob->AnimationTime);
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
}
}
glBindVertexArray(modelJob->Model->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, nullptr, modelJob->StartIndex);
glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int)));
}
}
@@ -1,6 +1,8 @@
#include "Rendering/RawModel.h"
#include "Rendering/RawModelAssimp.h"
RawModel::RawModel(std::string fileName)
#ifdef USING_ASSIMP_AS_IMPORTER
RawModelAssimp::RawModelAssimp(std::string fileName)
{
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(fileName, aiProcess_CalcTangentSpace | aiProcess_Triangulate);
@@ -38,7 +40,7 @@ RawModel::RawModel(std::string fileName)
//LOG_DEBUG("Index count %i", numIndices);
//LOG_DEBUG("Model has %i embedded textures", scene->mNumTextures);
std::vector<std::tuple<std::string, glm::mat4>> boneInfo;
std::map<std::string, int> boneNameMapping;
@@ -74,21 +76,7 @@ RawModel::RawModel(std::string fileName)
auto uv = mesh->mTextureCoords[0][vertexIndex];
desc.TextureCoords = glm::vec2(uv.x, uv.y);
}
// Material diffuse color
aiColor3D diffuse;
material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse);
float opacity;
material->Get(AI_MATKEY_OPACITY, opacity);
desc.DiffuseVertexColor = glm::vec4(diffuse.r, diffuse.g, diffuse.b, opacity);
desc.DiffuseVertexColor = glm::vec4(diffuse.r, diffuse.g, diffuse.b, opacity);
// Material specular color
aiColor3D specular;
material->Get(AI_MATKEY_COLOR_SPECULAR, specular);
desc.SpecularVertexColor = glm::vec4(specular.r, specular.g, specular.b, 1.f);
m_Vertices.push_back(desc);
}
@@ -128,7 +116,7 @@ RawModel::RawModel(std::string fileName)
}
for (auto& vertex : m_Vertices) {
vertex.Tangent = glm::normalize(vertex.Tangent);
vertex.BiTangent = glm::normalize(glm::cross(vertex.Tangent, glm::normalize(vertex.Normal)));
vertex.BiNormal = glm::normalize(glm::cross(vertex.Tangent, glm::normalize(vertex.Normal)));
}
// Material info
@@ -201,10 +189,7 @@ RawModel::RawModel(std::string fileName)
LOG_WARNING("Vertex weights (%i) greater than max weights per vertex (%i)", weights.size(), maxWeights);
}
for (int weightIndex = 0; weightIndex < weights.size() && weightIndex < maxWeights && weightIndex < 4; ++weightIndex) {
std::tie(desc.BoneIndices1[weightIndex], desc.BoneWeights1[weightIndex]) = weights[weightIndex];
}
for (int weightIndex = 4; weightIndex < weights.size() && weightIndex < maxWeights && weightIndex < 8; ++weightIndex) {
std::tie(desc.BoneIndices2[weightIndex - 4], desc.BoneWeights2[weightIndex - 4]) = weights[weightIndex];
std::tie(desc.BoneIndices[weightIndex], desc.BoneWeights[weightIndex]) = weights[weightIndex];
}
}
@@ -290,14 +275,14 @@ RawModel::RawModel(std::string fileName)
}
}
RawModel::~RawModel()
RawModelAssimp::~RawModelAssimp()
{
if (m_Skeleton) {
delete m_Skeleton;
}
}
void RawModel::CreateSkeleton(std::vector<std::tuple<std::string, glm::mat4>> &boneInfo, std::map<std::string, int> &boneNameMapping, aiNode* node, int parentID)
void RawModelAssimp::CreateSkeleton(std::vector<std::tuple<std::string, glm::mat4>> &boneInfo, std::map<std::string, int> &boneNameMapping, aiNode* node, int parentID)
{
std::string nodeName = node->mName.C_Str();
@@ -317,3 +302,5 @@ void RawModel::CreateSkeleton(std::vector<std::tuple<std::string, glm::mat4>> &b
CreateSkeleton(boneInfo, boneNameMapping, child, parentID);
}
}
#endif
+381
View File
@@ -0,0 +1,381 @@
#include "Rendering/RawModelCustom.h"
#ifndef USING_ASSIMP_AS_IMPORTER
RawModelCustom::RawModelCustom(std::string fileName)
{
if(fileName.substr(fileName.find_last_of(".")).compare(".mesh") != 0) {
throw Resource::FailedLoadingException("Unknown model file format. Please use \".mesh\" files.");
}
fileName = fileName.erase(fileName.find_last_of("."), fileName.find_last_of(".") - fileName.size());
ReadMeshFile(fileName);
ReadMaterialFile(fileName);
ReadAnimationFile(fileName);
}
void RawModelCustom::ReadMeshFile(std::string filePath)
{
char* fileData;
filePath += ".mesh";
std::ifstream in(filePath.c_str(), std::ios_base::binary | std::ios_base::ate);
if (!in.is_open()) {
throw Resource::FailedLoadingException("Open mesh file failed");
}
unsigned int fileByteSize = in.tellg();
in.seekg(0, std::ios_base::beg);
fileData = new char[fileByteSize];
in.read(fileData, fileByteSize);
in.close();
unsigned int offset = 0;
if (fileByteSize > 0) {
ReadMeshFileHeader(offset, fileData, fileByteSize);
ReadMesh(offset, fileData, fileByteSize);
}
delete fileData;
}
void RawModelCustom::ReadMeshFileHeader(unsigned int& offset, char* fileData, unsigned int& fileByteSize)
{
#ifdef BOOST_LITTLE_ENDIAN
m_Vertices.resize(*(unsigned int*)(fileData + offset));
offset += sizeof(unsigned int);
m_Indices.resize(*(unsigned int*)(fileData + offset));
offset += sizeof(unsigned int);
#else
#endif
}
void RawModelCustom::ReadMesh(unsigned int& offset, char* fileData, unsigned int& fileByteSize)
{
ReadVertices(offset, fileData, fileByteSize);
ReadIndices(offset, fileData, fileByteSize);
}
void RawModelCustom::ReadVertices(unsigned int& offset, char* fileData, unsigned int& fileByteSize)
{
#ifdef BOOST_LITTLE_ENDIAN
if (offset + m_Vertices.size() * sizeof(Vertex) > fileByteSize) {
throw Resource::FailedLoadingException("Reading vertices failed");
}
memcpy(&m_Vertices[0], fileData + offset, m_Vertices.size() * sizeof(Vertex));
offset += m_Vertices.size() * sizeof(Vertex);
#else
#endif
}
void RawModelCustom::ReadIndices(unsigned int& offset, char* fileData, unsigned int& fileByteSize)
{
#ifdef BOOST_LITTLE_ENDIAN
if (offset + m_Indices.size() * sizeof(unsigned int) > fileByteSize) {
throw Resource::FailedLoadingException("Reading indices failed");
}
memcpy(&m_Indices[0], fileData + offset, m_Indices.size() * sizeof(unsigned int));
offset += m_Indices.size() * sizeof(unsigned int);
#else
#endif
}
void RawModelCustom::ReadMaterialFile(std::string filePath)
{
char* fileData;
filePath += ".mtrl";
std::ifstream in(filePath.c_str(), std::ios_base::binary | std::ios_base::ate);
if (!in.is_open()) {
throw Resource::FailedLoadingException("Open material file failed");
}
unsigned int fileByteSize = in.tellg();
in.seekg(0, std::ios_base::beg);
fileData = new char[fileByteSize];
in.read(fileData, fileByteSize);
in.close();
unsigned int offset = 0;
if (fileByteSize > 0) {
ReadMaterials(offset, fileData, fileByteSize);
}
delete fileData;
}
void RawModelCustom::ReadMaterials(unsigned int& offset, char* fileData, unsigned int& fileByteSize)
{
#ifdef BOOST_LITTLE_ENDIAN
unsigned int* numMaterials = (unsigned int*)(fileData);
MaterialGroups.reserve(*numMaterials);
offset += sizeof(unsigned int);
for (int i = 0; i < *numMaterials; i++) {
ReadMaterialSingle(offset, fileData, fileByteSize);
}
#else
#endif
}
void RawModelCustom::ReadMaterialSingle(unsigned int &offset, char* fileData, unsigned int& fileByteSize)
{
MaterialGroup newMaterial;
#ifdef BOOST_LITTLE_ENDIAN
if (offset + sizeof(unsigned int) * 4 > fileByteSize) {
throw Resource::FailedLoadingException("Reading Material texture names length failed");
}
unsigned int* nameLengths = (unsigned int*)(fileData + offset);
offset += sizeof(unsigned int) * 4;
if (offset + sizeof(float) * 11 + sizeof(unsigned int) * 2 > fileByteSize) {
throw Resource::FailedLoadingException("Reading Material specular, reflection, color and start and end index values failed");
}
newMaterial.SpecularExponent = *(float*)(fileData + offset);
offset += sizeof(float);
newMaterial.ReflectionFactor = *(float*)(fileData + offset);
offset += sizeof(float);
memcpy(&newMaterial.DiffuseColor[0], fileData + offset, sizeof(float) * 3);
offset += sizeof(float) * 3;
memcpy(&newMaterial.SpecularColor[0], fileData + offset, sizeof(float) * 3);
offset += sizeof(float) * 3;
memcpy(&newMaterial.IncandescenceColor[0], fileData + offset, sizeof(float) * 3);
offset += sizeof(float) * 3;
newMaterial.StartIndex = *(unsigned int*)(fileData + offset);
offset += sizeof(unsigned int);
newMaterial.EndIndex = *(unsigned int*)(fileData + offset);
offset += sizeof(unsigned int);
if (nameLengths[0] > 0) {
if (offset + nameLengths[0] > fileByteSize) {
throw Resource::FailedLoadingException("Reading Material texture path failed");
}
newMaterial.TexturePath = "Textures/";
newMaterial.TexturePath += (fileData + offset);
newMaterial.TexturePath += ".png";
offset += nameLengths[0];
}
if (nameLengths[1] > 0) {
if (offset + nameLengths[1] > fileByteSize) {
throw Resource::FailedLoadingException("Reading Material NormalMap path failed");
}
newMaterial.NormalMapPath = "Textures/";
newMaterial.NormalMapPath += (fileData + offset);
newMaterial.NormalMapPath += ".png";
offset += nameLengths[1];
}
if (nameLengths[2] > 0) {
if (offset + nameLengths[2] > fileByteSize) {
throw Resource::FailedLoadingException("Reading Material SpecularMap path failed");
}
newMaterial.SpecularMapPath = "Textures/";
newMaterial.SpecularMapPath += (fileData + offset);
newMaterial.SpecularMapPath += ".png";
offset += nameLengths[2];
}
if (nameLengths[3] > 0) {
if (offset + nameLengths[3] > fileByteSize) {
throw Resource::FailedLoadingException("Reading Material IncandescenceMap path failed");
}
newMaterial.IncandescenceMapPath = "Textures/";
newMaterial.IncandescenceMapPath += (fileData + offset);
newMaterial.IncandescenceMapPath += ".png";
offset += nameLengths[3];
}
#else
#endif
MaterialGroups.push_back(newMaterial);
}
void RawModelCustom::ReadAnimationFile(std::string filePath)
{
char* fileData;
filePath += ".anim";
std::ifstream in(filePath.c_str(), std::ios_base::binary | std::ios_base::ate);
if (!in.is_open()) {
//throw Resource::FailedLoadingException("Open animation file failed");
return;
}
unsigned int fileByteSize = in.tellg();
in.seekg(0, std::ios_base::beg);
fileData = new char[fileByteSize];
in.read(fileData, fileByteSize);
in.close();
unsigned int offset = 0;
if (fileByteSize > 0) {
m_Skeleton = new Skeleton();
#ifdef BOOST_LITTLE_ENDIAN
unsigned int numBindPoses = *(unsigned int*)(fileData);
offset += sizeof(unsigned int);
unsigned int numAnimations = *(unsigned int*)(fileData + offset);
offset += sizeof(unsigned int);
#else
#endif
ReadAnimationBindPoses(offset, fileData, fileByteSize);
ReadAnimationClips(offset, fileData, fileByteSize, numAnimations);
}
delete fileData;
}
void RawModelCustom::ReadAnimationBindPoses(unsigned int &offset, char* fileData, unsigned int& fileByteSize)
{
#ifdef BOOST_LITTLE_ENDIAN
unsigned int* numBones = (unsigned int*)(fileData + offset);
offset += sizeof(unsigned int);
for (unsigned int i = 0; i < *numBones; i++) {
ReadAnimationJoint(offset, fileData, fileByteSize);
}
#else
#endif
}
void RawModelCustom::ReadAnimationJoint(unsigned int &offset, char* fileData, unsigned int& fileByteSize)
{
#ifdef BOOST_LITTLE_ENDIAN
if (offset + sizeof(unsigned int) > fileByteSize) {
throw Resource::FailedLoadingException("Reading Joint name length failed");
}
unsigned int jointNameLength = *(unsigned int*)(fileData + offset);
offset += sizeof(unsigned int);
if (offset + jointNameLength > fileByteSize) {
throw Resource::FailedLoadingException("Reading Joint name failed");
}
std::string jointName = (fileData + offset);
offset += jointNameLength;
if (offset + sizeof(float) * 4 * 4 > fileByteSize) {
throw Resource::FailedLoadingException("Reading Joint offset matrix failed");
}
glm::mat4 offsetMatrix;
memcpy(&offsetMatrix, fileData + offset, sizeof(float) * 4 * 4);
offset += sizeof(float) * 4 * 4;
if (offset + sizeof(int) > fileByteSize) {
throw Resource::FailedLoadingException("Reading Joint ID failed");
}
int jointID = *(int*)(fileData + offset);
offset += sizeof(int);
if (offset + sizeof(int) > fileByteSize) {
throw Resource::FailedLoadingException("Reading Joint Parent ID failed");
}
int jointParentID = *(int*)(fileData + offset);
offset += sizeof(int);
// Adding joint to the Skeleton
m_Skeleton->CreateBone(jointID, jointParentID, jointName, offsetMatrix);
#else
#endif
}
void RawModelCustom::ReadAnimationClips(unsigned int &offset, char* fileData, unsigned int& fileByteSize, unsigned int numberOfClips)
{
for (unsigned int i = 0; i < numberOfClips; i++) {
ReadAnimationClipSingle(offset, fileData, fileByteSize, i);
}
}
void RawModelCustom::ReadAnimationClipSingle(unsigned int &offset, char* fileData, unsigned int& fileByteSize, unsigned int clipIndex)
{
#ifdef BOOST_LITTLE_ENDIAN
Skeleton::Animation newAnimation;
if (offset + sizeof(unsigned int) > fileByteSize) {
throw Resource::FailedLoadingException("Reading AnimationClip name length failed");
}
unsigned int clipNameLength = *(unsigned int*)(fileData + offset);
offset += sizeof(unsigned int);
if (offset + clipNameLength > fileByteSize) {
throw Resource::FailedLoadingException("Reading AnimationClip name failed");
}
newAnimation.Name = (fileData + offset);
offset += clipNameLength;
if (offset + sizeof(float) > fileByteSize) {
throw Resource::FailedLoadingException("Reading AnimationClip duration failed");
}
newAnimation.Duration = *(float*)(fileData + offset);
offset += sizeof(float);
if (offset + sizeof(unsigned int) > fileByteSize) {
throw Resource::FailedLoadingException("Reading AnimationClip NrOfKeyframes failed");
}
unsigned int nrOfKeyframes = *(unsigned int*)(fileData + offset);
offset += sizeof(unsigned int);
if (offset + sizeof(unsigned int) > fileByteSize) {
throw Resource::FailedLoadingException("Reading AnimationClip NrOfJoints failed");
}
unsigned int nrOfJoints = *(unsigned int*)(fileData + offset);
offset += sizeof(unsigned int);
newAnimation.Keyframes.reserve(nrOfKeyframes);
for (unsigned int i = 0; i < nrOfKeyframes; i++) {
ReadAnimationKeyFrame(offset, fileData, fileByteSize, nrOfJoints, newAnimation);
}
m_Skeleton->Animations[newAnimation.Name] = newAnimation;
#else
#endif
}
void RawModelCustom::ReadAnimationKeyFrame(unsigned int &offset, char* fileData, unsigned int& fileByteSize, unsigned int nrOfJoints, Skeleton::Animation& animation)
{
Skeleton::Animation::Keyframe newKeyFrame;
if (offset + sizeof(int) > fileByteSize) {
throw Resource::FailedLoadingException("Reading AnimationKeyFrame index failed");
}
newKeyFrame.Index = *(int*)(fileData + offset);
offset += sizeof(int);
if (offset + sizeof(float) > fileByteSize) {
throw Resource::FailedLoadingException("Reading AnimationKeyFrame time failed");
}
newKeyFrame.Time = *(float*)(fileData + offset);
offset += sizeof(float);
if (offset + sizeof(Skeleton::Animation::Keyframe::BoneProperty) * nrOfJoints> fileByteSize) {
throw Resource::FailedLoadingException("Reading AnimationKeyFrame joints failed");
}
Skeleton::Animation::Keyframe::BoneProperty newBone;
for (unsigned int i = 0; i < nrOfJoints; i++) {
memcpy(&newBone, (fileData + offset), sizeof(Skeleton::Animation::Keyframe::BoneProperty));
offset += sizeof(Skeleton::Animation::Keyframe::BoneProperty);
newKeyFrame.BoneProperties[newBone.ID] = newBone;
}
animation.Keyframes.push_back(newKeyFrame);
}
RawModelCustom::~RawModelCustom()
{
if (m_Skeleton != nullptr) {
delete m_Skeleton;
}
}
#endif
+45 -10
View File
@@ -4,9 +4,11 @@ RenderSystem::RenderSystem(World* world, EventBroker* eventBroker, const IRender
: System(world, eventBroker)
, m_Renderer(renderer)
, m_RenderFrame(renderFrame)
, m_World(world)
{
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,28 +48,61 @@ 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)) {
if (!entity.HasComponent("HealthHUD") && entity.Name() != "Crosshair" && entity.Name() != "Weapon") { //Should work but needs to be fixed. Should only render the things "childed" to the local player camera
continue;
}
}
if ((entity.Name() == "Weapon" || entity.HasComponent("HealthHUD")) && !entity.IsChildOf(m_LocalPlayer)) {
continue;
}
Model* model;
try {
model = ResourceManager::Load<::Model, true>(resource);
} catch (const Resource::StillLoadingException&) {
//continue;
model = ResourceManager::Load<::Model>("Models/Core/UnitRaptor.obj");
model = ResourceManager::Load<::Model>("Models/Core/UnitRaptor.mesh");
} catch (const std::exception&) {
try {
model = ResourceManager::Load<::Model>("Models/Core/Error.obj");
model = ResourceManager::Load<::Model>("Models/Core/Error.mesh");
} catch (const std::exception&) {
continue;
}
}
float fillPercentage = 0.f;
glm::vec4 fillColor = glm::vec4(0);
if(m_World->HasComponent(modelComponent.EntityID, "Fill")) {
auto fillComponent = m_World->GetComponent(modelComponent.EntityID, "Fill");
fillPercentage = (float)(double)fillComponent["Percentage"];
fillColor = (glm::vec4)fillComponent["Color"];
}
glm::mat4 modelMatrix = Transform::ModelMatrix(modelComponent.EntityID, m_World);
for (auto matGroup : model->MaterialGroups()) {
std::shared_ptr<ModelJob> modelJob = std::shared_ptr<ModelJob>(new ModelJob(model, m_Camera, modelMatrix, matGroup, modelComponent, m_World));
std::shared_ptr<ModelJob> modelJob = std::shared_ptr<ModelJob>(new ModelJob(model, m_Camera, modelMatrix, matGroup, modelComponent, m_World, fillColor, fillPercentage));
jobs.push_back(modelJob);
}
}
}
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");
@@ -140,8 +175,8 @@ void RenderSystem::fillText(std::list<std::shared_ptr<RenderJob>>& jobs, World*
}
glm::mat4 modelMatrix = Transform::ModelMatrix(textComponent.EntityID, world);
std::shared_ptr<TextJob> modelJob = std::shared_ptr<TextJob>(new TextJob(modelMatrix, font, textComponent));
jobs.push_back(modelJob);
std::shared_ptr<TextJob> textJob = std::shared_ptr<TextJob>(new TextJob(modelMatrix, font, textComponent));
jobs.push_back(textJob);
}
}
@@ -155,12 +190,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;
scene.Camera = m_Camera;
+2 -2
View File
@@ -13,9 +13,9 @@ void Renderer::Initialize()
m_TextPass->Initialize();
m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.obj");
/* m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.obj");
m_UnitQuad = ResourceManager::Load<Model>("Models/Core/UnitQuad.obj");
m_UnitSphere = ResourceManager::Load<Model>("Models/Core/UnitSphere.obj");
m_UnitSphere = ResourceManager::Load<Model>("Models/Core/UnitSphere.obj");*/
m_ImGuiRenderPass = new ImGuiRenderPass(this, m_EventBroker);
}
+6 -2
View File
@@ -68,7 +68,7 @@ std::vector<glm::mat4> Skeleton::GetFrameBones(const Animation& animation, doubl
void Skeleton::AccumulateBoneTransforms(bool noRootMotion, const Animation::Keyframe &currentFrame, const Animation::Keyframe &nextFrame, float progress, std::map<int, glm::mat4> &boneMatrices, const Bone* bone, glm::mat4 parentMatrix)
{
glm::mat4 boneMatrix;
glm::mat4 boneMatrix;
if (currentFrame.BoneProperties.find(bone->ID) != currentFrame.BoneProperties.end() || nextFrame.BoneProperties.find(bone->ID) != nextFrame.BoneProperties.end()) {
Animation::Keyframe::BoneProperty currentBoneProperty = currentFrame.BoneProperties.at(bone->ID);
@@ -84,10 +84,13 @@ void Skeleton::AccumulateBoneTransforms(bool noRootMotion, const Animation::Keyf
positionInterp.z = 0;
}
boneMatrix = parentMatrix * (glm::translate(positionInterp) * glm::toMat4(rotationInterp) * glm::scale(scaleInterp));
boneMatrices[bone->ID] = boneMatrix * bone->OffsetMatrix;
} else {
boneMatrix = parentMatrix * bone->Parent->OffsetMatrix; // * glm::inverse(bone->OffsetMatrix);
if (bone->Parent) {
boneMatrix = parentMatrix; // * glm::inverse(bone->OffsetMatrix);
}
boneMatrices[bone->ID] = boneMatrix; // * bone->OffsetMatrix;
}
@@ -95,6 +98,7 @@ void Skeleton::AccumulateBoneTransforms(bool noRootMotion, const Animation::Keyf
std::string name = child->Name;
AccumulateBoneTransforms(noRootMotion, currentFrame, nextFrame, progress, boneMatrices, child, boneMatrix);
}
}
int Skeleton::GetBoneID(std::string name)
+1 -1
View File
@@ -198,7 +198,7 @@ bool SoundSystem::OnPlaySoundOnPosition(const Events::PlaySoundOnPosition & e)
(float&)(double)emitter["RollOffFactor"] = e.RollOffFactor;
(float&)(double)emitter["ReferenceDistance"] = e.ReferenceDistance;
auto model = m_World->AttachComponent(emitterID, "Model");
(std::string&)model["Resource"] = "Models/Core/UnitCube.obj";
(std::string&)model["Resource"] = "Models/Core/UnitCube.mesh"; // 360NoScope UnitCube
source->Type = SoundType::SFX;
m_Sources[emitterID] = source;
playSound(source);