void Pony::saveInventory() { win.logMessage("UDP: Saving inventory for "+QString().setNum(netviewId)+" ("+owner->name+")", udpTag); QDir playerPath(QDir::currentPath()); playerPath.cd("data"); playerPath.cd("players"); playerPath.mkdir(owner->name.toLatin1()); QFile file(QDir::currentPath()+"/data/players/"+owner->name.toLatin1()+"/inventory.dat"); if (!file.open(QIODevice::ReadWrite)) { win.logMessage("Error saving inventory for "+QString().setNum(netviewId)+" ("+owner->name+")", sysTag); return; } QByteArray invData = file.readAll(); // Try to find an existing entry for this pony, if found delete it. Then go at the end. for (int i=0; i<invData.size();) { // Read the name QString entryName = dataToString(invData.mid(i)); int nameSize = entryName.size()+getVUint32Size(invData.mid(i)); //win.logMessage("saveInventory : Reading entry "+entryName); quint8 invSize = invData[i+nameSize+4]; quint8 wornSize = invData[i+nameSize+4+1+invSize*9]; // Serialized sizeof InventoryItem is 9 if (entryName == this->name) // Delete the entry, we'll rewrite it at the end { invData.remove(i,nameSize+4+1+invSize*9+1+wornSize*5); break; } else // Skip this entry i += nameSize+4+1+invSize*9+1+wornSize*5; } // Now add our data at the end of the file QByteArray newEntry = stringToData(this->name); newEntry += uint32ToData(nBits); newEntry += uint8ToData(inv.size()); for (const InventoryItem& item : inv) { newEntry += uint8ToData(item.index); newEntry += uint32ToData(item.id); newEntry += uint32ToData(item.amount); } newEntry += uint8ToData(worn.size()); for (const WearableItem& item : worn) { newEntry += uint8ToData(item.index); newEntry += uint32ToData(item.id); } invData += newEntry; file.resize(0); file.write(invData); file.close(); }
void Pony::loadQuests() { win.logMessage("UDP: Loading quests for "+QString().setNum(netviewId)+" ("+owner->name+")", udpTag); QDir playerPath(QDir::currentPath()); playerPath.cd("data"); playerPath.cd("players"); playerPath.mkdir(owner->name.toLatin1()); QFile file(QDir::currentPath()+"/data/players/"+owner->name.toLatin1()+"/quests.dat"); if (!file.open(QIODevice::ReadOnly)) { win.logMessage("Error loading quests for "+QString().setNum(netviewId)+" ("+owner->name+")", sysTag); return; } QByteArray questData = file.readAll(); file.close(); // Try to find an existing entry for this pony and load it. for (int i=0; i<questData.size();) { // Read the name QString entryName = dataToString(questData.mid(i)); int nameSize = entryName.size()+getVUint32Size(questData.mid(i)); i+=nameSize; //win.logMessage("loadQuests : Reading entry "+entryName); quint16 nquests = dataToUint16(questData.mid(i)); i+=2; if (entryName == this->name) // Read the entry { for (int j=0; j<nquests; j++) { quint16 questId = dataToUint16(questData.mid(i)); quint16 questState = dataToUint16(questData.mid(i+2)); i+=4; for (Quest& quest : quests) { if (quest.id == questId) { quest.state = questState; break; } } } return; } else i += nquests * 4; } }
void Pony::saveQuests() { win.logMessage("UDP: Saving quests for "+QString().setNum(netviewId)+" ("+owner->name+")", udpTag); QDir playerPath(QDir::currentPath()); playerPath.cd("data"); playerPath.cd("players"); playerPath.mkdir(owner->name.toLatin1()); QFile file(QDir::currentPath()+"/data/players/"+owner->name.toLatin1()+"/quests.dat"); if (!file.open(QIODevice::ReadWrite)) { win.logMessage("Error saving quests for "+QString().setNum(netviewId)+" ("+owner->name+")", udpTag); return; } QByteArray questData = file.readAll(); // Try to find an existing entry for this pony, if found delete it. Then go at the end. for (int i=0; i<questData.size();) { // Read the name QString entryName = dataToString(questData.mid(i)); int nameSize = entryName.size()+getVUint32Size(questData.mid(i)); //win.logMessage("saveQuests : Reading entry "+entryName); quint16 entryDataSize = 4 * dataToUint16(questData.mid(i+nameSize)); if (entryName == this->name) // Delete the entry, we'll rewrite it at the end { questData.remove(i,nameSize+entryDataSize+2); break; } else i += nameSize+entryDataSize+2; } // Now add our data at the end of the file QByteArray newEntry = stringToData(this->name); newEntry += (quint8)(quests.size() & 0xFF); newEntry += (quint8)((quests.size() >> 8) & 0xFF); for (const Quest& quest : quests) { newEntry += (quint8)(quest.id & 0xFF); newEntry += (quint8)((quest.id >> 8) & 0xFF); newEntry += (quint8)(quest.state & 0xFF); newEntry += (quint8)((quest.state >> 8) & 0xFF); } questData += newEntry; file.resize(0); file.write(questData); file.close(); }
void Widget::udpProcessPendingDatagrams() { while (udpSocket->hasPendingDatagrams()) { QHostAddress rAddr; quint16 rPort; QByteArray datagram; qint64 dataRead = 0; int datagramSize = udpSocket->pendingDatagramSize(); datagram.resize(datagramSize); while(dataRead < datagram.size()) { qint64 readNow = udpSocket->readDatagram(datagram.data()+dataRead, datagramSize, &rAddr, &rPort); // le +dataRead sur un tableau, ça décale le pointeur d'un offset de taille dataRead ! if(readNow != -1) { dataRead += readNow; // Remember the total number of bytes read, so we know when to stop if (datagramSize > (datagram.size() - dataRead)) // Make sure we don't overflow datagramSize = (datagram.size() - dataRead); } else { logStatusMessage(QString("Socket error : ").arg(udpSocket->errorString())); return; } } // Add player on connection if ((unsigned char)datagram[0]==MsgConnect && (unsigned char)datagram[1]==0 && (unsigned char)datagram[2]==0 && datagram.size()>=22) { QString name = dataToString(datagram.right(datagram.size()-22)); int nameFullSize = getVUint32Size(datagram.right(datagram.size()-22))+name.size(); QString sesskey = dataToString(datagram.right(datagram.size()-22-nameFullSize)); //logMessage(QString("UDP: Connect detected with name : ")+name); //logMessage(QString("UDP: Connect detected with sesskey : ")+sesskey); //logMessage(QString("UDP: Datagram was : ")+datagram.toHex()); bool is_sesskey_valid = true; if (enableSessKeyValidation) { is_sesskey_valid = QCryptographicHash::hash(QString(sesskey.right(40) + saltPassword).toLatin1(), QCryptographicHash::Md5).toHex() == sesskey.left(32); } if (is_sesskey_valid) { //logMessage("Sesskey token accepted"); // Create new player if needed, else just update player Player* newPlayer = Player::findPlayer(udpPlayers, rAddr.toString(),rPort); if (newPlayer->IP != rAddr.toString()) // IP:Port not found in player list { newPlayer->resetNetwork(); //newPlayer->connected = true; // Not really connected until we finish the handshake newPlayer->name = name; newPlayer->IP = rAddr.toString(); newPlayer->port = rPort; // Check if we have too many players connected int n=0; for (int i=0;i<udpPlayers.size();i++) if (udpPlayers[i]->connected) n++; if (n>=maxConnected) { sendMessage(newPlayer, MsgDisconnect, "Error : Too many players connected. Try again later."); } else // If not add the player udpPlayers << newPlayer; } else // IP:Port found in player list { if (newPlayer->connected) // TODO: Error, player already connected { sendMessage(newPlayer, MsgDisconnect, "Error : Player already connected."); return; } // Check if we have too many players connected int n=0; for (int i=0;i<udpPlayers.size();i++) if (udpPlayers[i]->connected) n++; if (n>=maxConnected) { sendMessage(newPlayer, MsgDisconnect, "Error : Too many players connected. Try again later."); } newPlayer->resetNetwork(); newPlayer->name = name; newPlayer->IP = rAddr.toString(); newPlayer->port = rPort; //newPlayer->connected = true; // We're not really connected until we finish the handshake } } else { QString badHash = QCryptographicHash::hash((QString(sesskey.right(40)) +saltPassword).toLatin1(), QCryptographicHash::Md5).toHex(); logMessage("UDP: Sesskey rejected: got '"+badHash+"' instead of '"+sesskey.left(32) +"', passhash was '"+QString(sesskey.right(40))); Player* newPlayer = new Player; newPlayer->IP = rAddr.toString(); newPlayer->port = rPort; sendMessage(newPlayer, MsgDisconnect, "Error : Wrong sesskey hash."); return; } } Player* player = Player::findPlayer(udpPlayers, rAddr.toString(), rPort); if (player->IP == rAddr.toString() && player->port == rPort) { // Acquire datas player->receivedDatas->append(datagram); // Process data receiveMessage(player); } else // You need to connect with TCP first { logMessage("UDP: Request from unknown peer rejected : "+rAddr.toString()+":"+QString().setNum(rPort)); // Send disconnect message manually QString data("You're not connected, please login first. (aka the server has no idea who the hell you are)"); QByteArray msg(6,0); msg[0] = MsgDisconnect; msg[3] = (quint8)(((data.size()+1)*8)&0xFF); msg[4] = (quint8)((((data.size()+1)*8)>>8)&0xFF); msg[5] = (quint8)data.size(); msg += data; win.udpSocket->writeDatagram(msg,rAddr,rPort); } } }
bool Pony::loadInventory() { win.logMsg(QObject::tr("%1 UDP: Loading Inventory for %2 (%3)").arg(LOG_INFO).arg(QString().setNum(netviewId)).arg(owner->name)); QDir playerPath(QDir::currentPath()); playerPath.cd("data"); playerPath.cd("players"); playerPath.mkdir(owner->name.toLatin1()); QFile file(QDir::currentPath()+"/data/players/"+owner->name.toLatin1()+"/inventory.lpd"); if (!file.open(QIODevice::ReadOnly)) { win.logMsg(QObject::tr("%1 UDP: Error Loading Inventory for %2 (%3)").arg(LOG_SEVERE).arg(QString().setNum(netviewId)).arg(owner->name)); return false; } QByteArray invData = file.readAll(); file.close(); // Try to find an existing entry for this pony, if found load it. for (int i=0; i<invData.size();) { // Read the name QString entryName = dataToString(invData.mid(i)); int nameSize = entryName.size()+getVUint32Size(invData.mid(i)); //win.logMessage("loadInventory : Reading entry "+entryName); quint8 invSize = invData[i+nameSize+4]; quint8 wornSize = invData[i+nameSize+4+1+invSize*9]; // Serialized sizeof InventoryItem is 9 if (entryName == this->name) { i += nameSize; nBits = dataToUint32(invData.mid(i)); i+=5; // Skip nBits and invSize inv.clear(); for (int j=0; j<invSize; j++) { InventoryItem item; item.index = invData[i]; i++; item.id = dataToUint32(invData.mid(i)); i+=4; item.amount = dataToUint32(invData.mid(i)); i+=4; inv.append(item); } i++; // Skip wornSize wornItm.clear(); wornSlots = 0; for (int j=0; j<wornSize; j++) { WearableItem item; item.index = invData[i]; i++; item.id = dataToUint32(invData.mid(i)); i+=4; wornItm.append(item); wornSlots |= loe.wearablePositionsMap[item.id]; } return true; } else // Skip this entry i += nameSize+4+1+invSize*9+1+wornSize*5; } return false; // Entry not found }
void Widget::udpProcessPendingDatagrams() { while (udpSocket->hasPendingDatagrams()) { QHostAddress rAddr; quint16 rPort; QByteArray datagram; qint64 dataRead = 0; int datagramSize = udpSocket->pendingDatagramSize(); datagram.resize(datagramSize); while(dataRead < datagram.size()) { qint64 readNow = udpSocket->readDatagram(datagram.data()+dataRead, datagramSize, &rAddr, &rPort); // le +dataRead sur un tableau, ça décale le pointeur d'un offset de taille dataRead ! if(readNow != -1) { dataRead += readNow; // Counts the number of bytes read in total, stop when DataRead reached pendingDatagramSize if (datagramSize > (datagram.size() - dataRead)) // Evite de lire après la fin du tableau en mode fragmenté, evite donc que dataSent dépasse datagramSize, sinon Overflow et envoi de données inutiles et aléatoires !! datagramSize = (datagram.size() - dataRead); //QMessageBox::information(NULL,"SenderInfo",QString("DatagramSize : %1 sentNow : %2 dataSent : %3 Sizeof(datagram->data()) : %4").arg(QString().setNum(datagramSize),QString().setNum(sentNow),QString().setNum(dataSent),QString().setNum(datagram->size()))); } else { // Here, we add a message to the udpMessages for filtering later. logStatusMessage(QString("Socket error: ").arg(udpSocket->errorString()), udpTag); return; } } // Add player on connection if ((unsigned char)datagram[0]==MsgConnect && (unsigned char)datagram[1]==0 && (unsigned char)datagram[2]==0 && datagram.size()>=22) { QString name = dataToString(datagram.right(datagram.size()-22)); int nameFullSize = getVUint32Size(datagram.right(datagram.size()-22))+name.size(); QString sesskey = dataToString(datagram.right(datagram.size()-22-nameFullSize)); //logMessage(QString("UDP: Connect detected with name : ")+name, udpTag); //logMessage(QString("UDP: Connect detected with sesskey : ")+sesskey, udpTag); //logMessage(QString("UDP: Datagram was : ")+datagram.toHex(), udpTag); bool is_sesskey_valid = true; if (enableSessKeyValidation) { is_sesskey_valid = QCryptographicHash::hash(QString(sesskey.right(40) + saltPassword).toLatin1(), QCryptographicHash::Md5).toHex() == sesskey.left(32); } if (is_sesskey_valid) { //logMessage("Sesskey token accepted", udpTag); // Create new player if needed, else just update player Player* newPlayer = Player::findPlayer(udpPlayers, rAddr.toString(),rPort); if (newPlayer->IP != rAddr.toString()) // IP:Port not found in player list { newPlayer->resetNetwork(); //newPlayer->connected = true; // Not really connected until we finish the handshake newPlayer->name = name; newPlayer->IP = rAddr.toString(); newPlayer->port = rPort; // Check if we have too many players connected int n=0; for (int i=0;i<udpPlayers.size();i++) if (udpPlayers[i]->connected) n++; if (n>=maxConnected) { sendMessage(newPlayer, MsgDisconnect, "Error: Too many players connected. Try again later."); } else // If not add the player udpPlayers << newPlayer; } else // IP:Port found in player list { if (newPlayer->connected) // TODO: Error, player already connected { sendMessage(newPlayer, MsgDisconnect, "Error: Player already connected."); return; } // Check if we have too many players connected int n=0; for (int i=0;i<udpPlayers.size();i++) if (udpPlayers[i]->connected) n++; if (n>=maxConnected) { sendMessage(newPlayer, MsgDisconnect, "Error: Too many players connected. Try again later."); } newPlayer->resetNetwork(); newPlayer->name = name; newPlayer->IP = rAddr.toString(); newPlayer->port = rPort; //newPlayer->connected = true; // We're not really connected until we finish the handshake } } else { QString badHash = QCryptographicHash::hash((QString(sesskey.right(40)) +saltPassword).toLatin1(), QCryptographicHash::Md5).toHex(); logMessage("UDP: Sesskey rejected: got '"+badHash+"' instead of '"+sesskey.left(32)+"', passhash was '"+QString(sesskey.right(40)), udpTag); Player* newPlayer = new Player; newPlayer->IP = rAddr.toString(); newPlayer->port = rPort; sendMessage(newPlayer, MsgDisconnect, "Error : Wrong sesskey hash."); return; } } Player* player = Player::findPlayer(udpPlayers, rAddr.toString(), rPort); if (player->IP == rAddr.toString() && player->port == rPort) { // Acquire data player->receivedDatas->append(datagram); // Process data receiveMessage(player); } else // You need to connect with TCP first { logMessage("UDP: Request from unknown peer rejected : "+rAddr.toString()+":"+QString().setNum(rPort), udpTag); // Send disconnect message manually, with an appropriate message. QString data("BITCH, YOU ARE EITHER A HACKER OR THE SERVER JUST HATES THE F**K OUT OF YOU. RELOG OR YOU AINT GETTIN ON THIS SERVER, K?"); QByteArray msg(6,0); msg[0] = MsgDisconnect; msg[3] = (quint8)(((data.size()+1)*8)&0xFF); msg[4] = (quint8)((((data.size()+1)*8)>>8)&0xFF); msg[5] = (quint8)data.size(); msg += data; win.udpSocket->writeDatagram(msg,rAddr,rPort); } } }