R-Type
Distributed multiplayer game engine in C++
Loading...
Searching...
No Matches
Client.cpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** Created by mael on 08/12/2025.
4** File description:
5** Client.cpp
6*/
7
8#include "Client.hpp"
9
10Client::Client(const std::string &playerName, const std::string &host, uint16_t port, bool isSpectator)
11 : _playerName(playerName),
12 _username(""),
13 _password(""),
14 _serverHost(host),
15 _serverPort(port),
16 _isSpectator(isSpectator) {}
17
18Client::Client(const std::string &playerName, const std::string &username, const std::string &password,
19 const std::string &host, uint16_t port)
20 : _playerName(playerName),
21 _username(username),
22 _password(password),
23 _serverHost(host),
24 _serverPort(port),
25 _isSpectator(false) {}
26
28 LOG_INFO("Client shutting down...");
29 if (_gameLoop) {
30 _gameLoop->shutdown();
31 }
32 if (_replicator) {
33 _replicator->disconnect();
34 }
36}
37
39 if (_initialized) {
40 return true;
41 }
42
43 LOG_INFO("Initializing R-Type client...");
44
45 // Initialize networking
46 if (!initializeNetworking()) {
47 LOG_ERROR("Failed to initialize networking");
48 return false;
49 }
50
51 // Create EventBus
52 _eventBus = std::make_unique<EventBus>();
53 LOG_INFO("✓ EventBus created");
54
55 // Create Replicator
56 _replicator = std::make_unique<Replicator>(*_eventBus, _isSpectator);
57 LOG_INFO("✓ Replicator created", _isSpectator ? " (Spectator mode)" : "");
58
59 // Create GameLoop (pass shared EventBus, Replicator, and player name)
60 _gameLoop = std::make_unique<GameLoop>(*_eventBus, *_replicator, _playerName);
61
62 if (!_gameLoop->initialize()) {
63 LOG_ERROR("Failed to initialize GameLoop");
64 return false;
65 }
66 LOG_INFO("✓ GameLoop initialized");
67
68 _initialized = true;
69 LOG_INFO("Initialization complete!");
70
71 return true;
72}
73
74void Client::SetCredentials(const std::string &username, const std::string &password) {
75 _username = username;
76 _password = password;
77}
78
79void Client::SetServer(const std::string &host, uint16_t port) {
80 _serverHost = host;
81 _serverPort = port;
82 LOG_INFO("[Client] Server changed to ", host, ":", port);
83}
84
86 return connectToServer();
87}
88
90 LOG_INFO("Connecting to ", _serverHost, ":", _serverPort, "...");
91
92 if (!_replicator->connect(_serverHost, _serverPort)) {
93 LOG_ERROR("Failed to initiate connection");
94 return false;
95 }
96
97 // Wait for connection to establish (max 5 seconds)
98 LOG_INFO("Waiting for connection...");
99 bool connected = false;
100 for (int i = 0; i < 50 && !connected; ++i) {
101 _replicator->processMessages();
102 connected = _replicator->isConnected();
103 std::this_thread::sleep_for(std::chrono::milliseconds(100));
104 }
105
106 if (!connected) {
107 LOG_ERROR("Connection timeout");
108 return false;
109 }
110
111 LOG_INFO("✓ Connected to server!");
112
113 // Send connect request with authentication
114 LOG_INFO("Sending authentication request...");
115
116 // Use default credentials if not provided
117 std::string username = _username.empty() ? "guest" : _username;
118 std::string password = _password.empty() ? "guest" : _password;
119
120 if (!_replicator->sendConnectRequest(_playerName, username, password)) {
121 LOG_ERROR("Failed to send connect request");
122 return false;
123 }
124
125 // Wait for server response (max 3 seconds)
126 LOG_INFO("Waiting for server response...");
127 bool authenticated = false;
128 for (int i = 0; i < 30 && !authenticated; ++i) {
129 _replicator->processMessages();
130 // Check if we received authentication response
131 // For now, we assume processMessages handles it and we're authenticated after processing
132 // In a real implementation, you'd check a flag or state in Replicator
133 // Since we don't have access to that state, we keep the timeout but reduce it
134 std::this_thread::sleep_for(std::chrono::milliseconds(100));
135
136 // TODO: Add a method to Replicator to check if authenticated
137 // For now, we'll just wait a reasonable amount (500ms should be enough)
138 if (i >= 5) {
139 // After 500ms, assume we got the response
140 authenticated = true;
141 }
142 }
143
144 LOG_INFO("✓ Handshake complete!");
145
146 return true;
147}
148
150 if (!_initialized) {
151 LOG_ERROR("Cannot run: not initialized");
152 return;
153 }
154
155 LOG_INFO("Starting R-Type client...");
156 LOG_INFO("========================================");
157 LOG_INFO("R-Type Client Ready");
158 LOG_INFO(_isSpectator ? "Spectator: " : "Player: ", _playerName);
159 LOG_INFO("Waiting for server selection...");
160 LOG_INFO("========================================");
161
162 // Subscribe to SERVER_CONNECT event
163 _eventBus->subscribe<UIEvent>([this](const UIEvent &event) {
164 if (event.getType() == UIEventType::SERVER_CONNECT) {
165 // Parse server info from event data (format: "IP:PORT")
166 const std::string &serverInfo = event.getData();
167 size_t colonPos = serverInfo.find(':');
168 if (colonPos != std::string::npos) {
169 std::string ip = serverInfo.substr(0, colonPos);
170 uint16_t port = static_cast<uint16_t>(std::stoi(serverInfo.substr(colonPos + 1)));
171
172 LOG_INFO("[Client] Connecting to ", ip, ":", port, "...");
173 SetServer(ip, port);
174
175 // Launch connection in separate thread to avoid blocking UI
176 std::thread([this]() {
177 if (!Connect()) {
178 LOG_ERROR("[Client] Connection failed!");
179 // Publish CONNECTION_FAILED event
180 _eventBus->publish(UIEvent(UIEventType::CONNECTION_FAILED, "Server unreachable"));
181 } else {
182 LOG_INFO("[Client] ✓ Connected successfully!");
183 // Publish CONNECTION_SUCCESS event
185 }
186 }).detach();
187 }
188 }
189 });
190
191 // Run game loop (blocking) - connection will happen when SERVER_CONNECT event is published
192 _gameLoop->run();
193
194 LOG_INFO("Game loop stopped.");
195}
196
198 LOG_INFO("Stop requested...");
199 if (_gameLoop) {
200 _gameLoop->stop();
201 }
202}
#define LOG_INFO(...)
Definition Logger.hpp:181
#define LOG_ERROR(...)
Definition Logger.hpp:183
bool initializeNetworking()
Initialize the networking subsystem.
void deinitializeNetworking()
Cleanup the networking subsystem.
bool _initialized
Definition Client.hpp:119
uint16_t _serverPort
Definition Client.hpp:112
bool initialize()
Initialize client systems.
Definition Client.cpp:38
std::string _playerName
Definition Client.hpp:108
void SetServer(const std::string &host, uint16_t port)
Set server address and port.
Definition Client.cpp:79
std::unique_ptr< Replicator > _replicator
Definition Client.hpp:116
~Client()
Destructor - clean shutdown.
Definition Client.cpp:27
bool connectToServer()
Connect to server.
Definition Client.cpp:89
std::string _username
Definition Client.hpp:109
void stop()
Stop the client.
Definition Client.cpp:197
Client(const std::string &playerName, const std::string &host, uint16_t port, bool isSpectator=false)
Constructor.
Definition Client.cpp:10
std::string _password
Definition Client.hpp:110
std::unique_ptr< GameLoop > _gameLoop
Definition Client.hpp:117
bool Connect()
Connect to the configured server.
Definition Client.cpp:85
std::string _serverHost
Definition Client.hpp:111
void SetCredentials(const std::string &username, const std::string &password)
Update credentials for next connection attempt.
Definition Client.cpp:74
bool _isSpectator
Definition Client.hpp:113
void run()
Run the client (Start Game Loop directly)
Definition Client.cpp:149
std::unique_ptr< EventBus > _eventBus
Definition Client.hpp:115