mirror of
				https://github.com/OpenFusionProject/OpenFusion.git
				synced 2025-10-31 00:30:15 +00:00 
			
		
		
		
	[refactor] Refactor groups
This commit is contained in:
		
							
								
								
									
										17
									
								
								src/Chat.cpp
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								src/Chat.cpp
									
									
									
									
									
								
							| @@ -225,10 +225,6 @@ static void tradeChatHandler(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; | ||||
|     Player* plr = PlayerManager::getPlayer(sock); | ||||
|     Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup); | ||||
|  | ||||
|     if (otherPlr == nullptr) | ||||
|         return; | ||||
|  | ||||
|     std::string fullChat = sanitizeText(AUTOU16TOU8(chat->szFreeChat)); | ||||
|  | ||||
| @@ -251,16 +247,15 @@ static void groupChatHandler(CNSocket* sock, CNPacketData* data) { | ||||
|     resp.iSendPCID = plr->iID; | ||||
|     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) { | ||||
|     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* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup); | ||||
|  | ||||
|     if (otherPlr == nullptr) | ||||
|         return; | ||||
|  | ||||
|     std::string fullChat = sanitizeText(AUTOU16TOU8(chat->szFreeChat)); | ||||
|     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.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 | ||||
|   | ||||
| @@ -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 | ||||
|  * set of rolls. | ||||
|  */ | ||||
| void Combat::genQItemRolls(Player *leader, std::map<int, int>& rolls) { | ||||
|     for (int i = 0; i < leader->groupCnt; i++) { | ||||
|         if (leader->groupIDs[i] == 0) | ||||
|             continue; | ||||
|  | ||||
|         CNSocket *otherSock = PlayerManager::getSockFromID(leader->groupIDs[i]); | ||||
|         if (otherSock == nullptr) | ||||
|             continue; | ||||
|  | ||||
|         Player *member = PlayerManager::getPlayer(otherSock); | ||||
| void Combat::genQItemRolls(std::vector<Player*> players, std::map<int, int>& rolls) { | ||||
|     for (int i = 0; i < players.size(); i++) { | ||||
|  | ||||
|         Player* member = players[i]; | ||||
|         for (int j = 0; j < ACTIVE_MISSION_COUNT; j++) | ||||
|             if (member->tasks[j] != 0) | ||||
|                 rolls[member->tasks[j]] = Rand::rand(); | ||||
| @@ -679,7 +672,7 @@ static void playerTick(CNServer *serv, time_t currTime) { | ||||
|         bool transmit = false; | ||||
|  | ||||
|         // group ticks | ||||
|         if (plr->groupCnt > 1) | ||||
|         if (plr->group != nullptr) | ||||
|             Groups::groupTickInfo(plr); | ||||
|  | ||||
|         // do not tick dead players | ||||
|   | ||||
| @@ -25,5 +25,5 @@ namespace Combat { | ||||
|     void init(); | ||||
|  | ||||
|     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); | ||||
| } | ||||
|   | ||||
| @@ -16,10 +16,9 @@ std::unordered_map<int, EggType> Eggs::EggTypes; | ||||
|  | ||||
| int Eggs::eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration) { | ||||
|     Player* plr = PlayerManager::getPlayer(sock); | ||||
|     Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup); | ||||
|  | ||||
|     int bitFlag = Groups::getGroupFlags(otherPlr); | ||||
|     // TODO ABILITIES | ||||
|     int bitFlag = plr->group->conditionBitFlag; | ||||
|     int CBFlag = 0;// Abilities::applyBuff(sock, skillId, 1, 3, bitFlag); | ||||
|  | ||||
|     size_t resplen;  | ||||
| @@ -98,9 +97,8 @@ static void eggStep(CNServer* serv, time_t currTime) { | ||||
|             CNSocket* sock = it->first.first; | ||||
|             int32_t CBFlag = it->first.second; | ||||
|             Player* plr = PlayerManager::getPlayer(sock); | ||||
|             Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup); | ||||
|  | ||||
|             int groupFlags = Groups::getGroupFlags(otherPlr); | ||||
|             int groupFlags = plr->group->conditionBitFlag; | ||||
|             // TODO ABILITIES | ||||
|             //for (auto& pwr : Abilities::Powers) { | ||||
|             //    if (pwr.bitFlag == CBFlag) { // pick the power with the right flag and unbuff | ||||
|   | ||||
| @@ -25,6 +25,7 @@ enum class AIState { | ||||
| }; | ||||
|  | ||||
| class Chunk; | ||||
| struct Group; | ||||
|  | ||||
| struct Entity { | ||||
|     EntityKind kind = EntityKind::INVALID; | ||||
| @@ -130,6 +131,7 @@ struct CombatNPC : public BaseNPC, public ICombatant { | ||||
|     int level = 0; | ||||
|     int speed = 300; | ||||
|     AIState state = AIState::INACTIVE; | ||||
|     Group* group = nullptr; | ||||
|     int playersInView = 0; // for optimizing away AI in empty chunks | ||||
|  | ||||
|     std::map<AIState, void (*)(CombatNPC*, time_t)> stateHandlers; | ||||
|   | ||||
							
								
								
									
										220
									
								
								src/Groups.cpp
									
									
									
									
									
								
							
							
						
						
									
										220
									
								
								src/Groups.cpp
									
									
									
									
									
								
							| @@ -19,22 +19,65 @@ | ||||
|  | ||||
| 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) { | ||||
|     sP_CL2FE_REQ_PC_GROUP_INVITE* recv = (sP_CL2FE_REQ_PC_GROUP_INVITE*)data->buf; | ||||
|  | ||||
|     Player* plr = PlayerManager::getPlayer(sock); | ||||
|     Player* otherPlr = PlayerManager::getPlayerFromID(recv->iID_To); | ||||
|  | ||||
|     if (otherPlr == nullptr) | ||||
|         return; | ||||
|  | ||||
|     otherPlr = PlayerManager::getPlayerFromID(otherPlr->iIDGroup); | ||||
|  | ||||
|     if (otherPlr == nullptr) | ||||
|         return; | ||||
|  | ||||
|     // 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); | ||||
|         sock->sendPacket((void*)&resp, P_FE2CL_PC_GROUP_INVITE_FAIL, sizeof(sP_FE2CL_PC_GROUP_INVITE_FAIL)); | ||||
|         return; | ||||
| @@ -77,28 +120,29 @@ static void joinGroup(CNSocket* sock, CNPacketData* data) { | ||||
|     if (otherPlr == nullptr) | ||||
|         return; | ||||
|  | ||||
|     otherPlr = PlayerManager::getPlayerFromID(otherPlr->iIDGroup); | ||||
|  | ||||
|     if (otherPlr == nullptr) | ||||
|         return; | ||||
|     int size = otherPlr->group == nullptr ? 1 : (*otherPlr->group)[EntityKind::PLAYER].size(); | ||||
|  | ||||
|     // 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); | ||||
|         sock->sendPacket((void*)&resp, P_FE2CL_PC_GROUP_JOIN_FAIL, sizeof(sP_FE2CL_PC_GROUP_JOIN_FAIL)); | ||||
|         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"; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     plr->iIDGroup = otherPlr->iID; | ||||
|     otherPlr->groupCnt += 1; | ||||
|     otherPlr->groupIDs[otherPlr->groupCnt-1] = plr->iID; | ||||
|     if (otherPlr->group == nullptr) { | ||||
|         // create group | ||||
|         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]; | ||||
|  | ||||
|     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)); | ||||
|  | ||||
|     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::getPlayerFromID(otherPlr->groupIDs[i]); | ||||
|         CNSocket* sockTo = PlayerManager::getSockFromID(otherPlr->groupIDs[i]); | ||||
|         Player* varPlr = PlayerManager::getPlayer(players[i].sock); | ||||
|         CNSocket* sockTo = players[i].sock; | ||||
|  | ||||
|         if (varPlr == nullptr || sockTo == nullptr) | ||||
|             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) { | ||||
|     Player* plr = PlayerManager::getPlayer(sock); | ||||
|     groupKickPlayer(plr); | ||||
|     groupKick(plr); | ||||
| } | ||||
|  | ||||
| void Groups::sendToGroup(Player* plr, void* buf, uint32_t type, size_t size) { | ||||
|     for (int i = 0; i < plr->groupCnt; i++) { | ||||
|         CNSocket* sock = PlayerManager::getSockFromID(plr->groupIDs[i]); | ||||
|  | ||||
|         if (sock == nullptr) | ||||
|             continue; | ||||
|  | ||||
|         if (type == P_FE2CL_PC_GROUP_LEAVE_SUCC) { | ||||
|             Player* leavingPlr = PlayerManager::getPlayer(sock); | ||||
|             leavingPlr->iIDGroup = leavingPlr->iID; | ||||
|         } | ||||
|  | ||||
| void Groups::sendToGroup(Group* group, void* buf, uint32_t type, size_t size) { | ||||
|     auto players = (*group)[EntityKind::PLAYER]; | ||||
|     for (int i = 0; i < players.size(); i++) { | ||||
|         CNSocket* sock = players[i].sock; | ||||
|         sock->sendPacket(buf, type, size); | ||||
|     } | ||||
| } | ||||
|  | ||||
| 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"; | ||||
|         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]; | ||||
|  | ||||
|     memset(respbuf, 0, resplen); | ||||
| @@ -182,10 +221,11 @@ void Groups::groupTickInfo(Player* plr) { | ||||
|     sPCGroupMemberInfo *respdata = (sPCGroupMemberInfo*)(respbuf+sizeof(sP_FE2CL_PC_GROUP_MEMBER_INFO)); | ||||
|  | ||||
|     resp->iID = plr->iID; | ||||
|     resp->iMemberPCCnt = plr->groupCnt; | ||||
|     resp->iMemberPCCnt = players.size(); | ||||
|  | ||||
|     for (int i = 0; i < plr->groupCnt; i++) { | ||||
|         Player* varPlr = PlayerManager::getPlayerFromID(plr->groupIDs[i]); | ||||
|     for (int i = 0; i < players.size(); i++) { | ||||
|         EntityRef member = players[i]; | ||||
|         Player* varPlr = PlayerManager::getPlayer(member.sock); | ||||
|  | ||||
|         if (varPlr == nullptr) | ||||
|             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) { | ||||
|     for (int i = 0; i < plr->groupCnt; i++) { | ||||
|         for (int n = 0; n < plr->groupCnt; n++) { | ||||
|     Group* group = plr->group; | ||||
|     for (int i = 0; i < group->members.size(); i++) { | ||||
|         for (int n = 0; n < group->members.size(); n++) { | ||||
|             if (i == n) | ||||
|                 continue; | ||||
|  | ||||
|             Player* otherPlr = PlayerManager::getPlayerFromID(plr->groupIDs[i]); | ||||
|             CNSocket* sock = PlayerManager::getSockFromID(plr->groupIDs[n]); | ||||
|             EntityRef other = group->members[n]; | ||||
|  | ||||
|             // TODO ABILITIES | ||||
|             //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 (plr->iID == plr->iIDGroup) { | ||||
|     if (plr->group->members[0] == PlayerManager::getSockFromID(plr->iID)) { | ||||
|         groupUnbuff(plr); | ||||
|         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)); | ||||
|         plr->groupCnt = 1; | ||||
|         sendToGroup(plr->group, (void*)&resp1, P_FE2CL_PC_GROUP_LEAVE_SUCC, sizeof(sP_FE2CL_PC_GROUP_LEAVE_SUCC)); | ||||
|         disbandGroup(plr->group); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup); | ||||
|     auto players = (*group)[EntityKind::PLAYER]; | ||||
|  | ||||
|     if (otherPlr == nullptr) | ||||
|         return; | ||||
|  | ||||
|     if (!validOutVarPacket(sizeof(sP_FE2CL_PC_GROUP_LEAVE), otherPlr->groupCnt - 1, sizeof(sPCGroupMemberInfo))) { | ||||
|     if (!validOutVarPacket(sizeof(sP_FE2CL_PC_GROUP_LEAVE), players.size() - 1, sizeof(sPCGroupMemberInfo))) { | ||||
|         std::cout << "[WARN] bad sP_FE2CL_PC_GROUP_LEAVE packet size\n"; | ||||
|         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]; | ||||
|  | ||||
|     memset(respbuf, 0, resplen); | ||||
| @@ -257,78 +296,55 @@ void Groups::groupKickPlayer(Player* plr) { | ||||
|     sPCGroupMemberInfo *respdata = (sPCGroupMemberInfo*)(respbuf+sizeof(sP_FE2CL_PC_GROUP_LEAVE)); | ||||
|  | ||||
|     resp->iID_LeaveMember = plr->iID; | ||||
|     resp->iMemberPCCnt = otherPlr->groupCnt - 1; | ||||
|     resp->iMemberPCCnt = players.size() - 1; | ||||
|  | ||||
|     int bitFlag = getGroupFlags(otherPlr) & ~plr->iGroupConditionBitFlag; | ||||
|     int moveDown = 0; | ||||
|     int bitFlag = 0; // TODO ABILITIES getGroupFlags(otherPlr) & ~plr->iGroupConditionBitFlag; | ||||
|  | ||||
|     CNSocket* sock = PlayerManager::getSockFromID(plr->iID); | ||||
|  | ||||
|     if (sock == nullptr) | ||||
|         return; | ||||
|  | ||||
|     for (int i = 0; i < otherPlr->groupCnt; i++) { | ||||
|         Player* varPlr = PlayerManager::getPlayerFromID(otherPlr->groupIDs[i]); | ||||
|         CNSocket* sockTo = PlayerManager::getSockFromID(otherPlr->groupIDs[i]); | ||||
|     removeFromGroup(sock, group); | ||||
|  | ||||
|     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) | ||||
|             continue; | ||||
|  | ||||
|         if (moveDown == 1) | ||||
|             otherPlr->groupIDs[i-1] = otherPlr->groupIDs[i]; | ||||
|  | ||||
|         respdata[i-moveDown].iPC_ID = varPlr->iID; | ||||
|         respdata[i-moveDown].iPCUID = varPlr->PCStyle.iPC_UID; | ||||
|         respdata[i-moveDown].iNameCheck = varPlr->PCStyle.iNameCheck; | ||||
|         memcpy(respdata[i-moveDown].szFirstName, varPlr->PCStyle.szFirstName, sizeof(varPlr->PCStyle.szFirstName)); | ||||
|         memcpy(respdata[i-moveDown].szLastName, varPlr->PCStyle.szLastName, sizeof(varPlr->PCStyle.szLastName)); | ||||
|         respdata[i-moveDown].iSpecialState = varPlr->iSpecialState; | ||||
|         respdata[i-moveDown].iLv = varPlr->level; | ||||
|         respdata[i-moveDown].iHP = varPlr->HP; | ||||
|         respdata[i-moveDown].iMaxHP = PC_MAXHEALTH(varPlr->level); | ||||
|         // respdata[i-moveDown]].iMapType = 0; | ||||
|         // respdata[i-moveDown]].iMapNum = 0; | ||||
|         respdata[i-moveDown].iX = varPlr->x; | ||||
|         respdata[i-moveDown].iY = varPlr->y; | ||||
|         respdata[i-moveDown].iZ = varPlr->z; | ||||
|         respdata[i].iPC_ID = varPlr->iID; | ||||
|         respdata[i].iPCUID = varPlr->PCStyle.iPC_UID; | ||||
|         respdata[i].iNameCheck = varPlr->PCStyle.iNameCheck; | ||||
|         memcpy(respdata[i].szFirstName, varPlr->PCStyle.szFirstName, sizeof(varPlr->PCStyle.szFirstName)); | ||||
|         memcpy(respdata[i].szLastName, varPlr->PCStyle.szLastName, sizeof(varPlr->PCStyle.szLastName)); | ||||
|         respdata[i].iSpecialState = varPlr->iSpecialState; | ||||
|         respdata[i].iLv = varPlr->level; | ||||
|         respdata[i].iHP = varPlr->HP; | ||||
|         respdata[i].iMaxHP = PC_MAXHEALTH(varPlr->level); | ||||
|         // respdata[i]].iMapType = 0; | ||||
|         // respdata[i]].iMapNum = 0; | ||||
|         respdata[i].iX = varPlr->x; | ||||
|         respdata[i].iY = varPlr->y; | ||||
|         respdata[i].iZ = varPlr->z; | ||||
|         // client doesnt read nano data here | ||||
|  | ||||
|         if (varPlr == plr) { | ||||
|             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. | ||||
|         // remove the leaving member's buffs from the group and remove the group buffs from the leaving member. | ||||
|             // TODO ABILITIES | ||||
|           /*if (Abilities::SkillTable[varPlr->Nanos[varPlr->activeNano].iSkillID].targetType == 3) | ||||
|                 Abilities::applyBuff(sock, varPlr->Nanos[varPlr->activeNano].iSkillID, 2, 1, 0); | ||||
|             if (Abilities::SkillTable[plr->Nanos[varPlr->activeNano].iSkillID].targetType == 3) | ||||
|                 Abilities::applyBuff(sockTo, plr->Nanos[plr->activeNano].iSkillID, 2, 1, bitFlag);*/ | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     plr->iIDGroup = plr->iID; | ||||
|     otherPlr->groupCnt -= 1; | ||||
|  | ||||
|     sendToGroup(otherPlr, (void*)&respbuf, P_FE2CL_PC_GROUP_LEAVE, resplen); | ||||
|     sendToGroup(group, (void*)&respbuf, P_FE2CL_PC_GROUP_LEAVE, resplen); | ||||
|  | ||||
|     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)); | ||||
| } | ||||
|  | ||||
| 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() { | ||||
|     REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_INVITE, requestGroup); | ||||
|     REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GROUP_INVITE_REFUSE, refuseGroup); | ||||
|   | ||||
| @@ -1,17 +1,36 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "Player.hpp" | ||||
| #include "core/Core.hpp" | ||||
| #include "servers/CNShardServer.hpp" | ||||
| #include "Entities.hpp" | ||||
|  | ||||
| #include <map> | ||||
| #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 { | ||||
|     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 groupKickPlayer(Player* plr); | ||||
|     int getGroupFlags(Player* plr); | ||||
|     void groupKick(Player* plr); | ||||
|  | ||||
|     void addToGroup(EntityRef member, Group* group); | ||||
|     void removeFromGroup(EntityRef member, Group* group); | ||||
|     void disbandGroup(Group* group); | ||||
| } | ||||
|   | ||||
| @@ -842,22 +842,20 @@ void MobAI::onDeath(CombatNPC* npc, EntityRef src) { | ||||
|         Items::DropRoll rolled; | ||||
|         Items::DropRoll eventRolled; | ||||
|         std::map<int, int> qitemRolls; | ||||
|         std::vector<Player*> playerRefs; | ||||
|  | ||||
|         Player* leader = PlayerManager::getPlayerFromID(plr->iIDGroup); | ||||
|         assert(leader != nullptr); // should never happen | ||||
|  | ||||
|         Combat::genQItemRolls(leader, qitemRolls); | ||||
|  | ||||
|         if (plr->groupCnt == 1 && plr->iIDGroup == plr->iID) { | ||||
|         if (plr->group == nullptr) { | ||||
|             playerRefs.push_back(plr); | ||||
|             Combat::genQItemRolls(playerRefs, qitemRolls); | ||||
|             Items::giveMobDrop(src.sock, self, rolled, eventRolled); | ||||
|             Missions::mobKilled(src.sock, self->type, qitemRolls); | ||||
|         } | ||||
|         else { | ||||
|             for (int i = 0; i < leader->groupCnt; i++) { | ||||
|                 CNSocket* sockTo = PlayerManager::getSockFromID(leader->groupIDs[i]); | ||||
|                 if (sockTo == nullptr) | ||||
|                     continue; | ||||
|  | ||||
|             auto players = (*plr->group)[EntityKind::PLAYER]; | ||||
|             for (EntityRef pRef : players) playerRefs.push_back(PlayerManager::getPlayer(pRef.sock)); | ||||
|             Combat::genQItemRolls(playerRefs, qitemRolls); | ||||
|             for (int i = 0; i < players.size(); i++) { | ||||
|                 CNSocket* sockTo = players[i].sock; | ||||
|                 Player* otherPlr = PlayerManager::getPlayer(sockTo); | ||||
|  | ||||
|                 // only contribute to group members' kills if they're close enough | ||||
|   | ||||
| @@ -182,9 +182,12 @@ static void handleWarp(CNSocket* sock, int32_t warpId) { | ||||
|     if (Warps[warpId].isInstance) { | ||||
|         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 (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); | ||||
|  | ||||
|             // save Lair entrance coords as a pseudo-Resurrect 'Em | ||||
| @@ -194,14 +197,13 @@ static void handleWarp(CNSocket* sock, int32_t warpId) { | ||||
|             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); | ||||
|         else { | ||||
|             Player* leaderPlr = PlayerManager::getPlayerFromID(plr->iIDGroup); | ||||
|  | ||||
|             for (int i = 0; i < leaderPlr->groupCnt; i++) { | ||||
|                 Player* otherPlr = PlayerManager::getPlayerFromID(leaderPlr->groupIDs[i]); | ||||
|                 CNSocket* sockTo = PlayerManager::getSockFromID(leaderPlr->groupIDs[i]); | ||||
|             auto players = (*plr->group)[EntityKind::PLAYER]; | ||||
|             for (int i = 0; i < players.size(); i++) { | ||||
|                 CNSocket* sockTo = players[i].sock; | ||||
|                 Player* otherPlr = PlayerManager::getPlayer(sockTo); | ||||
|  | ||||
|                 if (otherPlr == nullptr || sockTo == nullptr) | ||||
|                     continue; | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| #include "core/Core.hpp" | ||||
| #include "Chunking.hpp" | ||||
| #include "Entities.hpp" | ||||
| #include "Groups.hpp" | ||||
|  | ||||
| #define ACTIVE_MISSION_COUNT 6 | ||||
|  | ||||
| @@ -65,10 +66,7 @@ struct Player : public Entity, public ICombatant { | ||||
|  | ||||
|     sTimeLimitItemDeleteInfo2CL toRemoveVehicle = {}; | ||||
|  | ||||
|     int32_t iIDGroup = 0; | ||||
|     int groupCnt = 0; | ||||
|     int32_t groupIDs[4] = {}; | ||||
|     int32_t iGroupConditionBitFlag = 0; | ||||
|     Group* group = nullptr; | ||||
|  | ||||
|     bool notify = false; | ||||
|     bool hidden = false; | ||||
|   | ||||
| @@ -41,7 +41,8 @@ void PlayerManager::removePlayer(CNSocket* key) { | ||||
|     Player* plr = getPlayer(key); | ||||
|     uint64_t fromInstance = plr->instanceID; | ||||
|  | ||||
|     Groups::groupKickPlayer(plr); | ||||
|     if(plr->group != nullptr) | ||||
|         Groups::groupKick(plr); | ||||
|  | ||||
|     // remove player's bullets | ||||
|     Combat::Bullets.erase(plr->iID); | ||||
| @@ -232,8 +233,7 @@ static void enterPlayer(CNSocket* sock, CNPacketData* data) { | ||||
|         Database::getPlayer(plr, lm->playerId); | ||||
|     } | ||||
|  | ||||
|     plr->groupCnt = 1; | ||||
|     plr->iIDGroup = plr->groupIDs[0] = plr->iID; | ||||
|     plr->group = nullptr; | ||||
|  | ||||
|     response.iID = plr->iID; | ||||
|     response.uiSvrTime = getTime(); | ||||
| @@ -474,9 +474,8 @@ static void revivePlayer(CNSocket* sock, CNPacketData* data) { | ||||
|     resp2.PCRegenDataForOtherPC.iHP = plr->HP; | ||||
|     resp2.PCRegenDataForOtherPC.iAngle = plr->angle; | ||||
|  | ||||
|     Player *otherPlr = getPlayerFromID(plr->iIDGroup); | ||||
|     if (otherPlr != nullptr) { | ||||
|         int bitFlag = Groups::getGroupFlags(otherPlr); | ||||
|     if (plr->group != nullptr) { | ||||
|         int bitFlag = plr->group->conditionBitFlag; | ||||
|         resp2.PCRegenDataForOtherPC.iConditionBitFlag = plr->iConditionBitFlag = plr->iSelfConditionBitFlag | bitFlag; | ||||
|  | ||||
|         resp2.PCRegenDataForOtherPC.iPCState = plr->iPCState; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 gsemaj
					gsemaj