1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

New objects are now created and initialized on server and sent to client

This commit is contained in:
Ivan Savenko 2024-07-12 16:51:27 +00:00
parent d2839c8e52
commit b07408e984
14 changed files with 95 additions and 87 deletions

View File

@ -161,7 +161,7 @@ public:
void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> & spells) override {}; void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> & spells) override {};
bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override {return false;}; bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override {return false;};
void createObject(const int3 & visitablePosition, const PlayerColor & initiator, MapObjectID type, MapObjectSubID subtype) override {}; void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) override {};
void setOwner(const CGObjectInstance * obj, PlayerColor owner) override {}; void setOwner(const CGObjectInstance * obj, PlayerColor owner) override {};
void giveExperience(const CGHeroInstance * hero, TExpType val) override {}; void giveExperience(const CGHeroInstance * hero, TExpType val) override {};
void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs = false) override {}; void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs = false) override {};

View File

@ -1048,7 +1048,7 @@ void ApplyClientNetPackVisitor::visitNewObject(NewObject & pack)
{ {
cl.invalidatePaths(); cl.invalidatePaths();
const CGObjectInstance *obj = cl.getObj(pack.createdObjectID); const CGObjectInstance *obj = pack.newObject;
if(CGI->mh) if(CGI->mh)
CGI->mh->onObjectFadeIn(obj, pack.initiator); CGI->mh->onObjectFadeIn(obj, pack.initiator);

View File

@ -92,7 +92,7 @@ public:
virtual void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> &spells)=0; virtual void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> &spells)=0;
virtual bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) = 0; virtual bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) = 0;
virtual void createObject(const int3 & visitablePosition, const PlayerColor & initiator, MapObjectID type, MapObjectSubID subtype) = 0; virtual void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) = 0;
virtual void setOwner(const CGObjectInstance * objid, PlayerColor owner)=0; virtual void setOwner(const CGObjectInstance * objid, PlayerColor owner)=0;
virtual void giveExperience(const CGHeroInstance * hero, TExpType val) =0; virtual void giveExperience(const CGHeroInstance * hero, TExpType val) =0;
virtual void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs=false)=0; virtual void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs=false)=0;

View File

