27 using std::make_unique;
31 using std::unique_ptr;
53 ApplicationClient::ApplicationClient(
Context* context,
UDPClient* udpClient) :
Thread(
"applicationserverclientthread"), mutex(
"applicationserverclientthread-mutex") {
54 this->context = unique_ptr<Context>(
context);
55 this->udpClient = unique_ptr<UDPClient>(
udpClient);
70 Console::println(
"ApplicationClient::run(): init");
73 auto timeLast = Time::getCurrentMillis();
74 vector<LogicNetworkPacket> inLogicsNetworkPacketsUnhandled;
75 vector<LogicNetworkPacket> safeLogicNetworkPackets;
76 vector<LogicNetworkPacket> fastLogicNetworkPackets;
77 vector<LogicNetworkPacket> inNetworkPackets;
79 auto timeNow = Time::getCurrentMillis();
82 for (
auto& logicNetworkPacket: inLogicsNetworkPacketsUnhandled) {
83 if (timeNow - logicNetworkPacket.getTime() > 1000L) {
84 string logicTypeIdString;
85 logicTypeIdString+= (char)((logicNetworkPacket.getLogicTypeId() >> 0) & 0xFF);
86 logicTypeIdString+= (char)((logicNetworkPacket.getLogicTypeId() >> 8) & 0xFF);
87 logicTypeIdString+= (char)((logicNetworkPacket.getLogicTypeId() >> 16) & 0xFF);
88 logicTypeIdString+= (char)((logicNetworkPacket.getLogicTypeId() >> 24) & 0xFF);
89 Console::println(
"ApplicationClient::run(): unhandled IN packet: 1s late: " + logicTypeIdString);
90 Console::println(
"Packet ASCII: ");
91 for (
auto i = 0; i < 255; i++) {
92 Console::print(
string() + (
char)(logicNetworkPacket.getData()[i]));
94 Console::println(
"Packet ORD: ");
95 for (
auto i = 0; i < 255; i++) {
96 Console::print(to_string(
int(logicNetworkPacket.getData()[i])) +
" ");
100 logicNetworkPacket.setReinjected();
101 inNetworkPackets.push_back(logicNetworkPacket);
103 inLogicsNetworkPacketsUnhandled.clear();
108 while (
true ==
true) {
110 unique_ptr<UDPClientMessage> message(
udpClient->receiveMessage());
112 if (message ==
nullptr)
break;
114 auto packet = message->getPacket();
115 if (packet ==
nullptr) {
119 auto safe = packet->getBool();
120 if (safe ==
true &&
udpClient->processSafeMessage(message.get()) ==
false) {
124 while (packet->getPosition() < UDPPacket::PACKET_MAX_SIZE - 17) {
126 auto size = packet->getByte();
129 if (size == 0)
break;
131 auto logicTypeId = packet->getInt();
134 inNetworkPackets.emplace_back(
135 message->getMessageId(),
137 message->getRetryCount(),
153 while (
true ==
true) {
155 auto newLogics =
context->getNewLogics();
158 auto addedLogics =
context->addNewLogics();
159 if (addedLogics == 0)
break;
166 for (
auto logic:
context->getLogics()) {
167 logic->updateLogic();
171 while (
true ==
true) {
173 auto newLogics =
context->getNewLogics();
176 auto addedLogics =
context->addNewLogics();
177 if (addedLogics == 0)
break;
183 for (
auto newLogic: newLogics) newLogic->updateLogic();
187 for (
auto logic:
context->getLogics()) {
188 logic->onLogicsProcessed();
195 for (
auto& packet: inNetworkPackets) {
196 if (packet.isProcessed() ==
false) {
197 inLogicsNetworkPacketsUnhandled.push_back(packet);
201 inNetworkPackets.clear();
209 for (
auto logic:
context->getLogics()) {
211 if (networkLogic !=
nullptr) {
217 for (
auto logic:
context->getLogics()) {
219 if (networkLogic !=
nullptr) {
224 if (logicNetworkPacket.getSafe() ==
true) {
225 safeLogicNetworkPackets.push_back(logicNetworkPacket);
227 fastLogicNetworkPackets.push_back(logicNetworkPacket);
238 auto udpClientPacket = make_unique<UDPPacket>();
240 udpClientPacket->putBool(
true);
242 for (
auto& safeNetworkPacket: safeLogicNetworkPackets) {
244 auto size = safeNetworkPacket.getPosition();
246 auto datagramSize = udpClientPacket->getSize();
248 if (datagramSize + 2 + (uint16_t)size > UDPPacket::PACKET_MAX_SIZE - 17) {
249 if (datagramSize < UDPPacket::PACKET_MAX_SIZE - 17) {
251 udpClientPacket->putByte(0);
254 udpClientPacket = make_unique<UDPPacket>();
256 udpClientPacket->putBool(
true);
259 udpClientPacket->putByte(size);
261 udpClientPacket->putInt(safeNetworkPacket.getLogicTypeId());
263 udpClientPacket->putBytes(safeNetworkPacket.getData(), safeNetworkPacket.getPosition());
266 auto datagramSize = udpClientPacket->getSize();
267 if (datagramSize > 1) {
268 if (datagramSize < UDPPacket::PACKET_MAX_SIZE - 17) {
270 udpClientPacket->putByte(0);
275 safeLogicNetworkPackets.clear();
279 auto udpClientPacket = make_unique<UDPPacket>();
281 udpClientPacket->putBool(
false);
283 for (
auto& fastNetworkPacket: fastLogicNetworkPackets) {
285 auto size = fastNetworkPacket.getPosition();
287 auto datagramSize = udpClientPacket->getSize();
288 if (datagramSize + 2 + (uint16_t)size > UDPPacket::PACKET_MAX_SIZE - 17) {
289 if (datagramSize < UDPPacket::PACKET_MAX_SIZE - 17) {
291 udpClientPacket->putByte(0);
294 udpClientPacket = make_unique<UDPPacket>();
296 udpClientPacket->putBool(
false);
299 udpClientPacket->putByte(size);
301 udpClientPacket->putInt(fastNetworkPacket.getLogicTypeId());
303 udpClientPacket->putBytes(fastNetworkPacket.getData(), fastNetworkPacket.getPosition());
306 auto datagramSize = udpClientPacket->getSize();
307 if (datagramSize > 1) {
308 if (datagramSize < UDPPacket::PACKET_MAX_SIZE - 17) {
310 udpClientPacket->putByte(0);
315 fastLogicNetworkPackets.clear();
320 int64_t timeDelta = Time::getCurrentMillis() - timeLast;
321 if (timeDelta > 33) {
322 Console::println(
"ApplicationClient::run(): time delta < 33FPS, it took " + to_string(timeDelta) +
" ms to compute");
325 if (timeDelta < 16) {
329 if (
context->isInitialized() ==
true) {
330 context->getWorld()->update(timeDelta / 1000.0f);
332 timeDelta = Time::getCurrentMillis() - timeLast;
333 if (timeDelta < 16) {
334 Thread::sleep(16 - timeDelta);
336 timeLast = Time::getCurrentMillis();
340 Console::println(
"ApplicationClient::run(): done");
345 for (
auto& logicNetworkPacket: inLogicNetworkPackets) {
346 for (
auto logic: logics) {
348 if (networkLogic !=
nullptr) {
350 logicNetworkPacket.reset();
360 for (
auto logic:
context->getLogics()) {
361 if (logic->isHandlingHIDInput() ==
true) {
362 logic->handleHIDEvents(mouseEvents, keyEvents);
370 auto now = Time::getCurrentMillis();
374 vector<Logic::QueuedSound> requeueSounds;
375 for (
auto logic:
context->getLogics()) {
376 logic->updateEngine();
378 auto gameLogicId = logic->getId();
379 for (
auto& queuedSound: logic->getQueuedSounds()) {
380 if (now > queuedSound.timeIssuedAt +
static_cast<int64_t
>(queuedSound.timeDelay)) {
386 queuedSound.ignoreIfPlaying,
387 queuedSound.attachedToLogic,
388 queuedSound.position,
392 requeueSounds.push_back(queuedSound);
395 logic->setQueuedSounds(requeueSounds);
396 requeueSounds.clear();
403 auto engine =
context->getEngine();
404 auto audio =
context->getAudio();
405 const auto& cameraPosition = engine->getCamera()->getLookFrom();
407 if (queuedSound.attachedToLogic ==
true) {
408 auto entity = engine->getEntity(queuedSound.gameLogicId);
409 if (entity ==
nullptr) {
411 queuedSound.distanceFromCamera = 100.0f * 100.0f;
413 queuedSound.position = entity->getTranslation();
416 queuedSound.distanceFromCamera = queuedSound.position.clone().sub(cameraPosition).computeLengthSquared();
422 return queuedSound1.distanceFromCamera < queuedSound2.distanceFromCamera;
426 if (queuedSound.distanceFromCamera >= 100.0f * 100.0f)
continue;
427 if (queuedSound.ignoreIfPlaying ==
true) {
428 auto activeSoundKey = queuedSound.gameLogicId +
"." + queuedSound.id;
431 auto sound = audio->getEntity(activeSoundIt->second.id);
432 if (sound !=
nullptr && sound->isPlaying() ==
true) {
433 sound->setSourcePosition(queuedSound.position);
434 sound->setGain(
audioGain * queuedSound.gain);
435 sound->setPitch(queuedSound.pitch);
440 for (
auto i = 0; i <
context->getSoundPoolSize(); i++) {
441 auto sound = audio->getEntity(queuedSound.id + (
context->getSoundPoolSize() == 1?
"":
"." + to_string(i)));
442 if (sound ==
nullptr) {
443 Console::println(
"WS::display(): " + queuedSound.gameLogicId +
": " + queuedSound.id +
": sound not found");
446 if (sound->isPlaying() ==
true) {
449 sound->setGain(
audioGain * queuedSound.gain);
450 sound->setSourcePosition(queuedSound.position);
451 sound->setPitch(queuedSound.pitch);
453 if (queuedSound.ignoreIfPlaying ==
true) {
454 auto activeSoundKey = queuedSound.gameLogicId +
"." + queuedSound.id;
456 .id = sound->getId(),
457 .attachedToLogic = queuedSound.attachedToLogic,
458 .gameLogicId = queuedSound.gameLogicId
464 vector<string> inactiveSounds;
465 for (
const auto& [activeSoundKey, activeSound]:
activeSounds) {
466 auto sound = audio->getEntity(activeSound.id);
467 if (sound->isPlaying() ==
false) {
468 inactiveSounds.push_back(activeSoundKey);
471 if (activeSound.attachedToLogic ==
true) {
472 auto entity = engine->getEntity(activeSound.gameLogicId);
473 if (entity !=
nullptr) sound->setSourcePosition(entity->getTranslation());
476 for (
auto& inactiveSound: inactiveSounds) {
Interface to audio module.
virtual ~ApplicationClient()
Public constructor.
unique_ptr< UDPClient > udpClient
unique_ptr< Context > context
void handleInNetworkPackets(const vector< Logic * > &logics, vector< LogicNetworkPacket > &inLogicNetworkPackets)
Handle in logic network packets.
unordered_map< string, ActiveSound > activeSounds
vector< QueuedSound > queuedSounds
void update()
Updates engine and audio to context engine and audio instances.
void handleHIDEvents(vector< GUIMouseEvent > &mouseEvents, vector< GUIKeyboardEvent > &keyEvents)
Collect HID events to pass to logics that have handling HID events enabled.
virtual void run() override
Abstract run() method, should be implemented by subclassed class, will be called after spawn by start...
void setLogicsMutex(Mutex *logicsMutex)
Set logics mutex.
static constexpr uint32_t LOGIC_TYPEID_NONE
vector< LogicNetworkPacket > & getNetworkPackets()
Get outgoing network packets.
virtual uint32_t getNetworkPacketTypeId()=0
virtual void handleNetworkPacket(LogicNetworkPacket &packet)=0
Handle network packet.
Dynamic physics world class.
void unlock()
Unlocks this mutex.
void lock()
Locks the mutex, additionally mutex locks will block until other locks have been unlocked.
bool isStopRequested()
Returns if stop has been requested.