60 Commits

Author SHA1 Message Date
=
ae3eb3276f fix change camera height
All checks were successful
Linux arm64 / Build (push) Successful in 5m20s
2024-04-15 18:50:20 +02:00
=
615f68b48b dampen player movements mid-air
All checks were successful
Linux arm64 / Build (push) Successful in 5m4s
2024-04-15 16:56:55 +02:00
=
c7547ffab5 document smoother class, minor nitpicks 2024-04-15 16:42:34 +02:00
Morph01
14610c1f94 map with separate objets
Some checks failed
Linux arm64 / Build (push) Failing after 3m17s
2024-04-14 23:47:24 +02:00
68dfc73ad2 better map
Some checks failed
Linux arm64 / Build (push) Failing after 3m30s
2024-04-14 23:13:59 +02:00
98625523ca use fabs
Some checks failed
Linux arm64 / Build (push) Failing after 3m33s
2024-04-14 23:08:16 +02:00
ee84b290a6 transform aabbs
Some checks failed
Linux arm64 / Build (push) Failing after 3m6s
2024-04-14 23:00:34 +02:00
=
6116ff3e59 oe
Some checks failed
Linux arm64 / Build (push) Failing after 2m54s
2024-04-14 22:39:22 +02:00
=
7d8045918e bon jsp si ca marche
Some checks failed
Linux arm64 / Build (push) Failing after 2m59s
2024-04-14 22:26:02 +02:00
d5bda8ab5d temporary render aabb
All checks were successful
Linux arm64 / Build (push) Successful in 5m20s
2024-04-13 15:37:55 +02:00
8ff74d028f load aabb 2024-04-13 15:37:40 +02:00
6089b144eb refactor Axis
All checks were successful
Linux arm64 / Build (push) Successful in 4m59s
2024-04-13 09:53:58 +02:00
ed3322f256 process model aabb 2024-04-13 09:46:21 +02:00
d13030fbb0 better doc 2024-04-13 09:14:57 +02:00
f78f36ffb2 Merge branch 'main' into physics
All checks were successful
Linux arm64 / Build (push) Successful in 5m5s
2024-04-13 09:02:10 +02:00
43510ea568 fix main menu on kick
All checks were successful
Linux arm64 / Build (push) Successful in 5m4s
2024-04-12 11:15:08 +02:00
9c6c25b17a add default server config
All checks were successful
Linux arm64 / Build (push) Successful in 5m19s
2024-04-12 11:07:23 +02:00
d8a3cb2785 Piou Piou (#48)
Some checks failed
Linux arm64 / Build (push) Has been cancelled
Fix #8

Reviewed-on: #48
Co-authored-by: Persson-dev <sim16.prib@gmail.com>
Co-committed-by: Persson-dev <sim16.prib@gmail.com>
2024-04-12 11:06:54 +02:00
27a76519a3 Suppressions d'erreurs Valgrind (#47)
All checks were successful
Linux arm64 / Build (push) Successful in 5m6s
Reviewed-on: #47
Co-authored-by: Persson-dev <sim16.prib@gmail.com>
Co-committed-by: Persson-dev <sim16.prib@gmail.com>
2024-04-12 10:54:59 +02:00
85585e157f Meilleur panel admin (#45)
All checks were successful
Linux arm64 / Build (push) Successful in 5m6s
Fix #34

Co-authored-by: Morph01 <thibaut6969delastreet@gmail.com>
Reviewed-on: #45
Co-authored-by: Persson-dev <sim16.prib@gmail.com>
Co-committed-by: Persson-dev <sim16.prib@gmail.com>
2024-04-11 17:29:11 +02:00
c2c6f1f033 C'est important la doc (#43)
All checks were successful
Linux arm64 / Build (push) Successful in 4m59s
C'est très long

Co-authored-by: Morph01 <thibaut6969delastreet@gmail.com>
Reviewed-on: #43
Co-authored-by: Persson-dev <sim16.prib@gmail.com>
Co-committed-by: Persson-dev <sim16.prib@gmail.com>
2024-04-11 17:17:40 +02:00
07d09332dd Musique de fond (#44)
All checks were successful
Linux arm64 / Build (push) Successful in 5m30s
Fix #7

Reviewed-on: #44
Co-authored-by: Persson-dev <sim16.prib@gmail.com>
Co-committed-by: Persson-dev <sim16.prib@gmail.com>
2024-04-11 16:59:07 +02:00
747fa13d3a fix action cache (this time it's actually working)
All checks were successful
Linux arm64 / Build (push) Successful in 5m4s
2024-04-11 16:21:49 +02:00
=
8a35b2390c use axis
All checks were successful
Linux arm64 / Build (push) Successful in 24m41s
2024-04-11 12:53:56 +02:00
=
dc2c74fcb1 almost full doc coverage in Physics.h, improve some functions
Some checks are pending
Linux arm64 / Build (push) Waiting to run
2024-04-11 12:51:43 +02:00
32ca078002 revert non blocking connect
All checks were successful
Linux arm64 / Build (push) Successful in 23m26s
2024-04-11 11:53:30 +02:00
=
bae3d70b3c copium
All checks were successful
Linux arm64 / Build (push) Successful in 23m5s
2024-04-10 17:17:00 +02:00
=
f3d5b4aeab fix windows build 2024-04-10 17:16:50 +02:00
=
1ab0d61890 fix merge 2024-04-10 17:16:37 +02:00
=
2896dbeaf6 Merge branch 'main' into physics
Some checks failed
Linux arm64 / Build (push) Failing after 23m21s
2024-04-10 16:01:38 +02:00
=
0175a1fed0 add ()
All checks were successful
Linux arm64 / Build (push) Successful in 4m55s
2024-04-10 15:32:37 +02:00
=
ce13f6f1ce moooooooonkey 2024-04-10 15:17:40 +02:00
=
69d5547d15 add ToCollision, optimise perspective matrix calculation
Some checks failed
Linux arm64 / Build (push) Failing after 2m19s
2024-04-10 14:55:07 +02:00
1d1a02a7b5 minor architectural changes, Intersection updated
Some checks failed
Linux arm64 / Build (push) Failing after 2m22s
2024-04-10 11:52:35 +02:00
e1efc5065c use leaderboard agin
All checks were successful
Linux arm64 / Build (push) Successful in 23m50s
2024-04-09 20:03:10 +02:00
8795562b42 Fix win (#38)
Some checks failed
Linux arm64 / Build (push) Has been cancelled
Reviewed-on: #38
Co-authored-by: Persson-dev <sim16.prib@gmail.com>
Co-committed-by: Persson-dev <sim16.prib@gmail.com>
2024-04-09 19:47:46 +02:00
cd7ca3edf0 yes
Some checks failed
Linux arm64 / Build (push) Failing after 2m17s
2024-04-09 12:16:18 +02:00
=
6e6a21ce09 implement bare-bones aabb-aabb intersection
All checks were successful
Linux arm64 / Build (push) Successful in 4m53s
2024-03-26 12:06:15 +01:00
=
0adeba26e4 minor fix
All checks were successful
Linux arm64 / Build (push) Successful in 4m50s
2024-03-26 11:35:37 +01:00
=
011d8a573c fix stupid build error
Some checks failed
Linux arm64 / Build (push) Has been cancelled
2024-03-26 11:33:56 +01:00
=
22406ad020 yes
Some checks failed
Linux arm64 / Build (push) Failing after 2m52s
2024-03-26 11:25:35 +01:00
=
4db55a372b csavgfdslgakdf;g
Some checks failed
Linux arm64 / Build (push) Failing after 2m42s
2024-03-26 11:13:22 +01:00
20d176ccb5 add range overlapping check utilities
Some checks failed
Linux arm64 / Build (push) Failing after 3m10s
2024-03-26 11:07:27 +01:00
3863e7907f better edge case handling 2024-03-26 10:24:35 +01:00
=
35b7d7bab0 I am fucking retarded what the fuck is this stupid brain smoking
All checks were successful
Linux arm64 / Build (push) Successful in 4m47s
2024-03-26 10:19:21 +01:00
6aca413b4f small refactor
Some checks failed
Linux arm64 / Build (push) Failing after 5m21s
2024-03-24 18:14:02 +01:00
ee322e3e7b improve tests, fix some bugs in Distance, (not working yet)
Some checks failed
Linux arm64 / Build (push) Failing after 2m28s
2024-03-24 17:43:07 +01:00
864a15e4c8 Squashed commit of the following:
All checks were successful
Linux arm64 / Build (push) Successful in 4m45s
commit c1ded40cc4
Author: Persson-dev <sim16.prib@gmail.com>
Date:   Thu Mar 21 17:24:05 2024 +0100

    improve network test

commit 285bf880ee
Author: Persson-dev <sim16.prib@gmail.com>
Date:   Thu Mar 21 17:14:43 2024 +0100

    fix warning

commit 06ff76607d
Author: Persson-dev <sim16.prib@gmail.com>
Date:   Thu Mar 21 15:45:33 2024 +0100

    add bots

commit 19229bbe8a
Author: Persson-dev <sim16.prib@gmail.com>
Date:   Thu Mar 21 14:55:57 2024 +0100

    fix warnings

commit 2b0930a734
Author: Morph01 <thibaut6969delastreet@gmail.com>
Date:   Tue Mar 19 10:43:55 2024 +0100

    hud of blitz (#16)

    Résoudre partiellement #12

    Co-authored-by: Persson-dev <sim16.prib@gmail.com>
    Co-authored-by: Morph01 <145839520+Morph01@users.noreply.github.com>
    Co-authored-by: Simon Pribylski <sim16.prib@gmail.com>
    Reviewed-on: #16

commit 84b6acad4c
Author: Persson-dev <sim16.prib@gmail.com>
Date:   Tue Mar 19 10:15:54 2024 +0100

    less spooky light

commit 9f94d51fc4
Author: Persson-dev <sim16.prib@gmail.com>
Date:   Thu Mar 14 16:36:15 2024 +0100

    Ajout de tests d'intégration (#17)

    Le paquet fournissant OpenGL a été temporairement remplacé par glew

    Reviewed-on: #17
    Co-authored-by: Persson-dev <sim16.prib@gmail.com>
    Co-committed-by: Persson-dev <sim16.prib@gmail.com>

commit 9951256881
Author: Simon Pribylski <sim16.prib@gmail.com>
Date:   Wed Mar 13 20:19:37 2024 +0100

    action: install libsdl via apt

commit 4a02054648
Author: Morph01 <145839520+Morph01@users.noreply.github.com>
Date:   Wed Mar 13 13:53:20 2024 +0100

    compression tests

commit 19c39312bf
Author: Morph01 <145839520+Morph01@users.noreply.github.com>
Date:   Wed Mar 13 13:51:57 2024 +0100

    setup action

commit d5014b1e8a
Author: Persson-dev <sim16.prib@gmail.com>
Date:   Tue Mar 12 10:26:47 2024 +0100

    Revert "extend Vec3"

    This reverts commit dccfa9c936.

commit dccfa9c936
Author: = <=>
Date:   Tue Mar 12 10:01:00 2024 +0100

    extend Vec3
Merge branch 'main' into physics
2024-03-22 19:33:45 +01:00
7efd8218ea moved functions in Maths.h
Some checks failed
Linux arm64 / Build (push) Has been cancelled
2024-03-22 19:28:46 +01:00
08db7f84b9 add missing include
All checks were successful
Linux arm64 / Build (push) Successful in 5m7s
2024-03-22 19:16:48 +01:00
7119dea783 merge 'main' branch
commit c1ded40cc4
Author: Persson-dev <sim16.prib@gmail.com>
Date:   Thu Mar 21 17:24:05 2024 +0100

    improve network test

commit 285bf880ee
Author: Persson-dev <sim16.prib@gmail.com>
Date:   Thu Mar 21 17:14:43 2024 +0100

    fix warning

commit 06ff76607d
Author: Persson-dev <sim16.prib@gmail.com>
Date:   Thu Mar 21 15:45:33 2024 +0100

    add bots

commit 19229bbe8a
Author: Persson-dev <sim16.prib@gmail.com>
Date:   Thu Mar 21 14:55:57 2024 +0100

    fix warnings

commit 2b0930a734
Author: Morph01 <thibaut6969delastreet@gmail.com>
Date:   Tue Mar 19 10:43:55 2024 +0100

    hud of blitz (#16)

    Résoudre partiellement #12

    Co-authored-by: Persson-dev <sim16.prib@gmail.com>
    Co-authored-by: Morph01 <145839520+Morph01@users.noreply.github.com>
    Co-authored-by: Simon Pribylski <sim16.prib@gmail.com>
    Reviewed-on: #16

commit 84b6acad4c
Author: Persson-dev <sim16.prib@gmail.com>
Date:   Tue Mar 19 10:15:54 2024 +0100

    less spooky light

commit 9f94d51fc4
Author: Persson-dev <sim16.prib@gmail.com>
Date:   Thu Mar 14 16:36:15 2024 +0100

    Ajout de tests d'intégration (#17)

    Le paquet fournissant OpenGL a été temporairement remplacé par glew

    Reviewed-on: #17
    Co-authored-by: Persson-dev <sim16.prib@gmail.com>
    Co-committed-by: Persson-dev <sim16.prib@gmail.com>

commit 9951256881
Author: Simon Pribylski <sim16.prib@gmail.com>
Date:   Wed Mar 13 20:19:37 2024 +0100

    action: install libsdl via apt

commit 4a02054648
Author: Morph01 <145839520+Morph01@users.noreply.github.com>
Date:   Wed Mar 13 13:53:20 2024 +0100

    compression tests

commit 19c39312bf
Author: Morph01 <145839520+Morph01@users.noreply.github.com>
Date:   Wed Mar 13 13:51:57 2024 +0100

    setup action

commit d5014b1e8a
Author: Persson-dev <sim16.prib@gmail.com>
Date:   Tue Mar 12 10:26:47 2024 +0100

    Revert "extend Vec3"

    This reverts commit dccfa9c936.

commit dccfa9c936
Author: = <=>
Date:   Tue Mar 12 10:01:00 2024 +0100

    extend Vec3
2024-03-22 19:15:01 +01:00
6e998fc368 change tests
All checks were successful
Linux arm64 / Build (push) Successful in 4m29s
2024-03-22 16:41:52 +01:00
441131a2f5 rename Intersects to distance 2024-03-22 16:14:56 +01:00
c875fa1dee more template
All checks were successful
Linux arm64 / Build (push) Successful in 4m46s
2024-03-22 15:50:32 +01:00
5e4b318d67 inline Reduce_<> functions
All checks were successful
Linux arm64 / Build (push) Successful in 4m34s
2024-03-22 15:26:07 +01:00
076fa7badc fix compilation error
Some checks failed
Linux arm64 / Build (push) Failing after 4m22s
2024-03-22 15:18:39 +01:00
1091abd034 fix some compilation errors
Some checks failed
Linux arm64 / Build (push) Failing after 2m14s
2024-03-22 14:58:26 +01:00
dd9ea3ece8 update intersects, document changes
Some checks failed
Linux arm64 / Build (push) Failing after 2m12s
2024-03-22 12:02:39 +01:00
6226161e31 fix compilation error, add min/max functions for Vec3d
Some checks failed
Linux arm64 / Build (push) Failing after 2m23s
2024-03-22 09:22:06 +01:00
6b32e8878e fix min/max functions
Some checks failed
Linux arm64 / Build (push) Failing after 2m18s
2024-03-22 09:18:34 +01:00
115 changed files with 3189 additions and 508 deletions

View File

@@ -10,7 +10,7 @@ jobs:
- name: Install deps
run : |
apt update
apt install -y libsdl2-dev libassimp-dev libglew-dev
apt install -y libsdl2-dev libassimp-dev libglew-dev
- name: Check out repository code
uses: actions/checkout@v3
@@ -22,11 +22,19 @@ jobs:
actions-cache-folder: '.xmake-cache'
actions-cache-key: 'ubuntu'
- name: Calc deps hash
uses: seepine/hash-files@v1
id: get-hash
with:
patterns: |
**/xmake.lua
**/xmake/*.lua
- name: Packages cache
uses: actions/cache@v4
with:
path: ~/.xmake
key: 'ubuntu-packages'
key: ${{ runner.os }}-${{ steps.get-hash.outputs.hash }}
- name: XMake config
run: xmake f -p linux -y --root
@@ -35,4 +43,4 @@ jobs:
run: xmake --root
- name: Test
run: xmake test --root
run: xmake test --root

Binary file not shown.

BIN
assets/laser.wav Normal file

Binary file not shown.

BIN
assets/sessionD.wav Normal file

Binary file not shown.

BIN
assets/sol.glb Normal file

Binary file not shown.

View File

@@ -7,10 +7,10 @@
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <string>
#include <vector>
#include <cstdint>
namespace blitz {
@@ -40,21 +40,31 @@ class DataBuffer {
DataBuffer& operator=(const DataBuffer& other);
DataBuffer& operator=(DataBuffer&& other);
/**
* \brief Append data to the buffer
*/
template <typename T>
void Append(const T& data) {
std::size_t size = sizeof(data);
std::size_t end_pos = m_Buffer.size();
m_Buffer.resize(m_Buffer.size() + size);
memcpy(&m_Buffer[end_pos], &data, size);
std::memcpy(&m_Buffer[end_pos], &data, size);
}
/**
* \brief Append data to the buffer
*/
template <typename T>
DataBuffer& operator<<(const T& data) {
Append(data);
return *this;
}
// don't use it for binary data !
/**
* \brief Append a string to the buffer
* \warning Don't use it for binary data !
* \param str The string to append
*/
DataBuffer& operator<<(const std::string& str) {
std::size_t strlen = str.length() + 1; // including null character
Resize(GetSize() + strlen);
@@ -62,16 +72,18 @@ class DataBuffer {
return *this;
}
DataBuffer& operator<<(DataBuffer& data) {
m_Buffer.insert(m_Buffer.end(), data.begin(), data.end());
return *this;
}
/**
* \brief Append data to the buffer from another const buffer
* \param data The buffer to append
*/
DataBuffer& operator<<(const DataBuffer& data) {
m_Buffer.insert(m_Buffer.end(), data.begin(), data.end());
return *this;
}
/**
* \brief Read some data from the buffer and assign to desired variable
*/
template <typename T>
DataBuffer& operator>>(T& data) {
assert(m_ReadOffset + sizeof(T) <= GetSize());
@@ -80,6 +92,10 @@ class DataBuffer {
return *this;
}
/**
* \brief Read some data from the buffer and assign to the new buffer
* \param data The buffer to assign
*/
DataBuffer& operator>>(DataBuffer& data) {
data.Resize(GetSize() - m_ReadOffset);
std::copy(m_Buffer.begin() + static_cast<difference_type>(m_ReadOffset), m_Buffer.end(), data.begin());
@@ -87,7 +103,11 @@ class DataBuffer {
return *this;
}
// Don't use it for binary data !
/**
* \brief Read a string from the buffer
* \param str The string to assign in the new buffer
* \warning Don't use it for binary data !
*/
DataBuffer& operator>>(std::string& str) {
std::size_t stringSize =
strlen(reinterpret_cast<const char*>(m_Buffer.data()) + m_ReadOffset) + 1; // including null character
@@ -98,30 +118,55 @@ class DataBuffer {
return *this;
}
/**
* \brief Write some data to the buffer
* \param buffer The buffer to write
* \param amount The amount of data to write
*/
void WriteSome(const char* buffer, std::size_t amount) {
std::size_t end_pos = m_Buffer.size();
m_Buffer.resize(m_Buffer.size() + amount);
memcpy(m_Buffer.data() + end_pos, buffer, amount);
std::memcpy(m_Buffer.data() + end_pos, buffer, amount);
}
/**
* \brief Write some data to the buffer
* \param buffer The buffer to write
* \param amount The amount of data to write
*/
void WriteSome(const std::uint8_t* buffer, std::size_t amount) {
std::size_t end_pos = m_Buffer.size();
m_Buffer.resize(m_Buffer.size() + amount);
memcpy(m_Buffer.data() + end_pos, buffer, amount);
std::memcpy(m_Buffer.data() + end_pos, buffer, amount);
}
/**
* \brief Read some data from the buffer
* \param buffer The buffer to Read
* \param amount The amount of data from the buffer
*/
void ReadSome(char* buffer, std::size_t amount) {
assert(m_ReadOffset + amount <= GetSize());
std::copy_n(m_Buffer.begin() + static_cast<difference_type>(m_ReadOffset), amount, buffer);
m_ReadOffset += amount;
}
/**
* \brief Read some data from the buffer
* \param buffer The buffer to Read
* \param amount The amount of data from the buffer
*/
void ReadSome(std::uint8_t* buffer, std::size_t amount) {
assert(m_ReadOffset + amount <= GetSize());
std::copy_n(m_Buffer.begin() + static_cast<difference_type>(m_ReadOffset), amount, buffer);
m_ReadOffset += amount;
}
/**
* \brief Read some data from the buffer
* \param buffer The buffer to Read
* \param amount The amount of data from the buffer
*/
void ReadSome(DataBuffer& buffer, std::size_t amount) {
assert(m_ReadOffset + amount <= GetSize());
buffer.Resize(amount);
@@ -129,64 +174,113 @@ class DataBuffer {
m_ReadOffset += amount;
}
/**
* \brief Resize the buffer
* \param size The new size of the buffer
*/
void Resize(std::size_t size) {
m_Buffer.resize(size);
}
/**
* \brief Reserve some space in the buffer
* \param amount The amount of space to reserve
*/
void Reserve(std::size_t amount) {
m_Buffer.reserve(amount);
}
void erase(iterator it) {
m_Buffer.erase(it);
}
/**
* \brief Clear the buffer
*/
void Clear() {
m_Buffer.clear();
m_ReadOffset = 0;
}
/**
* \brief When the buffer has been read entirely
*/
bool IsFinished() const {
return m_ReadOffset >= m_Buffer.size();
}
/**
* \brief Get the buffer data
*/
std::uint8_t* data() {
return m_Buffer.data();
}
/**
* \brief Get the buffer data
*/
const std::uint8_t* data() const {
return m_Buffer.data();
}
/**
* \brief Get the read offset
*/
std::size_t GetReadOffset() const {
return m_ReadOffset;
}
/**
* \brief Set the read offset
* \param pos The new read offset
*/
void SetReadOffset(std::size_t pos);
/**
* \brief Get the size of the buffer
*/
std::size_t GetSize() const;
/**
* \brief Get the remaining size of the buffer
*/
std::size_t GetRemaining() const;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
/**
* \brief Read a file into the buffer
* \param fileName The name of the file to read
*/
bool ReadFile(const std::string& fileName);
bool WriteFile(const std::string& fileName);
// Don't forget to free the data !
/**
* \brief Write a file into the buffer
* \param fileName The name of the file to write to
*/
bool WriteFile(const std::string& fileName) const;
/**
* \brief Allocate the buffer on the heap
* \warning Don't forget to free the data !
*/
std::uint8_t* HeapAllocatedData() const {
std::uint8_t* newBuffer = new std::uint8_t[GetSize()];
std::memcpy(newBuffer, data(), GetSize());
return newBuffer;
}
bool operator==(const DataBuffer& other) const{
/**
* \brief Operator == to compare two DataBuffer
*/
bool operator==(const DataBuffer& other) const {
return m_Buffer == other.m_Buffer;
}
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
};
/**
* \brief Operator << to write a DataBuffer to an ostream
*/
std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer);
} // namespace blitz

View File

@@ -3,7 +3,7 @@
/**
* \file Defines.h
* \brief File containing constants and typedefs
*/
*/
#include <cstdint>
@@ -13,8 +13,20 @@ namespace game {
/**
* \typedef PlayerID
* \brief Represents the identifier of a Player
*/
*/
typedef std::uint8_t PlayerID;
/**
* \enum GameState
* \brief The states of the game
*/
enum GameState : std::uint8_t {
gsNone = 0, /**< Default state */
gsWaiting, /**< Waiting state if the number of players is less than 2 */
gsPreparing, /**< Preparing state until the game start */
gsGame, /**< Game state during the players can shoot and kill ... */
gsEnd, /**< End state of the game : show the winner of the game and the leaderboard*/
};
} // namespace game
} // namespace blitz

View File

@@ -1,7 +1,17 @@
#pragma once
/**
* \file NonCopyable.h
* \brief File containing the blitz::NonCopyable class
*/
namespace blitz {
/**
* \class NonCopyable
* \brief Class used to make a class non copyable
* \note Inherit from this class privately to make a class non copyable
*/
class NonCopyable {
public:
NonCopyable(const NonCopyable&) = delete;

View File

@@ -2,17 +2,38 @@
namespace blitz {
/**
* \struct An exponential moving average smoother, or one pole lowpass filter
* smoothes incoming data by attenutating sharp/sudden changes
*/
class EMASmoother {
private:
float Alpha;
public:
float Current;
EMASmoother();
void TickUnitT(float target);
void Tick(float target, float delta);
float GetAlpha();
void SetAlpha(float alpha);
public:
/**
* \brief the current output value of the smoother
*/
float Current;
EMASmoother();
/**
* \brief behaves like `Tick(target, 1.0f)` but optimised
*/
void TickUnitT(float target);
/**
* \brief feed in the next value to the filter, and update `Current` accordingly
* \param target the value in question
* \param delta the time that has passed sinced the last value has been provided
*/
void Tick(float target, float delta);
/**
* \brief set the amount of time it should take to reacha certain value, the higher this is
* the "smoother the output signal"
*/
void SetSmoothingTime(float t);
};

View File

@@ -1,5 +1,10 @@
#pragma once
/**
* \file VarInt.h
* \brief File containing the blitz::VarInt class
*/
#include <cstddef>
#include <cstdint>
@@ -7,21 +12,46 @@ namespace blitz {
class DataBuffer;
/**
* \class VarInt
* \brief Variable-length format such that smaller numbers use fewer bytes.
*/
class VarInt {
private:
std::uint64_t m_Value;
public:
VarInt() : m_Value(0) {}
/**
* \brief Construct a variable integer from a value
* \param value The value of the variable integer
*/
VarInt(std::uint64_t value) : m_Value(value) {}
/**
* \brief Get the value of the variable integer
*/
std::uint64_t GetValue() const {
return m_Value;
}
/**
* \brief Get the length of the serialized variable integer
*/
std::size_t GetSerializedLength() const;
/**
* \brief Serialize the variable integer
* \param out The buffer to write the serialized variable integer to
* \param var The variable integer to serialize
*/
friend DataBuffer& operator<<(DataBuffer& out, const VarInt& var);
/**
* \brief Deserialize the variable integer
* \param in The buffer to read the serialized variable integer from
* \param var The variable integer to deserialize
*/
friend DataBuffer& operator>>(DataBuffer& in, VarInt& var);
};

View File

@@ -1,68 +1,150 @@
#pragma once
/**
* \file Game.h
* \brief File containing the blitz::game::Game class
*/
#include "Player.h"
#include "blitz/game/Listeners.h"
#include "blitz/game/World.h"
#include "blitz/misc/ObjectNotifier.h"
#include "blitz/misc/Time.h"
#include <map>
#include <memory>
namespace blitz {
namespace game {
/**
* \typedef PlayerMap
* \brief A map of players
*/
typedef std::map<PlayerID, Player> PlayerMap;
enum GameState : std::uint8_t {
gsNone = 0,
gsWaiting,
gsPreparing,
gsGame,
gsEnd,
};
/**
* \brief The game configuration
* \struct GameConfig
*/
struct GameConfig {
/**
* \brief The gravity applied to players
*/
float Gravity;
/**
* \brief The firing rate of the shoot in RPM (round per minute)
*/
int FiringRate;
};
class Game {
/**
* \class Game
* \brief Class representing a game
*/
class Game : public utils::ObjectNotifier<GameListener> {
protected:
PlayerMap m_Players;
GameState m_GameState;
utils::Timer m_GameTimer;
GameConfig m_Config;
std::unique_ptr<World> m_World;
public:
/** \brief Default constructor */
Game() : m_GameState(gsNone) {}
/**
* \brief Update the game with a delta time
* \param delta The time elapsed since the last update in milliseconds
*/
virtual void Tick(std::uint64_t delta) = 0;
/**
* \brief Get a player by its identifier
* \param id The identifier of the player
* \return The player if found, nullptr otherwise
*/
Player* GetPlayerById(PlayerID id);
/**
* \brief Get a player by its identifier (const version)
* \param id The identifier of the player
* \return The player if found, nullptr otherwise
*/
const Player* GetPlayerById(PlayerID id) const;
/**
* \brief Get the players
* \return The map of players
*/
PlayerMap& GetPlayers() {
return m_Players;
}
/**
* \brief Get the players (const version)
* \return The map of players
*/
const PlayerMap& GetPlayers() const {
return m_Players;
}
/**
* \brief Get the game state
* \return The game state
*/
GameState GetGameState() const {
return m_GameState;
}
/**
* \brief Set the game state
* \return The game state
*/
virtual void UpdateGameState(GameState newGameState, std::uint64_t timeRemaining);
/**
* \brief Load the game configuration
* \param config The game configuration to load
*/
void LoadConfig(const GameConfig& config) {
m_Config = config;
}
/**
* \brief Get the game configuration
* \return The game configuration
*/
const game::GameConfig& GetGameConfig() const {
return m_Config;
}
/**
* \brief Add a player to the game
* \param player The identifier of the player
* \param name The name of the player
*/
virtual void AddPlayer(PlayerID player, const std::string& name);
/**
* \brief Remove a player from the game
* \param player The identifier of the player
*/
virtual void RemovePlayer(PlayerID player);
/**
* \brief Get the remaining time of the game
* \return The remaining time of the game in milliseconds
*/
std::uint64_t GetGameStateRemainingTime() const {
return m_GameTimer.GetTimeRemaining();
}
/**
* \return The world associated with this game
*/
const World* GetWorld() const {
return m_World.get();
}
};

View File

@@ -1,21 +1,45 @@
#pragma once
/**
* \file LeaderBoard.h
* \brief File containing the blitz::game::LeaderBoard class
*/
#include "blitz/game/Player.h"
#include <vector>
namespace blitz {
namespace game {
/**
* \class LeaderBoard
* \brief The leaderboard of the game
*/
class LeaderBoard {
private:
std::vector<Player*> m_Players;
public:
/**
* \brief Add a player to the leaderboard
* \param player The player to add
*/
void AddPlayer(Player* player);
/**
* \brief Remove a player from the leaderboard
* \param player The player to remove
*/
void RemovePlayer(PlayerID player);
/**
* \brief Update the leaderboard
*/
void Update();
/**
* \brief Get the players in the leaderboard ordered by kills
* \return The players
*/
const std::vector<Player*>& GetPlayers() const {
return m_Players;
}

View File

@@ -13,7 +13,6 @@ typedef std::vector<ColoredPart> ColoredText;
} // namespace protocol
namespace game {
class PlayerInputListener {
@@ -22,12 +21,22 @@ class PlayerInputListener {
virtual void OnLocalPlayerShoot(const Vec3f& position, float yaw, float pitch) {}
};
class GameListener {
public:
virtual void OnPlayerJoin(game::PlayerID player) {}
virtual void OnPlayerLeave(game::PlayerID player) {}
virtual void OnGameStateUpdate(game::GameState newState) {}
};
class ClientListener {
public:
virtual void OnTextChatReceived(const protocol::ColoredText& text) {}
virtual void OnSpectatorChange(game::PlayerID player) {}
virtual void OnPlayerShoot(PlayerID player, const Vec3f& position, float yaw, float pitch) {}
virtual void OnClientPlayerJoin() {}
virtual void OnGameConfigUpdate() {}
virtual void OnGameJoin() {}
virtual void OnGameLeave() {}
};
} // namespace game

View File

@@ -1,22 +1,49 @@
#pragma once
/**
* \file Player.h
* \brief File containing the blitz::game::Player class
*/
#include "blitz/common/Defines.h"
#include "blitz/maths/Vector.h"
#include "blitz/maths/Physics.h"
#include <cstdint>
#include <string>
namespace blitz {
namespace game {
/**
* \struct PlayerStats
* \brief The statistics of a player
*/
struct PlayerStats {
/**
* \brief The number of deaths
*/
std::uint16_t m_Deaths;
/**
* \brief The number of kills
*/
std::uint16_t m_Kills;
/**
* \brief The number of shots
*/
std::uint32_t m_ShootCount;
/**
* \brief The number of successful shots
*/
std::uint32_t m_ShootSuccessCount;
};
/**
* \class Player
* \brief The player of the game
*/
class Player {
private:
maths::AABB m_Hitbox;
PlayerID m_ID;
std::string m_Name;
Vec3f m_Position;
@@ -25,94 +52,187 @@ class Player {
float m_Pitch;
float m_HP;
bool m_IsBot;
public:
Player(PlayerID id) : m_ID(id), m_Yaw(0), m_Pitch(0), m_HP(100), m_IsBot(false) {}
PlayerStats m_Stats{};
public:
/**
* \brief Default constructor
* \param id The ID of the player
*/
Player(PlayerID id) : m_ID(id), m_Yaw(0), m_Pitch(0), m_HP(100), m_IsBot(false) {}
/**
* \brief Get the ID of the player
* \return The ID of the player
*/
PlayerID GetID() const {
return m_ID;
}
/**
* \brief Get the name of the player
* \return The name of the player
*/
const std::string& GetName() const {
return m_Name;
}
/**
* \brief Set the name of the player
* \param name The name of the player
*/
void SetName(const std::string& name) {
m_Name = name;
}
/**
* \brief Get the player's hitbox
*/
maths::AABB GetHitBox() const {
return m_Hitbox + m_Position;
}
/**
* \brief Sets the player's hitbox
*/
void SetHitBoxSize(const maths::AABB& aabb) {
m_Hitbox = aabb;
}
/**
* \brief Get the position of the player
* \return The position of the player
*/
const Vec3f& GetPosition() const {
return m_Position;
}
/**
* \brief Set the position of the player
* \param newPos The new position of the player
*/
void SetPosition(const Vec3f& newPos) {
m_Position = newPos;
}
/**
* \brief Add a position to the player
* \param dPos The position to add
*/
void AddPosition(const Vec3f& dPos) {
m_Position += dPos;
}
/**
* \brief Get the velocity of the player
* \return The velocity of the player
*/
const Vec3f& GetVelocity() const {
return m_Velocity;
}
/**
* \brief Set the velocity of the player
* \param newVelocity The new velocity of the player
*/
void SetVelocity(const Vec3f& newVelocity) {
m_Velocity = newVelocity;
}
/**
* \brief Get the yaw of the player
* \return The yaw of the player in radians
*/
float GetYaw() const {
return m_Yaw;
}
/**
* \brief Set the yaw of the player
* \param yaw The yaw of the player in radians
*/
void SetYaw(float yaw) {
m_Yaw = yaw;
}
/**
* \brief Add a yaw to the player
* \param dYaw The yaw to add in radians
*/
void AddYaw(float dYaw) {
m_Yaw += dYaw;
}
/**
* \brief Get the pitch of the player
* \return The pitch of the player in radians
*/
float GetPitch() const {
return m_Pitch;
}
/**
* \brief Set the pitch of the player
* \param pitch The pitch of the player in radians
*/
void SetPitch(float pitch) {
m_Pitch = pitch;
}
/**
* \brief Add a pitch to the player
* \param dPitch The pitch to add in radians
*/
void AddPitch(float dPitch) {
m_Pitch += dPitch;
}
/**
* \brief Get the HP of the player
* \return The HP of the player
*/
float GetHP() const {
return m_HP;
}
/**
* \brief Set the HP of the player
* \param hp The HP of the player
*/
void SetHP(float hp) {
m_HP = hp;
}
/**
* \brief When the player is a bot
* \return True if the player is a bot
*/
bool IsBot() const {
return m_IsBot;
}
/**
* \brief Set the player as a bot
*/
void SetBot() {
m_IsBot = true;
}
/**
* \brief Get the statistics of the player (const version)
* \return The statistics of the player
*/
const PlayerStats& GetStats() const {
return m_Stats;
}
/**
* \brief Get the statistics of the player
* \return The statistics of the player
*/
PlayerStats& GetStats() {
return m_Stats;
}
void SetStats(const PlayerStats& stats) {
m_Stats = stats;
}
};

View File

@@ -0,0 +1,27 @@
#pragma once
#include "blitz/game/Listeners.h"
#include "blitz/maths/Physics.h"
#include <vector>
namespace blitz {
namespace game {
class Game;
class World {
protected:
Game* m_Game;
std::vector<maths::AABB> m_AABBs;
public:
World(Game* game);
virtual ~World();
const std::vector<maths::AABB>& GetAABBs() const {
return m_AABBs;
}
};
} // namespace game
} // namespace blitz

View File

@@ -1,5 +1,10 @@
#pragma once
/**
* \file Maths.h
* \brief File containing mathematical functions and constants
*/
#include "blitz/maths/Vector.h"
#include <cmath>
@@ -8,18 +13,19 @@ namespace maths {
static constexpr float PI = 3.141592653f;
template <typename T>
/**
* @brief returns the amount of overlap between the ranges [a1 ; b1] and [a2 ; b2]
*/
* \return the amount of overlap between the ranges [a1 ; b1] and [a2 ; b2]
*/
template <typename T>
T RangesOverlap(T& a1, T& b1, T& a2, T& b2) {
return std::min(std::max(a1, b1), std::max(a2, b2)) - std::max(std::min(a1, b1), std::min(a2, b2));
}
template <typename T>
/**
* @brief returns whether the ranges [a1 ; b1] and [a2 ; b2] overlap
*/
* \return whether the ranges [a1 ; b1] and [a2 ; b2] overlap
*/
template <typename T>
bool RangesOverlapping(T& a1, T& b1, T& a2, T& b2) {
return RangesOverlap(a1, a2, b1, b2) >= 0;
}
@@ -28,11 +34,19 @@ bool RangesOverlapping(T& a1, T& b1, T& a2, T& b2) {
// Vectors //
//////////////////////////////////////////////////////////////////
/**
* \brief Returns the length of the vector
* \return the length of the vector
*/
template <typename T>
T Length(const Vec3<T>& vect) {
return std::sqrt(vect.x * vect.x + vect.y * vect.y + vect.z * vect.z);
}
/**
* \brief Normalizes the vector
* \return the normalized vector
*/
template <typename T>
Vec3<T> Normalize(const Vec3<T>& vect) {
T length = Length(vect);
@@ -40,6 +54,10 @@ Vec3<T> Normalize(const Vec3<T>& vect) {
return {vect.x / length, vect.y / length, vect.z / length};
}
/**
* \brief Normalizes the vector
* \return the normalized vector
*/
template <typename T>
Vec4<T> Normalize(const Vec4<T>& vect) {
T length = std::sqrt(vect.x * vect.x + vect.y * vect.y + vect.z * vect.z + vect.w * vect.w);
@@ -47,11 +65,19 @@ Vec4<T> Normalize(const Vec4<T>& vect) {
return {vect.x / length, vect.y / length, vect.z / length, vect.w / length};
}
/**
* \brief Returns the dot product of the two vectors
* \return the dot product of the two vectors
*/
template <typename T>
T Dot(const Vec3<T>& vect, const Vec3<T>& other) {
return vect.x * other.x + vect.y * other.y + vect.z * other.z;
}
/**
* \brief Returns the cross product of the two vectors
* \return the cross product of the two vectors
*/
template <typename T>
Vec3<T> Cross(const Vec3<T>& vect, const Vec3<T>& other) {
return {
@@ -61,82 +87,102 @@ Vec3<T> Cross(const Vec3<T>& vect, const Vec3<T>& other) {
};
}
/**
* \brief Returns the dot product of the two vectors
* \return the dot product of the two vectors
*/
template <typename T>
T Dot(const Vec4<T>& vect, const Vec4<T>& other) {
return vect.x * other.x + vect.y * other.y + vect.z * other.z + vect.w * other.w;
}
/**
* \brief Returns the distance between the two vectors
* \return the distance between the two vectors
*/
template <typename T>
T Distance(const Vec3<T>& vect, const Vec3<T>& other) {
return Length(vect - other);
}
// it seems that `std::{min, max}`'s behavior conflicts with that of `cmath`'s `f{min, max}[f]`
// Why? Like I fucking know dude
/**
* \brief Returns the minimum of the three coordinates of the vector
* \return the minimum between the three coordinates of the vector
*/
template <typename T>
T ReduceMin(const Vec3<T>& vect) {
return std::min(std::min(vect.x, vect.y), vect.z);
}
/**
* \brief Returns the maximum of the three coordinates of the vector
* \return the maximum between the three coordinates of the vector
*/
template <typename T>
T ReduceMax(const Vec3<T>& vect) {
return std::max(std::max(vect.x, vect.y), vect.z);
}
/**
* @brief returns the (signed) minimal coordinate of the vector
*
* @param v
* @return constexpr T
* \brief Returns the (signed) minimal coordinate of the vector
* \param v a vector
* \return the (signed) minimal coordinate of the vector
*/
template <>
inline float ReduceMin<float>(const Vec3f& v) {
inline float ReduceFMinF(const Vec3f& v) {
return std::fminf(std::fminf(v.x, v.y), v.z);
}
inline Vec3f FmaF(const Vec3f& v, const Vec3f& a, const Vec3f& b) {
return {
std::fmaf(v.x, a.x, b.x),
std::fmaf(v.y, a.y, b.y),
std::fmaf(v.z, a.z, b.z),
};
}
inline Vec3d Fma(const Vec3d& v, const Vec3d& a, const Vec3d& b) {
return {
std::fma(v.x, a.x, b.x),
std::fma(v.y, a.y, b.y),
std::fma(v.z, a.z, b.z),
};
}
/**
* @brief returns the (signed) maximal coordinate of the vector
*
* @param v
* @return constexpr T
* \brief Returns the (signed) maximal coordinate of the vector
* \param v a vector
* \return the (signed) maximal coordinate of the vector
*/
template <>
inline float ReduceMax<float>(const Vec3f& v) {
inline float ReduceFMaxF(const Vec3f& v) {
return std::fmaxf(std::fmaxf(v.x, v.y), v.z);
}
/**
* @brief returns the (signed) minimal coordinate of the vector
*
* @param v
* @return constexpr T
* \brief returns the (signed) minimal coordinate of the vector
* \param v a vector
* \return the (signed) minimal coordinate of the vector
*/
template <>
inline double ReduceMin<double>(const Vec3d& v) {
inline double ReduceFMin(const Vec3d& v) {
return std::fmin(std::fmin(v.x, v.y), v.z);
}
/**
* @brief returns the (signed) maximal coordinate of the vector
*
* @param v
* @return constexpr T
* \brief returns the (signed) maximal coordinate of the vector
* \param v a vector
* \return the (signed) maximal coordinate of the vector
*/
template <>
inline double ReduceMax<double>(const Vec3d& v) {
inline double ReduceFMax(const Vec3d& v) {
return std::fmax(std::fmax(v.x, v.y), v.z);
}
/**
* @brief returns the coordinate-wise minimum of the given vectors,
* where a coordinate in the returned vector is NAN iff any of the two compared ones are NAN
*
* @tparam T
* @param self
* @param other
* @return constexpr Vec3f
* \brief returns the coordinate-wise minimum of the given vectors, where a coordinate in the returned vector is NAN iff any of the two
* compared ones are NAN
* \tparam T
* \param self a vector
* \param other an other vector
* \return the coordinate-wise minimum of the given vectors, where a coordinate in the returned vector is NAN iff any of the two
* compared ones are NAN
*/
template <typename T>
constexpr Vec3<T> Min(const Vec3<T>& self, const Vec3<T>& other) {
@@ -147,6 +193,23 @@ constexpr Vec3<T> Min(const Vec3<T>& self, const Vec3<T>& other) {
};
}
/**
* @brief returns the coordinate-wise minimum of the given vectors,
* where a coordinate in the returned vector is NAN iff both of the two compared ones are NAN
*
* @tparam T
* @param self
* @param other
* @return constexpr Vec3f
*/
constexpr Vec3f FMinF(const Vec3f& self, const Vec3f& other) {
return {
std::fminf(self.x, other.x),
std::fminf(self.y, other.y),
std::fminf(self.z, other.z),
};
}
/**
* @brief returns the coordinate-wise maximum of the given vectors,
* where a coordinate in the returned vector is NAN iff any of the two compared ones are NAN
@@ -154,7 +217,7 @@ constexpr Vec3<T> Min(const Vec3<T>& self, const Vec3<T>& other) {
* @tparam T
* @param self
* @param other
* @return constexpr Vec3f
* @return constexpr Vec3
*/
template <typename T>
constexpr Vec3<T> Max(const Vec3<T>& self, const Vec3<T>& other) {
@@ -165,10 +228,53 @@ constexpr Vec3<T> Max(const Vec3<T>& self, const Vec3<T>& other) {
};
}
/**
* @brief returns the coordinate-wise maximum of the given vectors,
* where a coordinate in the returned vector is NAN iff both of the two compared ones are NAN
*
* @tparam T
* @param self
* @param other
* @return constexpr Vec3
*/
constexpr Vec3f FMaxF(const Vec3f& self, const Vec3f& other) {
return {
std::fmaxf(self.x, other.x),
std::fmaxf(self.y, other.y),
std::fmaxf(self.z, other.z),
};
}
/**
* @brief lane-wise copysign
*/
constexpr Vec3f CopysignF(const Vec3f& v, const Vec3f& signs) {
return {
std::copysignf(v.x, signs.x),
std::copysignf(v.y, signs.y),
std::copysignf(v.z, signs.z),
};
}
/**
* @brief lane-wise copysign
*/
constexpr Vec3d Copysign(const Vec3d& v, const Vec3d& signs) {
return {
std::copysign(v.x, signs.x),
std::copysign(v.y, signs.y),
std::copysign(v.z, signs.z),
};
}
//////////////////////////////////////////////////////////////////
// Matricies //
// Matrices //
//////////////////////////////////////////////////////////////////
/**
* \brief Returns the dot product of the matrix and the vector
* \return the dot product of the matrix and the vector
*/
template <typename T>
Vec4<T> Dot(const Mat4<T>& mat, const Vec4<T>& vect) {
return {mat.x0 * vect.x + mat.x1 * vect.y + mat.x2 * vect.z + mat.x3 * vect.w,
@@ -177,6 +283,10 @@ Vec4<T> Dot(const Mat4<T>& mat, const Vec4<T>& vect) {
mat.w0 * vect.x + mat.w1 * vect.y + mat.w2 * vect.z + mat.w3 * vect.w};
}
/**
* \brief Returns the dot product of the matrix and an other matrix
* \return the dot product of the matrix and the other matrix
*/
template <typename T>
Mat4<T> Dot(const Mat4<T>& mat, const Mat4<T>& other) {
Mat4<T> result{};
@@ -192,6 +302,10 @@ Mat4<T> Dot(const Mat4<T>& mat, const Mat4<T>& other) {
return result;
}
/**
* \brief Returns the identity matrix
* \return the identity matrix
*/
template <typename T>
Mat4<T> Identity() {
Mat4<T> result{};
@@ -204,6 +318,10 @@ Mat4<T> Identity() {
return result;
}
/**
* \brief Returns the transposed matrix
* \return the transposed matrix
*/
template <typename T>
Mat4<T> Transpose(const Mat4<T>& mat) {
Mat4<T> result;
@@ -228,22 +346,88 @@ Mat4<T> Transpose(const Mat4<T>& mat) {
return result;
}
/**
* \brief Returns the perspective matrix
* \param fovY The field of view in the y direction
* \param aspectRatio The aspect ratio of the screen
* \param zNear The near clipping plane
* \param zFar The far clipping plane
* \return the perspective matrix
*/
Mat4f Perspective(float fovY, float aspectRatio, float zNear, float zFar);
/**
* \brief Returns the look matrix
* \param eyePos The position of the camera
* \param front The front vector of the camera
* \param up The up vector of the camera
* \return the look matrix
*/
Mat4f Look(const Vec3f& eyePos, const Vec3f& front, const Vec3f& up);
/**
* \brief Returns the inverse of the matrix
* \return the inverse of the matrix
*/
Mat4f Inverse(const Mat4f& mat);
/**
* \brief Returns the translation matrix
* \param translation The translation vector
* \return the translation matrix
*/
Mat4f Translate(const Vec3f& translation);
/**
* \brief Returns the scale matrix
* \param axisFactor The scaling factor for each axis
* \return the scale matrix
*/
Mat4f Scale(const Vec3f& axisFactor);
/**
* \brief Returns the rotation matrix around the x axis
* \param angle The angle of rotation
* \return the rotation matrix
*/
Mat4f RotateX(float angle);
/**
* \brief Returns the rotation matrix around the y axis
* \param angle The angle of rotation
* \return the rotation matrix
*/
Mat4f RotateY(float angle);
/**
* \brief Returns the rotation matrix around the z axis
* \param angle The angle of rotation
* \return the rotation matrix
*/
Mat4f RotateZ(float angle);
/**
* \brief Returns the rotation matrix
* \param angles The angles of rotation
* \return the rotation matrix
*/
Mat4f Rotate(const Vec3f& angles);
/**
* \brief Returns the rotation matrix
* \param angle The angle of rotation
* \param axis The axis of rotation
* \return the rotation matrix
*/
Mat4f Rotate(float angle, Vec3f axis);
/**
* \brief Returns the unit vector correspond to the yaw and pitch
* \param yaw Angle in radians
* \param pitch Angle in radians
*/
Vec3f GetDirectionVectorFromRotation(float yaw, float pitch);
} // namespace maths
} // namespace blitz

View File

@@ -1,30 +1,149 @@
#pragma once
#include "blitz/maths/Vector.h"
/**
* \file Physics.h
* \brief Physics logic
*/
#include "blitz/maths/Maths.h"
#include <optional>
namespace blitz {
namespace maths {
struct Ray {
Vec3f origin;
Vec3f direction;
/**
* \enum Axis
* \brief represents an axis in 3-dimensional space
*/
enum Axis : std::size_t { aX = 0, aY, aZ };
/**
* \brief encodes the movement an entity must perform, in an environment containing other
* entitis it may collide with
*/
struct CollisionData {
/**
* \brief the effective movement the entity can/should perform, immediately
*/
Vec3f delta;
/**
* \brief the direction of "slide" along a side of a bounding
* box, this is 0 if no collisions occured
*/
Vec3f slide;
};
/**
* \struct IntersectionData
* \brief Intermediate data encoding an intersection between a Ray/AABB and an AABB
*/
struct IntersectionData {
/**
* \brief by how much to translate before intersecting with the AABB
*/
float distance;
/**
* \brief the axis along which the collision happens, used to solve sliding requirements
*/
Axis axis;
/**
* \brief Returns the movements that the entity must perform. It is advised to make sure
* `0.0f <= distance <= 1.0f` as this would return incoherent data
* \pre `0.0f <= distance <= 1.0f`
* \param dir
* \return
*/
CollisionData ToCollision(const Vec3f& dir) const;
};
/**
* \struct AABB
* \brief an Axis Aligned Bounding Box, see wikipedia for more
*/
struct AABB {
Vec3f from;
Vec3f to;
/**
* \return A vector representing the center of mass of the box
*/
inline Vec3f Center() const;
/**
* \return The same box but all the coordinates in `from` are less than their
* counterparts in `to`.
*/
AABB Direct() const;
/**
* \brief Enlarges this box along each axis by the length of the box along said axis
* \param with
* \return The new, big, box
*
*/
AABB Enlarge(const AABB& with) const;
AABB operator+(const Vec3f& offset) const;
AABB operator+=(const Vec3f& offset);
/**
* \brief checks if this box overlaps with another one
* \param aabb
* \return whether this box overlaps with another one
*/
bool OverlapsWith(const AABB& aabb) const;
/**
* \brief Given this box is to be offset by some vector colinear to dir,
* this function behave exactly like Ray::Intersection
* \param aabb
* \param dir
* \return
*/
std::optional<IntersectionData> Intersection(const AABB& aabb, const Vec3f& dir) const;
};
inline AABB operator+(const AABB& aabb, const Vec3f& offset) {
AABB result = aabb;
result.from += offset;
result.to += offset;
return result;
}
/**
* \struct Ray
* \brief represents a (half-)line
*/
struct Ray {
/**
* \brief the origin/start/initial point of the line
*/
Vec3f origin;
/**
* \brief the direction of the line
*/
Vec3f direction;
float Distance(const Ray& ray, const AABB& aabb);
/**
* \brief Note that t isn't necessarily positive
* \param t
* \return `origin` + `direction` * `t`
*/
Vec3f operator()(float t) const;
bool Intersects(const Ray& ray, const AABB& aabb);
/**
* \brief Is essentially Intersection(aabb).distance >= 0.0f
* \returns `true` if the half-line `ray` _strictly_ intersects with `aabb`,
* and `false` if it _strictly_ doesn't intersect.
* Note that if it only intersects with corners, edges, or sides of the box,
* or if any coordinate in `ray` is `NAN` or `inf` or if any coordinate in
* `aabb` is `NAN` the result is unspecified.
*/
bool Intersects(const AABB& aabb) const;
/**
* \brief The `distance` field of the returned value is smallest number t
* (in absolute value), if it exists, such that `ray(t)` is in `aabb`. otherwise
* a quiet `NaN` is returned. The `axis` field is the axis to along
* which `ray` intersects/collides with `aabb`
*/
std::optional<IntersectionData> Intersection(const AABB& aabb) const;
};
} // namespace maths
} // namespace blitz

View File

@@ -1,7 +1,11 @@
#pragma once
/**
* \file Vector.h
* \brief File containing the Vector structs and 4x4 matrix
*/
#include <algorithm>
#include <cmath>
#include <cstddef>
namespace blitz {
@@ -43,6 +47,34 @@ struct Vec3 {
};
constexpr Vec3(T X = 0, T Y = 0, T Z = 0) : x(X), y(Y), z(Z) {}
static Vec3 splat(T val) {
return Vec3(val, val, val);
}
const T* data() const {
return reinterpret_cast<const T*>(this);
}
T* data() {
return reinterpret_cast<T*>(this);
}
const T& at(std::size_t index) const {
return data()[index];
}
T& at(std::size_t index) {
return data()[index];
}
const T& operator[](std::size_t index) const {
return at(index);
}
T& operator[](std::size_t index) {
return at(index);
}
};
template <typename T>
@@ -91,10 +123,6 @@ using Vec4d = Vec4<double>;
using Color = Vec3uc;
// Vec2
template <typename T>
@@ -139,10 +167,6 @@ constexpr Vec2<T> operator*(T mult, const Vec2<T>& vect) {
return vect * mult;
}
// Vec3
template <typename T>
@@ -221,11 +245,6 @@ Vec3<T>& operator/=(Vec3<T>& vect, const Vec3<T>& other) {
return vect;
}
template <typename T>
constexpr bool operator<(const Vec3<T>& vec3, const Vec3<T>& other) {
return vec3.x < other.x && vec3.y < other.y && vec3.z < other.z;
}
// Vec4
template <typename T>

View File

@@ -1,63 +1,88 @@
#pragma once
/**
* \file Easing.h
* \brief File containing mathematical functions and constants
*/
namespace blitz {
namespace utils {
/* Sine functions */
/**
* \brief Sine functions
*/
float EaseInSine(float x);
float EaseOutSine(float x);
float EaseInOutSine(float x);
/* Cubic functions */
/**
* \brief Cubic functions
*/
float EaseInCubic(float x);
float EaseOutCubic(float x);
float EaseInOutCubic(float x);
/* Quint functions */
/**
* \brief Quint functions
*/
float EaseInQuint(float x);
float EaseOutQuint(float x);
float EaseInOutQuint(float x);
/* Circ functions */
/**
* \brief Circ functions
*/
float EaseInCirc(float x);
float EaseOutCirc(float x);
float EaseInOutCirc(float x);
/* Elastic functions */
/**
* \brief Elastic functions
*/
float EaseInElastic(float x);
float EaseOutElastic(float x);
float EaseInOutElastic(float x);
/* Quad functions */
/**
* \brief Quad functions
*/
float EaseInQuad(float x);
float EaseOutQuad(float x);
float EaseInOutQuad(float x);
/* Quart functions */
/**
* \brief Quart functions
*/
float EaseInQuart(float x);
float EaseOutQuart(float x);
float EaseInOutQuart(float x);
/* Expo functions */
/**
* \brief Expo functions
*/
float EaseInExpo(float x);
float EaseOutExpo(float x);
float EaseInOutExpo(float x);
/* Back functions */
/**
* \brief Back functions
*/
float EaseInBack(float x);
float EaseOutBack(float x);
float EaseInOutBack(float x);
/* Bounce functions */
/**
* \brief Bounce functions
*/
float EaseInBounce(float x);
float EaseOutBounce(float x);

View File

@@ -1,5 +1,10 @@
#pragma once
/**
* \file Format.h
* \brief This file contains the definition of the `Format` function.
*/
#include <memory>
#include <stdexcept>
#include <string>
@@ -7,6 +12,17 @@
namespace blitz {
namespace utils {
/**
* \brief Formats a string using a format string and variadic arguments.
*
* This function takes a format string and a variable number of arguments and returns a formatted string.
* The format string can contain placeholders that will be replaced by the corresponding arguments.
*
* \param format The format string.
* \param args The variadic arguments to be formatted.
* \return The formatted string.
* \throws std::runtime_error if an error occurs during formatting.
*/
template <typename... Args>
std::string Format(const std::string& format, Args... args) {
int size = snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'

View File

@@ -1,13 +1,32 @@
#pragma once
/**
* \file Log.h
* \brief File defining log functions
*/
#include <string>
namespace blitz {
namespace utils {
void LOG(const std::string& msg); // Normal
void LOGD(const std::string& msg); // Normal en mode debug
void LOGE(const std::string& err); // Normal erreur
/**
* \brief Logs a normal message.
* \param msg The message to be logged.
*/
void LOG(const std::string& msg);
/**
* \brief Logs a normal message in debug mode.
* \param msg The message to be logged.
*/
void LOGD(const std::string& msg);
/**
* \brief Logs an error message.
* \param err The error message to be logged.
*/
void LOGE(const std::string& err);
} // namespace utils
} // namespace blitz

View File

@@ -1,5 +1,10 @@
#pragma once
/**
* \file ObjectNotifier.h
* \brief File containing the blitz::ObjectNotifier class
*/
#include <algorithm>
#include <functional>
#include <vector>
@@ -7,16 +12,26 @@
namespace blitz {
namespace utils {
/**
* \class ObjectNotifier
* \brief Class used to notify listeners
*/
template <typename Listener>
class ObjectNotifier {
protected:
std::vector<Listener*> m_Listeners;
public:
/**
* \brief Binds a listener to notify later
*/
void BindListener(Listener* listener) {
m_Listeners.push_back(listener);
}
/**
* \brief Unbinds a listener (in case the listener is destroyed for example)
*/
void UnbindListener(Listener* listener) {
auto iter = std::find(m_Listeners.begin(), m_Listeners.end(), listener);
@@ -26,8 +41,11 @@ class ObjectNotifier {
m_Listeners.erase(iter);
}
/**
* \brief Notify listeners that were bound
*/
template <typename Func, typename... Args>
void NotifyListeners(Func function, Args... args) {
void NotifyListeners(Func function, Args... args) const {
for (Listener* listener : m_Listeners)
std::bind(function, listener, args...)();
}

View File

@@ -1,5 +1,10 @@
#pragma once
/**
* \file PrettyLog.h
* \brief File defining log functions with colors
*/
#include "blitz/maths/Vector.h"
#include <string>
@@ -18,7 +23,13 @@ const static Vec3uc YELLOW = {255, 255, 0};
} // namespace TextColor
/**
* \brief Returns the color code for a given color.
*/
std::string GetTextColor(Vec3uc color);
/**
* \brief Returns the color code for the reset color.
*/
std::string GetTextColorReset();
} // namespace utils

View File

@@ -1,10 +1,21 @@
#pragma once
/**
* \file Random.h
* \brief Defines functions for generating random numbers.
*/
#include <random>
namespace blitz {
namespace utils {
/**
* \brief Returns a random integer between min and max.
* \param min The minimum value.
* \param max The maximum value.
* \return A random integer between min and max.
*/
template <typename NumberType>
NumberType GetRandomInt(NumberType min, NumberType max) {
std::random_device randomDevice;
@@ -13,6 +24,12 @@ NumberType GetRandomInt(NumberType min, NumberType max) {
return distrib(generator);
}
/**
* \brief Returns a random real number between min and max.
* \param min The minimum value.
* \param max The maximum value.
* \return A random real number between min and max.
*/
template <typename NumberType>
NumberType GetRandomReal(NumberType min, NumberType max) {
std::random_device randomDevice;

View File

@@ -10,7 +10,16 @@
namespace blitz {
namespace utils {
/**
* \def BLITZ_TEST_SUCCESSFUL
* \brief Used in tests to indicate that a test was successful
*/
#define BLITZ_TEST_SUCCESSFUL 0
/**
* \def BLITZ_TEST_FAILED
* \brief Used in tests to indicate that a test failed
*/
#define BLITZ_TEST_FAILED 1
#ifndef __FUNCTION_NAME__
@@ -24,7 +33,8 @@ namespace utils {
/**
* \def blitz_test_assert
* \param ... The expression to evaluate
* \brief Evaluates the expression and exits the program if not valid
* \brief Evaluates the expression and exits the program if not valid.
* \note It works like a basic assert() but also in release mode
*/
#define blitz_test_assert(...) \
if (!static_cast<bool>(__VA_ARGS__)) { \
@@ -37,6 +47,7 @@ namespace utils {
* \def blitz_debug_assert
* \param ... The expression to execute
* \brief Assertion without checks in release mode
* \note The expression is always executed. However, in release, no checks are made !
*/
#ifdef NDEBUG
#define blitz_debug_assert(...) __VA_ARGS__

View File

@@ -1,10 +1,19 @@
#pragma once
/**
* \file TickCounter.h
* \brief File containing the blitz::utils::TickCounter class
*/
#include <cstdint>
namespace blitz {
namespace utils {
/**
* \class TickCounter
* \brief Class used to count ticks
*/
class TickCounter {
private:
float m_TPS;
@@ -14,19 +23,42 @@ class TickCounter {
int m_TargetTPS;
public:
/**
* \brief Constructor
* \param tps The target ticks per second
*/
TickCounter(int tps) : m_TargetTPS(tps) {}
/**
* \brief Reset the tick counter
*/
void Reset();
bool Update(); // return true when tps is updated
/**
* \brief Update the tick counter
* \return True if the tick counter has been updated
*/
bool Update();
/**
* \brief Get the ticks per second
* \return The ticks per second
*/
float GetTPS() const {
return m_TPS;
}
/**
* \brief Get the milliseconds per tick
* \return The milliseconds per tick
*/
float GetMSPT() const {
return m_MSPT;
}
/**
* \brief Set the ticks per second
* \param mspt The ticks per second
*/
void SetMSPT(float mspt) {
m_MSPT = mspt;
}

View File

@@ -1,5 +1,11 @@
#pragma once
/**
* \file Time.h
* \brief File containing the blitz::utils::AutoTimer, blitz::utils::Timer, blitz::utils::CooldownTimer and blitz::utils::DelayTimer
* classes
*/
#include <algorithm>
#include <cstdint>
#include <functional>
@@ -7,11 +13,18 @@
namespace blitz {
namespace utils {
/**
* \brief Get current time
* \return Time elapsed since epoch in milliseconds
*/
std::uint64_t GetTime();
typedef std::function<void()> TimerExecFunction;
// utililty class to call a function at regular period of time
/**
* \class AutoTimer
* \brief Calls a function at regular period of time
*/
class AutoTimer {
private:
std::uint64_t m_Interval;
@@ -21,65 +34,136 @@ class AutoTimer {
std::uint64_t m_InternalTime = 0;
public:
/**
* \brief Default constructor
*/
AutoTimer() : m_Interval(0), m_Function(nullptr) {}
/**
* \param interval Time between each function call in milliseconds
*/
AutoTimer(std::uint64_t interval) : m_Interval(interval), m_Function(nullptr) {}
/**
* \param interval Time between each function call in milliseconds
* \param callback The function to call peridocally
*/
AutoTimer(std::uint64_t interval, TimerExecFunction callback) : m_Interval(interval), m_Function(callback) {}
/**
* \brief Updates the timer
*/
void Update();
/**
* \brief Updates the timer with the desired time step
* \param delta The time step in milliseconds
*/
void Update(std::uint64_t delta);
/**
* \brief Resets the internal cooldown
*/
void Reset();
/**
* \brief Sets a new interval
* \param newInterval the new interval in milliseconds
*/
void SetInterval(std::uint64_t newInterval) {
m_Interval = newInterval;
}
/**
* \return The interval between each callback in milliseconds
*/
std::uint64_t GetInterval() const {
return m_Interval;
}
/**
* \brief Set a new callback function
* \param newCallback The function to call
*/
void SetCallbackFunction(TimerExecFunction newCallback) {
m_Function = newCallback;
}
/**
* \return The callback function
*/
TimerExecFunction GetCallbackFunction() const {
return m_Function;
}
};
// utililty class to trigger update at regular period of time
/**
* \class Timer
* \brief Utililty class to trigger update at regular period of time
*/
class Timer {
private:
std::uint64_t m_Interval; // in millis
std::uint64_t m_InternalTime = 0;
public:
/**
* \brief Default constructor
*/
Timer() : m_Interval(0) {}
/**
* \brief Construct a Timer with the desired interval
* \param interval The interval between each update in milliseconds
*/
Timer(std::uint64_t interval) : m_Interval(interval) {}
/**
* \brief Updates the timer
* \param delta The time step in milliseconds
* \return true every interval milliseconds
*/
bool Update(std::uint64_t delta);
/**
* \brief Resets the timer to its original state
*/
void Reset();
// void ResetSoft(); // don't trigger the timer
/**
* \return The time remaing before the next Update() call will return true (in milliseconds)
*/
std::uint64_t GetTimeRemaining() const {
return m_Interval - m_InternalTime;
}
/**
* \return The time elapsed since the previous Update() call returned true (in milliseconds)
*/
std::uint64_t GetTimeElapsed() const {
return m_InternalTime;
}
/**
* \brief Set a new value for the interval
* \param newInterval the new interval to set
*/
void SetInterval(std::uint64_t newInterval) {
m_Interval = newInterval;
}
/**
* \return The interval between each successful Update()
*/
std::uint64_t GetInterval() const {
return m_Interval;
}
};
// utililty class to trigger update at regular period of time with a cooldown
/**
* \class CooldownTimer
* \brief Class to trigger update at regular period of time with a cooldown
*/
template <typename T>
class CooldownTimer {
private:
@@ -87,9 +171,20 @@ class CooldownTimer {
T m_CooldownTime;
public:
/**
* \brief Default constructor
*/
CooldownTimer() : m_Cooldown(0), m_CooldownTime(0) {}
/**
* \param cooldown The cooldown before Update() returns true again
*/
CooldownTimer(T cooldown) : m_Cooldown(0), m_CooldownTime(cooldown) {}
/**
* \brief Update the timer
* \param delta the time step
*/
bool Update(T delta) {
if (m_Cooldown > 0) {
m_Cooldown = std::max<T>(static_cast<T>(0), static_cast<T>(m_Cooldown - delta));
@@ -97,24 +192,40 @@ class CooldownTimer {
return m_Cooldown == 0;
}
/**
* \brief Apply a cooldown for the timer
*/
void ApplyCooldown() {
m_Cooldown = m_CooldownTime;
}
/**
* \brief Reset the cooldown. Update() will return true immediatly afterward.
*/
void Reset() {
m_Cooldown = 0;
}
/**
* \brief Change the timer cooldown
* \param newCooldown the new cooldown
*/
void SetCooldown(T newCooldown) {
m_CooldownTime = newCooldown;
}
/**
* \return The cooldown of the timer
*/
T GetCooldown() const {
return m_CooldownTime;
}
};
// utililty class to trigger update at regular period of time with a cooldown
/**
* \class DelayTimer
* \brief class to trigger an update after a period of time
*/
template <typename T>
class DelayTimer {
private:
@@ -122,7 +233,14 @@ class DelayTimer {
T m_InternalTime;
public:
/**
* \brief Default constructor
*/
DelayTimer() : m_DelayTime(0), m_InternalTime(0) {}
/**
* \param delay The delay to set
*/
DelayTimer(T delay) : m_DelayTime(delay), m_InternalTime(delay) {}
/**
@@ -134,16 +252,23 @@ class DelayTimer {
}
/**
* \brief Resets the timer
* \brief Resets the timer. Update() will immediatly return true
*/
void Reset() {
m_InternalTime = m_DelayTime;
}
/**
* \brief Changes the delay of the timer
* \param newDelay the new delay
*/
void SetDelay(T newDelay) {
m_DelayTime = newDelay;
}
/**
* \return the delay of the timer
*/
T GetDelay() const {
return m_DelayTime;
}

View File

@@ -56,7 +56,7 @@ class Connexion : public protocol::PacketHandler, private NonCopyable {
/**
* \brief Tries to connect the socket at the specified address and port
* \return Wether this action was succesfull
* \return Whether this action was succesfull
*/
bool Connect(const std::string& address, std::uint16_t port);

View File

@@ -35,7 +35,7 @@ class TCPListener : private NonCopyable {
* \param port The port to listen to
* \param maxConnexions The maximum amount of connexion that can happen at the same time. \n
* Every other guests will be kicked if this amount is reached.
* \return Wether this action was succesfull
* \return Whether this action was succesfull
*/
bool Listen(std::uint16_t port, int maxConnexions);

View File

@@ -1,5 +1,11 @@
#pragma once
/**
* \file PacketDispatcher.h
* \brief File containing the blitz::protocol::PacketDispatcher class
*/
#include "blitz/common/NonCopyable.h"
#include "blitz/protocol/Protocol.h"
#include <map>
@@ -9,22 +15,42 @@ namespace protocol {
class PacketHandler;
class PacketDispatcher {
/**
* \class PacketDispatcher
* \brief Class used to dispatch packets
*/
class PacketDispatcher : private NonCopyable {
private:
std::map<PacketType, std::vector<PacketHandler*>> m_Handlers;
public:
PacketDispatcher() = default;
PacketDispatcher(const PacketDispatcher& rhs) = delete;
PacketDispatcher& operator=(const PacketDispatcher& rhs) = delete;
PacketDispatcher(PacketDispatcher&& rhs) = delete;
PacketDispatcher& operator=(PacketDispatcher&& rhs) = delete;
/**
* \brief Constructor
*/
PacketDispatcher() {}
/**
* \brief Dispatch a packet
* \param packet The packet to dispatch
*/
void Dispatch(const Packet* packet);
/**
* \brief Register a packet handler
* \param type The packet type
* \param handler The packet handler
*/
void RegisterHandler(PacketType type, PacketHandler* handler);
/**
* \brief Unregister a packet handler
* \param type The packet type
* \param handler The packet handler
*/
void UnregisterHandler(PacketType type, PacketHandler* handler);
/**
* \brief Unregister a packet handler
* \param handler The packet handler
*/
void UnregisterHandler(PacketHandler* handler);
};

View File

@@ -1,13 +1,22 @@
#pragma once
/**
* \file PacketFactory.h
*/
#include "blitz/protocol/Protocol.h"
namespace blitz {
namespace protocol {
namespace PacketFactory {
/**
* \brief Creates a packet from a buffer.
* \param buffer The buffer containing the packet data.
* \return The created packet.
*/
const Packet* CreatePacket(PacketType type, DataBuffer& buffer);
}
} // namespace PacketFactory
} // namespace protocol
} // namespace blitz

View File

@@ -1,5 +1,10 @@
#pragma once
/**
* \file PacketHandler.h
* \brief File containing the blitz::protocol::PacketHandler class
*/
#include "blitz/protocol/PacketsForward.h"
#include "blitz/protocol/Protocol.h"
@@ -8,14 +13,26 @@ namespace protocol {
class PacketDispatcher;
/**
* \class PacketHandler
* \brief Class used to handle packets
*/
class PacketHandler {
private:
PacketDispatcher* m_Dispatcher;
public:
/**
* \brief Constructor
* \param dispatcher The packet dispatcher
*/
PacketHandler(PacketDispatcher* dispatcher) : m_Dispatcher(dispatcher) {}
virtual ~PacketHandler() {}
/**
* \brief Get the packet dispatcher
* \return The packet dispatcher
*/
PacketDispatcher* GetDispatcher() {
return m_Dispatcher;
}

View File

@@ -2,7 +2,7 @@
/**
* \file Protocol.h
* \brief File describing protocol
* \brief File containing the blitz::protocol::Protocol class
*/
#include "blitz/common/DataBuffer.h"

View File

@@ -1,5 +1,10 @@
#pragma once
/**
* \file ChatPacket.h
* \brief File containing the blitz::protocol::ChatPacket class
*/
#include "blitz/maths/Vector.h"
#include "blitz/protocol/Protocol.h"
#include <vector>
@@ -7,20 +12,53 @@
namespace blitz {
namespace protocol {
/**
* \struct ColoredPart
* \brief Represents a part of a chat message with a specific color.
*/
struct ColoredPart {
/**
* \brief The color of the part.
*/
Vec4f color;
/**
* \brief The text of the part.
*/
std::string text;
};
typedef std::vector<ColoredPart> ColoredText;
/**
* \class ChatPacket
* \brief Packet for sending chat messages.
* %Packet structure :
* | PacketType |
* |------------------------|
* | PacketType::Chat |
*
* | Field Name | Field Type | Notes |
* |--------------------|-------------------|-------------------------------|
* | m_Message | ColoredText | The message sent in the chat |
*/
class ChatPacket : public Packet {
private:
ColoredText m_Message;
public:
/**
* \brief Default constructor.
*/
ChatPacket() {}
/**
* \brief Constructor.
* \param msg The message to send.
*/
ChatPacket(const std::string& msg) : m_Message(ColorizeText(msg)) {}
/**
* \brief Constructor.
* \param msg The message to send.
*/
ChatPacket(const ColoredText& msg) : m_Message(msg) {}
virtual ~ChatPacket() {}
@@ -28,6 +66,10 @@ class ChatPacket : public Packet {
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
/**
* \brief Get the message.
* \return The message.
*/
const ColoredText& GetMessage() const {
return m_Message;
}
@@ -36,8 +78,17 @@ class ChatPacket : public Packet {
return PacketType::Chat;
}
/**
* \brief Get the text color.
*/
static std::string GetTextColor(Vec3uc color);
/**
* \brief Colorize a text.
*/
static ColoredText ColorizeText(const std::string& text);
/**
* \brief Get the colored text string.
*/
static std::string GetColoredTextString(const ColoredText& text);
};

View File

@@ -1,16 +1,40 @@
#pragma once
/**
* \file ConnexionInfoPacket.h
* \brief File containing the blitz::protocol::ConnexionInfoPacket class
*/
#include "blitz/protocol/Protocol.h"
namespace blitz {
namespace protocol {
/**
* \class ConnexionInfoPacket
* \brief Packet for sending connection information.
* %Packet structure :
* | PacketType |
* |------------------------|
* | PacketType::ConnexionInfo |
*
* | Field Name | Field Type | Notes |
* |--------------------|-------------------|-------------------------------|
* | m_ConnectionID | std::uint8_t | The connection ID |
*/
class ConnexionInfoPacket : public Packet {
private:
std::uint8_t m_ConnectionID;
public:
/**
* \brief Default constructor.
*/
ConnexionInfoPacket() {}
/**
* \brief Constructor.
* \param connectionID The ID of the connection.
*/
ConnexionInfoPacket(std::uint8_t connectionID) : m_ConnectionID(connectionID) {}
virtual ~ConnexionInfoPacket() {}
@@ -18,6 +42,10 @@ class ConnexionInfoPacket : public Packet {
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
/**
* \brief Get the connection ID.
* \return The connection ID.
*/
std::uint8_t GetConnectionID() const {
return m_ConnectionID;
}

View File

@@ -1,15 +1,39 @@
#pragma once
/**
* \file DisconnectPacket.h
* \brief File containing the blitz::protocol::DisconnectPacket class
*/
#include "blitz/protocol/Protocol.h"
namespace blitz {
namespace protocol {
/**
* \class DisconnectPacket
* \brief Packet for disconnecting from the server.
* %Packet structure :
* | PacketType |
* |------------------------|
* | PacketType::Disconnect |
*
* | Field Name | Field Type | Notes |
* |--------------------|-------------------|-------------------------------|
* | m_Reason | std::string | The reason for disconnection |
*/
class DisconnectPacket : public Packet {
private:
std::string m_Reason; // only when sent from server
public:
/**
* \brief Default constructor.
*/
DisconnectPacket() {}
/**
* \brief Constructor.
* \param reason The reason for disconnection.
*/
DisconnectPacket(std::string reason) : m_Reason(reason) {}
virtual ~DisconnectPacket() {}
@@ -17,6 +41,10 @@ class DisconnectPacket : public Packet {
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
/**
* \brief Get the reason for disconnection.
* \return The reason for disconnection.
*/
const std::string& GetReason() const {
return m_Reason;
}

View File

@@ -13,14 +13,14 @@ namespace protocol {
/**
* \class KeepAlivePacket
* \brief %Packet sent to measure the health of a connexion. \n
* \brief Packet sent to measure the health of a connexion. \n
* The client must respond with the same alive ID. Else, the connexion will be closed. \n
* %Packet structure :
* %Packet structure :
* | PacketType |
* |------------------------|
* | PacketType::KeepAlive |
*
* | Field Name | Field Type | Notes |
*
* | Field Name | Field Type | Notes |
* |--------------------|---------------|---------------------------------------------------------------------------|
* | Keep Alive ID | VarInt | The server generates a random ID, the client must respond with the same |
*

View File

@@ -13,7 +13,7 @@ namespace protocol {
/**
* \class PlayerJoinPacket
* \brief %Packet sent when a new player joins the game \n
* \brief Packet sent when a new player joins the game
* %Packet structure :
* | PacketType |
* |------------------------|

View File

@@ -1,24 +1,53 @@
#pragma once
/**
* \file PlayerLeavePacket.h
* \brief File containing the blitz::protocol::PlayerLeavePacket class
*/
#include "blitz/common/Defines.h"
#include "blitz/protocol/Protocol.h"
namespace blitz {
namespace protocol {
/**
* \class PlayerLeavePacket
* \brief Packet for when a player leaves the game.
* %Packet structure :
* | PacketType |
* |------------------------|
* | PacketType::PlayerLeave|
*
* | Field Name | Field Type | Notes |
* |--------------------|-------------------|-------------------------------|
* | m_PlayerID | PlayerID |The ID of the player that left |
*/
class PlayerLeavePacket : public Packet {
private:
std::uint8_t m_PlayerID;
game::PlayerID m_PlayerID;
public:
/**
* \brief Default constructor.
*/
PlayerLeavePacket() {}
PlayerLeavePacket(std::uint8_t playerID) : m_PlayerID(playerID) {}
/**
* \brief Constructor.
* \param playerID The ID of the player that left.
*/
PlayerLeavePacket(game::PlayerID playerID) : m_PlayerID(playerID) {}
virtual ~PlayerLeavePacket() {}
virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
std::uint8_t GetPlayerID() const {
/**
* \brief Get the ID of the player that left.
* \return The ID of the player that left.
*/
game::PlayerID GetPlayerID() const {
return m_PlayerID;
}

View File

@@ -1,5 +1,10 @@
#pragma once
/**
* \file PlayerListPacket.h
* \brief File containing the blitz::protocol::PlayerListPacket class
*/
#include <map>
#include "blitz/protocol/Protocol.h"
@@ -7,18 +12,34 @@
namespace blitz {
namespace protocol {
/**
* \struct PlayerInfo
* \brief Represents information about a player.
*/
struct PlayerInfo {
std::string name;
};
typedef std::map<std::uint8_t, PlayerInfo> PlayerList;
/**
* \class PlayerListPacket
* \brief Packet for sending the list of players.
* \todo PACKET STRUCTURE
*/
class PlayerListPacket : public Packet {
private:
PlayerList m_Players;
public:
/**
* \brief Default constructor.
*/
PlayerListPacket() {}
/**
* \brief Constructor.
* \param players The list of players.
*/
PlayerListPacket(const PlayerList& players) : m_Players(players) {}
virtual ~PlayerListPacket() {}
@@ -26,6 +47,11 @@ class PlayerListPacket : public Packet {
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
/**
* \brief Get the list of players.
* \return The list of players.
*/
const PlayerList& GetPlayers() const {
return m_Players;
}

View File

@@ -1,16 +1,40 @@
#pragma once
/**
* \file PlayerLoginPacket.h
* \brief File containing the blitz::protocol::PlayerLoginPacket class
*/
#include "blitz/protocol/Protocol.h"
namespace blitz {
namespace protocol {
/**
* \class PlayerLoginPacket
* \brief Packet for when a player logs in.
* %Packet structure :
* | PacketType |
* |------------------------|
* | PacketType::PlayerLogin|
*
* | Field Name | Field Type | Notes |
* |--------------------|-------------------|----------------------------------|
* | Player Name | std::string | Name of the player that logged in|
*/
class PlayerLoginPacket : public Packet {
private:
std::string m_PlayerName;
public:
/**
* \brief Default constructor.
*/
PlayerLoginPacket() {}
/**
* \brief Constructor.
* \param playerName The name of the player that logged in.
*/
PlayerLoginPacket(std::string playerName) : m_PlayerName(playerName) {}
virtual ~PlayerLoginPacket() {}
@@ -18,13 +42,17 @@ class PlayerLoginPacket : public Packet {
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
virtual PacketType GetType() const {
return PacketType::PlayerLogin;
}
/**
* \brief Get the name of the player that logged in.
* \return The name of the player that logged in.
*/
const std::string& GetPlayerName() const {
return m_PlayerName;
}
virtual PacketType GetType() const {
return PacketType::PlayerLogin;
}
};
} // namespace protocol

View File

@@ -1,5 +1,10 @@
#pragma once
/**
* \file PlayerPositionAndRotationPacket.h
* \brief File containing the blitz::protocol::PlayerPositionAndRotationPacket class
*/
#include "blitz/common/Defines.h"
#include "blitz/maths/Vector.h"
#include "blitz/protocol/Protocol.h"
@@ -7,6 +12,21 @@
namespace blitz {
namespace protocol {
/**
* \class PlayerPositionAndRotationPacket
* \brief Packet for sending a player's position and rotation.
* %Packet structure :
* | PacketType |
* |--------------------------------|
* | PacketType::PlayerPositionAndRotation |
*
* | Field Name | Field Type | Notes |
* |--------------------|-------------------|----------------------------------|
* | Player ID | PlayerID | Id of the player who moved |
* | Position | Vec3f | Position of the player |
* | Yaw | float | Yaw of the player |
* | Pitch | float | Pitch of the player |
*/
class PlayerPositionAndRotationPacket : public Packet {
private:
game::PlayerID m_Player; // only used when sent to client
@@ -14,28 +34,53 @@ class PlayerPositionAndRotationPacket : public Packet {
float m_Yaw, m_Pitch;
public:
/**
* \brief Default constructor.
*/
PlayerPositionAndRotationPacket() {}
/**
* \brief Constructor.
* \param position The position of the player.
* \param yaw The yaw of the player.
* \param pitch The pitch of the player.
* \param player The ID of the player.
*/
PlayerPositionAndRotationPacket(const Vec3f& position, float yaw, float pitch, game::PlayerID player = 0) :
m_Player(player), m_Position(position), m_Yaw(yaw), m_Pitch(pitch) {}
virtual ~PlayerPositionAndRotationPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
/**
* \brief Get the position of the player.
* \return The position of the player.
*/
const Vec3f& GetPosition() const {
return m_Position;
}
/**
* \brief Get the yaw of the player.
* \return The yaw of the player.
*/
float GetYaw() const {
return m_Yaw;
}
/**
* \brief Get the pitch of the player.
* \return The pitch of the player.
*/
float GetPitch() const {
return m_Pitch;
}
/**
* \brief Get the ID of the player.
* \return The ID of the player.
*/
game::PlayerID GetPlayer() const {
return m_Player;
}

View File

@@ -1,11 +1,31 @@
#pragma once
/**
* \file PlayerShootPacket.h
* \brief File containing the blitz::protocol::PlayerShootPacket class
*/
#include "blitz/game/Player.h"
#include "blitz/protocol/Protocol.h"
namespace blitz {
namespace protocol {
/**
* \class PlayerShootPacket
* \brief Packet for when a player shoots.
* %Packet structure :
* | PacketType |
* |------------------------|
* | PacketType::PlayerShoot|
*
* | Field Name | Field Type | Notes |
* |--------------------|-------------------|----------------------------------|
* | Player ID | PlayerID | The ID of the player that shot |
* | Position | Vec3f | Position of the player |
* | Yaw | float | Yaw of the player |
* | Pitch | float | Pitch of the player |
*/
class PlayerShootPacket : public Packet {
private:
game::PlayerID m_Player; // only used when sent to client
@@ -13,7 +33,17 @@ class PlayerShootPacket : public Packet {
float m_Yaw, m_Pitch;
public:
/**
* \brief Default constructor.
*/
PlayerShootPacket() {}
/**
* \brief Constructor.
* \param position The position of the player.
* \param yaw The yaw of the player.
* \param pitch The pitch of the player.
* \param player The ID of the player.
*/
PlayerShootPacket(Vec3f position, float yaw, float pitch, game::PlayerID player = 0) :
m_Player(player), m_Position(position), m_Yaw(yaw), m_Pitch(pitch) {}
virtual ~PlayerShootPacket() {}
@@ -22,18 +52,34 @@ class PlayerShootPacket : public Packet {
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
/**
* \brief Get the position of the player.
* \return The position of the player.
*/
const Vec3f& GetPosition() const {
return m_Position;
}
/**
* \brief Get the yaw of the player.
* \return The yaw of the player.
*/
float GetYaw() const {
return m_Yaw;
}
/**
* \brief Get the pitch of the player.
* \return The pitch of the player.
*/
float GetPitch() const {
return m_Pitch;
}
/**
* \brief Get the ID of the player.
* \return The ID of the player.
*/
game::PlayerID GetPlayer() const {
return m_Player;
}

View File

@@ -1,5 +1,10 @@
#pragma once
/**
* \file PlayerStatsPacket.h
* \brief File containing the blitz::protocol::PlayerStatsPacket class
*/
#include "blitz/common/Defines.h"
#include "blitz/game/Player.h"
#include "blitz/protocol/Protocol.h"
@@ -7,13 +12,34 @@
namespace blitz {
namespace protocol {
/**
* \class PlayerStatsPacket
* \brief Packet for sending player stats.
* %Packet structure :
* | PacketType |
* |------------------------|
* | PacketType::PlayerStats|
*
* | Field Name | Field Type | Notes |
* |--------------------|-------------------|-------------------------------|
* | Player ID | PlayerID | Id of the player |
* | Player Stats | PlayerStats | Stats of the player |
*/
class PlayerStatsPacket : public Packet {
private:
game::PlayerID m_PlayerID;
game::PlayerStats m_PlayerStats;
public:
/**
* \brief Default constructor.
*/
PlayerStatsPacket() {}
/**
* \brief Constructor.
* \param playerID The ID of the player.
* \param stats The stats of the player.
*/
PlayerStatsPacket(game::PlayerID playerID, const game::PlayerStats& stats) : m_PlayerID(playerID), m_PlayerStats(stats) {}
virtual ~PlayerStatsPacket() {}

View File

@@ -1,17 +1,41 @@
#pragma once
/**
* \file ServerConfigPacket.h
* \brief File containing the blitz::protocol::ServerConfigPacket class
*/
#include "blitz/game/Game.h"
#include "blitz/protocol/Protocol.h"
namespace blitz {
namespace protocol {
/**
* \class ServerConfigPacket
* \brief Packet for sending the server configuration.
* %Packet structure :
* | PacketType |
* |-------------------------|
* | PacketType::ServerConfig|
*
* | Field Name | Field Type | Notes |
* |--------------------|-------------------|-------------------------------|
* | Game Config | GameConfig | The game configuration |
*/
class ServerConfigPacket : public Packet {
private:
game::GameConfig m_GameConfig;
public:
/**
* \brief Default constructor.
*/
ServerConfigPacket() {}
/**
* \brief Constructor.
* \param GameConfig The game configuration.
*/
ServerConfigPacket(const game::GameConfig& GameConfig) : m_GameConfig(GameConfig) {}
virtual ~ServerConfigPacket() {}
@@ -19,6 +43,10 @@ class ServerConfigPacket : public Packet {
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
/**
* \brief Getter of the game configuration
* \return The game configuration
*/
game::GameConfig GetGameConfig() const {
return m_GameConfig;
}

View File

@@ -1,17 +1,45 @@
#pragma once
/**
* \file ServerTpsPacket.h
* \brief File containing the blitz::protocol::ServerTpsPacket class
*/
#include "blitz/protocol/Protocol.h"
namespace blitz {
namespace protocol {
/**
* \class ServerTpsPacket
* \brief Packet for sending server TPS (Tick per second) and MSPT (Milliseconds per tick).
* %Packet structure :
* | PacketType |
* |------------------------|
* | PacketType::ServerTps |
*
* | Field Name | Field Type | Notes |
* |--------------------|-------------------|-------------------------------|
* | Tps | float | Server TPS |
* | Mspt | float | Server MSPT |
* | PacketSendTime | uint64_t | Time the packet was sent |
*/
class ServerTpsPacket : public Packet {
private:
float m_TPS;
float m_MSPT;
std::uint64_t m_PacketSendTime; // used to calculate ping
public:
/**
* \brief Default constructor.
*/
ServerTpsPacket() {}
/**
* \brief Constructor.
* \param tps The server TPS.
* \param mspt The server MSPT.
* \param sendTime The time the packet was sent.
*/
ServerTpsPacket(float tps, float mspt, std::uint64_t sendTime) : m_TPS(tps), m_MSPT(mspt), m_PacketSendTime(sendTime) {}
virtual ~ServerTpsPacket() {}
@@ -19,14 +47,27 @@ class ServerTpsPacket : public Packet {
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
/**
* \brief Get the server TPS.
* \return The server TPS.
*/
float GetTPS() const {
return m_TPS;
}
/**
* \brief Get the server MSPT.
* \return The server MSPT.
*/
float GetMSPT() const {
return m_MSPT;
}
/**
* \brief Get the time the packet was sent.
* \return The time the packet was sent.
* \todo Calculate ping.
*/
std::uint64_t GetPacketSendTime() const {
return m_PacketSendTime;
}

View File

@@ -1,18 +1,44 @@
#pragma once
/**
* \file UpdateGameStatePacket.h
* \brief File containing the blitz::protocol::UpdateGameStatePacket class
*/
#include "blitz/game/Game.h"
#include "blitz/protocol/Protocol.h"
namespace blitz {
namespace protocol {
/**
* \class UpdateGameStatePacket
* \brief Packet for updating the game state.
* %Packet structure :
* | PacketType |
* |-----------------------------|
* | PacketType::UpdateGameState |
*
* | Field Name | Field Type | Notes |
* |--------------------|-------------------|----------------------------------------------|
* | Game State | GameState | The new game state |
* | Time Remaining | std::uint64_t | The time remaining in the current game state |
*/
class UpdateGameStatePacket : public Packet {
private:
game::GameState m_GameState;
std::uint64_t m_TimeRemaining;
public:
/**
* \brief Default constructor.
*/
UpdateGameStatePacket() {}
/**
* \brief Constructor.
* \param a_GameState The new game state.
* \param a_TimeRemaining The time remaining in the current game state.
*/
UpdateGameStatePacket(game::GameState a_GameState, std::uint64_t a_TimeRemaining = 0) :
m_GameState(a_GameState), m_TimeRemaining(a_TimeRemaining) {}
virtual ~UpdateGameStatePacket() {}
@@ -21,10 +47,18 @@ class UpdateGameStatePacket : public Packet {
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
/**
* \brief Get the new game state.
* \return The new game state.
*/
game::GameState GetGameState() const {
return m_GameState;
}
/**
* \brief Get the time remaining in the current game state.
* \return The time remaining in the current game state.
*/
std::uint64_t GetTimeRemaining() const {
return m_TimeRemaining;
}

View File

@@ -1,16 +1,40 @@
#pragma once
/**
* \file UpdateHealthPacket.h
* \brief File containing the blitz::protocol::UpdateHealthPacket class
*/
#include "blitz/protocol/Protocol.h"
namespace blitz {
namespace protocol {
/**
* \class UpdateHealthPacket
* \brief Packet for updating the health of a player.
* %Packet structure :
* | PacketType |
* |--------------------------|
* | PacketType::UpdateHealth |
*
* | Field Name | Field Type | Notes |
* |--------------------|-------------------|-------------------------------|
* | m_NewHealth | float | The new health value |
*/
class UpdateHealthPacket : public Packet {
private:
float m_NewHealth;
public:
/**
* \brief Default constructor.
*/
UpdateHealthPacket() {}
/**
* \brief Constructor.
* \param newHealth The new health value.
*/
UpdateHealthPacket(float newHealth) : m_NewHealth(newHealth) {}
virtual ~UpdateHealthPacket() {}
@@ -18,6 +42,10 @@ class UpdateHealthPacket : public Packet {
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
/**
* \brief Get the new health value.
* \return The new health value.
*/
float GetNewHealth() const {
return m_NewHealth;
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "blitz/common/DataBuffer.h"
#include "blitz/common/NonCopyable.h"
#include "blitz/maths/Vector.h"
#include "client/audio/AudioLoader.h"
namespace blitz {
namespace audio {
class AudioBuffer : private NonCopyable {
private:
unsigned int m_ID;
public:
AudioBuffer(AudioData&& audioData);
~AudioBuffer();
unsigned int GetID() const {
return m_ID;
}
};
} // namespace audio
} // namespace blitz

View File

@@ -0,0 +1,21 @@
#pragma once
#include "blitz/common/NonCopyable.h"
#include "blitz/maths/Vector.h"
namespace blitz {
namespace audio {
class AudioListener : private NonCopyable {
public:
AudioListener();
~AudioListener();
void SetGain(float a_Gain);
void SetPosition(const Vec3f& a_Position);
void SetVelocity(const Vec3f& a_Velocity);
void SetOrientation(const Vec3f& a_Orientation, const Vec3f& a_Up);
};
} // namespace audio
} // namespace blitz

View File

@@ -0,0 +1,24 @@
#pragma once
#include "blitz/common/DataBuffer.h"
namespace blitz {
namespace audio {
enum AudioFormat { afMono8 = 0, afMono16, afStereo8, afStereo16 };
struct AudioData {
DataBuffer m_Buffer;
AudioFormat m_Format;
std::uint32_t m_Frequency;
};
namespace AudioLoader {
// files should be 8 or 16 bits wav
AudioData LoadAudioFile(const std::string& filePath);
}; // namespace AudioLoader
} // namespace audio
} // namespace blitz

View File

@@ -0,0 +1,56 @@
#pragma once
#include "blitz/game/Listeners.h"
#include "client/audio/AudioListener.h"
#include "client/audio/AudioSource.h"
#include <map>
namespace blitz {
class Client;
namespace game {
class Player;
} // namespace game
namespace audio {
struct PlayerSound {
AudioSourcePtr m_Laser;
};
class AudioManager : public game::ClientListener, public game::GameListener {
private:
Client* m_Client;
game::Player* m_Player;
AudioListener m_Listener;
AudioSourcePtr m_MenuMusic;
AudioBufferPtr m_LaserSound;
std::map<game::PlayerID, PlayerSound> m_PlayerSources;
public:
AudioManager(Client* client);
~AudioManager();
virtual void OnGameJoin() override;
virtual void OnGameLeave() override;
virtual void OnClientPlayerJoin() override;
virtual void OnPlayerShoot(game::PlayerID player, const Vec3f& position, float yaw, float pitch) override;
virtual void OnPlayerJoin(game::PlayerID player) override;
virtual void OnPlayerLeave(game::PlayerID player) override;
void SetGlobalVolume(float volume);
void Update();
private:
void InitSounds();
AudioSourcePtr InitSourceFromFile(const std::string& fileName);
AudioSourcePtr InitSourceFromBuffer(const AudioBufferPtr& buffer);
AudioBufferPtr InitBufferFromFile(const std::string& fileName);
};
} // namespace audio
} // namespace blitz

View File

@@ -0,0 +1,43 @@
#pragma once
#include "blitz/common/NonCopyable.h"
#include "blitz/maths/Vector.h"
#include "client/audio/AudioBuffer.h"
#include <memory>
namespace blitz {
namespace audio {
typedef std::shared_ptr<AudioBuffer> AudioBufferPtr;
class AudioSource : NonCopyable {
private:
unsigned int m_ID;
AudioBufferPtr m_Buffer;
public:
enum SourceState { ssInitial = 0, ssPlaying, ssPaused, ssStopped };
AudioSource();
~AudioSource();
void SetGain(float a_Gain);
void SetPitch(float a_Pitch);
void SetPosition(const Vec3f& a_Position);
void SetDirection(const Vec3f& a_Direction);
void SetVelocity(const Vec3f& a_Velocity);
void SetLooping(bool a_Looping);
void SetRelative(bool a_Relative);
void SetBuffer(const AudioBufferPtr& a_Buffer);
SourceState GetSourceState() const;
void Play();
void Pause();
void Stop();
};
typedef std::unique_ptr<AudioSource> AudioSourcePtr;
} // namespace audio
} // namespace blitz

View File

@@ -1,11 +1,20 @@
#pragma once
/**
* \file BlitzConfig.h
* \brief File containing the blitz::BlitzConfig class
*/
#include "blitz/game/Game.h"
#include <array>
#include <string>
namespace blitz {
/**
* \enum KeyAction
* \brief Enum containing the key actions
*/
enum KeyAction {
kaAvancer = 0,
kaReculer,
@@ -17,9 +26,13 @@ enum KeyAction {
typedef std::array<int, kaMax> Keybinds;
/**
* \class BlitzConfig
* \brief Class used to manage the Blitz configuration
*/
class BlitzConfig {
private:
std::array<char, 256> m_Pseudo;
std::array<char, 20> m_Pseudo;
game::GameConfig m_ServerConfig;
bool m_VSync;
bool m_DisplayFps;
@@ -27,41 +40,71 @@ class BlitzConfig {
float m_MouseSpeed;
public:
/**
* \brief Default constructor
*/
BlitzConfig();
~BlitzConfig();
std::array<char, 256>& GetPseudo() {
std::array<char, 20>& GetPseudo() {
return m_Pseudo;
}
/**
* \brief Return whether VSync is enabled
*/
bool IsVSyncEnabled() const {
return m_VSync;
}
/**
* \brief Set whether VSync is enabled
*/
void SetVSync(bool vsync) {
m_VSync = vsync;
}
/**
* \brief Return whether the FPS display is enabled
*/
bool IsFPSDisplayEnabled() const {
return m_DisplayFps;
}
/**
* \brief Set whether the FPS display is enabled
*/
void SetFPSDisplay(bool display) {
m_DisplayFps = display;
}
/**
* \brief Get the keybinds
* \return The keybinds
*/
Keybinds& GetKeys() {
return m_Keybinds;
}
/**
* \brief Get the mouse speed
* \return The mouse speed
*/
float GetMouseSpeed() const {
return m_MouseSpeed;
}
/**
* \brief Set the mouse speed
*/
void SetMouseSpeed(float MouseSpeed) {
m_MouseSpeed = MouseSpeed;
}
/**
* \brief Get the server configuration
* \return The server configuration
*/
game::GameConfig& GetServerConfig() {
return m_ServerConfig;
}

View File

@@ -1,5 +1,12 @@
#pragma once
/**
* \file Display.h
* \brief File containing the blitz::Display class
*/
#include "client/display/InputManager.h"
#include "client/display/PlayerController.h"
#include <memory>
#include <string>
@@ -13,7 +20,10 @@ namespace gui {
class BlitzGui;
} // namespace gui
/**
* \class Display
* \brief Class used to manage the display
*/
class Display {
private:
SDL_Window* m_Window;
@@ -28,24 +38,76 @@ class Display {
bool m_FullScreen;
Client* m_Client;
input::InputManager& m_InputManager;
std::unique_ptr<gui::BlitzGui> m_BlitzGui;
input::PlayerController m_PlayerController;
public:
Display(int width, int height, const std::string& windowName, Client* client);
/**
* \brief Constructor
* \param width The width of the window
* \param height The height of the window
* \param windowName The name of the window
* \param client The client
* \param inputManager The InputManager
*/
Display(int width, int height, const std::string& windowName, Client* client, input::InputManager& inputManager);
~Display();
/**
* \brief Return whether the display has been created
*/
bool Create();
/**
* \brief Poll the events
* \note This function should be called at the beginning of the main loop
*/
void PollEvents();
/**
* \brief Update the display
* \note Swap the buffers
*/
void Update();
/**
* \brief Render the display (ImGui)
*/
void Render();
/**
* \brief Destroy the display (Not your mother's display)
*/
void Destroy();
/**
* \brief Return whether the display should be closed
*/
bool IsCloseRequested();
/**
* \brief Return widht/height ratio
*/
float GetAspectRatio();
/**
* \brief Return the window width
*/
int GetWindowWidth();
/**
* \brief Return the window height
*/
int GetWindowHeight();
/**
* \brief Return the player controller
*/
input::PlayerController& GetPlayerController() {
return m_PlayerController;
}
private:
void InitImGui();
};

View File

@@ -1,19 +1,30 @@
#pragma once
#include "blitz/misc/ObjectNotifier.h"
#include <SDL2/SDL_events.h>
#include <functional>
namespace blitz {
namespace InputManager {
namespace input {
typedef std::function<void(int)> KeyDownCallback;
typedef std::function<void(int, int)> MouseMoveCallback;
class InputListener {
public:
virtual void OnKeyDown(int imguiKey) {}
virtual void OnMouseMove(int deltaX, int deltaY) {}
};
void BindKeyDownCallback(const KeyDownCallback&);
void BindMouseMoveCallback(const MouseMoveCallback&);
void ProcessEvent(SDL_Event& event);
void GrabMouse(bool grabInput);
bool MouseGrabbed();
class InputManager : public utils::ObjectNotifier<InputListener> {
private:
bool m_MouseInputGrabbed;
} // namespace InputManager
public:
InputManager() : m_MouseInputGrabbed(false) {}
virtual ~InputManager() {}
void ProcessEvent(SDL_Event& event) const;
void GrabMouse(bool grabInput);
bool MouseGrabbed() const;
};
} // namespace input
} // namespace blitz

View File

@@ -1,9 +1,15 @@
#pragma once
/**
* \file PlayerController.h
* \brief File containing the blitz::input::PlayerController class.
*/
#include "blitz/common/Smoothing.h"
#include "blitz/game/Listeners.h"
#include "blitz/misc/ObjectNotifier.h"
#include "blitz/misc/Time.h"
#include "client/display/InputManager.h"
namespace blitz {
@@ -17,10 +23,16 @@ class Player;
namespace input {
class PlayerController : public utils::ObjectNotifier<game::PlayerInputListener>, game::ClientListener {
/**
* \brief Class that handles player input and sends it to the client.
* \details This class is responsible for handling player input and sending it to the server.
* It also handles the player's velocity and position.
*/
class PlayerController : public utils::ObjectNotifier<game::PlayerInputListener>, game::ClientListener, InputListener {
private:
game::Player* m_Player;
Client* m_Client;
input::InputManager& m_InputManager;
utils::CooldownTimer<float> m_ShootTimer{1.0f};
EMASmoother m_DxSmoother;
EMASmoother m_DySmoother;
@@ -32,24 +44,28 @@ class PlayerController : public utils::ObjectNotifier<game::PlayerInputListener>
bool m_OnGround;
public:
PlayerController(Client* client);
/**
* \brief Default constructor
*/
PlayerController(Client* client, input::InputManager& inputManager);
virtual ~PlayerController();
/**
* \brief Update things like player position and velocity.
*/
void Update(float delta);
virtual void OnGameConfigUpdate() override;
virtual void OnClientPlayerJoin() override;
virtual void OnGameLeave() override;
void SetAttachedPlayer(game::Player* a_Player) {
m_Player = a_Player;
}
game::Player* GetAttachedPlayer() {
return m_Player;
}
virtual void OnMouseMove(int, int) override;
private:
void UpdateShootTimer(int bpm);
void MouseMotionEvent(int, int);
void UpdatePosition(float delta);
void ApplyForce(const Vec3f& f, float delta);
void ApplyGravity(float delta);
};
} // namespace input

View File

@@ -0,0 +1,20 @@
#pragma once
#include "blitz/game/World.h"
namespace blitz {
namespace client {
class ClientGame;
class ClientWorld : public game::World {
public:
ClientWorld(ClientGame* game);
virtual ~ClientWorld() {}
private:
void LoadAABBs();
};
} // namespace client
} // namespace blitz

View File

@@ -1,6 +1,7 @@
#pragma once
#include "GuiWidget.h"
#include "client/display/InputManager.h"
namespace blitz {
@@ -13,7 +14,7 @@ class BlitzGui : public GuiWidget {
enum SubMenu { Main = 0 };
public:
BlitzGui(Client* client);
BlitzGui(Client* client, input::InputManager& inputManager);
virtual void Render() override;

View File

@@ -1,6 +1,7 @@
#pragma once
#include "GuiWidget.h"
#include "client/display/InputManager.h"
namespace blitz {
@@ -9,8 +10,11 @@ class Client;
namespace gui {
class CreateGameMenu : public GuiWidget {
private:
input::InputManager& m_InputManager;
public:
CreateGameMenu(GuiWidget* parent, Client* client) : GuiWidget(parent, client) {}
CreateGameMenu(GuiWidget* parent, Client* client, input::InputManager& inputManager);
virtual void Render() override;
};

View File

@@ -2,6 +2,7 @@
#include "GuiWidget.h"
#include "client/Client.h"
#include "client/display/InputManager.h"
#include <string>
#include <vector>
@@ -19,13 +20,15 @@ class GameChatGui : public GuiWidget, game::ClientListener {
bool ScrollToBottom = false;
bool AutoScroll = true;
float m_ChatDisplay = 0;
input::InputManager& m_InputManager;
void Draw(const char* title, bool* p_open);
void DrawMini(const char* title, bool* p_open);
public:
GameChatGui(GuiWidget* parent, Client* client);
GameChatGui(GuiWidget* parent, Client* client, input::InputManager& inputManager);
virtual ~GameChatGui();
virtual void OnTextChatReceived(const protocol::ColoredText& text) override;

View File

@@ -9,7 +9,7 @@ class Client;
namespace game {
class Player;
} // namespace game
} // namespace game
namespace gui {
class Hud : public GuiWidget {

View File

@@ -1,6 +1,7 @@
#pragma once
#include "GuiWidget.h"
#include "client/display/InputManager.h"
namespace blitz {
@@ -9,8 +10,11 @@ class Client;
namespace gui {
class JoinGameMenu : public GuiWidget {
private:
input::InputManager& m_InputManager;
public:
JoinGameMenu(GuiWidget* parent, Client* client) : GuiWidget(parent, client) {}
JoinGameMenu(GuiWidget* parent, Client* client, input::InputManager& inputManager);
virtual void Render() override;
};

View File

@@ -1,19 +1,29 @@
#pragma once
#include "GuiWidget.h"
#include "blitz/game/Listeners.h"
namespace blitz {
class Client;
namespace input {
class InputManager;
} // namespace input
namespace gui {
class MainMenu : public GuiWidget {
class MainMenu : public GuiWidget, public game::ClientListener {
private:
enum SubMenu { CREATE_MENU = 0, JOIN_MENU, OPTION_MENU };
input::InputManager& m_InputManager;
public:
MainMenu(Client* client);
MainMenu(Client* client, input::InputManager& inputManager);
virtual ~MainMenu();
virtual void OnGameLeave() override;
virtual void Render() override;
};

View File

@@ -3,6 +3,7 @@
#include "GuiWidget.h"
#include "blitz/misc/Time.h"
#include "client/config/BlitzConfig.h"
#include "client/display/InputManager.h"
#include <array>
#include <string>
@@ -12,7 +13,7 @@ class Client;
namespace gui {
class OptionsMenu : public GuiWidget {
class OptionsMenu : public GuiWidget, public input::InputListener {
private:
bool m_ShowFPS;
bool m_VSync;
@@ -20,13 +21,15 @@ class OptionsMenu : public GuiWidget {
bool m_KeyPopupShouldClose;
utils::Timer m_Timer{100};
KeyAction m_CurrentAction;
input::InputManager& m_InputManager;
public:
OptionsMenu(GuiWidget* parent, Client* client);
OptionsMenu(GuiWidget* parent, Client* client, input::InputManager& inputManager);
virtual ~OptionsMenu();
virtual void Render() override;
void OnKeyEvent(int key);
virtual void OnKeyDown(int key) override;
private:
std::string GetKeyActionCodeName(KeyAction);

View File

@@ -1,13 +1,17 @@
#pragma once
#include "GuiWidget.h"
#include "client/display/InputManager.h"
namespace blitz {
namespace gui {
class ServerGui : public GuiWidget {
private:
input::InputManager& m_InputManager;
public:
ServerGui(GuiWidget* parent, Client* client);
ServerGui(GuiWidget* parent, Client* client, input::InputManager& inputManager);
virtual void Render() override;
};

View File

@@ -37,6 +37,7 @@ class BulletRenderer {
void AddBullet(const Vec3f& origin, float yaw, float pitch, bool firstPersson);
void Update(float delta);
void Render();
void Clear();
};
} // namespace render

View File

@@ -1,7 +1,6 @@
#pragma once
#include "blitz/game/Player.h"
#include "blitz/maths/Vector.h"
#include <cstdint>
namespace blitz {

View File

@@ -29,14 +29,14 @@ class MainRenderer : public game::ClientListener, public game::PlayerInputListen
std::unique_ptr<shader::EntityShader> m_EntityShader;
std::unique_ptr<shader::WorldShader> m_WorldShader;
std::unique_ptr<shader::GunShader> m_GunShader;
input::PlayerController m_PlayerController;
unsigned int m_Texture;
float m_ShootTime;
Camera m_Camera;
BulletRenderer m_BulletRenderer;
input::PlayerController& m_PlayerController;
public:
MainRenderer(Client* client);
MainRenderer(Client* client, input::PlayerController& playerController);
~MainRenderer();
virtual void OnSpectatorChange(game::PlayerID player) override;
@@ -44,6 +44,7 @@ class MainRenderer : public game::ClientListener, public game::PlayerInputListen
virtual void OnLocalPlayerShoot(const Vec3f& position, float yaw, float pitch) override;
virtual void OnGameConfigUpdate() override;
virtual void OnGameLeave() override;
void Update();
void Render();

View File

@@ -1,5 +1,6 @@
#pragma once
#include "blitz/maths/Physics.h"
#include "client/render/loader/GLLoader.h"
#include <memory>
#include <string>
@@ -16,5 +17,7 @@ struct Model {
Model LoadModel(const std::string& fileName);
std::vector<maths::AABB> LoadModelAABBs(const std::string& fileName);
} // namespace ModelLoader
} // namespace blitz

View File

@@ -1,5 +1,10 @@
#pragma once
/**
* \file Server.h
* \brief File containing the blitz::server::Server class
*/
#include <map>
#include <thread>
@@ -8,7 +13,15 @@
#include "server/ServerConnexion.h"
#include "server/game/ServerGame.h"
/**
* \def SERVER_TPS
* \brief The server ticks per second
*/
#define SERVER_TPS 20
/**
* \def SERVER_TICK
* \brief The server tick duration
*/
#define SERVER_TICK 1000 / SERVER_TPS
namespace blitz {
@@ -16,6 +29,10 @@ namespace server {
typedef std::map<std::uint8_t, std::unique_ptr<ServerConnexion>> ConnexionMap;
/**
* \class Server
* \brief Class used to manage the server
*/
class Server {
private:
network::TCPListener m_Listener;
@@ -27,48 +44,117 @@ class Server {
std::thread m_Thread;
bool m_ServerRunning;
game::PlayerID m_FreePlayerID;
public:
/**
* \brief Constructor
*/
Server();
virtual ~Server();
/**
* \brief Start the server
* \param port The port
* \param blocking If the server is blocking
* \return If the server has started
*/
bool Start(std::uint16_t port, bool blocking);
void Stop(); // force the server to stop
/**
* \brief Force the server to stop
*/
void Stop();
/**
* \brief Restart the server
*/
void Restart();
/**
* \brief Add a bot
*/
void AddBot();
/**
* \brief Forcefully remove a player from the game
* \param player the id of the player to remove
*/
void KickPlayer(game::PlayerID player);
/**
* \brief Remove a connexion
* \param connexionID The connexion ID
*/
void RemoveConnexion(std::uint8_t connexionID);
/**
* \brief Broadcast a packet to all connexions
* \param packet The packet
*/
void BroadcastPacket(const protocol::Packet* packet);
/**
* \brief Broadcast a chat message
* \param msg The message
*/
void BroadcastChatMessage(const std::string& msg);
/**
* \brief Get the milliseconds per tick
* \return The milliseconds per tick
*/
float GetMSPT() const {
return m_TickCounter.GetMSPT();
}
/**
* \brief Get the ticks per second
* \return The ticks per second
*/
float GetTPS() const {
return m_TickCounter.GetTPS();
}
/**
* \brief Return whether the server is running
*/
bool IsRunning() {
return m_ServerRunning;
}
/**
* \brief Get the connexions (const version)
* \return The connexions
*/
const ConnexionMap& GetConnexions() const {
return m_Connections;
}
/**
* \brief Get the connexions
* \return The connexions
*/
ConnexionMap& GetConnexions() {
return m_Connections;
}
/**
* \brief Get the game
* \return The game
*/
ServerGame& GetGame() {
return m_Game;
}
/**
* \brief Get the listening port
* \return The listening port
*/
std::uint16_t GetListeningPort();
/**
* \brief Get a new player ID
* \return The new player ID
*/
game::PlayerID GetNewPlayerID();
private:

View File

@@ -1,5 +1,10 @@
#pragma once
/**
* \file ServerConnexion.h
* \brief File containing the blitz::server::ServerConnexion class
*/
#include "blitz/network/Connexion.h"
namespace blitz {
@@ -15,13 +20,23 @@ namespace server {
class Server;
/**
* \struct KeepAlive
* \brief Structure containing the keep alive informations
* \var KeepAlive::KeepAliveID The keep alive ID
* \var KeepAlive::SendTime The time when the keep alive was sent
* \var KeepAlive::RecievedResponse If the keep alive has recieved a response
*/
struct KeepAlive {
std::uint64_t keepAliveID = 0;
std::uint64_t sendTime;
bool recievedResponse = false;
std::uint64_t KeepAliveID = 0;
std::uint64_t SendTime;
bool RecievedResponse = false;
};
/**
* \class ServerConnexion
* \brief Class used to manage the server connexion
*/
class ServerConnexion : public network::Connexion {
private:
Server* m_Server;
@@ -31,11 +46,31 @@ class ServerConnexion : public network::Connexion {
std::string m_ChatColor;
public:
/**
* \brief Constructor
* \param server The server
* \param socket The socket
* \param id The ID of the connexion
*/
ServerConnexion(Server* server, network::TCPSocket& socket, std::uint8_t id);
/**
* \brief Move constructor
*/
ServerConnexion(ServerConnexion&& move);
virtual ~ServerConnexion();
void Start();
/**
* \brief Start the connexion
*/
void Init();
/**
* \brief Get the ID of the connexion
* \return The ID of the connexion
*/
std::uint8_t GetID() const {
return m_ID;
}
virtual void HandlePacket(const protocol::PlayerLoginPacket* packet) override;
virtual void HandlePacket(const protocol::KeepAlivePacket* packet) override;
@@ -44,10 +79,6 @@ class ServerConnexion : public network::Connexion {
virtual void HandlePacket(const protocol::PlayerPositionAndRotationPacket* packet) override;
virtual void HandlePacket(const protocol::PlayerShootPacket* packet) override;
std::uint8_t GetID() const {
return m_ID;
}
virtual bool UpdateSocket() override;
private:

View File

@@ -1,10 +1,22 @@
#pragma once
/**
* \file ServerGame.h
* \brief File containing the blitz::server::ServerGame class
*/
#include "blitz/game/Game.h"
namespace blitz {
namespace server {
/**
* \struct ServerDuration
* \brief Structure containing the server game durations
* \var ServerDuration::m_GameDuration The game duration
* \var ServerDuration::m_PrepDuration The preparation duration
* \var ServerDuration::m_EndDuration The end duration
*/
struct ServerDuration {
std::uint64_t m_GameDuration = 1000 * 3 * 60;
std::uint64_t m_PrepDuration = 1000 * 10;
@@ -13,6 +25,10 @@ struct ServerDuration {
class Server;
/**
* \class ServerGame
* \brief Class used to manage the server game
*/
class ServerGame : public game::Game {
private:
Server* m_Server;
@@ -20,22 +36,57 @@ class ServerGame : public game::Game {
ServerDuration m_ServerDuration;
public:
/**
* \brief Constructor
* \param server The server
*/
ServerGame(Server* server);
virtual ~ServerGame();
void CheckShoot(game::PlayerID player, Vec3f position, float yaw, float pitch);
/**
* \brief Process a player shoot
* \param player The player
* \param position The position of the player
* \param yaw The yaw
* \param pitch The pitch
*/
void ProcessShoot(game::PlayerID player, Vec3f position, float yaw, float pitch);
/**
* \brief Process a player login
* \param player The player
* \param name The name of the player
*/
void AddPlayer(game::PlayerID player, const std::string& name) override;
/**
* \brief Remove a player from the game if he disconnected
*/
void RemovePlayer(game::PlayerID player) override;
/**
* \brief Update the game
* \param delta The delta time in milliseconds
*/
void Tick(std::uint64_t delta) override;
void SetGameState(game::GameState gameState, std::uint64_t duration);
/**
* \brief Set the game state
* \param gameState The game state
* \param duration The duration in milliseconds
*/
virtual void UpdateGameState(game::GameState gameState, std::uint64_t duration) override;
/**
* \brief Get the server duration
* \return The server duration in milliseconds
*/
ServerDuration& GetServerDuration() {
return m_ServerDuration;
}
/**
* \brief Send the player positions
*/
void SendServerConfig();
private:
@@ -46,6 +97,7 @@ class ServerGame : public game::Game {
void StartGame(); // when at least 2 players joined
void CancelGame(); // when not enough players are left
void ResetPlayerStats();
void InitGameConfig();
};
} // namespace server

View File

@@ -19,7 +19,7 @@
#include "imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
class SDL_Window;
struct SDL_Window;
struct SDL_Renderer;
typedef union SDL_Event SDL_Event;

View File

@@ -1,23 +1,28 @@
#include "blitz/network/Network.h"
#include "client/Client.h"
#include "client/audio/AudioManager.h"
#include "client/display/Display.h"
#include "client/display/InputManager.h"
#include "client/render/MainRenderer.h"
int main(int argc, char** argv) {
blitz::Client client;
blitz::Display display(1920, 1080, "BlitzKrieg", &client);
blitz::input::InputManager inputManager;
blitz::Display display(1920, 1080, "BlitzKrieg", &client, inputManager);
if (!display.Create())
return EXIT_FAILURE;
blitz::render::MainRenderer renderer(&client);
blitz::render::MainRenderer renderer(&client, display.GetPlayerController());
blitz::audio::AudioManager audioManager(&client);
blitz::network::NetworkInitializer network;
while (!display.IsCloseRequested()) {
client.Update();
display.PollEvents();
renderer.Update();
audioManager.Update();
renderer.Render();
display.Render();
display.Update();

View File

@@ -85,7 +85,7 @@ bool DataBuffer::ReadFile(const std::string& fileName) {
return m_Buffer.size() > 0;
}
bool DataBuffer::WriteFile(const std::string& fileName) {
bool DataBuffer::WriteFile(const std::string& fileName) const {
try {
std::ofstream file(fileName, std::ostream::binary);
file.write(reinterpret_cast<const char*>(m_Buffer.data()), static_cast<std::streamsize>(m_Buffer.size()));

View File

@@ -1,4 +1,5 @@
#include "blitz/game/Game.h"
#include <cmath>
namespace blitz {
namespace game {
@@ -25,10 +26,19 @@ void Game::AddPlayer(PlayerID player, const std::string& name) {
static float MAX_HP = 100;
game::Player newPlayer{player};
static const maths::AABB PLAYER_BASE_AABB = {Vec3f{-0.5f, -0.9f, -0.5f}, Vec3f{0.5f, 0.9f, 0.5f}};
newPlayer.SetHitBoxSize(PLAYER_BASE_AABB);
newPlayer.SetPosition({
0.0f,
std::fabs(PLAYER_BASE_AABB.to.y - PLAYER_BASE_AABB.from.y) * 10.0f,
0.0f
});
newPlayer.SetName(name);
newPlayer.SetHP(MAX_HP);
GetPlayers().insert({player, newPlayer});
NotifyListeners(&GameListener::OnPlayerJoin, player);
}
void Game::RemovePlayer(PlayerID player) {
@@ -37,8 +47,17 @@ void Game::RemovePlayer(PlayerID player) {
if (it == GetPlayers().end())
return;
NotifyListeners(&GameListener::OnPlayerLeave, player);
GetPlayers().erase(it);
}
void Game::UpdateGameState(GameState newGameState, std::uint64_t timeRemaining) {
m_GameState = newGameState;
m_GameTimer.SetInterval(timeRemaining);
m_GameTimer.Reset();
NotifyListeners(&GameListener::OnGameStateUpdate, newGameState);
}
} // namespace game
} // namespace blitz

13
src/blitz/game/World.cpp Normal file
View File

@@ -0,0 +1,13 @@
#include "blitz/game/World.h"
#include "blitz/game/Game.h"
namespace blitz {
namespace game {
World::World(Game* game) : m_Game(game) {}
World::~World() {}
} // namespace game
} // namespace blitz

View File

@@ -5,15 +5,20 @@
namespace blitz {
namespace maths {
Mat4f Perspective(float fovY, float aspectRatio, float zNear, float zFar) {
const float tanHalfFovy = std::tan(fovY / 2.0f);
Mat4f Perspective(float fovY, float invAspectRatio, float zNear, float zFar) {
static const float FRAC_PI_2 = 1.5707963267948966;
const float cotanHalfFovy = -std::tan(std::fmaf(fovY, 0.5f, FRAC_PI_2));
float neg_i_z_diff = -1.0f / (zFar - zNear);
Mat4f result{};
result.x0 = 1.0f / (aspectRatio * tanHalfFovy);
result.y1 = 1.0f / (tanHalfFovy);
result.z2 = -(zFar + zNear) / (zFar - zNear);
result.x0 = cotanHalfFovy * invAspectRatio;
result.y1 = cotanHalfFovy;
result.z2 = (zFar + zNear) * neg_i_z_diff;
result.z3 = -1.0f;
result.w2 = -(2.0f * zFar * zNear) / (zFar - zNear);
result.w2 = 2.0f * zFar * zNear * neg_i_z_diff;
return result;
}
@@ -171,5 +176,13 @@ Mat4f Rotate(float angle, Vec3f axis) {
return mat;
}
Vec3f GetDirectionVectorFromRotation(float yaw, float pitch) {
return {
std::cos(yaw) * std::cos(pitch),
std::sin(pitch),
std::sin(yaw) * std::cos(pitch),
};
}
} // namespace maths
} // namespace blitz

113
src/blitz/maths/Physics.cpp Executable file → Normal file
View File

@@ -1,67 +1,112 @@
#include "blitz/maths/Physics.h"
#include "blitz/maths/Maths.h"
#include <cmath>
namespace blitz {
namespace maths {
/**
* @brief Returns `true` if the half-line `ray` _strictly_ intersects with `aabb`,
* and `false` if it _strictly_ doesn't intersect.
* Note that if it only intersects with corners, edges, or sides of the box,
* or if any coordinate in `ray` is `NAN` or `inf` or if any coordinate in
* `aabb` is `NAN` the result is unspecified.
* */
float Distance(const Ray& ray, const AABB& aabb) {
AABB AABB::Enlarge(const AABB& with) const {
const Vec3f dir = 0.5f * (with.to - with.from);
// This function calculates smallest interval I = ] a, b [, for strictly positive a and b
// such that for all t in I, for all l, r, o, d corresponding
// coordinates in aabb.from, aabb.to, ray.origin, ray.direction, respectively
return AABB{
from - dir,
to + dir,
};
}
AABB AABB::Direct() const {
return AABB{Min(from, to), Max(from, to)};
}
Vec3f AABB::Center() const {
return (from + to) * 0.5f;
}
AABB AABB::operator+(const Vec3f& offset) const {
return AABB{from + offset, to + offset};
}
AABB AABB::operator+=(const Vec3f& offset) {
*this = *this + offset;
return *this;
}
bool AABB::OverlapsWith(const AABB& aabb) const {
return RangesOverlapping(from.x, to.x, aabb.from.x, aabb.to.x) &&
RangesOverlapping(from.y, to.y, aabb.from.y, aabb.to.y) &&
RangesOverlapping(from.z, to.z, aabb.from.z, aabb.to.z);
}
std::optional<IntersectionData> AABB::Intersection(const AABB& aabb, const Vec3f& dir) const {
return Ray { Center(), dir }.Intersection(aabb.Enlarge(*this));
}
Vec3f Ray::operator()(float t) const {
return FmaF(Vec3f::splat(t), direction, origin);
}
std::optional<IntersectionData> Ray::Intersection(const AABB& aabb) const {
// This function calculates smallest interval I = ] tmin, tmax [,
// such that for all t in I ray(t) is in the AABB, now, if tmin > tmax
// there is no such t, i.e. the ray never intersects with the AABB
//
// min(l, r) < o + t * d < max(l, r)
//
// and returns true if it's non-empty i.e. a < b
// and returns true if it's non-empty i.e. a < b
// m = min(l, r), M = max(l, r)
// m < o + t * d < M
Vec3f l = Min(aabb.from, aabb.to);
Vec3f r = Max(aabb.to, aabb.from);
AABB directed = aabb.Direct();
Vec3f& l = directed.from;
Vec3f& r = directed.to;
// m - o < t * d < M - o
l -= ray.origin;
r -= ray.origin;
l -= origin;
r -= origin;
// (m - o) / d < t < (M - o) / d
l /= ray.direction;
r /= ray.direction;
l /= direction;
r /= direction;
// but if d is negative the inequality is flipped
Vec3f u = Min(l, r);
r = Max(l, r);
l = u;
float tmin = ReduceMax(l);
float tmax = ReduceMin(r);
const float tmin = ReduceFMaxF(l);
const float tmax = ReduceFMinF(r);
// Since Min propagates NANs and ReduceMin doesn't, and since NAN !< <any float>
// the inequality becomes ignored for coordinates where a NAN is involved
// Since Min propagates NANs and ReduceFMinF doesn't, and since NAN != <any float>
// the inequality becomes ignored for coordinates where a NaN is involved
// (as a result of 0.0 / 0.0). If all coordinates are NAN, this means
// that the box is reduced to a point and the ray has direction 0,
// in which case this returns -1
if (tmax >= 0.0f && tmin <= tmax) {
return std::fmaxf(tmin, 0.0f);
// in which case this returns 0.0, which is technically the correct result
if (tmin <= tmax && tmax > 0.0f) {
Axis axis = Axis::aZ;
for (std::size_t i = 2; i >= 0; i--) {
Axis this_axis = Axis(i);
if (l[this_axis] == tmin) {
axis = this_axis;
break;
}
}
const float dist = std::fmaxf(0.0f, tmin);
return std::make_optional(IntersectionData { dist, axis });
}
return -1.0f;
return std::nullopt;
}
bool Intersects(const AABB& aabb1, const AABB& aabb2) {
return false;
bool Ray::Intersects(const AABB& aabb) const {
auto data = Intersection(aabb);
return data.has_value() && data->distance >= 0.0f;
}
bool Intersects(const Ray& ray, const AABB& aabb) {
return Distance(ray, aabb) >= 0.0f;
CollisionData IntersectionData::ToCollision(const Vec3f& dir) const {
Vec3f new_dir = dir;
new_dir[axis] = 0.0f;
return CollisionData{dir * (distance - 0.07f), new_dir * (1.0f - distance)};
}
} // namespace maths

View File

@@ -22,7 +22,7 @@ static DataBuffer Inflate(const std::uint8_t* source, std::size_t size, std::siz
static DataBuffer Deflate(const std::uint8_t* source, std::size_t size) {
DataBuffer result;
uLongf compressedSize;
uLongf compressedSize = size;
result.Resize(size); // Resize for the compressed data to fit into
compress(

View File

@@ -32,7 +32,7 @@ float EaseOutCubic(float x) {
}
float EaseInOutCubic(float x) {
return static_cast<float>(x < 0.5 ? 4 * EaseInCubic(x) : 1 - std::pow(-2 * x + 2, 3) / 2.0);
return x < 0.5f ? 4.0f * EaseInCubic(x) : 1.0f - std::pow(-2.0f * x + 2.0f, 3.0f) / 2.0f;
}
/* Quint functions */
@@ -60,8 +60,8 @@ float EaseOutCirc(float x) {
}
float EaseInOutCirc(float x) {
return static_cast<float>(
x < 0.5 ? (1 - std::sqrt(1 - std::pow(2 * x, 2))) / 2.0 : (std::sqrt(1 - std::pow(-2 * x + 2, 2)) + 1) / 2.0);
return x < 0.5f ? (1.0f - std::sqrt(1.0f - std::pow(2.0f * x, 2.0f))) / 2.0f
: (std::sqrt(1.0f - std::pow(-2.0f * x + 2.0f, 2.0f)) + 1.0f) / 2.0f;
}
/* Elastic functions */

View File

@@ -1,10 +1,17 @@
#include "blitz/network/Network.h"
#include "blitz/misc/Log.h"
#include <signal.h>
namespace blitz {
namespace network {
/* Catch Signal Handler function */
void signal_callback_handler(int signum) {
utils::LOGD("[Network] Caught a SIGPIPE !");
}
#ifdef _WIN32
NetworkInitializer::NetworkInitializer() {
WSADATA wsaData;
@@ -18,7 +25,10 @@ NetworkInitializer::~NetworkInitializer() {
WSACleanup();
}
#else
NetworkInitializer::NetworkInitializer() {}
NetworkInitializer::NetworkInitializer() {
/* Prevents the game for crashing when socket closes on the other side */
signal(SIGPIPE, signal_callback_handler);
}
NetworkInitializer::~NetworkInitializer() {}
#endif

View File

@@ -89,8 +89,6 @@ bool TCPSocket::Connect(const std::string& host, unsigned short port) {
return false;
}
SetBlocking(m_Blocking);
struct addrinfo* ptr = nullptr;
for (ptr = result; ptr != nullptr; ptr = ptr->ai_next) {
struct sockaddr* sockaddr = ptr->ai_addr;
@@ -123,14 +121,15 @@ size_t TCPSocket::Send(const unsigned char* data, size_t size) {
while (sent < size) {
int cur = send(m_Handle, reinterpret_cast<const char*>(data + sent), static_cast<int>(size - sent), 0);
if (cur <= 0) {
m_Status = Status::Error;
Disconnect();
m_Status = Status::Error;
return 0;
}
sent += static_cast<std::size_t>(cur);
}
return sent;
}

View File

@@ -1,5 +1,6 @@
#include "blitz/protocol/packets/ChatPacket.h"
#include "blitz/common/VarInt.h"
#include "blitz/maths/Vector.h"
#include "blitz/misc/Log.h"
#include <map>
@@ -23,7 +24,7 @@ DataBuffer ChatPacket::Serialize(bool packetID) const {
WritePacketID(data, packetID);
data << static_cast<std::uint64_t>(m_Message.size());
data << VarInt{m_Message.size()};
for (const auto& part : m_Message) {
data << part.color << part.text;
}
@@ -31,12 +32,12 @@ DataBuffer ChatPacket::Serialize(bool packetID) const {
}
void ChatPacket::Deserialize(DataBuffer& data) {
std::uint64_t partsNumber;
VarInt partsNumber;
data >> partsNumber;
m_Message.resize(partsNumber);
m_Message.resize(partsNumber.GetValue());
for (std::size_t i = 0; i < partsNumber; ++i) {
for (std::size_t i = 0; i < partsNumber.GetValue(); ++i) {
data >> m_Message[i].color >> m_Message[i].text;
}
}

View File

@@ -13,7 +13,7 @@ DataBuffer GetAsset(const std::string& fileName) {
SDL_RWops* io = SDL_RWFromFile(fileName.c_str(), "rb");
assert(io != nullptr);
assert(io != nullptr && "Can't find the requested file !");
std::int64_t bufferSize = SDL_RWsize(io);

View File

@@ -1,5 +1,6 @@
#include "client/Client.h"
#include "blitz/misc/Log.h"
#include "blitz/protocol/packets/ChatPacket.h"
#include "blitz/protocol/packets/DisconnectPacket.h"
#include "blitz/protocol/packets/PlayerPositionAndRotationPacket.h"
@@ -17,11 +18,13 @@ Client::Client() :
m_Game(std::make_unique<client::ClientGame>(this, m_Connexion->GetDispatcher())) {}
Client::~Client() {
protocol::DisconnectPacket packet("Client");
m_Connexion->SendPacket(&packet);
Disconnect();
}
void Client::Update() {
if (m_Connexion->GetSocketStatus() != network::TCPSocket::Status::Connected)
return;
if (m_Connexion->UpdateSocket()) {
static std::uint64_t lastTime = utils::GetTime();
@@ -29,6 +32,8 @@ void Client::Update() {
m_Game->Tick(utils::GetTime() - lastTime);
lastTime = utils::GetTime();
} else {
Disconnect();
}
}
@@ -57,14 +62,26 @@ bool Client::CreateGame(std::uint16_t port, const std::string& pseudo) {
}
void Client::Disconnect() {
if (m_Connexion->GetSocketStatus() != network::TCPSocket::Status::Connected)
return;
protocol::DisconnectPacket packet("Client wants to leave !");
m_Connexion->SendPacket(&packet);
utils::LOGD("[Client] Disconnected !");
if (m_Server) {
m_Server->Stop();
}
m_Connexion->CloseConnection();
NotifyListeners(&game::ClientListener::OnGameLeave);
Reset();
}
void Client::Reset() {
utils::LOGD("[Client] Reset !");
// Reset server
m_Server.reset(nullptr);
m_Server = std::make_unique<server::Server>();

View File

@@ -5,6 +5,7 @@
#include "blitz/misc/PrettyLog.h"
#include "blitz/protocol/packets/ChatPacket.h"
#include "blitz/protocol/packets/ConnexionInfoPacket.h"
#include "blitz/protocol/packets/DisconnectPacket.h"
#include "blitz/protocol/packets/KeepAlivePacket.h"
#include "blitz/protocol/packets/PlayerLoginPacket.h"
#include "client/Client.h"
@@ -52,7 +53,8 @@ void ClientConnexion::HandlePacket(const protocol::ChatPacket* packet) {
}
void ClientConnexion::HandlePacket(const protocol::DisconnectPacket* packet) {
utils::LOG("Disconnected !");
utils::LOG("[ClientConnexion] Disconnected ! Reason : " + packet->GetReason());
m_Client->NotifyListeners(&game::ClientListener::OnGameLeave);
}
void ClientConnexion::HandlePacket(const protocol::KeepAlivePacket* packet) {
@@ -62,6 +64,7 @@ void ClientConnexion::HandlePacket(const protocol::KeepAlivePacket* packet) {
void ClientConnexion::HandlePacket(const protocol::ConnexionInfoPacket* packet) {
m_PlayerID = packet->GetConnectionID();
utils::LOGD("[ClientConnexion] Logging in with pseudo " + m_PlayerName + " ...");
Login(m_PlayerName);
}

View File

@@ -0,0 +1,27 @@
#include "client/audio/AudioBuffer.h"
#include <AL/al.h>
namespace blitz {
namespace audio {
static const std::vector<unsigned int> AudioFormats = {
AL_FORMAT_MONO8,
AL_FORMAT_MONO16,
AL_FORMAT_STEREO8,
AL_FORMAT_STEREO16,
};
AudioBuffer::AudioBuffer(AudioData&& audioData) {
alGenBuffers(1, &m_ID);
alBufferData(m_ID, AudioFormats[audioData.m_Format], audioData.m_Buffer.data() + audioData.m_Buffer.GetReadOffset(),
audioData.m_Buffer.GetSize() - audioData.m_Buffer.GetReadOffset(), static_cast<ALsizei>(audioData.m_Frequency));
}
AudioBuffer::~AudioBuffer() {
alDeleteBuffers(1, &m_ID);
m_ID = 0;
}
} // namespace audio
} // namespace blitz

View File

@@ -0,0 +1,47 @@
#include "client/audio/AudioListener.h"
#include "blitz/misc/Log.h"
#include <AL/al.h>
#include <AL/alc.h>
namespace blitz {
namespace audio {
AudioListener::AudioListener() {
ALCdevice* device = alcOpenDevice(nullptr);
if (device) {
ALCcontext* context = alcCreateContext(device, nullptr);
alcMakeContextCurrent(context);
} else {
utils::LOGE("[AudioListener] Can't initialize sound !");
}
}
AudioListener::~AudioListener() {
ALCcontext* context = alcGetCurrentContext();
ALCdevice* device = alcGetContextsDevice(context);
alcMakeContextCurrent(NULL);
alcDestroyContext(context);
alcCloseDevice(device);
}
void AudioListener::SetGain(float a_Gain) {
alListenerf(AL_GAIN, a_Gain);
}
void AudioListener::SetPosition(const Vec3f& a_Position) {
alListener3f(AL_POSITION, a_Position.x, a_Position.y, a_Position.z);
}
void AudioListener::SetVelocity(const Vec3f& a_Velocity) {
alListener3f(AL_VELOCITY, a_Velocity.x, a_Velocity.y, a_Velocity.z);
}
void AudioListener::SetOrientation(const Vec3f& a_Orientation, const Vec3f& a_Up) {
Vec3f data[] = {a_Orientation, a_Up};
alListenerfv(AL_ORIENTATION, reinterpret_cast<float*>(data));
}
} // namespace audio
} // namespace blitz

View File

@@ -0,0 +1,51 @@
#include "client/audio/AudioLoader.h"
#include "blitz/misc/Log.h"
#include "client/AssetsManager.h"
namespace blitz {
namespace audio {
namespace AudioLoader {
struct WavHeader {
/* RIFF Chunk Descriptor */
uint8_t RIFF[4]; // RIFF Header Magic header
uint32_t ChunkSize; // RIFF Chunk Size
uint8_t WAVE[4]; // WAVE Header
/* "fmt" sub-chunk */
uint8_t FMT[4]; // FMT header
uint32_t Subchunk1Size; // Size of the fmt chunk
uint16_t AudioFormat; // Audio format 1=PCM,6=mulaw,7=alaw, 257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM
uint16_t NumOfChan; // Number of channels 1=Mono 2=Sterio
uint32_t SamplesPerSec; // Sampling Frequency in Hz
uint32_t BytesPerSec; // bytes per second
uint16_t BlockAlign; // 2=16-bit mono, 4=16-bit stereo
uint16_t BitsPerSample; // Number of bits per sample
/* "data" sub-chunk */
uint8_t Subchunk2ID[4]; // "data" string
uint32_t Subchunk2Size; // Sampled data length
};
AudioData LoadAudioFile(const std::string& filePath) {
DataBuffer fileBuffer = utils::AssetsManager::GetAsset(filePath);
WavHeader wavHeader;
fileBuffer >> wavHeader;
if (wavHeader.Subchunk2Size == 0) {
utils::LOGE("[AudioLoader] Failed to load sound " + filePath + " !");
}
fileBuffer.Resize(fileBuffer.GetReadOffset() + wavHeader.Subchunk2Size);
int audioFormat = (wavHeader.NumOfChan - 1) * 2 + (wavHeader.BitsPerSample / 8) - 1;
return {fileBuffer, AudioFormat(audioFormat), wavHeader.SamplesPerSec};
}
}; // namespace AudioLoader
} // namespace audio
} // namespace blitz

View File

@@ -0,0 +1,108 @@
#include "client/audio/AudioManager.h"
#include "blitz/maths/Maths.h"
#include "blitz/misc/Log.h"
#include "client/Client.h"
#include "client/audio/AudioBuffer.h"
#include "client/game/ClientGame.h"
namespace blitz {
namespace audio {
AudioManager::AudioManager(Client* client) : m_Client(client), m_Player(nullptr) {
m_Listener.SetGain(1.0f);
InitSounds();
m_MenuMusic->Play();
m_Client->BindListener(this);
}
void AudioManager::SetGlobalVolume(float volume) {
m_Listener.SetGain(volume);
}
void AudioManager::Update() {
if (!m_Player)
return;
m_Listener.SetPosition(m_Player->GetPosition());
m_Listener.SetOrientation(maths::GetDirectionVectorFromRotation(m_Player->GetYaw(), m_Player->GetPitch()), {0.0f, 1.0f, 0.0f});
m_Listener.SetVelocity(m_Player->GetVelocity());
}
AudioSourcePtr AudioManager::InitSourceFromFile(const std::string& fileName) {
AudioBufferPtr audioBuffer = InitBufferFromFile(fileName);
return InitSourceFromBuffer(audioBuffer);
}
AudioSourcePtr AudioManager::InitSourceFromBuffer(const AudioBufferPtr& buffer) {
AudioSourcePtr audioSource = std::make_unique<AudioSource>();
audioSource->SetBuffer(buffer);
audioSource->SetPosition({});
audioSource->SetVelocity({});
audioSource->SetPitch(1.0f);
audioSource->SetRelative(false);
return audioSource;
}
AudioBufferPtr AudioManager::InitBufferFromFile(const std::string& fileName) {
AudioData audioData = AudioLoader::LoadAudioFile(fileName);
return std::make_shared<AudioBuffer>(std::move(audioData));
}
void AudioManager::InitSounds() {
m_MenuMusic = InitSourceFromFile("sessionD.wav");
m_MenuMusic->SetLooping(true);
m_LaserSound = InitBufferFromFile("laser.wav");
}
void AudioManager::OnGameJoin() {
m_MenuMusic->Stop();
m_Client->GetGame()->BindListener(this);
}
void AudioManager::OnGameLeave() {
m_MenuMusic->Play();
m_PlayerSources.clear();
m_Player = nullptr;
m_Client->GetGame()->UnbindListener(this);
}
void AudioManager::OnClientPlayerJoin() {
m_Player = m_Client->GetGame()->GetPlayerById(m_Client->GetPlayerID());
}
void AudioManager::OnPlayerJoin(game::PlayerID player) {
m_PlayerSources.insert({player, PlayerSound{InitSourceFromBuffer(m_LaserSound)}});
}
void AudioManager::OnPlayerLeave(game::PlayerID player) {
m_PlayerSources.erase(player);
}
void AudioManager::OnPlayerShoot(game::PlayerID playerID, const Vec3f& position, float yaw, float pitch) {
auto it = m_PlayerSources.find(playerID);
if (it == m_PlayerSources.end()) {
utils::LOGD("[AudioManager] No sound found for player " + std::to_string(playerID) + " !");
return;
}
game::Player* player = m_Client->GetGame()->GetPlayerById(playerID);
assert(player);
Vec3f shootFront = maths::GetDirectionVectorFromRotation(player->GetYaw(), player->GetPitch());
PlayerSound& playerSounds = it->second;
playerSounds.m_Laser->SetPosition(player->GetPosition());
playerSounds.m_Laser->SetDirection(shootFront);
playerSounds.m_Laser->Play();
}
AudioManager::~AudioManager() {
m_Client->UnbindListener(this);
}
} // namespace audio
} // namespace blitz

View File

@@ -0,0 +1,70 @@
#include "client/audio/AudioSource.h"
#include <AL/al.h>
namespace blitz {
namespace audio {
AudioSource::AudioSource() {
alGenSources(1, &m_ID);
}
AudioSource::~AudioSource() {
alDeleteSources(1, &m_ID);
}
void AudioSource::SetGain(float a_Gain) {
alSourcef(m_ID, AL_GAIN, a_Gain);
}
void AudioSource::SetPitch(float a_Pitch) {
alSourcef(m_ID, AL_PITCH, a_Pitch);
}
void AudioSource::SetPosition(const Vec3f& a_Position) {
alSource3f(m_ID, AL_POSITION, a_Position.x, a_Position.y, a_Position.z);
}
void AudioSource::SetDirection(const Vec3f& a_Direction) {
alSource3f(m_ID, AL_DIRECTION, a_Direction.x, a_Direction.y, a_Direction.z);
}
void AudioSource::SetVelocity(const Vec3f& a_Velocity) {
alSource3f(m_ID, AL_VELOCITY, a_Velocity.x, a_Velocity.y, a_Velocity.z);
}
void AudioSource::SetLooping(bool a_Looping) {
alSourcei(m_ID, AL_LOOPING, a_Looping);
}
void AudioSource::SetRelative(bool a_Relative) {
alSourcei(m_ID, AL_SOURCE_RELATIVE, a_Relative);
}
void AudioSource::SetBuffer(const AudioBufferPtr& a_Buffer) {
alSourcei(m_ID, AL_BUFFER, a_Buffer->GetID());
m_Buffer = a_Buffer;
}
AudioSource::SourceState AudioSource::GetSourceState() const {
int state;
alGetSourcei(m_ID, AL_SOURCE_STATE, &state);
return SourceState(state - AL_INITIAL);
}
void AudioSource::Play() {
alSourcePlay(m_ID);
}
void AudioSource::Pause() {
alSourcePause(m_ID);
}
void AudioSource::Stop() {
alSourceStop(m_ID);
}
} // namespace audio
} // namespace blitz

View File

@@ -20,7 +20,7 @@
namespace blitz {
Display::Display(int width, int height, const std::string& windowName, Client* client) :
Display::Display(int width, int height, const std::string& windowName, Client* client, input::InputManager& inputManager) :
m_WindowWidth(width),
m_WindowHeight(height),
m_AspectRatio(m_WindowHeight / static_cast<float>(m_WindowWidth)),
@@ -28,7 +28,9 @@ Display::Display(int width, int height, const std::string& windowName, Client* c
m_ShouldClose(false),
m_FullScreen(false),
m_Client(client),
m_BlitzGui(nullptr) {}
m_InputManager(inputManager),
m_BlitzGui(nullptr),
m_PlayerController(m_Client, m_InputManager) {}
Display::~Display() {
Destroy();
@@ -145,7 +147,7 @@ void Display::PollEvents() {
}
}
ImGui_ImplSDL2_ProcessEvent(&event);
InputManager::ProcessEvent(event);
m_InputManager.ProcessEvent(event);
}
#ifdef __ANDROID__
@@ -156,6 +158,8 @@ void Display::PollEvents() {
}
#endif
m_PlayerController.Update(ImGui::GetIO().DeltaTime);
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
@@ -164,7 +168,7 @@ void Display::PollEvents() {
void Display::Update() {
// center mouse
#ifndef __ANDROID__
if (InputManager::MouseGrabbed()) {
if (m_InputManager.MouseGrabbed()) {
SDL_WarpMouseInWindow(m_Window, GetWindowWidth() / 2, GetWindowHeight() / 2);
}
#endif
@@ -229,7 +233,7 @@ void Display::InitImGui() {
#ifndef __ANDROID__
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
#endif
m_BlitzGui = std::make_unique<gui::BlitzGui>(m_Client);
m_BlitzGui = std::make_unique<gui::BlitzGui>(m_Client, m_InputManager);
}
} // namespace blitz

View File

@@ -4,12 +4,7 @@
#include <vector>
namespace blitz {
namespace InputManager {
std::vector<KeyDownCallback> KeyCallBacks;
std::vector<MouseMoveCallback> MouseCallBacks;
bool MouseInputGrabbed = false;
namespace input {
static int ImGui_ImplSDL2_KeycodeToImGuiKey(int keycode) {
switch (keycode) {
@@ -227,36 +222,15 @@ static int ImGui_ImplSDL2_KeycodeToImGuiKey(int keycode) {
return ImGuiKey_None;
}
void BindKeyDownCallback(const KeyDownCallback& callback) {
KeyCallBacks.push_back(callback);
}
void BindMouseMoveCallback(const MouseMoveCallback& callback) {
MouseCallBacks.push_back(callback);
}
static void CallKeyFunctions(SDL_Keycode key) {
int imguiKey = ImGui_ImplSDL2_KeycodeToImGuiKey(key);
for (auto callback : KeyCallBacks) {
callback(imguiKey);
}
}
static void CallMouseFunctions(int xrel, int yrel) {
for (auto callback : MouseCallBacks) {
callback(xrel, yrel);
}
}
void ProcessEvent(SDL_Event& event) {
void InputManager::ProcessEvent(SDL_Event& event) const {
switch (event.type) {
case SDL_KEYDOWN: {
CallKeyFunctions(event.key.keysym.sym);
NotifyListeners(&InputListener::OnKeyDown, ImGui_ImplSDL2_KeycodeToImGuiKey(event.key.keysym.sym));
break;
}
case SDL_MOUSEMOTION: {
CallMouseFunctions(event.motion.xrel, event.motion.yrel);
NotifyListeners(&InputListener::OnMouseMove, event.motion.xrel, event.motion.yrel);
break;
}
@@ -265,16 +239,16 @@ void ProcessEvent(SDL_Event& event) {
}
}
void GrabMouse(bool grabInput) {
MouseInputGrabbed = grabInput;
void InputManager::GrabMouse(bool grabInput) {
m_MouseInputGrabbed = grabInput;
#ifndef __ANDROID__
SDL_SetRelativeMouseMode(static_cast<SDL_bool>(grabInput));
#endif
}
bool MouseGrabbed() {
return MouseInputGrabbed;
bool InputManager::MouseGrabbed() const {
return m_MouseInputGrabbed;
}
} // namespace InputManager
} // namespace input
} // namespace blitz

View File

@@ -2,6 +2,7 @@
#include "blitz/game/Player.h"
#include "blitz/maths/Maths.h"
#include "blitz/maths/Physics.h"
#include "blitz/misc/Log.h"
#include "client/Client.h"
#include "client/config/BlitzConfig.h"
@@ -20,32 +21,45 @@ static constexpr float DEFAULT_MAX_FB_SPEED = 10.;
static constexpr float DEFAULT_LR_SPEED_SMOOTHING_TIME = 1.0;
static constexpr float DEFAULT_FB_SPEED_SMOOTHING_TIME = 1.0;
PlayerController::PlayerController(Client* client) :
PlayerController::PlayerController(Client* client, input::InputManager& inputManager) :
m_Player(nullptr),
m_Client(client),
m_InputManager(inputManager),
m_Velocity({}),
m_MaxVelocity(DEFAULT_MAX_LR_SPEED, DEFAULT_MAX_FB_SPEED, DEFAULT_JUMP_VEL),
m_MaxVelocity(DEFAULT_MAX_LR_SPEED, DEFAULT_JUMP_VEL, DEFAULT_MAX_FB_SPEED),
m_OnGround(true) {
m_DxSmoother.Current = 0.0f;
m_DySmoother.Current = 0.0f;
m_DxSmoother.SetSmoothingTime(DEFAULT_LR_SPEED_SMOOTHING_TIME);
m_DySmoother.SetSmoothingTime(DEFAULT_FB_SPEED_SMOOTHING_TIME);
InputManager::BindMouseMoveCallback(
std::bind(&PlayerController::MouseMotionEvent, this, std::placeholders::_1, std::placeholders::_2));
client->BindListener(this);
m_InputManager.BindListener(this);
m_Client->BindListener(this);
}
PlayerController::~PlayerController() {
m_InputManager.UnbindListener(this);
m_Client->UnbindListener(this);
}
void PlayerController::OnGameConfigUpdate() {
UpdateShootTimer(m_Client->GetGame()->GetGameConfig().FiringRate);
}
void PlayerController::OnClientPlayerJoin() {
m_Player = m_Client->GetGame()->GetPlayerById(m_Client->GetPlayerID());
}
void PlayerController::OnGameLeave() {
m_Player = nullptr;
}
void PlayerController::UpdateShootTimer(int bpm) {
m_ShootTimer.SetCooldown(60.0f / static_cast<float>(bpm));
m_ShootTimer.Reset();
}
void PlayerController::MouseMotionEvent(int deltaX, int deltaY) {
if (!m_Player || !InputManager::MouseGrabbed())
void PlayerController::OnMouseMove(int deltaX, int deltaY) {
if (!m_Player || !m_InputManager.MouseGrabbed())
return;
float MouseSpeed = m_Client->GetConfig()->GetMouseSpeed();
@@ -59,7 +73,7 @@ void PlayerController::Update(float delta) {
if (!m_Player)
return;
if (InputManager::MouseGrabbed()) {
if (m_InputManager.MouseGrabbed()) {
Keybinds keys = m_Client->GetConfig()->GetKeys();
float lr = static_cast<float>(ImGui::IsKeyDown((ImGuiKey(keys[kaAvancer])))) -
static_cast<float>(ImGui::IsKeyDown((ImGuiKey(keys[kaReculer]))));
@@ -67,13 +81,19 @@ void PlayerController::Update(float delta) {
static_cast<float>(ImGui::IsKeyDown((ImGuiKey(keys[kaDroite]))));
// scale values in such a way that clamps ||(lr, fb)|| to 1.0
float scale = 1.0f / std::max(sqrt(lr * lr + fb * fb), 1.0f);
float scale = 1.0f / std::fmaxf(sqrt(lr * lr + fb * fb), 1.0f);
static constexpr float AIR_MOVEMENT_DAMP = 3.0f;
float no = std::fmaf(static_cast<float>(!m_OnGround), AIR_MOVEMENT_DAMP, 1.0f);
m_DxSmoother.SetSmoothingTime(DEFAULT_LR_SPEED_SMOOTHING_TIME * no);
m_DySmoother.SetSmoothingTime(DEFAULT_FB_SPEED_SMOOTHING_TIME * no);
m_Velocity.x = lr * m_MaxVelocity.x * scale;
m_Velocity.y = fb * m_MaxVelocity.y * scale;
m_Velocity.z = fb * m_MaxVelocity.z * scale;
if (ImGui::IsKeyDown(ImGuiKey::ImGuiKey_Space) && m_OnGround) {
m_Velocity.z = m_MaxVelocity.z;
m_Velocity.y = m_MaxVelocity.y;
NotifyListeners(&game::PlayerInputListener::OnLocalPlayerJump);
}
@@ -84,12 +104,22 @@ void PlayerController::Update(float delta) {
m_ShootTimer.ApplyCooldown();
}
} else {
m_Velocity.x = m_Velocity.y = 0.0f;
m_Velocity.x = m_Velocity.z = 0.0f;
}
ApplyGravity(delta);
UpdatePosition(delta);
}
void PlayerController::ApplyForce(const Vec3f& f, float delta) {
m_Velocity += f * delta;
}
void PlayerController::ApplyGravity(float delta) {
ApplyForce(Vec3f { 0.0f, -m_Client->GetGame()->GetGameConfig().Gravity, 0.0f }, delta);
}
void PlayerController::UpdatePosition(const float delta) {
float yaw = m_Player->GetYaw();
@@ -97,28 +127,54 @@ void PlayerController::UpdatePosition(const float delta) {
float cosine = std::cos(yaw);
m_DxSmoother.Tick(m_Velocity.x, delta);
m_DySmoother.Tick(m_Velocity.y, delta);
m_DySmoother.Tick(m_Velocity.z, delta);
float dx_smooth = m_DxSmoother.Current;
float dy_smooth = m_DySmoother.Current;
float dx = (dx_smooth * cosine + dy_smooth * sine) * delta;
float dy = (dx_smooth * sine - dy_smooth * cosine) * delta;
Vec3f vel = Vec3f((dx_smooth * cosine + dy_smooth * sine), m_Velocity.y, (dx_smooth * sine - dy_smooth * cosine)) * delta;
maths::CollisionData collision { Vec3f::splat(0.0f), vel };
float dz = m_Velocity.z * delta;
const auto& aabbs = m_Client->GetGame()->GetWorld()->GetAABBs();
maths::AABB hitbox = m_Player->GetHitBox();
// the floor here is y-level zero, once downwards collision lands it will be dynmicallly calculated
// assumed to be a negative number
const float floor_dist = 0.0f - m_Player->GetPosition().y;
bool on_ground = false;
if ((m_OnGround = (dz <= floor_dist))) {
dz = floor_dist;
m_Velocity.z = 0.0f;
} else {
m_Velocity.z -= m_Client->GetGame()->GetGameConfig().Gravity * 1.0f * delta;
}
do {
m_Player->AddPosition({dx, dz, dy});
maths::IntersectionData closest { 1.0f, maths::Axis::aY };
for (const maths::AABB& aabb : aabbs) {
auto intersection = hitbox.Intersection(aabb, collision.slide);
if (intersection.has_value()) {
float d = intersection->distance;
if (d < closest.distance) {
maths::Axis axis = intersection->axis;
on_ground |= (axis == maths::Axis::aY);
closest.distance = d;
closest.axis = axis;
}
}
}
if (closest.distance < 0.99f) {
m_Velocity[closest.axis] = 0.0f;
}
collision = closest.ToCollision(collision.slide);
Vec3f v = collision.delta;
m_Player->AddPosition(v);
m_Player->SetVelocity(v);
} while (maths::Length(collision.slide) > 1e-6);
m_OnGround = on_ground;
}
} // namespace input

View File

@@ -13,12 +13,14 @@
#include "blitz/protocol/packets/UpdateGameStatePacket.h"
#include "blitz/protocol/packets/UpdateHealthPacket.h"
#include "client/Client.h"
#include "client/game/ClientWorld.h"
namespace blitz {
namespace client {
ClientGame::ClientGame(Client* client, protocol::PacketDispatcher* dispatcher) :
protocol::PacketHandler(dispatcher), m_Client(client) {
m_World = std::make_unique<ClientWorld>(this);
RegisterHandlers();
}
@@ -31,8 +33,8 @@ void ClientGame::AddPlayer(game::PlayerID player, const std::string& name) {
m_LeaderBoard.AddPlayer(GetPlayerById(player));
}
void ClientGame::RemovePlayer(game::PlayerID player) {
Game::RemovePlayer(player);
m_LeaderBoard.RemovePlayer(player);
Game::RemovePlayer(player);
}
void ClientGame::RegisterHandlers() {
@@ -48,11 +50,17 @@ void ClientGame::RegisterHandlers() {
}
void ClientGame::HandlePacket(const protocol::PlayerJoinPacket* packet) {
if (packet->GetPlayerID() == m_Client->GetPlayerID()) {
m_Client->NotifyListeners(&game::ClientListener::OnGameJoin);
}
AddPlayer(packet->GetPlayerID(), packet->GetPlayerName());
// Initialize camera
if (packet->GetPlayerID() == m_Client->GetPlayerID()) {
m_Client->NotifyListeners(&game::ClientListener::OnSpectatorChange, packet->GetPlayerID());
m_Client->NotifyListeners(&game::ClientListener::OnClientPlayerJoin);
}
}
@@ -68,8 +76,9 @@ void ClientGame::HandlePacket(const protocol::PlayerListPacket* packet) {
void ClientGame::HandlePacket(const protocol::PlayerStatsPacket* packet) {
game::Player* player = m_Client->GetGame()->GetPlayerById(packet->GetPlayerID());
assert(player);
player->SetStats(packet->GetPlayerStats());
if (!player)
return;
player->GetStats() = packet->GetPlayerStats();
m_LeaderBoard.Update();
}
@@ -85,9 +94,7 @@ void ClientGame::HandlePacket(const protocol::UpdateHealthPacket* packet) {
}
void ClientGame::HandlePacket(const protocol::UpdateGameStatePacket* packet) {
m_GameState = packet->GetGameState();
m_GameTimer.SetInterval(packet->GetTimeRemaining());
m_GameTimer.Reset();
Game::UpdateGameState(packet->GetGameState(), packet->GetTimeRemaining());
}
void ClientGame::HandlePacket(const protocol::ServerConfigPacket* packet) {

View File

@@ -0,0 +1,18 @@
#include "client/game/ClientWorld.h"
#include "client/game/ClientGame.h"
#include "client/render/loader/ModelLoader.h"
namespace blitz {
namespace client {
ClientWorld::ClientWorld(ClientGame* game) : game::World(game) {
LoadAABBs();
}
void ClientWorld::LoadAABBs() {
m_AABBs = ModelLoader::LoadModelAABBs("sol.glb");
}
} // namespace client
} // namespace blitz

View File

@@ -11,14 +11,14 @@
namespace blitz {
namespace gui {
BlitzGui::BlitzGui(Client* client) : GuiWidget(nullptr, client) {
BlitzGui::BlitzGui(Client* client, input::InputManager& inputManager) : GuiWidget(nullptr, client) {
Enable();
AddWidget(std::make_unique<GameChatGui>(this, client));
AddWidget(std::make_unique<MainMenu>(client));
AddWidget(std::make_unique<GameChatGui>(this, client, inputManager));
AddWidget(std::make_unique<MainMenu>(client, inputManager));
AddWidget(std::make_unique<CrossHair>(client));
AddWidget(std::make_unique<Hud>(this, client));
AddWidget(std::make_unique<LeaderBoardGui>(this, client));
AddWidget(std::make_unique<ServerGui>(this, client));
AddWidget(std::make_unique<ServerGui>(this, client, inputManager));
SetCustomTheme();
}

View File

@@ -3,7 +3,6 @@
#include "blitz/misc/Format.h"
#include "blitz/misc/Log.h"
#include "client/Client.h"
#include "client/display/InputManager.h"
#include <cmath>
#include <imgui.h>
#include <string>
@@ -11,6 +10,9 @@
namespace blitz {
namespace gui {
CreateGameMenu::CreateGameMenu(GuiWidget* parent, Client* client, input::InputManager& inputManager) :
GuiWidget(parent, client), m_InputManager(inputManager) {}
void CreateGameMenu::Render() {
if (!IsEnabled())
return;
@@ -38,7 +40,7 @@ void CreateGameMenu::Render() {
utils::LOGD(utils::Format("[CreateGameMenu] Port saisi : %i", InputPort));
if (m_Client->CreateGame(InputPort, m_Client->GetConfig()->GetPseudo().data())) {
InputManager::GrabMouse(true);
m_InputManager.GrabMouse(true);
Disable();
}
}

Some files were not shown because too many files have changed in this diff Show More