mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2025-01-22 08:30:06 +00:00
Update Racing.cpp
Refactor Racing module: Introduce helper functions for race validation and scoring - Added `validateRaceStart` and `validateRaceEnd` functions to streamline race start and end checks. - Introduced `calculateRaceScore` and `calculateFMReward` functions for improved score and reward calculations. - Refactored `racingStart` and `racingEnd` methods to utilize new helper functions, enhancing code readability and maintainability. - Updated race ranking handling to encapsulate logic in `handleRaceRanking` function, improving separation of concerns.
This commit is contained in:
parent
6b9ae4c325
commit
0ee7af3ab5
156
src/Racing.cpp
156
src/Racing.cpp
@ -1,8 +1,6 @@
|
|||||||
#include "Racing.hpp"
|
#include "Racing.hpp"
|
||||||
|
|
||||||
#include "db/Database.hpp"
|
#include "db/Database.hpp"
|
||||||
#include "servers/CNShardServer.hpp"
|
#include "servers/CNShardServer.hpp"
|
||||||
|
|
||||||
#include "NPCManager.hpp"
|
#include "NPCManager.hpp"
|
||||||
#include "PlayerManager.hpp"
|
#include "PlayerManager.hpp"
|
||||||
#include "Missions.hpp"
|
#include "Missions.hpp"
|
||||||
@ -14,35 +12,125 @@ std::map<int32_t, EPInfo> Racing::EPData;
|
|||||||
std::map<CNSocket*, EPRace> Racing::EPRaces;
|
std::map<CNSocket*, EPRace> Racing::EPRaces;
|
||||||
std::map<int32_t, std::pair<std::vector<int>, std::vector<int>>> Racing::EPRewards;
|
std::map<int32_t, std::pair<std::vector<int>, std::vector<int>>> Racing::EPRewards;
|
||||||
|
|
||||||
static void racingStart(CNSocket* sock, CNPacketData* data) {
|
namespace {
|
||||||
|
// Helper functions
|
||||||
|
bool validateRaceStart(CNSocket* sock, int32_t startEcomID) {
|
||||||
|
if (NPCManager::NPCs.find(startEcomID) == NPCManager::NPCs.end())
|
||||||
|
return false; // starting line agent not found
|
||||||
|
|
||||||
|
int mapNum = MAPNUM(NPCManager::NPCs[startEcomID]->instanceID);
|
||||||
|
return EPData.find(mapNum) != EPData.end() && EPData[mapNum].EPID != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool validateRaceEnd(CNSocket* sock, int32_t endEcomID) {
|
||||||
|
if (EPRaces.find(sock) == EPRaces.end() ||
|
||||||
|
NPCManager::NPCs.find(endEcomID) == NPCManager::NPCs.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int mapNum = MAPNUM(NPCManager::NPCs[endEcomID]->instanceID);
|
||||||
|
return EPData.find(mapNum) != EPData.end() && EPData[mapNum].EPID != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int calculateRaceScore(const EPInfo& epInfo, int podsCollected, int timeDiff) {
|
||||||
|
int score = std::exp(
|
||||||
|
(epInfo.podFactor * podsCollected) / epInfo.maxPods
|
||||||
|
- (epInfo.timeFactor * timeDiff) / epInfo.maxTime
|
||||||
|
+ epInfo.scaleFactor);
|
||||||
|
|
||||||
|
return (settings::IZRACESCORECAPPED && score > epInfo.maxScore)
|
||||||
|
? epInfo.maxScore : score;
|
||||||
|
}
|
||||||
|
|
||||||
|
int calculateFMReward(const EPInfo& epInfo, int podsCollected) {
|
||||||
|
return (1.0 + std::exp(epInfo.scaleFactor - 1.0) * epInfo.podFactor * podsCollected)
|
||||||
|
/ epInfo.maxPods;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleRaceRanking(const EPInfo& epInfo, Player* plr, int podsCollected,
|
||||||
|
int score, int timeDiff, sP_FE2CL_REP_EP_RACE_END_SUCC& resp) {
|
||||||
|
Database::RaceRanking postRanking = {
|
||||||
|
.EPID = epInfo.EPID,
|
||||||
|
.PlayerID = plr->iID,
|
||||||
|
.RingCount = podsCollected,
|
||||||
|
.Score = score,
|
||||||
|
.Time = timeDiff,
|
||||||
|
.Timestamp = getTimestamp()
|
||||||
|
};
|
||||||
|
Database::postRaceRanking(postRanking);
|
||||||
|
|
||||||
|
Database::RaceRanking topRankingPlayer = Database::getTopRaceRanking(epInfo.EPID, plr->iID);
|
||||||
|
|
||||||
|
std::vector<int>* rankScores = &EPRewards[epInfo.EPID].first;
|
||||||
|
std::vector<int>* rankRewards = &EPRewards[epInfo.EPID].second;
|
||||||
|
int maxRank = rankScores->size() - 1;
|
||||||
|
|
||||||
|
int topRank = 0;
|
||||||
|
while (topRank < maxRank && rankScores->at(topRank) > topRankingPlayer.Score)
|
||||||
|
topRank++;
|
||||||
|
|
||||||
|
int currentRank = 0;
|
||||||
|
while (currentRank < maxRank && rankScores->at(currentRank) > postRanking.Score)
|
||||||
|
currentRank++;
|
||||||
|
|
||||||
|
resp.iEPTopRank = topRank + 1;
|
||||||
|
resp.iEPTopRingCount = topRankingPlayer.RingCount;
|
||||||
|
resp.iEPTopScore = topRankingPlayer.Score;
|
||||||
|
resp.iEPTopTime = topRankingPlayer.Time;
|
||||||
|
resp.iEPRank = currentRank + 1;
|
||||||
|
resp.iEPRingCnt = postRanking.RingCount;
|
||||||
|
resp.iEPScore = postRanking.Score;
|
||||||
|
resp.iEPRaceTime = postRanking.Time;
|
||||||
|
|
||||||
|
if (currentRank <= maxRank) {
|
||||||
|
sItemReward reward;
|
||||||
|
reward.iSlotNum = Items::findFreeSlot(plr);
|
||||||
|
if (reward.iSlotNum > -1) {
|
||||||
|
reward.eIL = 1;
|
||||||
|
sItemBase item = {
|
||||||
|
.iID = rankRewards->at(currentRank),
|
||||||
|
.iType = 9,
|
||||||
|
.iOpt = 1,
|
||||||
|
.iTimeLimit = 0
|
||||||
|
};
|
||||||
|
reward.sItem = item;
|
||||||
|
if (reward.sItem.iID != 0) {
|
||||||
|
resp.RewardItem = reward;
|
||||||
|
plr->Inven[reward.iSlotNum] = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Racing::racingStart(CNSocket* sock, CNPacketData* data) {
|
||||||
auto req = (sP_CL2FE_REQ_EP_RACE_START*)data->buf;
|
auto req = (sP_CL2FE_REQ_EP_RACE_START*)data->buf;
|
||||||
|
|
||||||
if (NPCManager::NPCs.find(req->iStartEcomID) == NPCManager::NPCs.end())
|
if (!validateRaceStart(sock, req->iStartEcomID))
|
||||||
return; // starting line agent not found
|
return;
|
||||||
|
|
||||||
int mapNum = MAPNUM(NPCManager::NPCs[req->iStartEcomID]->instanceID);
|
int mapNum = MAPNUM(NPCManager::NPCs[req->iStartEcomID]->instanceID);
|
||||||
if (EPData.find(mapNum) == EPData.end() || EPData[mapNum].EPID == 0)
|
|
||||||
return; // IZ not found
|
|
||||||
|
|
||||||
// make ongoing race entry
|
EPRaces[sock] = {
|
||||||
EPRace race = { {}, req->iEPRaceMode, req->iEPTicketItemSlotNum, getTime() / 1000 };
|
std::set<int32_t>(),
|
||||||
EPRaces[sock] = race;
|
req->iEPRaceMode,
|
||||||
|
req->iEPTicketItemSlotNum,
|
||||||
|
getTime() / 1000
|
||||||
|
};
|
||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_REP_EP_RACE_START_SUCC, resp);
|
INITSTRUCT(sP_FE2CL_REP_EP_RACE_START_SUCC, resp);
|
||||||
resp.iStartTick = 0; // ignored
|
resp.iStartTick = 0;
|
||||||
resp.iLimitTime = EPData[mapNum].maxTime;
|
resp.iLimitTime = EPData[mapNum].maxTime;
|
||||||
|
|
||||||
sock->sendPacket(resp, P_FE2CL_REP_EP_RACE_START_SUCC);
|
sock->sendPacket(resp, P_FE2CL_REP_EP_RACE_START_SUCC);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void racingGetPod(CNSocket* sock, CNPacketData* data) {
|
static void racingGetPod(CNSocket* sock, CNPacketData* data) {
|
||||||
if (EPRaces.find(sock) == EPRaces.end())
|
if (EPRaces.find(sock) == EPRaces.end())
|
||||||
return; // race not found
|
return;
|
||||||
|
|
||||||
auto req = (sP_CL2FE_REQ_EP_GET_RING*)data->buf;
|
auto req = (sP_CL2FE_REQ_EP_GET_RING*)data->buf;
|
||||||
|
|
||||||
if (EPRaces[sock].collectedRings.count(req->iRingLID))
|
if (EPRaces[sock].collectedRings.count(req->iRingLID))
|
||||||
return; // can't collect the same ring twice
|
return;
|
||||||
|
|
||||||
// without an anticheat system, we really don't have a choice but to honor the request
|
// without an anticheat system, we really don't have a choice but to honor the request
|
||||||
// TODO: proximity check so players can't cheat the race by replaying packets
|
// TODO: proximity check so players can't cheat the race by replaying packets
|
||||||
@ -106,22 +194,11 @@ static void racingEnd(CNSocket* sock, CNPacketData* data) {
|
|||||||
int timeDiff = now - epRace.startTime;
|
int timeDiff = now - epRace.startTime;
|
||||||
int podsCollected = epRace.collectedRings.size();
|
int podsCollected = epRace.collectedRings.size();
|
||||||
|
|
||||||
int score = std::exp(
|
int score = calculateRaceScore(epInfo, podsCollected, timeDiff);
|
||||||
(epInfo.podFactor * podsCollected) / epInfo.maxPods
|
int fm = calculateFMReward(epInfo, podsCollected);
|
||||||
- (epInfo.timeFactor * timeDiff) / epInfo.maxTime
|
|
||||||
+ epInfo.scaleFactor);
|
|
||||||
score = (settings::IZRACESCORECAPPED && score > epInfo.maxScore) ? epInfo.maxScore : score;
|
|
||||||
int fm = (1.0 + std::exp(epInfo.scaleFactor - 1.0) * epInfo.podFactor * podsCollected) / epInfo.maxPods;
|
|
||||||
|
|
||||||
// we submit the ranking first...
|
// we submit the ranking first...
|
||||||
Database::RaceRanking postRanking = {};
|
handleRaceRanking(epInfo, plr, podsCollected, score, timeDiff, resp);
|
||||||
postRanking.EPID = epInfo.EPID;
|
|
||||||
postRanking.PlayerID = plr->iID;
|
|
||||||
postRanking.RingCount = podsCollected;
|
|
||||||
postRanking.Score = score;
|
|
||||||
postRanking.Time = timeDiff;
|
|
||||||
postRanking.Timestamp = getTimestamp();
|
|
||||||
Database::postRaceRanking(postRanking);
|
|
||||||
|
|
||||||
// ...then we get the top ranking, which may or may not be what we just submitted
|
// ...then we get the top ranking, which may or may not be what we just submitted
|
||||||
Database::RaceRanking topRankingPlayer = Database::getTopRaceRanking(epInfo.EPID, plr->iID);
|
Database::RaceRanking topRankingPlayer = Database::getTopRaceRanking(epInfo.EPID, plr->iID);
|
||||||
@ -145,13 +222,13 @@ static void racingEnd(CNSocket* sock, CNPacketData* data) {
|
|||||||
|
|
||||||
// this ranking
|
// this ranking
|
||||||
int rank = 0;
|
int rank = 0;
|
||||||
while (rank < maxRank && rankScores->at(rank) > postRanking.Score)
|
while (rank < maxRank && rankScores->at(rank) > score)
|
||||||
rank++;
|
rank++;
|
||||||
|
|
||||||
resp.iEPRank = rank + 1;
|
resp.iEPRank = rank + 1;
|
||||||
resp.iEPRingCnt = postRanking.RingCount;
|
resp.iEPRingCnt = podsCollected;
|
||||||
resp.iEPScore = postRanking.Score;
|
resp.iEPScore = score;
|
||||||
resp.iEPRaceTime = postRanking.Time;
|
resp.iEPRaceTime = timeDiff;
|
||||||
resp.iEPRaceMode = EPRaces[sock].mode;
|
resp.iEPRaceMode = EPRaces[sock].mode;
|
||||||
resp.iEPRewardFM = fm;
|
resp.iEPRewardFM = fm;
|
||||||
|
|
||||||
@ -161,21 +238,6 @@ static void racingEnd(CNSocket* sock, CNPacketData* data) {
|
|||||||
resp.iFatigue = 50;
|
resp.iFatigue = 50;
|
||||||
resp.iFatigue_Level = 1;
|
resp.iFatigue_Level = 1;
|
||||||
|
|
||||||
sItemReward reward;
|
|
||||||
reward.iSlotNum = Items::findFreeSlot(plr);
|
|
||||||
reward.eIL = 1;
|
|
||||||
sItemBase item;
|
|
||||||
item.iID = rankRewards->at(rank); // rank scores and rewards line up
|
|
||||||
item.iType = 9;
|
|
||||||
item.iOpt = 1;
|
|
||||||
item.iTimeLimit = 0;
|
|
||||||
reward.sItem = item;
|
|
||||||
|
|
||||||
if (reward.iSlotNum > -1 && reward.sItem.iID != 0) {
|
|
||||||
resp.RewardItem = reward;
|
|
||||||
plr->Inven[reward.iSlotNum] = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
EPRaces.erase(sock);
|
EPRaces.erase(sock);
|
||||||
sock->sendPacket(resp, P_FE2CL_REP_EP_RACE_END_SUCC);
|
sock->sendPacket(resp, P_FE2CL_REP_EP_RACE_END_SUCC);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user