mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-05 06:50:04 +00:00
[WIP] Incremental mission save 2
This commit (and the previous one) exist to document the first approach I took to storing mission data. It's only here for posterity. This comment was added while rebasing.
This commit is contained in:
parent
ae654f996c
commit
3665dc2c93
@ -4,9 +4,12 @@
|
|||||||
#include "PlayerManager.hpp"
|
#include "PlayerManager.hpp"
|
||||||
#include "ItemManager.hpp"
|
#include "ItemManager.hpp"
|
||||||
|
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
std::map<int32_t, Reward*> MissionManager::Rewards;
|
std::map<int32_t, Reward*> MissionManager::Rewards;
|
||||||
std::map<int32_t, SUItem*> MissionManager::SUItems;
|
std::map<int32_t, SUItem*> MissionManager::SUItems;
|
||||||
std::map<int32_t, QuestDropSet*> MissionManager::QuestDropSets;
|
std::map<int32_t, QuestDropSet*> MissionManager::QuestDropSets;
|
||||||
|
std::map<int32_t, ItemCleanup*> MissionManager::ItemCleanups;
|
||||||
|
|
||||||
void MissionManager::init() {
|
void MissionManager::init() {
|
||||||
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_START, acceptMission);
|
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_START, acceptMission);
|
||||||
@ -37,6 +40,22 @@ void MissionManager::completeTask(CNSocket* sock, CNPacketData* data) {
|
|||||||
response.iTaskNum = missionData->iTaskNum;
|
response.iTaskNum = missionData->iTaskNum;
|
||||||
std::cout << missionData->iTaskNum << std::endl;
|
std::cout << missionData->iTaskNum << std::endl;
|
||||||
|
|
||||||
|
// clean up quest items which have served their purpose
|
||||||
|
if (ItemCleanups.find(missionData->iTaskNum) != ItemCleanups.end()) {
|
||||||
|
ItemCleanup *clean = ItemCleanups[missionData->iTaskNum];
|
||||||
|
|
||||||
|
std::cout << "clearing qitems\n";
|
||||||
|
for (int i = 0; i < AQINVEN_COUNT; i++)
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if (plr->QInven[i].iID == clean->itemIds[j])
|
||||||
|
memset(&plr->QInven[i], 0, sizeof(sItemBase));
|
||||||
|
/*
|
||||||
|
* NOTE: As quest items are not graphically enumerated client-side,
|
||||||
|
* the client does not need to be notified of item cleanup, since
|
||||||
|
* the items will just be clobbered upon assignment anyway.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SUItems
|
* SUItems
|
||||||
*
|
*
|
||||||
@ -49,42 +68,104 @@ void MissionManager::completeTask(CNSocket* sock, CNPacketData* data) {
|
|||||||
if (SUItems.find(missionData->iTaskNum) != SUItems.end()) {
|
if (SUItems.find(missionData->iTaskNum) != SUItems.end()) {
|
||||||
SUItem *suitem = SUItems[missionData->iTaskNum];
|
SUItem *suitem = SUItems[missionData->iTaskNum];
|
||||||
|
|
||||||
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
for (int i = 0; i < 3; i++)
|
||||||
assert(resplen < CN_PACKET_BUFFER_SIZE);
|
if (suitem->itemIds[i] != 0)
|
||||||
// we know it's only one trailing struct, so we can skip full validation
|
dropQuestItem(sock, missionData->iTaskNum, 1, suitem->itemIds[i], 0);
|
||||||
|
|
||||||
uint8_t respbuf[resplen]; // not a variable length array, don't worry
|
|
||||||
sP_FE2CL_REP_REWARD_ITEM *reward = (sP_FE2CL_REP_REWARD_ITEM *)respbuf;
|
|
||||||
sItemReward *item = (sItemReward *)(respbuf + sizeof(sP_FE2CL_REP_REWARD_ITEM));
|
|
||||||
|
|
||||||
// don't forget to zero the buffer!
|
|
||||||
memset(respbuf, 0, resplen);
|
|
||||||
|
|
||||||
reward->m_iCandy = plr->money;
|
|
||||||
reward->m_iFusionMatter = plr->fusionmatter;
|
|
||||||
reward->iFatigue = 100; // prevents warning message
|
|
||||||
reward->iFatigue_Level = 1;
|
|
||||||
reward->iItemCnt = 1; // remember to update resplen if you change this
|
|
||||||
reward->iTaskID = missionData->iTaskNum;
|
|
||||||
reward->iNPC_TypeID = 0; // XXX
|
|
||||||
|
|
||||||
item->sItem.iType = 8;
|
|
||||||
item->sItem.iID = suitem->itemIds[0]; // XXX XXX XXX
|
|
||||||
item->sItem.iOpt = 1; // XXX count needs to be correct
|
|
||||||
item->iSlotNum = 0; // XXX
|
|
||||||
item->eIL = 2;
|
|
||||||
|
|
||||||
std::cout << "sending item packet\n";
|
|
||||||
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// mission rewards
|
// mission rewards
|
||||||
if (Rewards.find(missionData->iTaskNum) == Rewards.end()) {
|
if (Rewards.find(missionData->iTaskNum) != Rewards.end()) {
|
||||||
// not a mission's final task
|
giveMissionReward(sock, missionData->iTaskNum);
|
||||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_END_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_END_SUCC));
|
}
|
||||||
|
|
||||||
|
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_END_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_END_SUCC));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MissionManager::setMission(CNSocket* sock, CNPacketData* data) {
|
||||||
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID))
|
||||||
|
return; // malformed packet
|
||||||
|
|
||||||
|
sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID* missionData = (sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID*)data->buf;
|
||||||
|
INITSTRUCT(sP_FE2CL_REP_PC_SET_CURRENT_MISSION_ID, response);
|
||||||
|
|
||||||
|
response.iCurrentMissionID = missionData->iCurrentMissionID;
|
||||||
|
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_SET_CURRENT_MISSION_ID, sizeof(sP_FE2CL_REP_PC_SET_CURRENT_MISSION_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MissionManager::quitMission(CNSocket* sock, CNPacketData* data) {
|
||||||
|
if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_STOP))
|
||||||
|
return; // malformed packet
|
||||||
|
|
||||||
|
sP_CL2FE_REQ_PC_TASK_STOP* missionData = (sP_CL2FE_REQ_PC_TASK_STOP*)data->buf;
|
||||||
|
INITSTRUCT(sP_FE2CL_REP_PC_TASK_STOP_SUCC, response);
|
||||||
|
|
||||||
|
response.iTaskNum = missionData->iTaskNum;
|
||||||
|
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_STOP_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_STOP_SUCC));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: coalesce into ItemManager::findFreeSlot()?
|
||||||
|
int MissionManager::findFreeQSlot(Player *plr) {
|
||||||
|
int i;
|
||||||
|
sItemBase free;
|
||||||
|
|
||||||
|
memset(&free, 0, sizeof(sItemBase));
|
||||||
|
|
||||||
|
for (i = 0; i < AQINVEN_COUNT; i++)
|
||||||
|
if (memcmp(&plr->QInven[i], &free, sizeof(sItemBase)) == 0)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
// not found
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MissionManager::dropQuestItem(CNSocket *sock, int task, int count, int id, int mobid) {
|
||||||
|
const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward);
|
||||||
|
assert(resplen < CN_PACKET_BUFFER_SIZE);
|
||||||
|
// we know it's only one trailing struct, so we can skip full validation
|
||||||
|
|
||||||
|
uint8_t respbuf[resplen]; // not a variable length array, don't worry
|
||||||
|
sP_FE2CL_REP_REWARD_ITEM *reward = (sP_FE2CL_REP_REWARD_ITEM *)respbuf;
|
||||||
|
sItemReward *item = (sItemReward *)(respbuf + sizeof(sP_FE2CL_REP_REWARD_ITEM));
|
||||||
|
Player *plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
|
// don't forget to zero the buffer!
|
||||||
|
memset(respbuf, 0, resplen);
|
||||||
|
|
||||||
|
// find free quest item slot
|
||||||
|
int slot = findFreeQSlot(plr);
|
||||||
|
if (slot == -1) {
|
||||||
|
// this should never happen
|
||||||
|
std::cout << "[WARN] Player has no room for quest item!?" << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Reward *reward = Rewards[missionData->iTaskNum];
|
std::cout << "new qitem in slot " << slot << std::endl;
|
||||||
|
|
||||||
|
// update player
|
||||||
|
plr->QInven[slot].iType = 8;
|
||||||
|
plr->QInven[slot].iID = id;
|
||||||
|
plr->QInven[slot].iOpt = count;
|
||||||
|
|
||||||
|
// preserve stats
|
||||||
|
reward->m_iCandy = plr->money;
|
||||||
|
reward->m_iFusionMatter = plr->fusionmatter;
|
||||||
|
reward->iFatigue = 100; // prevents warning message
|
||||||
|
reward->iFatigue_Level = 1;
|
||||||
|
|
||||||
|
reward->iItemCnt = 1; // remember to update resplen if you change this
|
||||||
|
reward->iTaskID = task;
|
||||||
|
reward->iNPC_TypeID = mobid;
|
||||||
|
|
||||||
|
item->sItem = plr->QInven[slot];
|
||||||
|
item->iSlotNum = slot;
|
||||||
|
item->eIL = 2;
|
||||||
|
|
||||||
|
std::cout << "sending quest item\n";
|
||||||
|
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MissionManager::giveMissionReward(CNSocket *sock, int task) {
|
||||||
|
Reward *reward = Rewards[task];
|
||||||
|
Player *plr = PlayerManager::getPlayer(sock);
|
||||||
|
|
||||||
int nrewards = 0;
|
int nrewards = 0;
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
@ -99,7 +180,7 @@ void MissionManager::completeTask(CNSocket* sock, CNPacketData* data) {
|
|||||||
std::cout << "Not enough room to complete task" << std::endl;
|
std::cout << "Not enough room to complete task" << std::endl;
|
||||||
INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_FAIL, fail);
|
INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_FAIL, fail);
|
||||||
|
|
||||||
fail.iTaskNum = missionData->iTaskNum;
|
fail.iTaskNum = task;
|
||||||
fail.iErrorCode = 13; // inventory full
|
fail.iErrorCode = 13; // inventory full
|
||||||
|
|
||||||
sock->sendPacket((void*)&fail, P_FE2CL_REP_PC_TASK_END_FAIL, sizeof(sP_FE2CL_REP_PC_TASK_END_FAIL));
|
sock->sendPacket((void*)&fail, P_FE2CL_REP_PC_TASK_END_FAIL, sizeof(sP_FE2CL_REP_PC_TASK_END_FAIL));
|
||||||
@ -137,30 +218,5 @@ void MissionManager::completeTask(CNSocket* sock, CNPacketData* data) {
|
|||||||
plr->Inven[slots[i]] = item->sItem;
|
plr->Inven[slots[i]] = item->sItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_END_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_END_SUCC));
|
|
||||||
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MissionManager::setMission(CNSocket* sock, CNPacketData* data) {
|
|
||||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID))
|
|
||||||
return; // malformed packet
|
|
||||||
|
|
||||||
sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID* missionData = (sP_CL2FE_REQ_PC_SET_CURRENT_MISSION_ID*)data->buf;
|
|
||||||
INITSTRUCT(sP_FE2CL_REP_PC_SET_CURRENT_MISSION_ID, response);
|
|
||||||
|
|
||||||
response.iCurrentMissionID = missionData->iCurrentMissionID;
|
|
||||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_SET_CURRENT_MISSION_ID, sizeof(sP_FE2CL_REP_PC_SET_CURRENT_MISSION_ID));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MissionManager::quitMission(CNSocket* sock, CNPacketData* data) {
|
|
||||||
if (data->size != sizeof(sP_CL2FE_REQ_PC_TASK_STOP))
|
|
||||||
return; // malformed packet
|
|
||||||
|
|
||||||
sP_CL2FE_REQ_PC_TASK_STOP* missionData = (sP_CL2FE_REQ_PC_TASK_STOP*)data->buf;
|
|
||||||
INITSTRUCT(sP_FE2CL_REP_PC_TASK_STOP_SUCC, response);
|
|
||||||
|
|
||||||
response.iTaskNum = missionData->iTaskNum;
|
|
||||||
sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_STOP_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_STOP_SUCC));
|
|
||||||
}
|
|
||||||
|
|
||||||
//void MissionManager::dropQuestItem(CNSocket *sock, int mobid, int count) {}
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CNShardServer.hpp"
|
#include "CNShardServer.hpp"
|
||||||
|
#include "Player.hpp"
|
||||||
|
|
||||||
#include "contrib/JSON.hpp"
|
#include "contrib/JSON.hpp"
|
||||||
|
|
||||||
@ -42,14 +43,29 @@ struct QuestDropSet {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ItemCleanup {
|
||||||
|
int32_t itemIds[4];
|
||||||
|
|
||||||
|
ItemCleanup(nlohmann::json ids) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
itemIds[i] = ids[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
namespace MissionManager {
|
namespace MissionManager {
|
||||||
extern std::map<int32_t, Reward*> Rewards;
|
extern std::map<int32_t, Reward*> Rewards;
|
||||||
extern std::map<int32_t, SUItem*> SUItems;
|
extern std::map<int32_t, SUItem*> SUItems;
|
||||||
extern std::map<int32_t, QuestDropSet*> QuestDropSets;
|
extern std::map<int32_t, QuestDropSet*> QuestDropSets;
|
||||||
|
extern std::map<int32_t, ItemCleanup*> ItemCleanups;
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
void acceptMission(CNSocket* sock, CNPacketData* data);
|
void acceptMission(CNSocket* sock, CNPacketData* data);
|
||||||
void completeTask(CNSocket* sock, CNPacketData* data);
|
void completeTask(CNSocket* sock, CNPacketData* data);
|
||||||
void setMission(CNSocket* sock, CNPacketData* data);
|
void setMission(CNSocket* sock, CNPacketData* data);
|
||||||
void quitMission(CNSocket* sock, CNPacketData* data);
|
void quitMission(CNSocket* sock, CNPacketData* data);
|
||||||
|
|
||||||
|
int findFreeQSlot(Player *plr);
|
||||||
|
void dropQuestItem(CNSocket *sock, int task, int count, int id, int mobid);
|
||||||
|
void giveMissionReward(CNSocket *sock, int task);
|
||||||
}
|
}
|
||||||
|
@ -32,4 +32,7 @@ struct Player {
|
|||||||
bool isTrading;
|
bool isTrading;
|
||||||
bool isTradeConfirm;
|
bool isTradeConfirm;
|
||||||
bool IsGM;
|
bool IsGM;
|
||||||
|
|
||||||
|
int tasks[6];
|
||||||
|
sItemBase QInven[AQINVEN_COUNT];
|
||||||
};
|
};
|
||||||
|
@ -12,7 +12,6 @@ void TableData::init() {
|
|||||||
|
|
||||||
// load NPCs from NPC.json
|
// load NPCs from NPC.json
|
||||||
try {
|
try {
|
||||||
|
|
||||||
std::ifstream inFile(settings::NPCJSON);
|
std::ifstream inFile(settings::NPCJSON);
|
||||||
nlohmann::json npcData;
|
nlohmann::json npcData;
|
||||||
|
|
||||||
@ -39,7 +38,7 @@ void TableData::init() {
|
|||||||
|
|
||||||
// load temporary mob dump
|
// load temporary mob dump
|
||||||
try {
|
try {
|
||||||
std::ifstream inFile(settings::MOBJSON); // not in settings, since it's temp
|
std::ifstream inFile(settings::MOBJSON);
|
||||||
nlohmann::json npcData;
|
nlohmann::json npcData;
|
||||||
|
|
||||||
// read file into json
|
// read file into json
|
||||||
@ -82,7 +81,7 @@ void TableData::init() {
|
|||||||
|
|
||||||
std::cout << "[INFO] populated " << NPCManager::Warps.size() << " Warps" << std::endl;
|
std::cout << "[INFO] populated " << NPCManager::Warps.size() << " Warps" << std::endl;
|
||||||
|
|
||||||
// missions
|
// load mission-related data
|
||||||
nlohmann::json tasks = xdtData["m_pMissionTable"]["m_pMissionData"];
|
nlohmann::json tasks = xdtData["m_pMissionTable"]["m_pMissionData"];
|
||||||
|
|
||||||
for (auto _task = tasks.begin(); _task != tasks.end(); _task++) {
|
for (auto _task = tasks.begin(); _task != tasks.end(); _task++) {
|
||||||
@ -99,9 +98,8 @@ void TableData::init() {
|
|||||||
|
|
||||||
// quest items obtained after completing a certain task
|
// quest items obtained after completing a certain task
|
||||||
// (distinct from quest items dropped from mobs)
|
// (distinct from quest items dropped from mobs)
|
||||||
if (task["m_iSUItem"][0] != 0) {
|
if (task["m_iSUItem"][0] != 0)
|
||||||
MissionManager::SUItems[task["m_iHTaskID"]] = new SUItem(task["m_iSUItem"]);
|
MissionManager::SUItems[task["m_iHTaskID"]] = new SUItem(task["m_iSUItem"]);
|
||||||
}
|
|
||||||
|
|
||||||
// quest item mob drops
|
// quest item mob drops
|
||||||
if (task["m_iCSUItemID"][0] != 0) {
|
if (task["m_iCSUItemID"][0] != 0) {
|
||||||
@ -109,6 +107,12 @@ void TableData::init() {
|
|||||||
// TODO: timeouts, drop rates, etc.
|
// TODO: timeouts, drop rates, etc.
|
||||||
// not sure if we need to keep track of NumNeeded/NumToKill server-side.
|
// not sure if we need to keep track of NumNeeded/NumToKill server-side.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// quest item cleanup
|
||||||
|
if (task["m_iDelItemID"][0] != 0) {
|
||||||
|
std::cout << "adding DelItem for " << task["m_iHTaskID"] << std::endl;
|
||||||
|
MissionManager::ItemCleanups[task["m_iHTaskID"]] = new ItemCleanup(task["m_iDelItemID"]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "[INFO] Loaded mission-related data" << std::endl;
|
std::cout << "[INFO] Loaded mission-related data" << std::endl;
|
||||||
@ -129,4 +133,6 @@ void TableData::cleanup() {
|
|||||||
delete pair.second;
|
delete pair.second;
|
||||||
for (auto& pair : MissionManager::QuestDropSets)
|
for (auto& pair : MissionManager::QuestDropSets)
|
||||||
delete pair.second;
|
delete pair.second;
|
||||||
|
for (auto& pair : MissionManager::ItemCleanups)
|
||||||
|
delete pair.second;
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,9 @@ void terminate(int arg) {
|
|||||||
std::cout << "OpenFusion: terminating." << std::endl;
|
std::cout << "OpenFusion: terminating." << std::endl;
|
||||||
shardServer->kill();
|
shardServer->kill();
|
||||||
shardThread->join();
|
shardThread->join();
|
||||||
|
#if defined(__SANITIZE_ADDRESS__) || (defined(__has_feature) && __has_feature(address_sanitizer))
|
||||||
TableData::cleanup();
|
TableData::cleanup();
|
||||||
|
#endif
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#define AEQUIP_COUNT 9
|
#define AEQUIP_COUNT 9
|
||||||
#define AINVEN_COUNT 50
|
#define AINVEN_COUNT 50
|
||||||
|
#define AQINVEN_COUNT 50
|
||||||
|
|
||||||
#pragma pack(push)
|
#pragma pack(push)
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#define AEQUIP_COUNT 12
|
#define AEQUIP_COUNT 12
|
||||||
#define AINVEN_COUNT 50
|
#define AINVEN_COUNT 50
|
||||||
|
#define AQINVEN_COUNT 50
|
||||||
|
|
||||||
#pragma pack(push)
|
#pragma pack(push)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user