@ -532,7 +532,7 @@ void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const
if (!boat) if (!boat)
{ {
//Create a new boat for hero //Create a new boat for hero
cb->createObject(boatPos, h->getOwner(), Obj::BOAT, getBoatType().getNum()); cb->createBoat(boatPos, getBoatType(), h->getOwner());
boatId = cb->getTopObj(boatPos)->id; boatId = cb->getTopObj(boatPos)->id;
} }
} }
@ -614,11 +614,6 @@ void CGHeroInstance::pickRandomObject(vstd::RNG & rand)
this->subID = oldSubID; this->subID = oldSubID;
} }
void CGHeroInstance::initObj(vstd::RNG & rand)
{
}
void CGHeroInstance::recreateSecondarySkillsBonuses() void CGHeroInstance::recreateSecondarySkillsBonuses()
{ {
auto secondarySkillsBonuses = getBonuses(Selector::sourceType()(BonusSource::SECONDARY_SKILL)); auto secondarySkillsBonuses = getBonuses(Selector::sourceType()(BonusSource::SECONDARY_SKILL));

View File

@ -293,7 +293,6 @@ public:
void boatDeserializationFix(); void boatDeserializationFix();
void deserializationFix(); void deserializationFix();
void initObj(vstd::RNG & rand) override;
void pickRandomObject(vstd::RNG & rand) override; void pickRandomObject(vstd::RNG & rand) override;
void onHeroVisit(const CGHeroInstance * h) const override; void onHeroVisit(const CGHeroInstance * h) const override;
std::string getObjectName() const override; std::string getObjectName() const override;

View File

@ -1421,7 +1421,6 @@ void HeroRecruited::applyGs(CGameState * gs) const
h->setOwner(player); h->setOwner(player);
h->pos = tile; h->pos = tile;
h->initObj(gs->getRandomGenerator());
if(h->id == ObjectInstanceID()) if(h->id == ObjectInstanceID())
{ {
@ -1475,59 +1474,13 @@ void GiveHero::applyGs(CGameState * gs) const
void NewObject::applyGs(CGameState *gs) void NewObject::applyGs(CGameState *gs)
{ {
TerrainId terrainType = ETerrainId::NONE; newObject->id = ObjectInstanceID(static_cast<si32>(gs->map->objects.size()));
if (!gs->isInTheMap(targetPos)) gs->map->objects.emplace_back(newObject);
{ gs->map->addBlockVisTiles(newObject);
logGlobal->error("Attempt to create object outside map at %s!", targetPos.toString());
return;
}
const TerrainTile & t = gs->map->getTile(targetPos);
terrainType = t.terType->getId();
auto handler = VLC->objtypeh->getHandlerFor(ID, subID);
CGObjectInstance * o = handler->create(gs->callback, nullptr);
handler->configureObject(o, gs->getRandomGenerator());
assert(o->ID == this->ID);
if (ID == Obj::MONSTER) //probably more options will be needed
{
//CStackInstance hlp;
auto * cre = dynamic_cast<CGCreature *>(o);
//cre->slots[0] = hlp;
assert(cre);
cre->notGrowingTeam = cre->neverFlees = false;
cre->character = 2;
cre->gainedArtifact = ArtifactID::NONE;
cre->identifier = -1;
cre->addToSlot(SlotID(0), new CStackInstance(subID.getNum(), -1)); //add placeholder stack
}
assert(!handler->getTemplates(terrainType).empty());
if (handler->getTemplates().empty())
{
logGlobal->error("Attempt to create object (%d %d) with no templates!", ID, subID.getNum());
return;
}
if (!handler->getTemplates(terrainType).empty())
o->appearance = handler->getTemplates(terrainType).front();
else
o->appearance = handler->getTemplates().front();
o->id = ObjectInstanceID(static_cast<si32>(gs->map->objects.size()));
o->pos = targetPos + o->getVisitableOffset();
gs->map->objects.emplace_back(o);
gs->map->addBlockVisTiles(o);
o->initObj(gs->getRandomGenerator());
gs->map->calculateGuardingGreaturePositions(); gs->map->calculateGuardingGreaturePositions();
createdObjectID = o->id; logGlobal->debug("Added object id=%d; address=%x; name=%s", newObject->id, (intptr_t)newObject, newObject->getObjectName());
logGlobal->debug("Added object id=%d; address=%x; name=%s", o->id, (intptr_t)o, o->getObjectName());
} }
void NewArtifact::applyGs(CGameState *gs) void NewArtifact::applyGs(CGameState *gs)

View File

@ -787,23 +787,15 @@ struct DLL_LINKAGE NewObject : public CPackForClient
void applyGs(CGameState * gs); void applyGs(CGameState * gs);
/// Object ID to create /// Object ID to create
MapObjectID ID; CGObjectInstance * newObject;
/// Object secondary ID to create
MapObjectSubID subID;
/// Position of visitable tile of created object
int3 targetPos;
/// Which player initiated creation of this object /// Which player initiated creation of this object
PlayerColor initiator; PlayerColor initiator;
ObjectInstanceID createdObjectID; //used locally, filled during applyGs
void visitTyped(ICPackVisitor & visitor) override; void visitTyped(ICPackVisitor & visitor) override;
template <typename Handler> void serialize(Handler & h) template <typename Handler> void serialize(Handler & h)
{ {
h & ID; h & newObject;
subID.serializeIdentifier(h, ID);
h & targetPos;
h & initiator; h & initiator;
} }
}; };

View File

@ -238,12 +238,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
} }
else //create boat else //create boat
{ {
NewObject no; env->createBoat(summonPos, BoatId::NECROPOLIS, parameters.caster->getCasterOwner());
no.ID = Obj::BOAT;
no.subID = BoatId::NECROPOLIS;
no.targetPos = summonPos;
no.initiator = parameters.caster->getCasterOwner();
env->apply(&no);
} }
return ESpellCastResult::OK; return ESpellCastResult::OK;
} }

View File

@ -58,6 +58,7 @@ public:
virtual const CMap * getMap() const = 0; virtual const CMap * getMap() const = 0;
virtual const CGameInfoCallback * getCb() const = 0; virtual const CGameInfoCallback * getCb() const = 0;
virtual void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) = 0;
virtual bool moveHero(ObjectInstanceID hid, int3 dst, EMovementMode mode) = 0; //TODO: remove virtual bool moveHero(ObjectInstanceID hid, int3 dst, EMovementMode mode) = 0; //TODO: remove
virtual void genericQuery(Query * request, PlayerColor color, std::function<void(std::optional<int32_t>)> callback) = 0;//TODO: type safety on query, use generic query packet when implemented virtual void genericQuery(Query * request, PlayerColor color, std::function<void(std::optional<int32_t>)> callback) = 0;//TODO: type safety on query, use generic query packet when implemented

View File

