1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Smart map object serialization over net.

Fixed doubling click sound on map selection.
This commit is contained in:
Michał W. Urbańczyk 2009-10-06 00:32:33 +00:00
parent 2cf3e6885f
commit fe7ef6bbe1
13 changed files with 169 additions and 40 deletions

View File

@ -572,9 +572,9 @@ bool CCallback::battleCanCastSpell()
return false;
if(gs->curB->side1 == player)
return gs->curB->castSpells[0] == 0 && gs->getHero(gs->curB->hero1)->getArt(17);
return gs->curB->castSpells[0] == 0 && gs->curB->heroes[0]->getArt(17);
else
return gs->curB->castSpells[1] == 0 && gs->getHero(gs->curB->hero2)->getArt(17);
return gs->curB->castSpells[1] == 0 && gs->curB->heroes[1]->getArt(17);
}
bool CCallback::battleCanFlee()
@ -617,13 +617,13 @@ std::pair<ui32, ui32> CCallback::battleEstimateDamage(int attackerID, int defend
if(gs->curB->side1 == player)
{
attackerHero = gs->getHero(gs->curB->hero1);
defenderHero = gs->getHero(gs->curB->hero2);
attackerHero = gs->curB->heroes[0];
defenderHero = gs->curB->heroes[1];
}
else
{
attackerHero = gs->getHero(gs->curB->hero2);
defenderHero = gs->getHero(gs->curB->hero1);
attackerHero = gs->curB->heroes[1];
defenderHero = gs->curB->heroes[0];
}
const CStack * attacker = gs->curB->getStack(attackerID, false),

View File

@ -744,9 +744,12 @@ void SelectionTab::showAll( SDL_Surface * to )
void SelectionTab::clickLeft( tribool down, bool previousState )
{
int line = getLine();
if(line != -1)
select(line);
if(down)
{
int line = getLine();
if(line != -1)
select(line);
}
}
void SelectionTab::wheelScrolled( bool down, bool in )
@ -801,7 +804,7 @@ int SelectionTab::getLine()
Point clickPos(GH.current->button.x, GH.current->button.y);
clickPos = clickPos - pos.topLeft();
if (clickPos.y > 115 && clickPos.y < 564 && clickPos.x > 52 && clickPos.x < 366)
if (clickPos.y > 115 && clickPos.y < 564 && clickPos.x > 22 && clickPos.x < 371)
{
line = (clickPos.y-115) / 25; //which line
}

View File

@ -243,6 +243,7 @@ void CClient::load( const std::string & fname )
tlog0 <<"Waiting for server: "<<tmh.getDif()<<std::endl;
serv = new CConnection(conf.cc.server,portc,NAME);
serv->setGS(gs);
tlog0 <<"Setting up connection: "<<tmh.getDif()<<std::endl;
ui8 pom8;
@ -303,6 +304,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
CGI->state = new CGameState();
tlog0 <<"\tGamestate: "<<tmh.getDif()<<std::endl;
serv = con;
serv->setGS(CGI->state);
CConnection &c(*con);
////////////////////////////////////////////////////
ui8 pom8;

View File

@ -347,10 +347,10 @@ void GarrisonDialog::applyCl(CClient *cl)
void BattleStart::applyCl( CClient *cl )
{
if(vstd::contains(cl->playerint,info->side1))
cl->playerint[info->side1]->battleStart(&info->army1, &info->army2, info->tile, GS(cl)->getHero(info->hero1), GS(cl)->getHero(info->hero2), 0);
cl->playerint[info->side1]->battleStart(&info->army1, &info->army2, info->tile, info->heroes[0], info->heroes[1], 0);
if(vstd::contains(cl->playerint,info->side2))
cl->playerint[info->side2]->battleStart(&info->army1, &info->army2, info->tile, GS(cl)->getHero(info->hero1), GS(cl)->getHero(info->hero2), 1);
cl->playerint[info->side2]->battleStart(&info->army1, &info->army2, info->tile, info->heroes[0], info->heroes[1], 1);
}
void BattleNextRound::applyCl( CClient *cl )

View File

@ -196,7 +196,7 @@ namespace vstd
return std::find(c.begin(),c.end(),i);
}
template <typename Container, typename Item>
bool operator-=(Container &c, const Item &i) //removes element i from container c, returns false if c does not contain i
typename Container::size_type operator-=(Container &c, const Item &i) //removes element i from container c, returns false if c does not contain i
{
typename Container::iterator itr = find(c,i);
if(itr == c.end())

View File

@ -1155,6 +1155,9 @@ int CGHeroInstance::valOfBonuses( HeroBonus::BonusType type, int subtype /*= -1*
bool CGHeroInstance::hasBonusOfType(HeroBonus::BonusType type, int subtype /*= -1*/) const
{
if(!this) //to allow calls on NULL and avoid checking duplication
return false; //if hero doesn't exist then bonus neither can
if(subtype == -1) //any subtype
{
for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)

View File

@ -1587,11 +1587,8 @@ bool CGameState::battleCanFlee(int player)
if(!curB) //there is no battle
return false;
const CGHeroInstance *h1 = getHero(curB->hero1);
const CGHeroInstance *h2 = getHero(curB->hero2);
if(h1 && h1->hasBonusOfType(HeroBonus::ENEMY_CANT_ESCAPE) //eg. one of heroes is wearing shakles of war
|| h2 && h2->hasBonusOfType(HeroBonus::ENEMY_CANT_ESCAPE))
if(curB->heroes[0]->hasBonusOfType(HeroBonus::ENEMY_CANT_ESCAPE) //eg. one of heroes is wearing shakles of war
|| curB->heroes[0]->hasBonusOfType(HeroBonus::ENEMY_CANT_ESCAPE))
return false;
return true;
@ -1687,9 +1684,7 @@ const CGHeroInstance * CGameState::battleGetOwner(int stackID)
if(!curB)
return NULL;
si32 ourHero = curB->getStack(stackID)->attackerOwned ? curB->hero1 : curB->hero2;
return getHero(ourHero);
return curB->heroes[!curB->getStack(stackID)->attackerOwned];
}
UpgradeInfo CGameState::getUpgradeInfo(const CArmedInstance *obj, int stackPos)
@ -2515,7 +2510,7 @@ si8 CGameState::battleMaxSpellLevel()
si8 levelLimit = SPELL_LEVELS;
const CGHeroInstance *h1 = getHero(curB->hero1);
const CGHeroInstance *h1 = curB->heroes[0];
if(h1)
{
for(std::list<HeroBonus>::const_iterator i = h1->bonuses.begin(); i != h1->bonuses.end(); i++)
@ -2523,7 +2518,7 @@ si8 CGameState::battleMaxSpellLevel()
amin(levelLimit, i->val);
}
const CGHeroInstance *h2 = getHero(curB->hero2);
const CGHeroInstance *h2 = curB->heroes[1];
if(h2)
{
for(std::list<HeroBonus>::const_iterator i = h2->bonuses.begin(); i != h2->bonuses.end(); i++)
@ -2759,8 +2754,8 @@ bool CGameState::battleCanShoot(int ID, int dest)
if(our->hasFeatureOfType(StackFeature::SHOOTER)//it's shooter
&& our->owner != dst->owner
&& dst->alive()
&& (!curB->isStackBlocked(ID) ||
( ourHero && ourHero->hasBonusOfType(HeroBonus::FREE_SHOOTING) ) )
&& (!curB->isStackBlocked(ID)
|| ourHero->hasBonusOfType(HeroBonus::FREE_SHOOTING))
&& our->shots
)
return true;

View File

@ -125,7 +125,7 @@ struct DLL_EXPORT BattleInfo
ui8 siege; // = 0 ordinary battle = 1 a siege with a Fort = 2 a siege with a Citadel = 3 a siege with a Castle
si32 tid; //used during town siege - id of attacked town; -1 if not town defence
int3 tile; //for background and bonuses
si32 hero1, hero2;
CGHeroInstance *heroes[2];
CCreatureSet army1, army2;
std::vector<CStack*> stacks;
std::vector<CObstacleInstance> obstacles;
@ -134,8 +134,9 @@ struct DLL_EXPORT BattleInfo
template <typename Handler> void serialize(Handler &h, const int version)
{
h & side1 & side2 & round & activeStack & siege & tid & tile & stacks & army1 & army2 & hero1 & hero2 & obstacles
h & side1 & side2 & round & activeStack & siege & tid & tile & stacks & army1 & army2 & obstacles
& castSpells & si;
h & heroes;
}
const CStack * getNextStack() const; //which stack will have turn after current one
void getStackQueue(std::vector<const CStack *> &out, int howMany, int turn = 0, int lastMoved = -1) const; //returns stack in order of their movement action

View File

@ -4,10 +4,18 @@
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <fstream>
#ifndef _MSC_VER
#include "../lib/RegisterTypes.cpp"
#include "../hch/CObjectHandler.h"
#endif
//for smart objs serialization over net
#include "CGameState.h"
#include "map.h"
#include "../hch/CObjectHandler.h"
/*
* Connection.cpp, part of VCMI engine
*
@ -54,6 +62,7 @@ void CConnection::init()
tlog0 << "Established connection with "<<pom<<std::endl;
wmx = new boost::mutex;
rmx = new boost::mutex;
gs = NULL;
}
CConnection::CConnection(std::string host, std::string port, std::string Name)
@ -173,6 +182,27 @@ void CConnection::close()
}
}
CGObjectInstance *CConnection::loadObject()
{
assert(gs);
si32 id;
*this >> id;
assert(id >= 0 && id < gs->map->objects.size());
return gs->map->objects[id];
}
void CConnection::saveObject( const CGObjectInstance *data )
{
assert(gs);
assert(data);
*this << data->id;
}
void CConnection::setGS( CGameState *state )
{
gs = state;
}
CSaveFile::CSaveFile( const std::string &fname )
:sfile(new std::ofstream((USER_DIR "/" + fname).c_str(),std::ios::binary))
{

View File

@ -21,6 +21,8 @@
#include <boost/type_traits/is_array.hpp>
const ui32 version = 710;
class CConnection;
class CGObjectInstance;
class CGameState;
namespace mpl = boost::mpl;
/*
@ -305,6 +307,13 @@ public:
ui16 tid = typeList.getTypeID(data);
*this << tid;
This()->savePointerHlp(tid, data);
}
//that part of ptr serialization was extracted to allow customization of its behavior in derived classes
template <typename T>
void savePointerHlp(ui16 tid, const T &data)
{
if(!tid)
*this << *data; //if type is unregistered simply write all data in a standard way
else
@ -491,6 +500,10 @@ public:
template <typename T>
void loadSerializable(T &data)
{
////that const cast would be evil because it allows to implicitly overwrite const objects when deserializing
//typedef typename boost::remove_const<T>::type nonConstT;
//nonConstT &hlp = const_cast<nonConstT&>(data);
//hlp.serialize(*this,myVersion);
data.serialize(*this,myVersion);
}
template <typename T>
@ -514,7 +527,13 @@ public:
//get type id
ui16 tid;
*this >> tid;
This()->loadPointerHlp(tid, data);
}
//that part of ptr deserialization was extracted to allow customization of its behavior in derived classes
template <typename T>
void loadPointerHlp( ui16 tid, T & data )
{
if(!tid)
{
typedef typename boost::remove_pointer<T>::type npT;
@ -526,6 +545,7 @@ public:
loaders[tid]->loadPtr(*this,&data);
}
}
template <typename T>
void loadSerializable(std::vector<T> &data)
{
@ -620,7 +640,9 @@ public:
class DLL_EXPORT CConnection
:public CISer<CConnection>, public COSer<CConnection>
{
CGameState *gs;
CConnection(void);
void init();
public:
boost::mutex *rmx, *wmx; // read/write mutexes
@ -646,6 +668,74 @@ public:
template<class T>
CConnection &operator&(const T&);
~CConnection(void);
void setGS(CGameState *state);
CGObjectInstance *loadObject(); //reads id from net and returns that obj
void saveObject(const CGObjectInstance *data);
template<typename T>
struct loadObjectHelper
{
static void invoke(CConnection &s, T &data, ui16 tid)
{
data = static_cast<T>(s.loadObject());
}
};
template<typename T>
struct loadRestHelper
{
static void invoke(CConnection &s, T &data, ui16 tid)
{
s.CISer<CConnection>::loadPointerHlp(tid, data);
}
};
template<typename T>
struct saveObjectHelper
{
static void invoke(CConnection &s, const T &data, ui16 tid)
{
//CGObjectInstance *&hlp = const_cast<CGObjectInstance*&>(data); //for loading pointer to const obj we must remove the qualifier
s.saveObject(data);
}
};
template<typename T>
struct saveRestHelper
{
static void invoke(CConnection &s, const T &data, ui16 tid)
{
s.COSer<CConnection>::savePointerHlp(tid, data);
}
};
//"overload" loading pointer procedure
template <typename T>
void loadPointerHlp( ui16 tid, T & data )
{
typedef typename
//if
mpl::eval_if< boost::is_base_of<CGObjectInstance, typename boost::remove_pointer<T>::type>,
mpl::identity<loadObjectHelper<T> >,
//else
mpl::identity<loadRestHelper<T> >
>::type typex;
typex::invoke(*this, data, tid);
}
//"overload" saving pointer procedure
template <typename T>
void savePointerHlp( ui16 tid, const T & data )
{
typedef typename
//if
mpl::eval_if< boost::is_base_of<CGObjectInstance, typename boost::remove_pointer<T>::type>,
mpl::identity<saveObjectHelper<T> >,
//else
mpl::identity<saveRestHelper<T> >
>::type typex;
typex::invoke(*this, data, tid);
}
};
#endif // __CONNECTION_H__

View File

@ -666,10 +666,11 @@ void BattleResult::applyGs( CGameState *gs )
//remove any "until next battle" bonuses
CGHeroInstance *h;
h = gs->getHero(gs->curB->hero1);
h = gs->curB->heroes[0];
if(h)
h->bonuses.remove_if(HeroBonus::OneBattle);
h = gs->getHero(gs->curB->hero2);
h = gs->curB->heroes[1];
if(h)
h->bonuses.remove_if(HeroBonus::OneBattle);
@ -748,7 +749,7 @@ DLL_EXPORT void StartAction::applyGs( CGameState *gs )
DLL_EXPORT void SpellCast::applyGs( CGameState *gs )
{
CGHeroInstance *h = (side) ? gs->getHero(gs->curB->hero2) : gs->getHero(gs->curB->hero1);
CGHeroInstance *h = (side) ? gs->curB->heroes[1] : gs->curB->heroes[0];
if(h)
{
int spellCost = 0;

View File

@ -358,7 +358,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
//check for bad morale => freeze
if(next->Morale() < 0 &&
!((hero1 && hero1->hasBonusOfType(HeroBonus::BLOCK_MORALE)) || (hero2 && hero2->hasBonusOfType(HeroBonus::BLOCK_MORALE))) //checking if heroes have (or don't have) morale blocking bonuses)
!((hero1->hasBonusOfType(HeroBonus::BLOCK_MORALE)) || (hero2->hasBonusOfType(HeroBonus::BLOCK_MORALE))) //checking if heroes have (or don't have) morale blocking bonuses)
)
{
if( rand()%24 < (-next->Morale())*2 )
@ -461,7 +461,7 @@ askInterfaceForMove:
&& !vstd::contains(next->state,WAITING)
&& next->alive()
&& next->Morale() > 0
&& !((hero1 && hero1->hasBonusOfType(HeroBonus::BLOCK_MORALE)) || (hero2 && hero2->hasBonusOfType(HeroBonus::BLOCK_MORALE)) ) //checking if heroes have (or don't have) morale blocking bonuses
&& !((hero1->hasBonusOfType(HeroBonus::BLOCK_MORALE)) || (hero2->hasBonusOfType(HeroBonus::BLOCK_MORALE)) ) //checking if heroes have (or don't have) morale blocking bonuses
)
if(rand()%24 < next->Morale()) //this stack hasn't got morale this turn
goto askInterfaceForMove; //move this stack once more
@ -757,7 +757,7 @@ void CGameHandler::init(StartInfo *si, int Seed)
tlog0 << "Map loaded!" << std::endl;
gs = new CGameState();
tlog0 << "Gamestate created!" << std::endl;
gs->init(si,map,Seed);
gs->init(si,map,Seed);
tlog0 << "Gamestate initialized!" << std::endl;
for(std::map<ui8,PlayerState>::iterator i = gs->players.begin(); i != gs->players.end(); i++)
@ -978,8 +978,8 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
curB->tile = tile;
curB->army1=army1;
curB->army2=army2;
curB->hero1=(hero1)?(hero1->id):(-1);
curB->hero2=(hero2)?(hero2->id):(-1);
curB->heroes[0] = const_cast<CGHeroInstance*>(hero1);
curB->heroes[1] = const_cast<CGHeroInstance*>(hero2);
curB->round = -2;
curB->activeStack = -1;
@ -2609,7 +2609,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
case 9: //catapult
{
sendAndApply(&StartAction(ba));
const CGHeroInstance * attackingHero = (ba.side) ? gs->getHero(gs->curB->hero2) : gs->getHero(gs->curB->hero1);
const CGHeroInstance * attackingHero = gs->curB->heroes[ba.side];
CHeroHandler::SBallisticsLevelInfo sbi = VLC->heroh->ballistics[attackingHero->getSecSkillLevel(20)]; //artillery
int attackedPart = gs->curB->hexToWallPart(ba.destinationTile);
@ -3008,8 +3008,8 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
{
case 1: //hero casts spell
{
CGHeroInstance *h = (ba.side) ? gs->getHero(gs->curB->hero2) : gs->getHero(gs->curB->hero1);
CGHeroInstance *secondHero = (!ba.side) ? gs->getHero(gs->curB->hero2) : gs->getHero(gs->curB->hero1);
const CGHeroInstance *h = gs->curB->heroes[ba.side];
const CGHeroInstance *secondHero = gs->curB->heroes[!ba.side];
if(!h)
{
tlog2 << "Wrong caster!\n";
@ -3028,7 +3028,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
|| (h->mana < gs->curB->getSpellCost(s, h)) //not enough mana
|| (ba.additionalInfo < 10) //it's adventure spell (not combat)
|| (gs->curB->castSpells[ba.side]) //spell has been cast
|| (secondHero && secondHero->hasBonusOfType(HeroBonus::SPELL_IMMUNITY, s->id)) //non - casting hero provides immunity for this spell
|| (secondHero->hasBonusOfType(HeroBonus::SPELL_IMMUNITY, s->id)) //non - casting hero provides immunity for this spell
|| (gs->battleMaxSpellLevel() < s->level) //non - casting hero stops caster from casting this spell
)
{
@ -3179,7 +3179,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
checkForBattleEnd(gs->curB->stacks);
if(battleResult.get())
{
endBattle(gs->curB->tile, getHero(gs->curB->hero1), getHero(gs->curB->hero2));
endBattle(gs->curB->tile, gs->curB->heroes[0], gs->curB->heroes[1]);
}
return true;
}

View File

@ -88,6 +88,7 @@ void CVCMIServer::newGame(CConnection *c)
}
gh.init(si,rand());
c->setGS(gh.gs);
CConnection* cc; //tcp::socket * ss;
for(int i=0; i<clients; i++)
@ -107,6 +108,7 @@ void CVCMIServer::newGame(CConnection *c)
continue;
}
cc = new CConnection(s,NAME);
cc->setGS(gh.gs);
}
gh.conns.insert(cc);
}
@ -192,6 +194,7 @@ void CVCMIServer::loadGame( CConnection *c )
tlog0 <<"Reading handlers"<<std::endl;
lf >> (gh.gs);
c->setGS(gh.gs);
tlog0 <<"Reading gamestate"<<std::endl;
}
@ -220,6 +223,7 @@ void CVCMIServer::loadGame( CConnection *c )
continue;
}
cc = new CConnection(s,NAME);
cc->setGS(gh.gs);
}
gh.conns.insert(cc);
}