-
Notifications
You must be signed in to change notification settings - Fork 65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update Racing.cpp #302
Update Racing.cpp #302
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,6 @@ | ||
#include "Racing.hpp" | ||
|
||
#include "db/Database.hpp" | ||
#include "servers/CNShardServer.hpp" | ||
|
||
#include "NPCManager.hpp" | ||
#include "PlayerManager.hpp" | ||
#include "Missions.hpp" | ||
|
@@ -14,35 +12,125 @@ std::map<int32_t, EPInfo> Racing::EPData; | |
std::map<CNSocket*, EPRace> Racing::EPRaces; | ||
std::map<int32_t, std::pair<std::vector<int>, std::vector<int>>> Racing::EPRewards; | ||
|
||
static void racingStart(CNSocket* sock, CNPacketData* data) { | ||
auto req = (sP_CL2FE_REQ_EP_RACE_START*)data->buf; | ||
namespace { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't use a namespace to isolate the helpers, just make them static so they're local to the file. This is the pattern we use in the rest of the codebase. |
||
// Helper functions | ||
bool validateRaceStart(CNSocket* sock, int32_t startEcomID) { | ||
if (NPCManager::NPCs.find(startEcomID) == NPCManager::NPCs.end()) | ||
return false; // starting line agent not found | ||
|
||
if (NPCManager::NPCs.find(req->iStartEcomID) == NPCManager::NPCs.end()) | ||
return; // starting line agent not found | ||
int mapNum = MAPNUM(NPCManager::NPCs[startEcomID]->instanceID); | ||
return EPData.find(mapNum) != EPData.end() && EPData[mapNum].EPID != 0; | ||
} | ||
Comment on lines
+17
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should validate that a player is not already in a race. |
||
|
||
int mapNum = MAPNUM(NPCManager::NPCs[req->iStartEcomID]->instanceID); | ||
if (EPData.find(mapNum) == EPData.end() || EPData[mapNum].EPID == 0) | ||
return; // IZ not found | ||
bool validateRaceEnd(CNSocket* sock, int32_t endEcomID) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're not actually using this helper in |
||
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; | ||
} | ||
|
||
// make ongoing race entry | ||
EPRace race = { {}, req->iEPRaceMode, req->iEPTicketItemSlotNum, getTime() / 1000 }; | ||
EPRaces[sock] = race; | ||
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; | ||
|
||
if (!validateRaceStart(sock, req->iStartEcomID)) | ||
return; | ||
|
||
int mapNum = MAPNUM(NPCManager::NPCs[req->iStartEcomID]->instanceID); | ||
|
||
EPRaces[sock] = { | ||
std::set<int32_t>(), | ||
req->iEPRaceMode, | ||
req->iEPTicketItemSlotNum, | ||
getTime() / 1000 | ||
}; | ||
|
||
INITSTRUCT(sP_FE2CL_REP_EP_RACE_START_SUCC, resp); | ||
resp.iStartTick = 0; // ignored | ||
resp.iStartTick = 0; | ||
resp.iLimitTime = EPData[mapNum].maxTime; | ||
|
||
sock->sendPacket(resp, P_FE2CL_REP_EP_RACE_START_SUCC); | ||
} | ||
|
||
static void racingGetPod(CNSocket* sock, CNPacketData* data) { | ||
if (EPRaces.find(sock) == EPRaces.end()) | ||
return; // race not found | ||
return; | ||
|
||
auto req = (sP_CL2FE_REQ_EP_GET_RING*)data->buf; | ||
|
||
if (EPRaces[sock].collectedRings.count(req->iRingLID)) | ||
return; // can't collect the same ring twice | ||
Comment on lines
-32
to
-45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think your formatter might have stripped these comments |
||
return; | ||
|
||
// 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 | ||
|
@@ -106,22 +194,11 @@ static void racingEnd(CNSocket* sock, CNPacketData* data) { | |
int timeDiff = now - epRace.startTime; | ||
int podsCollected = epRace.collectedRings.size(); | ||
|
||
int score = std::exp( | ||
(epInfo.podFactor * podsCollected) / epInfo.maxPods | ||
- (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; | ||
int score = calculateRaceScore(epInfo, podsCollected, timeDiff); | ||
int fm = calculateFMReward(epInfo, podsCollected); | ||
|
||
// we submit the ranking first... | ||
Database::RaceRanking postRanking = {}; | ||
postRanking.EPID = epInfo.EPID; | ||
postRanking.PlayerID = plr->iID; | ||
postRanking.RingCount = podsCollected; | ||
postRanking.Score = score; | ||
postRanking.Time = timeDiff; | ||
postRanking.Timestamp = getTimestamp(); | ||
Database::postRaceRanking(postRanking); | ||
handleRaceRanking(epInfo, plr, podsCollected, score, timeDiff, resp); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmmmmm |
||
|
||
// ...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); | ||
|
@@ -145,13 +222,13 @@ static void racingEnd(CNSocket* sock, CNPacketData* data) { | |
|
||
// this ranking | ||
int rank = 0; | ||
while (rank < maxRank && rankScores->at(rank) > postRanking.Score) | ||
while (rank < maxRank && rankScores->at(rank) > score) | ||
rank++; | ||
|
||
resp.iEPRank = rank + 1; | ||
resp.iEPRingCnt = postRanking.RingCount; | ||
resp.iEPScore = postRanking.Score; | ||
resp.iEPRaceTime = postRanking.Time; | ||
resp.iEPRingCnt = podsCollected; | ||
resp.iEPScore = score; | ||
resp.iEPRaceTime = timeDiff; | ||
resp.iEPRaceMode = EPRaces[sock].mode; | ||
resp.iEPRewardFM = fm; | ||
|
||
|
@@ -161,21 +238,6 @@ static void racingEnd(CNSocket* sock, CNPacketData* data) { | |
resp.iFatigue = 50; | ||
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); | ||
sock->sendPacket(resp, P_FE2CL_REP_EP_RACE_END_SUCC); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our headers are organized into a hierarchy to avoid things like cyclic inclusion. These spaces exist to indicate that, so please don't remove them.