@ -50,9 +50,12 @@
#include "../lib/mapping/CMap.h" #include "../lib/mapping/CMap.h"
#include "../lib/mapping/CMapService.h" #include "../lib/mapping/CMapService.h"
#include "../lib/mapObjects/CGCreature.h"
#include "../lib/mapObjects/CGMarket.h" #include "../lib/mapObjects/CGMarket.h"
#include "../lib/mapObjects/CGTownInstance.h" #include "../lib/mapObjects/CGTownInstance.h"
#include "../lib/mapObjects/MiscObjects.h" #include "../lib/mapObjects/MiscObjects.h"
#include "../lib/mapObjectConstructors/AObjectTypeHandler.h"
#include "../lib/mapObjectConstructors/CObjectClassesHandler.h"
#include "../lib/modding/ModIncompatibility.h" #include "../lib/modding/ModIncompatibility.h"
#include "../lib/networkPacks/StackLocation.h" #include "../lib/networkPacks/StackLocation.h"
#include "../lib/pathfinder/CPathfinder.h" #include "../lib/pathfinder/CPathfinder.h"
@ -3684,7 +3687,7 @@ bool CGameHandler::buildBoat(ObjectInstanceID objid, PlayerColor playerID)
} }
giveResources(playerID, -boatCost); giveResources(playerID, -boatCost);
createObject(tile, playerID, Obj::BOAT, obj->getBoatType().getNum()); createBoat(tile, obj->getBoatType(), playerID);
return true; return true;
} }
@ -3809,7 +3812,7 @@ bool CGameHandler::dig(const CGHeroInstance *h)
if (h->diggingStatus() != EDiggingStatus::CAN_DIG) //checks for terrain and movement if (h->diggingStatus() != EDiggingStatus::CAN_DIG) //checks for terrain and movement
COMPLAIN_RETF("Hero cannot dig (error code %d)!", static_cast<int>(h->diggingStatus())); COMPLAIN_RETF("Hero cannot dig (error code %d)!", static_cast<int>(h->diggingStatus()));
createObject(h->visitablePos(), h->getOwner(), Obj::HOLE, 0 ); createHole(h->visitablePos(), h->getOwner());
//take MPs //take MPs
SetMovePoints smp; SetMovePoints smp;
@ -4214,7 +4217,7 @@ void CGameHandler::spawnWanderingMonsters(CreatureID creatureID)
{ {
auto count = cre->getRandomAmount(std::rand); auto count = cre->getRandomAmount(std::rand);
createObject(*tile, PlayerColor::NEUTRAL, Obj::MONSTER, creatureID); createWanderingMonster(*tile, creatureID);
auto monsterId = getTopObj(*tile)->id; auto monsterId = getTopObj(*tile)->id;
setObjPropertyValue(monsterId, ObjProperty::MONSTER_COUNT, count); setObjPropertyValue(monsterId, ObjProperty::MONSTER_COUNT, count);
@ -4413,13 +4416,71 @@ scripting::Pool * CGameHandler::getGlobalContextPool() const
//} //}
#endif #endif
void CGameHandler::createObject(const int3 & visitablePosition, const PlayerColor & initiator, MapObjectID type, MapObjectSubID subtype)
CGObjectInstance * CGameHandler::createNewObject(const int3 & visitablePosition, MapObjectID objectID, MapObjectSubID subID)
{ {
TerrainId terrainType = ETerrainId::NONE;
if (!gs->isInTheMap(visitablePosition))
throw std::runtime_error("Attempt to create object outside map at " + visitablePosition.toString());
const TerrainTile & t = gs->map->getTile(visitablePosition);
terrainType = t.terType->getId();
auto handler = VLC->objtypeh->getHandlerFor(objectID, subID);
CGObjectInstance * o = handler->create(gs->callback, nullptr);
handler->configureObject(o, getRandomGenerator());
assert(o->ID == objectID);
assert(!handler->getTemplates(terrainType).empty());
if (handler->getTemplates().empty())
throw std::runtime_error("Attempt to create object (" + std::to_string(objectID) + ", " + std::to_string(subID.getNum()) + ") with no templates!");
if (!handler->getTemplates(terrainType).empty())
o->appearance = handler->getTemplates(terrainType).front();
else
o->appearance = handler->getTemplates().front();
o->pos = visitablePosition + o->getVisitableOffset();
return o;
}
void CGameHandler::createWanderingMonster(const int3 & visitablePosition, CreatureID creature)
{
auto createdObject = createNewObject(visitablePosition, Obj::MONSTER, creature);
auto * cre = dynamic_cast<CGCreature *>(createdObject);
assert(cre);
cre->notGrowingTeam = cre->neverFlees = false;
cre->character = 2;
cre->gainedArtifact = ArtifactID::NONE;
cre->identifier = -1;
cre->addToSlot(SlotID(0), new CStackInstance(creature, -1)); //add placeholder stack
newObject(createdObject, PlayerColor::NEUTRAL);
}
void CGameHandler::createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator)
{
auto createdObject = createNewObject(visitablePosition, Obj::BOAT, type);
newObject(createdObject, initiator);
}
void CGameHandler::createHole(const int3 & visitablePosition, PlayerColor initiator)
{
auto createdObject = createNewObject(visitablePosition, Obj::HOLE, 0);
newObject(createdObject, initiator);
}
void CGameHandler::newObject(CGObjectInstance * object, PlayerColor initiator)
{
object->initObj(gs->getRandomGenerator());
NewObject no; NewObject no;
no.ID = type; no.newObject = object;
no.subID = subtype;
no.initiator = initiator; no.initiator = initiator;
no.targetPos = visitablePosition;
sendAndApply(&no); sendAndApply(&no);
} }

View File

@ -92,6 +92,14 @@ public:
bool isAllowedExchange(ObjectInstanceID id1, ObjectInstanceID id2); bool isAllowedExchange(ObjectInstanceID id1, ObjectInstanceID id2);
void giveSpells(const CGTownInstance *t, const CGHeroInstance *h); void giveSpells(const CGTownInstance *t, const CGHeroInstance *h);
// Helpers to create new object of specified type
CGObjectInstance * createNewObject(const int3 & visitablePosition, MapObjectID objectID, MapObjectSubID subID);
void createWanderingMonster(const int3 & visitablePosition, CreatureID creature);
void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) override;
void createHole(const int3 & visitablePosition, PlayerColor initiator);
void newObject(CGObjectInstance * object, PlayerColor initiator);
explicit CGameHandler(CVCMIServer * lobby); explicit CGameHandler(CVCMIServer * lobby);
~CGameHandler(); ~CGameHandler();
@ -100,7 +108,6 @@ public:
//do sth //do sth
void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> &spells) override; void changeSpells(const CGHeroInstance * hero, bool give, const std::set<SpellID> &spells) override;
bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override; bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override;
void createObject(const int3 & visitablePosition, const PlayerColor & initiator, MapObjectID type, MapObjectSubID subtype) override;
void setOwner(const CGObjectInstance * obj, PlayerColor owner) override; void setOwner(const CGObjectInstance * obj, PlayerColor owner) override;
void giveExperience(const CGHeroInstance * hero, TExpType val) override; void giveExperience(const CGHeroInstance * hero, TExpType val) override;
void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs=false) override; void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs=false) override;

