mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-29 21:56:54 +02:00
* Server will strictly require answering the queries before taking any actions. Let me know, if this causes any freezes.
* Fixed crash on new week after we lost battle with neutral monster but killed the top stack (merging failed then). * minor changes
This commit is contained in:
parent
5fff82a3d2
commit
8b7a2f179c
@ -58,6 +58,8 @@ bool CCallback::moveHero(const CGHeroInstance *h, int3 dst)
|
|||||||
void CCallback::selectionMade(int selection, int asker)
|
void CCallback::selectionMade(int selection, int asker)
|
||||||
{
|
{
|
||||||
QueryReply pack(asker,selection);
|
QueryReply pack(asker,selection);
|
||||||
|
pack.player = player;
|
||||||
|
|
||||||
boost::unique_lock<boost::mutex> lock(*cl->serv->wmx);
|
boost::unique_lock<boost::mutex> lock(*cl->serv->wmx);
|
||||||
*cl->serv << &pack;
|
*cl->serv << &pack;
|
||||||
}
|
}
|
||||||
|
@ -214,10 +214,7 @@ void CClient::endGame( bool closeConnection /*= true*/ )
|
|||||||
delete pint;
|
delete pint;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_FOREACH(CCallback *cb, callbacks)
|
callbacks.clear();
|
||||||
{
|
|
||||||
delete cb;
|
|
||||||
}
|
|
||||||
tlog0 << "Deleted playerInts." << std::endl;
|
tlog0 << "Deleted playerInts." << std::endl;
|
||||||
|
|
||||||
tlog0 << "Client stopped." << std::endl;
|
tlog0 << "Client stopped." << std::endl;
|
||||||
@ -379,6 +376,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
|
|||||||
battleints[color] = playerint[color];
|
battleints[color] = playerint[color];
|
||||||
|
|
||||||
playerint[color]->init(cb);
|
playerint[color]->init(cb);
|
||||||
|
callbacks[color] = std::auto_ptr<CCallback>(cb);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -465,10 +463,9 @@ void CClient::serialize( Handler &h, const int version )
|
|||||||
else
|
else
|
||||||
nInt = new CPlayerInterface(pid);
|
nInt = new CPlayerInterface(pid);
|
||||||
|
|
||||||
CCallback *callback = new CCallback(gs,pid,this);
|
callbacks[pid] = std::auto_ptr<CCallback>(new CCallback(gs,pid,this));
|
||||||
callbacks.insert(callback);
|
|
||||||
battleints[pid] = playerint[pid] = nInt;
|
battleints[pid] = playerint[pid] = nInt;
|
||||||
nInt->init(callback);
|
nInt->init(callbacks[pid].get());
|
||||||
nInt->serialize(h, version);
|
nInt->serialize(h, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ class CClient : public IGameCallback
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CCallback *cb;
|
CCallback *cb;
|
||||||
std::set<CCallback*> callbacks; //callbacks given to player interfaces
|
std::map<ui8,std::auto_ptr<CCallback> > callbacks; //callbacks given to player interfaces
|
||||||
std::vector<IGameEventsReceiver*> privilagedGameEventReceivers; //scripting modules, spectator interfaces
|
std::vector<IGameEventsReceiver*> privilagedGameEventReceivers; //scripting modules, spectator interfaces
|
||||||
std::vector<IBattleEventsReceiver*> privilagedBattleEventReceivers; //scripting modules, spectator interfaces
|
std::vector<IBattleEventsReceiver*> privilagedBattleEventReceivers; //scripting modules, spectator interfaces
|
||||||
std::map<ui8,CGameInterface *> playerint;
|
std::map<ui8,CGameInterface *> playerint;
|
||||||
|
@ -528,7 +528,7 @@ void HeroLevelUp::applyCl( CClient *cl )
|
|||||||
CGHeroInstance *h = GS(cl)->getHero(heroid);
|
CGHeroInstance *h = GS(cl)->getHero(heroid);
|
||||||
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,LOCPLINT->cb,_1,id));
|
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(const_cast<const CGHeroInstance*>(h),static_cast<int>(primskill),skills, callback);
|
cl->playerint[h->tempOwner]->heroGotLevel(const_cast<const CGHeroInstance*>(h),static_cast<int>(primskill),skills, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2941,8 +2941,14 @@ void CGCreature::endBattle( BattleResult *result ) const
|
|||||||
cb->changeStackType (StackLocation(this, i->first), cre); //un-upgrade creatures
|
cb->changeStackType (StackLocation(this, i->first), cre); //un-upgrade creatures
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//first stack has to be at slot 0 -> if original one got killed, move there first remaining stack
|
||||||
|
if(!hasStackAtSlot(0))
|
||||||
|
cb->moveStack(StackLocation(this, stacks.begin()->first), StackLocation(this, 0), stacks.begin()->second->count);
|
||||||
|
|
||||||
while (stacks.size() > 1) //hopefully that's enough
|
while (stacks.size() > 1) //hopefully that's enough
|
||||||
{
|
{
|
||||||
|
// TODO it's either overcomplicated (if we assume there'll be only one stack) or buggy (if we allow multiple stacks... but that'll also cause troubles elsewhere)
|
||||||
i = stacks.end();
|
i = stacks.end();
|
||||||
i--;
|
i--;
|
||||||
TSlot slot = getSlotFor(i->second->type);
|
TSlot slot = getSlotFor(i->second->type);
|
||||||
@ -3013,7 +3019,7 @@ void CGCreature::setPropertyDer(ui8 what, ui32 val)
|
|||||||
case ObjProperty::MONSTER_EXP:
|
case ObjProperty::MONSTER_EXP:
|
||||||
giveStackExp(val);
|
giveStackExp(val);
|
||||||
break;
|
break;
|
||||||
case 13:
|
case ObjProperty::MONSTER_RESTORE_TYPE:
|
||||||
restore.basicType = val;
|
restore.basicType = val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3145,7 +3151,7 @@ void CGCreature::fight( const CGHeroInstance *h ) const
|
|||||||
//split stacks
|
//split stacks
|
||||||
int totalCount; //TODO: multiple creature types in a stack?
|
int totalCount; //TODO: multiple creature types in a stack?
|
||||||
int basicType = stacks.begin()->second->type->idNumber;
|
int basicType = stacks.begin()->second->type->idNumber;
|
||||||
cb->setObjProperty(id, 13, basicType); //store info about creature stack
|
cb->setObjProperty(id, ObjProperty::MONSTER_RESTORE_TYPE, basicType); //store info about creature stack
|
||||||
|
|
||||||
float relativePower = ((float)h->getTotalStrength() / getArmyStrength());
|
float relativePower = ((float)h->getTotalStrength() / getArmyStrength());
|
||||||
int stacksCount;
|
int stacksCount;
|
||||||
|
@ -1029,7 +1029,7 @@ namespace ObjProperty
|
|||||||
{
|
{
|
||||||
//TODO: move non general properties out to the appropriate objs classes
|
//TODO: move non general properties out to the appropriate objs classes
|
||||||
enum {OWNER = 1, BLOCKVIS = 2, PRIMARY_STACK_COUNT = 3, VISITORS = 4, VISITED = 5, ID = 6, AVAILABLE_CREATURE = 7, SUBID = 8,
|
enum {OWNER = 1, BLOCKVIS = 2, PRIMARY_STACK_COUNT = 3, VISITORS = 4, VISITED = 5, ID = 6, AVAILABLE_CREATURE = 7, SUBID = 8,
|
||||||
MONSTER_COUNT = 10, MONSTER_POWER = 11, MONSTER_EXP = 12};
|
MONSTER_COUNT = 10, MONSTER_POWER = 11, MONSTER_EXP = 12, MONSTER_RESTORE_TYPE = 13};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SetObjectProperty : public CPackForClient//1001
|
struct SetObjectProperty : public CPackForClient//1001
|
||||||
@ -1791,11 +1791,12 @@ struct QueryReply : public CPackForServer
|
|||||||
QueryReply(){type = 6000;};
|
QueryReply(){type = 6000;};
|
||||||
QueryReply(ui32 QID, ui32 Answer):qid(QID),answer(Answer){type = 6000;};
|
QueryReply(ui32 QID, ui32 Answer):qid(QID),answer(Answer){type = 6000;};
|
||||||
ui32 qid, answer; //hero and artifact id
|
ui32 qid, answer; //hero and artifact id
|
||||||
|
ui8 player;
|
||||||
|
|
||||||
bool applyGh(CGameHandler *gh);
|
bool applyGh(CGameHandler *gh);
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & qid & answer;
|
h & qid & answer & player;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -635,7 +635,18 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
|
|||||||
int packType = typeList.getTypeID(pack); //get the id of type
|
int packType = typeList.getTypeID(pack); //get the id of type
|
||||||
CBaseForGHApply *apply = applier->apps[packType]; //and appropriae applier object
|
CBaseForGHApply *apply = applier->apps[packType]; //and appropriae applier object
|
||||||
|
|
||||||
if(apply)
|
if(packType != typeList.getTypeID<QueryReply>() && states[getCurrentPlayer()].queries.size())
|
||||||
|
{
|
||||||
|
complain("Answer the query before attempting any further actions!");
|
||||||
|
PackageApplied applied;
|
||||||
|
applied.result = false;
|
||||||
|
applied.packType = packType;
|
||||||
|
{
|
||||||
|
boost::unique_lock<boost::mutex> lock(*c.wmx);
|
||||||
|
c << &applied;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(apply)
|
||||||
{
|
{
|
||||||
bool result = apply->applyOnGH(this,&c,pack);
|
bool result = apply->applyOnGH(this,&c,pack);
|
||||||
tlog5 << "Message successfully applied (result=" << result << ")!\n";
|
tlog5 << "Message successfully applied (result=" << result << ")!\n";
|
||||||
@ -2911,9 +2922,10 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, ui8 player)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGameHandler::queryReply( ui32 qid, ui32 answer )
|
bool CGameHandler::queryReply(ui32 qid, ui32 answer, ui8 player)
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::recursive_mutex> lock(gsm);
|
boost::unique_lock<boost::recursive_mutex> lock(gsm);
|
||||||
|
states.removeQuery(player, qid);
|
||||||
if(vstd::contains(callbacks,qid))
|
if(vstd::contains(callbacks,qid))
|
||||||
{
|
{
|
||||||
CFunctionList<void(ui32)> callb = callbacks[qid];
|
CFunctionList<void(ui32)> callb = callbacks[qid];
|
||||||
|
@ -197,7 +197,7 @@ public:
|
|||||||
bool makeBattleAction(BattleAction &ba);
|
bool makeBattleAction(BattleAction &ba);
|
||||||
void handleSpellCasting(int spellID, int spellLvl, THex destination, ui8 casterSide, ui8 casterColor, const CGHeroInstance * caster, const CGHeroInstance * secHero, int usedSpellPower, SpellCasting::ECastingMode mode, const CStack * stack);
|
void handleSpellCasting(int spellID, int spellLvl, THex destination, ui8 casterSide, ui8 casterColor, const CGHeroInstance * caster, const CGHeroInstance * secHero, int usedSpellPower, SpellCasting::ECastingMode mode, const CStack * stack);
|
||||||
bool makeCustomAction(BattleAction &ba);
|
bool makeCustomAction(BattleAction &ba);
|
||||||
bool queryReply( ui32 qid, ui32 answer );
|
bool queryReply( ui32 qid, ui32 answer, ui8 player );
|
||||||
bool hireHero( const CGObjectInstance *obj, ui8 hid, ui8 player );
|
bool hireHero( const CGObjectInstance *obj, ui8 hid, ui8 player );
|
||||||
bool buildBoat( ui32 objid );
|
bool buildBoat( ui32 objid );
|
||||||
bool setFormation( si32 hid, ui8 formation );
|
bool setFormation( si32 hid, ui8 formation );
|
||||||
|
@ -225,8 +225,9 @@ bool BuildBoat::applyGh( CGameHandler *gh )
|
|||||||
|
|
||||||
bool QueryReply::applyGh( CGameHandler *gh )
|
bool QueryReply::applyGh( CGameHandler *gh )
|
||||||
{
|
{
|
||||||
//TODO - check if player matches the query
|
ERROR_IF_NOT(player);
|
||||||
return gh->queryReply(qid,answer);
|
assert(vstd::contains(gh->states.players, player));
|
||||||
|
return gh->queryReply(qid, answer, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MakeAction::applyGh( CGameHandler *gh )
|
bool MakeAction::applyGh( CGameHandler *gh )
|
||||||
|
Loading…
x
Reference in New Issue
Block a user