/* * @RDE_HEADER@ * Worker for Tetra Simulation * $Id$ * $HeadURL$ * $Author$ */ #include "worker.h" #include #include #include #include #include #include #include #include TTWorker::TTWorker(QTcpSocket *socket, const TTSArgs &ttsArgs) : m_socket(socket) , m_timer(new QTimer(this)) , m_counter(0) , m_toogle(true) , m_ttsArgs(ttsArgs) , m_patternList(interpretPattern(ttsArgs.pattern)) , m_generalPosition(ttsArgs.position) , m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("TTWorker")) { qsrand(time(nullptr)); // randomize for later use in class "Player" } bool TTWorker::init() { connect(m_socket, &QTcpSocket::disconnected, this, &TTWorker::deleteLater); connect(m_socket, QOverload::of(&QTcpSocket::error), this, &TTWorker::onSocketError); connect(m_socket, &QTcpSocket::readyRead, this, &TTWorker::onReadyRead); connect(m_timer, &QTimer::timeout, this, &TTWorker::onSendPlayerPositions); if (m_ttsArgs.movs_per_msec < 200) { ERROR_LOG(m_logger) << "Invalid value for 'movements per milliseconds'! Please choose a number greater than 200 msecs or equal. Program stopped."; return false; } return true; } void TTWorker::startExecution() { //mTimer->start(mTtsargs.movs_per_msec); m_timer->start(m_ttsArgs.movs_per_msec); NOTICE_LOG(m_logger) << "Start Exe login all Player"; // create all players & add them to the players-list, send logins for (unsigned int i = 0; i < m_ttsArgs.cntPlayer; i++) { int eqId = m_ttsArgs.eqIdStart + i; int issi = m_ttsArgs.eqIdStart + i + 2000; // = Ausstattungsnummer + 2000 QPointF posUTM((m_generalPosition.x() + (i / m_ttsArgs.pprow) * m_ttsArgs.pspacing), (m_generalPosition.y() + (i % m_ttsArgs.pprow) * m_ttsArgs.pspacing)); // initial position for a player Player *p = new Player(eqId, issi, m_ttsArgs.minimumDeathTicks, m_ttsArgs.maximumDeathTicks, posUTM); m_playerList.append(p); sendLogin(p->eqId, p->issi); } if (m_ttsArgs.deactivationSingleMines) QTimer::singleShot(1000, this, &TTWorker::onSendDeaktivierungEinzelminen); if (m_ttsArgs.demandOldBraodcastTelegrams) QTimer::singleShot(1000, this, &TTWorker::onSendNachforderungBroadcastTelegramm); // QTimer::singleShot(25000, this , &TTWorker::onSendNlosSimulatorDirection); // QTimer::singleShot(120000, this , &TTWorker::onSendNlosFireResult); } QVector TTWorker::interpretPattern(QString pattern) const { if (pattern.isEmpty()) { ERROR_LOG(m_logger) << "INVALID PATTERN - pattern-size < 1"; exit(8); } if (pattern.at(0) == QLatin1Char('%')) // this pattern is a predefined pattern from the settings file { pattern.remove(0, 1); // delete '%'-character as it disturbes the interpreter QString patternAlias = pattern; pattern = m_ttsArgs.settings->value(QLatin1String("pattern/") + patternAlias).toString(); if (pattern.isEmpty()) // there is no pattern with this alias! { ERROR_LOG(m_logger) << "INVALID PATTERN - alias '" << patternAlias << "' is not available in settings file! Program halted."; exit(9); } } // now the pattern (if it was only an alias) is refered, continue..: if (pattern.at(pattern.count() - 1) == QLatin1Char('#')) // delete the character ';' if there is one at the end of string - because of strtok/split pattern.remove(pattern.count() - 1, 1); QVector newPatternList; // list we give back to replace the patternList in this class runningPattern rp; // pattern we use (and reuse) to add a new runningPattern instance to the patternList QStringList strings = pattern.split(QLatin1Char('#')); // list of pattern (f.g. "1,2,3", "1,2,3"); QStringList stringy; // list of pattern-ingredients ;) (f.g. "1", "2", "3") int i; // counter, global because of error message at the end of this function (see variable "strings") for (i = 0; i < strings.count(); i++) { stringy = strings.at(i).split(QLatin1Char(',')); // split one pattern to the "ingredients" if (stringy.count() != 3) // pattern consists of 3 numbers, if there are more or less, then the pattern is wrong break; bool ok = true; rp.steps = stringy.at(0).toInt(&ok); if (!ok) break; // is not a number, so throw an error and exit this application rp.ethering = stringy.at(1).toInt(&ok); if (!ok) break; // ^ rp.northering = stringy.at(2).toInt(&ok); if (!ok) break; // ^ newPatternList.append(rp); // add a new instance to the list (i hope this will create an instance and does not use a reference !!1) if (i == strings.count() - 1) // are we at the end of the strings.count ? if yes, then return the list - important to NOT throw a error message return newPatternList; // IMPORTANT! Or an wrong error message will be thrown } ERROR_LOG(m_logger) << "INVALID PATTERN: '" << strings.at(i) << "'. Cannot start without correct pattern!"; exit(5); // we can't work - exit! return QVector(); // for security & compiler issues.. } void TTWorker::sendLogin(uint32_t eqId, uint32_t issi) { N_CoPrtCnv::CoPrtCnvRadioTelegram *tele = new N_CoPrtCnv::CoPrtCnvRadioTelegram(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_LoginRequest, eqId, issi); DEBUG_LOG(m_logger) << "SEND LOGIN FOR ISSI=" << issi << ", eqId=" << eqId; sendTelegram(tele, issi); } void TTWorker::onReadyRead() { N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader header; qint64 bytesRead = m_socket->peek((char *)&header, sizeof(header)); if (sizeof(header) != bytesRead) { DEBUG_LOG(m_logger) << "To few bytes to read from socket"; return; } if (N_CoPrtCnv::CoPrtCnvRadioTelegram::MAGIC_NUMBER != header.m_MagicNumber) { ERROR_LOG(m_logger) << "Disconnect because radio-Telegram does not begin with magic-number A5: I got " << header.m_MagicNumber; m_socket->disconnectFromHost(); return; } if (!N_CoPrtCnv::CoPrtCnvRadioTelegram::isTelegramLengthOk(header.m_Length)) { WARNING_LOG(m_logger) << "Radio-Telegram length to big: " << header.m_Length << " - but I proceed with this telegram."; } // prepare data-bucket for entire telegram uint16_t dataSize = header.m_Length + sizeof(header); if (m_socket->bytesAvailable() < dataSize) { DEBUG_LOG(m_logger) << "not enough bytes available - waiting for more data"; return; } QByteArray buf(dataSize, Qt::Uninitialized); // read the telegram with header bytesRead = 0; while (bytesRead < dataSize) { qint64 br = m_socket->read(&buf.data()[bytesRead], dataSize - bytesRead); bytesRead += br; } handleReceivedTelegram(buf); if (m_socket->bytesAvailable()) QTimer::singleShot(0, this, &TTWorker::onReadyRead); } void TTWorker::handleReceivedTelegram(const QByteArray &data) { INFO_LOG(m_logger) << data.size(); // evaluate PDU-Type switch (data.at(4)) { // response to register indication case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterInd: handleRegisterInd(); startExecution(); break; case N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq: handleDataIndReq(data); // tele->getDestISSI() == ISSI an des angesprochenen Teilnehmers // data is deleted inside handleDataIndReq() break; default: INFO_LOG(m_logger) << "Radio-Telegram with PDU-Type=" << (int)data[4] << " not implemented!"; break; } } void TTWorker::sendTelegram(N_CoPrtCnv::CoPrtCnvRadioTelegram *radioTelegram, uint32_t issi) { radioTelegram->setZaehler(m_counter++); radioTelegram->setDestISSI(m_ttsArgs.destIssi); radioTelegram->setSrcISSI(issi); //INFO_LOG(mLogger) << "BITE message sent for Player (" << eqId << ") with ISSI: " << issi; m_socket->write(radioTelegram->data()); m_socket->flush(); delete radioTelegram; } void TTWorker::onSendNachforderungBroadcastTelegramm() { Player *p = m_playerList.at(0); if (p->isLogin) { N_CoPrtCnv::CoPrtCnvRadioTelegram tel(GEF_NACHFORDERUNG_BROADCAST_TELEGRAMME, 10, p->eqId); tel.setZaehler(0); tel.setBroadcastIndex(0); tel.setDestISSI(m_ttsArgs.destIssi); tel.setSrcISSI(p->issi); tel.setPayload4Byte(0); // gps_zeit tel.setPayload1Byte(0); // ruecksetzzaehler tel.setPayload2Byte(m_ttsArgs.demandOldBraodcastTelegramsCounter); // broadcast index m_socket->write(tel.data()); } else QTimer::singleShot(1000, this, &TTWorker::onSendNachforderungBroadcastTelegramm); } void TTWorker::onSendDeaktivierungEinzelminen() { if (m_playerList.isEmpty()) { ERROR_LOG(m_logger) << "No player for onSendDeaktivierungEinzelminen..."; return; } Player *p = m_playerList.at(0); static unsigned int mineId = m_ttsArgs.minimumMineId; NOTICE_LOG(m_logger) << "onSendDeaktivierungEinzelminen " << p->isLogin; if (p->isLogin) { TrainingAreaBase::TetraIcd::MineTriggered tele; tele.header.equipmentNumber = p->eqId; tele.header.timeStamp = time(nullptr) * 1000; tele.mineIndex = mineId++; tele.mineAreaId = 0; sendTelegram(tele, p->issi); } if (mineId <= m_ttsArgs.maximumMineId) QTimer::singleShot(1000, this, &TTWorker::onSendDeaktivierungEinzelminen); } /*! \brief Send sample NlosFireResult Telegram every three minutes (FOR TESTING NLOS) \author Niklas Schmidt */ // void TTWorker::onSendNlosFireResult() // { // if (m_playerList.isEmpty()) // { // ERROR_LOG(m_logger) << "No player for onSendNlosFireResult..."; // return; // } // Player *p = m_playerList.at(0); // TrainingAreaBase::TetraIcd::NlosDirectionOrShootingResult fireResult; // fireResult.header.equipmentNumber = p->eqId; // fireResult.header.timeStamp = time(nullptr) * 1000; // fireResult.messageId = 0xE401; // fireResult.version = 4; // fireResult.shootingRes = TrainingAreaBase::TetraIcd::NlosDirectionOrShootingResult::ShootingResult::Hit; // fireResult.targetEquipmentNumber = 1205; // INFO_LOG(m_logger) << "Send NlosFireResult"; // sendTelegram(fireResult, p->issi); // QTimer::singleShot(120000, this, &TTWorker::onSendNlosFireResult); // } /*! \brief Send sample NlosSimulatorDirection Telegram(FOR TESTING NLOS) \author Niklas Schmidt */ // void TTWorker::onSendNlosSimulatorDirection() // { // if (m_playerList.isEmpty()) // { // ERROR_LOG(m_logger) << "No player for onSendNlosFireResult..."; // return; // } // Player *p = m_playerList.at(0); // TrainingAreaBase::TetraIcd::NlosDirectionOrShootingResult simulatorDirection; // simulatorDirection.header.equipmentNumber = 7150; // simulatorDirection.header.timeStamp = time(nullptr) * 1000; // simulatorDirection.messageId = 0xE400; // std::random_device rd; //Will be used to obtain a seed for the random number engine // std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd() // std::uniform_int_distribution distrib(1, 34999); // simulatorDirection.version = 4; // simulatorDirection.directionInDegree = 0/*distrib(gen)*/; // simulatorDirection.attachmentInDegree = 0; // INFO_LOG(m_logger) << "Send NlosSimulatorDirection"; // sendTelegram(simulatorDirection, p->issi); // QTimer::singleShot(100000, this, &TTWorker::onSendNlosSimulatorDirection); // } void TTWorker::sendTaktischerStatus(uint32_t eqId, uint32_t issi, TrainingAreaBase::TetraIcd::VulnerabilityState vbg) { TrainingAreaBase::TetraIcd::StateChange tele; tele.header.equipmentNumber = eqId; tele.header.timeStamp = time(nullptr) * 1000; tele.tasVitality = 90; tele.tasVulnerabilityKindId = 459008; tele.vulnerabilityBits = 0; for (Player *p : qAsConst(m_playerList)) { if (p->eqId == eqId) { p->vbg = vbg; tele.vulnerabilityState = vbg; DEBUG_LOG(m_logger) << "Player (" << p->eqId << ") - VBG: " << int(vbg); break; } } sendTelegram(tele, issi); } void TTWorker::sendSanitationReport(uint32_t eqId, uint32_t issi) { m_toogle = false; return; //NOTE: Will never be executed TrainingAreaBase::TetraIcd::SanitaryMaterialStockReport tele; tele.header.equipmentNumber = eqId; tele.header.timeStamp = time(nullptr) * 1000; int matCount = 14; tele.sanitaryMaterialCount = matCount; std::vector mat; mat.reserve(matCount); for (int i = 1; i <= matCount; i++) mat.emplace_back(i); tele.sanitaryMaterialStock = mat; sendTelegram(tele, issi); } // void TTWorker::sendSanitation(uint32_t eqId, uint32_t issi) // { // m_toogle = true; // return; //NOTE: Will never be executed // TrainingAreaBase::TetraIcd::Sanitation tele; // tele.header.equipmentNumber = eqId; // tele.header.timeStamp = time(nullptr) * 1000; // tele.proceduresTaken = 1117; // tele.uniqeId = 2777777; // tele.originatorEquipmentNumber = 1001; // tele.qualification = TrainingAreaBase::TetraIcd::Qualification::FAA; // tele.sanitationResult = TrainingAreaBase::TetraIcd::SanitationResult::Needed; // sendTelegram(tele, issi); // } void TTWorker::sendBITE(uint32_t eqId, uint32_t issi) { TrainingAreaBase::TetraIcd::BiteReport tele; tele.header.equipmentNumber = eqId; tele.header.timeStamp = time(nullptr) * 1000; tele.loginType = TrainingAreaBase::TetraIcd::BiteReport::LoginType::Relogin; tele.configError = false; sendTelegram(tele, issi); sendTaktischerStatus(eqId, issi, TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady); // rebirth for old Players, who are still dead } void TTWorker::handleDataIndReq(const QByteArray &data) { QScopedPointer radioTelegram(new N_CoPrtCnv::CoPrtCnvRadioTelegram(data)); int telID = radioTelegram->getTelID(); // get the Telegram ID, to switch through it switch (telID) { #if 0 TODO case GEF_AUSLOESUNG_DUS_TREFFER: // player hit! send a taktischer status that we are dead { /* TODO: only receive damage, do not die instantly - rt_data unused */ DEBUG_LOG(mLogger) << "handleAusloeserDUSTreffer: eqId=" << radioTelegram->getIdentity() << " issi=" << radioTelegram->getDestISSI(); XDR_Wrapper_it *wrapper = nullptr; if (!N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(wrapper, radioTelegram.data())) if (!wrapper) return; const ausloesung_dus_treffer_rt &rt_data = static_cast(wrapper)->get_rt(); if (rt_data.bek_wirkung > 90) sendTaktischerStatus(radioTelegram->getIdentity(), radioTelegram->getDestISSI(), TOTALAUSFALL); // kill Player else sendTaktischerStatus(radioTelegram->getIdentity(), radioTelegram->getDestISSI(), ANNAEHENDER_TREFFER); delete wrapper; return; } #endif case GEF_TAKTISCHER_STATUS: // just resend this one to answer the station's question { N_CoPrtCnv::CoPrtCnvCentralTelegram *tele = N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(radioTelegram.data()); TrainingAreaBase::TetraIcd::StateChange sc = TrainingAreaBase::TetraIcd::StateChange::fromJson(tele->jsonData()); delete tele; DEBUG_LOG(m_logger) << " Try to Resetnd State " << sc.header.equipmentNumber << " we got state: " << static_cast(sc.vulnerabilityState) << " and this bits here: " << sc.vulnerabilityBits; sc.header.timeStamp = time(nullptr) * 1000; uint32_t issi = 0; for (int i = 0; i < m_playerList.count(); i++) // get issi from player's eqId { if (radioTelegram->getIdentity() == m_playerList.at(i)->eqId) { issi = m_playerList.at(i)->issi; break; } } ERROR_LOG(m_logger) << " Try to Resetnd S2tate " << sc.header.equipmentNumber << " we got state: " << static_cast(sc.vulnerabilityState) << " and this bits here: " << sc.vulnerabilityBits; sendTelegram(sc, issi); // resend return; } case GEF_SANITAETSDIENST_INSTANDSETZUNG_PVSAN: { N_CoPrtCnv::CoPrtCnvCentralTelegram *tele = N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(radioTelegram.data()); TrainingAreaBase::TetraIcd::Sanitation sc = TrainingAreaBase::TetraIcd::Sanitation::fromJson(tele->jsonData()); delete tele; DEBUG_LOG(m_logger) << " Try to Resetnd State " << sc.header.equipmentNumber << " we got procedure: " << sc.proceduresTaken; sc.header.timeStamp = time(nullptr) * 1000; uint32_t issi = 0; for (int i = 0; i < m_playerList.count(); i++) // get issi from player's eqId { if (radioTelegram->getIdentity() == m_playerList.at(i)->eqId) { issi = m_playerList.at(i)->issi; break; } } ERROR_LOG(m_logger) << " Try to Resetnd S2tate " << sc.header.equipmentNumber << " we got state: " << sc.proceduresTaken; sendTelegram(sc, issi); // resend return; } case GEF_TREFFER_AUSLOESUNG: // we have got a new status (f.g. wounded lying) and send back our new status case GEF_INIT: // ?? .. or just act like this is a treffer ausloesung ....... ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ { TrainingAreaBase::TetraIcd::StateChange tele; uint32_t issi = 0; for (int i = 0; i < m_playerList.count(); i++) // get issi from player's eqId { if (radioTelegram->getIdentity() == m_playerList.at(i)->eqId) { issi = m_playerList.at(i)->issi; break; } } TrainingAreaBase::TetraIcd::VulnerabilityState state = (telID == GEF_TREFFER_AUSLOESUNG) ? static_cast(radioTelegram->getPayloadDataUInt8(7)) : TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady; //get vbg from radio tele.originatorType = TrainingAreaBase::TetraIcd::OriginatorType::Initialisation; //set origin tele.header.equipmentNumber = radioTelegram->getIdentity(); //set header tele.header.timeStamp = time(nullptr) * 1000; uint32_t vulcomplete = radioTelegram->getPayloadDataUInt32(8, 2); uint32_t vitality = vulcomplete &= 0xF000; vitality >>= 12; tele.tasVulnerabilityKindId = vulcomplete &= 0x0FFF; //including vitality tele.tasVulnerabilityKindId <<= 16; tele.tasVulnerabilityKindId |= 0xB1; tele.tasVitality = (vitality - 1) * 10; if (tele.tasVitality < 0) tele.tasVitality = 100; if (state == TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady && vitality > 0) tele.vulnerabilityState = TrainingAreaBase::TetraIcd::VulnerabilityState::MediumDamage; else tele.vulnerabilityState = state; sendTelegram(tele, issi); // send new status return; } // case GEF_NLOS_DATENVERKEHR_TDS_GEF: // { // ERROR_LOG(m_logger) << "NlosTargetData empfangen"; // N_CoPrtCnv::CoPrtCnvCentralTelegram *tele = N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToCentral(radioTelegram.data()); // TrainingAreaBase::TetraIcd::NlosTargetData sc = TrainingAreaBase::TetraIcd::NlosTargetData::fromJson(tele->jsonData()); // delete tele; // QJsonDocument doc(sc.toJson()); // ERROR_LOG(m_logger) << "Receive NlosTargetData Size: " << radioTelegram.data()->getSize() << "\n Structure: " << doc.toJson(QJsonDocument::Indented); // return; // } } // miscellaneous messages.. if (radioTelegram->isLoginTelegram()) { // fixme: login accepted ? DEBUG_LOG(m_logger) << "player cont: " << m_playerList.count(); for (int i = 0; i < m_playerList.count(); i++) // set player isLogin true { Player *p = m_playerList.at(i); if (radioTelegram->getDestISSI() == p->issi) // is this the player we look for? { if (p->isLogin) return; DEBUG_LOG(m_logger) << "Player #" << i << " with eqId=" << p->eqId << " and issi=" << p->issi << " is now logged in."; p->isLogin = true; sendBITE(p->eqId, p->issi); // send BITE message to log us in, though return; } } // player not found ERROR_LOG(m_logger) << "Invalid player was logged in. issi: '" << radioTelegram->getDestISSI() << "'"; return; } // none of our swicthes & conditions wanted this received message! we have got a unused or invalid message.. throw it away and give, at least, a DEBUG message DEBUG_LOG(m_logger) << "Received unused or invalid telegram with Telegram-ID: " << telID; } static void fillHeader(char *data, int len) { N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader *hdr = (N_CoPrtCnv::CoPrtCnvRadioTelegram::PrtCnvRadioGwHeader *)data; hdr->m_MagicNumber = N_CoPrtCnv::CoPrtCnvRadioTelegram::MAGIC_NUMBER; hdr->m_Counter = 0; hdr->m_Length = len; } void TTWorker::handleRegisterInd() { m_counter = 1; QByteArray buf; buf.resize(6); fillHeader(buf.data(), 2); buf[4] = N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp; buf[5] = N_CoPrtCnv::CoPrtCnvRadioTelegram::e_IssiSuccessfulRegistered; m_socket->write(buf); //mTimer->start(1000); } void TTWorker::movePlayer(Player *p) // move the player like the pattern says { // use all variables from the Player POINTER (do not use new instances) if (p->patternInList > m_patternList.count() - 1) // if patternInList is HIGHER than the list-count is, then jump back to position 0 to start again p->patternInList = 0; // set to list-start else { if (p->stepInPattern > m_patternList.at(p->patternInList).steps) // if we have less steps than the stepInPattern says, then we have obsolved all wnted steps, so we can jump to the new pattern in the List { p->stepInPattern = 1; // reset steps for the new pattern if (p->patternInList == m_patternList.count() - 1) // if there is NOT a next pattern, then reset pattern counter to 0 p->patternInList = 0; else p->patternInList++; // jump to next pattern IF there is a next pattern } } p->posUTM.setX(p->posUTM.x() + m_patternList.at(p->patternInList).northering); // increase northering as the pattern says p->posUTM.setY(p->posUTM.y() + m_patternList.at(p->patternInList).ethering); // ^^^^^^^^ ethering ^^^^^^^^^^^^^^^^^^^ p->stepInPattern++; // increase the step counter before we leave, so the player can be moved the next time!! } void TTWorker::onSendPlayerPositions() { // return; qint64 bytesSent = 0; int playerCount = 0; TrainingAreaBase::TetraIcd::PositionReport tele; for (int i = 0; i < m_playerList.count(); i++) { Player *p = m_playerList.at(i); if (!p->isLogin) // do not send position data if one player is not logged in { INFO_LOG(m_logger) << "Player with eqId=" << p->eqId << " and issi=" << p->issi << " is not logged in."; break; } playerCount++; // respawn : if (p->vbg != TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady && p->isEndOfTicks()) // only count to zero (isEndOfTicks = are the ticks running out ?) for respawn, if Player is NOT alive! sendTaktischerStatus(p->eqId, p->issi, TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady); // only give rebirth, do not kill //(unsigned short)!p->isAlive); // kill Player if he is alive, give rebirth to Player if he is dead tele.header.equipmentNumber = p->eqId; if (m_toogle) sendSanitationReport(p->eqId, p->issi); // else // sendSanitation(p->eqId, p->issi); movePlayer(p); // move players tele.relPosition.offsetY = p->posUTM.y(); tele.relPosition.offsetX = p->posUTM.x(); tele.header.timeStamp = time(nullptr) * 1000; N_CoPrtCnv::CoPrtCnvCentralTelegram ct(tele); N_CoPrtCnv::CoPrtCnvRadioTelegram *tel = N_CoPrtCnv::CoPrtCnvTelegramConverter::convertToRadio(&ct); tel->setZaehler(m_counter++); tel->setDestISSI(m_ttsArgs.destIssi); tel->setSrcISSI(p->issi); m_socket->write(tel->data()); bytesSent += tel->getPayloadSize(); delete tel; } bool bFlushed = m_socket->flush(); INFO_LOG(m_logger) << "Sent " << bytesSent << "bytes (" << playerCount << " players), bFlushed=" << bFlushed; } void TTWorker::onSocketError() { if (m_socket) m_socket->disconnectFromHost(); }