void sendEntitiesList(Player *player) { levelLoadMutex.lock(); // Protect player->inGame if (player->inGame == 0) // Not yet in game, send player's ponies list (Characters scene) { levelLoadMutex.unlock(); #if DEBUG_LOG win.logMessage("UDP: Sending ponies list"); #endif sendPonies(player); return; } else if (player->inGame > 1) // Not supposed to happen, let's do it anyway { //levelLoadMutex.unlock(); win.logMessage(QString("UDP: Entities list already sent to ")+QString().setNum(player->pony.netviewId) +", resending anyway"); //return; } else // Loading finished, sending entities list win.logMessage(QString("UDP: Sending entities list to ")+QString().setNum(player->pony.netviewId)); Scene* scene = findScene(player->pony.sceneName); // Spawn all the players on the client for (int i=0; i<scene->players.size(); i++) sendNetviewInstantiate(&scene->players[i]->pony, player); // Send npcs for (int i=0; i<win.npcs.size(); i++) if (win.npcs[i]->sceneName.toLower() == player->pony.sceneName.toLower()) { #if DEBUG_LOG win.logMessage("UDP: Sending NPC "+win.npcs[i]->name); #endif sendNetviewInstantiate(win.npcs[i], player); } // Spawn some mobs in Zecoras if (scene->name.toLower() == "zecoras") { sendNetviewInstantiate(player,"mobs/dragon", win.getNewId(), win.getNewNetviewId(), {-33.0408, 0.000425577, 101.766}, {0,-1,0,1}); } player->inGame = 2; levelLoadMutex.unlock(); // Send stats of the client's pony sendSetMaxStatRPC(player, 0, 100); sendSetStatRPC(player, 0, 100); sendSetMaxStatRPC(player, 1, 100); sendSetStatRPC(player, 1, 100); }
void sendEntitiesList(Player *player) { levelLoadMutex.lock(); // Protect player->inGame if (player->inGame == 0) // Not yet in game, send player's ponies list (Characters scene) { levelLoadMutex.unlock(); sendPonies(player); return; } else if (player->inGame > 1) // Not supposed to happen, let's do it anyway { //levelLoadMutex.unlock(); win.logMessage(QString("UDP: Entities list already sent to ")+QString().setNum(player->pony.netviewId) +", resending anyway"); //return; } else // Loading finished, sending entities list win.logMessage(QString("UDP: Sending entities list to ")+QString().setNum(player->pony.netviewId)); Scene* scene = findScene(player->pony.sceneName); // Spawn all the players on the client for (int i=0; i<scene->players.size(); i++) sendNetviewInstantiate(scene->players[i], player); /// SEND DONUT STEEL (in front of the mirror) if (scene->name == "RaritysBoutique") { win.logMessage(QString("UDP: Sending Donut Steel to ")+QString().setNum(player->pony.netviewId)); sendNetviewInstantiate(player,"PlayerBase",0,0,UVector(24.7333,-1.16802,-51.7106), UQuaternion(0,-0.25,0,1)); } player->inGame = 2; levelLoadMutex.unlock(); // Send stats of the client's pony sendSetMaxStatRPC(player, 0, 100); sendSetStatRPC(player, 0, 100); sendSetMaxStatRPC(player, 1, 100); sendSetStatRPC(player, 1, 100); }
void Pony::takeDamage(unsigned amount) { if (health <= (float)amount/defense) kill(); else { health -= (float)amount/defense; Scene* scene = findScene(sceneName); for (Player* player : scene->players) { sendSetStatRPC(player, netviewId, 1, health); } } }
void sendPonySave(Player *player, QByteArray msg) { if (player->inGame < 2) // Not supposed to happen, ignoring the request { win.logMessage("UDP: Savegame requested too soon by "+QString().setNum(player->pony.netviewId)); return; } quint16 netviewId = (quint8)msg[6] + ((quint8)msg[7]<<8); Player* refresh = Player::findPlayer(win.udpPlayers, netviewId); if (netviewId == player->pony.netviewId) { if (player->inGame == 3) // Hopefully that'll fix people stuck on the default cam without creating clones { win.logMessage("UDP: Savegame already sent to "+QString().setNum(player->pony.netviewId) +", resending anyway"); } else win.logMessage(QString("UDP: Sending pony save for/to ")+QString().setNum(netviewId)); // Set current/max stats sendSetMaxStatRPC(player, 0, 100); sendSetStatRPC(player, 0, 100); sendSetMaxStatRPC(player, 1, 100); sendSetStatRPC(player, 1, 100); sendPonyData(player); // Set inventory (start with always the same, until we implement it properly) InventoryItem raincloudHat; raincloudHat.id=73; raincloudHat.index=0; InventoryItem goggles; goggles.id=17; goggles.index=1; InventoryItem hat; hat.id=62; hat.index=2; InventoryItem bag; bag.id=60; bag.index=3; player->inv.clear(); player->inv << raincloudHat << goggles << hat << bag; player->worn.clear(); //player->worn << goggles << bag; player->nBits = 15; sendInventoryRPC(player, player->inv, player->worn, player->nBits); // Send skills QList<QPair<quint32, quint32> > skills; skills << QPair<quint32, quint32>(10, 0); // Ground pound if (player->pony.getType() == Pony::EarthPony) skills << QPair<quint32, quint32>(5, 0); // Seismic buck else if (player->pony.getType() == Pony::Pegasus) skills << QPair<quint32, quint32>(11, 0); // Tornado else if (player->pony.getType() == Pony::Unicorn) skills << QPair<quint32, quint32>(2, 0); // Teleport sendSkillsRPC(player, skills); // Set current/max stats again (that's what the official server does, not my idea !) sendSetMaxStatRPC(player, 0, 100); sendSetStatRPC(player, 0, 100); sendSetMaxStatRPC(player, 1, 100); sendSetStatRPC(player, 1, 100); /// SEND DONUT STEEL (he's a moose dark-as-my-soul OC) if (player->pony.sceneName == "RaritysBoutique") { win.logMessage("UDP: Sending pony save for Donut Steel to "+QString().setNum(player->pony.netviewId)); Player donutSteel; donutSteel.pony.id = donutSteel.pony.netviewId = 0; donutSteel.pony.ponyData = QByteArray::fromHex("0b446f6e757420537465656c0402b70000000000000000000000ca1a0017ff00032e03ff050072ff000c000b0000000000cdcc8c3fff9f"); sendPonyData(&donutSteel, player); } refresh->inGame = 3; } else if (!refresh->IP.isEmpty()) { win.logMessage(QString("UDP: Sending pony save for ")+QString().setNum(refresh->pony.netviewId) +" to "+QString().setNum(player->pony.netviewId)); sendWornRPC(refresh, player, refresh->worn); sendSetStatRPC(refresh, player, 0, 100); sendSetMaxStatRPC(refresh, player, 0, 100); sendSetStatRPC(refresh, player, 1, 100); sendSetMaxStatRPC(refresh, player, 1, 100); sendPonyData(refresh, player); if (!refresh->lastValidReceivedAnimation.isEmpty()) sendMessage(player, MsgUserReliableOrdered12, refresh->lastValidReceivedAnimation); } else { win.logMessage("UDP: Error sending pony save : netviewId "+QString().setNum(netviewId)+" not found"); } }
void receiveChatMessage(QByteArray msg, Player* player) { QString txt = dataToString(msg.mid(7)); QString author = player->pony.name; //logMessage("Chat "+author+":"+txt); if (txt.startsWith("/stuck") || txt.startsWith("unstuck me")) { sendLoadSceneRPC(player, player->pony.sceneName); } else if (txt == ":anhero") { QTimer *anheroTimer = new QTimer(); anheroTimer->setSingleShot(true); QString deadPlayerName = player->name; QObject::connect(anheroTimer, &QTimer::timeout, [=]() { // Find player again instead of reusing pointer, in case they disconnect Player* deadPlayer = Player::findPlayer(Player::udpPlayers, deadPlayerName); if (deadPlayer->connected && deadPlayer->pony.dead) { sendSetStatRPC(deadPlayer, 1, deadPlayer->pony.health); Scene* scene = findScene(deadPlayer->pony.sceneName); for (Player* other : scene->players) sendNetviewInstantiate(&deadPlayer->pony, other); deadPlayer->pony.dead = false; } delete anheroTimer; // Don't delete deadPlayer here. That kills the player's session } ); if (!player->pony.dead) { player->pony.dead = true; sendSetStatRPC(player, 1, 0); anheroTimer->start(5000); Scene* scene = findScene(player->pony.sceneName); for (Player* other : scene->players) sendNetviewRemove(other, player->pony.netviewId, NetviewRemoveReasonKill); } } else if (txt == ":commands") { sendChatMessage(player, "<span color=\"yellow\">List of Commands:</span><br /><em>:roll</em><br /><span color=\"yellow\">Rolls a random number between 00 and 99</span><br /><em>:msg player message</em><br /><span color=\"yellow\">Sends a private message to a player</span><br /><em>:names</em><br /><span color=\"yellow\">Lists all players on the server</span><br /><em>:me action</em><br /><span color=\"yellow\">States your current action</span><br /><em>:tp location</em><br /><span color=\"yellow\">Teleports your pony to the specified region</span>", "[Server]", ChatLocal); } else if (txt.startsWith(":msg")) { if(txt.count(" ") < 2) sendChatMessage(player, ":msg<br /><span color=\"yellow\">Usage:</span><br /><em>:msg player message</em><br /><span color=\"yellow\">Player names are case-insensitive, ignore spaces and you do not need to type out their full name.</span>", author, ChatLocal); else { for (int i=0; i<Player::udpPlayers.size(); i++) { if (Player::udpPlayers[i]->inGame>=2 && Player::udpPlayers[i]->pony.name.toLower().remove(" ") .startsWith(txt.toLower().section(" ", 1, 1))) { txt = txt.remove(0, txt.indexOf(" ", 5) + 1); sendChatMessage(Player::udpPlayers[i], "<span color=\"yellow\">[PM] </span>" + txt, author, ChatLocal); sendChatMessage(player, "<span color=\"yellow\">[PM to " + Player::udpPlayers[i]->pony.name + "] </span>" + txt, author, ChatLocal); } } } } else if (txt.startsWith(":names")) { QString namesmsg = "<span color=\"yellow\">Players currently in game:</span>"; for (int i=0; i<Player::udpPlayers.size(); i++) if (Player::udpPlayers[i]->inGame>=2) namesmsg += "<br />#b" + Player::udpPlayers[i]->pony.name + "#b<br /><span color=\"yellow\"> - in " + Player::udpPlayers[i]->pony.sceneName + "</span>"; sendChatMessage(player, namesmsg, "[Server]", ChatLocal); } else if (txt.startsWith(":tp")) { if (txt.count(" ") < 1) { QString msgtosend = ":tp<br /><span color=\"yellow\">Usage:</span><br /><em>:tp location</em><br /><span color=\"yellow\">Available locations:</span><em>"; for (int i=0; i<Scene::scenes.size(); i++) msgtosend += "<br />" + Scene::scenes[i].name; sendChatMessage(player, msgtosend + "</em>", author, ChatLocal); } else sendLoadSceneRPC(player, txt.remove(0, 4)); } else if (txt == ":me") { sendChatMessage(player, ":me<br /><span color=\"yellow\">Usage:</span><br /><em>:me action</em>", author, ChatLocal); } else // Broadcast the message { int rollnum = -1; QString rollstr; bool actmsg = false; if (txt == ":roll") { if (player->chatRollCooldownEnd < QDateTime::currentDateTime()) { rollnum = qrand() % 100; rollstr.sprintf("<span color=\"yellow\">#b%s#b rolls %02d</span>", author.toLocal8Bit().data(), rollnum); player->chatRollCooldownEnd = QDateTime::currentDateTime().addSecs(10); } } if (txt.startsWith(":me ")) { actmsg = true; txt.remove(0, 3); txt = "<em>#b* " + author + "#b" + txt + "</em>"; } if ((quint8)msg[6] == 8) // Local chat only { Scene* scene = findScene(player->pony.sceneName); if (scene->name.isEmpty()) logMessage(QObject::tr("UDP: Can't find the scene for chat message, aborting")); else { for (int i=0; i<scene->players.size(); i++) { if (scene->players[i]->inGame>=2) { if (rollnum > -1) sendChatMessage(scene->players[i], rollstr, "[Server]", ChatLocal); else if (actmsg) sendChatMessage(scene->players[i], txt, "", ChatLocal); else if (txt.startsWith(">")) sendChatMessage(scene->players[i], "<span color=\"green\">" + txt + "</span>", author, ChatLocal); else sendChatMessage(scene->players[i], txt, author, ChatLocal); } } } } else // Send globally { for (int i=0; i<Player::udpPlayers.size(); i++) { if (Player::udpPlayers[i]->inGame>=2) { if (rollnum > -1) sendChatMessage(Player::udpPlayers[i], rollstr, "[Server]", ChatGeneral); else if (actmsg) sendChatMessage(Player::udpPlayers[i], txt, "", ChatGeneral); else if (txt.startsWith(">")) sendChatMessage(Player::udpPlayers[i], "<span color=\"green\">" + txt + "</span>", author, ChatGeneral); else sendChatMessage(Player::udpPlayers[i], txt, author, ChatGeneral); } } } } }
void sendPonySave(Player *player, QByteArray msg) { if (player->inGame < 2) // Not supposed to happen, ignoring the request { win.logMessage("UDP: Savegame requested too soon by "+QString().setNum(player->pony.netviewId)); return; } quint16 netviewId = (quint8)msg[6] + ((quint16)(quint8)msg[7]<<8); Player* refresh = Player::findPlayer(win.udpPlayers, netviewId); // Find players // Find NPC Pony* npc = NULL; for (int i=0; i<win.npcs.size(); i++) if (win.npcs[i]->netviewId == netviewId) npc = win.npcs[i]; // If we found a matching NPC, send him and exits if (npc != NULL) { #if DEBUG_LOG win.logMessage("UDP: Sending ponyData and worn items for NPC "+npc->name); #endif sendPonyData(npc, player); if (npc->inv.size()) // This NPC has a shop { sendAddViewAddShop(player, npc); } return; } if (netviewId == player->pony.netviewId) // Current player { if (player->inGame == 3) // Hopefully that'll fix people stuck on the default cam without creating clones { win.logMessage("UDP: Savegame already sent to "+QString().setNum(player->pony.netviewId) +", resending anyway"); } else win.logMessage(QString("UDP: Sending pony save for/to ")+QString().setNum(netviewId)); // Set current/max stats sendSetMaxStatRPC(player, 0, 100); sendSetStatRPC(player, 0, 100); sendSetMaxStatRPC(player, 1, 100); sendSetStatRPC(player, 1, 100); sendPonyData(player); // Send inventory sendInventoryRPC(player, player->pony.inv, player->pony.worn, player->pony.nBits); // Send skills QList<QPair<quint32, quint32> > skills; skills << QPair<quint32, quint32>(10, 0); // Ground pound (all races) if (player->pony.getType() == Pony::EarthPony) { skills << QPair<quint32, quint32>(5, 0); // Seismic buck skills << QPair<quint32, quint32>(16, 0); // Rough Terrain } else if (player->pony.getType() == Pony::Pegasus) { skills << QPair<quint32, quint32>(11, 0); // Dual Cyclone skills << QPair<quint32, quint32>(14, 0); // Gale } else if (player->pony.getType() == Pony::Unicorn) { skills << QPair<quint32, quint32>(2, 0); // Teleport skills << QPair<quint32, quint32>(9, 0); // Rainbow Fields skills << QPair<quint32, quint32>(12, 0); // Heal skills << QPair<quint32, quint32>(15, 0); // Magical Arrow } sendSkillsRPC(player, skills); // Set current/max stats again (that's what the official server does, not my idea !) sendSetMaxStatRPC(player, 0, 100); sendSetStatRPC(player, 0, 100); sendSetMaxStatRPC(player, 1, 100); sendSetStatRPC(player, 1, 100); refresh->inGame = 3; } else if (!refresh->IP.isEmpty()) { win.logMessage(QString("UDP: Sending pony save for ")+QString().setNum(refresh->pony.netviewId) +" to "+QString().setNum(player->pony.netviewId)); //sendWornRPC(refresh, player, refresh->worn); sendSetStatRPC(refresh, player, 0, 100); sendSetMaxStatRPC(refresh, player, 0, 100); sendSetStatRPC(refresh, player, 1, 100); sendSetMaxStatRPC(refresh, player, 1, 100); sendPonyData(&refresh->pony, player); if (!refresh->lastValidReceivedAnimation.isEmpty()) sendMessage(player, MsgUserReliableOrdered12, refresh->lastValidReceivedAnimation); } else { win.logMessage("UDP: Error sending pony save : netviewId "+QString().setNum(netviewId)+" not found"); } }