Merge request of CREAsTIVE-master branch with conflicts resolution

master
Vectozavr 2023-05-21 16:45:39 +03:00
commit d722d60d9e
12 changed files with 191 additions and 33 deletions

2
3dzavr

@ -1 +1 @@
Subproject commit f80ebaf4522310a7560c19e6da2a3a8f36f2eb16 Subproject commit 5217578e1500cbe567ddf13a44fffd60e3ad445c

View File

@ -28,6 +28,8 @@ add_executable(${CMAKE_PROJECT_NAME}
ShooterConsts.h ShooterConsts.h
network/ShooterMsgType.h network/ShooterMsgType.h
network/ShooterMsgType.cpp network/ShooterMsgType.cpp
network/Chat.cpp
network/Chat.h
# 3d engine: # 3d engine:
3dzavr/engine/Consts.h 3dzavr/engine/Consts.h
3dzavr/engine/math/Vec4D.h 3dzavr/engine/math/Vec4D.h

View File

@ -8,9 +8,9 @@
#include "3dzavr/engine/animation/Animations.h" #include "3dzavr/engine/animation/Animations.h"
#include "ShooterConsts.h" #include "ShooterConsts.h"
#include "3dzavr/engine/io/SoundController.h" #include "3dzavr/engine/io/SoundController.h"
#include "network/Chat.h"
using namespace std; using namespace std;
// Read server/client settings and start both. // Read server/client settings and start both.
// If client doesn't connect to the localhost - server doesn't start. // If client doesn't connect to the localhost - server doesn't start.
void Shooter::initNetwork() { void Shooter::initNetwork() {
@ -65,6 +65,7 @@ void Shooter::initNetwork() {
client->setRemoveBonusCallBack([this](const ObjectNameTag &bonusName) { removeBonus(bonusName); }); client->setRemoveBonusCallBack([this](const ObjectNameTag &bonusName) { removeBonus(bonusName); });
client->setChangeEnemyWeaponCallBack( client->setChangeEnemyWeaponCallBack(
[this](const std::string &weaponName, sf::Uint16 id) { changeEnemyWeapon(weaponName, id); }); [this](const std::string &weaponName, sf::Uint16 id) { changeEnemyWeapon(weaponName, id); });
} }
void Shooter::start() { void Shooter::start() {
@ -130,11 +131,11 @@ void Shooter::start() {
server->stop(); server->stop();
this->exit(); this->exit();
}, "Exit", 5, 5, ShooterConsts::MAIN_MENU_GUI, {0, 66}, {0, 86}, {0, 46}, Consts::MEDIUM_FONT, {255, 255, 255}); }, "Exit", 5, 5, ShooterConsts::MAIN_MENU_GUI, {0, 66}, {0, 86}, {0, 46}, Consts::MEDIUM_FONT, {255, 255, 255});
client->setChatManager(chat);
} }
void Shooter::update() { void Shooter::update() {
// This code executed every time step: // This code executed every time step:
server->update(); server->update();
client->update(); client->update();
@ -142,7 +143,14 @@ void Shooter::update() {
if (!screen->hasFocus()) { if (!screen->hasFocus()) {
return; return;
} }
if (keyboard->isKeyTapped(sf::Keyboard::Enter)) {
if (isTypingMessage) {
client->sendMessage(message);
message = "";
}
isTypingMessage = !isTypingMessage;
}
if (!isTypingMessage) {
if (keyboard->isKeyTapped(sf::Keyboard::Escape)) { if (keyboard->isKeyTapped(sf::Keyboard::Escape)) {
inGame = !inGame; inGame = !inGame;
screen->setMouseCursorVisible(!inGame); screen->setMouseCursorVisible(!inGame);
@ -163,10 +171,30 @@ void Shooter::update() {
if (keyboard->isKeyTapped(sf::Keyboard::L)) { if (keyboard->isKeyTapped(sf::Keyboard::L)) {
screen->stopRender(); screen->stopRender();
} }
}
if (inGame) { if (inGame) {
screen->setTitle(ShooterConsts::PROJECT_NAME); screen->setTitle(ShooterConsts::PROJECT_NAME);
if (isTypingMessage) {
string symbols = screen->getInputSymbols();
for (char s : symbols) {
if (s == (char)8) {//backspace
message = message.substr(0, message.size() - 1);
}
else if (s == (char)27) {//escape
message = ""; //FIXME: не работает потому что isKeyTapped имеют задержку,
isTypingMessage = false; //т. е. этот код выполняется после нажатия на ESC,
} // но при следующем цикле при проверке isKeyTapped(ESC) возвращается TRUE
else if (message.length() < ShooterConsts::MAX_MESSAGE_LENGTH && s!=(char)13) {//13=enter
message += s;
}
}
}
else {
playerController->update(); playerController->update();
}
} else { } else {
mainMenu.update(); mainMenu.update();
} }
@ -177,6 +205,24 @@ void Shooter::update() {
if (SoundController::getStatus(SoundTag("background")) != sf::Sound::Status::Playing) { if (SoundController::getStatus(SoundTag("background")) != sf::Sound::Status::Playing) {
SoundController::loadAndPlay(SoundTag("background"), ShooterConsts::BACK_NOISE); SoundController::loadAndPlay(SoundTag("background"), ShooterConsts::BACK_NOISE);
} }
}
void Shooter::drawChat() {
sf::Color chatColor = isTypingMessage? sf::Color(50, 50, 50, 255) : sf::Color(50, 50, 50, chat->update(Time::deltaTime()));
string chatText = isTypingMessage ? chat->getChat() : chat->getChatPreview();
screen->drawText(chatText, Vec2D{ 0, (double)screen->height()*0.25 }, 20, chatColor);
if (isTypingMessage){
screen->drawTetragon(
Vec2D{ (double)screen->width() * 0.05, (double)screen->height() * 0.7 },
Vec2D{ (double)screen->width() * 0.95, (double)screen->height() * 0.7 },
Vec2D{ (double)screen->width() * 0.95, (double)screen->height() * 0.7+40 },
Vec2D{ (double)screen->width() * 0.05, (double)screen->height() * 0.7+40 }, sf::Color(150, 150, 150, 150));
screen->drawText(message, Vec2D{(double)screen->width() * 0.05, (double)screen->height() * 0.7}, 30, sf::Color(0, 0, 0, 255));
}
} }
void Shooter::gui() { void Shooter::gui() {
@ -192,6 +238,7 @@ void Shooter::gui() {
// health player stats // health player stats
drawPlayerStats(); drawPlayerStats();
drawStatsTable(); drawStatsTable();
drawChat();
} }
void Shooter::drawStatsTable() { void Shooter::drawStatsTable() {

View File

@ -26,6 +26,9 @@ private:
std::shared_ptr<ShooterServer> server = std::make_shared<ShooterServer>(); std::shared_ptr<ShooterServer> server = std::make_shared<ShooterServer>();
std::shared_ptr<ShooterClient> client = std::make_shared<ShooterClient>(player); std::shared_ptr<ShooterClient> client = std::make_shared<ShooterClient>(player);
std::shared_ptr<ChatManager> chat = std::make_shared<ChatManager>();
bool isTypingMessage = false;
string message = "";
bool inGame = false; bool inGame = false;
int fireTraces = 0; int fireTraces = 0;
@ -34,6 +37,7 @@ private:
void start() override; void start() override;
void update() override; void update() override;
void gui() override; void gui() override;
void drawChat();
void play(); void play();
void drawPlayerStats(); void drawPlayerStats();
void drawStatsTable(); void drawStatsTable();

View File

@ -15,6 +15,7 @@ namespace ShooterConsts {
const double SLOW_MO_COEFFICIENT = 5; const double SLOW_MO_COEFFICIENT = 5;
const double FIRE_DISTANCE = 1000; const double FIRE_DISTANCE = 1000;
const double BONUS_RECHARGE_TIME = 30; const double BONUS_RECHARGE_TIME = 30;
const int MAX_MESSAGE_LENGTH = 70;
const std::string PLAYER_NAME = "Player"; const std::string PLAYER_NAME = "Player";
const std::string PROJECT_NAME = "Shooter"; const std::string PROJECT_NAME = "Shooter";

39
network/Chat.cpp Normal file
View File

@ -0,0 +1,39 @@
#include "Chat.h"
#include <string>
#include <iostream>
void ChatManager::addNewMessage(std::string author, std::string message) {
hide = 7.0;
messages.push_back(message);
authors.push_back(author);
isChatUpdate = true;
if (messages.size() > 20) {
messages.erase(messages.begin());
}
}
int ChatManager::update(double delta) {
hide = std::max(hide-delta, 0.0);
return std::min((int)(hide * 255.0), 255);
}
std::string ChatManager::getChat() {
updateChat(); return chatStr;
}
std::string ChatManager::getChatPreview() {
updateChat(); return chatStrPrev;
}
void ChatManager::updateChat() {
if (isChatUpdate) {
isChatUpdate = false;
int size = messages.size();
chatStr = "";
chatStrPrev = "";
for (int messageIndex = size - 1; messageIndex >= 0; messageIndex--)
{
if (messageIndex > size - 6) {
chatStrPrev += authors[messageIndex] + ": " + messages[messageIndex] + "\n";
}
chatStr += authors[messageIndex] + ": " + messages[messageIndex] + "\n";
}
}
}

23
network/Chat.h Normal file
View File

@ -0,0 +1,23 @@
//#ifndef SHOOTER_SHOOTERSERVER_H
#ifndef CHAT_H
#define CHAT_H
#include <vector>
#include <string>
using namespace std;
class ChatManager final {
private:
std::vector<std::string> messages;
std::vector<std::string> authors;
bool isChatUpdate = true;
std::string chatStr = "";
std::string chatStrPrev = "";
double hide = 0.0;
void updateChat();
public:
void addNewMessage(std::string author, std::string message);
int update(double delta);
std::string getChat();
std::string getChatPreview();
};
#endif

View File

@ -29,7 +29,6 @@ void ShooterClient::processInit(sf::Packet &packet) {
if (_spawnPlayerCallBack != nullptr) { if (_spawnPlayerCallBack != nullptr) {
_spawnPlayerCallBack(targetId); _spawnPlayerCallBack(targetId);
} }
_players[targetId]->translateToPoint(Vec3D{x, y, z}); _players[targetId]->translateToPoint(Vec3D{x, y, z});
_players[targetId]->setHealth(health); _players[targetId]->setHealth(health);
_players[targetId]->setKills(kills); _players[targetId]->setKills(kills);
@ -123,6 +122,18 @@ void ShooterClient::processDisconnect(sf::Uint16 targetId) {
} }
} }
void ShooterClient::sendMessage(string message){
if (message.length() == 0)
return;
chatManager->addNewMessage(_player->playerNickName(), message);
sf::Packet packet;
packet << MsgType::Custom << ShooterMsgType::newMessage << message;
_socket.send(packet, _socket.serverId());
}
void ShooterClient::newMessage(string message, string name) {
chatManager->addNewMessage(name, message);
}
void ShooterClient::processCustomPacket(sf::Packet &packet) { void ShooterClient::processCustomPacket(sf::Packet &packet) {
sf::Uint16 buffId[2]; sf::Uint16 buffId[2];
@ -131,6 +142,7 @@ void ShooterClient::processCustomPacket(sf::Packet &packet) {
ShooterMsgType type; ShooterMsgType type;
packet >> type; packet >> type;
string name, message;
switch (type) { switch (type) {
case ShooterMsgType::Kill: case ShooterMsgType::Kill:
@ -227,6 +239,11 @@ void ShooterClient::processCustomPacket(sf::Packet &packet) {
_changeEnemyWeaponCallBack(tmp, buffId[0]); _changeEnemyWeaponCallBack(tmp, buffId[0]);
} }
break; break;
case ShooterMsgType::newMessage:
packet >> name >> message;
newMessage(message, name);
break;
default: default:
Log::log("ShooterClient::processCustomPacket: unknown message type " + Log::log("ShooterClient::processCustomPacket: unknown message type " +
std::to_string(static_cast<int>(type))); std::to_string(static_cast<int>(type)));
@ -304,7 +321,7 @@ ShooterClient::setChangeEnemyWeaponCallBack(std::function<void(const std::string
_changeEnemyWeaponCallBack = std::move(changeEnemyWeapon); _changeEnemyWeaponCallBack = std::move(changeEnemyWeapon);
} }
void ShooterClient::requestMap(std::string clientIp, std::string *current_map) { void ShooterClient::requestMap(const std::string& clientIp, std::string *current_map) {
Log::log("---------[FTP server]---------"); Log::log("---------[FTP server]---------");
sf::Ftp ftp; sf::Ftp ftp;
sf::Ftp::Response connectResponse = ftp.connect(clientIp, 21); sf::Ftp::Response connectResponse = ftp.connect(clientIp, 21);
@ -316,7 +333,8 @@ void ShooterClient::requestMap(std::string clientIp, std::string *current_map) {
if (dirResponse.isOk()) { if (dirResponse.isOk()) {
const std::vector<std::string>& listing = dirResponse.getListing(); const std::vector<std::string>& listing = dirResponse.getListing();
if (listing.size()!=0) {
if (listing.size() != 0) {
for (std::vector<std::string>::const_iterator it = listing.begin(); it != listing.end(); ++it) for (std::vector<std::string>::const_iterator it = listing.begin(); it != listing.end(); ++it)
Log::log("- "+*it); Log::log("- "+*it);

View File

@ -8,6 +8,7 @@
#include "../3dzavr/engine/network/ClientUDP.h" #include "../3dzavr/engine/network/ClientUDP.h"
#include "../player/Player.h" #include "../player/Player.h"
#include <SFML/Config.hpp> #include <SFML/Config.hpp>
#include "Chat.h"
class ShooterClient final : public ClientUDP { class ShooterClient final : public ClientUDP {
private: private:
@ -22,9 +23,15 @@ private:
std::function<void(const std::string &, const Vec3D &)> _addBonusCallBack; std::function<void(const std::string &, const Vec3D &)> _addBonusCallBack;
std::function<void(const ObjectNameTag &)> _removeBonusCallBack; std::function<void(const ObjectNameTag &)> _removeBonusCallBack;
std::function<void(const std::string &, sf::Uint16)> _changeEnemyWeaponCallBack; std::function<void(const std::string &, sf::Uint16)> _changeEnemyWeaponCallBack;
std::shared_ptr<ChatManager> chatManager;
public: public:
explicit ShooterClient(std::shared_ptr<Player> player) : _player(player) {}; explicit ShooterClient(std::shared_ptr<Player> player) : _player(player) {};
void sendMessage(std::string message);
void newMessage(std::string message, std::string name);
void updatePacket() override; void updatePacket() override;
void setSpawnPlayerCallBack(std::function<void(sf::Uint16)> spawn); void setSpawnPlayerCallBack(std::function<void(sf::Uint16)> spawn);
@ -59,9 +66,11 @@ public:
void changeWeapon(const std::string &weaponName); void changeWeapon(const std::string &weaponName);
void setChatManager(std::shared_ptr<ChatManager> chat) { chatManager = chat; };
void addPlayer(sf::Uint16 id, std::shared_ptr<Player> player); void addPlayer(sf::Uint16 id, std::shared_ptr<Player> player);
void requestMap(std::string clientIp, std::string *current_map); static void requestMap(const std::string& clientIp, std::string *current_map);
[[nodiscard]] std::map<sf::Uint16, std::shared_ptr<Player>> const &players() const { return _players; } [[nodiscard]] std::map<sf::Uint16, std::shared_ptr<Player>> const &players() const { return _players; }

View File

@ -14,7 +14,8 @@ enum class ShooterMsgType {
InitBonuses, InitBonuses,
AddBonus, AddBonus,
RemoveBonus, RemoveBonus,
ChangeWeapon ChangeWeapon,
newMessage
}; };
sf::Packet &operator<<(sf::Packet &packet, ShooterMsgType type); sf::Packet &operator<<(sf::Packet &packet, ShooterMsgType type);

View File

@ -79,6 +79,7 @@ void ShooterServer::processCustomPacket(sf::Packet &packet, sf::Uint16 senderId)
double damage; double damage;
std::string tmp; std::string tmp;
double newHealth; double newHealth;
std::string message;
ShooterMsgType type; ShooterMsgType type;
packet >> type; packet >> type;
@ -140,6 +141,18 @@ void ShooterServer::processCustomPacket(sf::Packet &packet, sf::Uint16 senderId)
} }
} }
break;
case ShooterMsgType::newMessage:
packet >> message;
sendPacket << MsgType::Custom << ShooterMsgType::newMessage << _players[senderId]->playerNickName() << message;
if (message.length() == 0)
break;
for (auto& player : _players) {
if (player.first != senderId) {
_socket.send(sendPacket, player.first);
}
}
break; break;
default: default:
Log::log("ShooterServer::processCustomPacket: unknown message type " + Log::log("ShooterServer::processCustomPacket: unknown message type " +

View File

@ -17,6 +17,7 @@
#include "../weapon/Rifle.h" #include "../weapon/Rifle.h"
#include "../ShooterConsts.h" #include "../ShooterConsts.h"
class Player final : public RigidBody { class Player final : public RigidBody {
private: private:
double _health = ShooterConsts::HEALTH_MAX; double _health = ShooterConsts::HEALTH_MAX;