Merge remote-tracking branch 'origin/master' into DefenderShield
# Conflicts: # resources/Schema/Components.xsd
This commit is contained in:
@@ -28,6 +28,21 @@ bool RayVsAABB(const Ray& ray, const AABB& box);
|
|||||||
//Return true if the ray hits the box, also outputs distance from ray origin to intersection point in [outDistance].
|
//Return true if the ray hits the box, also outputs distance from ray origin to intersection point in [outDistance].
|
||||||
bool RayVsAABB(const Ray& ray, const AABB& box, float& outDistance);
|
bool RayVsAABB(const Ray& ray, const AABB& box, float& outDistance);
|
||||||
|
|
||||||
|
//Return true if the ray hits the triangle.
|
||||||
|
bool RayVsTriangle(const Ray& ray,
|
||||||
|
const glm::vec3& v0,
|
||||||
|
const glm::vec3& v1,
|
||||||
|
const glm::vec3& v2,
|
||||||
|
bool trueOnNegativeDistance = false);
|
||||||
|
//Return true if the ray hits the triangle, and the distance is less than outDistance.
|
||||||
|
bool RayVsTriangle(const Ray& ray,
|
||||||
|
const glm::vec3& v0,
|
||||||
|
const glm::vec3& v1,
|
||||||
|
const glm::vec3& v2,
|
||||||
|
float& outDistance,
|
||||||
|
float& outUCoord,
|
||||||
|
float& outVCoord,
|
||||||
|
bool trueOnNegativeDistance = false);
|
||||||
//Return true if the ray hits any of the triangles in the model. Stops checking when a hit is detected.
|
//Return true if the ray hits any of the triangles in the model. Stops checking when a hit is detected.
|
||||||
bool RayVsModel(const Ray& ray,
|
bool RayVsModel(const Ray& ray,
|
||||||
const std::vector<RawModel::Vertex>& modelVertices,
|
const std::vector<RawModel::Vertex>& modelVertices,
|
||||||
@@ -52,6 +67,9 @@ bool AABBvsTriangles(const AABB& box,
|
|||||||
const std::vector<RawModel::Vertex>& modelVertices,
|
const std::vector<RawModel::Vertex>& modelVertices,
|
||||||
const std::vector<unsigned int>& modelIndices,
|
const std::vector<unsigned int>& modelIndices,
|
||||||
const glm::mat4& modelMatrix,
|
const glm::mat4& modelMatrix,
|
||||||
|
glm::vec3& boxVelocity,
|
||||||
|
float verticalStepHeight,
|
||||||
|
bool& isOnGround,
|
||||||
glm::vec3& outResolutionVector);
|
glm::vec3& outResolutionVector);
|
||||||
|
|
||||||
//Return true if the boxes are intersecting.
|
//Return true if the boxes are intersecting.
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ struct ComponentWrapper
|
|||||||
// Specialization for string literals
|
// Specialization for string literals
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
void SetField(std::string name, const char(&value)[N]) { Field<std::string>(name) = std::string(value); }
|
void SetField(std::string name, const char(&value)[N]) { Field<std::string>(name) = std::string(value); }
|
||||||
|
|
||||||
|
void Copy(ComponentWrapper& destination)
|
||||||
|
{
|
||||||
|
memcpy(destination.Data, this->Data, Info.Stride);
|
||||||
|
}
|
||||||
|
|
||||||
struct SubscriptProxy
|
struct SubscriptProxy
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef EPickupSpawned_h__
|
||||||
|
#define EPickupSpawned_h__
|
||||||
|
|
||||||
|
#include "Core/Event.h"
|
||||||
|
#include "Core/EntityWrapper.h"
|
||||||
|
|
||||||
|
namespace Events
|
||||||
|
{
|
||||||
|
|
||||||
|
struct PickupSpawned : Event
|
||||||
|
{
|
||||||
|
EntityWrapper Pickup;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -9,6 +9,7 @@ namespace Events
|
|||||||
|
|
||||||
struct PlayerDamage : Event
|
struct PlayerDamage : Event
|
||||||
{
|
{
|
||||||
|
//NOTE: this struct is missing information on what the damageSource is
|
||||||
EntityWrapper Player;
|
EntityWrapper Player;
|
||||||
double Damage;
|
double Damage;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#define EPlayerDeath_h__
|
#define EPlayerDeath_h__
|
||||||
|
|
||||||
#include "EventBroker.h"
|
#include "EventBroker.h"
|
||||||
#include "../Core/Entity.h"
|
#include "../Core/EntityWrapper.h"
|
||||||
|
|
||||||
namespace Events
|
namespace Events
|
||||||
{
|
{
|
||||||
@@ -10,8 +10,7 @@ namespace Events
|
|||||||
struct PlayerDeath : Event
|
struct PlayerDeath : Event
|
||||||
{
|
{
|
||||||
//KilledBy,KilledByWhat is optional for now. It might be used later in the playerlog-system
|
//KilledBy,KilledByWhat is optional for now. It might be used later in the playerlog-system
|
||||||
EntityID KilledBy;
|
EntityWrapper Player;
|
||||||
EntityID PlayerID;
|
|
||||||
std::string KilledByWhat;
|
std::string KilledByWhat;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,16 +2,16 @@
|
|||||||
#define EPlayerHealthPickup_h__
|
#define EPlayerHealthPickup_h__
|
||||||
|
|
||||||
#include "EventBroker.h"
|
#include "EventBroker.h"
|
||||||
#include "../Core/Entity.h"
|
#include "../Core/EntityWrapper.h"
|
||||||
|
|
||||||
namespace Events
|
namespace Events
|
||||||
{
|
{
|
||||||
|
|
||||||
struct PlayerHealthPickup : Event
|
struct PlayerHealthPickup : Event
|
||||||
{
|
{
|
||||||
double HealthAmount;
|
EntityWrapper Player;
|
||||||
EntityID PlayerHealedID;
|
double HealthAmount;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ public:
|
|||||||
m_ExtraMemory.push_back((char*)malloc(m_Stride));
|
m_ExtraMemory.push_back((char*)malloc(m_Stride));
|
||||||
//We should preferably not enter here to avoid performance issues. Set more numMaxElements in constructor instead.
|
//We should preferably not enter here to avoid performance issues. Set more numMaxElements in constructor instead.
|
||||||
if (!DisableMemoryPool::Value) {
|
if (!DisableMemoryPool::Value) {
|
||||||
LOG_WARNING("Allocated slots exceed Pool size, extra memory allocated dynamically. Pool size: %u, dynamic size: %u.", m_NumSlots, m_ExtraMemory.size());
|
LOG_DEBUG("Allocated slots exceed Pool size, extra memory allocated dynamically. Pool size: %u, dynamic size: %u.", m_NumSlots, m_ExtraMemory.size());
|
||||||
}
|
}
|
||||||
return m_ExtraMemory.back();
|
return m_ExtraMemory.back();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ struct Child
|
|||||||
std::vector<ContainedObject>& m_StaticObjectsRef;
|
std::vector<ContainedObject>& m_StaticObjectsRef;
|
||||||
std::vector<ContainedObject>& m_DynamicObjectsRef;
|
std::vector<ContainedObject>& m_DynamicObjectsRef;
|
||||||
|
|
||||||
bool hasChildren() const;
|
inline bool hasChildren() const { return m_Children[0] != nullptr; }
|
||||||
int childIndexContainingPoint(const glm::vec3& point) const;
|
int childIndexContainingPoint(const glm::vec3& point) const;
|
||||||
std::vector<int> childIndicesContainingBox(const AABB& box) const;
|
std::vector<int> childIndicesContainingBox(const AABB& box) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
class Ray
|
class Ray
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Ray()
|
||||||
|
: m_Origin(glm::vec3(0.f))
|
||||||
|
, m_Direction(glm::vec3(0, 0, 1))
|
||||||
|
{}
|
||||||
Ray(const glm::vec3& origin, const glm::vec3& dir)
|
Ray(const glm::vec3& origin, const glm::vec3& dir)
|
||||||
: m_Origin(origin)
|
: m_Origin(origin)
|
||||||
, m_Direction(glm::normalize(dir))
|
, m_Direction(glm::normalize(dir))
|
||||||
|
|||||||
@@ -200,13 +200,16 @@ static T* ResourceManager::Load(const std::string& resourceName, Resource* paren
|
|||||||
}
|
}
|
||||||
|
|
||||||
//If resource has already been cached and completely loaded.
|
//If resource has already been cached and completely loaded.
|
||||||
it = m_ResourceCache.find(cacheKey);
|
{
|
||||||
if (it != m_ResourceCache.end()) {
|
boost::lock_guard<decltype(m_Mutex)> guard(m_Mutex);
|
||||||
if (it->second != nullptr) {
|
it = m_ResourceCache.find(cacheKey);
|
||||||
return static_cast<T*>(it->second);
|
if (it != m_ResourceCache.end()) {
|
||||||
} else {
|
if (it->second != nullptr) {
|
||||||
//Don't return null on failure, exception instead.
|
return static_cast<T*>(it->second);
|
||||||
throw Resource::FailedLoadingException();
|
} else {
|
||||||
|
//Don't return null on failure, exception instead.
|
||||||
|
throw Resource::FailedLoadingException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ glm::vec3 AbsoluteScale(EntityWrapper entity);
|
|||||||
glm::vec3 AbsoluteScale(World* world, EntityID entity);
|
glm::vec3 AbsoluteScale(World* world, EntityID entity);
|
||||||
glm::mat4 ModelMatrix(EntityWrapper entity);
|
glm::mat4 ModelMatrix(EntityWrapper entity);
|
||||||
glm::mat4 ModelMatrix(EntityID entity, World* world);
|
glm::mat4 ModelMatrix(EntityID entity, World* world);
|
||||||
|
glm::vec3 TransformPoint(const glm::vec3& point, const glm::mat4& matrix);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "../GLM.h"
|
#include "../GLM.h"
|
||||||
#include "../Core/InputController.h"
|
#include "../Core/InputController.h"
|
||||||
#include "../Core/ELockMouse.h"
|
#include "../Core/ELockMouse.h"
|
||||||
|
#include "InputHandler.h"
|
||||||
|
|
||||||
template <typename EventContext>
|
template <typename EventContext>
|
||||||
class FirstPersonInputController : public InputController<EventContext>
|
class FirstPersonInputController : public InputController<EventContext>
|
||||||
@@ -25,6 +26,10 @@ public:
|
|||||||
virtual bool OnCommand(const Events::InputCommand& e) override;
|
virtual bool OnCommand(const Events::InputCommand& e) override;
|
||||||
virtual void Reset();
|
virtual void Reset();
|
||||||
|
|
||||||
|
void AssaultDashCheck(double dt, bool isJumping, double assaultDashCoolDownMaxTimer);
|
||||||
|
virtual bool AssaultDashDoubleTapped() const { return m_AssaultDashDoubleTapped; }
|
||||||
|
virtual bool PlayerIsDashing() const { return m_PlayerIsDashing; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const int m_PlayerID;
|
const int m_PlayerID;
|
||||||
bool m_MouseLocked = false;
|
bool m_MouseLocked = false;
|
||||||
@@ -33,6 +38,22 @@ protected:
|
|||||||
bool m_Jumping = false;
|
bool m_Jumping = false;
|
||||||
bool m_DoubleJumping = false;
|
bool m_DoubleJumping = false;
|
||||||
bool m_Crouching = false;
|
bool m_Crouching = false;
|
||||||
|
//assault dash membervariables - needed to calculate the doubletap- and dashlogic
|
||||||
|
double m_AssaultDashDoubleTapDeltaTime = 0.0;
|
||||||
|
double m_AssaultDashCoolDownTimer = 0.0;
|
||||||
|
//i will let m_AssaultDashDoubleTapSensitivityTimer stay hardcoded, its not really a gamevariable (more an inputvariable),
|
||||||
|
//and its very unlikely that someone wants to change that value
|
||||||
|
const float m_AssaultDashDoubleTapSensitivityTimer = 0.25f;
|
||||||
|
std::string m_AssaultDashTapDirection = "";
|
||||||
|
std::string m_CurrentDirectionVector = "";
|
||||||
|
bool m_AssaultDashDoubleTapped = false;
|
||||||
|
bool m_PlayerIsDashing = false;
|
||||||
|
bool m_ShiftDashing = false;
|
||||||
|
bool m_ValidDoubleTap = false;
|
||||||
|
|
||||||
|
//specialabilitys
|
||||||
|
bool m_MovementKeyDown = false;
|
||||||
|
bool m_SpecialAbilityKeyDown = false;
|
||||||
|
|
||||||
EventRelay<EventContext, Events::LockMouse> m_ELockMouse;
|
EventRelay<EventContext, Events::LockMouse> m_ELockMouse;
|
||||||
bool OnLockMouse(const Events::LockMouse& e);
|
bool OnLockMouse(const Events::LockMouse& e);
|
||||||
@@ -104,6 +125,26 @@ bool FirstPersonInputController<EventContext>::OnCommand(const Events::InputComm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e.Command == "Forward" || e.Command == "Right") {
|
||||||
|
if (e.Value != 0) {
|
||||||
|
m_CurrentDirectionVector = e.Command == "Right" ? (e.Value > 0 ? "Right" : "Left") : (e.Value > 0 ? "Forward" : "Backward");
|
||||||
|
}
|
||||||
|
//if value = 0 then you have just released this key
|
||||||
|
if (e.Value != 0) {
|
||||||
|
m_MovementKeyDown = true;
|
||||||
|
//if you pressed the same key within m_AssaultDashDoubleTapSensitivityTimer then you have doubletapped it
|
||||||
|
if (m_AssaultDashDoubleTapDeltaTime < m_AssaultDashDoubleTapSensitivityTimer && m_AssaultDashTapDirection == m_CurrentDirectionVector) {
|
||||||
|
m_ValidDoubleTap = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//== 0
|
||||||
|
m_MovementKeyDown = false;
|
||||||
|
//you have just released the key, store what key it was and reset the doubletap-sensitivity-timer
|
||||||
|
m_AssaultDashTapDirection = m_CurrentDirectionVector;
|
||||||
|
m_AssaultDashDoubleTapDeltaTime = 0.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (e.Command == "Jump") {
|
if (e.Command == "Jump") {
|
||||||
m_Jumping = e.Value > 0;
|
m_Jumping = e.Value > 0;
|
||||||
}
|
}
|
||||||
@@ -112,6 +153,19 @@ bool FirstPersonInputController<EventContext>::OnCommand(const Events::InputComm
|
|||||||
m_Crouching = e.Value > 0;
|
m_Crouching = e.Value > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e.Command == "SpecialAbility") {
|
||||||
|
if (e.Value > 0) {
|
||||||
|
m_SpecialAbilityKeyDown = true;
|
||||||
|
} else {
|
||||||
|
m_SpecialAbilityKeyDown = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_SpecialAbilityKeyDown && m_MovementKeyDown) {
|
||||||
|
m_ShiftDashing = true;
|
||||||
|
} else {
|
||||||
|
m_ShiftDashing = false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,4 +183,53 @@ bool FirstPersonInputController<EventContext>::OnLockMouse(const Events::LockMou
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename EventContext>
|
||||||
|
void FirstPersonInputController<EventContext>::AssaultDashCheck(double dt, bool isJumping, double assaultDashCoolDownMaxTimer) {
|
||||||
|
m_AssaultDashDoubleTapDeltaTime += dt;
|
||||||
|
m_AssaultDashCoolDownTimer -= dt;
|
||||||
|
//cooldown = assaultDashCoolDownMaxTimer sec, pretend the dash lasts 0.25 sec (for friction to do its work)
|
||||||
|
if (m_AssaultDashCoolDownTimer > (assaultDashCoolDownMaxTimer - 0.25f)) {
|
||||||
|
m_PlayerIsDashing = true;
|
||||||
|
} else {
|
||||||
|
m_PlayerIsDashing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//dashing with shift
|
||||||
|
if (m_ShiftDashing && m_AssaultDashCoolDownTimer <= 0.0f && !isJumping) {
|
||||||
|
//player is dashing with shift
|
||||||
|
//the wanted-direction is set in playermovement already so we dont need to check what direction we want to dash in!
|
||||||
|
m_AssaultDashCoolDownTimer = assaultDashCoolDownMaxTimer;
|
||||||
|
m_AssaultDashDoubleTapped = true;
|
||||||
|
m_AssaultDashDoubleTapDeltaTime = 0.f;
|
||||||
|
//moving to the side has priority
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//dashing with doubletap - check if doubletap to dash enabled
|
||||||
|
if (ResourceManager::Load<ConfigFile>("Input.ini")->Get<bool>("Keyboard.DoubleTapToDash", false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//reset the DoubleTapped state in case we recently doubleTapped (doubletap will only happen during 1 frame)
|
||||||
|
if (m_AssaultDashDoubleTapped) {
|
||||||
|
m_AssaultDashDoubleTapped = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if we have received a valid doubletap
|
||||||
|
if (!m_ValidDoubleTap) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_ValidDoubleTap = false;
|
||||||
|
|
||||||
|
if (!(m_AssaultDashCoolDownTimer <= 0.0f && !isJumping)) {
|
||||||
|
//if we cant dash at the moment, then just reset the tap-sensitivity-timer
|
||||||
|
m_AssaultDashDoubleTapDeltaTime = 0.f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//ok, we have a valid tap, lets do it
|
||||||
|
m_AssaultDashDoubleTapped = true;
|
||||||
|
m_AssaultDashDoubleTapDeltaTime = 0.f;
|
||||||
|
m_AssaultDashCoolDownTimer = assaultDashCoolDownMaxTimer;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -36,7 +36,7 @@ private:
|
|||||||
boost::asio::ip::udp::socket m_Socket;
|
boost::asio::ip::udp::socket m_Socket;
|
||||||
|
|
||||||
// Sending message to server logic
|
// Sending message to server logic
|
||||||
int bytesRead = -1;
|
size_t bytesRead = 0;
|
||||||
char readBuf[INPUTSIZE] = { 0 };
|
char readBuf[INPUTSIZE] = { 0 };
|
||||||
|
|
||||||
// Packet loss logic
|
// Packet loss logic
|
||||||
@@ -69,7 +69,7 @@ private:
|
|||||||
|
|
||||||
// Private member functions
|
// Private member functions
|
||||||
void readFromServer();
|
void readFromServer();
|
||||||
int receive(char* data);
|
size_t receive(char* data);
|
||||||
void send(Packet& packet);
|
void send(Packet& packet);
|
||||||
void connect();
|
void connect();
|
||||||
void disconnect();
|
void disconnect();
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ protected:
|
|||||||
unsigned int m_SaveDataIntervalMs = 1000;
|
unsigned int m_SaveDataIntervalMs = 1000;
|
||||||
std::clock_t m_SaveDataTimer;
|
std::clock_t m_SaveDataTimer;
|
||||||
unsigned int m_MaxConnections;
|
unsigned int m_MaxConnections;
|
||||||
unsigned int m_TimeoutMs;
|
double m_TimeoutMs;
|
||||||
void saveToFile();
|
void saveToFile();
|
||||||
void updateNetworkData();
|
void updateNetworkData();
|
||||||
void initialize();
|
void initialize();
|
||||||
|
|||||||
@@ -3,16 +3,16 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
struct NetworkData {
|
struct NetworkData {
|
||||||
unsigned int TotalTime = 0;
|
double TotalTime = 0;
|
||||||
unsigned int TotalDataReceived = 0;
|
size_t TotalDataReceived = 0;
|
||||||
unsigned int TotalDataSent = 0;
|
size_t TotalDataSent = 0;
|
||||||
unsigned int AmountOfMessagesReceived = 0;
|
size_t AmountOfMessagesReceived = 0;
|
||||||
unsigned int AmountOfMessagesSent = 0;
|
unsigned int AmountOfMessagesSent = 0;
|
||||||
// Interval based
|
// Interval based
|
||||||
unsigned int DataReceivedThisInterval = 0;
|
size_t DataReceivedThisInterval = 0;
|
||||||
unsigned int DataSentThisInterval = 0;
|
size_t DataSentThisInterval = 0;
|
||||||
// pair: first=reveived, second=send
|
// pair: first=reveived, second=send
|
||||||
std::vector<std::pair<unsigned int, unsigned int>> BandwidthBytes;
|
std::vector<std::pair<size_t, size_t>> BandwidthBytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -13,7 +13,7 @@ public:
|
|||||||
// arg2: PacketID for identifying packet loss.
|
// arg2: PacketID for identifying packet loss.
|
||||||
Packet(MessageType type, unsigned int& packetID);
|
Packet(MessageType type, unsigned int& packetID);
|
||||||
// Used to create packet from already existing data buffer.
|
// Used to create packet from already existing data buffer.
|
||||||
Packet(char* data, const int sizeOfPacket);
|
Packet(char* data, const size_t sizeOfPacket);
|
||||||
Packet(MessageType type);
|
Packet(MessageType type);
|
||||||
~Packet();
|
~Packet();
|
||||||
void Init(MessageType type, unsigned int& packetID);
|
void Init(MessageType type, unsigned int& packetID);
|
||||||
@@ -51,18 +51,18 @@ public:
|
|||||||
std::string ReadString();
|
std::string ReadString();
|
||||||
char* ReadData(int SizeOfData);
|
char* ReadData(int SizeOfData);
|
||||||
void ChangePacketID(unsigned int& packetID);
|
void ChangePacketID(unsigned int& packetID);
|
||||||
int Size() { return m_Offset; };
|
size_t Size() { return m_Offset; };
|
||||||
char* Data() { return m_Data; };
|
char* Data() { return m_Data; };
|
||||||
unsigned int DataReadSize() { return m_ReturnDataOffset; }
|
size_t DataReadSize() { return m_ReturnDataOffset; }
|
||||||
unsigned int MaxSize() { return m_MaxPacketSize; }
|
size_t MaxSize() { return m_MaxPacketSize; }
|
||||||
unsigned int HeaderSize() { return m_HeaderSize; }
|
size_t HeaderSize() { return m_HeaderSize; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char* m_Data;
|
char* m_Data;
|
||||||
unsigned int m_ReturnDataOffset = 0;
|
size_t m_ReturnDataOffset = 0;
|
||||||
int m_Offset = 0;
|
size_t m_Offset = 0;
|
||||||
unsigned int m_MaxPacketSize = 512;
|
size_t m_MaxPacketSize = 512;
|
||||||
unsigned int m_HeaderSize = 0;
|
size_t m_HeaderSize = 0;
|
||||||
void resizeData();
|
void resizeData();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -36,14 +36,14 @@ private:
|
|||||||
std::map<PlayerID, PlayerDefinition> m_ConnectedPlayers;
|
std::map<PlayerID, PlayerDefinition> m_ConnectedPlayers;
|
||||||
// HACK: Fix INPUTSIZE
|
// HACK: Fix INPUTSIZE
|
||||||
char readBuffer[INPUTSIZE] = { 0 };
|
char readBuffer[INPUTSIZE] = { 0 };
|
||||||
int bytesRead = 0;
|
size_t bytesRead = 0;
|
||||||
// time for previouse message
|
// time for previouse message
|
||||||
std::clock_t previousePingMessage = std::clock();
|
std::clock_t previousePingMessage = std::clock();
|
||||||
std::clock_t previousSnapshotMessage = std::clock();
|
std::clock_t previousSnapshotMessage = std::clock();
|
||||||
std::clock_t timOutTimer = std::clock();
|
std::clock_t timOutTimer = std::clock();
|
||||||
// How often we send messages (milliseconds)
|
// How often we send messages (milliseconds)
|
||||||
int pingIntervalMs;
|
float pingIntervalMs;
|
||||||
int snapshotInterval;
|
float snapshotInterval;
|
||||||
int checkTimeOutInterval = 100;
|
int checkTimeOutInterval = 100;
|
||||||
int m_NextPlayerID = 0;
|
int m_NextPlayerID = 0;
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ private:
|
|||||||
PacketID m_PreviousPacketID = 0;
|
PacketID m_PreviousPacketID = 0;
|
||||||
|
|
||||||
// Private member functions
|
// Private member functions
|
||||||
int receive(char* data);
|
size_t receive(char* data);
|
||||||
void readFromClients();
|
void readFromClients();
|
||||||
void send(PlayerID player, Packet& packet);
|
void send(PlayerID player, Packet& packet);
|
||||||
void send(Packet& packet);
|
void send(Packet& packet);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
class HealthSystem : public PureSystem
|
class HealthSystem : public PureSystem
|
||||||
{
|
{
|
||||||
@@ -26,7 +27,7 @@ private:
|
|||||||
EventRelay<HealthSystem, Events::PlayerDamage> m_EPlayerDamage;
|
EventRelay<HealthSystem, Events::PlayerDamage> m_EPlayerDamage;
|
||||||
bool HealthSystem::OnPlayerDamaged(Events::PlayerDamage& e);
|
bool HealthSystem::OnPlayerDamaged(Events::PlayerDamage& e);
|
||||||
EventRelay<HealthSystem, Events::PlayerHealthPickup> m_EPlayerHealthPickup;
|
EventRelay<HealthSystem, Events::PlayerHealthPickup> m_EPlayerHealthPickup;
|
||||||
bool HealthSystem::OnPlayerHealthPickup(const Events::PlayerHealthPickup& e);
|
bool HealthSystem::OnPlayerHealthPickup(Events::PlayerHealthPickup& e);
|
||||||
|
|
||||||
//vector which will keep track of health changes
|
//vector which will keep track of health changes
|
||||||
std::vector<std::tuple<EntityID, double>> m_DeltaHealthVector;
|
std::vector<std::tuple<EntityID, double>> m_DeltaHealthVector;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class InterpolationSystem : public PureSystem
|
|||||||
glm::vec3 Position;
|
glm::vec3 Position;
|
||||||
glm::vec3 Scale;
|
glm::vec3 Scale;
|
||||||
glm::quat Orientation;
|
glm::quat Orientation;
|
||||||
double interpolationTime;
|
float interpolationTime;
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
InterpolationSystem(World* world, EventBroker* eventBroker);
|
InterpolationSystem(World* world, EventBroker* eventBroker);
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef PickupSpawnSystem_h__
|
||||||
|
#define PickupSpawnSystem_h__
|
||||||
|
|
||||||
|
#include "Core/System.h"
|
||||||
|
#include "Core/Transform.h"
|
||||||
|
#include "Core/ResourceManager.h"
|
||||||
|
#include "Core/EntityFileParser.h"
|
||||||
|
#include "Core/EPickupSpawned.h"
|
||||||
|
#include "Core/EPlayerHealthPickup.h"
|
||||||
|
#include "Engine/Collision/ETrigger.h"
|
||||||
|
#include "Common.h"
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
class PickupSpawnSystem : public ImpureSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PickupSpawnSystem(World* world, EventBroker* eventBroker);
|
||||||
|
|
||||||
|
virtual void Update(double dt) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
EventRelay<PickupSpawnSystem, Events::TriggerTouch> m_ETriggerTouch;
|
||||||
|
bool OnTriggerTouch(Events::TriggerTouch& e);
|
||||||
|
|
||||||
|
struct NewHealthPickup {
|
||||||
|
glm::vec3 Pos;
|
||||||
|
double HealthGain;
|
||||||
|
double RespawnTimer;
|
||||||
|
double DecreaseThisRespawnTimer;
|
||||||
|
};
|
||||||
|
std::vector<NewHealthPickup> m_ETriggerTouchVector;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#ifndef PlayerDeathSystem_h__
|
||||||
|
#define PlayerDeathSystem_h__
|
||||||
|
|
||||||
|
#include "Core/System.h"
|
||||||
|
#include "Input/EInputCommand.h"
|
||||||
|
#include "GLM.h"
|
||||||
|
#include "Rendering/ESetCamera.h"
|
||||||
|
#include "Core/ConfigFile.h"
|
||||||
|
|
||||||
|
#include "Core/EntityFile.h"
|
||||||
|
#include "Core/EntityFileParser.h"
|
||||||
|
|
||||||
|
#include "Core/EPlayerDeath.h"
|
||||||
|
|
||||||
|
class PlayerDeathSystem : public ImpureSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PlayerDeathSystem(World* world, EventBroker* eventBroker);
|
||||||
|
|
||||||
|
virtual void Update(double dt) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
EventRelay<PlayerDeathSystem, Events::PlayerDeath> m_OnPlayerDeath;
|
||||||
|
bool OnPlayerDeath(Events::PlayerDeath& e);
|
||||||
|
|
||||||
|
void createDeathEffect(EntityWrapper player);
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif
|
||||||
@@ -20,4 +20,5 @@ private:
|
|||||||
|
|
||||||
EventRelay<PlayerMovementSystem, Events::PlayerSpawned> m_EPlayerSpawned;
|
EventRelay<PlayerMovementSystem, Events::PlayerSpawned> m_EPlayerSpawned;
|
||||||
bool OnPlayerSpawned(Events::PlayerSpawned& e);
|
bool OnPlayerSpawned(Events::PlayerSpawned& e);
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "Systems/SpawnerSystem.h"
|
#include "Systems/SpawnerSystem.h"
|
||||||
#include "Events/ESpawnerSpawn.h"
|
#include "Events/ESpawnerSpawn.h"
|
||||||
#include "Core/EPlayerSpawned.h"
|
#include "Core/EPlayerSpawned.h"
|
||||||
|
#include "Core/EPlayerDeath.h"
|
||||||
#include "Rendering/ESetCamera.h"
|
#include "Rendering/ESetCamera.h"
|
||||||
#include "Core/ConfigFile.h"
|
#include "Core/ConfigFile.h"
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ A=Right,-1
|
|||||||
R=Reload
|
R=Reload
|
||||||
Space=Jump
|
Space=Jump
|
||||||
LeftControl=Crouch
|
LeftControl=Crouch
|
||||||
LeftShift=Sprint
|
RightShift=Sprint
|
||||||
|
LeftShift=SpecialAbility
|
||||||
F1=ToggleEditor
|
F1=ToggleEditor
|
||||||
C=ConnectToServer
|
C=ConnectToServer
|
||||||
N=SwitchToServer
|
N=SwitchToServer
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
<xs:include schemaLocation="Components/Fill.xsd"/>
|
<xs:include schemaLocation="Components/Fill.xsd"/>
|
||||||
<xs:include schemaLocation="Components/Lifetime.xsd"/>
|
<xs:include schemaLocation="Components/Lifetime.xsd"/>
|
||||||
<xs:include schemaLocation="Components/HiddenForLocalPlayer.xsd"/>
|
<xs:include schemaLocation="Components/HiddenForLocalPlayer.xsd"/>
|
||||||
|
<xs:include schemaLocation="Components/HealthPickup.xsd"/>
|
||||||
|
<xs:include schemaLocation="Components/DashAbility.xsd"/>
|
||||||
<xs:include schemaLocation="Components/Shield.xsd"/>
|
<xs:include schemaLocation="Components/Shield.xsd"/>
|
||||||
<xs:include schemaLocation="Components/Shielded.xsd"/>
|
<xs:include schemaLocation="Components/Shielded.xsd"/>
|
||||||
</xs:schema>
|
</xs:schema>
|
||||||
@@ -7,10 +7,10 @@
|
|||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:all>
|
<xs:all>
|
||||||
<xs:element name="Origin" type="t:Vector" minOccurs="0">
|
<xs:element name="Origin" type="t:Vector" minOccurs="0">
|
||||||
<xs:annotation><xs:documentation>Middle point of the bounding box</xs:documentation></xs:annotation>
|
<xs:annotation><xs:documentation>Middle point of the bounding box, in model space</xs:documentation></xs:annotation>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
<xs:element name="Size" type="t:Vector" minOccurs="0">
|
<xs:element name="Size" type="t:Vector" minOccurs="0">
|
||||||
<xs:annotation><xs:documentation>Size of the bounding box</xs:documentation></xs:annotation>
|
<xs:annotation><xs:documentation>Size of the bounding box, in model space</xs:documentation></xs:annotation>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
</xs:all>
|
</xs:all>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||||
|
<DashAbility xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="DashAbility.xsd">
|
||||||
|
<CoolDownMaxTimer>2.0</CoolDownMaxTimer>
|
||||||
|
</DashAbility>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="types">
|
||||||
|
<xs:import schemaLocation="../Types.xsd" namespace="types"/>
|
||||||
|
|
||||||
|
<xs:element name="DashAbility">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>A dash component for one of the classes</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:all>
|
||||||
|
<xs:element name="CoolDownMaxTimer" type="t:double" minOccurs="0">
|
||||||
|
<xs:annotation><xs:documentation>This is the cooldown on dash</xs:documentation></xs:annotation>
|
||||||
|
</xs:element>
|
||||||
|
</xs:all>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:schema>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||||
|
<HealthPickup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="HealthPickup.xsd">
|
||||||
|
<RespawnTimer>3</RespawnTimer>
|
||||||
|
<HealthGain>30</HealthGain>
|
||||||
|
</HealthPickup>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="types">
|
||||||
|
<xs:import schemaLocation="../Types.xsd" namespace="types"/>
|
||||||
|
|
||||||
|
<xs:element name="HealthPickup">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>A Health Pickup</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:all>
|
||||||
|
<xs:element name="RespawnTimer" type="t:double" minOccurs="0">
|
||||||
|
<xs:annotation><xs:documentation>The respawn timer for a health pickup</xs:documentation></xs:annotation>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="HealthGain" type="t:double" minOccurs="0">
|
||||||
|
<xs:annotation><xs:documentation>How much percent max-health the player will get when he picks the healthPickup up</xs:documentation></xs:annotation>
|
||||||
|
</xs:element>
|
||||||
|
</xs:all>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:schema>
|
||||||
@@ -2,4 +2,6 @@
|
|||||||
<Physics xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Physics.xsd">
|
<Physics xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Physics.xsd">
|
||||||
<Velocity X="0" Y="0" Z="0"/>
|
<Velocity X="0" Y="0" Z="0"/>
|
||||||
<Gravity>true</Gravity>
|
<Gravity>true</Gravity>
|
||||||
|
<IsOnGround>false</IsOnGround>
|
||||||
|
<VerticalStepHeight>0.33</VerticalStepHeight>
|
||||||
</Physics>
|
</Physics>
|
||||||
|
|||||||
@@ -13,6 +13,10 @@
|
|||||||
<xs:annotation><xs:documentation>m/s^2</xs:documentation></xs:annotation>
|
<xs:annotation><xs:documentation>m/s^2</xs:documentation></xs:annotation>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
<xs:element name="Gravity" type="t:bool" minOccurs="0"/>
|
<xs:element name="Gravity" type="t:bool" minOccurs="0"/>
|
||||||
|
<xs:element name="IsOnGround" type="t:bool" minOccurs="0"/>
|
||||||
|
<xs:element name="VerticalStepHeight" type="t:double" minOccurs="0">
|
||||||
|
<xs:annotation><xs:documentation>The largest height of a "stair-step" that can be walked over</xs:documentation></xs:annotation>
|
||||||
|
</xs:element>
|
||||||
</xs:all>
|
</xs:all>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<c:AABB/>
|
<c:AABB/>
|
||||||
<c:CapturePoint/>
|
<c:CapturePoint/>
|
||||||
<c:Model>
|
<c:Model>
|
||||||
<Resource>C:\Users\123456\Workspace\TacticalZ\assets\Models\Core\UnitSphere.mesh</Resource>
|
<Resource>Models/Core/UnitSphere.mesh</Resource>
|
||||||
</c:Model>
|
</c:Model>
|
||||||
<c:Team/>
|
<c:Team/>
|
||||||
<c:Transform/>
|
<c:Transform/>
|
||||||
|
|||||||
@@ -0,0 +1,164 @@
|
|||||||
|
<?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:Transform/>
|
||||||
|
</Components>
|
||||||
|
|
||||||
|
<Children>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:AABB/>
|
||||||
|
<c:Collidable/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>../assets/Models/Test/ObstacleCourse.mesh</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="0" Z="0.00638055196"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:DirectionalLight>
|
||||||
|
<Intensity>0.46000027656555176</Intensity>
|
||||||
|
</c:DirectionalLight>
|
||||||
|
<c:Transform>
|
||||||
|
<Orientation X="0" Y="2.59000015" Z="0.799000025"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:AABB/>
|
||||||
|
<c:Collidable/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>../assets/Models/Core/UnitCube.mesh</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="-1.52309108" Y="5.72108126" Z="0"/>
|
||||||
|
<Scale X="5" Y="5" Z="5"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity name="BluSpawn">
|
||||||
|
<Components>
|
||||||
|
<c:PlayerSpawn/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitCube.mesh</Resource>
|
||||||
|
<Visible>false</Visible>
|
||||||
|
</c:Model>
|
||||||
|
<c:Spawner>
|
||||||
|
<EntityFile>Schema/Entities/Player.xml</EntityFile>
|
||||||
|
</c:Spawner>
|
||||||
|
<c:Team>
|
||||||
|
<Team>
|
||||||
|
<Blue/>
|
||||||
|
</Team>
|
||||||
|
</c:Team>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="1" Y="1.60000002" Z="1"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:SpawnPoint/>
|
||||||
|
<c:Transform/>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:SpawnPoint/>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="-2.05988312" Y="0" Z="2.79573512"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="1.85022807" Y="0" Z="-2.08909845"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="2.98651481" Y="0" Z="-4.67667246"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="-5.16323137" Y="0" Z="3.62892342"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
</Children>
|
||||||
|
</Entity>
|
||||||
|
<Entity name="RedSpawn">
|
||||||
|
<Components>
|
||||||
|
<c:PlayerSpawn/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitCube.mesh</Resource>
|
||||||
|
<Visible>false</Visible>
|
||||||
|
</c:Model>
|
||||||
|
<c:Spawner>
|
||||||
|
<EntityFile>Schema/Entities/Player.xml</EntityFile>
|
||||||
|
</c:Spawner>
|
||||||
|
<c:Team>
|
||||||
|
<Team>
|
||||||
|
<Red/>
|
||||||
|
</Team>
|
||||||
|
</c:Team>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="-1.20000005" Y="1.60000002" Z="-8.40000057"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:SpawnPoint/>
|
||||||
|
<c:Transform/>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="0" Z="2.24403"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="2.20245028" Y="0" Z="-1.97843659"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="4.79769945" Y="0" Z="-5.2088728"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
</Children>
|
||||||
|
</Entity>
|
||||||
|
</Children>
|
||||||
|
|
||||||
|
</Entity>
|
||||||
@@ -1,122 +1,67 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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">
|
||||||
|
|
||||||
<Entity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xi="http://www.w3.org/2001/XInclude" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd" xmlns:c="components">
|
<Components>
|
||||||
<Components>
|
<c:Transform/>
|
||||||
<c:Transform>
|
</Components>
|
||||||
<Orientation X="0" Y="0" Z="0"/>
|
|
||||||
</c:Transform>
|
<Children>
|
||||||
<c:Model>
|
<Entity>
|
||||||
<Resource>Models/DummyScene.mesh</Resource>
|
<Components>
|
||||||
</c:Model>
|
<c:AABB/>
|
||||||
</Components>
|
<c:Collidable/>
|
||||||
<Children>
|
<c:Model>
|
||||||
<Entity>
|
<Resource>../assets/Models/Test/ObstacleCourse.mesh</Resource>
|
||||||
<Components>
|
</c:Model>
|
||||||
<c:Transform>
|
<c:Transform>
|
||||||
<Position X="-1.5"/>
|
<Position X="0" Y="0" Z="0.00638055196"/>
|
||||||
<Scale X="1" Y="1" Z="1"/>
|
</c:Transform>
|
||||||
</c:Transform>
|
</Components>
|
||||||
<c:Model>
|
<Children/>
|
||||||
<Resource>Models/Core/UnitSphere.mesh</Resource>
|
</Entity>
|
||||||
</c:Model>
|
<Entity>
|
||||||
</Components>
|
<Components>
|
||||||
</Entity>
|
<c:DirectionalLight>
|
||||||
<Entity>
|
<Intensity>0.46000027656555176</Intensity>
|
||||||
<Components>
|
</c:DirectionalLight>
|
||||||
<c:Transform>
|
<c:Transform>
|
||||||
<Position X="1.5"/>
|
<Orientation X="0" Y="2.59000015" Z="0.799000025"/>
|
||||||
<Scale X="2" Y="2" Z="2"/>
|
</c:Transform>
|
||||||
</c:Transform>
|
</Components>
|
||||||
<c:Model>
|
<Children/>
|
||||||
<Resource>Models/RotationWidgetX.mesh</Resource>
|
</Entity>
|
||||||
</c:Model>
|
<Entity>
|
||||||
<c:Trigger>
|
<Components>
|
||||||
</c:Trigger>
|
<c:AABB/>
|
||||||
</Components>
|
<c:Collidable/>
|
||||||
</Entity>
|
<c:Model>
|
||||||
<Entity>
|
<Resource>../assets/Models/Core/UnitCube.mesh</Resource>
|
||||||
<Components>
|
</c:Model>
|
||||||
<c:Player>
|
<c:Physics>
|
||||||
<Velocity X="0" Y="0" Z="0"/>
|
<Gravity>false</Gravity>
|
||||||
</c:Player>
|
</c:Physics>
|
||||||
<c:Transform>
|
<c:Player/>
|
||||||
<Position X="2.5"/>
|
<c:Transform>
|
||||||
</c:Transform>
|
<Position X="-8.80904388" Y="1.82786822" Z="7.97052002"/>
|
||||||
<c:Model>
|
<Scale X="0.100000001" Y="1" Z="0.100000001"/>
|
||||||
<Resource>Models/Core/UnitCube.mesh</Resource>
|
</c:Transform>
|
||||||
</c:Model>
|
</Components>
|
||||||
<c:AABB>
|
<Children/>
|
||||||
</c:AABB>
|
</Entity>
|
||||||
</Components>
|
<Entity>
|
||||||
</Entity>
|
<Components>
|
||||||
<Entity>
|
<c:AABB/>
|
||||||
<Components>
|
<c:Collidable/>
|
||||||
<c:Transform>
|
<c:Model>
|
||||||
<Position X="0" Y="-0"/>
|
<Resource>../assets/Models/Core/colorbox.mesh</Resource>
|
||||||
<Scale X="1" Y="1" Z="1"/>
|
</c:Model>
|
||||||
</c:Transform>
|
<c:Transform>
|
||||||
<!--<c:Move>
|
<Position X="-1.52309108" Y="5.72108126" Z="0"/>
|
||||||
<Speed>1</Speed>
|
<Scale X="5" Y="5" Z="5"/>
|
||||||
<Direction X="-1"/>
|
</c:Transform>
|
||||||
<Rotation Y="3.14"/>
|
</Components>
|
||||||
</c:Move>-->
|
<Children/>
|
||||||
</Components>
|
</Entity>
|
||||||
<Children>
|
</Children>
|
||||||
<Entity>
|
|
||||||
<Components>
|
</Entity>
|
||||||
<c:Transform>
|
|
||||||
<Position X="0" Y="0"/>
|
|
||||||
<Orientation X="0.0" Y="0" Z="1.0"/>
|
|
||||||
</c:Transform>
|
|
||||||
<c:Model>
|
|
||||||
<Resource>Models/Core/UnitRaptor.mesh</Resource>
|
|
||||||
<Color R="1" G="0.4" B="0.8"/>
|
|
||||||
</c:Model>
|
|
||||||
</Components>
|
|
||||||
<Children>
|
|
||||||
<Entity>
|
|
||||||
<Components>
|
|
||||||
<c:Transform>
|
|
||||||
<Position X="-0.01" Y="0.55"/>
|
|
||||||
<Orientation X="0" Y="0" Z="-1"/>
|
|
||||||
</c:Transform>
|
|
||||||
<c:RaptorCopter>
|
|
||||||
<Speed>20</Speed>
|
|
||||||
<Axis Y="1"/>
|
|
||||||
</c:RaptorCopter>
|
|
||||||
</Components>
|
|
||||||
<Children>
|
|
||||||
<Entity>
|
|
||||||
<Components>
|
|
||||||
<c:Transform>
|
|
||||||
<Position X="0" Y="0"/>
|
|
||||||
<Scale X="1.7" Y="0.03" Z="0.1"/>
|
|
||||||
<Orientation X="0" Y="0" Z="0"/>
|
|
||||||
</c:Transform>
|
|
||||||
<c:Model>
|
|
||||||
<Resource>Models/Core/UnitCube.mesh</Resource>
|
|
||||||
<Color R="1" G="0.4" B="0.8"/>
|
|
||||||
</c:Model>
|
|
||||||
</Components>
|
|
||||||
</Entity>
|
|
||||||
<Entity>
|
|
||||||
<Components>
|
|
||||||
<c:Transform>
|
|
||||||
<Position X="0" Y="0"/>
|
|
||||||
<Scale X="1.7" Y="0.03" Z="0.1"/>
|
|
||||||
<Orientation X="0" Y="1.57" Z="0"/>
|
|
||||||
</c:Transform>
|
|
||||||
<c:Model>
|
|
||||||
<Resource>Models/Core/UnitCube.mesh</Resource>
|
|
||||||
<Color R="1" G="0.4" B="0.8"/>
|
|
||||||
</c:Model>
|
|
||||||
</Components>
|
|
||||||
</Entity>
|
|
||||||
</Children>
|
|
||||||
</Entity>
|
|
||||||
</Children>
|
|
||||||
</Entity>
|
|
||||||
</Children>
|
|
||||||
</Entity>
|
|
||||||
</Children>
|
|
||||||
</Entity>
|
|
||||||
|
|||||||
@@ -8,6 +8,10 @@
|
|||||||
<Children>
|
<Children>
|
||||||
<Entity name="Scenemesh">
|
<Entity name="Scenemesh">
|
||||||
<Components>
|
<Components>
|
||||||
|
<c:AABB>
|
||||||
|
<Size X="150" Y="64" Z="180"/>
|
||||||
|
</c:AABB>
|
||||||
|
<c:Collidable/>
|
||||||
<c:Model>
|
<c:Model>
|
||||||
<Resource>Models\MapVersion1.mesh</Resource>
|
<Resource>Models\MapVersion1.mesh</Resource>
|
||||||
</c:Model>
|
</c:Model>
|
||||||
@@ -139,7 +143,7 @@
|
|||||||
</Team>
|
</Team>
|
||||||
</c:Team>
|
</c:Team>
|
||||||
<c:Transform>
|
<c:Transform>
|
||||||
<Position X="57.7363472" Y="1.18853188" Z="79.5"/>
|
<Position X="57.7363472" Y="2.38900018" Z="79.5"/>
|
||||||
</c:Transform>
|
</c:Transform>
|
||||||
</Components>
|
</Components>
|
||||||
<Children>
|
<Children>
|
||||||
@@ -201,7 +205,7 @@
|
|||||||
</Team>
|
</Team>
|
||||||
</c:Team>
|
</c:Team>
|
||||||
<c:Transform>
|
<c:Transform>
|
||||||
<Position X="-60.2567062" Y="1.60000002" Z="-78.1000061"/>
|
<Position X="-60.2567062" Y="3.4000001" Z="-78.1000061"/>
|
||||||
</c:Transform>
|
</c:Transform>
|
||||||
</Components>
|
</Components>
|
||||||
<Children>
|
<Children>
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?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:HealthPickup/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitSphere.mesh</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="1" Z="0"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:Trigger/>
|
||||||
|
</Components>
|
||||||
|
|
||||||
|
<Children/>
|
||||||
|
|
||||||
|
</Entity>
|
||||||
@@ -0,0 +1,294 @@
|
|||||||
|
<?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:Transform/>
|
||||||
|
</Components>
|
||||||
|
|
||||||
|
<Children>
|
||||||
|
<Entity name="Scenemesh">
|
||||||
|
<Components>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models\MapVersion1.mesh</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform/>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity name="DirectionalLight">
|
||||||
|
<Components>
|
||||||
|
<c:DirectionalLight>
|
||||||
|
<Intensity>2</Intensity>
|
||||||
|
</c:DirectionalLight>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/DirectionalLightWidget.mesh</Resource>
|
||||||
|
<Visible>false</Visible>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="61.9050903" Z="0"/>
|
||||||
|
<Scale X="50" Y="50" Z="50"/>
|
||||||
|
<Orientation X="4.42700005" Y="0" Z="0"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity name="PointLight">
|
||||||
|
<Components>
|
||||||
|
<c:PointLight>
|
||||||
|
<Radius>8</Radius>
|
||||||
|
<Intensity>2.7999999523162842</Intensity>
|
||||||
|
</c:PointLight>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0.370978802" Y="1.88588905" Z="-0.55370003"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity name="PointLight">
|
||||||
|
<Components>
|
||||||
|
<c:PointLight>
|
||||||
|
<Radius>8</Radius>
|
||||||
|
<Intensity>2.7999999523162842</Intensity>
|
||||||
|
</c:PointLight>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="38.0347443" Y="1.88588905" Z="62.7340622"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:AABB/>
|
||||||
|
<c:Collidable/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitCube.mesh</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="-0.904668212" Y="0" Z="8.48177528"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:AABB/>
|
||||||
|
<c:Collidable/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitCube.mesh</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="-4.61666441" Y="0" Z="-8.51156044"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:AABB/>
|
||||||
|
<c:Collidable/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitCube.mesh</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="-7.56803513" Y="-0.0658408776" Z="0.59418112"/>
|
||||||
|
<Scale X="1.20000005" Y="0.900000036" Z="1.30000007"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:AABB/>
|
||||||
|
<c:Collidable/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitCube.mesh</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="10.460474" Y="0" Z="-3.92580295"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:AABB/>
|
||||||
|
<c:Collidable/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitCube.mesh</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="1.09146011" Y="-0.315138876" Z="-0.333906144"/>
|
||||||
|
<Scale X="150" Y="1" Z="180"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity name="BluSpawn">
|
||||||
|
<Components>
|
||||||
|
<c:PlayerSpawn/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitCube.mesh</Resource>
|
||||||
|
<Visible>false</Visible>
|
||||||
|
</c:Model>
|
||||||
|
<c:Spawner>
|
||||||
|
<EntityFile>Schema/Entities/Player.xml</EntityFile>
|
||||||
|
</c:Spawner>
|
||||||
|
<c:Team>
|
||||||
|
<Team>
|
||||||
|
<Blue/>
|
||||||
|
</Team>
|
||||||
|
</c:Team>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="57.7363472" Y="1.18853188" Z="79.5"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:SpawnPoint/>
|
||||||
|
<c:Transform/>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:SpawnPoint/>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="-2.05988312" Y="0" Z="2.79573512"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="1.85022807" Y="0" Z="-2.08909845"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="2.98651481" Y="0" Z="-4.67667246"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="-5.16323137" Y="0" Z="3.62892342"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
</Children>
|
||||||
|
</Entity>
|
||||||
|
<Entity name="RedSpawn">
|
||||||
|
<Components>
|
||||||
|
<c:PlayerSpawn/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitCube.mesh</Resource>
|
||||||
|
<Visible>false</Visible>
|
||||||
|
</c:Model>
|
||||||
|
<c:Spawner>
|
||||||
|
<EntityFile>Schema/Entities/Player.xml</EntityFile>
|
||||||
|
</c:Spawner>
|
||||||
|
<c:Team>
|
||||||
|
<Team>
|
||||||
|
<Red/>
|
||||||
|
</Team>
|
||||||
|
</c:Team>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="-60.2567062" Y="1.60000002" Z="-78.1000061"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:SpawnPoint/>
|
||||||
|
<c:Transform/>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="0" Z="2.24403"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="2.20245028" Y="0" Z="-1.97843659"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="4.79769945" Y="0" Z="-5.2088728"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
</Children>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:AABB/>
|
||||||
|
<c:HealthPickup>
|
||||||
|
<RespawnTimer>1</RespawnTimer>
|
||||||
|
<HealthGain>22</HealthGain>
|
||||||
|
</c:HealthPickup>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitSphere.mesh</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="60" Y="1" Z="80"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:Trigger/>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:AABB/>
|
||||||
|
<c:HealthPickup>
|
||||||
|
<RespawnTimer>1</RespawnTimer>
|
||||||
|
<HealthGain>22</HealthGain>
|
||||||
|
</c:HealthPickup>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitSphere.mesh</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="60" Y="1" Z="80"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:Trigger/>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:AABB/>
|
||||||
|
<c:HealthPickup>
|
||||||
|
<RespawnTimer>4</RespawnTimer>
|
||||||
|
<HealthGain>44</HealthGain>
|
||||||
|
</c:HealthPickup>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitSphere.mesh</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="60" Y="1" Z="80"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:Trigger/>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
</Children>
|
||||||
|
|
||||||
|
</Entity>
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?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:Collidable/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>../assets/Models/MapVersion1.mesh</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform/>
|
||||||
|
</Components>
|
||||||
|
|
||||||
|
<Children>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:AABB/>
|
||||||
|
<c:Collidable/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>../assets/Models/Core/UnitCube.mesh</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Physics>
|
||||||
|
<Gravity>false</Gravity>
|
||||||
|
</c:Physics>
|
||||||
|
<c:Player/>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="-1.48400009" Y="3.68200016" Z="24.7580013"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:DirectionalLight/>
|
||||||
|
<c:Transform>
|
||||||
|
<Orientation X="3.80300021" Y="1.37800002" Z="4.10000038"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
</Children>
|
||||||
|
|
||||||
|
</Entity>
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<?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:Transform>
|
||||||
|
<Position X="0" Y="0" Z="-0.313012958"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
|
||||||
|
<Children>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Camera/>
|
||||||
|
<c:Listener/>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="2.56531811" Y="0.637967348" Z="0.202344239"/>
|
||||||
|
<Orientation X="2.68780756" Y="1.36143553" Z="3.14159179"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Collidable/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>../assets/Models/Core/Tri.obj</Resource>
|
||||||
|
<Color A="1" B="1" G="0.392156869" R="0"/>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform>
|
||||||
|
<Scale X="2" Y="2" Z="0.200000003"/>
|
||||||
|
<Orientation X="2.70100021" Y="2.37000012" Z="0.266000003"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>../assets/Models/Core/Tri.obj</Resource>
|
||||||
|
<Color A="1" B="0" G="0" R="1"/>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform>
|
||||||
|
<Orientation X="0" Y="3.14159274" Z="4.71238899"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
</Children>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:AABB/>
|
||||||
|
<c:Collidable/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>../assets/Models/Core/UnitCube.obj</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Physics/>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="-1.95333278" Y="0.296304941" Z="2.56487775"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
</Children>
|
||||||
|
|
||||||
|
</Entity>
|
||||||
@@ -6,22 +6,6 @@
|
|||||||
</Components>
|
</Components>
|
||||||
|
|
||||||
<Children>
|
<Children>
|
||||||
<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="7" Y="-0.727000058" Z="-1.22800004"/>
|
|
||||||
<Scale X="50" Y="1.45100009" Z="50"/>
|
|
||||||
</c:Transform>
|
|
||||||
</Components>
|
|
||||||
<Children/>
|
|
||||||
</Entity>
|
|
||||||
<Entity name="RedSpawn">
|
<Entity name="RedSpawn">
|
||||||
<Components>
|
<Components>
|
||||||
<c:PlayerSpawn/>
|
<c:PlayerSpawn/>
|
||||||
@@ -81,6 +65,10 @@
|
|||||||
</Entity>
|
</Entity>
|
||||||
<Entity name="ObstacleCourse">
|
<Entity name="ObstacleCourse">
|
||||||
<Components>
|
<Components>
|
||||||
|
<c:AABB>
|
||||||
|
<Size X="50" Y="50" Z="50"/>
|
||||||
|
</c:AABB>
|
||||||
|
<c:Collidable/>
|
||||||
<c:Model>
|
<c:Model>
|
||||||
<Resource>Models/Test/ObstacleCourse.mesh</Resource>
|
<Resource>Models/Test/ObstacleCourse.mesh</Resource>
|
||||||
</c:Model>
|
</c:Model>
|
||||||
@@ -88,51 +76,6 @@
|
|||||||
</Components>
|
</Components>
|
||||||
<Children/>
|
<Children/>
|
||||||
</Entity>
|
</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">
|
<Entity name="BlueSpawn">
|
||||||
<Components>
|
<Components>
|
||||||
<c:PlayerSpawn/>
|
<c:PlayerSpawn/>
|
||||||
@@ -197,7 +140,7 @@
|
|||||||
</Team>
|
</Team>
|
||||||
</c:Team>
|
</c:Team>
|
||||||
<c:Transform>
|
<c:Transform>
|
||||||
<Position X="-1.68112314" Y="0.0264999866" Z="3.06287026"/>
|
<Position X="-1.68112314" Y="0.0288829971" Z="3.06287026"/>
|
||||||
<Orientation X="0" Y="2.14675093" Z="0"/>
|
<Orientation X="0" Y="2.14675093" Z="0"/>
|
||||||
</c:Transform>
|
</c:Transform>
|
||||||
</Components>
|
</Components>
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
<Origin X="0" Y="0.772000015" Z="0"/>
|
<Origin X="0" Y="0.772000015" Z="0"/>
|
||||||
<Size X="1" Y="1.60000002" Z="1"/>
|
<Size X="1" Y="1.60000002" Z="1"/>
|
||||||
</c:AABB>
|
</c:AABB>
|
||||||
|
<c:DashAbility>
|
||||||
|
<CoolDownMaxTimer>2.0</CoolDownMaxTimer>
|
||||||
|
</c:DashAbility>
|
||||||
<c:Collidable/>
|
<c:Collidable/>
|
||||||
<c:Health/>
|
<c:Health/>
|
||||||
<c:Physics>
|
<c:Physics>
|
||||||
@@ -101,13 +104,6 @@
|
|||||||
</Entity>
|
</Entity>
|
||||||
<Entity name="Weapon">
|
<Entity name="Weapon">
|
||||||
<Components>
|
<Components>
|
||||||
<c:ExplosionEffect>
|
|
||||||
<ColorByDistance>true</ColorByDistance>
|
|
||||||
<Velocity X="0.800000012" Y="0.0379999988" Z="0"/>
|
|
||||||
<ExplosionDuration>3.7999999523162842</ExplosionDuration>
|
|
||||||
<EndColor A="0" B="23.5294113" G="11.7647057" R="0"/>
|
|
||||||
<Randomness>true</Randomness>
|
|
||||||
</c:ExplosionEffect>
|
|
||||||
<c:Model>
|
<c:Model>
|
||||||
<Resource>Models/AssaultWeaponRed.mesh</Resource>
|
<Resource>Models/AssaultWeaponRed.mesh</Resource>
|
||||||
</c:Model>
|
</c:Model>
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||||
|
<Entity name="Explosion" xmlns:c="components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd">
|
||||||
|
|
||||||
|
<Components>
|
||||||
|
<c:Animation>
|
||||||
|
<Name>Hold Pos</Name>
|
||||||
|
</c:Animation>
|
||||||
|
<c:Lifetime>
|
||||||
|
<Lifetime>2.5</Lifetime>
|
||||||
|
</c:Lifetime>
|
||||||
|
<c:ExplosionEffect>
|
||||||
|
<ColorByDistance>true</ColorByDistance>
|
||||||
|
<Velocity X="0" Y="7.76300049" Z="0"/>
|
||||||
|
<ExplosionOrigin X="0" Y="0.67900002" Z="0"/>
|
||||||
|
<ExponentialAccelaration>true</ExponentialAccelaration>
|
||||||
|
<ExplosionDuration>3</ExplosionDuration>
|
||||||
|
<EndColor A="0" B="0" G="0" R="1"/>
|
||||||
|
<Randomness>true</Randomness>
|
||||||
|
</c:ExplosionEffect>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/AssaultAnimated.mesh</Resource>
|
||||||
|
<Color A="1" B="0" G="0" R="1"/>
|
||||||
|
<Transparent>true</Transparent>
|
||||||
|
</c:Model>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="0" Z="3.46966481"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
|
||||||
|
<Children>
|
||||||
|
<Entity name="Camera">
|
||||||
|
<Components>
|
||||||
|
<c:Camera/>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="2.49700022" Z="4.31700039"/>
|
||||||
|
<Orientation X="5.95600033" Y="0" Z="0"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children/>
|
||||||
|
</Entity>
|
||||||
|
</Children>
|
||||||
|
|
||||||
|
</Entity>
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "Engine/GLM.h"
|
#include "Engine/GLM.h"
|
||||||
#include "Core/World.h"
|
#include "Core/World.h"
|
||||||
#include "Rendering/Model.h"
|
#include "Rendering/Model.h"
|
||||||
|
#include "imgui/imgui.h"
|
||||||
|
|
||||||
namespace Collision
|
namespace Collision
|
||||||
{
|
{
|
||||||
@@ -116,36 +117,79 @@ bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation)
|
|||||||
return glm::all(axisesIntersecting);
|
return glm::all(axisesIntersecting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RayVsTriangle(const Ray& ray,
|
||||||
|
const glm::vec3& v0,
|
||||||
|
const glm::vec3& v1,
|
||||||
|
const glm::vec3& v2,
|
||||||
|
bool trueOnNegativeDistance)
|
||||||
|
{
|
||||||
|
glm::vec3 e1 = v1 - v0; //v1 - v0
|
||||||
|
glm::vec3 e2 = v2 - v0; //v2 - v0
|
||||||
|
glm::vec3 m = ray.Origin() - v0;
|
||||||
|
glm::vec3 MxE1 = glm::cross(m, e1);
|
||||||
|
glm::vec3 DxE2 = glm::cross(ray.Direction(), e2);
|
||||||
|
float DetInv = glm::dot(e1, DxE2);
|
||||||
|
if (std::abs(DetInv) < FLT_EPSILON) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DetInv = 1.0f / DetInv;
|
||||||
|
float u = glm::dot(m, DxE2) * DetInv;
|
||||||
|
float v = glm::dot(ray.Direction(), MxE1) * DetInv;
|
||||||
|
//u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem
|
||||||
|
if ((u + 0.001f) < 0 || (v + 0.001f) < 0 || 1 < u + v) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//Here, u and v are positive, u+v <= 1, and if distance is positive - triangle is hit.
|
||||||
|
return trueOnNegativeDistance || 0 <= glm::dot(e2, MxE1) * DetInv;
|
||||||
|
}
|
||||||
|
|
||||||
bool RayVsModel(const Ray& ray,
|
bool RayVsModel(const Ray& ray,
|
||||||
const std::vector<RawModel::Vertex>& modelVertices,
|
const std::vector<RawModel::Vertex>& modelVertices,
|
||||||
const std::vector<unsigned int>& modelIndices)
|
const std::vector<unsigned int>& modelIndices)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < modelIndices.size(); ++i) {
|
for (int i = 0; i < modelIndices.size(); ++i) {
|
||||||
glm::vec3 v0 = modelVertices[modelIndices[i]].Position;
|
glm::vec3 v0 = modelVertices[modelIndices[i]].Position;
|
||||||
glm::vec3 e1 = modelVertices[modelIndices[++i]].Position - v0; //v1 - v0
|
glm::vec3 v1 = modelVertices[modelIndices[++i]].Position;
|
||||||
glm::vec3 e2 = modelVertices[modelIndices[++i]].Position - v0; //v2 - v0
|
glm::vec3 v2 = modelVertices[modelIndices[++i]].Position;
|
||||||
glm::vec3 m = ray.Origin() - v0;
|
if (RayVsTriangle(ray, v0, v1, v2)) {
|
||||||
glm::vec3 MxE1 = glm::cross(m, e1);
|
|
||||||
glm::vec3 DxE2 = glm::cross(ray.Direction(), e2);
|
|
||||||
float DetInv = glm::dot(e1, DxE2);
|
|
||||||
if (std::abs(DetInv) < FLT_EPSILON) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
DetInv = 1.0f / DetInv;
|
|
||||||
float u = glm::dot(m, DxE2) * DetInv;
|
|
||||||
float v = glm::dot(ray.Direction(), MxE1) * DetInv;
|
|
||||||
//u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem
|
|
||||||
if ((u + 0.001f) < 0 || (v + 0.001f) < 0 || 1 < u + v) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
//Here, u and v are positive, u+v <= 1, and if distance is positive - triangle is hit.
|
|
||||||
if (0 <= glm::dot(e2, MxE1) * DetInv) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RayVsTriangle(const Ray& ray,
|
||||||
|
const glm::vec3& v0,
|
||||||
|
const glm::vec3& v1,
|
||||||
|
const glm::vec3& v2,
|
||||||
|
float& outDistance,
|
||||||
|
float& outUCoord,
|
||||||
|
float& outVCoord,
|
||||||
|
bool trueOnNegativeDistance)
|
||||||
|
{
|
||||||
|
glm::vec3 e1 = v1 - v0; //v1 - v0
|
||||||
|
glm::vec3 e2 = v2 - v0; //v2 - v0
|
||||||
|
glm::vec3 m = ray.Origin() - v0;
|
||||||
|
glm::vec3 MxE1 = glm::cross(m, e1);
|
||||||
|
glm::vec3 DxE2 = glm::cross(ray.Direction(), e2);//pVec
|
||||||
|
float DetInv = glm::dot(e1, DxE2);
|
||||||
|
if (std::abs(DetInv) < FLT_EPSILON) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DetInv = 1.0f / DetInv;
|
||||||
|
float dist = glm::dot(e2, MxE1) * DetInv;
|
||||||
|
if (dist >= outDistance) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
outDistance = dist;
|
||||||
|
outUCoord = glm::dot(m, DxE2) * DetInv;
|
||||||
|
outVCoord = glm::dot(ray.Direction(), MxE1) * DetInv;
|
||||||
|
|
||||||
|
//u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem
|
||||||
|
//If u and v are positive, u+v <= 1, dist is positive, and less than closest.
|
||||||
|
return (0 <= (outUCoord + 0.001f) && 0 <= (outVCoord + 0.001f) && outUCoord + outVCoord <= 1 && (trueOnNegativeDistance || 0 <= dist));
|
||||||
|
}
|
||||||
|
|
||||||
bool RayVsModel(const Ray& ray,
|
bool RayVsModel(const Ray& ray,
|
||||||
const std::vector<RawModel::Vertex>& modelVertices,
|
const std::vector<RawModel::Vertex>& modelVertices,
|
||||||
const std::vector<unsigned int>& modelIndices,
|
const std::vector<unsigned int>& modelIndices,
|
||||||
@@ -157,26 +201,12 @@ bool RayVsModel(const Ray& ray,
|
|||||||
bool hit = false;
|
bool hit = false;
|
||||||
for (int i = 0; i < modelIndices.size(); ++i) {
|
for (int i = 0; i < modelIndices.size(); ++i) {
|
||||||
glm::vec3 v0 = modelVertices[modelIndices[i]].Position;
|
glm::vec3 v0 = modelVertices[modelIndices[i]].Position;
|
||||||
glm::vec3 e1 = modelVertices[modelIndices[++i]].Position - v0; //v1 - v0
|
glm::vec3 v1 = modelVertices[modelIndices[++i]].Position;
|
||||||
glm::vec3 e2 = modelVertices[modelIndices[++i]].Position - v0; //v2 - v0
|
glm::vec3 v2 = modelVertices[modelIndices[++i]].Position;
|
||||||
glm::vec3 m = ray.Origin() - v0;
|
float dist;
|
||||||
glm::vec3 MxE1 = glm::cross(m, e1);
|
float u;
|
||||||
glm::vec3 DxE2 = glm::cross(ray.Direction(), e2);//pVec
|
float v;
|
||||||
float DetInv = glm::dot(e1, DxE2);
|
if (RayVsTriangle(ray, v0, v1, v2, dist, u, v)) {
|
||||||
if (std::abs(DetInv) < FLT_EPSILON) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
DetInv = 1.0f / DetInv;
|
|
||||||
float dist = glm::dot(e2, MxE1) * DetInv;
|
|
||||||
if (dist >= outDistance) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
float u = glm::dot(m, DxE2) * DetInv;
|
|
||||||
float v = glm::dot(ray.Direction(), MxE1) * DetInv;
|
|
||||||
|
|
||||||
//u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem
|
|
||||||
//If u and v are positive, u+v <= 1, dist is positive, and less than closest.
|
|
||||||
if (0 <= (u + 0.001f) && 0 <= (v + 0.001f) && u + v <= 1 && 0 <= dist) {
|
|
||||||
outDistance = dist;
|
outDistance = dist;
|
||||||
outUCoord = u;
|
outUCoord = u;
|
||||||
outVCoord = v;
|
outVCoord = v;
|
||||||
@@ -199,43 +229,338 @@ bool RayVsModel(const Ray& ray,
|
|||||||
return hit;
|
return hit;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AABBvsTriangles(const AABB& box, const std::vector<RawModel::Vertex>& modelVertices, const std::vector<unsigned int>& modelIndices, const glm::mat4& modelMatrix, glm::vec3& outResolutionVector)
|
constexpr inline int signNonZero(float x)
|
||||||
{
|
{
|
||||||
bool hit = false;
|
return x < 0 ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline glm::vec3 signNonZero(const glm::vec3& x)
|
||||||
|
{
|
||||||
|
glm::vec3 r;
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
r[i] = (float)signNonZero(x[i]);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool vectorHasLength(const T& vec)
|
||||||
|
{
|
||||||
|
return glm::any(glm::greaterThan(glm::abs(vec), T(0.0001f)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rectangleVsTriangle(const glm::vec2& boxMin,
|
||||||
|
const glm::vec2& boxMax,
|
||||||
|
const std::array<glm::vec2, 3>& triPos,
|
||||||
|
glm::vec2& resolutionDirection,
|
||||||
|
float& resolutionDistanceSq,
|
||||||
|
bool& pushedFromTriNormal)
|
||||||
|
{
|
||||||
|
pushedFromTriNormal = false;
|
||||||
|
resolutionDistanceSq = INFINITY;
|
||||||
|
//Project along box normals (coordinate axes, since it's axis-aligned).
|
||||||
|
for (int ax = 0; ax < 2; ++ax) {
|
||||||
|
float minTri = INFINITY;
|
||||||
|
float maxTri = -INFINITY;
|
||||||
|
for (const glm::vec2& t : triPos) {
|
||||||
|
minTri = std::min(t[ax], minTri);
|
||||||
|
maxTri = std::max(t[ax], maxTri);
|
||||||
|
}
|
||||||
|
if (boxMax[ax] <= minTri || maxTri <= boxMin[ax]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Here: maxBox > minTri && minBox < maxTri
|
||||||
|
//Left is negative.
|
||||||
|
float leftRes = minTri - boxMax[ax];
|
||||||
|
float rightRes = maxTri - boxMin[ax];
|
||||||
|
float push = rightRes < -leftRes ? rightRes : leftRes;
|
||||||
|
float absPushSq = abs(push);
|
||||||
|
absPushSq *= absPushSq;
|
||||||
|
|
||||||
|
if (absPushSq < resolutionDistanceSq) {
|
||||||
|
resolutionDistanceSq = absPushSq;
|
||||||
|
resolutionDirection[1 - ax] = 0.f;
|
||||||
|
resolutionDirection[ax] = push;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Project along triangle normals.
|
||||||
|
//Put edges into normal vector, make normals in the loop.
|
||||||
|
std::array<glm::vec2, 3> triNormals = {
|
||||||
|
triPos[1] - triPos[0],
|
||||||
|
triPos[2] - triPos[1],
|
||||||
|
triPos[0] - triPos[2]
|
||||||
|
};
|
||||||
|
std::array<glm::vec2, 4> boxPos = {
|
||||||
|
boxMax,
|
||||||
|
glm::vec2(boxMax.x, boxMin.y),
|
||||||
|
glm::vec2(boxMin.x, boxMax.y),
|
||||||
|
boxMin
|
||||||
|
};
|
||||||
|
for (auto& normal : triNormals) {
|
||||||
|
if (!vectorHasLength(normal)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//Rotate edge to a normal.
|
||||||
|
normal = glm::normalize(glm::vec2(-normal.y, normal.x));
|
||||||
|
//Project triangle onto the normal.
|
||||||
|
float minTri = INFINITY;
|
||||||
|
float maxTri = -INFINITY;
|
||||||
|
for (const glm::vec2& point : triPos) {
|
||||||
|
float dot = glm::dot(normal, point);
|
||||||
|
minTri = std::min(dot, minTri);
|
||||||
|
maxTri = std::max(dot, maxTri);
|
||||||
|
}
|
||||||
|
//Project box onto the normal.
|
||||||
|
float minBox = INFINITY;
|
||||||
|
float maxBox = -INFINITY;
|
||||||
|
for (const glm::vec2& point : boxPos) {
|
||||||
|
float dot = glm::dot(normal, point);
|
||||||
|
minBox = std::min(dot, minBox);
|
||||||
|
maxBox = std::max(dot, maxBox);
|
||||||
|
}
|
||||||
|
if (maxBox <= minTri || maxTri <= minBox) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Here: maxBox > minTri && minBox < maxTri
|
||||||
|
//Left is negative.
|
||||||
|
float leftRes = minTri - maxBox;
|
||||||
|
float rightRes = maxTri - minBox;
|
||||||
|
float push = rightRes < -leftRes ? rightRes : leftRes;
|
||||||
|
float absPushSq = abs(push);
|
||||||
|
absPushSq *= absPushSq;
|
||||||
|
|
||||||
|
if (absPushSq < resolutionDistanceSq) {
|
||||||
|
resolutionDistanceSq = absPushSq;
|
||||||
|
resolutionDirection = push * normal;
|
||||||
|
pushedFromTriNormal = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr float SlopeConstant(float degrees)
|
||||||
|
{
|
||||||
|
return (1.0f - degrees / 90.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns true if the angle between horizon and the collision surface is less than 45 degrees.
|
||||||
|
constexpr bool FaceIsGround(float faceNormalY)
|
||||||
|
{
|
||||||
|
//TODO: Perhaps the 45 degrees could be saved in a component or in the config..
|
||||||
|
return faceNormalY > SlopeConstant(45.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//An array containing 3 int pairs { 0, 2 }, { 0, 1 }, { 1, 2 }
|
||||||
|
constexpr std::array<std::pair<int, int>, 3> dimensionPairs({ std::pair<int, int>(0, 2), std::pair<int, int>(0, 1), std::pair<int, int>(1, 2) });
|
||||||
|
|
||||||
|
bool AABBvsTriangle(const AABB& box,
|
||||||
|
const std::array<glm::vec3, 3>& triPos,
|
||||||
|
const glm::vec3& originalBoxVelocity,
|
||||||
|
float verticalStepHeight,
|
||||||
|
bool& isOnGround,
|
||||||
|
glm::vec3& boxVelocity,
|
||||||
|
glm::vec3& outResolution)
|
||||||
|
{
|
||||||
|
//Check so we don't have a zero area triangle when calculating the normal.
|
||||||
|
//Also, don't check a triangle facing away from the player.
|
||||||
|
//Less checks, and we should be able to walk out from models if we are trapped inside.
|
||||||
|
glm::vec3 triNormal = glm::cross(triPos[1] - triPos[0], triPos[2] - triPos[0]);
|
||||||
|
if (!vectorHasLength(triNormal) || (glm::dot(triNormal, originalBoxVelocity) > 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
triNormal = glm::normalize(triNormal);
|
||||||
|
|
||||||
|
enum BoxTriResolveCase
|
||||||
|
{
|
||||||
|
ResolveDimX,
|
||||||
|
ResolveDimY,
|
||||||
|
ResolveDimZ,
|
||||||
|
Line, //Box edge colliding with triangle line.
|
||||||
|
Corner //Box corner colliding with the triangle face.
|
||||||
|
};
|
||||||
|
struct Resolution
|
||||||
|
{
|
||||||
|
Resolution()
|
||||||
|
: DistanceSq(INFINITY)
|
||||||
|
, Vector(0.f)
|
||||||
|
{}
|
||||||
|
BoxTriResolveCase Case;
|
||||||
|
float DistanceSq;
|
||||||
|
glm::vec3 Vector;
|
||||||
|
};
|
||||||
|
//The smallest resolution that solves the collision.
|
||||||
|
Resolution resolveShortest;
|
||||||
|
//The smallest resolution that solves the collision, that resolves upwards.
|
||||||
|
Resolution resolveUpwards;
|
||||||
|
//If player stands on the ground and collides with a ground triangle,
|
||||||
|
//we might step up onto it if the step is small enough.
|
||||||
|
bool canStairStepUp = isOnGround && FaceIsGround(triNormal.y);
|
||||||
|
|
||||||
const glm::vec3& origin = box.Origin();
|
const glm::vec3& origin = box.Origin();
|
||||||
|
const glm::vec3& half = box.HalfSize();
|
||||||
const glm::vec3& min = box.MinCorner();
|
const glm::vec3& min = box.MinCorner();
|
||||||
const glm::vec3& max = box.MaxCorner();
|
const glm::vec3& max = box.MaxCorner();
|
||||||
|
|
||||||
outResolutionVector.x = INFINITY;
|
//For each projection in xy-, xz-, and yx-planes.
|
||||||
|
for (std::pair<int, int> dim : dimensionPairs) {
|
||||||
for (int i = 0; i < modelIndices.size(); ++i) {
|
//2D Triangle.
|
||||||
glm::vec3 p = modelVertices[i].Position;
|
//Project triangle.
|
||||||
p = glm::vec3(modelMatrix * glm::vec4(p.x, p.y, p.z, 1));
|
std::array<glm::vec2, 3> t2D = {
|
||||||
|
glm::vec2(triPos[0][dim.first], triPos[0][dim.second]),
|
||||||
float distFromOrigin = glm::abs(origin.x - p.x);
|
glm::vec2(triPos[1][dim.first], triPos[1][dim.second]),
|
||||||
float penetration = box.HalfSize().x - distFromOrigin;
|
glm::vec2(triPos[2][dim.first], triPos[2][dim.second])
|
||||||
if (penetration > 0 && penetration < glm::abs(outResolutionVector.x)) {
|
};
|
||||||
if (p.x > origin.x) {
|
//Project box.
|
||||||
outResolutionVector.x = -penetration;
|
glm::vec2 boxMin(min[dim.first], min[dim.second]);
|
||||||
} else {
|
glm::vec2 boxMax(max[dim.first], max[dim.second]);
|
||||||
outResolutionVector.x = penetration;
|
glm::vec2 resolutionVector;
|
||||||
|
float resolutionDist;
|
||||||
|
bool pushedFromTriangleLine;
|
||||||
|
//if projections don't overlap, return false.
|
||||||
|
if (!rectangleVsTriangle(boxMin, boxMax, t2D, resolutionVector, resolutionDist, pushedFromTriangleLine)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
//Overwrite the smallest resolution if this is smaller.
|
||||||
|
if (resolutionDist < resolveShortest.DistanceSq) {
|
||||||
|
resolveShortest.Vector = glm::vec3(0.f);
|
||||||
|
resolveShortest.Vector[dim.first] = resolutionVector.x;
|
||||||
|
resolveShortest.Vector[dim.second] = resolutionVector.y;
|
||||||
|
resolveShortest.DistanceSq = resolutionDist;
|
||||||
|
//If we pushed away from triangle line (edge), or if we
|
||||||
|
//move the player along one coordinate axis (pick the dimension that isn't zero).
|
||||||
|
resolveShortest.Case = pushedFromTriangleLine ? Line : static_cast<BoxTriResolveCase>((abs(resolveShortest.Vector[dim.first]) < 0.0001f) ? dim.second : dim.first);
|
||||||
|
}
|
||||||
|
//Overwrite the smallest upward resolution if this is smaller, and resolves upwards.
|
||||||
|
constexpr int yAxis = 1;
|
||||||
|
bool resIsUpwardsIn3D = dim.first == yAxis && resolutionVector.x > 0 || dim.second == yAxis && resolutionVector.y > 0;
|
||||||
|
if (canStairStepUp && resIsUpwardsIn3D && resolutionDist < resolveUpwards.DistanceSq) {
|
||||||
|
resolveUpwards.Vector = glm::vec3(0.f);
|
||||||
|
resolveUpwards.Vector[dim.first] = resolutionVector.x;
|
||||||
|
resolveUpwards.Vector[dim.second] = resolutionVector.y;
|
||||||
|
resolveUpwards.DistanceSq = resolutionDist;
|
||||||
|
//If we pushed away from triangle line (edge), or if we
|
||||||
|
//move the player along one coordinate axis (pick the dimension that isn't zero).
|
||||||
|
resolveUpwards.Case = pushedFromTriangleLine ? Line : static_cast<BoxTriResolveCase>((abs(resolveUpwards.Vector[dim.first]) < 0.0001f) ? dim.second : dim.first);
|
||||||
}
|
}
|
||||||
hit = true;
|
|
||||||
}
|
}
|
||||||
//glm::vec3 pLocal = origin - p;
|
|
||||||
//for (int axis = 0; axis < 3; ++axis) {
|
|
||||||
// if (p[axis] < min[axis] || p[axis] > max[axis]) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (glm::abs(pLocal[axis]) < box.HalfSize()[axis]) {
|
|
||||||
// outResolutionVector[axis] = (glm::sign(pLocal[axis]) * box.HalfSize()[axis]) - pLocal[axis];
|
|
||||||
// hit = true;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//If the triangle does intersect any of the cube diagonals, it will
|
||||||
|
//intersect the cube diagonal that comes
|
||||||
|
//closest to being perpendicular to the plane of the triangle.
|
||||||
|
glm::vec3 diagonal = signNonZero(triNormal) * half;
|
||||||
|
//The triangle plane contains all points P in dot(triNormal, P) == dot(triNormal, v0)
|
||||||
|
//The diagonal line contains all points P in P = origin + diagonal * t.
|
||||||
|
float t = glm::dot(triNormal, triPos[0] - origin) / glm::dot(triNormal, diagonal);
|
||||||
|
//If intersection point between plane and diagonal is within the box.
|
||||||
|
if (glm::abs(t) > 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
glm::vec3 cornerResolution = (1+t) * diagonal;
|
||||||
|
//Overwrite the smallest resolution if cornerResolution is smaller.
|
||||||
|
float lenSq = glm::length2(cornerResolution);
|
||||||
|
if (lenSq < resolveShortest.DistanceSq) {
|
||||||
|
resolveShortest.Vector = cornerResolution;
|
||||||
|
resolveShortest.Case = Corner;
|
||||||
|
}
|
||||||
|
if (canStairStepUp && cornerResolution.y > 0 && lenSq < resolveUpwards.DistanceSq) {
|
||||||
|
resolveUpwards.Vector = cornerResolution;
|
||||||
|
resolveUpwards.Case = Corner;
|
||||||
|
resolveUpwards.DistanceSq = lenSq;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Force the resolution upwards if it is smaller than the threshold verticalStepHeight.
|
||||||
|
//Else take the shortest resolution.
|
||||||
|
bool takeUp = resolveUpwards.Vector.y > 0 && resolveUpwards.Vector.y < verticalStepHeight;
|
||||||
|
Resolution& bestResolve = takeUp ? resolveUpwards : resolveShortest;
|
||||||
|
outResolution = bestResolve.Vector;
|
||||||
|
|
||||||
|
glm::vec3 projNorm;
|
||||||
|
switch (bestResolve.Case) {
|
||||||
|
case ResolveDimY:
|
||||||
|
boxVelocity.y = 0.f;
|
||||||
|
if (outResolution.y > 0)
|
||||||
|
isOnGround = true;
|
||||||
|
case ResolveDimX:
|
||||||
|
case ResolveDimZ:
|
||||||
|
//If we get here, the resolution is along one coordinate axis.
|
||||||
|
//set velocity to 0 in y if it is along y-axis.
|
||||||
|
return true;
|
||||||
|
case Line:
|
||||||
|
projNorm = glm::normalize(outResolution);
|
||||||
|
break;
|
||||||
|
case Corner:
|
||||||
|
projNorm = triNormal;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//If the collision was not on steep wall or similarly (e.g. walking on the ground), force resolution in y only.
|
||||||
|
if (FaceIsGround(projNorm.y)) {
|
||||||
|
//Ensure that the player always is moved upwards, instead of sliding down.
|
||||||
|
float len = glm::length(outResolution);
|
||||||
|
float ang = glm::half_pi<float>() - glm::acos(outResolution.y / len);
|
||||||
|
if (len > 0.0000001f && ang > 0.0000001f) {
|
||||||
|
outResolution.x = 0;
|
||||||
|
outResolution.y = len / glm::sin(ang);
|
||||||
|
outResolution.z = 0;
|
||||||
|
}
|
||||||
|
//Also zero the vertical velocity, if it is positive, else project it onto the normal.
|
||||||
|
//Project the velocity onto the normal of the hit line/face.
|
||||||
|
//w = v - <v,n>*n, |n|==1.
|
||||||
|
boxVelocity.y = std::min(boxVelocity.y - glm::dot(boxVelocity, projNorm) * projNorm.y, 0.f);
|
||||||
|
isOnGround = true;
|
||||||
|
} else {
|
||||||
|
//Enter here if the triangle is a steep slope, and it is not facing downwards.
|
||||||
|
//Project the velocity onto the normal of the hit line/face.
|
||||||
|
//w = v - <v,n>*n, |n|==1.
|
||||||
|
//"ice cream"-effect, air resistance + projected velocity.
|
||||||
|
if (!isOnGround) {
|
||||||
|
boxVelocity = boxVelocity - glm::dot(boxVelocity, projNorm) * projNorm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AABBvsTriangles(const AABB& box,
|
||||||
|
const std::vector<RawModel::Vertex>& modelVertices,
|
||||||
|
const std::vector<unsigned int>& modelIndices,
|
||||||
|
const glm::mat4& modelMatrix,
|
||||||
|
glm::vec3& boxVelocity,
|
||||||
|
float verticalStepHeight,
|
||||||
|
bool& isOnGround,
|
||||||
|
glm::vec3& outResolutionVector)
|
||||||
|
{
|
||||||
|
bool hit = false;
|
||||||
|
|
||||||
|
bool everHitTheGround = false;
|
||||||
|
AABB newBox = box;
|
||||||
|
outResolutionVector = glm::vec3(0.f);
|
||||||
|
glm::vec3 originalBoxVelocity(boxVelocity);
|
||||||
|
for (int i = 0; i < modelIndices.size(); ) {
|
||||||
|
std::array<glm::vec3, 3> triVertices = {
|
||||||
|
Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix),
|
||||||
|
Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix),
|
||||||
|
Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix)
|
||||||
|
};
|
||||||
|
glm::vec3 outVec;
|
||||||
|
bool collideWithGround = isOnGround;
|
||||||
|
if (AABBvsTriangle(newBox, triVertices, originalBoxVelocity, verticalStepHeight, collideWithGround, boxVelocity, outVec)) {
|
||||||
|
hit = true;
|
||||||
|
outResolutionVector += outVec;
|
||||||
|
newBox = AABB::FromOriginSize(newBox.Origin() + outVec, newBox.Size());
|
||||||
|
if (collideWithGround) {
|
||||||
|
everHitTheGround = isOnGround = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!everHitTheGround) {
|
||||||
|
isOnGround = false;
|
||||||
|
}
|
||||||
return hit;
|
return hit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "Collision/Collision.h"
|
#include "Collision/Collision.h"
|
||||||
#include "Collision/CollisionSystem.h"
|
#include "Collision/CollisionSystem.h"
|
||||||
#include "Core/AABB.h"
|
#include "Core/AABB.h"
|
||||||
|
#include "Rendering/Model.h"
|
||||||
|
|
||||||
void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt)
|
void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt)
|
||||||
{
|
{
|
||||||
@@ -25,33 +26,34 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Collision::AABBVsAABB(boxA, boxB, resolutionVector)) {
|
if (boxB.Entity.HasComponent("Model") && Collision::AABBVsAABB(boxA, boxB)) {
|
||||||
|
//Here we know boxB is a entity with Collideable, AABB, and Model.
|
||||||
|
RawModel* model;
|
||||||
|
try {
|
||||||
|
model = ResourceManager::Load<RawModel, true>(boxB.Entity["Model"]["Resource"]);
|
||||||
|
} catch (const std::exception&) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::mat4 modelMatrix = Transform::ModelMatrix(boxB.Entity);
|
||||||
|
|
||||||
|
glm::vec3 inOutVelocity = (glm::vec3)cPhysics["Velocity"];
|
||||||
|
bool isOnGround = (bool)cPhysics["IsOnGround"];
|
||||||
|
float verticalStepHeight = (float)(double)cPhysics["VerticalStepHeight"];
|
||||||
|
if (Collision::AABBvsTriangles(boxA, model->m_Vertices, model->m_Indices, modelMatrix, inOutVelocity, verticalStepHeight, isOnGround, resolutionVector)) {
|
||||||
|
(glm::vec3&)cTransform["Position"] += resolutionVector;
|
||||||
|
cPhysics["Velocity"] = inOutVelocity;
|
||||||
|
(bool)cPhysics["IsOnGround"] = isOnGround;
|
||||||
|
} else {
|
||||||
|
(bool)cPhysics["IsOnGround"] = false;
|
||||||
|
}
|
||||||
|
} else if (Collision::AABBVsAABB(boxA, boxB, resolutionVector)) {
|
||||||
|
//Enter here if boxB has no Model.
|
||||||
(glm::vec3&)cTransform["Position"] += resolutionVector;
|
(glm::vec3&)cTransform["Position"] += resolutionVector;
|
||||||
if (resolutionVector.y > 0) {
|
(bool)cPhysics["IsOnGround"] = resolutionVector.y > 0;
|
||||||
|
if ((bool)cPhysics["IsOnGround"]){
|
||||||
((glm::vec3&)cPhysics["Velocity"]).y = 0.f;
|
((glm::vec3&)cPhysics["Velocity"]).y = 0.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// HACK: Temporarily collide against all collidable models since they're not in the octree yet
|
|
||||||
//auto otherCollidables = world->GetComponents("Model");
|
|
||||||
//for (auto& cModel : *otherCollidables) {
|
|
||||||
// if (cModel.EntityID == entity) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// if (!world->HasComponent(cModel.EntityID, "Collidable")) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// auto absPosition = RenderQueueFactory::AbsolutePosition(world, cModel.EntityID);
|
|
||||||
// auto absOrientation = RenderQueueFactory::AbsoluteOrientation(world, cModel.EntityID);
|
|
||||||
// auto absScale = RenderQueueFactory::AbsoluteScale(world, cModel.EntityID);
|
|
||||||
// glm::mat4 modelMatrix = glm::translate(absPosition); // *glm::toMat4(absOrientation) * glm::scale(absScale);
|
|
||||||
|
|
||||||
// auto model = ResourceManager::Load<Model>(cModel["Resource"]);
|
|
||||||
// glm::vec3 resolutionVector;
|
|
||||||
// if (Collision::AABBvsTriangles(boxA, model->m_Vertices, model->m_Indices, modelMatrix, resolutionVector)) {
|
|
||||||
// (glm::vec3&)cTransform["Position"] += resolutionVector;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -275,9 +275,4 @@ std::vector<int> Child::childIndicesContainingBox(const AABB& box) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Child::hasChildren() const
|
|
||||||
{
|
|
||||||
return m_Children[0] != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -97,3 +97,7 @@ glm::mat4 Transform::ModelMatrix(EntityID entity, World* world)
|
|||||||
return modelMatrix;
|
return modelMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 Transform::TransformPoint(const glm::vec3& point, const glm::mat4& matrix)
|
||||||
|
{
|
||||||
|
return glm::vec3(matrix * glm::vec4(point.x, point.y, point.z, 1));
|
||||||
|
}
|
||||||
@@ -258,11 +258,11 @@ void Client::parseSnapshot(Packet& packet)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Client::receive(char* data)
|
size_t Client::receive(char* data)
|
||||||
{
|
{
|
||||||
boost::system::error_code error;
|
boost::system::error_code error;
|
||||||
|
|
||||||
int bytesReceived = m_Socket.receive_from(boost
|
size_t bytesReceived = m_Socket.receive_from(boost
|
||||||
::asio::buffer((void*)data, INPUTSIZE),
|
::asio::buffer((void*)data, INPUTSIZE),
|
||||||
m_ReceiverEndpoint,
|
m_ReceiverEndpoint,
|
||||||
0, error);
|
0, error);
|
||||||
@@ -390,7 +390,7 @@ void Client::identifyPacketLoss()
|
|||||||
bool Client::hasServerTimedOut()
|
bool Client::hasServerTimedOut()
|
||||||
{
|
{
|
||||||
// Time in ms
|
// Time in ms
|
||||||
float timeSincePing = 1000 * (std::clock() - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
|
double timeSincePing = 1000 * (std::clock() - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
|
||||||
if (timeSincePing > m_TimeoutMs) {
|
if (timeSincePing > m_TimeoutMs) {
|
||||||
// Clear everything and go to menu.
|
// Clear everything and go to menu.
|
||||||
LOG_INFO("Server has timed out, returning to menu, Beep Boop.");
|
LOG_INFO("Server has timed out, returning to menu, Beep Boop.");
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ void Network::saveToFile()
|
|||||||
outfile << "Total messages received," + std::to_string(m_NetworkData.AmountOfMessagesReceived) + "\n";
|
outfile << "Total messages received," + std::to_string(m_NetworkData.AmountOfMessagesReceived) + "\n";
|
||||||
outfile << "Total messages sent," + std::to_string(m_NetworkData.AmountOfMessagesSent) + "\n";
|
outfile << "Total messages sent," + std::to_string(m_NetworkData.AmountOfMessagesSent) + "\n";
|
||||||
|
|
||||||
float messagesReceivedPerSec = (float)m_NetworkData.AmountOfMessagesReceived / (m_NetworkData.TotalTime / 1000);
|
double messagesReceivedPerSec = m_NetworkData.AmountOfMessagesReceived / (m_NetworkData.TotalTime / 1000);
|
||||||
float messagesSentPerSec = (float)m_NetworkData.AmountOfMessagesSent / (m_NetworkData.TotalTime / 1000);
|
double messagesSentPerSec = m_NetworkData.AmountOfMessagesSent / (m_NetworkData.TotalTime / 1000);
|
||||||
float dataReceivedPerSec = (float)m_NetworkData.TotalDataReceived / (m_NetworkData.TotalTime / 1000);
|
double dataReceivedPerSec = m_NetworkData.TotalDataReceived / (m_NetworkData.TotalTime / 1000);
|
||||||
float dataSentPerSec = (float)m_NetworkData.TotalDataSent / (m_NetworkData.TotalTime / 1000);
|
double dataSentPerSec = m_NetworkData.TotalDataSent / (m_NetworkData.TotalTime / 1000);
|
||||||
outfile << "Avarage messages received / s: " + std::to_string(messagesReceivedPerSec) + "\n";
|
outfile << "Avarage messages received / s: " + std::to_string(messagesReceivedPerSec) + "\n";
|
||||||
outfile << "Avarage messages sents / s: " + std::to_string(messagesSentPerSec) + "\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 received B/s: " + std::to_string(dataReceivedPerSec) + "\n";
|
||||||
@@ -52,7 +52,7 @@ void Network::updateNetworkData()
|
|||||||
if (m_SaveDataIntervalMs < (1000 * (currentTime - m_SaveDataTimer) / (double)CLOCKS_PER_SEC)) {
|
if (m_SaveDataIntervalMs < (1000 * (currentTime - m_SaveDataTimer) / (double)CLOCKS_PER_SEC)) {
|
||||||
// Set values
|
// Set values
|
||||||
m_NetworkData.TotalTime += (1000 * (currentTime - m_SaveDataTimer) / (double)CLOCKS_PER_SEC);
|
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));
|
m_NetworkData.BandwidthBytes.push_back(std::pair<size_t, size_t>(m_NetworkData.DataReceivedThisInterval, m_NetworkData.DataSentThisInterval));
|
||||||
// Reset interval stuff
|
// Reset interval stuff
|
||||||
m_SaveDataTimer = std::clock();
|
m_SaveDataTimer = std::clock();
|
||||||
m_NetworkData.DataSentThisInterval = 0;
|
m_NetworkData.DataSentThisInterval = 0;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Packet::Packet(MessageType type, unsigned int& packetID)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create message
|
// Create message
|
||||||
Packet::Packet(char* data, const int sizeOfPacket)
|
Packet::Packet(char* data, const size_t sizeOfPacket)
|
||||||
{
|
{
|
||||||
// Resize message
|
// Resize message
|
||||||
m_MaxPacketSize = sizeOfPacket;
|
m_MaxPacketSize = sizeOfPacket;
|
||||||
@@ -45,7 +45,7 @@ void Packet::Init(MessageType type, unsigned int & packetID)
|
|||||||
void Packet::WriteString(const std::string& str)
|
void Packet::WriteString(const std::string& str)
|
||||||
{
|
{
|
||||||
// Message, add one extra byte for null terminator
|
// Message, add one extra byte for null terminator
|
||||||
int sizeOfString = str.size() + 1;
|
size_t sizeOfString = str.size() + 1;
|
||||||
if (m_Offset + sizeOfString > m_MaxPacketSize) {
|
if (m_Offset + sizeOfString > m_MaxPacketSize) {
|
||||||
//LOG_WARNING("Package::WriteString(): Data size in packet exceeded maximum package size. New size is %i bytes\n", m_MaxPacketSize*2);
|
//LOG_WARNING("Package::WriteString(): Data size in packet exceeded maximum package size. New size is %i bytes\n", m_MaxPacketSize*2);
|
||||||
resizeData();
|
resizeData();
|
||||||
@@ -82,7 +82,7 @@ char * Packet::ReadData(int SizeOfData)
|
|||||||
//LOG_WARNING("packet ReadData(): Oh no! You are trying to remove things outside my memory kingdom");
|
//LOG_WARNING("packet ReadData(): Oh no! You are trying to remove things outside my memory kingdom");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
unsigned int oldReturnDataOffset = m_ReturnDataOffset;
|
size_t oldReturnDataOffset = m_ReturnDataOffset;
|
||||||
m_ReturnDataOffset += SizeOfData;
|
m_ReturnDataOffset += SizeOfData;
|
||||||
return (m_Data + oldReturnDataOffset);
|
return (m_Data + oldReturnDataOffset);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Server::Server() : m_Socket(m_IOService, boost::asio::ip::udp::endpoint(boost::a
|
|||||||
{
|
{
|
||||||
Network::initialize();
|
Network::initialize();
|
||||||
ConfigFile* config = ResourceManager::Load<ConfigFile>("Config.ini");
|
ConfigFile* config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||||
snapshotInterval = 1000 * config->Get<float>("Networking.SnapshotInterval", 0.05);
|
snapshotInterval = 1000 * config->Get<float>("Networking.SnapshotInterval", 0.05f);
|
||||||
pingIntervalMs = config->Get<float>("Networking.PingIntervalMs", 1000);
|
pingIntervalMs = config->Get<float>("Networking.PingIntervalMs", 1000);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ void Server::readFromClients()
|
|||||||
bytesRead = receive(readBuffer);
|
bytesRead = receive(readBuffer);
|
||||||
Packet packet(readBuffer, bytesRead);
|
Packet packet(readBuffer, bytesRead);
|
||||||
parseMessageType(packet);
|
parseMessageType(packet);
|
||||||
} catch (const std::exception& err) {
|
} catch (const std::exception&) {
|
||||||
//LOG_ERROR("%i: Read from client crashed %s", m_PacketID, err.what());
|
//LOG_ERROR("%i: Read from client crashed %s", m_PacketID, err.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,9 +103,9 @@ void Server::parseMessageType(Packet& packet)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Server::receive(char * data)
|
size_t Server::receive(char * data)
|
||||||
{
|
{
|
||||||
unsigned int length = m_Socket.receive_from(
|
size_t length = m_Socket.receive_from(
|
||||||
boost::asio::buffer((void*)data
|
boost::asio::buffer((void*)data
|
||||||
, INPUTSIZE)
|
, INPUTSIZE)
|
||||||
, m_ReceiverEndpoint, 0);
|
, m_ReceiverEndpoint, 0);
|
||||||
@@ -121,7 +121,7 @@ int Server::receive(char * data)
|
|||||||
void Server::send(PlayerID player, Packet& packet)
|
void Server::send(PlayerID player, Packet& packet)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
int bytesSent = m_Socket.send_to(
|
size_t bytesSent = m_Socket.send_to(
|
||||||
boost::asio::buffer(packet.Data(), packet.Size()),
|
boost::asio::buffer(packet.Data(), packet.Size()),
|
||||||
m_ConnectedPlayers[player].Endpoint,
|
m_ConnectedPlayers[player].Endpoint,
|
||||||
0);
|
0);
|
||||||
@@ -131,7 +131,7 @@ void Server::send(PlayerID player, Packet& packet)
|
|||||||
m_NetworkData.DataSentThisInterval += packet.Size();
|
m_NetworkData.DataSentThisInterval += packet.Size();
|
||||||
m_NetworkData.AmountOfMessagesSent++;
|
m_NetworkData.AmountOfMessagesSent++;
|
||||||
}
|
}
|
||||||
} catch (const boost::system::system_error& e) {
|
} catch (const boost::system::system_error&) {
|
||||||
// TODO: Clean up invalid endpoints out of m_ConnectedPlayers later
|
// TODO: Clean up invalid endpoints out of m_ConnectedPlayers later
|
||||||
m_ConnectedPlayers[player].Endpoint = boost::asio::ip::udp::endpoint();
|
m_ConnectedPlayers[player].Endpoint = boost::asio::ip::udp::endpoint();
|
||||||
}
|
}
|
||||||
@@ -231,12 +231,12 @@ void Server::sendPing()
|
|||||||
|
|
||||||
void Server::checkForTimeOuts()
|
void Server::checkForTimeOuts()
|
||||||
{
|
{
|
||||||
int startPing = 1000 * m_StartPingTime
|
double startPing = 1000 * m_StartPingTime
|
||||||
/ static_cast<double>(CLOCKS_PER_SEC);
|
/ static_cast<double>(CLOCKS_PER_SEC);
|
||||||
|
|
||||||
for (int i = 0; i < m_ConnectedPlayers.size(); i++) {
|
for (int i = 0; i < m_ConnectedPlayers.size(); i++) {
|
||||||
if (m_ConnectedPlayers[i].Endpoint.address() != boost::asio::ip::address()) {
|
if (m_ConnectedPlayers[i].Endpoint.address() != boost::asio::ip::address()) {
|
||||||
int stopPing = 1000 * m_ConnectedPlayers[i].StopTime /
|
double stopPing = 1000 * m_ConnectedPlayers[i].StopTime /
|
||||||
static_cast<double>(CLOCKS_PER_SEC);
|
static_cast<double>(CLOCKS_PER_SEC);
|
||||||
if (startPing > stopPing + m_TimeoutMs) {
|
if (startPing > stopPing + m_TimeoutMs) {
|
||||||
LOG_INFO("User %i timed out!", i);
|
LOG_INFO("User %i timed out!", i);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ void DrawColorCorrectionPass::Draw(GLuint sceneTexture, GLuint bloomTexture, GLu
|
|||||||
|
|
||||||
DrawScreenQuadPassState state = DrawScreenQuadPassState();
|
DrawScreenQuadPassState state = DrawScreenQuadPassState();
|
||||||
m_ColorCorrectionProgram->Bind();
|
m_ColorCorrectionProgram->Bind();
|
||||||
//glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
glUniform1f(glGetUniformLocation(m_ColorCorrectionProgram->GetHandle(), "Exposure"), exposure);
|
glUniform1f(glGetUniformLocation(m_ColorCorrectionProgram->GetHandle(), "Exposure"), exposure);
|
||||||
glUniform1f(glGetUniformLocation(m_ColorCorrectionProgram->GetHandle(), "Gamma"), gamma);
|
glUniform1f(glGetUniformLocation(m_ColorCorrectionProgram->GetHandle(), "Gamma"), gamma);
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,10 @@
|
|||||||
#include "Systems/PlayerMovementSystem.h"
|
#include "Systems/PlayerMovementSystem.h"
|
||||||
#include "Systems/SpawnerSystem.h"
|
#include "Systems/SpawnerSystem.h"
|
||||||
#include "Systems/PlayerSpawnSystem.h"
|
#include "Systems/PlayerSpawnSystem.h"
|
||||||
|
#include "Systems/PlayerDeathSystem.h"
|
||||||
#include "Core/EntityFileWriter.h"
|
#include "Core/EntityFileWriter.h"
|
||||||
#include "Game/Systems/CapturePointSystem.h"
|
#include "Game/Systems/CapturePointSystem.h"
|
||||||
|
#include "Game/Systems/PickupSpawnSystem.h"
|
||||||
#include "Game/Systems/WeaponSystem.h"
|
#include "Game/Systems/WeaponSystem.h"
|
||||||
#include "Game/Systems/PlayerHUD.h"
|
#include "Game/Systems/PlayerHUD.h"
|
||||||
#include "Game/Systems/LifetimeSystem.h"
|
#include "Game/Systems/LifetimeSystem.h"
|
||||||
@@ -88,9 +90,11 @@ Game::Game(int argc, char* argv[])
|
|||||||
m_SystemPipeline->AddSystem<InterpolationSystem>(updateOrderLevel);
|
m_SystemPipeline->AddSystem<InterpolationSystem>(updateOrderLevel);
|
||||||
m_SystemPipeline->AddSystem<SpawnerSystem>(updateOrderLevel);
|
m_SystemPipeline->AddSystem<SpawnerSystem>(updateOrderLevel);
|
||||||
m_SystemPipeline->AddSystem<PlayerSpawnSystem>(updateOrderLevel);
|
m_SystemPipeline->AddSystem<PlayerSpawnSystem>(updateOrderLevel);
|
||||||
|
m_SystemPipeline->AddSystem<PlayerDeathSystem>(updateOrderLevel);
|
||||||
m_SystemPipeline->AddSystem<WeaponSystem>(updateOrderLevel, m_Renderer);
|
m_SystemPipeline->AddSystem<WeaponSystem>(updateOrderLevel, m_Renderer);
|
||||||
m_SystemPipeline->AddSystem<LifetimeSystem>(updateOrderLevel);
|
m_SystemPipeline->AddSystem<LifetimeSystem>(updateOrderLevel);
|
||||||
m_SystemPipeline->AddSystem<CapturePointSystem>(updateOrderLevel);
|
m_SystemPipeline->AddSystem<CapturePointSystem>(updateOrderLevel);
|
||||||
|
m_SystemPipeline->AddSystem<PickupSpawnSystem>(updateOrderLevel);
|
||||||
// Populate Octree with collidables
|
// Populate Octree with collidables
|
||||||
++updateOrderLevel;
|
++updateOrderLevel;
|
||||||
m_SystemPipeline->AddSystem<CollidableOctreeSystem>(updateOrderLevel, m_OctreeCollision, "Collidable");
|
m_SystemPipeline->AddSystem<CollidableOctreeSystem>(updateOrderLevel, m_OctreeCollision, "Collidable");
|
||||||
|
|||||||
@@ -11,38 +11,6 @@ HealthSystem::HealthSystem(World* m_World, EventBroker* eventBroker)
|
|||||||
|
|
||||||
void HealthSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt)
|
void HealthSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt)
|
||||||
{
|
{
|
||||||
//if entityID of health is 9 then the players ID is also 9 (player,health are connected to the same entity)
|
|
||||||
double maxHealth = (double)component["MaxHealth"];
|
|
||||||
|
|
||||||
//process the DeltaHealthVector and change the entitys health accordingly
|
|
||||||
for (size_t i = m_DeltaHealthVector.size(); i > 0; i--)
|
|
||||||
{
|
|
||||||
auto deltaHP = m_DeltaHealthVector[i - 1];
|
|
||||||
//if we have a healthchange for the current player and health is greater than 0, then apply it
|
|
||||||
if (std::get<0>(deltaHP) == component.EntityID && (double)component["Health"] > 0.0f) {
|
|
||||||
//get the deltaHP value from the tuple and make sure you dont get more than maxHealth
|
|
||||||
double newHealth = std::min((double)component["Health"] + (double)std::get<1>(deltaHP), maxHealth);
|
|
||||||
component["Health"] = newHealth;
|
|
||||||
m_DeltaHealthVector.erase(m_DeltaHealthVector.begin() + i - 1);
|
|
||||||
//check if health is <= 0
|
|
||||||
if ((double)component["Health"] <= 0.0f) {
|
|
||||||
component["Health"] = 0.0;
|
|
||||||
//publish death event
|
|
||||||
Events::PlayerDeath e;
|
|
||||||
e.PlayerID = component.EntityID;
|
|
||||||
m_EventBroker->Publish(e);
|
|
||||||
//clear the remaining hpDeltas for the dead player
|
|
||||||
for (size_t j = m_DeltaHealthVector.size(); j > 0; j--)
|
|
||||||
{
|
|
||||||
if (std::get<0>(m_DeltaHealthVector[j - 1]) == component.EntityID)
|
|
||||||
m_DeltaHealthVector.erase(m_DeltaHealthVector.begin() + j - 1);
|
|
||||||
}
|
|
||||||
//delete the player and break the loop
|
|
||||||
m_World->DeleteEntity(entity.ID);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HealthSystem::OnPlayerDamaged(Events::PlayerDamage& e)
|
bool HealthSystem::OnPlayerDamaged(Events::PlayerDamage& e)
|
||||||
@@ -50,18 +18,24 @@ bool HealthSystem::OnPlayerDamaged(Events::PlayerDamage& e)
|
|||||||
ComponentWrapper cHealth = e.Player["Health"];
|
ComponentWrapper cHealth = e.Player["Health"];
|
||||||
double& health = cHealth["Health"];
|
double& health = cHealth["Health"];
|
||||||
health -= e.Damage;
|
health -= e.Damage;
|
||||||
|
|
||||||
if (health <= 0.0) {
|
if (health <= 0.0) {
|
||||||
m_World->DeleteEntity(e.Player.ID);
|
Events::PlayerDeath ePlayerDeath;
|
||||||
|
ePlayerDeath.Player = e.Player;
|
||||||
|
m_EventBroker->Publish(ePlayerDeath);
|
||||||
|
//Note: we will delete the entity in PlayerDeathSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HealthSystem::OnPlayerHealthPickup(const Events::PlayerHealthPickup& e)
|
bool HealthSystem::OnPlayerHealthPickup(Events::PlayerHealthPickup& e)
|
||||||
{
|
{
|
||||||
//save the changed HP to a vector. it will be taken care of in UpdateComponent
|
ComponentWrapper cHealth = e.Player["Health"];
|
||||||
m_DeltaHealthVector.push_back(std::make_tuple(e.PlayerHealedID, e.HealthAmount));
|
double& health = cHealth["Health"];
|
||||||
|
health += e.HealthAmount;
|
||||||
|
health = std::min(health, (double)cHealth["MaxHealth"]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ InterpolationSystem::InterpolationSystem(World* world, EventBroker* eventBroker)
|
|||||||
, PureSystem("Transform")
|
, PureSystem("Transform")
|
||||||
{
|
{
|
||||||
ConfigFile* config = ResourceManager::Load<ConfigFile>("Config.ini");
|
ConfigFile* config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||||
m_SnapshotInterval = config->Get<float>("Networking.SnapshotInterval", 0.05);
|
m_SnapshotInterval = config->Get<float>("Networking.SnapshotInterval", 0.05f);
|
||||||
EVENT_SUBSCRIBE_MEMBER(m_EInterpolate, &InterpolationSystem::OnInterpolate);
|
EVENT_SUBSCRIBE_MEMBER(m_EInterpolate, &InterpolationSystem::OnInterpolate);
|
||||||
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &InterpolationSystem::OnPlayerSpawned);
|
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &InterpolationSystem::OnPlayerSpawned);
|
||||||
}
|
}
|
||||||
@@ -18,9 +18,9 @@ void InterpolationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrappe
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_NextTransform.find(transform.EntityID) != m_NextTransform.end()) { // Exists in map
|
if (m_NextTransform.find(transform.EntityID) != m_NextTransform.end()) { // Exists in map
|
||||||
m_NextTransform[transform.EntityID].interpolationTime += dt;
|
m_NextTransform[transform.EntityID].interpolationTime += static_cast<float>(dt);
|
||||||
Transform sTransform = m_NextTransform[transform.EntityID];
|
Transform sTransform = m_NextTransform[transform.EntityID];
|
||||||
double time = sTransform.interpolationTime;
|
float time = sTransform.interpolationTime;
|
||||||
if (time > m_SnapshotInterval) {
|
if (time > m_SnapshotInterval) {
|
||||||
if (m_LastReceivedTransform.find(transform.EntityID) != m_LastReceivedTransform.end()) {
|
if (m_LastReceivedTransform.find(transform.EntityID) != m_LastReceivedTransform.end()) {
|
||||||
m_NextTransform[transform.EntityID] = m_LastReceivedTransform[transform.EntityID];
|
m_NextTransform[transform.EntityID] = m_LastReceivedTransform[transform.EntityID];
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#include "Systems/PickupSpawnSystem.h"
|
||||||
|
|
||||||
|
PickupSpawnSystem::PickupSpawnSystem(World* m_World, EventBroker* eventBroker)
|
||||||
|
: System(m_World, eventBroker)
|
||||||
|
{
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_ETriggerTouch, &PickupSpawnSystem::OnTriggerTouch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PickupSpawnSystem::Update(double dt)
|
||||||
|
{
|
||||||
|
for (auto it = m_ETriggerTouchVector.begin(); it != m_ETriggerTouchVector.end(); ++it)
|
||||||
|
{
|
||||||
|
auto& healthPickupPosition = *it;
|
||||||
|
//set the double timer value (value 3)
|
||||||
|
healthPickupPosition.DecreaseThisRespawnTimer -= dt;
|
||||||
|
if (healthPickupPosition.DecreaseThisRespawnTimer < 0) {
|
||||||
|
//spawn and delete the vector item
|
||||||
|
auto entityFile = ResourceManager::Load<EntityFile>("Schema/Entities/HealthPickup.xml");
|
||||||
|
EntityFileParser parser(entityFile);
|
||||||
|
EntityID healthPickupID = parser.MergeEntities(m_World);
|
||||||
|
|
||||||
|
//let the world know a pickup has spawned (graphics effects, etc)
|
||||||
|
Events::PickupSpawned ePickupSpawned;
|
||||||
|
ePickupSpawned.Pickup = EntityWrapper(m_World, healthPickupID);
|
||||||
|
m_EventBroker->Publish(ePickupSpawned);
|
||||||
|
|
||||||
|
//set values from the old entity to the new entity
|
||||||
|
auto& newHealthPickupEntity = EntityWrapper(m_World, healthPickupID);
|
||||||
|
newHealthPickupEntity["Transform"]["Position"] = healthPickupPosition.Pos;
|
||||||
|
newHealthPickupEntity["HealthPickup"]["HealthGain"] = healthPickupPosition.HealthGain;
|
||||||
|
newHealthPickupEntity["HealthPickup"]["RespawnTimer"] = healthPickupPosition.RespawnTimer;
|
||||||
|
|
||||||
|
//erase the current element (healthPickupPosition)
|
||||||
|
m_ETriggerTouchVector.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PickupSpawnSystem::OnTriggerTouch(Events::TriggerTouch& e)
|
||||||
|
{
|
||||||
|
if (!e.Trigger.HasComponent("HealthPickup")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
double healthGiven = 0.01*(double)e.Trigger["HealthPickup"]["HealthGain"] * (double)e.Entity["Health"]["MaxHealth"];
|
||||||
|
//cant pick up healthpacks if you are already at MaxHealth
|
||||||
|
if ((double)e.Entity["Health"]["Health"] >= (double)e.Entity["Health"]["MaxHealth"]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//personEntered = e.Entity, thingEntered = e.Trigger
|
||||||
|
Events::PlayerHealthPickup ePlayerHealthPickup;
|
||||||
|
ePlayerHealthPickup.HealthAmount = healthGiven;
|
||||||
|
ePlayerHealthPickup.Player = e.Entity;
|
||||||
|
m_EventBroker->Publish(ePlayerHealthPickup);
|
||||||
|
|
||||||
|
//copy position, healthgain, respawntimer (twice since one of the values will be counted down to 0, the other will be set in the new object)
|
||||||
|
//we need to copy all values since each value can be different for each healthPickup
|
||||||
|
m_ETriggerTouchVector.push_back({ (glm::vec3)e.Trigger["Transform"]["Position"] ,e.Trigger["HealthPickup"]["HealthGain"],
|
||||||
|
e.Trigger["HealthPickup"]["RespawnTimer"],e.Trigger["HealthPickup"]["RespawnTimer"] });
|
||||||
|
|
||||||
|
//delete the healthpickup
|
||||||
|
m_World->DeleteEntity(e.Trigger.ID);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#include "Systems/PlayerDeathSystem.h"
|
||||||
|
|
||||||
|
PlayerDeathSystem::PlayerDeathSystem(World* m_World, EventBroker* eventBroker)
|
||||||
|
: System(m_World, eventBroker)
|
||||||
|
{
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_OnPlayerDeath, &PlayerDeathSystem::OnPlayerDeath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerDeathSystem::Update(double dt)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlayerDeathSystem::OnPlayerDeath(Events::PlayerDeath& e)
|
||||||
|
{
|
||||||
|
if (!e.Player.Valid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
createDeathEffect(e.Player);
|
||||||
|
|
||||||
|
// Delete player
|
||||||
|
m_World->DeleteEntity(e.Player.ID);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerDeathSystem::createDeathEffect(EntityWrapper player)
|
||||||
|
{
|
||||||
|
//load the explosioneffect XML
|
||||||
|
auto deathEffect = ResourceManager::Load<EntityFile>("Schema/Entities/PlayerDeathExplosionWithCamera.xml");
|
||||||
|
EntityFileParser parser(deathEffect);
|
||||||
|
EntityID deathEffectID = parser.MergeEntities(m_World);
|
||||||
|
EntityWrapper deathEffectEW = EntityWrapper(m_World, deathEffectID);
|
||||||
|
|
||||||
|
//components that we need from player
|
||||||
|
auto playerCamera = player.FirstChildByName("Camera");
|
||||||
|
auto playerEntityModel = player.FirstChildByName("PlayerModel")["Model"];
|
||||||
|
auto playerEntityAnimation = player.FirstChildByName("PlayerModel")["Animation"];
|
||||||
|
|
||||||
|
//copy the data from player to explisioneffectmodel
|
||||||
|
playerEntityModel.Copy(deathEffectEW["Model"]);
|
||||||
|
playerEntityAnimation.Copy(deathEffectEW["Animation"]);
|
||||||
|
//freeze the animation
|
||||||
|
deathEffectEW["Animation"]["Speed"] = 0.0;
|
||||||
|
|
||||||
|
//copy the models position,orientation
|
||||||
|
deathEffectEW["Transform"]["Position"] = (glm::vec3)player["Transform"]["Position"];
|
||||||
|
deathEffectEW["Transform"]["Orientation"] = (glm::vec3)player["Transform"]["Orientation"];
|
||||||
|
//effect,camera is relative to playersPosition
|
||||||
|
//deathEffectEW["ExplosionEffect"]["ExplosionOrigin"] = glm::vec3(0, 0, 0);
|
||||||
|
|
||||||
|
//camera (with lifetime) behind the player
|
||||||
|
auto cam = deathEffectEW.FirstChildByName("Camera");
|
||||||
|
Events::SetCamera eSetCamera;
|
||||||
|
eSetCamera.CameraEntity = cam;
|
||||||
|
m_EventBroker->Publish(eSetCamera);
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "Systems/PlayerMovementSystem.h"
|
#include "Systems/PlayerMovementSystem.h"
|
||||||
|
|
||||||
PlayerMovementSystem::PlayerMovementSystem(World* world, EventBroker* eventBroker)
|
PlayerMovementSystem::PlayerMovementSystem(World* world, EventBroker* eventBroker)
|
||||||
: System(world, eventBroker)
|
: System(world, eventBroker)
|
||||||
, PureSystem("Player")
|
, PureSystem("Player")
|
||||||
{
|
{
|
||||||
@@ -41,8 +41,15 @@ void PlayerMovementSystem::Update(double dt)
|
|||||||
|
|
||||||
if (player.HasComponent("Physics")) {
|
if (player.HasComponent("Physics")) {
|
||||||
ComponentWrapper cPhysics = player["Physics"];
|
ComponentWrapper cPhysics = player["Physics"];
|
||||||
|
//Assault Dash Check
|
||||||
|
if (player.HasComponent("DashAbility")) {
|
||||||
|
controller->AssaultDashCheck(dt, ((glm::vec3)cPhysics["Velocity"]).y != 0.0f, player["DashAbility"]["CoolDownMaxTimer"]);
|
||||||
|
}
|
||||||
glm::vec3 wishDirection = controller->Movement() * glm::inverse(glm::quat(ori));
|
glm::vec3 wishDirection = controller->Movement() * glm::inverse(glm::quat(ori));
|
||||||
|
//this makes sure you can only dash in the 4 directions: forw,backw,left,right
|
||||||
|
if (controller->AssaultDashDoubleTapped() && controller->Movement().z != 0 && controller->Movement().x != 0) {
|
||||||
|
wishDirection = glm::vec3(controller->Movement().x, 0, 0)* glm::inverse(glm::quat(ori));
|
||||||
|
}
|
||||||
float wishSpeed;
|
float wishSpeed;
|
||||||
if (controller->Crouching()) {
|
if (controller->Crouching()) {
|
||||||
wishSpeed = playerCrouchSpeed;
|
wishSpeed = playerCrouchSpeed;
|
||||||
@@ -50,11 +57,13 @@ void PlayerMovementSystem::Update(double dt)
|
|||||||
wishSpeed = playerMovementSpeed;
|
wishSpeed = playerMovementSpeed;
|
||||||
}
|
}
|
||||||
glm::vec3& velocity = cPhysics["Velocity"];
|
glm::vec3& velocity = cPhysics["Velocity"];
|
||||||
ImGui::Text("velocity: (%f, %f, %f)", velocity.x, velocity.y, velocity.z);
|
bool isOnGround = (bool)cPhysics["IsOnGround"];
|
||||||
|
ImGui::Text(isOnGround ? "On ground" : "In air");
|
||||||
|
ImGui::Text("velocity: (%f, %f, %f) |%f|", velocity.x, velocity.y, velocity.z, glm::length(velocity));
|
||||||
glm::vec3 groundVelocity(0.f, 0.f, 0.f);
|
glm::vec3 groundVelocity(0.f, 0.f, 0.f);
|
||||||
groundVelocity.x = glm::dot(velocity, glm::vec3(1.f, 0.f, 0.f));
|
groundVelocity.x = velocity.x;
|
||||||
groundVelocity.z = glm::dot(velocity, glm::vec3(0.f, 0.f, 1.f));
|
groundVelocity.z = velocity.z;
|
||||||
ImGui::Text("groundVelocity: (%f, %f, %f) |%f|", groundVelocity.x, groundVelocity.y, groundVelocity.z, glm::length(wishDirection));
|
ImGui::Text("groundVelocity: (%f, %f, %f) |%f|", groundVelocity.x, groundVelocity.y, groundVelocity.z, glm::length(groundVelocity));
|
||||||
ImGui::Text("wishDirection: (%f, %f, %f) |%f|", wishDirection.x, wishDirection.y, wishDirection.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 currentSpeedProj = glm::dot(groundVelocity, wishDirection);
|
||||||
float addSpeed = wishSpeed - currentSpeedProj;
|
float addSpeed = wishSpeed - currentSpeedProj;
|
||||||
@@ -67,20 +76,23 @@ void PlayerMovementSystem::Update(double dt)
|
|||||||
ImGui::InputFloat("accel", &accel);
|
ImGui::InputFloat("accel", &accel);
|
||||||
static float airAccel = 0.5f;
|
static float airAccel = 0.5f;
|
||||||
ImGui::InputFloat("airAccel", &airAccel);
|
ImGui::InputFloat("airAccel", &airAccel);
|
||||||
float actualAccel = (velocity.y != 0) ? airAccel : accel;
|
float actualAccel = isOnGround ? accel : airAccel;
|
||||||
static float surfaceFriction = 5.f;
|
static float surfaceFriction = 5.f;
|
||||||
ImGui::InputFloat("surfaceFriction", &surfaceFriction);
|
ImGui::InputFloat("surfaceFriction", &surfaceFriction);
|
||||||
float accelerationSpeed = actualAccel * (float)dt * wishSpeed * surfaceFriction;
|
float accelerationSpeed = actualAccel * (float)dt * wishSpeed * surfaceFriction;
|
||||||
accelerationSpeed = glm::min(accelerationSpeed, addSpeed);
|
//if doubleTapped do Assault Dash - but only boost maximum 50.0f
|
||||||
|
float doubleTapDashBoost = controller->AssaultDashDoubleTapped() ? 40.0f : 1.0f;
|
||||||
|
accelerationSpeed = glm::min(doubleTapDashBoost*glm::min(accelerationSpeed, addSpeed), 50.0f);
|
||||||
velocity += accelerationSpeed * wishDirection;
|
velocity += accelerationSpeed * wishDirection;
|
||||||
ImGui::Text("velocity: (%f, %f, %f) |%f|", velocity.x, velocity.y, velocity.z, glm::length(velocity));
|
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 || !controller->DoubleJumping())) {
|
//you cant jump and dash at the same time - since there is no friction in the air and we would thus dash much further in the air
|
||||||
|
if (!controller->PlayerIsDashing() && controller->Jumping() && !controller->Crouching() && (isOnGround || !controller->DoubleJumping())) {
|
||||||
|
(bool)cPhysics["IsOnGround"] = false;
|
||||||
if (velocity.y == 0.f) {
|
if (velocity.y == 0.f) {
|
||||||
controller->SetDoubleJumping(false);
|
controller->SetDoubleJumping(false);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
controller->SetDoubleJumping(true);
|
controller->SetDoubleJumping(true);
|
||||||
}
|
}
|
||||||
velocity.y += 4.f;
|
velocity.y += 4.f;
|
||||||
@@ -101,6 +113,7 @@ void PlayerMovementSystem::Update(double dt)
|
|||||||
ComponentWrapper cAnimation = playerModel["Animation"];
|
ComponentWrapper cAnimation = playerModel["Animation"];
|
||||||
|
|
||||||
float movementLength = glm::length(groundVelocity);
|
float movementLength = glm::length(groundVelocity);
|
||||||
|
//TODO: add assault dash animation here
|
||||||
if (glm::length(controller->Movement()) > 0.f) {
|
if (glm::length(controller->Movement()) > 0.f) {
|
||||||
if (controller->Crouching()) {
|
if (controller->Crouching()) {
|
||||||
cAnimation["Name"] = "Crouch Walk";
|
cAnimation["Name"] = "Crouch Walk";
|
||||||
@@ -134,6 +147,7 @@ void PlayerMovementSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapp
|
|||||||
|
|
||||||
ComponentWrapper& cPhysics = entity["Physics"];
|
ComponentWrapper& cPhysics = entity["Physics"];
|
||||||
glm::vec3& velocity = cPhysics["Velocity"];
|
glm::vec3& velocity = cPhysics["Velocity"];
|
||||||
|
bool isOnGround = (bool)cPhysics["IsOnGround"];
|
||||||
|
|
||||||
// Ground friction
|
// Ground friction
|
||||||
float speed = glm::length(velocity);
|
float speed = glm::length(velocity);
|
||||||
@@ -141,7 +155,7 @@ void PlayerMovementSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapp
|
|||||||
ImGui::InputFloat("groundFriction", &groundFriction);
|
ImGui::InputFloat("groundFriction", &groundFriction);
|
||||||
static float airFriction = 0.f;
|
static float airFriction = 0.f;
|
||||||
ImGui::InputFloat("airFriction", &airFriction);
|
ImGui::InputFloat("airFriction", &airFriction);
|
||||||
float friction = (velocity.y != 0) ? airFriction : groundFriction;
|
float friction = isOnGround ? groundFriction : airFriction;
|
||||||
if (speed > 0) {
|
if (speed > 0) {
|
||||||
float drop = speed * friction * (float)dt;
|
float drop = speed * friction * (float)dt;
|
||||||
float multiplier = glm::max(speed - drop, 0.f) / speed;
|
float multiplier = glm::max(speed - drop, 0.f) / speed;
|
||||||
|
|||||||
@@ -75,7 +75,9 @@ bool PlayerSpawnSystem::OnPlayerSpawned(Events::PlayerSpawned& e)
|
|||||||
// Check if a player already exists
|
// Check if a player already exists
|
||||||
if (m_PlayerEntities.count(e.PlayerID) != 0) {
|
if (m_PlayerEntities.count(e.PlayerID) != 0) {
|
||||||
// TODO: Disallow infinite respawning here
|
// TODO: Disallow infinite respawning here
|
||||||
m_World->DeleteEntity(m_PlayerEntities[e.PlayerID].ID);
|
if (m_PlayerEntities[e.PlayerID].Valid()) {
|
||||||
|
m_World->DeleteEntity(m_PlayerEntities[e.PlayerID].ID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the player for future reference
|
// Store the player for future reference
|
||||||
|
|||||||
@@ -255,14 +255,14 @@ void CapturePointTest::TestSetup8()
|
|||||||
}
|
}
|
||||||
void CapturePointTest::DoTouchEvent(EntityID whoDidSomething, EntityID onWhatObject) {
|
void CapturePointTest::DoTouchEvent(EntityID whoDidSomething, EntityID onWhatObject) {
|
||||||
Events::TriggerTouch touchEvent;
|
Events::TriggerTouch touchEvent;
|
||||||
touchEvent.Entity = whoDidSomething;
|
touchEvent.Entity = EntityWrapper(m_World, whoDidSomething);
|
||||||
touchEvent.Trigger = onWhatObject;
|
touchEvent.Trigger = EntityWrapper(m_World, onWhatObject);
|
||||||
m_EventBroker->Publish(touchEvent);
|
m_EventBroker->Publish(touchEvent);
|
||||||
}
|
}
|
||||||
void CapturePointTest::DoLeaveEvent(EntityID whoDidSomething, EntityID onWhatObject) {
|
void CapturePointTest::DoLeaveEvent(EntityID whoDidSomething, EntityID onWhatObject) {
|
||||||
Events::TriggerLeave leaveEvent;
|
Events::TriggerLeave leaveEvent;
|
||||||
leaveEvent.Entity = whoDidSomething;
|
leaveEvent.Entity = EntityWrapper(m_World, whoDidSomething);
|
||||||
leaveEvent.Trigger = onWhatObject;
|
leaveEvent.Trigger = EntityWrapper(m_World, onWhatObject);
|
||||||
m_EventBroker->Publish(leaveEvent);
|
m_EventBroker->Publish(leaveEvent);
|
||||||
}
|
}
|
||||||
void CapturePointTest::TestSuccess1() {
|
void CapturePointTest::TestSuccess1() {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ void RayTest(std::string fileName) {
|
|||||||
Ray ray(glm::vec3(-50, 0, 0), glm::vec3(1, 0, 0));
|
Ray ray(glm::vec3(-50, 0, 0), glm::vec3(1, 0, 0));
|
||||||
//using a
|
//using a
|
||||||
|
|
||||||
here, else we have to init the renderingsystem
|
//here, else we have to init the renderingsystem
|
||||||
ResourceManager::RegisterType<RawModel>("RawModel");
|
ResourceManager::RegisterType<RawModel>("RawModel");
|
||||||
auto unitBox = ResourceManager::Load<RawModel>(fileName);
|
auto unitBox = ResourceManager::Load<RawModel>(fileName);
|
||||||
BOOST_REQUIRE(unitBox != nullptr);
|
BOOST_REQUIRE(unitBox != nullptr);
|
||||||
|
|||||||
@@ -48,42 +48,38 @@ GameHealthSystemTest::GameHealthSystemTest()
|
|||||||
fp.MergeEntities(m_World);
|
fp.MergeEntities(m_World);
|
||||||
|
|
||||||
// Create system pipeline
|
// Create system pipeline
|
||||||
m_SystemPipeline = new SystemPipeline(m_World,m_EventBroker);
|
m_SystemPipeline = new SystemPipeline(m_World, m_EventBroker);
|
||||||
m_SystemPipeline->AddSystem<HealthSystem>(0);
|
m_SystemPipeline->AddSystem<HealthSystem>(0);
|
||||||
|
|
||||||
//The Test
|
//The Test
|
||||||
//create entity which has transform,player,model,health in it. i.e. is a player
|
//create entity which has transform,player,model,health in it. i.e. is a player
|
||||||
EntityID playerID = m_World->CreateEntity();
|
EntityID playerID = m_World->CreateEntity();
|
||||||
ComponentWrapper transform = m_World->AttachComponent(playerID, "Transform");
|
|
||||||
ComponentWrapper model = m_World->AttachComponent(playerID, "Model");
|
|
||||||
model["Resource"] = "Models/Core/UnitSphere.mesh"; // 360NoScope UnitSphere
|
|
||||||
ComponentWrapper player = m_World->AttachComponent(playerID, "Player");
|
ComponentWrapper player = m_World->AttachComponent(playerID, "Player");
|
||||||
ComponentWrapper health = m_World->AttachComponent(playerID, "Health");
|
ComponentWrapper health = m_World->AttachComponent(playerID, "Health");
|
||||||
healthsID = playerID;
|
healthsID = playerID;
|
||||||
double currentHealth = (double)m_World->GetComponent(healthsID, "Health")["Health"];
|
|
||||||
|
EntityID playerID2 = m_World->CreateEntity();
|
||||||
|
ComponentWrapper player2 = m_World->AttachComponent(playerID2, "Player");
|
||||||
|
ComponentWrapper health2 = m_World->AttachComponent(playerID2, "Health");
|
||||||
|
|
||||||
//heal player with 40
|
//heal player with 40
|
||||||
Events::PlayerHealthPickup e3;
|
Events::PlayerHealthPickup e3;
|
||||||
e3.HealthAmount = 40.0f;
|
e3.HealthAmount = 40.0f;
|
||||||
e3.PlayerHealedID = healthsID;
|
e3.Player = EntityWrapper(m_World, player.EntityID);
|
||||||
m_EventBroker->Publish(e3);
|
m_EventBroker->Publish(e3);
|
||||||
|
|
||||||
//damage player with 50
|
//damage player with 50
|
||||||
Events::PlayerDamage e;
|
Events::PlayerDamage e;
|
||||||
e.DamageAmount = 50.0f;
|
e.Damage = 50.0f;
|
||||||
e.PlayerDamagedID = healthsID;
|
e.Player = EntityWrapper(m_World, player.EntityID);
|
||||||
m_EventBroker->Publish(e);
|
m_EventBroker->Publish(e);
|
||||||
|
|
||||||
//heal some other player with 40
|
//heal some other player with 40
|
||||||
Events::PlayerHealthPickup e2;
|
Events::PlayerHealthPickup e2;
|
||||||
e2.HealthAmount = 40.0f;
|
e2.HealthAmount = 40.0f;
|
||||||
e2.PlayerHealedID = healthsID + 1;
|
e2.Player = EntityWrapper(m_World, player2.EntityID);
|
||||||
m_EventBroker->Publish(e2);
|
m_EventBroker->Publish(e2);
|
||||||
|
|
||||||
EntityID playerID2 = m_World->CreateEntity();
|
|
||||||
ComponentWrapper transform2 = m_World->AttachComponent(playerID2, "Transform");
|
|
||||||
ComponentWrapper model2 = m_World->AttachComponent(playerID2, "Model");
|
|
||||||
model2["Resource"] = "Models/Core/UnitSphere.mesh"; // 360NoScope UnitSphere
|
|
||||||
ComponentWrapper player2 = m_World->AttachComponent(playerID2, "Player");
|
|
||||||
ComponentWrapper health2 = m_World->AttachComponent(playerID2, "Health");
|
|
||||||
//END TEST
|
//END TEST
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user