[refactor] Refactor groups

This commit is contained in:
gsemaj 2022-04-22 21:13:00 -04:00 committed by gsemaj
parent 4b834579c5
commit 03d28bf4e4
No known key found for this signature in database
GPG Key ID: 24B96BAA40497929
11 changed files with 182 additions and 160 deletions

View File

@ -225,10 +225,6 @@ static void tradeChatHandler(CNSocket* sock, CNPacketData* data) {
static void groupChatHandler(CNSocket* sock, CNPacketData* data) { static void groupChatHandler(CNSocket* sock, CNPacketData* data) {
sP_CL2FE_REQ_SEND_ALL_GROUP_FREECHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_ALL_GROUP_FREECHAT_MESSAGE*)data->buf; sP_CL2FE_REQ_SEND_ALL_GROUP_FREECHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_ALL_GROUP_FREECHAT_MESSAGE*)data->buf;
Player* plr = PlayerManager::getPlayer(sock); Player* plr = PlayerManager::getPlayer(sock);
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
if (otherPlr == nullptr)
return;
std::string fullChat = sanitizeText(AUTOU16TOU8(chat->szFreeChat)); std::string fullChat = sanitizeText(AUTOU16TOU8(chat->szFreeChat));
@ -251,16 +247,15 @@ static void groupChatHandler(CNSocket* sock, CNPacketData* data) {
resp.iSendPCID = plr->iID; resp.iSendPCID = plr->iID;
resp.iEmoteCode = chat->iEmoteCode; resp.iEmoteCode = chat->iEmoteCode;
Groups::sendToGroup(otherPlr, (void*)&resp, P_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC)); if (plr->group == nullptr)
sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC));
else
Groups::sendToGroup(plr->group, (void*)&resp, P_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC));
} }
static void groupMenuChatHandler(CNSocket* sock, CNPacketData* data) { static void groupMenuChatHandler(CNSocket* sock, CNPacketData* data) {
sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE*)data->buf; sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_ALL_GROUP_MENUCHAT_MESSAGE*)data->buf;
Player* plr = PlayerManager::getPlayer(sock); Player* plr = PlayerManager::getPlayer(sock);
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
if (otherPlr == nullptr)
return;
std::string fullChat = sanitizeText(AUTOU16TOU8(chat->szFreeChat)); std::string fullChat = sanitizeText(AUTOU16TOU8(chat->szFreeChat));
std::string logLine = "[GroupMenuChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat; std::string logLine = "[GroupMenuChat] " + PlayerManager::getPlayerName(plr, true) + ": " + fullChat;
@ -275,7 +270,9 @@ static void groupMenuChatHandler(CNSocket* sock, CNPacketData* data) {
resp.iSendPCID = plr->iID; resp.iSendPCID = plr->iID;
resp.iEmoteCode = chat->iEmoteCode; resp.iEmoteCode = chat->iEmoteCode;
Groups::sendToGroup(otherPlr, (void*)&resp, P_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC)); if (plr->group == nullptr)
sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC));
Groups::sendToGroup(plr->group, (void*)&resp, P_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC));
} }
// we only allow plain ascii, at least for now // we only allow plain ascii, at least for now

View File

