Compare commits
51 Commits
d3467418c7
...
aabb
| Author | SHA1 | Date | |
|---|---|---|---|
| 17c61c5950 | |||
| 864a15e4c8 | |||
| 7efd8218ea | |||
| 08db7f84b9 | |||
| 7119dea783 | |||
| 6e998fc368 | |||
| 441131a2f5 | |||
| c875fa1dee | |||
| 5e4b318d67 | |||
| 076fa7badc | |||
| 1091abd034 | |||
| dd9ea3ece8 | |||
| 6226161e31 | |||
| 6b32e8878e | |||
| c1ded40cc4 | |||
| 285bf880ee | |||
| 06ff76607d | |||
| 19229bbe8a | |||
| 438bc4a968 | |||
| 9aa546881a | |||
| 4db03f2b83 | |||
| 0119d36b5c | |||
| 249d7534a4 | |||
|
|
abe89d2089 | ||
| f070b28d8b | |||
|
|
a7f734d22e | ||
| 2b0930a734 | |||
|
|
abbc4419fa | ||
| 84b6acad4c | |||
| 9f94d51fc4 | |||
| 9951256881 | |||
|
|
4a02054648 | ||
|
|
19c39312bf | ||
| 86e47601d7 | |||
| d5014b1e8a | |||
|
|
a3b6d2488f | ||
|
|
dccfa9c936 | ||
| e39fc8aa70 | |||
| d42f67724d | |||
| 71bc4dd249 | |||
| 2cb5074140 | |||
| 269ac16d28 | |||
| b7926d7a98 | |||
| 52da1cf19b | |||
| 2da89c8dab | |||
| 88cb433ecf | |||
| d96b01074e | |||
| a1effa05cd | |||
| 7b58117f36 | |||
| bf8a6458a0 | |||
| 18ddede8c0 |
38
.gitea/workflows/ubuntu.yaml
Normal file
38
.gitea/workflows/ubuntu.yaml
Normal file
@@ -0,0 +1,38 @@
|
||||
name: Linux arm64
|
||||
run-name: Build And Test
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
Build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install deps
|
||||
run : |
|
||||
apt update
|
||||
apt install -y libsdl2-dev libassimp-dev libglew-dev
|
||||
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare XMake
|
||||
uses: xmake-io/github-action-setup-xmake@v1
|
||||
with:
|
||||
xmake-version: latest
|
||||
actions-cache-folder: '.xmake-cache'
|
||||
actions-cache-key: 'ubuntu'
|
||||
|
||||
- name: Packages cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.xmake
|
||||
key: 'ubuntu-packages'
|
||||
|
||||
- name: XMake config
|
||||
run: xmake f -p linux -y --root
|
||||
|
||||
- name: Build
|
||||
run: xmake --root
|
||||
|
||||
- name: Test
|
||||
run: xmake test --root
|
||||
32
.github/workflows/macos.yml
vendored
32
.github/workflows/macos.yml
vendored
@@ -1,32 +0,0 @@
|
||||
name: macOS
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
runs-on: macos-latest
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-macOS
|
||||
cancel-in-progress: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: xmake-io/github-action-setup-xmake@v1
|
||||
with:
|
||||
xmake-version: branch@master
|
||||
|
||||
- name: Prepare XMake
|
||||
run: xmake f -p macosx -y
|
||||
|
||||
- name: Build
|
||||
run: xmake
|
||||
|
||||
- name: Test
|
||||
run: xmake test
|
||||
42
.github/workflows/windows.yml
vendored
42
.github/workflows/windows.yml
vendored
@@ -1,42 +0,0 @@
|
||||
name: Windows
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [x64, x86]
|
||||
vs_runtime: [MT, MD]
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.ref }}-${{ github.base_ref }}-${{ github.head_ref }}-Windows-${{ matrix.arch }}-${{ matrix.vs_runtime }}
|
||||
cancel-in-progress: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: xmake-io/github-action-setup-xmake@v1
|
||||
with:
|
||||
xmake-version: branch@master
|
||||
|
||||
- name: Configure Pagefile
|
||||
uses: al-cheb/configure-pagefile-action@v1.2
|
||||
with:
|
||||
minimum-size: 8GB
|
||||
maximum-size: 32GB
|
||||
disk-root: "D:"
|
||||
|
||||
- name: Prepare XMake
|
||||
run: xmake f -p windows -a ${{ matrix.arch }} --vs_runtime=${{ matrix.vs_runtime }} -y
|
||||
|
||||
- name: Build
|
||||
run: xmake
|
||||
|
||||
- name: Test
|
||||
run: xmake test
|
||||
20
.vscode/c_cpp_properties.json
vendored
20
.vscode/c_cpp_properties.json
vendored
@@ -1,11 +1,13 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Blitz",
|
||||
"cppStandard": "c++17",
|
||||
"includePath": ["include"],
|
||||
"compileCommands": ".vscode/compile_commands.json"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Blitz",
|
||||
"cppStandard": "c++17",
|
||||
"includePath": [
|
||||
"include"
|
||||
],
|
||||
"compileCommands": ".vscode/compile_commands.json"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
BIN
assets/cube.glb
Normal file
BIN
assets/cube.glb
Normal file
Binary file not shown.
BIN
assets/fingergun.png
Normal file
BIN
assets/fingergun.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 218 KiB |
BIN
assets/jp.png
Normal file
BIN
assets/jp.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
@@ -10,6 +10,7 @@
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace blitz {
|
||||
|
||||
@@ -180,6 +181,10 @@ class DataBuffer {
|
||||
std::memcpy(newBuffer, data(), GetSize());
|
||||
return newBuffer;
|
||||
}
|
||||
|
||||
bool operator==(const DataBuffer& other) const{
|
||||
return m_Buffer == other.m_Buffer;
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer);
|
||||
|
||||
@@ -28,8 +28,8 @@ class Game {
|
||||
return m_Players;
|
||||
}
|
||||
|
||||
void AddPlayer(PlayerID player, const std::string& name);
|
||||
void RemovePlayer(PlayerID player);
|
||||
virtual void AddPlayer(PlayerID player, const std::string& name);
|
||||
virtual void RemovePlayer(PlayerID player);
|
||||
};
|
||||
|
||||
|
||||
|
||||
15
include/blitz/game/Listeners.h
Normal file
15
include/blitz/game/Listeners.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "blitz/maths/Vector.h"
|
||||
|
||||
namespace blitz {
|
||||
namespace game {
|
||||
|
||||
class PlayerInputListener {
|
||||
public:
|
||||
virtual void OnLocalPlayerJump() {}
|
||||
virtual void OnLocalPlayerShoot(const Vec3f& position, float yaw, float pitch) {}
|
||||
};
|
||||
|
||||
} // namespace game
|
||||
} // namespace blitz
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "blitz/common/Defines.h"
|
||||
#include "blitz/common/Vector.h"
|
||||
#include "blitz/maths/Vector.h"
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "blitz/common/Vector.h"
|
||||
#include "blitz/maths/Vector.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace blitz {
|
||||
@@ -55,6 +55,100 @@ 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
|
||||
|
||||
|
||||
template <typename T>
|
||||
T ReduceMin(const Vec3<T>& vect) {
|
||||
return std::min(std::min(vect.x, vect.y), vect.z);
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
template <>
|
||||
inline float ReduceMin<float>(const Vec3f& v) {
|
||||
return std::fminf(std::fminf(v.x, v.y), v.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief returns the (signed) maximal coordinate of the vector
|
||||
*
|
||||
* @param v
|
||||
* @return constexpr T
|
||||
*/
|
||||
template <>
|
||||
inline float ReduceMax<float>(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
|
||||
*/
|
||||
template <>
|
||||
inline double ReduceMin<double>(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
|
||||
*/
|
||||
template <>
|
||||
inline double ReduceMax<double>(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
|
||||
*/
|
||||
template <typename T>
|
||||
constexpr Vec3<T> Min(const Vec3<T>& self, const Vec3<T>& other) {
|
||||
return {
|
||||
std::min(self.x, other.x),
|
||||
std::min(self.y, other.y),
|
||||
std::min(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
|
||||
*
|
||||
* @tparam T
|
||||
* @param self
|
||||
* @param other
|
||||
* @return constexpr Vec3f
|
||||
*/
|
||||
template <typename T>
|
||||
constexpr Vec3<T> Max(const Vec3<T>& self, const Vec3<T>& other) {
|
||||
return {
|
||||
std::max(self.x, other.x),
|
||||
std::max(self.y, other.y),
|
||||
std::max(self.z, other.z),
|
||||
};
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Matricies //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
@@ -125,6 +219,8 @@ Mat4f Inverse(const Mat4f& mat);
|
||||
|
||||
Mat4f Translate(const Vec3f& translation);
|
||||
|
||||
Mat4f Scale(const Vec3f& axisFactor);
|
||||
|
||||
Mat4f RotateX(float angle);
|
||||
Mat4f RotateY(float angle);
|
||||
Mat4f RotateZ(float angle);
|
||||
30
include/blitz/maths/Physics.h
Normal file
30
include/blitz/maths/Physics.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "blitz/maths/Vector.h"
|
||||
|
||||
namespace blitz {
|
||||
namespace maths {
|
||||
|
||||
struct Ray {
|
||||
Vec3f origin;
|
||||
Vec3f direction;
|
||||
};
|
||||
|
||||
struct AABB {
|
||||
Vec3f from;
|
||||
Vec3f to;
|
||||
};
|
||||
|
||||
inline AABB operator+(const AABB& aabb, const Vec3f& offset) {
|
||||
AABB result = aabb;
|
||||
result.from += offset;
|
||||
result.to += offset;
|
||||
return result;
|
||||
}
|
||||
|
||||
float Distance(const Ray& ray, const AABB& aabb);
|
||||
|
||||
bool Intersects(const Ray& ray, const AABB& aabb);
|
||||
|
||||
} // namespace maths
|
||||
} // namespace blitz
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
|
||||
namespace blitz {
|
||||
@@ -178,7 +180,7 @@ Vec3<T>& operator+=(Vec3<T>& vect, const Vec3<T>& other) {
|
||||
|
||||
template <typename T>
|
||||
constexpr Vec3<T> operator-(const Vec3<T>& vect, const Vec3<T>& other) {
|
||||
return vect + (-other);
|
||||
return {vect.x - other.x, vect.y - other.y, vect.z - other.z};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -197,6 +199,40 @@ constexpr Vec3<T> operator*(T mult, const Vec3<T>& vect) {
|
||||
return vect * mult;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr Vec3<T> operator*=(const Vec3<T>& vect, T mult) {
|
||||
vect = vect * mult;
|
||||
return vect;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr Vec3<T> operator*=(T mult, const Vec3<T>& vect) {
|
||||
vect = vect * mult;
|
||||
return vect;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr Vec3<T> operator*(const Vec3<T>& vect, const Vec3<T>& other) {
|
||||
return {vect.x * other.x, vect.y * other.y, vect.z * other.z};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Vec3<T>& operator*=(Vec3<T>& vect, const Vec3<T>& other) {
|
||||
vect = vect * other;
|
||||
return vect;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr Vec3<T> operator/(const Vec3<T>& vect, const Vec3<T>& other) {
|
||||
return {vect.x / other.x, vect.y / other.y, vect.z / other.z};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Vec3<T>& operator/=(Vec3<T>& vect, const Vec3<T>& other) {
|
||||
vect = vect / other;
|
||||
return vect;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -279,11 +315,11 @@ struct Mat4 {
|
||||
}
|
||||
|
||||
T at(std::size_t row, std::size_t column) const {
|
||||
return operator[](row* MATRIX_SIZE + column);
|
||||
return operator[](row * MATRIX_SIZE + column);
|
||||
}
|
||||
|
||||
T& at(std::size_t row, std::size_t column) {
|
||||
return operator[](row* MATRIX_SIZE + column);
|
||||
return operator[](row * MATRIX_SIZE + column);
|
||||
}
|
||||
};
|
||||
|
||||
25
include/blitz/misc/PrettyLog.h
Normal file
25
include/blitz/misc/PrettyLog.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "blitz/maths/Vector.h"
|
||||
#include <string>
|
||||
|
||||
namespace blitz {
|
||||
namespace utils {
|
||||
|
||||
namespace TextColor {
|
||||
|
||||
const static Vec3uc AQUA = {0, 255, 255};
|
||||
const static Vec3uc BLUE = {0, 0, 255};
|
||||
const static Vec3uc GREEN = {0, 255, 0};
|
||||
const static Vec3uc PURPLE = {255, 0, 255};
|
||||
const static Vec3uc RED = {255, 0, 0};
|
||||
const static Vec3uc WHITE = {255, 255, 255};
|
||||
const static Vec3uc YELLOW = {255, 255, 0};
|
||||
|
||||
} // namespace TextColor
|
||||
|
||||
std::string GetTextColor(Vec3uc color);
|
||||
std::string GetTextColorReset();
|
||||
|
||||
} // namespace utils
|
||||
} // namespace blitz
|
||||
@@ -29,6 +29,7 @@ class PacketHandler {
|
||||
virtual void HandlePacket(const PlayerListPacket* packet) {}
|
||||
virtual void HandlePacket(const PlayerLoginPacket* packet) {}
|
||||
virtual void HandlePacket(const PlayerPositionAndRotationPacket* packet) {}
|
||||
virtual void HandlePacket(const PlayerShootPacket* packet) {}
|
||||
virtual void HandlePacket(const ServerTpsPacket* packet) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -7,4 +7,5 @@
|
||||
#include "packets/PlayerListPacket.h"
|
||||
#include "packets/PlayerLoginPacket.h"
|
||||
#include "packets/PlayerPositionAndRotationPacket.h"
|
||||
#include "packets/PlayerShootPacket.h"
|
||||
#include "packets/ServerTpsPacket.h"
|
||||
@@ -12,6 +12,7 @@ class PlayerLeavePacket;
|
||||
class PlayerListPacket;
|
||||
class PlayerLoginPacket;
|
||||
class PlayerPositionAndRotationPacket;
|
||||
class PlayerShootPacket;
|
||||
class ServerTpsPacket;
|
||||
|
||||
} // namespace protocol
|
||||
|
||||
@@ -35,6 +35,7 @@ enum class PacketType : std::uint8_t {
|
||||
Disconnect, /**< Corresponds to DisconnectPacket */
|
||||
Chat, /**< Corresponds to ChatPacket */
|
||||
PlayerPositionAndRotation, /**< Corresponds to PlayerPositionAndRotationPacket */
|
||||
PlayerShoot, /**< Corresponds to PlayerShootPacket */
|
||||
|
||||
PACKET_COUNT
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "blitz/common/Vector.h"
|
||||
#include "blitz/maths/Vector.h"
|
||||
#include "blitz/protocol/Protocol.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "blitz/common/Defines.h"
|
||||
#include "blitz/common/Vector.h"
|
||||
#include "blitz/maths/Vector.h"
|
||||
#include "blitz/protocol/Protocol.h"
|
||||
|
||||
namespace blitz {
|
||||
|
||||
47
include/blitz/protocol/packets/PlayerShootPacket.h
Normal file
47
include/blitz/protocol/packets/PlayerShootPacket.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include "blitz/game/Player.h"
|
||||
#include "blitz/protocol/Protocol.h"
|
||||
|
||||
namespace blitz {
|
||||
namespace protocol {
|
||||
|
||||
class PlayerShootPacket : public Packet {
|
||||
private:
|
||||
game::PlayerID m_Player; // only used when sent to client
|
||||
Vec3f m_Position;
|
||||
float m_Yaw, m_Pitch;
|
||||
|
||||
public:
|
||||
PlayerShootPacket() {}
|
||||
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() {}
|
||||
|
||||
virtual DataBuffer Serialize(bool packetID = true) const;
|
||||
virtual void Deserialize(DataBuffer& data);
|
||||
virtual void Dispatch(PacketHandler* handler) const;
|
||||
|
||||
const Vec3f& GetPosition() const {
|
||||
return m_Position;
|
||||
}
|
||||
|
||||
float GetYaw() const {
|
||||
return m_Yaw;
|
||||
}
|
||||
|
||||
float GetPitch() const {
|
||||
return m_Pitch;
|
||||
}
|
||||
|
||||
game::PlayerID GetPlayer() const {
|
||||
return m_Player;
|
||||
}
|
||||
|
||||
virtual PacketType GetType() const {
|
||||
return PacketType::PlayerShoot;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace protocol
|
||||
} // namespace blitz
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "blitz/common/Defines.h"
|
||||
#include "blitz/game/Listeners.h"
|
||||
#include "blitz/misc/ObjectNotifier.h"
|
||||
#include "blitz/misc/Time.h"
|
||||
#include "blitz/protocol/packets/ChatPacket.h"
|
||||
@@ -25,11 +26,12 @@ class Server;
|
||||
class GuiListener {
|
||||
public:
|
||||
virtual void OnTextChatReceived(const protocol::ColoredText& text) {}
|
||||
virtual void OnSpectatorChange(const game::PlayerID player) {}
|
||||
virtual void OnSpectatorChange(game::PlayerID player) {}
|
||||
virtual void OnPlayerShoot(game::PlayerID player, const Vec3f& position, float yaw, float pitch) {}
|
||||
};
|
||||
|
||||
// Singleton
|
||||
class Client : public utils::ObjectNotifier<GuiListener> {
|
||||
class Client : public utils::ObjectNotifier<GuiListener>, public game::PlayerInputListener {
|
||||
private:
|
||||
std::unique_ptr<server::Server> m_Server;
|
||||
std::unique_ptr<client::ClientConnexion> m_Connexion;
|
||||
@@ -55,6 +57,8 @@ class Client : public utils::ObjectNotifier<GuiListener> {
|
||||
|
||||
void SendPlayerPosAndLook(const Vec3f& position, float yaw, float pitch);
|
||||
|
||||
virtual void OnLocalPlayerShoot(const Vec3f& position, float yaw, float pitch) override;
|
||||
|
||||
game::PlayerID GetPlayerID() const;
|
||||
|
||||
client::ClientGame* GetGame() {
|
||||
@@ -65,6 +69,12 @@ class Client : public utils::ObjectNotifier<GuiListener> {
|
||||
return &m_Config;
|
||||
}
|
||||
|
||||
bool IsAdmin() const;
|
||||
|
||||
server::Server* GetServer() {
|
||||
return m_Server.get();
|
||||
}
|
||||
|
||||
private:
|
||||
void Reset();
|
||||
|
||||
|
||||
@@ -5,11 +5,24 @@
|
||||
|
||||
namespace blitz {
|
||||
|
||||
enum KeyAction {
|
||||
kaAvancer = 0,
|
||||
kaReculer,
|
||||
kaDroite,
|
||||
kaGauche,
|
||||
kaMax,
|
||||
};
|
||||
|
||||
typedef std::array<int, kaMax> Keybinds;
|
||||
|
||||
class BlitzConfig {
|
||||
private:
|
||||
std::array<char, 256> m_Pseudo;
|
||||
bool m_VSync;
|
||||
bool m_DisplayFps;
|
||||
KeyAction m_CurrentAction;
|
||||
Keybinds m_Keybinds{};
|
||||
|
||||
|
||||
public:
|
||||
BlitzConfig();
|
||||
@@ -35,6 +48,10 @@ class BlitzConfig {
|
||||
m_DisplayFps = display;
|
||||
}
|
||||
|
||||
Keybinds& GetKeys() {
|
||||
return m_Keybinds;
|
||||
}
|
||||
|
||||
private:
|
||||
void LoadConfig();
|
||||
void LoadDefaultConfig();
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "blitz/common/Smoothing.h"
|
||||
#include "blitz/game/Listeners.h"
|
||||
#include "blitz/misc/ObjectNotifier.h"
|
||||
#include "blitz/misc/Time.h"
|
||||
|
||||
namespace blitz {
|
||||
|
||||
class Client;
|
||||
|
||||
namespace game {
|
||||
|
||||
class Player;
|
||||
@@ -13,28 +17,23 @@ class Player;
|
||||
|
||||
namespace input {
|
||||
|
||||
class PlayerListener {
|
||||
public:
|
||||
virtual void OnPlayerJump() {}
|
||||
virtual void OnPlayerShoot() {}
|
||||
};
|
||||
|
||||
class PlayerController : public utils::ObjectNotifier<PlayerListener> {
|
||||
class PlayerController : public utils::ObjectNotifier<game::PlayerInputListener> {
|
||||
private:
|
||||
game::Player* m_Player;
|
||||
Client* m_Client;
|
||||
utils::CooldownTimer<float> m_ShootTimer{1.0f};
|
||||
EMASmoother m_DxSmoother;
|
||||
/// maximum x-axis velocity
|
||||
float m_MaxDx;
|
||||
EMASmoother m_DySmoother;
|
||||
/// current (target) x-axis velocity
|
||||
float m_Dx;
|
||||
EMASmoother m_DySmoother;
|
||||
/// maximum (target) y-axis velocity
|
||||
float m_MaxDy;
|
||||
/// current (target) y-axis velocity
|
||||
float m_Dy;
|
||||
/// current z-axis velocity
|
||||
float m_Dz;
|
||||
/// maximum x-axis velocity
|
||||
float m_MaxDx;
|
||||
/// maximum (target) y-axis velocity
|
||||
float m_MaxDy;
|
||||
/// maximum z-axis velocity (velocity at initial keypress)
|
||||
float m_MaxDz;
|
||||
/// individual gravitational force
|
||||
@@ -43,7 +42,7 @@ class PlayerController : public utils::ObjectNotifier<PlayerListener> {
|
||||
bool m_OnGround;
|
||||
|
||||
public:
|
||||
PlayerController();
|
||||
PlayerController(Client* client);
|
||||
|
||||
void Update(float delta);
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ class ClientGame : public game::Game, public protocol::PacketHandler {
|
||||
virtual void HandlePacket(const protocol::PlayerLeavePacket* packet) override;
|
||||
virtual void HandlePacket(const protocol::PlayerListPacket* packet) override;
|
||||
virtual void HandlePacket(const protocol::PlayerPositionAndRotationPacket* packet) override;
|
||||
virtual void HandlePacket(const protocol::PlayerShootPacket* packet) override;
|
||||
|
||||
private:
|
||||
void RegisterHandlers();
|
||||
|
||||
@@ -15,6 +15,9 @@ class GameChatGui : public GuiWidget, GuiListener {
|
||||
std::vector<protocol::ColoredText> m_Lines;
|
||||
std::vector<protocol::ColoredText> m_TempLines;
|
||||
bool m_FocusRequested = false;
|
||||
int HistoryPos; // -1: new line, 0..History.Size-1 browsing history.
|
||||
bool ScrollToBottom = false;
|
||||
bool AutoScroll = true;
|
||||
float m_ChatDisplay = 0;
|
||||
|
||||
|
||||
|
||||
25
include/client/gui/Hud.h
Normal file
25
include/client/gui/Hud.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "GuiWidget.h"
|
||||
#include "client/Client.h"
|
||||
|
||||
namespace blitz {
|
||||
|
||||
class Client;
|
||||
|
||||
namespace gui {
|
||||
class Hud : public GuiWidget {
|
||||
private:
|
||||
/* data */
|
||||
|
||||
void Draw(const char* title, bool* p_open);
|
||||
unsigned int m_GunTexture;
|
||||
unsigned int m_JP;
|
||||
|
||||
public:
|
||||
Hud(GuiWidget* parent, Client* client);
|
||||
virtual void Render() override;
|
||||
};
|
||||
|
||||
} // namespace gui
|
||||
} // namespace blitz
|
||||
@@ -1,6 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "GuiWidget.h"
|
||||
#include "blitz/misc/Time.h"
|
||||
#include "client/config/BlitzConfig.h"
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
namespace blitz {
|
||||
|
||||
@@ -12,6 +16,10 @@ class OptionsMenu : public GuiWidget {
|
||||
private:
|
||||
bool m_ShowFPS;
|
||||
bool m_VSync;
|
||||
bool m_IsKeyPopupOpen;
|
||||
bool m_KeyPopupShouldClose;
|
||||
utils::Timer m_Timer{100};
|
||||
KeyAction m_CurrentAction;
|
||||
|
||||
public:
|
||||
OptionsMenu(GuiWidget* parent, Client* client);
|
||||
@@ -19,6 +27,11 @@ class OptionsMenu : public GuiWidget {
|
||||
virtual void Render() override;
|
||||
|
||||
void OnKeyEvent(int key);
|
||||
|
||||
private:
|
||||
std::string GetKeyActionCodeName(KeyAction);
|
||||
void HotkeyBindingButton();
|
||||
void HotkeyBindingPopUp();
|
||||
};
|
||||
|
||||
} // namespace gui
|
||||
|
||||
16
include/client/gui/ServerGui.h
Normal file
16
include/client/gui/ServerGui.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "GuiWidget.h"
|
||||
|
||||
namespace blitz {
|
||||
namespace gui {
|
||||
|
||||
class ServerGui : public GuiWidget {
|
||||
public:
|
||||
ServerGui(GuiWidget* parent, Client* client);
|
||||
|
||||
virtual void Render() override;
|
||||
};
|
||||
|
||||
} // namespace gui
|
||||
} // namespace blitz
|
||||
44
include/client/render/BulletRenderer.h
Normal file
44
include/client/render/BulletRenderer.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "blitz/maths/Vector.h"
|
||||
#include "client/render/loader/ModelLoader.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace blitz {
|
||||
|
||||
namespace shader {
|
||||
class BulletShader;
|
||||
} // namespace shader
|
||||
|
||||
|
||||
namespace render {
|
||||
|
||||
class Camera;
|
||||
|
||||
struct Trail {
|
||||
Mat4f m_Transform;
|
||||
float m_Decay;
|
||||
};
|
||||
|
||||
|
||||
class BulletRenderer {
|
||||
private:
|
||||
std::vector<Trail> m_Trails;
|
||||
ModelLoader::Model m_BulletModel;
|
||||
std::unique_ptr<shader::BulletShader> m_Shader;
|
||||
unsigned int m_Vbo;
|
||||
const Camera& m_Camera;
|
||||
|
||||
public:
|
||||
BulletRenderer(const Camera& cam);
|
||||
~BulletRenderer();
|
||||
|
||||
void AddBullet(const Vec3f& origin, float yaw, float pitch);
|
||||
void Update(float delta);
|
||||
void Render();
|
||||
};
|
||||
|
||||
} // namespace render
|
||||
} // namespace blitz
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "blitz/common/Vector.h"
|
||||
#include "blitz/game/Player.h"
|
||||
#include "blitz/maths/Vector.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace blitz {
|
||||
@@ -19,6 +19,8 @@ class Camera {
|
||||
|
||||
void Update(float delta);
|
||||
|
||||
static float GetPlayerEyeHeight();
|
||||
|
||||
void SetAttachedPlayer(game::Player* a_Player) {
|
||||
m_Player = a_Player;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "client/Client.h"
|
||||
#include "client/display/PlayerController.h"
|
||||
#include "client/render/BulletRenderer.h"
|
||||
#include "client/render/Camera.h"
|
||||
#include "client/render/loader/GLLoader.h"
|
||||
#include "client/render/loader/ModelLoader.h"
|
||||
@@ -19,7 +20,7 @@ class GunShader;
|
||||
|
||||
namespace render {
|
||||
|
||||
class MainRenderer : public GuiListener, public input::PlayerListener {
|
||||
class MainRenderer : public GuiListener, public game::PlayerInputListener {
|
||||
private:
|
||||
Client* m_Client;
|
||||
ModelLoader::Model m_PlayerModel;
|
||||
@@ -32,14 +33,15 @@ class MainRenderer : public GuiListener, public input::PlayerListener {
|
||||
unsigned int m_Texture;
|
||||
float m_ShootTime;
|
||||
Camera m_Camera;
|
||||
BulletRenderer m_BulletRenderer;
|
||||
|
||||
public:
|
||||
MainRenderer(Client* client);
|
||||
~MainRenderer();
|
||||
|
||||
virtual void OnSpectatorChange(const game::PlayerID player) override;
|
||||
|
||||
virtual void OnPlayerShoot() override;
|
||||
virtual void OnSpectatorChange(game::PlayerID player) override;
|
||||
virtual void OnPlayerShoot(game::PlayerID player, const Vec3f& position, float yaw, float pitch) override;
|
||||
virtual void OnLocalPlayerShoot(const Vec3f& position, float yaw, float pitch) override;
|
||||
|
||||
void Update();
|
||||
void Render();
|
||||
|
||||
8
include/client/render/OpenGL.h
Normal file
8
include/client/render/OpenGL.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef BLITZ_GL_LOADER_GLBNIDING
|
||||
#include <GL/glew.h>
|
||||
#else
|
||||
#include <glbinding/gl/gl.h>
|
||||
using namespace gl;
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "blitz/maths/Physics.h"
|
||||
#include "client/render/loader/GLLoader.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -12,6 +13,7 @@ typedef std::unique_ptr<GL::VertexArray> VaoPtr;
|
||||
|
||||
struct Model {
|
||||
std::vector<VaoPtr> mVaos;
|
||||
std::vector<maths::AABB> mAABBs;
|
||||
};
|
||||
|
||||
Model LoadModel(const std::string& fileName);
|
||||
|
||||
30
include/client/render/shader/BulletShader.h
Normal file
30
include/client/render/shader/BulletShader.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "ShaderProgram.h"
|
||||
|
||||
namespace blitz {
|
||||
namespace shader {
|
||||
|
||||
class BulletShader : public ShaderProgram {
|
||||
private:
|
||||
unsigned int m_LocationProjectionMatrix = 0;
|
||||
unsigned int m_LocationViewMatrix = 0;
|
||||
unsigned int m_LocationAlpha = 0;
|
||||
unsigned int m_LocationTransform = 0;
|
||||
|
||||
protected:
|
||||
virtual void GetAllUniformLocation() override;
|
||||
|
||||
public:
|
||||
BulletShader();
|
||||
|
||||
bool LoadShader();
|
||||
|
||||
void SetProjectionMatrix(const Mat4f& proj) const;
|
||||
void SetViewMatrix(const Mat4f& view) const;
|
||||
void SetTransform(const Mat4f& trans) const;
|
||||
void SetDecay(float decay) const;
|
||||
};
|
||||
|
||||
} // namespace shader
|
||||
} // namespace blitz
|
||||
@@ -1,8 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "blitz/common/Vector.h"
|
||||
#include <glbinding/SharedBitfield.h>
|
||||
#include <glbinding/gl/enum.h>
|
||||
#include "blitz/maths/Vector.h"
|
||||
#include "client/render/OpenGL.h"
|
||||
#include <string>
|
||||
|
||||
namespace blitz {
|
||||
@@ -37,7 +36,7 @@ class ShaderProgram {
|
||||
unsigned int m_VertexShaderID;
|
||||
unsigned int m_FragmentShaderID;
|
||||
|
||||
int LoadShader(const std::string& source, gl::GLenum type);
|
||||
int LoadShader(const std::string& source, GLenum type);
|
||||
};
|
||||
|
||||
} // namespace shader
|
||||
|
||||
@@ -36,6 +36,8 @@ class Server {
|
||||
|
||||
void Restart();
|
||||
|
||||
void AddBot();
|
||||
|
||||
void RemoveConnexion(std::uint8_t connexionID);
|
||||
|
||||
void BroadcastPacket(const protocol::Packet* packet);
|
||||
@@ -67,6 +69,8 @@ class Server {
|
||||
|
||||
std::uint16_t GetListeningPort();
|
||||
|
||||
game::PlayerID GetNewPlayerID();
|
||||
|
||||
private:
|
||||
void Accept();
|
||||
void UpdateSockets();
|
||||
|
||||
@@ -42,6 +42,7 @@ class ServerConnexion : public network::Connexion {
|
||||
virtual void HandlePacket(const protocol::DisconnectPacket* packet) override;
|
||||
virtual void HandlePacket(const protocol::ChatPacket* packet) override;
|
||||
virtual void HandlePacket(const protocol::PlayerPositionAndRotationPacket* packet) override;
|
||||
virtual void HandlePacket(const protocol::PlayerShootPacket* packet) override;
|
||||
|
||||
std::uint8_t GetID() const {
|
||||
return m_ID;
|
||||
|
||||
@@ -17,6 +17,11 @@ class ServerGame : public game::Game {
|
||||
ServerGame(Server* server);
|
||||
virtual ~ServerGame();
|
||||
|
||||
void CheckShoot(game::PlayerID player, Vec3f position, float yaw, float pitch);
|
||||
|
||||
void AddPlayer(game::PlayerID player, const std::string& name) override;
|
||||
void RemovePlayer(game::PlayerID player) override;
|
||||
|
||||
void Tick(std::uint64_t delta) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -79,7 +79,7 @@ bool DataBuffer::ReadFile(const std::string& fileName) {
|
||||
m_Buffer = DataBuffer::Data(s.begin(), s.end());
|
||||
m_ReadOffset = 0;
|
||||
} catch (std::exception& e) {
|
||||
utils::LOGE(utils::Format("Failed to read file %s ! reason : %s", fileName.c_str(), e.what()));
|
||||
utils::LOGE(utils::Format("[IO] Failed to read file %s ! reason : %s", fileName.c_str(), e.what()));
|
||||
return false;
|
||||
}
|
||||
return m_Buffer.size() > 0;
|
||||
@@ -91,7 +91,7 @@ bool DataBuffer::WriteFile(const std::string& fileName) {
|
||||
file.write(reinterpret_cast<const char*>(m_Buffer.data()), static_cast<std::streamsize>(m_Buffer.size()));
|
||||
file.flush();
|
||||
} catch (std::exception& e) {
|
||||
utils::LOGE(utils::Format("Failed to read file %s ! reason : %s", fileName.c_str(), e.what()));
|
||||
utils::LOGE(utils::Format("[IO] Failed to read file %s ! reason : %s", fileName.c_str(), e.what()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -30,7 +30,7 @@ DataBuffer& operator<<(DataBuffer& out, const VarInt& var) {
|
||||
|
||||
DataBuffer& operator>>(DataBuffer& in, VarInt& var) {
|
||||
var.m_Value = 0;
|
||||
int position = 0;
|
||||
unsigned int position = 0;
|
||||
std::uint8_t currentByte;
|
||||
|
||||
while (true) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "blitz/misc/Maths.h"
|
||||
#include "blitz/maths/Maths.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
@@ -89,12 +89,24 @@ Mat4f Inverse(const Mat4f& mat) {
|
||||
Mat4f Translate(const Vec3f& translation) {
|
||||
Mat4f mat = Identity<float>();
|
||||
|
||||
Vec4f vh {translation.x, translation.y, translation.z, 1.0};
|
||||
Vec4f vh{translation.x, translation.y, translation.z, 1.0};
|
||||
|
||||
mat.at(3, 0) = Dot(Vec4f{mat.at(0, 0), mat.at(1, 0), mat.at(2, 0), mat.at(3, 0)}, vh);
|
||||
mat.at(3, 1) = Dot(Vec4f{mat.at(0, 1), mat.at(1, 1), mat.at(2, 1), mat.at(3, 1)}, vh);
|
||||
mat.at(3, 2) = Dot(Vec4f{mat.at(0, 2), mat.at(1, 2), mat.at(2, 2), mat.at(3, 2)}, vh);
|
||||
mat.at(3, 3) = Dot(Vec4f{mat.at(0, 3), mat.at(1, 3), mat.at(2, 3), mat.at(3, 3)}, vh);
|
||||
mat.at(3, 0) = vh.x;
|
||||
mat.at(3, 1) = vh.y;
|
||||
mat.at(3, 2) = vh.z;
|
||||
mat.at(3, 3) = vh.w;
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
|
||||
Mat4f Scale(const Vec3f& axisFactor) {
|
||||
Mat4f mat{};
|
||||
|
||||
mat.at(0, 0) = axisFactor.x;
|
||||
mat.at(1, 1) = axisFactor.y;
|
||||
mat.at(2, 2) = axisFactor.z;
|
||||
mat.at(3, 3) = 1.0f;
|
||||
|
||||
return mat;
|
||||
}
|
||||
63
src/blitz/maths/Physics.cpp
Executable file
63
src/blitz/maths/Physics.cpp
Executable file
@@ -0,0 +1,63 @@
|
||||
#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) {
|
||||
|
||||
// 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
|
||||
//
|
||||
// min(l, r) < o + t * d < max(l, r)
|
||||
//
|
||||
// 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.from, aabb.to);
|
||||
|
||||
// m - o < t * d < M - o
|
||||
l -= ray.origin;
|
||||
r -= ray.origin;
|
||||
|
||||
// (m - o) / d < t < (M - o) / d
|
||||
l /= ray.direction;
|
||||
r /= ray.direction;
|
||||
|
||||
// but if d is negative the inequality is flipped
|
||||
l = Min(l, r);
|
||||
r = Max(l, r);
|
||||
|
||||
float tmin = ReduceMax(l);
|
||||
float tmax = ReduceMin(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
|
||||
// (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 (tmin <= tmax) {
|
||||
return std::fmaxf(tmin, 0.0f);
|
||||
}
|
||||
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
bool Intersects(const Ray& ray, const AABB& aabb) {
|
||||
return Distance(ray, aabb) >= 0.0f;
|
||||
}
|
||||
|
||||
} // namespace maths
|
||||
} // namespace blitz
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "blitz/misc/Easing.h"
|
||||
|
||||
#include "blitz/misc/Maths.h"
|
||||
#include "blitz/maths/Maths.h"
|
||||
|
||||
namespace blitz {
|
||||
namespace utils {
|
||||
|
||||
15
src/blitz/misc/PrettyLog.cpp
Normal file
15
src/blitz/misc/PrettyLog.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "blitz/misc/PrettyLog.h"
|
||||
|
||||
namespace blitz {
|
||||
namespace utils {
|
||||
|
||||
std::string GetTextColor(Vec3uc color) {
|
||||
return "\033[38;2;" + std::to_string(+color.r) + ";" + std::to_string(color.g) + ";" + std::to_string(color.b) + "m";
|
||||
}
|
||||
|
||||
std::string GetTextColorReset() {
|
||||
return "\033[0m";
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
} // namespace blitz
|
||||
@@ -9,9 +9,9 @@ namespace network {
|
||||
NetworkInitializer::NetworkInitializer() {
|
||||
WSADATA wsaData;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) < 0) {
|
||||
utils::LOGE("Failed to initialize network !");
|
||||
utils::LOGE("[Network] Failed to initialize network !");
|
||||
} else {
|
||||
utils::LOG("Network initialized !");
|
||||
utils::LOG("[Network] Network initialized !");
|
||||
}
|
||||
}
|
||||
NetworkInitializer::~NetworkInitializer() {
|
||||
|
||||
@@ -19,7 +19,7 @@ TCPListener::~TCPListener() {
|
||||
|
||||
bool TCPListener::Listen(std::uint16_t port, int maxConnections) {
|
||||
if ((m_Handle = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
|
||||
utils::LOGE("Failed to create server socket !");
|
||||
utils::LOGE("[TCPListener] Failed to create server socket !");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace blitz {
|
||||
namespace network {
|
||||
|
||||
TCPSocket::TCPSocket() :
|
||||
m_Blocking(false), m_Status(Status::Disconnected), m_Port(0), m_Handle(static_cast<SocketHandle>(INVALID_SOCKET)) {}
|
||||
m_Blocking(false), m_Status(Status::Disconnected), m_Handle(static_cast<SocketHandle>(INVALID_SOCKET)), m_Port(0) {}
|
||||
|
||||
|
||||
TCPSocket::TCPSocket(TCPSocket&& other) {
|
||||
@@ -79,13 +79,13 @@ bool TCPSocket::Connect(const std::string& host, unsigned short port) {
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
if (getaddrinfo(host.c_str(), std::to_string(static_cast<int>(port)).c_str(), &hints, &result) != 0) {
|
||||
utils::LOGE("Failed to get address info !");
|
||||
utils::LOGE("[TCPSocket] Failed to get address info !");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Handle = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (m_Handle < 0) {
|
||||
utils::LOGE("Failed to create socket !");
|
||||
utils::LOGE("[TCPSocket] Failed to create socket !");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ bool TCPSocket::Connect(const std::string& host, unsigned short port) {
|
||||
for (ptr = result; ptr != nullptr; ptr = ptr->ai_next) {
|
||||
struct sockaddr* sockaddr = ptr->ai_addr;
|
||||
if (connect(m_Handle, sockaddr, sizeof(sockaddr_in)) != 0) {
|
||||
utils::LOGE("Failed to connect with this address !");
|
||||
utils::LOGE("[TCPSocket] Failed to connect with this address !");
|
||||
continue;
|
||||
}
|
||||
m_RemoteAddr = *sockaddr;
|
||||
@@ -103,7 +103,7 @@ bool TCPSocket::Connect(const std::string& host, unsigned short port) {
|
||||
freeaddrinfo(result);
|
||||
|
||||
if (!ptr) {
|
||||
utils::LOGE("Could not find a suitable interface for connecting !");
|
||||
utils::LOGE("[TCPSocket] Could not find a suitable interface for connecting !");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ static std::array<PacketPtr, static_cast<std::size_t>(PacketType::PACKET_COUNT)>
|
||||
std::make_unique<DisconnectPacket>(),
|
||||
std::make_unique<ChatPacket>(),
|
||||
std::make_unique<PlayerPositionAndRotationPacket>(),
|
||||
std::make_unique<PlayerShootPacket>(),
|
||||
};
|
||||
|
||||
const Packet* CreatePacket(PacketType type, DataBuffer& buffer) {
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#include "blitz/protocol/Packets.h"
|
||||
|
||||
#define REGISTER_DISPATCH_CLASS(className) \
|
||||
void className::Dispatch(PacketHandler* handler) const { handler->HandlePacket(this); }
|
||||
void className::Dispatch(PacketHandler* handler) const { \
|
||||
handler->HandlePacket(this); \
|
||||
}
|
||||
|
||||
namespace blitz {
|
||||
namespace protocol {
|
||||
@@ -22,6 +24,7 @@ REGISTER_DISPATCH_CLASS(DisconnectPacket)
|
||||
REGISTER_DISPATCH_CLASS(ServerTpsPacket)
|
||||
REGISTER_DISPATCH_CLASS(ChatPacket)
|
||||
REGISTER_DISPATCH_CLASS(PlayerPositionAndRotationPacket)
|
||||
REGISTER_DISPATCH_CLASS(PlayerShootPacket);
|
||||
|
||||
} // namespace protocol
|
||||
} // namespace blitz
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "blitz/protocol/packets/ChatPacket.h"
|
||||
|
||||
#include "blitz/common/Vector.h"
|
||||
#include "blitz/maths/Vector.h"
|
||||
#include "blitz/misc/Log.h"
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
@@ -84,7 +84,7 @@ ColoredText ChatPacket::ColorizeText(const std::string& text) {
|
||||
static_cast<float>(std::stoul(blue, nullptr, 16)) / 255.0f, 1.0f};
|
||||
cursor += 6;
|
||||
} catch (std::exception& e) {
|
||||
utils::LOG("warning ! wrong color providen !");
|
||||
utils::LOG("[ChatPacket] warning ! wrong color providen !");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ void PlayerListPacket::Deserialize(DataBuffer& data) {
|
||||
VarInt playerCount;
|
||||
data >> playerCount;
|
||||
|
||||
for (int i = 0; i < playerCount.GetValue(); i++) {
|
||||
for (std::size_t i = 0; i < playerCount.GetValue(); i++) {
|
||||
std::uint8_t playerID;
|
||||
PlayerInfo playerInfo;
|
||||
data >> playerID >> playerInfo.name;
|
||||
|
||||
19
src/blitz/protocol/packets/PlayerShootPacket.cpp
Normal file
19
src/blitz/protocol/packets/PlayerShootPacket.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include "blitz/protocol/packets/PlayerShootPacket.h"
|
||||
|
||||
namespace blitz {
|
||||
namespace protocol {
|
||||
|
||||
DataBuffer PlayerShootPacket::Serialize(bool packetID) const {
|
||||
DataBuffer data;
|
||||
|
||||
WritePacketID(data, packetID);
|
||||
data << m_Player << m_Position << m_Yaw << m_Pitch;
|
||||
return data;
|
||||
}
|
||||
|
||||
void PlayerShootPacket::Deserialize(DataBuffer& data) {
|
||||
data >> m_Player >> m_Position >> m_Yaw >> m_Pitch;
|
||||
}
|
||||
|
||||
} // namespace protocol
|
||||
} // namespace blitz
|
||||
@@ -9,7 +9,7 @@ namespace utils {
|
||||
namespace AssetsManager {
|
||||
|
||||
DataBuffer GetAsset(const std::string& fileName) {
|
||||
utils::LOGD(utils::Format("Opening file %s...", fileName.c_str()));
|
||||
utils::LOGD(utils::Format("[AssetsManager] Opening file %s...", fileName.c_str()));
|
||||
|
||||
SDL_RWops* io = SDL_RWFromFile(fileName.c_str(), "rb");
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "blitz/protocol/packets/ChatPacket.h"
|
||||
#include "blitz/protocol/packets/DisconnectPacket.h"
|
||||
#include "blitz/protocol/packets/PlayerPositionAndRotationPacket.h"
|
||||
#include "blitz/protocol/packets/PlayerShootPacket.h"
|
||||
#include "client/ClientConnexion.h"
|
||||
#include "client/game/ClientGame.h"
|
||||
#include "server/Server.h"
|
||||
@@ -78,6 +79,13 @@ void Client::SendPlayerPosAndLook(const Vec3f& position, float yaw, float pitch)
|
||||
m_Connexion->SendPacket(&packet);
|
||||
}
|
||||
|
||||
|
||||
void Client::OnLocalPlayerShoot(const Vec3f& position, float yaw, float pitch) {
|
||||
protocol::PlayerShootPacket packet(position, yaw, pitch);
|
||||
m_Connexion->SendPacket(&packet);
|
||||
}
|
||||
|
||||
|
||||
game::PlayerID Client::GetPlayerID() const {
|
||||
return m_Connexion->GetPlayerID();
|
||||
}
|
||||
@@ -86,6 +94,10 @@ bool Client::IsConnected() {
|
||||
return m_Connexion->GetSocketStatus() == network::TCPSocket::Status::Connected;
|
||||
}
|
||||
|
||||
bool Client::IsAdmin() const {
|
||||
return m_Server->IsRunning();
|
||||
}
|
||||
|
||||
void Client::UpdatePosition(std::uint64_t delta) {
|
||||
// send position every tick (50 ms)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "blitz/misc/Format.h"
|
||||
#include "blitz/misc/Log.h"
|
||||
#include "blitz/misc/PrettyLog.h"
|
||||
#include "blitz/protocol/packets/ChatPacket.h"
|
||||
#include "blitz/protocol/packets/ConnexionInfoPacket.h"
|
||||
#include "blitz/protocol/packets/KeepAlivePacket.h"
|
||||
@@ -11,6 +12,17 @@
|
||||
namespace blitz {
|
||||
namespace client {
|
||||
|
||||
static std::string PrintColoredText(const protocol::ColoredText& coloredText) {
|
||||
std::string text;
|
||||
for (const auto& part : coloredText) {
|
||||
text += utils::GetTextColor({static_cast<std::uint8_t>(part.color.r * 255), static_cast<std::uint8_t>(part.color.g * 255),
|
||||
static_cast<std::uint8_t>(part.color.b * 255)}) +
|
||||
part.text;
|
||||
}
|
||||
text += utils::GetTextColorReset();
|
||||
return text;
|
||||
}
|
||||
|
||||
ClientConnexion::ClientConnexion(Client* client) : network::Connexion(&m_Dispatcher), m_Client(client) {
|
||||
RegisterHandlers();
|
||||
}
|
||||
@@ -35,7 +47,7 @@ bool ClientConnexion::Connect(const std::string& pseudo, const std::string& addr
|
||||
}
|
||||
|
||||
void ClientConnexion::HandlePacket(const protocol::ChatPacket* packet) {
|
||||
utils::LOG(utils::Format("Chat : %s", protocol::ChatPacket::GetColoredTextString(packet->GetMessage()).c_str()));
|
||||
utils::LOG("[Chat] " + PrintColoredText(packet->GetMessage()));
|
||||
m_Client->ChatTextReceived(packet->GetMessage());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "client/config/BlitzConfig.h"
|
||||
|
||||
#include "blitz/misc/Log.h"
|
||||
#include "imgui.h"
|
||||
#include <fstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@@ -22,7 +23,7 @@ void BlitzConfig::LoadConfig() {
|
||||
LoadDefaultConfig();
|
||||
|
||||
if (!file) {
|
||||
utils::LOG("Could not load config !");
|
||||
utils::LOG("[BlitzConfig] Could not load config !");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -36,8 +37,11 @@ void BlitzConfig::LoadConfig() {
|
||||
std::memcpy(m_Pseudo.data(), pseudo.data(), pseudo.size() + 1);
|
||||
jsonInput.at("vsync").get_to<bool>(m_VSync);
|
||||
jsonInput.at("fps").get_to<bool>(m_DisplayFps);
|
||||
jsonInput.at("keys").get_to<Keybinds>(m_Keybinds);
|
||||
|
||||
utils::LOG("[BlitzConfig] Restored config !");
|
||||
} catch (std::exception& e) {
|
||||
utils::LOGE("Failed to load config !");
|
||||
utils::LOGE("[BlitzConfig] Failed to load config !");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,19 +50,21 @@ void BlitzConfig::LoadDefaultConfig() {
|
||||
m_VSync = true;
|
||||
const char defaultPseudo[] = "Pseudo";
|
||||
std::memcpy(m_Pseudo.data(), defaultPseudo, sizeof(defaultPseudo));
|
||||
m_Keybinds = {ImGuiKey_Z, ImGuiKey_S, ImGuiKey_D, ImGuiKey_Q};
|
||||
}
|
||||
|
||||
void BlitzConfig::SaveConfig() {
|
||||
std::ofstream file{"settings.json"};
|
||||
|
||||
if (!file) {
|
||||
utils::LOGE("Could not save config !");
|
||||
utils::LOGE("[BlitzConfig] Could not save config !");
|
||||
}
|
||||
|
||||
json jsonOutput = {
|
||||
{"pseudo", GetPseudo().data()},
|
||||
{"vsync", IsVSyncEnabled()},
|
||||
{"fps", IsFPSDisplayEnabled()},
|
||||
{"keys", GetKeys()},
|
||||
};
|
||||
|
||||
file << jsonOutput;
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#include "client/display/Display.h"
|
||||
|
||||
#include "client/display/InputManager.h"
|
||||
#include "client/render/OpenGL.h"
|
||||
#include <SDL2/SDL.h>
|
||||
#include <backends/imgui_impl_opengl3.h>
|
||||
#include <backends/imgui_impl_sdl2.h>
|
||||
#include <glbinding/gl/gl.h>
|
||||
#include <glbinding/glbinding.h>
|
||||
|
||||
#include "blitz/misc/Format.h"
|
||||
#include "blitz/misc/Log.h"
|
||||
@@ -13,17 +12,21 @@
|
||||
|
||||
#include "client/gui/BlitzGui.h"
|
||||
|
||||
using namespace gl;
|
||||
#ifndef BLITZ_GL_LOADER_GLBNIDING
|
||||
#include <GL/glew.h>
|
||||
#else
|
||||
#include <glbinding/glbinding.h>
|
||||
#endif
|
||||
|
||||
namespace blitz {
|
||||
|
||||
Display::Display(int width, int height, const std::string& windowName, Client* client) :
|
||||
m_WindowWidth(width),
|
||||
m_WindowHeight(height),
|
||||
m_AspectRatio(m_WindowHeight / static_cast<float>(m_WindowWidth)),
|
||||
m_WindowName(windowName),
|
||||
m_ShouldClose(false),
|
||||
m_FullScreen(false),
|
||||
m_AspectRatio(m_WindowHeight / static_cast<float>(m_WindowWidth)),
|
||||
m_Client(client),
|
||||
m_BlitzGui(nullptr) {}
|
||||
|
||||
@@ -52,7 +55,7 @@ bool Display::Create() {
|
||||
m_GL_Context = SDL_GL_CreateContext(m_Window);
|
||||
|
||||
if (!m_GL_Context) {
|
||||
utils::LOGE(utils::Format("Could not create context ! SDL error : %s", SDL_GetError()));
|
||||
utils::LOGE(utils::Format("[Display] Could not create context ! SDL error : %s", SDL_GetError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -86,15 +89,23 @@ bool Display::Create() {
|
||||
}
|
||||
|
||||
utils::LOG(utils::Format(
|
||||
"GL Context : %i.%i %s, Color : R:%i G:%i B:%i A:%i, Depth bits : %i", major, minor, mask_desc, r, g, b, a, depth));
|
||||
utils::LOG(
|
||||
utils::Format("Antialiasing : %s, Number of samples per pixel : %i", multisamples ? "true" : "false", multisamplescount));
|
||||
utils::LOG(utils::Format("Screen keyboard supported : %s", SDL_HasScreenKeyboardSupport() ? "true" : "false"));
|
||||
"[Display] GL Context : %i.%i %s, Color : R:%i G:%i B:%i A:%i, Depth bits : %i", major, minor, mask_desc, r, g, b, a, depth));
|
||||
utils::LOG(utils::Format(
|
||||
"[Display] Antialiasing : %s, Number of samples per pixel : %i", multisamples ? "true" : "false", multisamplescount));
|
||||
utils::LOG(utils::Format("[Display] Screen keyboard supported : %s", SDL_HasScreenKeyboardSupport() ? "true" : "false"));
|
||||
|
||||
SDL_GL_MakeCurrent(m_Window, m_GL_Context);
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
|
||||
#ifndef BLITZ_GL_LOADER_GLBNIDING
|
||||
GLenum error = glewInit();
|
||||
if (error != GLEW_OK) {
|
||||
utils::LOGE(utils::Format("[Display] Failed to initialise glew : %s", glewGetErrorString(error)));
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
glbinding::initialize(reinterpret_cast<glbinding::ProcAddress (*)(const char*)>(SDL_GL_GetProcAddress));
|
||||
#endif
|
||||
|
||||
InitImGui();
|
||||
return true;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "client/display/PlayerController.h"
|
||||
|
||||
#include "blitz/game/Player.h"
|
||||
#include "blitz/maths/Maths.h"
|
||||
#include "blitz/misc/Log.h"
|
||||
#include "blitz/misc/Maths.h"
|
||||
#include "client/Client.h"
|
||||
#include "client/display/InputManager.h"
|
||||
#include "imgui.h"
|
||||
#include <algorithm>
|
||||
@@ -18,17 +19,17 @@ 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() :
|
||||
PlayerController::PlayerController(Client* client) :
|
||||
m_Player(nullptr),
|
||||
m_Client(client),
|
||||
m_Dx(0.0),
|
||||
m_Dy(0.0),
|
||||
m_Dz(0.0),
|
||||
m_MaxDx(DEFAULT_MAX_LR_SPEED),
|
||||
m_MaxDy(DEFAULT_MAX_FB_SPEED),
|
||||
m_MaxDz(DEFAULT_JUMP_VEL),
|
||||
m_Dz(0.0),
|
||||
m_G(DEFAULT_GRAVITY),
|
||||
m_OnGround(true)
|
||||
{
|
||||
m_OnGround(true) {
|
||||
m_DxSmoother.Current = 0.0f;
|
||||
m_DySmoother.Current = 0.0f;
|
||||
m_DxSmoother.SetSmoothingTime(DEFAULT_LR_SPEED_SMOOTHING_TIME);
|
||||
@@ -53,8 +54,11 @@ void PlayerController::Update(float delta) {
|
||||
return;
|
||||
|
||||
if (InputManager::MouseGrabbed()) {
|
||||
float lr = static_cast<float>(ImGui::IsKeyDown(ImGuiKey_Z)) - static_cast<float>(ImGui::IsKeyDown(ImGuiKey_S));
|
||||
float fb = static_cast<float>(ImGui::IsKeyDown(ImGuiKey_Q)) - static_cast<float>(ImGui::IsKeyDown(ImGuiKey_D));
|
||||
Keybinds keys = m_Client->GetConfig()->GetKeys();
|
||||
float lr = static_cast<float>(ImGui::IsKeyDown((ImGuiKey(keys[kaAvancer])))) -
|
||||
static_cast<float>(ImGui::IsKeyDown((ImGuiKey(keys[kaReculer]))));
|
||||
float fb = static_cast<float>(ImGui::IsKeyDown((ImGuiKey(keys[kaGauche])))) -
|
||||
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);
|
||||
@@ -64,12 +68,13 @@ void PlayerController::Update(float delta) {
|
||||
|
||||
if (ImGui::IsKeyDown(ImGuiKey::ImGuiKey_Space) && m_OnGround) {
|
||||
m_Dz = m_MaxDz;
|
||||
NotifyListeners(&PlayerListener::OnPlayerJump);
|
||||
NotifyListeners(&game::PlayerInputListener::OnLocalPlayerJump);
|
||||
}
|
||||
|
||||
bool canShoot = m_ShootTimer.Update(delta);
|
||||
if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && canShoot) {
|
||||
NotifyListeners(&PlayerListener::OnPlayerShoot);
|
||||
NotifyListeners(
|
||||
&game::PlayerInputListener::OnLocalPlayerShoot, m_Player->GetPosition(), m_Player->GetYaw(), m_Player->GetPitch());
|
||||
m_ShootTimer.ApplyCooldown();
|
||||
}
|
||||
}
|
||||
@@ -98,7 +103,7 @@ void PlayerController::UpdatePosition(const float delta) {
|
||||
// assumed to be a negative number
|
||||
const float floor_dist = 0.0f - m_Player->GetPosition().y;
|
||||
|
||||
if (m_OnGround = dz <= floor_dist) {
|
||||
if ((m_OnGround = (dz <= floor_dist))) {
|
||||
dz = floor_dist;
|
||||
m_Dz = 0.0f;
|
||||
} else {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "blitz/protocol/packets/PlayerLeavePacket.h"
|
||||
#include "blitz/protocol/packets/PlayerListPacket.h"
|
||||
#include "blitz/protocol/packets/PlayerPositionAndRotationPacket.h"
|
||||
#include "blitz/protocol/packets/PlayerShootPacket.h"
|
||||
#include "client/Client.h"
|
||||
|
||||
namespace blitz {
|
||||
@@ -25,6 +26,7 @@ void ClientGame::RegisterHandlers() {
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerLeave, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerList, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerPositionAndRotation, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerShoot, this);
|
||||
}
|
||||
|
||||
void ClientGame::HandlePacket(const protocol::PlayerJoinPacket* packet) {
|
||||
@@ -46,6 +48,11 @@ void ClientGame::HandlePacket(const protocol::PlayerListPacket* packet) {
|
||||
}
|
||||
}
|
||||
|
||||
void ClientGame::HandlePacket(const protocol::PlayerShootPacket* packet) {
|
||||
m_Client->NotifyListeners(
|
||||
&GuiListener::OnPlayerShoot, packet->GetPlayer(), packet->GetPosition(), packet->GetYaw(), packet->GetPitch());
|
||||
}
|
||||
|
||||
void ClientGame::HandlePacket(const protocol::PlayerPositionAndRotationPacket* packet) {
|
||||
if (packet->GetPlayer() == m_Client->GetPlayerID())
|
||||
return;
|
||||
@@ -61,7 +68,6 @@ void ClientGame::HandlePacket(const protocol::PlayerPositionAndRotationPacket* p
|
||||
}
|
||||
|
||||
void ClientGame::Tick(std::uint64_t delta) {
|
||||
float deltaTime = static_cast<float>(delta) / 1000.0f;
|
||||
for (auto& [playerId, player] : GetPlayers()) {
|
||||
player.SetPosition(player.GetPosition() + player.GetVelocity() * (static_cast<float>(delta) / 100.0f));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "client/gui/BlitzGui.h"
|
||||
|
||||
#include "client/gui/GameChatGui.h"
|
||||
#include "client/gui/Hud.h"
|
||||
#include "client/gui/MainMenu.h"
|
||||
#include "client/gui/ServerGui.h"
|
||||
#include <imgui.h>
|
||||
|
||||
namespace blitz {
|
||||
@@ -11,6 +13,8 @@ BlitzGui::BlitzGui(Client* client) : GuiWidget(nullptr, client) {
|
||||
Enable();
|
||||
AddWidget(std::make_unique<GameChatGui>(this, client));
|
||||
AddWidget(std::make_unique<MainMenu>(client));
|
||||
AddWidget(std::make_unique<ServerGui>(this, client));
|
||||
AddWidget(std::make_unique<Hud>(this, client));
|
||||
SetCustomTheme();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
#include "client/gui/ColorFulText.h"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
|
||||
namespace blitz {
|
||||
namespace gui {
|
||||
|
||||
void RenderColorfulText(const protocol::ColoredText& parts, float alpha) {
|
||||
ImGuiContext& g = *ImGui::GetCurrentContext();
|
||||
for (auto& part : parts) {
|
||||
ImGui::TextColored({part.color.r, part.color.g, part.color.b, alpha}, part.text.c_str());
|
||||
const bool need_backup = (g.CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set
|
||||
if (need_backup)
|
||||
ImGui::PushTextWrapPos(0.0f);
|
||||
ImGui::TextColored({part.color.r, part.color.g, part.color.b, alpha}, "%s", part.text.c_str());
|
||||
if (need_backup)
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - ImGui::CalcTextSize(".").x);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ void CreateGameMenu::Render() {
|
||||
SetNextWindowFullScreen();
|
||||
|
||||
static int InputPort = 0;
|
||||
const static ImVec2 buttonSize = {300, 60};
|
||||
auto displaySize = ImGui::GetIO().DisplaySize;
|
||||
const static int paddingHeight = 40;
|
||||
|
||||
ImGui::Begin("CreateWindow", nullptr, GetWindowFullScreenFlags());
|
||||
{
|
||||
@@ -32,7 +35,7 @@ void CreateGameMenu::Render() {
|
||||
ImGui::Text("Port saisi : %d", InputPort);
|
||||
|
||||
if (ImGui::Button("Creer")) {
|
||||
utils::LOGD(utils::Format("Port saisi : %i", InputPort));
|
||||
utils::LOGD(utils::Format("[CreateGameMenu] Port saisi : %i", InputPort));
|
||||
|
||||
if (m_Client->CreateGame(InputPort, m_Client->GetConfig()->GetPseudo().data())) {
|
||||
InputManager::GrabMouse(true);
|
||||
@@ -40,7 +43,9 @@ void CreateGameMenu::Render() {
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::Button("Retour") || ImGui::IsKeyPressed(ImGuiKey_Escape)) {
|
||||
ImGui::SetCursorPosX(displaySize.x - buttonSize.x - paddingHeight);
|
||||
ImGui::SetCursorPosY(displaySize.y - buttonSize.y - paddingHeight);
|
||||
if (ImGui::Button("Retour", buttonSize) || ImGui::IsKeyPressed(ImGuiKey_Escape)) {
|
||||
Disable();
|
||||
m_Parent->Enable();
|
||||
}
|
||||
|
||||
@@ -21,22 +21,15 @@ GameChatGui::GameChatGui(GuiWidget* parent, Client* client) : GuiWidget(parent,
|
||||
}
|
||||
|
||||
void GameChatGui::Draw(const char* title, bool* p_open) {
|
||||
HistoryPos = -1;
|
||||
static int chat_width = 620;
|
||||
static int chat_height = 450;
|
||||
static int chatInput_width = 590;
|
||||
static int scrolling_width = chat_height - 90;
|
||||
ImGui::SetNextWindowPos(ImVec2(0, ImGui::GetIO().DisplaySize.y - chat_height));
|
||||
ImGui::SetNextWindowPos(ImVec2(0, ImGui::GetIO().DisplaySize.y - 2 * chat_height));
|
||||
ImGui::SetNextWindowSize(ImVec2(chat_width, chat_height));
|
||||
// const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
|
||||
ImGui::Begin(title, p_open, GetWindowFullScreenFlags());
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 0.0f, 0.73f));
|
||||
if (ImGui::BeginChild("ChatContent", ImVec2(0, chat_height - 90), false, ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
||||
for (const auto& line : m_Lines) {
|
||||
RenderColorfulText(line, 1);
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::EndChild();
|
||||
ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_EscapeClearsAll;
|
||||
|
||||
if (m_FocusRequested) {
|
||||
@@ -44,6 +37,10 @@ void GameChatGui::Draw(const char* title, bool* p_open) {
|
||||
m_FocusRequested = false;
|
||||
}
|
||||
|
||||
for (const auto& line : m_Lines) {
|
||||
RenderColorfulText(line, 1);
|
||||
}
|
||||
|
||||
const static ImVec4 chatColorInputText = {1.0f, 0.0f, 0.0f, 0.27f};
|
||||
ImGui::SetNextItemWidth(chatInput_width);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, chatColorInputText);
|
||||
@@ -51,6 +48,11 @@ void GameChatGui::Draw(const char* title, bool* p_open) {
|
||||
m_Client->SendChatText(InputBuf);
|
||||
InputBuf[0] = '\0';
|
||||
}
|
||||
|
||||
if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
|
||||
ImGui::SetScrollHereY(1.0f);
|
||||
ScrollToBottom = false;
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
@@ -59,14 +61,18 @@ void GameChatGui::Draw(const char* title, bool* p_open) {
|
||||
|
||||
void GameChatGui::DrawMini(const char* title, bool* p_open) {
|
||||
static int chat_width = 620;
|
||||
static int chat_height = 110;
|
||||
ImGui::SetNextWindowPos(ImVec2(0, ImGui::GetIO().DisplaySize.y - chat_height));
|
||||
static int chat_height = 225;
|
||||
ImGui::SetNextWindowPos(ImVec2(0, ImGui::GetIO().DisplaySize.y - 3.5 * chat_height));
|
||||
ImGui::SetNextWindowSize(ImVec2(chat_width, chat_height));
|
||||
ImGui::Begin(title, p_open, GetWindowFullScreenFlags() | ImGuiWindowFlags_NoNav);
|
||||
{
|
||||
for (const auto& line : m_TempLines) {
|
||||
RenderColorfulText(line, utils::EaseOutCubic(m_ChatDisplay / ChatFadeTime));
|
||||
}
|
||||
|
||||
if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
|
||||
ImGui::SetScrollHereY(1.0f);
|
||||
ScrollToBottom = false;
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
90
src/client/gui/Hud.cpp
Normal file
90
src/client/gui/Hud.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
#include "client/gui/Hud.h"
|
||||
|
||||
#include "client/gui/GuiWidget.h"
|
||||
#include "client/render/loader/TextureLoader.h"
|
||||
#include <client/Client.h>
|
||||
#include <imgui.h>
|
||||
|
||||
namespace blitz {
|
||||
namespace gui {
|
||||
|
||||
Hud::Hud(GuiWidget* parent, Client* client) : GuiWidget(parent, client) {
|
||||
m_GunTexture = TextureLoader::LoadGLTexture("fingergun.png");
|
||||
m_JP = TextureLoader::LoadGLTexture("jp.png");
|
||||
}
|
||||
|
||||
void Hud::Draw(const char* title, bool* p_open) {
|
||||
|
||||
SetNextWindowFullScreen();
|
||||
ImGui::Begin(title, nullptr, GetWindowFullScreenFlags() | ImGuiWindowFlags_NoInputs);
|
||||
|
||||
auto displaySize = ImGui::GetIO().DisplaySize;
|
||||
const static ImVec2 buttonSize = {300, 60};
|
||||
const static ImVec2 fingergunSize = {256, 134.5};
|
||||
const static ImVec2 jpSize = {256 / 2, 256 / 2};
|
||||
const static int paddingHeight = 40;
|
||||
const static ImVec2 pvBarPos = {displaySize.x / 2.2f, displaySize.y - 3 * paddingHeight};
|
||||
const static ImVec2 progressSize = {100.0f, 30.0f};
|
||||
const static ImVec2 currentWeaponPos = {
|
||||
displaySize.x - buttonSize.x - 3 * paddingHeight, displaySize.y - buttonSize.y - 1.5f * paddingHeight};
|
||||
const static ImVec2 currentWeaponPosImage = {
|
||||
displaySize.x - fingergunSize.x - paddingHeight, displaySize.y - fingergunSize.y + 1.0f / 2.5f * paddingHeight};
|
||||
ImVec2 spacing = ImGui::GetStyle().ItemInnerSpacing;
|
||||
|
||||
ImGui::SetCursorPosX(3 * paddingHeight);
|
||||
ImGui::SetCursorPosY(pvBarPos.y - 2 * paddingHeight);
|
||||
ImGui::BeginGroup();
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(m_JP), jpSize);
|
||||
|
||||
ImGui::SameLine(0.0f, paddingHeight);
|
||||
// ImGui::EndGroup();
|
||||
|
||||
// ImGui::SetCursorPosX(pvBarPos.x);
|
||||
// ImGui::SetCursorPosY(pvBarPos.y);
|
||||
ImGui::BeginGroup();
|
||||
{
|
||||
// Animate a simple progress bar
|
||||
static float progress = 0.0f, progress_dir = 1.0f;
|
||||
progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
|
||||
if (progress >= +1.0f) {
|
||||
progress = +1.0f;
|
||||
progress_dir *= -1.0f;
|
||||
}
|
||||
if (progress <= 0.0f) {
|
||||
progress = 0.0f;
|
||||
progress_dir *= -1.0f;
|
||||
}
|
||||
int pv = static_cast<int>(progress * 100);
|
||||
|
||||
ImGui::Text("PV : %i", pv);
|
||||
// ImGui::Dummy();
|
||||
ImGui::ProgressBar(progress, progressSize, "");
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
ImGui::EndGroup();
|
||||
|
||||
ImGui::SetCursorPosX(currentWeaponPos.x);
|
||||
ImGui::SetCursorPosY(currentWeaponPos.y);
|
||||
ImGui::BeginGroup();
|
||||
{
|
||||
ImGui::Text("FingerGun");
|
||||
ImGui::SameLine(0.0f, spacing.x * 50);
|
||||
ImGui::Text("3 | 9");
|
||||
|
||||
ImGui::SetCursorPosX(currentWeaponPosImage.x);
|
||||
ImGui::SetCursorPosY(currentWeaponPosImage.y);
|
||||
ImGui::Image(reinterpret_cast<ImTextureID>(m_GunTexture), fingergunSize);
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void Hud::Render() {
|
||||
if (!m_Client->IsConnected())
|
||||
return;
|
||||
|
||||
Draw("Hud Blitz", nullptr);
|
||||
}
|
||||
} // namespace gui
|
||||
} // namespace blitz
|
||||
@@ -17,6 +17,9 @@ void JoinGameMenu::Render() {
|
||||
SetNextWindowFullScreen();
|
||||
|
||||
static int InputPort = 25565;
|
||||
const static ImVec2 buttonSize = {300, 60};
|
||||
auto displaySize = ImGui::GetIO().DisplaySize;
|
||||
const static int paddingHeight = 40;
|
||||
|
||||
ImGui::Begin("JoinWindow", nullptr, GetWindowFullScreenFlags());
|
||||
{
|
||||
@@ -36,7 +39,7 @@ void JoinGameMenu::Render() {
|
||||
ImGui::Text("Port saisi : %d", InputPort);
|
||||
|
||||
if (ImGui::Button("Rejoindre")) {
|
||||
utils::LOGD(utils::Format("Adresse saisie : %s, Port saisi : %i", InputAddress, InputPort));
|
||||
utils::LOGD(utils::Format("[JoinGameMenu] Adresse saisie : %s, Port saisi : %i", InputAddress, InputPort));
|
||||
|
||||
if (m_Client->JoinGame(m_Client->GetConfig()->GetPseudo().data(), InputAddress, InputPort)) {
|
||||
InputManager::GrabMouse(true);
|
||||
@@ -44,7 +47,9 @@ void JoinGameMenu::Render() {
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::Button("Retour") || ImGui::IsKeyPressed(ImGuiKey_Escape)) {
|
||||
ImGui::SetCursorPosX(displaySize.x - buttonSize.x - paddingHeight);
|
||||
ImGui::SetCursorPosY(displaySize.y - buttonSize.y - paddingHeight);
|
||||
if (ImGui::Button("Retour", buttonSize) || ImGui::IsKeyPressed(ImGuiKey_Escape)) {
|
||||
Disable();
|
||||
m_Parent->Enable();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "client/gui/OptionsMenu.h"
|
||||
|
||||
#include "blitz/misc/Format.h"
|
||||
#include "blitz/misc/Log.h"
|
||||
#include "client/Client.h"
|
||||
#include "client/display/InputManager.h"
|
||||
#include "client/gui/FPSMenu.h"
|
||||
@@ -9,7 +11,86 @@
|
||||
namespace blitz {
|
||||
namespace gui {
|
||||
|
||||
OptionsMenu::OptionsMenu(GuiWidget* parent, Client* client) : GuiWidget(parent, client) {
|
||||
static std::string ActionNames[kaMax] = {
|
||||
"Avancer",
|
||||
"Reculer",
|
||||
"Droite",
|
||||
"Gauche",
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static std::string GetActionName(KeyAction action) {
|
||||
return ActionNames[action];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static std::string GetImGuiKeyName(int key) {
|
||||
if (key == ImGuiKey_None) {
|
||||
return "?";
|
||||
}
|
||||
return ImGui::GetKeyName(static_cast<ImGuiKey>(key));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void OptionsMenu::HotkeyBindingButton() {
|
||||
for (std::size_t i = 0; i < m_Client->GetConfig()->GetKeys().size(); i++) {
|
||||
if (ImGui::Button(utils::Format("%s##%i", GetKeyActionCodeName(KeyAction(i)).c_str(), i).c_str())) {
|
||||
m_IsKeyPopupOpen = true;
|
||||
m_CurrentAction = KeyAction(i);
|
||||
ImGui::OpenPopup("Changer de touche");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%s", GetActionName(KeyAction(i)).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void OptionsMenu::HotkeyBindingPopUp() {
|
||||
// Always center this window when appearing
|
||||
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
|
||||
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||
|
||||
if (ImGui::BeginPopupModal("Changer de touche", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::Text("Entrez la touche pour : ");
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "%s", GetActionName(m_CurrentAction).c_str());
|
||||
ImGui::Text("Si vous voulez annulez cette action, appuyez sur Echap !");
|
||||
ImGui::Dummy({0, 40});
|
||||
ImGui::Text("La touche pour ");
|
||||
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "%s", GetActionName(m_CurrentAction).c_str());
|
||||
ImGui::SameLine();
|
||||
ImGui::Text(" est : ");
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "%s", GetKeyActionCodeName(m_CurrentAction).c_str());
|
||||
|
||||
if (m_KeyPopupShouldClose && m_Timer.Update(ImGui::GetIO().DeltaTime * 1000)) {
|
||||
m_KeyPopupShouldClose = false;
|
||||
m_IsKeyPopupOpen = false;
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
OptionsMenu::OptionsMenu(GuiWidget* parent, Client* client) :
|
||||
GuiWidget(parent, client), m_IsKeyPopupOpen(false), m_KeyPopupShouldClose(false) {
|
||||
AddWidget(std::make_unique<FPSMenu>(this, client));
|
||||
InputManager::BindKeyDownCallback(std::bind(&OptionsMenu::OnKeyEvent, this, std::placeholders::_1));
|
||||
|
||||
@@ -20,7 +101,37 @@ OptionsMenu::OptionsMenu(GuiWidget* parent, Client* client) : GuiWidget(parent,
|
||||
SDL_GL_SetSwapInterval(m_VSync);
|
||||
}
|
||||
|
||||
void OptionsMenu::OnKeyEvent(int key) {}
|
||||
|
||||
|
||||
|
||||
|
||||
void OptionsMenu::OnKeyEvent(int key) {
|
||||
if (!m_IsKeyPopupOpen)
|
||||
return;
|
||||
|
||||
if (key == ImGuiKey_Escape) {
|
||||
m_KeyPopupShouldClose = true;
|
||||
ImGui::GetIO().ClearInputKeys(); // releases the Escape key
|
||||
return;
|
||||
}
|
||||
|
||||
m_Client->GetConfig()->GetKeys()[static_cast<std::size_t>(m_CurrentAction)] = key;
|
||||
m_KeyPopupShouldClose = true;
|
||||
|
||||
utils::LOG(std::to_string(key));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
std::string OptionsMenu::GetKeyActionCodeName(KeyAction act) {
|
||||
return GetImGuiKeyName(static_cast<int>(m_Client->GetConfig()->GetKeys()[act]));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void OptionsMenu::Render() {
|
||||
GuiWidget::Render();
|
||||
@@ -34,6 +145,8 @@ void OptionsMenu::Render() {
|
||||
if (!IsEnabled())
|
||||
return;
|
||||
|
||||
const static ImVec2 buttonSize = {300, 60};
|
||||
auto displaySize = ImGui::GetIO().DisplaySize;
|
||||
const static int paddingHeight = 40;
|
||||
const static int startPos = 15;
|
||||
|
||||
@@ -47,31 +160,60 @@ void OptionsMenu::Render() {
|
||||
|
||||
ImGui::NewLine();
|
||||
|
||||
if (ImGui::Checkbox("AFFICHER LES FPS", &m_ShowFPS)) {
|
||||
m_SubWidgets[0]->SetState(m_ShowFPS);
|
||||
m_Client->GetConfig()->SetFPSDisplay(m_ShowFPS);
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("VSync", &m_VSync)) {
|
||||
SDL_GL_SetSwapInterval(m_VSync);
|
||||
m_Client->GetConfig()->SetVSync(m_VSync);
|
||||
}
|
||||
|
||||
if (ImGui::Button("Retour") || ImGui::IsKeyPressed(ImGuiKey_Escape)) {
|
||||
if (ImGui::Button("Retour") || (ImGui::IsKeyPressed(ImGuiKey_Escape, false) && !m_IsKeyPopupOpen)) {
|
||||
Disable();
|
||||
if (m_Client->IsConnected()) {
|
||||
InputManager::GrabMouse(true);
|
||||
ImGui::SetCursorPosX(displaySize.x - buttonSize.x - paddingHeight);
|
||||
ImGui::SetCursorPosY(displaySize.y - 2 * buttonSize.y - paddingHeight);
|
||||
} else {
|
||||
m_Parent->Enable();
|
||||
ImGui::SetCursorPosX(displaySize.x - buttonSize.x - paddingHeight);
|
||||
ImGui::SetCursorPosY(displaySize.y - buttonSize.y - paddingHeight);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Client->IsConnected()) {
|
||||
if (ImGui::Button("Quitter la partie")) {
|
||||
m_Client->Disconnect();
|
||||
ImGui::BeginGroup();
|
||||
if (ImGui::Button("Retour", buttonSize) || ImGui::IsKeyPressed(ImGuiKey_Escape)) {
|
||||
Disable();
|
||||
m_Parent->Enable();
|
||||
if (m_Client->IsConnected()) {
|
||||
InputManager::GrabMouse(true);
|
||||
} else {
|
||||
m_Parent->Enable();
|
||||
}
|
||||
}
|
||||
if (m_Client->IsConnected()) {
|
||||
if (ImGui::Button("Quitter la partie", buttonSize)) {
|
||||
m_Client->Disconnect();
|
||||
Disable();
|
||||
m_Parent->Enable();
|
||||
}
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
|
||||
if (ImGui::BeginTabBar("OPTIONS", tab_bar_flags)) {
|
||||
if (ImGui::BeginTabItem("CONTROLES")) {
|
||||
// Always center this window when appearing
|
||||
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
|
||||
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||
|
||||
HotkeyBindingButton();
|
||||
HotkeyBindingPopUp();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("GRAPHISMES")) {
|
||||
if (ImGui::Checkbox("AFFICHER LES FPS", &m_ShowFPS)) {
|
||||
m_SubWidgets[0]->SetState(m_ShowFPS);
|
||||
m_Client->GetConfig()->SetFPSDisplay(m_ShowFPS);
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("VSync", &m_VSync)) {
|
||||
SDL_GL_SetSwapInterval(m_VSync);
|
||||
m_Client->GetConfig()->SetVSync(m_VSync);
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("AUDIO")) {
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
32
src/client/gui/ServerGui.cpp
Normal file
32
src/client/gui/ServerGui.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "client/gui/ServerGui.h"
|
||||
|
||||
#include "client/Client.h"
|
||||
#include "server/Server.h"
|
||||
#include <imgui.h>
|
||||
|
||||
namespace blitz {
|
||||
namespace gui {
|
||||
|
||||
ServerGui::ServerGui(GuiWidget* parent, Client* client) : GuiWidget(parent, client) {}
|
||||
|
||||
void ServerGui::Render() {
|
||||
if (!m_Client->IsAdmin())
|
||||
return;
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_P)) {
|
||||
ImGui::OpenPopup("Admin panel");
|
||||
}
|
||||
|
||||
static bool popup_opened = true;
|
||||
|
||||
// this is uggly but okay for now
|
||||
if (ImGui::BeginPopupModal("Admin panel", &popup_opened)) {
|
||||
if (ImGui::Button("Add Bot")) {
|
||||
m_Client->GetServer()->AddBot();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gui
|
||||
} // namespace blitz
|
||||
79
src/client/render/BulletRenderer.cpp
Normal file
79
src/client/render/BulletRenderer.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "client/render/BulletRenderer.h"
|
||||
|
||||
#include "blitz/maths/Maths.h"
|
||||
#include "blitz/misc/Log.h"
|
||||
#include "blitz/misc/Test.h"
|
||||
#include "client/render/Camera.h"
|
||||
#include "client/render/OpenGL.h"
|
||||
#include "client/render/loader/GLLoader.h"
|
||||
#include "client/render/shader/BulletShader.h"
|
||||
#include <imgui.h>
|
||||
|
||||
namespace blitz {
|
||||
namespace render {
|
||||
|
||||
static const float BULLET_DECAY_TIME = 5.0f;
|
||||
|
||||
BulletRenderer::BulletRenderer(const Camera& camera) : m_Camera(camera) {
|
||||
m_Shader = std::make_unique<shader::BulletShader>();
|
||||
blitz_debug_assert(m_Shader->LoadShader());
|
||||
|
||||
m_BulletModel = ModelLoader::LoadModel("cube.glb");
|
||||
}
|
||||
|
||||
BulletRenderer::~BulletRenderer() {}
|
||||
|
||||
void BulletRenderer::AddBullet(const Vec3f& origin, float yaw, float pitch) {
|
||||
static const float TRAIL_LENGHT = 50;
|
||||
|
||||
Vec3f direction = {
|
||||
std::cos(yaw) * std::cos(pitch),
|
||||
std::sin(pitch),
|
||||
std::sin(yaw) * std::cos(pitch),
|
||||
};
|
||||
|
||||
Vec3f middle = origin + direction * (TRAIL_LENGHT / 2.0f);
|
||||
|
||||
Mat4f rotate = maths::Dot(maths::RotateX(-pitch), maths::RotateY(yaw + maths::PI / 2));
|
||||
Mat4f scale = maths::Scale({0.01, 0.01, TRAIL_LENGHT / 2.0f - 0.2f});
|
||||
Mat4f translate = maths::Translate(middle);
|
||||
|
||||
Mat4f transform = maths::Dot(scale, maths::Dot(rotate, translate));
|
||||
|
||||
Trail trail{transform, BULLET_DECAY_TIME};
|
||||
m_Trails.push_back(trail);
|
||||
}
|
||||
|
||||
void BulletRenderer::Update(float delta) {
|
||||
for (Trail& trail : m_Trails) {
|
||||
trail.m_Decay -= delta;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < m_Trails.size(); i++) {
|
||||
if (m_Trails[i].m_Decay < 0) {
|
||||
m_Trails.erase(m_Trails.begin() + i);
|
||||
}
|
||||
}
|
||||
|
||||
m_Shader->Start();
|
||||
m_Shader->SetProjectionMatrix(m_Camera.GetPerspectiveMatrix());
|
||||
m_Shader->SetViewMatrix(m_Camera.GetViewMatrix());
|
||||
}
|
||||
|
||||
void BulletRenderer::Render() {
|
||||
m_Shader->Start();
|
||||
|
||||
// un peu frauduleux
|
||||
ModelLoader::VaoPtr& vao = m_BulletModel.mVaos[0];
|
||||
|
||||
vao->Bind();
|
||||
for (Trail& trail : m_Trails) {
|
||||
m_Shader->SetDecay(trail.m_Decay / BULLET_DECAY_TIME);
|
||||
m_Shader->SetTransform(trail.m_Transform);
|
||||
glDrawElements(GL_TRIANGLES, vao->GetVertexCount(), GL_UNSIGNED_INT, nullptr);
|
||||
}
|
||||
vao->Unbind();
|
||||
}
|
||||
|
||||
} // namespace render
|
||||
} // namespace blitz
|
||||
@@ -1,13 +1,13 @@
|
||||
#include "client/render/Camera.h"
|
||||
|
||||
#include "blitz/game/Player.h"
|
||||
#include "blitz/misc/Maths.h"
|
||||
#include "blitz/maths/Maths.h"
|
||||
#include "imgui.h"
|
||||
|
||||
namespace blitz {
|
||||
namespace render {
|
||||
|
||||
static const float eyeHeight = 1.25f;
|
||||
static const float EyeHeight = 1.25f;
|
||||
|
||||
void Camera::Update(float delta) {
|
||||
int windowWidth = ImGui::GetIO().DisplaySize.x;
|
||||
@@ -21,6 +21,10 @@ void Camera::Update(float delta) {
|
||||
}
|
||||
}
|
||||
|
||||
float Camera::GetPlayerEyeHeight() {
|
||||
return EyeHeight;
|
||||
}
|
||||
|
||||
Mat4f Camera::GetViewMatrix() const {
|
||||
Vec3f front = {
|
||||
std::cos(m_Player->GetYaw()) * std::cos(m_Player->GetPitch()),
|
||||
@@ -28,7 +32,7 @@ Mat4f Camera::GetViewMatrix() const {
|
||||
std::sin(m_Player->GetYaw()) * std::cos(m_Player->GetPitch()),
|
||||
};
|
||||
|
||||
return maths::Look(m_Player->GetPosition() + Vec3f{0, eyeHeight, 0}, front, {0, 1, 0});
|
||||
return maths::Look(m_Player->GetPosition() + Vec3f{0, EyeHeight, 0}, front, {0, 1, 0});
|
||||
}
|
||||
|
||||
} // namespace render
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
#include "client/render/MainRenderer.h"
|
||||
|
||||
#include "blitz/maths/Maths.h"
|
||||
#include "blitz/misc/Easing.h"
|
||||
#include "blitz/misc/Format.h"
|
||||
#include "blitz/misc/Log.h"
|
||||
#include "blitz/misc/Maths.h"
|
||||
#include "blitz/misc/Test.h"
|
||||
#include "blitz/misc/Time.h"
|
||||
#include "client/Client.h"
|
||||
#include "client/game/ClientGame.h"
|
||||
#include "client/render/OpenGL.h"
|
||||
#include "client/render/loader/GLLoader.h"
|
||||
#include "client/render/loader/ModelLoader.h"
|
||||
#include "client/render/loader/TextureLoader.h"
|
||||
#include "client/render/shader/BulletShader.h"
|
||||
#include "client/render/shader/EntityShader.h"
|
||||
#include "client/render/shader/GunShader.h"
|
||||
#include "client/render/shader/WorldShader.h"
|
||||
#include "imgui.h"
|
||||
#include <glbinding/gl/gl.h>
|
||||
|
||||
using namespace gl;
|
||||
|
||||
namespace blitz {
|
||||
namespace render {
|
||||
@@ -25,12 +24,14 @@ namespace render {
|
||||
static const Vec4f SkyColor = {0.6, 0.8, 1, 1};
|
||||
static const Vec4f MenuColor = {0, 0, 0, 0};
|
||||
|
||||
MainRenderer::MainRenderer(Client* client) : m_Client(client), m_ShootTime(0) {
|
||||
MainRenderer::MainRenderer(Client* client) :
|
||||
m_Client(client), m_PlayerController(m_Client), m_ShootTime(0), m_BulletRenderer(m_Camera) {
|
||||
|
||||
LoadModels();
|
||||
|
||||
client->BindListener(this);
|
||||
m_PlayerController.BindListener(this);
|
||||
m_PlayerController.BindListener(client);
|
||||
|
||||
m_EntityShader = std::make_unique<shader::EntityShader>();
|
||||
blitz_debug_assert(m_EntityShader->LoadShader());
|
||||
@@ -48,6 +49,9 @@ MainRenderer::MainRenderer(Client* client) : m_Client(client), m_ShootTime(0) {
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_FRONT);
|
||||
glFrontFace(GL_CW);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
MainRenderer::~MainRenderer() {}
|
||||
@@ -88,6 +92,8 @@ void MainRenderer::Render() {
|
||||
RenderWorld();
|
||||
RenderPlayers();
|
||||
RenderGun();
|
||||
|
||||
m_BulletRenderer.Render();
|
||||
}
|
||||
|
||||
void MainRenderer::RenderPlayers() {
|
||||
@@ -100,10 +106,14 @@ void MainRenderer::RenderPlayers() {
|
||||
}
|
||||
}
|
||||
|
||||
void MainRenderer::OnPlayerShoot() {
|
||||
void MainRenderer::OnLocalPlayerShoot(const Vec3f& position, float yaw, float pitch) {
|
||||
m_ShootTime = 1.0f;
|
||||
}
|
||||
|
||||
void MainRenderer::OnPlayerShoot(game::PlayerID player, const Vec3f& position, float yaw, float pitch) {
|
||||
m_BulletRenderer.AddBullet(position + Vec3f{0.0f, Camera::GetPlayerEyeHeight(), 0.0f}, yaw, pitch);
|
||||
}
|
||||
|
||||
void MainRenderer::RenderGun() {
|
||||
if (!m_Camera.GetAttachedPlayer())
|
||||
return;
|
||||
@@ -144,17 +154,21 @@ void MainRenderer::Update() {
|
||||
|
||||
m_PlayerController.Update(delta);
|
||||
m_Camera.Update(delta);
|
||||
m_BulletRenderer.Update(delta);
|
||||
|
||||
Mat4f projectionMatrix = m_Camera.GetPerspectiveMatrix();
|
||||
Mat4f viewMatrix = m_Camera.GetViewMatrix();
|
||||
|
||||
m_EntityShader->Start();
|
||||
m_EntityShader->SetProjectionMatrix(m_Camera.GetPerspectiveMatrix());
|
||||
m_EntityShader->SetViewMatrix(m_Camera.GetViewMatrix());
|
||||
m_EntityShader->SetProjectionMatrix(projectionMatrix);
|
||||
m_EntityShader->SetViewMatrix(viewMatrix);
|
||||
|
||||
m_WorldShader->Start();
|
||||
m_WorldShader->SetProjectionMatrix(m_Camera.GetPerspectiveMatrix());
|
||||
m_WorldShader->SetViewMatrix(m_Camera.GetViewMatrix());
|
||||
m_WorldShader->SetProjectionMatrix(projectionMatrix);
|
||||
m_WorldShader->SetViewMatrix(viewMatrix);
|
||||
|
||||
m_GunShader->Start();
|
||||
m_GunShader->SetProjectionMatrix(m_Camera.GetPerspectiveMatrix());
|
||||
m_GunShader->SetProjectionMatrix(projectionMatrix);
|
||||
|
||||
m_ShootTime = std::max(0.0f, m_ShootTime - delta);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#include "client/render/loader/GLLoader.h"
|
||||
|
||||
#include "blitz/misc/Log.h"
|
||||
#include <glbinding/gl/gl.h>
|
||||
|
||||
using namespace gl;
|
||||
#include "client/render/OpenGL.h"
|
||||
|
||||
namespace blitz {
|
||||
namespace GL {
|
||||
|
||||
@@ -82,15 +82,19 @@ static VaoPtr ProcessMesh(aiMesh* mesh, const aiScene* scene, const aiMatrix4x4&
|
||||
return Vao;
|
||||
}
|
||||
|
||||
static void ProcessNode(aiNode* node, const aiScene* scene, std::vector<VaoPtr>& meshes, const aiMatrix4x4& transform) {
|
||||
static void ProcessNode(
|
||||
aiNode* node, const aiScene* scene, std::vector<VaoPtr>& meshes, std::vector<maths::AABB>& aabbs, const aiMatrix4x4& transform) {
|
||||
// recursive
|
||||
for (unsigned int i = 0; i < node->mNumChildren; i++) {
|
||||
ProcessNode(node->mChildren[i], scene, meshes, transform * node->mTransformation);
|
||||
ProcessNode(node->mChildren[i], scene, meshes, aabbs, transform * node->mTransformation);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < node->mNumMeshes; i++) {
|
||||
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
|
||||
meshes.push_back(ProcessMesh(mesh, scene, transform * node->mTransformation));
|
||||
|
||||
aiAABB& aabb = mesh->mAABB;
|
||||
aabbs.push_back({Vec3f{aabb.mMin.x, aabb.mMin.y, aabb.mMin.z}, {aabb.mMax.x, aabb.mMax.y, aabb.mMax.z}});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,14 +108,16 @@ Model LoadModel(const std::string& fileName) {
|
||||
aiProcess_OptimizeMeshes);
|
||||
|
||||
if (nullptr == scene) {
|
||||
utils::LOGE("Failed to load model !");
|
||||
utils::LOGE("[ModelLoader] Failed to load model !");
|
||||
return {};
|
||||
}
|
||||
|
||||
utils::LOGD(utils::Format("\tModel nodes : %i", scene->mRootNode->mNumMeshes));
|
||||
utils::LOGD(utils::Format("[ModelLoader]\tModel nodes : %i", scene->mRootNode->mNumMeshes));
|
||||
|
||||
Model model;
|
||||
ProcessNode(scene->mRootNode, scene, model.mVaos, {});
|
||||
ProcessNode(scene->mRootNode, scene, model.mVaos, model.mAABBs, {});
|
||||
|
||||
utils::LOGD(utils::Format("[ModelLoader]\tAABB count : %i", model.mAABBs.size()));
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
@@ -3,12 +3,10 @@
|
||||
#include "client/AssetsManager.h"
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "blitz/misc/Log.h"
|
||||
#include "client/render/OpenGL.h"
|
||||
#include "stb_image.h"
|
||||
#include <glbinding/gl/gl.h>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace gl;
|
||||
|
||||
namespace blitz {
|
||||
namespace TextureLoader {
|
||||
|
||||
@@ -21,7 +19,7 @@ unsigned int LoadGLTexture(const std::string& fileName) {
|
||||
const unsigned char* image = stbi_load_from_memory(buffer.data(), buffer.GetSize(), &width, &height, &comp, STBI_default);
|
||||
|
||||
if (image == nullptr) {
|
||||
utils::LOGE("Erreur lors du chargement de la texture !");
|
||||
utils::LOGE("[TextureLoader] Erreur lors du chargement de la texture !");
|
||||
throw(std::runtime_error("Failed to load texture"));
|
||||
}
|
||||
|
||||
|
||||
67
src/client/render/shader/BulletShader.cpp
Normal file
67
src/client/render/shader/BulletShader.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#include "client/render/shader/BulletShader.h"
|
||||
|
||||
namespace blitz {
|
||||
namespace shader {
|
||||
|
||||
static const std::string vertexSource = ShaderProgram::GetShaderHeader() + R"(
|
||||
|
||||
layout(location = 0) in vec3 position;
|
||||
layout(location = 1) in float decay;
|
||||
|
||||
uniform mat4 viewMatrix;
|
||||
uniform mat4 projectionMatrix;
|
||||
uniform mat4 modelMatrix;
|
||||
|
||||
out float pass_decay;
|
||||
|
||||
void main(void){
|
||||
vec4 worldPos = modelMatrix * vec4(position, 1.0);
|
||||
pass_decay = decay;
|
||||
gl_Position = projectionMatrix * viewMatrix * worldPos;
|
||||
}
|
||||
)";
|
||||
|
||||
static const std::string fragmentSource = ShaderProgram::GetShaderHeader() + R"(
|
||||
|
||||
in float pass_decay;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
uniform float alpha;
|
||||
|
||||
void main(void){
|
||||
out_color = vec4(1.0, 0.0, 0.0, alpha);
|
||||
}
|
||||
)";
|
||||
|
||||
BulletShader::BulletShader() : ShaderProgram() {}
|
||||
|
||||
bool BulletShader::LoadShader() {
|
||||
return ShaderProgram::LoadProgram(vertexSource, fragmentSource);
|
||||
}
|
||||
|
||||
void BulletShader::GetAllUniformLocation() {
|
||||
m_LocationViewMatrix = static_cast<unsigned int>(GetUniformLocation("viewMatrix"));
|
||||
m_LocationProjectionMatrix = static_cast<unsigned int>(GetUniformLocation("projectionMatrix"));
|
||||
m_LocationTransform = static_cast<unsigned int>(GetUniformLocation("modelMatrix"));
|
||||
m_LocationAlpha = static_cast<unsigned int>(GetUniformLocation("alpha"));
|
||||
}
|
||||
|
||||
void BulletShader::SetProjectionMatrix(const Mat4f& proj) const {
|
||||
LoadMat4(m_LocationProjectionMatrix, proj);
|
||||
}
|
||||
|
||||
void BulletShader::SetViewMatrix(const Mat4f& view) const {
|
||||
LoadMat4(m_LocationViewMatrix, view);
|
||||
}
|
||||
|
||||
void BulletShader::SetDecay(float alpha) const {
|
||||
LoadFloat(m_LocationAlpha, alpha);
|
||||
}
|
||||
|
||||
void BulletShader::SetTransform(const Mat4f& trans) const {
|
||||
LoadMat4(m_LocationTransform, trans);
|
||||
}
|
||||
|
||||
} // namespace shader
|
||||
} // namespace blitz
|
||||
@@ -44,6 +44,7 @@ void main(void){
|
||||
float brightness = diffuse;
|
||||
|
||||
out_color = vec4(1.0, 1.0, 1.0, 1.0) * brightness;
|
||||
out_color.w = 1.0;
|
||||
}
|
||||
)";
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ out vec4 out_color;
|
||||
void main(void){
|
||||
|
||||
out_color = pos;
|
||||
out_color.w = 1.0;
|
||||
// out_color = gl_Position + vec4(0.5, 0.5, 0.5, 0);
|
||||
// out_color = texture(textureSampler, pass_textureCoords);
|
||||
|
||||
|
||||
@@ -2,14 +2,12 @@
|
||||
|
||||
#include "blitz/misc/Format.h"
|
||||
#include "blitz/misc/Log.h"
|
||||
#include "client/render/OpenGL.h"
|
||||
#include <fstream>
|
||||
#include <glbinding/gl/gl.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
using namespace gl;
|
||||
|
||||
namespace blitz {
|
||||
namespace shader {
|
||||
|
||||
@@ -30,7 +28,7 @@ void ShaderProgram::Stop() const {
|
||||
int ShaderProgram::GetUniformLocation(const std::string& uniformName) const {
|
||||
const int location = glGetUniformLocation(m_ProgramID, uniformName.c_str());
|
||||
if (location == -1) {
|
||||
utils::LOGD(utils::Format("Warning ! Uniform variable %s not found !", uniformName.c_str()));
|
||||
utils::LOGD(utils::Format("[ShaderProgram] Warning ! Uniform variable %s not found !", uniformName.c_str()));
|
||||
}
|
||||
return location;
|
||||
}
|
||||
@@ -104,7 +102,7 @@ int ShaderProgram::LoadShader(const std::string& source, GLenum type) {
|
||||
std::vector<char> shaderError(static_cast<std::size_t>(size));
|
||||
glGetShaderInfoLog(shaderID, size, &size, shaderError.data());
|
||||
|
||||
utils::LOGE("Could not compile shader !");
|
||||
utils::LOGE("[ShaderProgram] Could not compile shader !");
|
||||
|
||||
utils::LOGE(shaderError.data());
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ void main(void){
|
||||
|
||||
float lightDistance = length(toLightVector);
|
||||
|
||||
const vec3 attenuation = vec3(0.3, 0.3, 0.03);
|
||||
const vec3 attenuation = vec3(0.3, 0.03, 0);
|
||||
float attenuationFactor = attenuation.x + attenuation.y * lightDistance + attenuation.z * lightDistance * lightDistance;
|
||||
|
||||
vec3 unitNormal = normalize(surfaceNormal);
|
||||
@@ -71,6 +71,7 @@ void main(void){
|
||||
float brightness = (diffuse + specular) / attenuationFactor;
|
||||
|
||||
out_color = brightness * texture(textureSampler, pass_textureCoords);
|
||||
out_color.w = 1.0;
|
||||
|
||||
}
|
||||
)";
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "blitz/game/Game.h"
|
||||
#include "blitz/misc/Format.h"
|
||||
#include "blitz/misc/Log.h"
|
||||
#include "blitz/misc/Random.h"
|
||||
#include "blitz/misc/Time.h"
|
||||
#include "blitz/protocol/PacketFactory.h"
|
||||
#include "blitz/protocol/packets/ChatPacket.h"
|
||||
@@ -13,7 +14,7 @@
|
||||
namespace blitz {
|
||||
namespace server {
|
||||
|
||||
Server::Server() : m_ServerRunning(false), m_TickCounter(SERVER_TPS), m_Game(this) {}
|
||||
Server::Server() : m_TickCounter(SERVER_TPS), m_Game(this), m_ServerRunning(false) {}
|
||||
|
||||
Server::~Server() {
|
||||
StopThread();
|
||||
@@ -52,14 +53,14 @@ void Server::StopThread() {
|
||||
|
||||
bool Server::Start(std::uint16_t port, bool blocking) {
|
||||
if (!m_Listener.Listen(port, 10)) {
|
||||
utils::LOGE(utils::Format("Failed to bind port %u !", port));
|
||||
utils::LOGE(utils::Format("[Server] Failed to bind port %u !", port));
|
||||
return false;
|
||||
}
|
||||
if (!m_Listener.SetBlocking(false)) {
|
||||
utils::LOGE("Failed to block server socket !");
|
||||
utils::LOGE("[Server] Failed to block server socket !");
|
||||
return false;
|
||||
}
|
||||
utils::LOG(utils::Format("Server started at port %u !", m_Listener.GetListeningPort()));
|
||||
utils::LOG(utils::Format("[Server] Server started at port %u !", m_Listener.GetListeningPort()));
|
||||
m_TickCounter.Reset();
|
||||
m_ServerRunning = true;
|
||||
if (blocking) {
|
||||
@@ -76,7 +77,7 @@ void Server::Clean() {
|
||||
|
||||
m_Connections.clear();
|
||||
|
||||
utils::LOG("Server successfully stopped !");
|
||||
utils::LOG("[Server] Server successfully stopped !");
|
||||
}
|
||||
|
||||
void Server::Stop() {
|
||||
@@ -100,9 +101,9 @@ void Server::Tick(std::uint64_t delta) {
|
||||
}
|
||||
|
||||
void Server::Accept() {
|
||||
static std::uint8_t newPlayerID = 0;
|
||||
network::TCPSocket newSocket;
|
||||
if (m_Listener.Accept(newSocket)) {
|
||||
game::PlayerID newPlayerID = GetNewPlayerID();
|
||||
auto con = std::make_unique<ServerConnexion>(this, newSocket, newPlayerID);
|
||||
m_Connections.insert(std::move(ConnexionMap::value_type{newPlayerID, std::move(con)}));
|
||||
m_Connections[newPlayerID]->Start();
|
||||
@@ -110,6 +111,13 @@ void Server::Accept() {
|
||||
}
|
||||
}
|
||||
|
||||
game::PlayerID Server::GetNewPlayerID() {
|
||||
static game::PlayerID lastPlayerID = 0;
|
||||
game::PlayerID newPlayerID = lastPlayerID;
|
||||
lastPlayerID++;
|
||||
return newPlayerID;
|
||||
}
|
||||
|
||||
void Server::UpdateSockets() {
|
||||
static std::vector<std::int16_t> closeConnexions;
|
||||
for (auto& connection : m_Connections) {
|
||||
@@ -154,5 +162,15 @@ std::uint16_t Server::GetListeningPort() {
|
||||
return m_Listener.GetListeningPort();
|
||||
}
|
||||
|
||||
void Server::AddBot() {
|
||||
game::PlayerID botID = GetNewPlayerID();
|
||||
|
||||
m_Game.AddPlayer(botID, "Bot " + std::to_string(static_cast<unsigned int>(botID)));
|
||||
|
||||
// set the bot at a random location to be able to see several of them
|
||||
game::Player* botPlayer = m_Game.GetPlayerById(botID);
|
||||
botPlayer->SetPosition({utils::GetRandomReal(-10.0f, 10.0f), 0.0f, utils::GetRandomReal(-10.0f, 10.0f)});
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
} // namespace blitz
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "blitz/protocol/packets/PlayerListPacket.h"
|
||||
#include "blitz/protocol/packets/PlayerLoginPacket.h"
|
||||
#include "blitz/protocol/packets/PlayerPositionAndRotationPacket.h"
|
||||
#include "blitz/protocol/packets/PlayerShootPacket.h"
|
||||
#include "client/gui/ColorFulText.h"
|
||||
#include "server/Server.h"
|
||||
#include <unordered_map>
|
||||
@@ -46,6 +47,7 @@ void ServerConnexion::RegisterHandlers() {
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::KeepAlive, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerLogin, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::Chat, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerShoot, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerPositionAndRotation, this);
|
||||
}
|
||||
|
||||
@@ -82,32 +84,22 @@ void ServerConnexion::InitPlayerChatColor() {
|
||||
const std::string& playerName = m_Player->GetName();
|
||||
|
||||
std::size_t hash = std::hash<std::string>()(playerName);
|
||||
unsigned int red = hash >> 16 & 0xFF;
|
||||
unsigned int green = hash >> 8 & 0xFF;
|
||||
unsigned int blue = hash & 0xFF;
|
||||
std::uint8_t red = hash >> 16 & 0xFF;
|
||||
std::uint8_t green = hash >> 8 & 0xFF;
|
||||
std::uint8_t blue = hash & 0xFF;
|
||||
|
||||
m_ChatColor = protocol::ChatPacket::GetTextColor({red, green, blue});
|
||||
}
|
||||
|
||||
void ServerConnexion::HandlePacket(const protocol::PlayerLoginPacket* packet) {
|
||||
game::Player newPlayer{m_ID};
|
||||
newPlayer.SetName(packet->GetPlayerName());
|
||||
|
||||
SendPlayers();
|
||||
|
||||
m_Server->GetGame().GetPlayers().insert({m_ID, newPlayer});
|
||||
m_Server->GetGame().AddPlayer(m_ID, packet->GetPlayerName());
|
||||
|
||||
m_Player = m_Server->GetGame().GetPlayerById(m_ID);
|
||||
|
||||
protocol::PlayerJoinPacket joinPacket(m_ID, m_Player->GetName());
|
||||
m_Server->BroadcastPacket(&joinPacket);
|
||||
|
||||
InitPlayerChatColor();
|
||||
|
||||
std::string joinMessage = utils::Format("%s a rejoint la partie !", packet->GetPlayerName().c_str());
|
||||
|
||||
utils::LOG(joinMessage);
|
||||
m_Server->BroadcastChatMessage(protocol::ChatPacket::GetTextColor(protocol::YELLOW) + joinMessage);
|
||||
}
|
||||
|
||||
void ServerConnexion::HandlePacket(const protocol::KeepAlivePacket* packet) {
|
||||
@@ -139,6 +131,13 @@ void ServerConnexion::HandlePacket(const protocol::PlayerPositionAndRotationPack
|
||||
m_Player->SetPitch(packet->GetPitch());
|
||||
}
|
||||
|
||||
void ServerConnexion::HandlePacket(const protocol::PlayerShootPacket* packet) {
|
||||
protocol::PlayerShootPacket broadcastShoot(packet->GetPosition(), packet->GetYaw(), packet->GetPitch(), m_Player->GetID());
|
||||
m_Server->BroadcastPacket(&broadcastShoot);
|
||||
|
||||
m_Server->GetGame().CheckShoot(m_Player->GetID(), packet->GetPosition(), packet->GetYaw(), packet->GetPitch());
|
||||
}
|
||||
|
||||
void ServerConnexion::Start() {
|
||||
InitConnection();
|
||||
SendKeepAlive();
|
||||
@@ -169,7 +168,7 @@ ServerConnexion::~ServerConnexion() {
|
||||
if (m_Player) {
|
||||
std::string leaveMessage = utils::Format("%s a quitte la partie !", m_Player->GetName().c_str());
|
||||
|
||||
utils::LOG(leaveMessage);
|
||||
utils::LOG("[Server] " + leaveMessage);
|
||||
m_Server->BroadcastChatMessage(protocol::ChatPacket::GetTextColor(protocol::YELLOW) + leaveMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
#include "server/game/ServerGame.h"
|
||||
|
||||
#include "blitz/maths/Physics.h"
|
||||
#include "blitz/misc/Format.h"
|
||||
#include "blitz/misc/Log.h"
|
||||
#include "blitz/protocol/packets/ChatPacket.h"
|
||||
#include "blitz/protocol/packets/PlayerJoinPacket.h"
|
||||
#include "blitz/protocol/packets/PlayerPositionAndRotationPacket.h"
|
||||
#include "server/Server.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace blitz {
|
||||
namespace server {
|
||||
@@ -23,5 +29,39 @@ void ServerGame::SendPlayerPositions() {
|
||||
}
|
||||
}
|
||||
|
||||
void ServerGame::CheckShoot(game::PlayerID shooter, Vec3f position, float yaw, float pitch) {
|
||||
maths::Ray shootRay;
|
||||
shootRay.origin = position + Vec3f{0.0, 1.75, 0.0};
|
||||
shootRay.direction = {
|
||||
std::cos(yaw) * std::cos(pitch),
|
||||
std::sin(pitch),
|
||||
std::sin(yaw) * std::cos(pitch),
|
||||
};
|
||||
|
||||
static const maths::AABB playerStaticAABB = {Vec3f{-0.5f, 0.0f, -0.5f}, Vec3f{0.5f, 1.8f, 0.5f}};
|
||||
|
||||
for (const auto& [playerId, player] : GetPlayers()) {
|
||||
if (playerId != shooter && maths::Distance(shootRay, playerStaticAABB + player.GetPosition()) > 0.0f) {
|
||||
utils::LOG("[Server] " + player.GetName() + " a été touché !");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServerGame::AddPlayer(game::PlayerID player, const std::string& name) {
|
||||
Game::AddPlayer(player, name);
|
||||
|
||||
protocol::PlayerJoinPacket joinPacket(player, name);
|
||||
m_Server->BroadcastPacket(&joinPacket);
|
||||
|
||||
std::string joinMessage = utils::Format("%s a rejoint la partie !", name.c_str());
|
||||
|
||||
utils::LOG("[Server] " + joinMessage);
|
||||
m_Server->BroadcastChatMessage(protocol::ChatPacket::GetTextColor(protocol::YELLOW) + joinMessage);
|
||||
}
|
||||
|
||||
void ServerGame::RemovePlayer(game::PlayerID player) {
|
||||
Game::RemovePlayer(player);
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
} // namespace blitz
|
||||
|
||||
45
test/test_compression.cpp
Normal file
45
test/test_compression.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#include "blitz/misc/Test.h"
|
||||
|
||||
#include "blitz/misc/Compression.h"
|
||||
|
||||
void ReciprocalTest() {
|
||||
blitz::DataBuffer original;
|
||||
original << "Some data to compress and decompress";
|
||||
|
||||
// Use your compression functions here
|
||||
blitz::DataBuffer compressed = blitz::utils::Compress(original);
|
||||
blitz::DataBuffer decompressed = blitz::utils::Decompress(compressed);
|
||||
|
||||
// Check that after compressing and then decompressing, we get back the original data
|
||||
blitz_test_assert(original == decompressed);
|
||||
}
|
||||
|
||||
void CompressionTest() {
|
||||
blitz::DataBuffer original;
|
||||
original << "Some data to compresssssssssssssssssssssssssssssssssssssssssssssssssssssssssss";
|
||||
|
||||
// Use your compression functions here
|
||||
blitz::DataBuffer compressed = blitz::utils::Compress(original);
|
||||
|
||||
// Check that the compressed data is smaller than the original
|
||||
blitz_test_assert(compressed.GetSize() < original.GetSize());
|
||||
}
|
||||
|
||||
void DecompressionTest() {
|
||||
blitz::DataBuffer original;
|
||||
original << "Some data to compress and decompress";
|
||||
|
||||
// Use your compression functions here
|
||||
blitz::DataBuffer compressed = blitz::utils::Compress(original);
|
||||
blitz::DataBuffer decompressed = blitz::utils::Decompress(compressed);
|
||||
|
||||
// Check that the decompressed data is the same size as the original
|
||||
blitz_test_assert(original.GetSize() == decompressed.GetSize());
|
||||
}
|
||||
|
||||
int main() {
|
||||
ReciprocalTest();
|
||||
CompressionTest();
|
||||
DecompressionTest();
|
||||
return BLITZ_TEST_SUCCESSFUL;
|
||||
}
|
||||
58
test/test_intersects.cpp
Executable file
58
test/test_intersects.cpp
Executable file
@@ -0,0 +1,58 @@
|
||||
#include "blitz/misc/Test.h"
|
||||
|
||||
#include "blitz/maths/Physics.h"
|
||||
#include "blitz/misc/Log.h"
|
||||
#include "blitz/misc/Format.h"
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <limits>
|
||||
|
||||
using namespace blitz;
|
||||
using namespace maths;
|
||||
|
||||
#define let auto // sexy boiiii
|
||||
|
||||
static void test_left() {
|
||||
let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
|
||||
let ray = Ray { {-2.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f} };
|
||||
|
||||
blitz_test_assert(Intersects(ray, box));
|
||||
}
|
||||
|
||||
static void test_right() {
|
||||
let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
|
||||
let ray = Ray { {2.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f} };
|
||||
|
||||
blitz_test_assert(Intersects(ray, box));
|
||||
}
|
||||
|
||||
static void test_forward() {
|
||||
let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
|
||||
let ray = Ray { {0.0f, 2.0f, 0.0f}, {0.0f, -1.0f, 0.0f} };
|
||||
|
||||
blitz_test_assert(Intersects(ray, box));
|
||||
}
|
||||
|
||||
static void test_backward() {
|
||||
let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
|
||||
let ray = Ray { {0.0f, -2.0f, 0.0f}, {0.0f, 1.0f, 0.0f} };
|
||||
|
||||
blitz_test_assert(Intersects(ray, box));
|
||||
}
|
||||
|
||||
static void test_shifted() {
|
||||
|
||||
let box = AABB { {-1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f} };
|
||||
let ray = Ray { {-3.0f, 0.0f, 100.0f}, {1.0f, 0.0f, 0.0f} };
|
||||
|
||||
blitz_test_assert(!Intersects(ray, box));
|
||||
}
|
||||
|
||||
int main(int argc, const char* args[]) {
|
||||
test_left();
|
||||
test_right();
|
||||
test_forward();
|
||||
test_backward();
|
||||
test_shifted();
|
||||
return BLITZ_TEST_SUCCESSFUL;
|
||||
}
|
||||
46
test/test_network.cpp
Normal file
46
test/test_network.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#include "blitz/misc/Test.h"
|
||||
|
||||
#include "blitz/network/TCPListener.h"
|
||||
#include "blitz/network/TCPSocket.h"
|
||||
#include "blitz/misc/Random.h"
|
||||
|
||||
// Test the connection and disconnection of a TCPSocket
|
||||
void ConnectDisconnect() {
|
||||
blitz::network::TCPListener localserver;
|
||||
localserver.Listen(0, 1);
|
||||
blitz::network::TCPSocket socket;
|
||||
// Try to connect to a local server on port 8080
|
||||
blitz_test_assert(socket.Connect("localhost", localserver.GetListeningPort()));
|
||||
// Check if the socket status is Connected after connection
|
||||
blitz_test_assert(socket.GetStatus() == blitz::network::TCPSocket::Status::Connected);
|
||||
socket.Disconnect();
|
||||
// Check if the socket status is Disconnected after disconnection
|
||||
blitz_test_assert(socket.GetStatus() == blitz::network::TCPSocket::Status::Disconnected);
|
||||
}
|
||||
|
||||
// Test the listening and accepting of a TCPListener
|
||||
void Listener() {
|
||||
// Choose a random port
|
||||
std::uint16_t randomPort = blitz::utils::GetRandomInt(30000, 35000);
|
||||
|
||||
blitz::network::TCPListener listener;
|
||||
// Start listening on random port with a maximum of 10 connections
|
||||
blitz_test_assert(listener.Listen(randomPort, 10));
|
||||
// Check if the listener is listening on the correct port
|
||||
blitz_test_assert(listener.GetListeningPort() == randomPort);
|
||||
// Check if the listener has the correct maximum number of connections
|
||||
blitz_test_assert(listener.GetMaximumConnections() == 10);
|
||||
|
||||
blitz::network::TCPSocket socket;
|
||||
// Try to connect to the listener
|
||||
blitz_test_assert(socket.Connect("localhost", randomPort));
|
||||
blitz::network::TCPSocket newSocket;
|
||||
// Try to accept the connection from the socket
|
||||
blitz_test_assert(listener.Accept(newSocket));
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ConnectDisconnect();
|
||||
Listener();
|
||||
return BLITZ_TEST_SUCCESSFUL;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "blitz/misc/Test.h"
|
||||
|
||||
#include "blitz/common/Vector.h"
|
||||
#include "blitz/maths/Vector.h"
|
||||
|
||||
using namespace blitz;
|
||||
|
||||
|
||||
100
xmake.lua
100
xmake.lua
@@ -1,97 +1,13 @@
|
||||
-- We need that for the tests
|
||||
set_xmakever("2.8.5")
|
||||
|
||||
set_policy("package.install_locally", true)
|
||||
|
||||
add_rules("mode.debug", "mode.release", "mode.valgrind")
|
||||
|
||||
add_requires("libsdl 2.28.3", {configs = {sdlmain = false}})
|
||||
add_requires("glbinding >= 3", "zlib", "assimp", "nlohmann_json")
|
||||
|
||||
set_languages("c++17")
|
||||
add_includedirs("include")
|
||||
|
||||
-- Game files (with server)
|
||||
target("Blitz")
|
||||
if is_os("windows") then
|
||||
set_kind("static")
|
||||
add_links("ws2_32") -- link network stuff
|
||||
else
|
||||
set_kind("shared")
|
||||
end
|
||||
|
||||
add_files("src/blitz/**.cpp", "src/server/**.cpp")
|
||||
|
||||
add_packages("zlib")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- Server binary (headless)
|
||||
target("BlitzServer")
|
||||
set_kind("binary")
|
||||
set_default(false)
|
||||
|
||||
add_files("src/ServerMain.cpp")
|
||||
|
||||
-- Libraries
|
||||
add_deps("Blitz")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- Client binary (default)
|
||||
target("BlitzClient")
|
||||
if is_plat("android") then
|
||||
set_kind("shared")
|
||||
else
|
||||
set_kind("binary")
|
||||
end
|
||||
|
||||
set_default(true)
|
||||
|
||||
add_files("src/client/**.cpp", "src/ClientMain.cpp")
|
||||
|
||||
-- Libraries
|
||||
add_deps("Blitz")
|
||||
add_packages("libsdl", "glbinding", "assimp", "nlohmann_json")
|
||||
|
||||
add_includedirs("libs", "libs/imgui")
|
||||
add_files("libs/imgui/**.cpp")
|
||||
|
||||
if is_plat("macosx") then
|
||||
add_frameworks("OpenGL")
|
||||
elseif is_plat("windows") then
|
||||
add_ldflags("/LTCG") -- fix compiltation of glbinding
|
||||
end
|
||||
|
||||
-- Assets
|
||||
set_rundir("$(projectdir)/assets")
|
||||
|
||||
-- Valgrind test
|
||||
if is_mode("valgrind") then
|
||||
on_run(function (target)
|
||||
os.cd("$(projectdir)/assets")
|
||||
os.execv("valgrind", {target:targetfile()})
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- Tests
|
||||
for _, file in ipairs(os.files("test/test_*.cpp")) do
|
||||
local name = path.basename(file)
|
||||
target(name)
|
||||
set_kind("binary")
|
||||
add_files("test/" .. name .. ".cpp")
|
||||
|
||||
set_default(false)
|
||||
|
||||
add_deps("Blitz")
|
||||
|
||||
add_tests("compile_and_run")
|
||||
if is_mode("release") then
|
||||
set_warnings("all", "error")
|
||||
else
|
||||
set_warnings("all")
|
||||
end
|
||||
|
||||
includes("xmake/BlitzClient.lua")
|
||||
includes("xmake/BlitzServer.lua")
|
||||
includes("xmake/BlitzTest.lua")
|
||||
15
xmake/Blitz.lua
Normal file
15
xmake/Blitz.lua
Normal file
@@ -0,0 +1,15 @@
|
||||
add_requires("zlib")
|
||||
|
||||
-- Game files (with server)
|
||||
target("Blitz")
|
||||
if is_os("windows") then
|
||||
set_kind("static")
|
||||
add_links("ws2_32") -- link network stuff
|
||||
else
|
||||
set_kind("shared")
|
||||
end
|
||||
|
||||
add_includedirs("../include")
|
||||
add_files("../src/blitz/**.cpp", "../src/server/**.cpp")
|
||||
|
||||
add_packages("zlib")
|
||||
41
xmake/BlitzClient.lua
Normal file
41
xmake/BlitzClient.lua
Normal file
@@ -0,0 +1,41 @@
|
||||
includes("Blitz.lua")
|
||||
|
||||
add_requires("libsdl 2.28.3", {configs = {sdlmain = false}})
|
||||
add_requires("glew", "assimp", "nlohmann_json")
|
||||
|
||||
-- Client binary (default)
|
||||
target("BlitzClient")
|
||||
if is_plat("android") then
|
||||
set_kind("shared")
|
||||
else
|
||||
set_kind("binary")
|
||||
end
|
||||
|
||||
set_default(true)
|
||||
|
||||
add_includedirs("../include")
|
||||
add_files("../src/client/**.cpp", "../src/ClientMain.cpp")
|
||||
|
||||
-- Libraries
|
||||
add_deps("Blitz")
|
||||
add_packages("libsdl", "glew", "assimp", "nlohmann_json")
|
||||
|
||||
add_includedirs("../libs", "../libs/imgui")
|
||||
add_files("../libs/imgui/**.cpp")
|
||||
|
||||
if is_plat("macosx") then
|
||||
add_frameworks("OpenGL")
|
||||
elseif is_plat("windows") then
|
||||
add_ldflags("/LTCG") -- fix compiltation of glbinding
|
||||
end
|
||||
|
||||
-- Assets
|
||||
set_rundir("../assets")
|
||||
|
||||
-- Valgrind test
|
||||
if is_mode("valgrind") then
|
||||
on_run(function (target)
|
||||
os.cd("../assets")
|
||||
os.execv("valgrind", {"-s", "--leak-check=full", target:targetfile()})
|
||||
end)
|
||||
end
|
||||
12
xmake/BlitzServer.lua
Normal file
12
xmake/BlitzServer.lua
Normal file
@@ -0,0 +1,12 @@
|
||||
includes("Blitz.lua")
|
||||
|
||||
-- Server binary (headless)
|
||||
target("BlitzServer")
|
||||
set_kind("binary")
|
||||
set_default(false)
|
||||
|
||||
add_includedirs("../include")
|
||||
add_files("../src/ServerMain.cpp")
|
||||
|
||||
-- Libraries
|
||||
add_deps("Blitz")
|
||||
20
xmake/BlitzTest.lua
Normal file
20
xmake/BlitzTest.lua
Normal file
@@ -0,0 +1,20 @@
|
||||
includes("Blitz.lua")
|
||||
|
||||
-- Tests were introduced in that version
|
||||
set_xmakever("2.8.5")
|
||||
|
||||
-- Tests
|
||||
for _, file in ipairs(os.files("../test/test_*.cpp")) do
|
||||
local name = path.basename(file)
|
||||
target(name)
|
||||
set_kind("binary")
|
||||
|
||||
add_includedirs("../include")
|
||||
add_files("../test/" .. name .. ".cpp")
|
||||
|
||||
set_default(false)
|
||||
|
||||
add_deps("Blitz")
|
||||
|
||||
add_tests("compile_and_run")
|
||||
end
|
||||
Reference in New Issue
Block a user