mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Rewritten many parts of query handling. Fixed several scenarios leading to a hang (including #1012). Purged boost::function from player interface (handy but impossible to serialize). VCAI will keep description for each unanswered query, so the further debugging will be easier.
This commit is contained in:
parent
ab0a384d31
commit
edccbd4809
@ -12,14 +12,15 @@ void CEmptyAI::yourTurn()
|
|||||||
{
|
{
|
||||||
cb->endTurn();
|
cb->endTurn();
|
||||||
}
|
}
|
||||||
void CEmptyAI::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback)
|
|
||||||
|
void CEmptyAI::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, int queryID)
|
||||||
{
|
{
|
||||||
callback(rand()%skills.size());
|
cb->selectionMade(rand() % skills.size(), queryID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEmptyAI::commanderGotLevel(const CCommanderInstance * commander, std::vector<ui32> skills, boost::function<void(ui32)> &callback)
|
void CEmptyAI::commanderGotLevel(const CCommanderInstance * commander, std::vector<ui32> skills, int queryID)
|
||||||
{
|
{
|
||||||
callback(0);
|
cb->selectionMade(rand() % skills.size(), queryID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEmptyAI::showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel)
|
void CEmptyAI::showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel)
|
||||||
@ -27,7 +28,7 @@ void CEmptyAI::showBlockingDialog(const std::string &text, const std::vector<Com
|
|||||||
cb->selectionMade(0, askID);
|
cb->selectionMade(0, askID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEmptyAI::showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd)
|
void CEmptyAI::showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, int queryID)
|
||||||
{
|
{
|
||||||
onEnd();
|
cb->selectionMade(0, queryID);
|
||||||
}
|
}
|
@ -12,10 +12,10 @@ class CEmptyAI : public CGlobalAI
|
|||||||
public:
|
public:
|
||||||
void init(CCallback * CB) override;
|
void init(CCallback * CB) override;
|
||||||
void yourTurn() override;
|
void yourTurn() override;
|
||||||
void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback) override;
|
void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, int queryID) override;
|
||||||
void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, boost::function<void(ui32)> &callback) override;
|
void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, int queryID) override;
|
||||||
void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) override;
|
void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) override;
|
||||||
void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd) override;
|
void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, int queryID) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NAME "EmptyAI 0.1"
|
#define NAME "EmptyAI 0.1"
|
||||||
|
116
AI/VCAI/VCAI.cpp
116
AI/VCAI/VCAI.cpp
@ -733,7 +733,7 @@ void VCAI::requestRealized(PackageApplied *pa)
|
|||||||
|
|
||||||
if(pa->packType == typeList.getTypeID<QueryReply>())
|
if(pa->packType == typeList.getTypeID<QueryReply>())
|
||||||
{
|
{
|
||||||
status.removeQuery();
|
status.receivedAnswerConfirmation(pa->requestID, pa->result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -829,20 +829,20 @@ void VCAI::yourTurn()
|
|||||||
makingTurn = new boost::thread(&VCAI::makeTurn, this);
|
makingTurn = new boost::thread(&VCAI::makeTurn, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCAI::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback)
|
void VCAI::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, int queryID)
|
||||||
{
|
{
|
||||||
NET_EVENT_HANDLER;
|
NET_EVENT_HANDLER;
|
||||||
LOG_ENTRY;
|
LOG_ENTRY;
|
||||||
status.addQuery();
|
status.addQuery(queryID, boost::str(boost::format("Hero %s got level %d") % hero->name % hero->level));
|
||||||
requestActionASAP(boost::bind(callback, 0));
|
requestActionASAP([=]{ answerQuery(queryID, 0); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCAI::commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, boost::function<void(ui32)> &callback)
|
void VCAI::commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, int queryID)
|
||||||
{
|
{
|
||||||
NET_EVENT_HANDLER;
|
NET_EVENT_HANDLER;
|
||||||
LOG_ENTRY;
|
LOG_ENTRY;
|
||||||
status.addQuery();
|
status.addQuery(queryID, boost::str(boost::format("Commander %s of %s got level %d") % commander->name % commander->armyObj->nodeName() % (int)commander->level));
|
||||||
requestActionASAP(boost::bind(callback, 0));
|
requestActionASAP([=]{ answerQuery(queryID, 0); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCAI::showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel)
|
void VCAI::showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel)
|
||||||
@ -850,7 +850,8 @@ void VCAI::showBlockingDialog(const std::string &text, const std::vector<Compone
|
|||||||
NET_EVENT_HANDLER;
|
NET_EVENT_HANDLER;
|
||||||
LOG_ENTRY;
|
LOG_ENTRY;
|
||||||
int sel = 0;
|
int sel = 0;
|
||||||
status.addQuery();
|
status.addQuery(askID, boost::str(boost::format("Blocking dialog query with %d components - %s")
|
||||||
|
% components.size() % text));
|
||||||
|
|
||||||
if(selection) //select from multiple components -> take the last one (they're indexed [1-size])
|
if(selection) //select from multiple components -> take the last one (they're indexed [1-size])
|
||||||
sel = components.size();
|
sel = components.size();
|
||||||
@ -860,21 +861,25 @@ void VCAI::showBlockingDialog(const std::string &text, const std::vector<Compone
|
|||||||
|
|
||||||
requestActionASAP([=]()
|
requestActionASAP([=]()
|
||||||
{
|
{
|
||||||
cb->selectionMade(sel, askID);
|
answerQuery(askID, sel);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCAI::showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd)
|
void VCAI::showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, int queryID)
|
||||||
{
|
{
|
||||||
NET_EVENT_HANDLER;
|
NET_EVENT_HANDLER;
|
||||||
LOG_ENTRY;
|
LOG_ENTRY;
|
||||||
status.addQuery();
|
|
||||||
|
std::string s1 = up ? up->nodeName() : "NONE";
|
||||||
|
std::string s2 = down ? down->nodeName() : "NONE";
|
||||||
|
|
||||||
|
status.addQuery(queryID, boost::str(boost::format("Garrison dialog with %s and %s") % s1 % s2));
|
||||||
|
|
||||||
//you can't request action from action-response thread
|
//you can't request action from action-response thread
|
||||||
requestActionASAP([=]()
|
requestActionASAP([=]()
|
||||||
{
|
{
|
||||||
pickBestCreatures (down, up);
|
pickBestCreatures (down, up);
|
||||||
onEnd();
|
answerQuery(queryID, 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2197,6 +2202,9 @@ void VCAI::finish()
|
|||||||
|
|
||||||
void VCAI::requestActionASAP(boost::function<void()> whatToDo)
|
void VCAI::requestActionASAP(boost::function<void()> whatToDo)
|
||||||
{
|
{
|
||||||
|
// static boost::mutex m;
|
||||||
|
// boost::unique_lock<boost::mutex> mylock(m);
|
||||||
|
|
||||||
boost::barrier b(2);
|
boost::barrier b(2);
|
||||||
boost::thread newThread([&b,this,whatToDo]()
|
boost::thread newThread([&b,this,whatToDo]()
|
||||||
{
|
{
|
||||||
@ -2221,10 +2229,32 @@ void VCAI::lostHero(HeroPtr h)
|
|||||||
remove_if_present(reservedHeroesMap, h);
|
remove_if_present(reservedHeroesMap, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VCAI::answerQuery(int queryID, int selection)
|
||||||
|
{
|
||||||
|
BNLOG("I'll answer the query %d giving the choice %d", queryID % selection);
|
||||||
|
if(queryID != -1)
|
||||||
|
{
|
||||||
|
int requestID = cb->selectionMade(selection, queryID);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BNLOG("Since the query ID is %d, the answer won't be sent. This is not a real query!", queryID);
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VCAI::requestSent(const CPackForServer *pack, int requestID)
|
||||||
|
{
|
||||||
|
//BNLOG("I have sent request of type %s", typeid(*pack).name());
|
||||||
|
if(auto reply = dynamic_cast<const QueryReply*>(pack))
|
||||||
|
{
|
||||||
|
status.attemptedAnsweringQuery(reply->qid, requestID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AIStatus::AIStatus()
|
AIStatus::AIStatus()
|
||||||
{
|
{
|
||||||
battle = NO_BATTLE;
|
battle = NO_BATTLE;
|
||||||
remainingQueries = 0;
|
|
||||||
havingTurn = false;
|
havingTurn = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2246,29 +2276,38 @@ BattleState AIStatus::getBattle()
|
|||||||
return battle;
|
return battle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIStatus::addQueries(int val)
|
void AIStatus::addQuery(int ID, std::string description)
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::mutex> lock(mx);
|
boost::unique_lock<boost::mutex> lock(mx);
|
||||||
remainingQueries += val;
|
if(ID == -1)
|
||||||
BNLOG("Changing count of queries by %d, to a total of %d", val % remainingQueries);
|
{
|
||||||
assert(remainingQueries >= 0);
|
BNLOG("The \"query\" has an id %d, it'll be ignored as non-query. Description: %s", ID % description);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!vstd::contains(remainingQueries, ID));
|
||||||
|
assert(ID >= 0);
|
||||||
|
|
||||||
|
remainingQueries[ID] = description;
|
||||||
cv.notify_all();
|
cv.notify_all();
|
||||||
|
BNLOG("Adding query %d - %s. Total queries count: %d", ID % description % remainingQueries.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIStatus::addQuery()
|
void AIStatus::removeQuery(int ID)
|
||||||
{
|
{
|
||||||
addQueries(1);
|
boost::unique_lock<boost::mutex> lock(mx);
|
||||||
}
|
assert(vstd::contains(remainingQueries, ID));
|
||||||
|
|
||||||
void AIStatus::removeQuery()
|
std::string description = remainingQueries[ID];
|
||||||
{
|
remainingQueries.erase(ID);
|
||||||
addQueries(-1);
|
cv.notify_all();
|
||||||
|
BNLOG("Removing query %d - %s. Total queries count: %d", ID % description % remainingQueries.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
int AIStatus::getQueriesCount()
|
int AIStatus::getQueriesCount()
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::mutex> lock(mx);
|
boost::unique_lock<boost::mutex> lock(mx);
|
||||||
return remainingQueries;
|
return remainingQueries.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIStatus::startedTurn()
|
void AIStatus::startedTurn()
|
||||||
@ -2288,7 +2327,7 @@ void AIStatus::madeTurn()
|
|||||||
void AIStatus::waitTillFree()
|
void AIStatus::waitTillFree()
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::mutex> lock(mx);
|
boost::unique_lock<boost::mutex> lock(mx);
|
||||||
while(battle != NO_BATTLE || remainingQueries)
|
while(battle != NO_BATTLE || remainingQueries.size())
|
||||||
cv.wait(lock);
|
cv.wait(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2298,6 +2337,33 @@ bool AIStatus::haveTurn()
|
|||||||
return havingTurn;
|
return havingTurn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AIStatus::attemptedAnsweringQuery(int queryID, int answerRequestID)
|
||||||
|
{
|
||||||
|
boost::unique_lock<boost::mutex> lock(mx);
|
||||||
|
assert(vstd::contains(remainingQueries, queryID));
|
||||||
|
std::string description = remainingQueries[queryID];
|
||||||
|
BNLOG("Attempted answering query %d - %s. Request id=%d. Waiting for results...", queryID % description % answerRequestID);
|
||||||
|
requestToQueryID[answerRequestID] = queryID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AIStatus::receivedAnswerConfirmation(int answerRequestID, int result)
|
||||||
|
{
|
||||||
|
assert(vstd::contains(requestToQueryID, answerRequestID));
|
||||||
|
int query = requestToQueryID[answerRequestID];
|
||||||
|
assert(vstd::contains(remainingQueries, query));
|
||||||
|
requestToQueryID.erase(answerRequestID);
|
||||||
|
|
||||||
|
if(result)
|
||||||
|
{
|
||||||
|
removeQuery(query);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tlog1 << "Something went really wrong, failed to answer query " << query << ": " << remainingQueries[query];
|
||||||
|
//TODO safely retry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int3 whereToExplore(HeroPtr h)
|
int3 whereToExplore(HeroPtr h)
|
||||||
{
|
{
|
||||||
//TODO it's stupid and ineffective, write sth better
|
//TODO it's stupid and ineffective, write sth better
|
||||||
|
@ -44,7 +44,9 @@ class AIStatus
|
|||||||
boost::condition_variable cv;
|
boost::condition_variable cv;
|
||||||
|
|
||||||
BattleState battle;
|
BattleState battle;
|
||||||
int remainingQueries;
|
std::map<int, std::string> remainingQueries;
|
||||||
|
std::map<int, int> requestToQueryID; //IDs of answer-requests sent to server => query ids (so we can match answer confirmation from server to the query)
|
||||||
|
|
||||||
bool havingTurn;
|
bool havingTurn;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -52,14 +54,15 @@ public:
|
|||||||
~AIStatus();
|
~AIStatus();
|
||||||
void setBattle(BattleState BS);
|
void setBattle(BattleState BS);
|
||||||
BattleState getBattle();
|
BattleState getBattle();
|
||||||
void addQueries(int val);
|
void addQuery(int ID, std::string description);
|
||||||
void addQuery();
|
void removeQuery(int ID);
|
||||||
void removeQuery();
|
|
||||||
int getQueriesCount();
|
int getQueriesCount();
|
||||||
void startedTurn();
|
void startedTurn();
|
||||||
void madeTurn();
|
void madeTurn();
|
||||||
void waitTillFree();
|
void waitTillFree();
|
||||||
bool haveTurn();
|
bool haveTurn();
|
||||||
|
void attemptedAnsweringQuery(int queryID, int answerRequestID);
|
||||||
|
void receivedAnswerConfirmation(int answerRequestID, int result);
|
||||||
};
|
};
|
||||||
|
|
||||||
enum EGoals
|
enum EGoals
|
||||||
@ -245,10 +248,11 @@ public:
|
|||||||
|
|
||||||
virtual void init(CCallback * CB);
|
virtual void init(CCallback * CB);
|
||||||
virtual void yourTurn();
|
virtual void yourTurn();
|
||||||
virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback) OVERRIDE; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
|
|
||||||
virtual void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, boost::function<void(ui32)> &callback) OVERRIDE; //TODO
|
virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, int queryID) OVERRIDE; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
|
||||||
|
virtual void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, int queryID) OVERRIDE; //TODO
|
||||||
virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) OVERRIDE; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
|
virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) OVERRIDE; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
|
||||||
virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd) OVERRIDE; //all stacks operations between these objects become allowed, interface has to call onEnd when done
|
virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, int queryID) OVERRIDE; //all stacks operations between these objects become allowed, interface has to call onEnd when done
|
||||||
virtual void serialize(COSer<CSaveFile> &h, const int version) OVERRIDE; //saving
|
virtual void serialize(COSer<CSaveFile> &h, const int version) OVERRIDE; //saving
|
||||||
virtual void serialize(CISer<CLoadFile> &h, const int version) OVERRIDE; //loading
|
virtual void serialize(CISer<CLoadFile> &h, const int version) OVERRIDE; //loading
|
||||||
virtual void finish() OVERRIDE;
|
virtual void finish() OVERRIDE;
|
||||||
@ -353,6 +357,8 @@ public:
|
|||||||
TResources estimateIncome() const;
|
TResources estimateIncome() const;
|
||||||
bool containsSavedRes(const TResources &cost) const;
|
bool containsSavedRes(const TResources &cost) const;
|
||||||
|
|
||||||
|
void requestSent(const CPackForServer *pack, int requestID) OVERRIDE;
|
||||||
|
void answerQuery(int queryID, int selection);
|
||||||
//special function that can be called ONLY from game events handling thread and will send request ASAP
|
//special function that can be called ONLY from game events handling thread and will send request ASAP
|
||||||
void requestActionASAP(boost::function<void()> whatToDo);
|
void requestActionASAP(boost::function<void()> whatToDo);
|
||||||
};
|
};
|
||||||
|
@ -55,12 +55,20 @@ bool CCallback::moveHero(const CGHeroInstance *h, int3 dst)
|
|||||||
sendRequest(&pack);
|
sendRequest(&pack);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
void CCallback::selectionMade(int selection, int asker)
|
|
||||||
|
int CCallback::selectionMade(int selection, int queryID)
|
||||||
{
|
{
|
||||||
QueryReply pack(asker,selection);
|
if(queryID == -1)
|
||||||
|
{
|
||||||
|
tlog1 << "Cannot answer the query -1!\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryReply pack(queryID,selection);
|
||||||
pack.player = player;
|
pack.player = player;
|
||||||
sendRequest(&pack);
|
return sendRequest(&pack);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCallback::recruitCreatures(const CGObjectInstance *obj, ui32 ID, ui32 amount, si32 level/*=-1*/)
|
void CCallback::recruitCreatures(const CGObjectInstance *obj, ui32 ID, ui32 amount, si32 level/*=-1*/)
|
||||||
{
|
{
|
||||||
if(player!=obj->tempOwner && obj->ID != 106)
|
if(player!=obj->tempOwner && obj->ID != 106)
|
||||||
@ -182,7 +190,7 @@ int CBattleCallback::battleMakeAction(BattleAction* action)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBattleCallback::sendRequest(const CPack* request)
|
int CBattleCallback::sendRequest(const CPack *request)
|
||||||
{
|
{
|
||||||
int requestID = cl->sendRequest(request, player);
|
int requestID = cl->sendRequest(request, player);
|
||||||
if(waitTillRealize)
|
if(waitTillRealize)
|
||||||
@ -191,6 +199,8 @@ void CBattleCallback::sendRequest(const CPack* request)
|
|||||||
auto gsUnlocker = vstd::makeUnlockSharedGuardIf(getGsMutex(), unlockGsWhenWaiting);
|
auto gsUnlocker = vstd::makeUnlockSharedGuardIf(getGsMutex(), unlockGsWhenWaiting);
|
||||||
cl->waitingRequest.waitWhileContains(requestID);
|
cl->waitingRequest.waitWhileContains(requestID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return requestID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCallback::swapGarrisonHero( const CGTownInstance *town )
|
void CCallback::swapGarrisonHero( const CGTownInstance *town )
|
||||||
@ -378,4 +388,4 @@ bool CBattleCallback::battleMakeTacticAction( BattleAction * action )
|
|||||||
ma.ba = *action;
|
ma.ba = *action;
|
||||||
sendRequest(&ma);
|
sendRequest(&ma);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
10
CCallback.h
10
CCallback.h
@ -56,7 +56,7 @@ public:
|
|||||||
|
|
||||||
virtual void trade(const CGObjectInstance *market, int mode, int id1, int id2, int val1, const CGHeroInstance *hero = NULL)=0; //mode==0: sell val1 units of id1 resource for id2 resiurce
|
virtual void trade(const CGObjectInstance *market, int mode, int id1, int id2, int val1, const CGHeroInstance *hero = NULL)=0; //mode==0: sell val1 units of id1 resource for id2 resiurce
|
||||||
|
|
||||||
virtual void selectionMade(int selection, int asker) =0;
|
virtual int selectionMade(int selection, int queryID) =0;
|
||||||
virtual int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2)=0;//swaps creatures between two possibly different garrisons // TODO: AI-unsafe code - fix it!
|
virtual int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2)=0;//swaps creatures between two possibly different garrisons // TODO: AI-unsafe code - fix it!
|
||||||
virtual int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2)=0;//joins first stack to the second (creatures must be same type)
|
virtual int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2)=0;//joins first stack to the second (creatures must be same type)
|
||||||
virtual int mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2) =0; //first goes to the second
|
virtual int mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2) =0; //first goes to the second
|
||||||
@ -83,16 +83,15 @@ class CBattleCallback : public IBattleCallback, public CBattleInfoCallback
|
|||||||
private:
|
private:
|
||||||
CBattleCallback(CGameState *GS, int Player, CClient *C);
|
CBattleCallback(CGameState *GS, int Player, CClient *C);
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void sendRequest(const CPack *request);
|
int sendRequest(const CPack *request); //returns requestID (that'll be matched to requestID in PackageApplied)
|
||||||
CClient *cl;
|
CClient *cl;
|
||||||
//virtual bool hasAccess(int playerId) const;
|
//virtual bool hasAccess(int playerId) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int battleMakeAction(BattleAction* action) OVERRIDE;//for casting spells by hero - DO NOT use it for moving active stack
|
int battleMakeAction(BattleAction* action) OVERRIDE;//for casting spells by hero - DO NOT use it for moving active stack
|
||||||
bool battleMakeTacticAction(BattleAction * action) OVERRIDE; // performs tactic phase actions
|
bool battleMakeTacticAction(BattleAction * action) OVERRIDE; // performs tactic phase actions
|
||||||
|
|
||||||
friend class CCallback;
|
friend class CCallback;
|
||||||
friend class CClient;
|
friend class CClient;
|
||||||
};
|
};
|
||||||
@ -114,12 +113,13 @@ public:
|
|||||||
virtual void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int3 src = int3(-1,-1,-1), int movement = -1);
|
virtual void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int3 src = int3(-1,-1,-1), int movement = -1);
|
||||||
virtual void recalculatePaths(); //updates main, client pathfinder info (should be called when moving hero is over)
|
virtual void recalculatePaths(); //updates main, client pathfinder info (should be called when moving hero is over)
|
||||||
|
|
||||||
|
|
||||||
void unregisterMyInterface(); //stops delivering information about game events to that player's interface -> can be called ONLY after victory/loss
|
void unregisterMyInterface(); //stops delivering information about game events to that player's interface -> can be called ONLY after victory/loss
|
||||||
|
|
||||||
//commands
|
//commands
|
||||||
bool moveHero(const CGHeroInstance *h, int3 dst); //dst must be free, neighbouring tile (this function can move hero only by one tile)
|
bool moveHero(const CGHeroInstance *h, int3 dst); //dst must be free, neighbouring tile (this function can move hero only by one tile)
|
||||||
bool teleportHero(const CGHeroInstance *who, const CGTownInstance *where);
|
bool teleportHero(const CGHeroInstance *who, const CGTownInstance *where);
|
||||||
void selectionMade(int selection, int asker);
|
int selectionMade(int selection, int queryID);
|
||||||
int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2);
|
int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2);
|
||||||
int mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2); //first goes to the second
|
int mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2); //first goes to the second
|
||||||
int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2); //first goes to the second
|
int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2); //first goes to the second
|
||||||
|
@ -983,7 +983,12 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView /*= true*/)
|
|||||||
LOCPLINT->cb->setSelection(sel);
|
LOCPLINT->cb->setSelection(sel);
|
||||||
selection = sel;
|
selection = sel;
|
||||||
if (LOCPLINT->battleInt == NULL && active & GENERAL)
|
if (LOCPLINT->battleInt == NULL && active & GENERAL)
|
||||||
CCS->musich->playMusic(CCS->musich->terrainMusics[LOCPLINT->cb->getTile(sel->visitablePos())->tertype], -1);
|
{
|
||||||
|
auto pos = sel->visitablePos();
|
||||||
|
auto tile = LOCPLINT->cb->getTile(pos);
|
||||||
|
if(tile)
|
||||||
|
CCS->musich->playMusic(CCS->musich->terrainMusics[tile->tertype], -1);
|
||||||
|
}
|
||||||
if(centerView)
|
if(centerView)
|
||||||
centerOn(sel);
|
centerOn(sel);
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ CCreatureWindow::CCreatureWindow (const CCommanderInstance * Commander):
|
|||||||
dismiss = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second, cfl, 333, 148,"IVIEWCR2.DEF", SDLK_d);
|
dismiss = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second, cfl, 333, 148,"IVIEWCR2.DEF", SDLK_d);
|
||||||
}
|
}
|
||||||
|
|
||||||
CCreatureWindow::CCreatureWindow (std::vector<ui32> &skills, const CCommanderInstance * Commander, boost::function<void(ui32)> &callback):
|
CCreatureWindow::CCreatureWindow (std::vector<ui32> &skills, const CCommanderInstance * Commander, boost::function<void(ui32)> callback):
|
||||||
CWindowObject(PLAYER_COLORED),
|
CWindowObject(PLAYER_COLORED),
|
||||||
type(COMMANDER_LEVEL_UP),
|
type(COMMANDER_LEVEL_UP),
|
||||||
commander (Commander),
|
commander (Commander),
|
||||||
|
@ -90,7 +90,7 @@ public:
|
|||||||
CCreatureWindow (const CStackInstance &stack, int Type); //pop-up c-tor
|
CCreatureWindow (const CStackInstance &stack, int Type); //pop-up c-tor
|
||||||
CCreatureWindow(const CStackInstance &st, int Type, boost::function<void()> Upg, boost::function<void()> Dsm, UpgradeInfo *ui); //full garrison window
|
CCreatureWindow(const CStackInstance &st, int Type, boost::function<void()> Upg, boost::function<void()> Dsm, UpgradeInfo *ui); //full garrison window
|
||||||
CCreatureWindow(const CCommanderInstance * commander); //commander window
|
CCreatureWindow(const CCommanderInstance * commander); //commander window
|
||||||
CCreatureWindow(std::vector<ui32> &skills, const CCommanderInstance * commander, boost::function<void(ui32)> &callback);
|
CCreatureWindow(std::vector<ui32> &skills, const CCommanderInstance * commander, boost::function<void(ui32)> callback);
|
||||||
CCreatureWindow(int Cid, int Type, int creatureCount); //c-tor
|
CCreatureWindow(int Cid, int Type, int creatureCount); //c-tor
|
||||||
|
|
||||||
void init(const CStackInstance *stack, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner);
|
void init(const CStackInstance *stack, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner);
|
||||||
|
@ -470,22 +470,24 @@ void CPlayerInterface::receivedResource(int type, int val)
|
|||||||
GH.totalRedraw();
|
GH.totalRedraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayerInterface::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16>& skills, boost::function<void(ui32)> &callback)
|
void CPlayerInterface::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16>& skills, int queryID)
|
||||||
{
|
{
|
||||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||||
waitWhileDialog();
|
waitWhileDialog();
|
||||||
CCS->soundh->playSound(soundBase::heroNewLevel);
|
CCS->soundh->playSound(soundBase::heroNewLevel);
|
||||||
|
|
||||||
CLevelWindow *lw = new CLevelWindow(hero,pskill,skills,callback);
|
CLevelWindow *lw = new CLevelWindow(hero,pskill,skills,
|
||||||
|
[=](ui32 selection){ cb->selectionMade(selection, queryID); });
|
||||||
GH.pushInt(lw);
|
GH.pushInt(lw);
|
||||||
}
|
}
|
||||||
void CPlayerInterface::commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, boost::function<void(ui32)> &callback)
|
void CPlayerInterface::commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, int queryID)
|
||||||
{
|
{
|
||||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||||
waitWhileDialog();
|
waitWhileDialog();
|
||||||
CCS->soundh->playSound(soundBase::heroNewLevel);
|
CCS->soundh->playSound(soundBase::heroNewLevel);
|
||||||
|
|
||||||
CCreatureWindow * cw = new CCreatureWindow(skills, commander, callback);
|
CCreatureWindow * cw = new CCreatureWindow(skills, commander,
|
||||||
|
[=](ui32 selection){ cb->selectionMade(selection, queryID); });
|
||||||
GH.pushInt(cw);
|
GH.pushInt(cw);
|
||||||
}
|
}
|
||||||
void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
|
void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
|
||||||
@ -1279,9 +1281,10 @@ bool CPlayerInterface::altPressed() const
|
|||||||
return SDL_GetKeyState(NULL)[SDLK_LALT] || SDL_GetKeyState(NULL)[SDLK_RALT];
|
return SDL_GetKeyState(NULL)[SDLK_LALT] || SDL_GetKeyState(NULL)[SDLK_RALT];
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd )
|
void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, int queryID)
|
||||||
{
|
{
|
||||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||||
|
auto onEnd = [=]{ cb->selectionMade(0, queryID); };
|
||||||
|
|
||||||
if(stillMoveHero.get() == DURING_MOVE && adventureInt->terrain.currentPath && adventureInt->terrain.currentPath->nodes.size() > 1) //to ignore calls on passing through garrisons
|
if(stillMoveHero.get() == DURING_MOVE && adventureInt->terrain.currentPath && adventureInt->terrain.currentPath->nodes.size() > 1) //to ignore calls on passing through garrisons
|
||||||
{
|
{
|
||||||
|
@ -140,8 +140,8 @@ public:
|
|||||||
void artifactDisassembled(const ArtifactLocation &al);
|
void artifactDisassembled(const ArtifactLocation &al);
|
||||||
|
|
||||||
void heroCreated(const CGHeroInstance* hero) OVERRIDE;
|
void heroCreated(const CGHeroInstance* hero) OVERRIDE;
|
||||||
void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback) OVERRIDE;
|
void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, int queryID) OVERRIDE;
|
||||||
void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, boost::function<void(ui32)> &callback) OVERRIDE;
|
void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, int queryID) OVERRIDE;
|
||||||
void heroInGarrisonChange(const CGTownInstance *town) OVERRIDE;
|
void heroInGarrisonChange(const CGTownInstance *town) OVERRIDE;
|
||||||
void heroMoved(const TryMoveHero & details) OVERRIDE;
|
void heroMoved(const TryMoveHero & details) OVERRIDE;
|
||||||
void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val) OVERRIDE;
|
void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val) OVERRIDE;
|
||||||
@ -154,7 +154,7 @@ public:
|
|||||||
void showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level) OVERRIDE;
|
void showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level) OVERRIDE;
|
||||||
void showShipyardDialog(const IShipyard *obj) OVERRIDE; //obj may be town or shipyard;
|
void showShipyardDialog(const IShipyard *obj) OVERRIDE; //obj may be town or shipyard;
|
||||||
void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, int soundID, bool selection, bool cancel) OVERRIDE; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
|
void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, int soundID, bool selection, bool cancel) OVERRIDE; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
|
||||||
void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd) OVERRIDE;
|
void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, int queryID) OVERRIDE;
|
||||||
void showPuzzleMap() OVERRIDE;
|
void showPuzzleMap() OVERRIDE;
|
||||||
void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor) OVERRIDE;
|
void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor) OVERRIDE;
|
||||||
void showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor) OVERRIDE;
|
void showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor) OVERRIDE;
|
||||||
|
@ -642,6 +642,9 @@ int CClient::sendRequest(const CPack *request, int player)
|
|||||||
|
|
||||||
waitingRequest.pushBack(requestID);
|
waitingRequest.pushBack(requestID);
|
||||||
serv->sendPackToServer(*request, player, requestID);
|
serv->sendPackToServer(*request, player, requestID);
|
||||||
|
if(vstd::contains(playerint, player))
|
||||||
|
playerint[player]->requestSent(dynamic_cast<const CPackForServer*>(request), requestID);
|
||||||
|
|
||||||
return requestID;
|
return requestID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1619,7 +1619,7 @@ void CSplitWindow::sliderMoved(int to)
|
|||||||
setAmount(rightMin + to, false);
|
setAmount(rightMin + to, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
CLevelWindow::CLevelWindow(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback):
|
CLevelWindow::CLevelWindow(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> callback):
|
||||||
CWindowObject(PLAYER_COLORED, "LVLUPBKG"),
|
CWindowObject(PLAYER_COLORED, "LVLUPBKG"),
|
||||||
cb(callback)
|
cb(callback)
|
||||||
{
|
{
|
||||||
|
@ -481,7 +481,7 @@ class CLevelWindow : public CWindowObject
|
|||||||
void selectionChanged(unsigned to);
|
void selectionChanged(unsigned to);
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CLevelWindow(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback); //c-tor
|
CLevelWindow(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> callback); //c-tor
|
||||||
~CLevelWindow(); //d-tor
|
~CLevelWindow(); //d-tor
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -528,13 +528,14 @@ void SetObjectProperty::applyCl( CClient *cl )
|
|||||||
|
|
||||||
void HeroLevelUp::applyCl( CClient *cl )
|
void HeroLevelUp::applyCl( CClient *cl )
|
||||||
{
|
{
|
||||||
CGHeroInstance *h = GS(cl)->getHero(heroid);
|
const CGHeroInstance *h = cl->getHero(heroid);
|
||||||
|
//INTERFACE_CALL_IF_PRESENT(h->tempOwner, heroGotLevel, h, primskill, skills, id);
|
||||||
if(vstd::contains(cl->playerint,h->tempOwner))
|
if(vstd::contains(cl->playerint,h->tempOwner))
|
||||||
{
|
{
|
||||||
boost::function<void(ui32)> callback = boost::function<void(ui32)>(boost::bind(&CCallback::selectionMade,cl->callbacks[h->tempOwner].get(),_1,id));
|
cl->playerint[h->tempOwner]->heroGotLevel(h, static_cast<int>(primskill), skills, queryID);
|
||||||
cl->playerint[h->tempOwner]->heroGotLevel(const_cast<const CGHeroInstance*>(h),static_cast<int>(primskill),skills, callback);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommanderLevelUp::applyCl( CClient *cl )
|
void CommanderLevelUp::applyCl( CClient *cl )
|
||||||
{
|
{
|
||||||
CCommanderInstance * commander = GS(cl)->getHero(heroid)->commander;
|
CCommanderInstance * commander = GS(cl)->getHero(heroid)->commander;
|
||||||
@ -542,8 +543,7 @@ void CommanderLevelUp::applyCl( CClient *cl )
|
|||||||
ui8 player = commander->armyObj->tempOwner;
|
ui8 player = commander->armyObj->tempOwner;
|
||||||
if (commander->armyObj && vstd::contains(cl->playerint, player)) //is it possible for Commander to exist beyond armed instance?
|
if (commander->armyObj && vstd::contains(cl->playerint, player)) //is it possible for Commander to exist beyond armed instance?
|
||||||
{
|
{
|
||||||
auto callback = boost::function<void(ui32)>(boost::bind(&CCallback::selectionMade,cl->callbacks[player].get(),_1,id));
|
cl->playerint[player]->commanderGotLevel(commander, skills, queryID);
|
||||||
cl->playerint[player]->commanderGotLevel(commander, skills, callback);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -553,7 +553,7 @@ void BlockingDialog::applyCl( CClient *cl )
|
|||||||
text.toString(str);
|
text.toString(str);
|
||||||
|
|
||||||
if(vstd::contains(cl->playerint,player))
|
if(vstd::contains(cl->playerint,player))
|
||||||
cl->playerint[player]->showBlockingDialog(str,components,id,(soundBase::soundID)soundID,selection(),cancel());
|
cl->playerint[player]->showBlockingDialog(str,components,queryID,(soundBase::soundID)soundID,selection(),cancel());
|
||||||
else
|
else
|
||||||
tlog2 << "We received YesNoDialog for not our player...\n";
|
tlog2 << "We received YesNoDialog for not our player...\n";
|
||||||
}
|
}
|
||||||
@ -566,8 +566,7 @@ void GarrisonDialog::applyCl(CClient *cl)
|
|||||||
if(!vstd::contains(cl->playerint,h->getOwner()))
|
if(!vstd::contains(cl->playerint,h->getOwner()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
boost::function<void()> callback = boost::bind(&CCallback::selectionMade,cl->callbacks[h->getOwner()].get(),0,id);
|
cl->playerint[h->getOwner()]->showGarrisonDialog(obj,h,removableUnits,queryID);
|
||||||
cl->playerint[h->getOwner()]->showGarrisonDialog(obj,h,removableUnits,callback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BattleStart::applyCl( CClient *cl )
|
void BattleStart::applyCl( CClient *cl )
|
||||||
|
@ -76,8 +76,8 @@ public:
|
|||||||
virtual void yourTurn(){}; //called AFTER playerStartsTurn(player)
|
virtual void yourTurn(){}; //called AFTER playerStartsTurn(player)
|
||||||
|
|
||||||
//pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
|
//pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
|
||||||
virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback)=0;
|
virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, int queryID)=0;
|
||||||
virtual void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, boost::function<void(ui32)> &callback)=0;
|
virtual void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, int queryID)=0;
|
||||||
|
|
||||||
// Show a dialog, player must take decision. If selection then he has to choose between one of given components,
|
// Show a dialog, player must take decision. If selection then he has to choose between one of given components,
|
||||||
// if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called
|
// if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called
|
||||||
@ -85,7 +85,7 @@ public:
|
|||||||
virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) = 0;
|
virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) = 0;
|
||||||
|
|
||||||
// all stacks operations between these objects become allowed, interface has to call onEnd when done
|
// all stacks operations between these objects become allowed, interface has to call onEnd when done
|
||||||
virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd) = 0;
|
virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, int queryID) = 0;
|
||||||
virtual void serialize(COSer<CSaveFile> &h, const int version){}; //saving
|
virtual void serialize(COSer<CSaveFile> &h, const int version){}; //saving
|
||||||
virtual void serialize(CISer<CLoadFile> &h, const int version){}; //loading
|
virtual void serialize(CISer<CLoadFile> &h, const int version){}; //loading
|
||||||
virtual void finish(){}; //if for some reason we want to end
|
virtual void finish(){}; //if for some reason we want to end
|
||||||
|
@ -35,6 +35,7 @@ struct SetStackEffect;
|
|||||||
struct BattleTriggerEffect;
|
struct BattleTriggerEffect;
|
||||||
class CComponent;
|
class CComponent;
|
||||||
struct CObstacleInstance;
|
struct CObstacleInstance;
|
||||||
|
struct CPackForServer;
|
||||||
|
|
||||||
class DLL_LINKAGE IBattleEventsReceiver
|
class DLL_LINKAGE IBattleEventsReceiver
|
||||||
{
|
{
|
||||||
@ -112,6 +113,7 @@ public:
|
|||||||
virtual void availableCreaturesChanged(const CGDwelling *town){};
|
virtual void availableCreaturesChanged(const CGDwelling *town){};
|
||||||
virtual void heroBonusChanged(const CGHeroInstance *hero, const Bonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
|
virtual void heroBonusChanged(const CGHeroInstance *hero, const Bonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
|
||||||
virtual void playerBonusChanged(const Bonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
|
virtual void playerBonusChanged(const Bonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
|
||||||
|
virtual void requestSent(const CPackForServer *pack, int requestID){};
|
||||||
virtual void requestRealized(PackageApplied *pa){};
|
virtual void requestRealized(PackageApplied *pa){};
|
||||||
virtual void heroExchangeStarted(si32 hero1, si32 hero2){};
|
virtual void heroExchangeStarted(si32 hero1, si32 hero2){};
|
||||||
virtual void objectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged
|
virtual void objectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged
|
||||||
|
@ -81,7 +81,12 @@ struct CPackForServer : public CPack
|
|||||||
|
|
||||||
struct Query : public CPackForClient
|
struct Query : public CPackForClient
|
||||||
{
|
{
|
||||||
ui32 id;
|
ui32 queryID; // equals to -1 if it is not an actual query (and should not be answered)
|
||||||
|
|
||||||
|
Query()
|
||||||
|
{
|
||||||
|
queryID = -1;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -201,6 +206,7 @@ struct PackageApplied : public CPackForClient //94
|
|||||||
ui32 requestID; //an ID given by client to the request that was applied
|
ui32 requestID; //an ID given by client to the request that was applied
|
||||||
ui8 player;
|
ui8 player;
|
||||||
|
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & result & packType & requestID & player;
|
h & result & packType & requestID & player;
|
||||||
@ -1156,7 +1162,7 @@ struct HeroLevelUp : public Query//2000
|
|||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & id & heroid & primskill & level & skills;
|
h & queryID & heroid & primskill & level & skills;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1174,7 +1180,7 @@ struct CommanderLevelUp : public Query
|
|||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & id & heroid & sl & skills;
|
h & queryID & heroid & sl & skills;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1235,7 +1241,7 @@ struct BlockingDialog : public Query//2003
|
|||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & id & text & components & player & flags & soundID;
|
h & queryID & text & components & player & flags & soundID;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1248,7 +1254,7 @@ struct GarrisonDialog : public Query//2004
|
|||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & id & objid & hid & removableUnits;
|
h & queryID & objid & hid & removableUnits;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -176,6 +176,7 @@ void PlayerStatuses::removeQuery(ui8 player, ui32 id)
|
|||||||
boost::unique_lock<boost::mutex> l(mx);
|
boost::unique_lock<boost::mutex> l(mx);
|
||||||
if(players.find(player) != players.end())
|
if(players.find(player) != players.end())
|
||||||
{
|
{
|
||||||
|
assert(vstd::contains(players[player].queries, id));
|
||||||
players[player].queries.erase(id);
|
players[player].queries.erase(id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2164,24 +2165,28 @@ void CGameHandler::heroExchange(si32 hero1, si32 hero2)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGameHandler::prepareNewQuery(Query * queryPack, ui8 player, const boost::function<void(ui32)> &callback)
|
||||||
|
{
|
||||||
|
boost::unique_lock<boost::recursive_mutex> lock(gsm);
|
||||||
|
tlog4 << "Creating a query for player " << (int)player << " with ID=" << QID << std::endl;
|
||||||
|
callbacks[QID] = callback;
|
||||||
|
states.addQuery(player, QID);
|
||||||
|
queryPack->queryID = QID;
|
||||||
|
QID++;
|
||||||
|
}
|
||||||
|
|
||||||
void CGameHandler::applyAndAsk( Query * sel, ui8 player, boost::function<void(ui32)> &callback )
|
void CGameHandler::applyAndAsk( Query * sel, ui8 player, boost::function<void(ui32)> &callback )
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::recursive_mutex> lock(gsm);
|
boost::unique_lock<boost::recursive_mutex> lock(gsm);
|
||||||
sel->id = QID;
|
prepareNewQuery(sel, player, callback);
|
||||||
callbacks[QID] = callback;
|
|
||||||
states.addQuery(player,QID);
|
|
||||||
QID++;
|
|
||||||
sendAndApply(sel);
|
sendAndApply(sel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::ask( Query * sel, ui8 player, const CFunctionList<void(ui32)> &callback )
|
void CGameHandler::ask( Query * sel, ui8 player, const CFunctionList<void(ui32)> &callback )
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::recursive_mutex> lock(gsm);
|
boost::unique_lock<boost::recursive_mutex> lock(gsm);
|
||||||
sel->id = QID;
|
prepareNewQuery(sel, player, callback);
|
||||||
callbacks[QID] = callback;
|
|
||||||
states.addQuery(player,QID);
|
|
||||||
sendToAllClients(sel);
|
sendToAllClients(sel);
|
||||||
QID++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::sendToAllClients( CPackForClient * info )
|
void CGameHandler::sendToAllClients( CPackForClient * info )
|
||||||
@ -3207,16 +3212,9 @@ bool CGameHandler::queryReply(ui32 qid, ui32 answer, ui8 player)
|
|||||||
if(callb)
|
if(callb)
|
||||||
callb(answer);
|
callb(answer);
|
||||||
}
|
}
|
||||||
else if(vstd::contains(garrisonCallbacks,qid))
|
|
||||||
{
|
|
||||||
if(garrisonCallbacks[qid])
|
|
||||||
garrisonCallbacks[qid]();
|
|
||||||
garrisonCallbacks.erase(qid);
|
|
||||||
allowedExchanges.erase(qid);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tlog1 << "Unknown query reply...\n";
|
complain("Unknown query reply!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -4752,15 +4750,22 @@ void CGameHandler::showGarrisonDialog( int upobj, int hid, bool removableUnits,
|
|||||||
GarrisonDialog gd;
|
GarrisonDialog gd;
|
||||||
gd.hid = hid;
|
gd.hid = hid;
|
||||||
gd.objid = upobj;
|
gd.objid = upobj;
|
||||||
|
gd.removableUnits = removableUnits;
|
||||||
|
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::recursive_mutex> lock(gsm);
|
boost::unique_lock<boost::recursive_mutex> lock(gsm);
|
||||||
gd.id = QID;
|
prepareNewQuery(&gd, player);
|
||||||
garrisonCallbacks[QID] = cb;
|
|
||||||
allowedExchanges[QID] = std::pair<si32,si32>(upobj,hid);
|
//register callback manually since we need to use query ID that's given in result of prepareNewQuery call
|
||||||
states.addQuery(player,QID);
|
callbacks[gd.queryID] = [=](ui32 answer)
|
||||||
QID++;
|
{
|
||||||
gd.removableUnits = removableUnits;
|
// Garrison callback calls the "original callback" and closes the exchange between objs.
|
||||||
|
cb();
|
||||||
|
boost::unique_lock<boost::recursive_mutex> lockGsm(this->gsm);
|
||||||
|
allowedExchanges.erase(gd.queryID);
|
||||||
|
};
|
||||||
|
|
||||||
|
allowedExchanges[gd.queryID] = std::pair<si32,si32>(upobj,hid);
|
||||||
sendAndApply(&gd);
|
sendAndApply(&gd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,8 +94,9 @@ public:
|
|||||||
//queries stuff
|
//queries stuff
|
||||||
boost::recursive_mutex gsm;
|
boost::recursive_mutex gsm;
|
||||||
ui32 QID;
|
ui32 QID;
|
||||||
|
|
||||||
|
//TODO get rid of cfunctionlist (or similar) and use serialziable callback structure
|
||||||
std::map<ui32, CFunctionList<void(ui32)> > callbacks; //query id => callback function - for selection and yes/no dialogs
|
std::map<ui32, CFunctionList<void(ui32)> > callbacks; //query id => callback function - for selection and yes/no dialogs
|
||||||
std::map<ui32, boost::function<void()> > garrisonCallbacks; //query id => callback - for garrison dialogs
|
|
||||||
std::map<ui32, std::pair<si32,si32> > allowedExchanges;
|
std::map<ui32, std::pair<si32,si32> > allowedExchanges;
|
||||||
|
|
||||||
bool isBlockedByQueries(const CPack *pack, int packType, ui8 player);
|
bool isBlockedByQueries(const CPack *pack, int packType, ui8 player);
|
||||||
@ -243,6 +244,7 @@ public:
|
|||||||
void sendMessageToAll(const std::string &message);
|
void sendMessageToAll(const std::string &message);
|
||||||
void sendMessageTo(CConnection &c, const std::string &message);
|
void sendMessageTo(CConnection &c, const std::string &message);
|
||||||
void applyAndAsk(Query * sel, ui8 player, boost::function<void(ui32)> &callback);
|
void applyAndAsk(Query * sel, ui8 player, boost::function<void(ui32)> &callback);
|
||||||
|
void prepareNewQuery(Query * queryPack, ui8 player, const boost::function<void(ui32)> &callback = 0); //generates unique query id and writes it to the pack; blocks the player till query is answered (then callback is called)
|
||||||
void ask(Query * sel, ui8 player, const CFunctionList<void(ui32)> &callback);
|
void ask(Query * sel, ui8 player, const CFunctionList<void(ui32)> &callback);
|
||||||
void sendToAllClients(CPackForClient * info);
|
void sendToAllClients(CPackForClient * info);
|
||||||
void sendAndApply(CPackForClient * info);
|
void sendAndApply(CPackForClient * info);
|
||||||
|
@ -226,7 +226,14 @@ bool BuildBoat::applyGh( CGameHandler *gh )
|
|||||||
|
|
||||||
bool QueryReply::applyGh( CGameHandler *gh )
|
bool QueryReply::applyGh( CGameHandler *gh )
|
||||||
{
|
{
|
||||||
ERROR_IF_NOT(player);
|
auto playerToConnection = gh->connections.find(player);
|
||||||
|
if(playerToConnection == gh->connections.end())
|
||||||
|
COMPLAIN_AND_RETURN("No such player!");
|
||||||
|
if(playerToConnection->second != c)
|
||||||
|
COMPLAIN_AND_RETURN("Message came from wrong connection!");
|
||||||
|
if(qid == -1)
|
||||||
|
COMPLAIN_AND_RETURN("Cannot answer the query with id -1!");
|
||||||
|
|
||||||
assert(vstd::contains(gh->states.players, player));
|
assert(vstd::contains(gh->states.players, player));
|
||||||
return gh->queryReply(qid, answer, player);
|
return gh->queryReply(qid, answer, player);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user