void Pony::respawn() { health = maxHealth; sendLoadSceneRPC(owner, sceneName); dead = false; }
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); } } } } }
// Processes the commands entered directly in the server, not the chat messages void Widget::sendCmdLine() { if (!enableGameServer) { logMessage(QObject::tr("This is not a game server, commands are disabled")); return; } QString str = ui->cmdLine->text(); if (str == "clear") { ui->log->clear(); return; } else if (str == "stop") { delete this; return; } else if (str == "listTcpPlayers") { for (int i=0; i<tcpPlayers.size(); i++) { Player* p = tcpPlayers[i]; logMessage(p->name+" "+p->IP+":"+QString().setNum(p->port)); } return; } else if (str.startsWith("setPeer")) { if (udpPlayers.size() == 1) { cmdPeer = udpPlayers[0]; QString peerName = cmdPeer->IP + " " + QString().setNum(cmdPeer->port); logMessage(QObject::tr("UDP: Peer set to %1").arg(peerName)); return; } str = str.right(str.size()-8); QStringList args = str.split(':'); bool ok; if (args.size() != 2) { if (args.size() != 1) { logMessage(QObject::tr("UDP: setPeer takes a pony id or ip:port combination")); return; } quint16 id = args[0].toUInt(&ok); if (!ok) { logMessage(QObject::tr("UDP: setPeer takes a pony id as argument")); return; } for (int i=0; i<udpPlayers.size();i++) { if (udpPlayers[i]->pony.id == id) { cmdPeer = Player::findPlayer(udpPlayers,udpPlayers[i]->IP, udpPlayers[i]->port); logMessage(QObject::tr("UDP: Peer set to %1").arg(udpPlayers[i]->pony.name)); return; } } logMessage(QObject::tr("UDP: Peer not found (id %1)").arg(args[0])); return; } quint16 port = args[1].toUInt(&ok); if (!ok) { logMessage(QObject::tr("UDP: setPeer takes a port as argument")); return; } cmdPeer = Player::findPlayer(udpPlayers,args[0], port); if (cmdPeer->IP!="") logMessage(QObject::tr("UDP: Peer set to %1").arg(str)); else logMessage(QObject::tr("UDP: Peer not found (%1)").arg(str)); return; } else if (str.startsWith("listPeers")) { if (str.size()<=10) { for (int i=0; i<win.udpPlayers.size();i++) win.logMessage(QString().setNum(win.udpPlayers[i]->pony.id) +" ("+QString().setNum(win.udpPlayers[i]->pony.netviewId)+")" +" "+win.udpPlayers[i]->pony.name +" "+win.udpPlayers[i]->IP +":"+QString().setNum(win.udpPlayers[i]->port) +" "+QString().setNum((int)timestampNow()-win.udpPlayers[i]->lastPingTime)+"s"); return; } str = str.right(str.size()-10); Scene* scene = findScene(str); if (scene->name.isEmpty()) win.logMessage(QObject::tr("Can't find scene")); else for (int i=0; i<scene->players.size();i++) win.logMessage(win.udpPlayers[i]->IP +":"+QString().setNum(win.udpPlayers[i]->port) +" "+QString().setNum((int)timestampNow()-win.udpPlayers[i]->lastPingTime)+"s"); return; } else if (str.startsWith("listVortexes")) { for (int i=0; i<scenes.size(); i++) { win.logMessage("Scene "+scenes[i].name); for (int j=0; j<scenes[i].vortexes.size(); j++) win.logMessage("Vortex "+QString().setNum(scenes[i].vortexes[j].id) +" to "+scenes[i].vortexes[j].destName+" " +QString().setNum(scenes[i].vortexes[j].destPos.x)+" " +QString().setNum(scenes[i].vortexes[j].destPos.y)+" " +QString().setNum(scenes[i].vortexes[j].destPos.z)); } return; } else if (str.startsWith("sync")) { win.logMessage(QObject::tr("UDP: Syncing manually")); sync.doSync(); return; } // DEBUG global commands from now on else if (str==("dbgStressLoad")) { // Send all the players to the GemMines at the same time for (int i=0; i<udpPlayers.size(); i++) sendLoadSceneRPC(udpPlayers[i], "GemMines"); return; } else if (str.startsWith("dbgStressLoad")) { str = str.mid(14); // Send all the players to the given scene at the same time for (int i=0; i<udpPlayers.size(); i++) sendLoadSceneRPC(udpPlayers[i], str); return; } else if (str.startsWith("tele")) { str = str.right(str.size()-5); QStringList args = str.split(' '); if (args.size() != 2) { logStatusMessage(QObject::tr("Error: Usage is tele ponyIdToMove destinationPonyId")); return; } bool ok; bool ok1; bool ok2 = false; quint16 sourceID = args[0].toUInt(&ok); quint16 destID = args[1].toUInt(&ok1); Player* sourcePeer; if (!ok && !ok1) { logStatusMessage(QObject::tr("Error: Usage is tele ponyIdToMove destinationPonyId")); return; } for (int i=0; i<udpPlayers.size();i++) { if (udpPlayers[i]->pony.id == sourceID) { sourcePeer = udpPlayers[i]; ok2 = true; break; } } if (!ok2) { logStatusMessage(QObject::tr("Error: Source peer does not exist!")); return; } for (int i=0; i<udpPlayers.size();i++) { if (udpPlayers[i]->pony.id == destID) { logMessage(QObject::tr("UDP: Teleported %1 to %2").arg(sourcePeer->pony.name,udpPlayers[i]->pony.name)); if (udpPlayers[i]->pony.sceneName.toLower() != sourcePeer->pony.sceneName.toLower()) sendLoadSceneRPC(sourcePeer, udpPlayers[i]->pony.sceneName, udpPlayers[i]->pony.pos); else sendMove(sourcePeer, udpPlayers[i]->pony.pos.x, udpPlayers[i]->pony.pos.y, udpPlayers[i]->pony.pos.z); return; } } logMessage(QObject::tr("Error: Destination peer does not exist!")); } if (cmdPeer->IP=="") { logMessage(QObject::tr("Select a peer first with setPeer/listPeers")); return; } else // Refresh peer info { cmdPeer = Player::findPlayer(udpPlayers,cmdPeer->IP, cmdPeer->port); if (cmdPeer->IP=="") { logMessage(QObject::tr("UDP: Peer not found")); return; } } // User commands from now on (requires setPeer) if (str.startsWith("disconnect")) { logMessage(QObject::tr("UDP: Disconnecting")); sendMessage(cmdPeer,MsgDisconnect, "Connection closed by the server admin"); Player::disconnectPlayerCleanup(cmdPeer); // Save game and remove the player } else if (str.startsWith("load")) { str = str.mid(5); sendLoadSceneRPC(cmdPeer, str); } else if (str.startsWith("getPos")) { logMessage(QObject::tr("Pos : ","Short for position") + QString().setNum(cmdPeer->pony.pos.x) + " " + QString().setNum(cmdPeer->pony.pos.y) + " " + QString().setNum(cmdPeer->pony.pos.z)); } else if (str.startsWith("getRot")) { logMessage(QObject::tr("Rot : x=","Short for rotation") + QString().setNum(cmdPeer->pony.rot.x) + ", y=" + QString().setNum(cmdPeer->pony.rot.y) + ", z=" + QString().setNum(cmdPeer->pony.rot.z) + ", w=" + QString().setNum(cmdPeer->pony.rot.w)); } else if (str.startsWith("getPonyData")) { logMessage("ponyData : "+cmdPeer->pony.ponyData.toBase64()); } else if (str.startsWith("sendPonies")) { sendPonies(cmdPeer); } else if (str.startsWith("sendUtils3")) { logMessage(QObject::tr("UDP: Sending Utils3 request")); QByteArray data(1,3); sendMessage(cmdPeer,MsgUserReliableOrdered6,data); } else if (str.startsWith("setPlayerId")) { str = str.right(str.size()-12); QByteArray data(3,4); bool ok; unsigned id = str.toUInt(&ok); if (ok) { logMessage(QObject::tr("UDP: Sending setPlayerId request")); data[1]=(quint8)(id&0xFF); data[2]=(quint8)((id >> 8)&0xFF); sendMessage(cmdPeer,MsgUserReliableOrdered6,data); } else
void receiveChatMessage(QByteArray msg, Player* player) { QString txt = dataToString(msg.mid(7)); QString author = player->pony.name; //win.logMessage("Chat "+author+":"+txt); if (txt.startsWith("/stuck") || txt.startsWith("unstuck me")) { sendLoadSceneRPC(player, player->pony.sceneName); } 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<win.udpPlayers.size(); i++) { if (win.udpPlayers[i]->inGame>=2 && win.udpPlayers[i]->pony.name.toLower().remove(" ").startsWith(txt.toLower().section(" ", 1, 1))) { txt = txt.remove(0, txt.indexOf(" ", 5) + 1); sendChatMessage(win.udpPlayers[i], "<span color=\"yellow\">[PM] </span>" + txt, author, ChatLocal); sendChatMessage(player, "<span color=\"yellow\">[PM to " + win.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<win.udpPlayers.size(); i++) if (win.udpPlayers[i]->inGame>=2) namesmsg += "<br />#b" + win.udpPlayers[i]->pony.name + "#b<br /><span color=\"yellow\"> - in " + win.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<win.scenes.size(); i++) msgtosend += "<br />" + win.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()) win.logMessage("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<win.udpPlayers.size(); i++) { if (win.udpPlayers[i]->inGame>=2) { if (rollnum > -1) sendChatMessage(win.udpPlayers[i], rollstr, "[Server]", ChatGeneral); else if (actmsg) sendChatMessage(win.udpPlayers[i], txt, "", ChatGeneral); else if (txt.startsWith(">")) sendChatMessage(win.udpPlayers[i], "<span color=\"green\">" + txt + "</span>", author, ChatGeneral); else sendChatMessage(win.udpPlayers[i], txt, author, ChatGeneral); } } } } }