@ -268,17 +268,10 @@ void Combat::npcAttackPc(Mob *mob, time_t currTime) {
* single RNG roll per mission task, and every group member shares that same * single RNG roll per mission task, and every group member shares that same
* set of rolls. * set of rolls.
*/ */
void Combat::genQItemRolls(Player *leader, std::map<int, int>& rolls) { void Combat::genQItemRolls(std::vector<Player*> players, std::map<int, int>& rolls) {
for (int i = 0; i < leader->groupCnt; i++) { for (int i = 0; i < players.size(); i++) {
if (leader->groupIDs[i] == 0)
continue;
CNSocket *otherSock = PlayerManager::getSockFromID(leader->groupIDs[i]);
if (otherSock == nullptr)
continue;
Player *member = PlayerManager::getPlayer(otherSock);
Player* member = players[i];
for (int j = 0; j < ACTIVE_MISSION_COUNT; j++) for (int j = 0; j < ACTIVE_MISSION_COUNT; j++)
if (member->tasks[j] != 0) if (member->tasks[j] != 0)
rolls[member->tasks[j]] = Rand::rand(); rolls[member->tasks[j]] = Rand::rand();
@ -679,7 +672,7 @@ static void playerTick(CNServer *serv, time_t currTime) {
bool transmit = false; bool transmit = false;
// group ticks // group ticks
if (plr->groupCnt > 1) if (plr->group != nullptr)
Groups::groupTickInfo(plr); Groups::groupTickInfo(plr);
// do not tick dead players // do not tick dead players

View File

@ -25,5 +25,5 @@ namespace Combat {
void init(); void init();
void npcAttackPc(Mob *mob, time_t currTime); void npcAttackPc(Mob *mob, time_t currTime);
void genQItemRolls(Player* leader, std::map<int, int>& rolls); void genQItemRolls(std::vector<Player*> players, std::map<int, int>& rolls);
} }

View File

@ -16,10 +16,9 @@ std::unordered_map<int, EggType> Eggs::EggTypes;
int Eggs::eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration) { int Eggs::eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration) {
Player* plr = PlayerManager::getPlayer(sock); Player* plr = PlayerManager::getPlayer(sock);
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
int bitFlag = Groups::getGroupFlags(otherPlr);
// TODO ABILITIES // TODO ABILITIES
int bitFlag = plr->group->conditionBitFlag;
int CBFlag = 0;// Abilities::applyBuff(sock, skillId, 1, 3, bitFlag); int CBFlag = 0;// Abilities::applyBuff(sock, skillId, 1, 3, bitFlag);
size_t resplen; size_t resplen;
@ -98,9 +97,8 @@ static void eggStep(CNServer* serv, time_t currTime) {
CNSocket* sock = it->first.first; CNSocket* sock = it->first.first;
int32_t CBFlag = it->first.second; int32_t CBFlag = it->first.second;
Player* plr = PlayerManager::getPlayer(sock); Player* plr = PlayerManager::getPlayer(sock);
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
int groupFlags = Groups::getGroupFlags(otherPlr); int groupFlags = plr->group->conditionBitFlag;
// TODO ABILITIES // TODO ABILITIES
//for (auto& pwr : Abilities::Powers) { //for (auto& pwr : Abilities::Powers) {
// if (pwr.bitFlag == CBFlag) { // pick the power with the right flag and unbuff // if (pwr.bitFlag == CBFlag) { // pick the power with the right flag and unbuff

View File

@ -25,6 +25,7 @@ enum class AIState {
}; };
class Chunk; class Chunk;
struct Group;
struct Entity { struct Entity {
EntityKind kind = EntityKind::INVALID; EntityKind kind = EntityKind::INVALID;
@ -130,6 +131,7 @@ struct CombatNPC : public BaseNPC, public ICombatant {
int level = 0; int level = 0;
int speed = 300; int speed = 300;
AIState state = AIState::INACTIVE; AIState state = AIState::INACTIVE;
Group* group = nullptr;
int playersInView = 0; // for optimizing away AI in empty chunks int playersInView = 0; // for optimizing away AI in empty chunks
std::map<AIState, void (*)(CombatNPC*, time_t)> stateHandlers; std::map<AIState, void (*)(CombatNPC*, time_t)> stateHandlers;

View File

@ -19,22 +19,65 @@
using namespace Groups; using namespace Groups;
void Groups::addToGroup(EntityRef member, Group* group) {
if (member.kind == EntityKind::PLAYER) {
Player* plr = PlayerManager::getPlayer(member.sock);
plr->group = group;
}
else if (member.kind == EntityKind::COMBAT_NPC) {
CombatNPC* npc = (CombatNPC*)member.getEntity();
npc->group = group;
}
else {
std::cout << "[WARN] Adding a weird entity type to a group" << std::endl;
}
group->members.push_back(member);
}
void Groups::removeFromGroup(EntityRef member, Group* group) {
if (member.kind == EntityKind::PLAYER) {
Player* plr = PlayerManager::getPlayer(member.sock);
plr->group = nullptr; // no dangling pointers here muahaahahah
}
else if (member.kind == EntityKind::COMBAT_NPC) {
CombatNPC* npc = (CombatNPC*)member.getEntity();
npc->group = nullptr;
}
else {
std::cout << "[WARN] Adding a weird entity type to a group" << std::endl;
}
auto it = std::find(group->members.begin(), group->members.end(), member);
if (it == group->members.end()) {
std::cout << "[WARN] Tried to remove a member that isn't in the group" << std::endl;
return;
}
group->members.erase(it);
if (group->members.empty()) delete group; // cleanup memory
}
void Groups::disbandGroup(Group* group) {
// remove everyone from the group!!
std::vector<EntityRef> members = group->members;
for (EntityRef member : members) {
removeFromGroup(member, group);
}
}
static void requestGroup(CNSocket* sock, CNPacketData* data) { static void requestGroup(CNSocket* sock, CNPacketData* data) {
sP_CL2FE_REQ_PC_GROUP_INVITE* recv = (sP_CL2FE_REQ_PC_GROUP_INVITE*)data->buf; sP_CL2FE_REQ_PC_GROUP_INVITE* recv = (sP_CL2FE_REQ_PC_GROUP_INVITE*)data->buf;
Player* plr = PlayerManager::getPlayer(sock); Player* plr = PlayerManager::getPlayer(sock);
Player* otherPlr = PlayerManager::getPlayerFromID(recv->iID_To); Player* otherPlr = PlayerManager::getPlayerFromID(recv->iID_To);
if (otherPlr == nullptr)
return;
otherPlr = PlayerManager::getPlayerFromID(otherPlr->iIDGroup);
if (otherPlr == nullptr) if (otherPlr == nullptr)
return; return;
// fail if the group is full or the other player is already in a group // fail if the group is full or the other player is already in a group
if (plr->groupCnt >= 4 || otherPlr->iIDGroup != otherPlr->iID || otherPlr->groupCnt > 1) { if ((plr->group != nullptr && (*plr->group)[EntityKind::PLAYER].size() >= 4) || otherPlr->group != nullptr) {
INITSTRUCT(sP_FE2CL_PC_GROUP_INVITE_FAIL, resp); INITSTRUCT(sP_FE2CL_PC_GROUP_INVITE_FAIL, resp);
sock->sendPacket((void*)&resp, P_FE2CL_PC_GROUP_INVITE_FAIL, sizeof(sP_FE2CL_PC_GROUP_INVITE_FAIL)); sock->sendPacket((void*)&resp, P_FE2CL_PC_GROUP_INVITE_FAIL, sizeof(sP_FE2CL_PC_GROUP_INVITE_FAIL));
return; return;
@ -77,28 +120,29 @@ static void joinGroup(CNSocket* sock, CNPacketData* data) {
if (otherPlr == nullptr) if (otherPlr == nullptr)
return; return;
otherPlr = PlayerManager::getPlayerFromID(otherPlr->iIDGroup); int size = otherPlr->group == nullptr ? 1 : (*otherPlr->group)[EntityKind::PLAYER].size();
if (otherPlr == nullptr)
return;
// fail if the group is full or the other player is already in a group // fail if the group is full or the other player is already in a group
if (plr->groupCnt > 1 || plr->iIDGroup != plr->iID || otherPlr->groupCnt >= 4) { if (plr->group != nullptr || size + 1 > 4) {
INITSTRUCT(sP_FE2CL_PC_GROUP_JOIN_FAIL, resp); INITSTRUCT(sP_FE2CL_PC_GROUP_JOIN_FAIL, resp);
sock->sendPacket((void*)&resp, P_FE2CL_PC_GROUP_JOIN_FAIL, sizeof(sP_FE2CL_PC_GROUP_JOIN_FAIL)); sock->sendPacket((void*)&resp, P_FE2CL_PC_GROUP_JOIN_FAIL, sizeof(sP_FE2CL_PC_GROUP_JOIN_FAIL));
return; return;
} }
if (!validOutVarPacket(sizeof(sP_FE2CL_PC_GROUP_JOIN), otherPlr->groupCnt + 1, sizeof(sPCGroupMemberInfo))) { if (!validOutVarPacket(sizeof(sP_FE2CL_PC_GROUP_JOIN), size + 1, sizeof(sPCGroupMemberInfo))) {
std::cout << "[WARN] bad sP_FE2CL_PC_GROUP_JOIN packet size\n"; std::cout << "[WARN] bad sP_FE2CL_PC_GROUP_JOIN packet size\n";
return; return;
} }
plr->iIDGroup = otherPlr->iID; if (otherPlr->group == nullptr) {
otherPlr->groupCnt += 1; // create group
otherPlr->groupIDs[otherPlr->groupCnt-1] = plr->iID; otherPlr->group = new Group(); // spooky
addToGroup(PlayerManager::getSockFromID(recv->iID_From), otherPlr->group);
}
addToGroup(sock, otherPlr->group);
auto players = (*otherPlr->group)[EntityKind::PLAYER];
size_t resplen = sizeof(sP_FE2CL_PC_GROUP_JOIN) + otherPlr->groupCnt * sizeof(sPCGroupMemberInfo); size_t resplen = sizeof(sP_FE2CL_PC_GROUP_JOIN) + players.size() * sizeof(sPCGroupMemberInfo);
uint8_t respbuf[CN_PACKET_BUFFER_SIZE]; uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
memset(respbuf, 0, resplen); memset(respbuf, 0, resplen);
@ -107,13 +151,13 @@ static void joinGroup(CNSocket* sock, CNPacketData* data) {
sPCGroupMemberInfo *respdata = (sPCGroupMemberInfo*)(respbuf+sizeof(sP_FE2CL_PC_GROUP_JOIN)); sPCGroupMemberInfo *respdata = (sPCGroupMemberInfo*)(respbuf+sizeof(sP_FE2CL_PC_GROUP_JOIN));
resp->iID_NewMember = plr->iID; resp->iID_NewMember = plr->iID;
resp->iMemberPCCnt = otherPlr->groupCnt; resp->iMemberPCCnt = players.size();
int bitFlag = getGroupFlags(otherPlr); int bitFlag = otherPlr->group->conditionBitFlag;
for (int i = 0; i < players.size(); i++) {
for (int i = 0; i < otherPlr->groupCnt; i++) { Player* varPlr = PlayerManager::getPlayer(players[i].sock);
Player* varPlr = PlayerManager::getPlayerFromID(otherPlr->groupIDs[i]); CNSocket* sockTo = players[i].sock;
CNSocket* sockTo = PlayerManager::getSockFromID(otherPlr->groupIDs[i]);
if (varPlr == nullptr || sockTo == nullptr) if (varPlr == nullptr || sockTo == nullptr)
continue; continue;
@ -143,37 +187,32 @@ static void joinGroup(CNSocket* sock, CNPacketData* data) {
} }
} }
sendToGroup(otherPlr, (void*)&respbuf, P_FE2CL_PC_GROUP_JOIN, resplen); Groups::sendToGroup(otherPlr->group, (void*)&respbuf, P_FE2CL_PC_GROUP_JOIN, resplen);
} }
static void leaveGroup(CNSocket* sock, CNPacketData* data) { static void leaveGroup(CNSocket* sock, CNPacketData* data) {
Player* plr = PlayerManager::getPlayer(sock); Player* plr = PlayerManager::getPlayer(sock);
groupKickPlayer(plr); groupKick(plr);
} }
void Groups::sendToGroup(Player* plr, void* buf, uint32_t type, size_t size) { void Groups::sendToGroup(Group* group, void* buf, uint32_t type, size_t size) {
for (int i = 0; i < plr->groupCnt; i++) { auto players = (*group)[EntityKind::PLAYER];
CNSocket* sock = PlayerManager::getSockFromID(plr->groupIDs[i]); for (int i = 0; i < players.size(); i++) {
CNSocket* sock = players[i].sock;
if (sock == nullptr)
continue;
if (type == P_FE2CL_PC_GROUP_LEAVE_SUCC) {
Player* leavingPlr = PlayerManager::getPlayer(sock);
leavingPlr->iIDGroup = leavingPlr->iID;
}
sock->sendPacket(buf, type, size); sock->sendPacket(buf, type, size);
} }
} }
void Groups::groupTickInfo(Player* plr) { void Groups::groupTickInfo(Player* plr) {
if (!validOutVarPacket(sizeof(sP_FE2CL_PC_GROUP_MEMBER_INFO), plr->groupCnt, sizeof(sPCGroupMemberInfo))) {
auto players = (*plr->group)[EntityKind::PLAYER];
if (!validOutVarPacket(sizeof(sP_FE2CL_PC_GROUP_MEMBER_INFO), players.size(), sizeof(sPCGroupMemberInfo))) {
std::cout << "[WARN] bad sP_FE2CL_PC_GROUP_JOIN packet size\n"; std::cout << "[WARN] bad sP_FE2CL_PC_GROUP_JOIN packet size\n";
return; return;
} }
size_t resplen = sizeof(sP_FE2CL_PC_GROUP_MEMBER_INFO) + plr->groupCnt * sizeof(sPCGroupMemberInfo); size_t resplen = sizeof(sP_FE2CL_PC_GROUP_MEMBER_INFO) + players.size() * sizeof(sPCGroupMemberInfo);
uint8_t respbuf[CN_PACKET_BUFFER_SIZE]; uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
memset(respbuf, 0, resplen); memset(respbuf, 0, resplen);
@ -182,10 +221,11 @@ void Groups::groupTickInfo(Player* plr) {
sPCGroupMemberInfo *respdata = (sPCGroupMemberInfo*)(respbuf+sizeof(sP_FE2CL_PC_GROUP_MEMBER_INFO)); sPCGroupMemberInfo *respdata = (sPCGroupMemberInfo*)(respbuf+sizeof(sP_FE2CL_PC_GROUP_MEMBER_INFO));
resp->iID = plr->iID; resp->iID = plr->iID;
resp->iMemberPCCnt = plr->groupCnt; resp->iMemberPCCnt = players.size();
for (int i = 0; i < plr->groupCnt; i++) { for (int i = 0; i < players.size(); i++) {
Player* varPlr = PlayerManager::getPlayerFromID(plr->groupIDs[i]); EntityRef member = players[i];
Player* varPlr = PlayerManager::getPlayer(member.sock);
if (varPlr == nullptr) if (varPlr == nullptr)
continue; continue;
@ -210,17 +250,17 @@ void Groups::groupTickInfo(Player* plr) {
} }
} }
sendToGroup(plr, (void*)&respbuf, P_FE2CL_PC_GROUP_MEMBER_INFO, resplen); sendToGroup(plr->group, (void*)&respbuf, P_FE2CL_PC_GROUP_MEMBER_INFO, resplen);
} }
static void groupUnbuff(Player* plr) { static void groupUnbuff(Player* plr) {
for (int i = 0; i < plr->groupCnt; i++) { Group* group = plr->group;
for (int n = 0; n < plr->groupCnt; n++) { for (int i = 0; i < group->members.size(); i++) {
for (int n = 0; n < group->members.size(); n++) {
if (i == n) if (i == n)
continue; continue;
Player* otherPlr = PlayerManager::getPlayerFromID(plr->groupIDs[i]); EntityRef other = group->members[n];
CNSocket* sock = PlayerManager::getSockFromID(plr->groupIDs[n]);
// TODO ABILITIES // TODO ABILITIES
//Abilities::applyBuff(sock, otherPlr->Nanos[otherPlr->activeNano].iSkillID, 2, 1, 0); //Abilities::applyBuff(sock, otherPlr->Nanos[otherPlr->activeNano].iSkillID, 2, 1, 0);
@ -228,27 +268,26 @@ static void groupUnbuff(Player* plr) {
} }
} }
void Groups::groupKickPlayer(Player* plr) { void Groups::groupKick(Player* plr) {
Group* group = plr->group;
// if you are the group leader, destroy your own group and kick everybody // if you are the group leader, destroy your own group and kick everybody
if (plr->iID == plr->iIDGroup) { if (plr->group->members[0] == PlayerManager::getSockFromID(plr->iID)) {
groupUnbuff(plr); groupUnbuff(plr);
INITSTRUCT(sP_FE2CL_PC_GROUP_LEAVE_SUCC, resp1); INITSTRUCT(sP_FE2CL_PC_GROUP_LEAVE_SUCC, resp1);
sendToGroup(plr, (void*)&resp1, P_FE2CL_PC_GROUP_LEAVE_SUCC, sizeof(sP_FE2CL_PC_GROUP_LEAVE_SUCC)); sendToGroup(plr->group, (void*)&resp1, P_FE2CL_PC_GROUP_LEAVE_SUCC, sizeof(sP_FE2CL_PC_GROUP_LEAVE_SUCC));
plr->groupCnt = 1; disbandGroup(plr->group);
return; return;
} }
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup); auto players = (*group)[EntityKind::PLAYER];
if (otherPlr == nullptr) if (!validOutVarPacket(sizeof(sP_FE2CL_PC_GROUP_LEAVE), players.size() - 1, sizeof(sPCGroupMemberInfo))) {
return;
if (!validOutVarPacket(sizeof(sP_FE2CL_PC_GROUP_LEAVE), otherPlr->groupCnt - 1, sizeof(sPCGroupMemberInfo))) {
std::cout << "[WARN] bad sP_FE2CL_PC_GROUP_LEAVE packet size\n"; std::cout << "[WARN] bad sP_FE2CL_PC_GROUP_LEAVE packet size\n";
return; return;
} }
size_t resplen = sizeof(sP_FE2CL_PC_GROUP_LEAVE) + (otherPlr->groupCnt - 1) * sizeof(sPCGroupMemberInfo); size_t resplen = sizeof(sP_FE2CL_PC_GROUP_LEAVE) + (players.size() - 1) * sizeof(sPCGroupMemberInfo);
uint8_t respbuf[CN_PACKET_BUFFER_SIZE]; uint8_t respbuf[CN_PACKET_BUFFER_SIZE];
memset(respbuf, 0, resplen); memset(respbuf, 0, resplen);
@ -257,78 +296,55 @@ void Groups::groupKickPlayer(Player* plr) {
sPCGroupMemberInfo *respdata = (sPCGroupMemberInfo*)(respbuf+sizeof(sP_FE2CL_PC_GROUP_LEAVE)); sPCGroupMemberInfo *respdata = (sPCGroupMemberInfo*)(respbuf+sizeof(sP_FE2CL_PC_GROUP_LEAVE));
resp->iID_LeaveMember = plr->iID; resp->iID_LeaveMember = plr->iID;
resp->iMemberPCCnt = otherPlr->groupCnt - 1; resp->iMemberPCCnt = players.size() - 1;
int bitFlag = getGroupFlags(otherPlr) & ~plr->iGroupConditionBitFlag; int bitFlag = 0; // TODO ABILITIES getGroupFlags(otherPlr) & ~plr->iGroupConditionBitFlag;
int moveDown = 0;
CNSocket* sock = PlayerManager::getSockFromID(plr->iID); CNSocket* sock = PlayerManager::getSockFromID(plr->iID);
if (sock == nullptr) if (sock == nullptr)
return; return;
for (int i = 0; i < otherPlr->groupCnt; i++) { removeFromGroup(sock, group);
Player* varPlr = PlayerManager::getPlayerFromID(otherPlr->groupIDs[i]);
CNSocket* sockTo = PlayerManager::getSockFromID(otherPlr->groupIDs[i]); players = (*group)[EntityKind::PLAYER];
for (int i = 0; i < players.size(); i++) {
CNSocket* sockTo = players[i].sock;
Player* varPlr = PlayerManager::getPlayer(sock);
if (varPlr == nullptr || sockTo == nullptr) if (varPlr == nullptr || sockTo == nullptr)
continue; continue;
if (moveDown == 1) respdata[i].iPC_ID = varPlr->iID;
otherPlr->groupIDs[i-1] = otherPlr->groupIDs[i]; respdata[i].iPCUID = varPlr->PCStyle.iPC_UID;
respdata[i].iNameCheck = varPlr->PCStyle.iNameCheck;
respdata[i-moveDown].iPC_ID = varPlr->iID; memcpy(respdata[i].szFirstName, varPlr->PCStyle.szFirstName, sizeof(varPlr->PCStyle.szFirstName));
respdata[i-moveDown].iPCUID = varPlr->PCStyle.iPC_UID; memcpy(respdata[i].szLastName, varPlr->PCStyle.szLastName, sizeof(varPlr->PCStyle.szLastName));
respdata[i-moveDown].iNameCheck = varPlr->PCStyle.iNameCheck; respdata[i].iSpecialState = varPlr->iSpecialState;
memcpy(respdata[i-moveDown].szFirstName, varPlr->PCStyle.szFirstName, sizeof(varPlr->PCStyle.szFirstName)); respdata[i].iLv = varPlr->level;
memcpy(respdata[i-moveDown].szLastName, varPlr->PCStyle.szLastName, sizeof(varPlr->PCStyle.szLastName)); respdata[i].iHP = varPlr->HP;
respdata[i-moveDown].iSpecialState = varPlr->iSpecialState; respdata[i].iMaxHP = PC_MAXHEALTH(varPlr->level);
respdata[i-moveDown].iLv = varPlr->level; // respdata[i]].iMapType = 0;
respdata[i-moveDown].iHP = varPlr->HP; // respdata[i]].iMapNum = 0;
respdata[i-moveDown].iMaxHP = PC_MAXHEALTH(varPlr->level); respdata[i].iX = varPlr->x;
// respdata[i-moveDown]].iMapType = 0; respdata[i].iY = varPlr->y;
// respdata[i-moveDown]].iMapNum = 0; respdata[i].iZ = varPlr->z;
respdata[i-moveDown].iX = varPlr->x;
respdata[i-moveDown].iY = varPlr->y;
respdata[i-moveDown].iZ = varPlr->z;
// client doesnt read nano data here // client doesnt read nano data here
if (varPlr == plr) { // remove the leaving member's buffs from the group and remove the group buffs from the leaving member.
moveDown = 1;
otherPlr->groupIDs[i] = 0;
} else { // remove the leaving member's buffs from the group and remove the group buffs from the leaving member.
// TODO ABILITIES // TODO ABILITIES
/*if (Abilities::SkillTable[varPlr->Nanos[varPlr->activeNano].iSkillID].targetType == 3) /*if (Abilities::SkillTable[varPlr->Nanos[varPlr->activeNano].iSkillID].targetType == 3)
Abilities::applyBuff(sock, varPlr->Nanos[varPlr->activeNano].iSkillID, 2, 1, 0); Abilities::applyBuff(sock, varPlr->Nanos[varPlr->activeNano].iSkillID, 2, 1, 0);
if (Abilities::SkillTable[plr->Nanos[varPlr->activeNano].iSkillID].targetType == 3) if (Abilities::SkillTable[plr->Nanos[varPlr->activeNano].iSkillID].targetType == 3)
Abilities::applyBuff(sockTo, plr->Nanos[plr->activeNano].iSkillID, 2, 1, bitFlag);*/ Abilities::applyBuff(sockTo, plr->Nanos[plr->activeNano].iSkillID, 2, 1, bitFlag);*/
}
} }
plr->iIDGroup = plr->iID; sendToGroup(group, (void*)&respbuf, P_FE2CL_PC_GROUP_LEAVE, resplen);
otherPlr->groupCnt -= 1;
sendToGroup(otherPlr, (void*)&respbuf, P_FE2CL_PC_GROUP_LEAVE, resplen);
INITSTRUCT(sP_FE2CL_PC_GROUP_LEAVE_SUCC, resp1); INITSTRUCT(sP_FE2CL_PC_GROUP_LEAVE_SUCC, resp1);
sock->sendPacket((void*)&resp1, P_FE2CL_PC_GROUP_LEAVE_SUCC, sizeof(sP_FE2CL_PC_GROUP_LEAVE_SUCC)); sock->sendPacket((void*)&resp1, P_FE2CL_PC_GROUP_LEAVE_SUCC, sizeof(sP_FE2CL_PC_GROUP_LEAVE_SUCC));
} }
int Groups::getGroupFlags(Player* plr) {
int bitFlag = 0;
for (int i = 0; i < plr->groupCnt; i++) {
Player* otherPlr = PlayerManager::getPlayerFromID(plr->groupIDs[i]);
if (otherPlr == nullptr)
continue;
bitFlag |= otherPlr->iGroupConditionBitFlag;
}
return bitFlag;
}
void Groups::init() { void Groups::init() {
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_INVITE, requestGroup); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_INVITE, requestGroup);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_INVITE_REFUSE, refuseGroup); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_INVITE_REFUSE, refuseGroup);

View File

@ -1,17 +1,36 @@
#pragma once #pragma once
#include "Player.hpp"
#include "core/Core.hpp" #include "core/Core.hpp"
#include "servers/CNShardServer.hpp" #include "servers/CNShardServer.hpp"
#include "Entities.hpp"
#include <map> #include <map>
#include <list> #include <list>
struct Player;
enum EntityKind;
struct Group {
std::vector<EntityRef> members;
int32_t conditionBitFlag;
auto operator[](EntityKind kind) {
std::vector<EntityRef> filtered;
std::copy_if(members.begin(), members.end(), std::back_inserter(filtered), [kind](EntityRef e) {
return e.kind == kind;
});
return filtered;
}
};
namespace Groups { namespace Groups {
void init(); void init();
void sendToGroup(Player* plr, void* buf, uint32_t type, size_t size); void sendToGroup(Group* group, void* buf, uint32_t type, size_t size);
void groupTickInfo(Player* plr); void groupTickInfo(Player* plr);
void groupKickPlayer(Player* plr); void groupKick(Player* plr);
int getGroupFlags(Player* plr);
void addToGroup(EntityRef member, Group* group);
void removeFromGroup(EntityRef member, Group* group);
void disbandGroup(Group* group);
} }

View File

@ -842,22 +842,20 @@ void MobAI::onDeath(CombatNPC* npc, EntityRef src) {
Items::DropRoll rolled; Items::DropRoll rolled;
Items::DropRoll eventRolled; Items::DropRoll eventRolled;
std::map<int, int> qitemRolls; std::map<int, int> qitemRolls;
std::vector<Player*> playerRefs;
Player* leader = PlayerManager::getPlayerFromID(plr->iIDGroup); if (plr->group == nullptr) {
assert(leader != nullptr); // should never happen playerRefs.push_back(plr);
Combat::genQItemRolls(playerRefs, qitemRolls);
Combat::genQItemRolls(leader, qitemRolls);
if (plr->groupCnt == 1 && plr->iIDGroup == plr->iID) {
Items::giveMobDrop(src.sock, self, rolled, eventRolled); Items::giveMobDrop(src.sock, self, rolled, eventRolled);
Missions::mobKilled(src.sock, self->type, qitemRolls); Missions::mobKilled(src.sock, self->type, qitemRolls);
} }
else { else {
for (int i = 0; i < leader->groupCnt; i++) { auto players = (*plr->group)[EntityKind::PLAYER];
CNSocket* sockTo = PlayerManager::getSockFromID(leader->groupIDs[i]); for (EntityRef pRef : players) playerRefs.push_back(PlayerManager::getPlayer(pRef.sock));
if (sockTo == nullptr) Combat::genQItemRolls(playerRefs, qitemRolls);
continue; for (int i = 0; i < players.size(); i++) {
CNSocket* sockTo = players[i].sock;
Player* otherPlr = PlayerManager::getPlayer(sockTo); Player* otherPlr = PlayerManager::getPlayer(sockTo);
// only contribute to group members' kills if they're close enough // only contribute to group members' kills if they're close enough

View File

@ -182,9 +182,12 @@ static void handleWarp(CNSocket* sock, int32_t warpId) {
if (Warps[warpId].isInstance) { if (Warps[warpId].isInstance) {
uint64_t instanceID = Warps[warpId].instanceID; uint64_t instanceID = Warps[warpId].instanceID;
Player* leader = plr;
if (plr->group != nullptr) leader = PlayerManager::getPlayer((*plr->group)[EntityKind::PLAYER][0].sock);
// if warp requires you to be on a mission, it's gotta be a unique instance // if warp requires you to be on a mission, it's gotta be a unique instance
if (Warps[warpId].limitTaskID != 0 || instanceID == 14) { // 14 is a special case for the Time Lab if (Warps[warpId].limitTaskID != 0 || instanceID == 14) { // 14 is a special case for the Time Lab
instanceID += ((uint64_t)plr->iIDGroup << 32); // upper 32 bits are leader ID instanceID += ((uint64_t)leader->iID << 32); // upper 32 bits are leader ID
Chunking::createInstance(instanceID); Chunking::createInstance(instanceID);
// save Lair entrance coords as a pseudo-Resurrect 'Em // save Lair entrance coords as a pseudo-Resurrect 'Em
@ -194,14 +197,13 @@ static void handleWarp(CNSocket* sock, int32_t warpId) {
plr->recallInstance = instanceID; plr->recallInstance = instanceID;
} }
if (plr->iID == plr->iIDGroup && plr->groupCnt == 1) if (plr->group == nullptr)
PlayerManager::sendPlayerTo(sock, Warps[warpId].x, Warps[warpId].y, Warps[warpId].z, instanceID); PlayerManager::sendPlayerTo(sock, Warps[warpId].x, Warps[warpId].y, Warps[warpId].z, instanceID);
else { else {
Player* leaderPlr = PlayerManager::getPlayerFromID(plr->iIDGroup); auto players = (*plr->group)[EntityKind::PLAYER];
for (int i = 0; i < players.size(); i++) {
for (int i = 0; i < leaderPlr->groupCnt; i++) { CNSocket* sockTo = players[i].sock;
Player* otherPlr = PlayerManager::getPlayerFromID(leaderPlr->groupIDs[i]); Player* otherPlr = PlayerManager::getPlayer(sockTo);
CNSocket* sockTo = PlayerManager::getSockFromID(leaderPlr->groupIDs[i]);
if (otherPlr == nullptr || sockTo == nullptr) if (otherPlr == nullptr || sockTo == nullptr)
continue; continue;

View File

@ -6,6 +6,7 @@
#include "core/Core.hpp" #include "core/Core.hpp"
#include "Chunking.hpp" #include "Chunking.hpp"
#include "Entities.hpp" #include "Entities.hpp"
#include "Groups.hpp"
#define ACTIVE_MISSION_COUNT 6 #define ACTIVE_MISSION_COUNT 6
@ -65,10 +66,7 @@ struct Player : public Entity, public ICombatant {
sTimeLimitItemDeleteInfo2CL toRemoveVehicle = {}; sTimeLimitItemDeleteInfo2CL toRemoveVehicle = {};
int32_t iIDGroup = 0; Group* group = nullptr;
int groupCnt = 0;
int32_t groupIDs[4] = {};
int32_t iGroupConditionBitFlag = 0;
bool notify = false; bool notify = false;
bool hidden = false; bool hidden = false;

View File

@ -41,7 +41,8 @@ void PlayerManager::removePlayer(CNSocket* key) {
Player* plr = getPlayer(key); Player* plr = getPlayer(key);
uint64_t fromInstance = plr->instanceID; uint64_t fromInstance = plr->instanceID;
Groups::groupKickPlayer(plr); if(plr->group != nullptr)
Groups::groupKick(plr);
// remove player's bullets // remove player's bullets
Combat::Bullets.erase(plr->iID); Combat::Bullets.erase(plr->iID);
@ -232,8 +233,7 @@ static void enterPlayer(CNSocket* sock, CNPacketData* data) {
Database::getPlayer(plr, lm->playerId); Database::getPlayer(plr, lm->playerId);
} }
plr->groupCnt = 1; plr->group = nullptr;
plr->iIDGroup = plr->groupIDs[0] = plr->iID;
response.iID = plr->iID; response.iID = plr->iID;
response.uiSvrTime = getTime(); response.uiSvrTime = getTime();
@ -474,9 +474,8 @@ static void revivePlayer(CNSocket* sock, CNPacketData* data) {
resp2.PCRegenDataForOtherPC.iHP = plr->HP; resp2.PCRegenDataForOtherPC.iHP = plr->HP;
resp2.PCRegenDataForOtherPC.iAngle = plr->angle; resp2.PCRegenDataForOtherPC.iAngle = plr->angle;
Player *otherPlr = getPlayerFromID(plr->iIDGroup); if (plr->group != nullptr) {
if (otherPlr != nullptr) { int bitFlag = plr->group->conditionBitFlag;
int bitFlag = Groups::getGroupFlags(otherPlr);
resp2.PCRegenDataForOtherPC.iConditionBitFlag = plr->iConditionBitFlag = plr->iSelfConditionBitFlag | bitFlag; resp2.PCRegenDataForOtherPC.iConditionBitFlag = plr->iConditionBitFlag = plr->iSelfConditionBitFlag | bitFlag;
resp2.PCRegenDataForOtherPC.iPCState = plr->iPCState; resp2.PCRegenDataForOtherPC.iPCState = plr->iPCState;