655 lines
24 KiB
C++
655 lines
24 KiB
C++
/*
|
|
* @RDE_HEADER@
|
|
* Worker for Tetra Simulation
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*/
|
|
|
|
#include "worker.h"
|
|
|
|
#include <QtCore/QTimer>
|
|
#include <QtNetwork/QTcpSocket>
|
|
#include <NGLLogger/NGLLoggerBootstrap.h>
|
|
#include <time.h>
|
|
#include <random>
|
|
#include <iostream>
|
|
#include <QStringList>
|
|
#include <QJsonDocument>
|
|
|
|
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<QAbstractSocket::SocketError>::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<runningPattern> 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<runningPattern> 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<runningPattern>(); // 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<long long> 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<int> 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<N_CoPrtCnv::CoPrtCnvRadioTelegram> 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<XDR_AUSLOESUNG_DUS_TREFFER_Wrapper *>(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<int>(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<int>(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<TrainingAreaBase::TetraIcd::VulnerabilityState>(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();
|
|
}
|