View File

@ -94,6 +94,11 @@ bool ServerSpellCastEnvironment::moveHero(ObjectInstanceID hid, int3 dst, EMovem
return gh->moveHero(hid, dst, mode, false); return gh->moveHero(hid, dst, mode, false);
} }
void ServerSpellCastEnvironment::createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator)
{
return gh->createBoat(visitablePosition, type, initiator);
}
void ServerSpellCastEnvironment::genericQuery(Query * request, PlayerColor color, std::function<void(std::optional<int32_t>)> callback) void ServerSpellCastEnvironment::genericQuery(Query * request, PlayerColor color, std::function<void(std::optional<int32_t>)> callback)
{ {
auto query = std::make_shared<CGenericQuery>(gh, color, callback); auto query = std::make_shared<CGenericQuery>(gh, color, callback);

View File

@ -37,6 +37,7 @@ public:
const CMap * getMap() const override; const CMap * getMap() const override;
const CGameInfoCallback * getCb() const override; const CGameInfoCallback * getCb() const override;
bool moveHero(ObjectInstanceID hid, int3 dst, EMovementMode mode) override; bool moveHero(ObjectInstanceID hid, int3 dst, EMovementMode mode) override;
void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) override;
void genericQuery(Query * request, PlayerColor color, std::function<void(std::optional<int32_t>)> callback) override; void genericQuery(Query * request, PlayerColor color, std::function<void(std::optional<int32_t>)> callback) override;
private: private:
CGameHandler * gh; CGameHandler * gh;

View File

@ -227,8 +227,7 @@ bool HeroPoolProcessor::hireHero(const ObjectInstanceID & objectID, const HeroTy
if(gameHandler->getTile(targetPos)->isWater() && !recruitedHero->boat) if(gameHandler->getTile(targetPos)->isWater() && !recruitedHero->boat)
{ {
//Create a new boat for hero //Create a new boat for hero
gameHandler->createObject(targetPos, player, Obj::BOAT, recruitedHero->getBoatType().getNum()); gameHandler->createBoat(targetPos, recruitedHero->getBoatType(), player);
hr.boatId = gameHandler->getTopObj(targetPos)->id; hr.boatId = gameHandler->getTopObj(targetPos)->id;
} }