Skip to content
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

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 111 additions & 49 deletions src/Racing.cpp
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"
Comment on lines 1 to 6
Copy link
Member

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.

Expand All @@ -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 {
Copy link
Member

Choose a reason for hiding this comment

The 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should validate that a player is not already in a race.
I would also recommend having an output argument for mapnum to avoid having to recalculate it in the packet handlers.


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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're not actually using this helper in Racing::racingEnd :P

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
Copy link
Member

Choose a reason for hiding this comment

The 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
Expand Down Expand Up @@ -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);
Copy link
Member

Choose a reason for hiding this comment

The 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);
Expand All @@ -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;

Expand All @@ -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);
}
Expand Down
Loading