diff --git a/AI/Nullkiller/AIGateway.cpp b/AI/Nullkiller/AIGateway.cpp index 5485d5b88..5f94dd1df 100644 --- a/AI/Nullkiller/AIGateway.cpp +++ b/AI/Nullkiller/AIGateway.cpp @@ -390,7 +390,7 @@ void AIGateway::advmapSpellCast(const CGHeroInstance * caster, int spellID) NET_EVENT_HANDLER; } -void AIGateway::showInfoDialog(const std::string & text, const std::vector & components, int soundID) +void AIGateway::showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector & components, int soundID) { LOG_TRACE_PARAMS(logAi, "soundID '%i'", soundID); NET_EVENT_HANDLER; diff --git a/AI/Nullkiller/AIGateway.h b/AI/Nullkiller/AIGateway.h index 98b0fca8b..1443392f3 100644 --- a/AI/Nullkiller/AIGateway.h +++ b/AI/Nullkiller/AIGateway.h @@ -153,7 +153,7 @@ public: void playerBonusChanged(const Bonus & bonus, bool gain) override; void heroCreated(const CGHeroInstance *) override; void advmapSpellCast(const CGHeroInstance * caster, int spellID) override; - void showInfoDialog(const std::string & text, const std::vector & components, int soundID) override; + void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector & components, int soundID) override; void requestRealized(PackageApplied * pa) override; void receivedResource() override; void objectRemoved(const CGObjectInstance * obj) override; diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index da7eced29..83b272c9e 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -20,6 +20,7 @@ #include "../../lib/CHeroHandler.h" #include "../../lib/CModHandler.h" #include "../../lib/CGameState.h" +#include "../../lib/NetPacksBase.h" #include "../../lib/NetPacks.h" #include "../../lib/serializer/CTypeList.h" #include "../../lib/serializer/BinarySerializer.h" @@ -475,7 +476,7 @@ void VCAI::advmapSpellCast(const CGHeroInstance * caster, int spellID) NET_EVENT_HANDLER; } -void VCAI::showInfoDialog(const std::string & text, const std::vector & components, int soundID) +void VCAI::showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector & components, int soundID) { LOG_TRACE_PARAMS(logAi, "soundID '%i'", soundID); NET_EVENT_HANDLER; diff --git a/AI/VCAI/VCAI.h b/AI/VCAI/VCAI.h index 5ea900961..249a91189 100644 --- a/AI/VCAI/VCAI.h +++ b/AI/VCAI/VCAI.h @@ -186,7 +186,7 @@ public: void playerBonusChanged(const Bonus & bonus, bool gain) override; void heroCreated(const CGHeroInstance *) override; void advmapSpellCast(const CGHeroInstance * caster, int spellID) override; - void showInfoDialog(const std::string & text, const std::vector & components, int soundID) override; + void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector & components, int soundID) override; void requestRealized(PackageApplied * pa) override; void receivedResource() override; void objectRemoved(const CGObjectInstance * obj) override; diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index bea2cee3d..8d004ccd3 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -1031,18 +1031,16 @@ void CPlayerInterface::yourTacticPhase(int distance) boost::this_thread::sleep(boost::posix_time::millisec(1)); } -void CPlayerInterface::showComp(const Component &comp, std::string message) +void CPlayerInterface::showInfoDialog(EInfoWindowMode type, const std::string &text, const std::vector & components, int soundID) { EVENT_HANDLER_CALLED_BY_CLIENT; - waitWhileDialog(); //Fix for mantis #98 + if(type == InfoWindow::INFO) { + adventureInt->infoBar->showComponents(components, text); + if (makingTurn && GH.listInt.size() && LOCPLINT == this) + CCS->soundh->playSound(static_cast(soundID)); + return; + } - CCS->soundh->playSoundFromSet(CCS->soundh->pickupSounds); - adventureInt->infoBar->showComponent(comp, message); -} - -void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector & components, int soundID) -{ - EVENT_HANDLER_CALLED_BY_CLIENT; if (settings["session"]["autoSkip"].Bool() && !GH.isKeyboardShiftDown()) { return; @@ -1093,7 +1091,7 @@ void CPlayerInterface::showInfoDialogAndWait(std::vector & components std::string str; text.toString(str); - showInfoDialog(str, components, 0); + showInfoDialog(EInfoWindowMode::MODAL, str, components, 0); waitWhileDialog(); } diff --git a/client/CPlayerInterface.h b/client/CPlayerInterface.h index 0f1264c56..591ecf260 100644 --- a/client/CPlayerInterface.h +++ b/client/CPlayerInterface.h @@ -168,7 +168,7 @@ public: void heroMovePointsChanged(const CGHeroInstance * hero) override; void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town) override; void receivedResource() override; - void showInfoDialog(const std::string & text, const std::vector & components, int soundID) override; + void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector & components, int soundID) 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 showBlockingDialog(const std::string &text, const std::vector &components, QueryID 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. @@ -201,7 +201,6 @@ public: void playerBlocked(int reason, bool start) override; void gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult) override; void playerStartsTurn(PlayerColor player) override; //called before yourTurn on active itnerface - void showComp(const Component &comp, std::string message) override; //display component in the advmapint infobox void saveGame(BinarySerializer & h, const int version) override; //saving void loadGame(BinaryDeserializer & h, const int version) override; //loading void showWorldViewEx(const std::vector & objectPositions, bool showTerrain) override; diff --git a/client/Client.h b/client/Client.h index c51fbf759..140b5ad0f 100644 --- a/client/Client.h +++ b/client/Client.h @@ -217,7 +217,6 @@ public: void removeArtifact(const ArtifactLocation & al) override {}; bool moveArtifact(const ArtifactLocation & al1, const ArtifactLocation & al2) override {return false;}; - void showCompInfo(ShowInInfobox * comp) override {}; void heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) override {}; void visitCastleObjects(const CGTownInstance * obj, const CGHeroInstance * hero) override {}; void stopHeroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) override {}; diff --git a/client/ClientNetPackVisitors.h b/client/ClientNetPackVisitors.h index 72d0a9f2e..20c51428c 100644 --- a/client/ClientNetPackVisitors.h +++ b/client/ClientNetPackVisitors.h @@ -96,7 +96,6 @@ public: void visitYourTurn(YourTurn & pack) override; void visitSaveGameClient(SaveGameClient & pack) override; void visitPlayerMessageClient(PlayerMessageClient & pack) override; - void visitShowInInfobox(ShowInInfobox & pack) override; void visitAdvmapSpellCast(AdvmapSpellCast & pack) override; void visitShowWorldViewEx(ShowWorldViewEx & pack) override; void visitOpenWindow(OpenWindow & pack) override; diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index d41ca125f..dee2ebf71 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -592,7 +592,7 @@ void ApplyClientNetPackVisitor::visitInfoWindow(InfoWindow & pack) std::string str; pack.text.toString(str); - if(!callInterfaceIfPresent(cl, pack.player, &CGameInterface::showInfoDialog, str, pack.components,(soundBase::soundID)pack.soundID)) + if(!callInterfaceIfPresent(cl, pack.player, &CGameInterface::showInfoDialog, pack.type, str, pack.components,(soundBase::soundID)pack.soundID)) logNetwork->warn("We received InfoWindow for not our player..."); } @@ -855,11 +855,6 @@ void ApplyClientNetPackVisitor::visitPlayerMessageClient(PlayerMessageClient & p LOCPLINT->cingconsole->print(str.str()); } -void ApplyClientNetPackVisitor::visitShowInInfobox(ShowInInfobox & pack) -{ - callInterfaceIfPresent(cl, pack.player, &IGameEventsReceiver::showComp, pack.c, pack.text.toString()); -} - void ApplyClientNetPackVisitor::visitAdvmapSpellCast(AdvmapSpellCast & pack) { cl.invalidatePaths(); diff --git a/client/adventureMap/CInfoBar.cpp b/client/adventureMap/CInfoBar.cpp index 722f700a5..d020635d6 100644 --- a/client/adventureMap/CInfoBar.cpp +++ b/client/adventureMap/CInfoBar.cpp @@ -163,16 +163,39 @@ CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo() } } -CInfoBar::VisibleComponentInfo::VisibleComponentInfo(const Component & compToDisplay, std::string message) +CInfoBar::VisibleComponentInfo::VisibleComponentInfo(const std::vector & compsToDisplay, std::string message) { OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); background = std::make_shared("ADSTATOT", 1, 0); + auto fullRect = Rect(4, 4, 171, 171); + auto textRect = fullRect; + auto imageRect = fullRect; - comp = std::make_shared(compToDisplay); - comp->moveTo(Point(pos.x+47, pos.y+50)); + if(!compsToDisplay.empty()) + { + auto size = CComponent::large; + if(compsToDisplay.size() > 2) + size = CComponent::small; + if(message != "") + { + textRect = Rect(4, 4, 171, 42); + imageRect = Rect(4, 42, 171, 121); + if(compsToDisplay.size() > 4) + size = CComponent::tiny; + } + else if(compsToDisplay.size() > 4) + size = CComponent::small; - text = std::make_shared(message, Rect(10, 4, 160, 50), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); + std::vector> vect; + + for(const auto & c : compsToDisplay) + vect.emplace_back(std::make_shared(c, size)); + + comps = std::make_shared(vect, imageRect, 4, 4, 1); + } + + text = std::make_shared(message, textRect, 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); } void CInfoBar::playNewDaySound() @@ -266,11 +289,12 @@ void CInfoBar::showDate() redraw(); } -void CInfoBar::showComponent(const Component & comp, std::string message) +void CInfoBar::showComponents(const std::vector & comps, std::string message) { OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); state = COMPONENT; - visibleInfo = std::make_shared(comp, message); + visibleInfo = std::make_shared(comps, message); + setTimer(3000); redraw(); } diff --git a/client/adventureMap/CInfoBar.h b/client/adventureMap/CInfoBar.h index 5b5809954..be1a4234a 100644 --- a/client/adventureMap/CInfoBar.h +++ b/client/adventureMap/CInfoBar.h @@ -23,6 +23,7 @@ VCMI_LIB_NAMESPACE_END class CAnimImage; class CShowableAnim; class CComponent; +class CComponentBox; class CHeroTooltip; class CTownTooltip; class CLabel; @@ -97,10 +98,10 @@ class CInfoBar : public CIntObject class VisibleComponentInfo : public CVisibleInfo { - std::shared_ptr comp; + std::shared_ptr comps; std::shared_ptr text; public: - VisibleComponentInfo(const Component & compToDisplay, std::string message); + VisibleComponentInfo(const std::vector & compsToDisplay, std::string message); }; enum EState @@ -127,8 +128,8 @@ public: /// show new day/week animation void showDate(); - /// show component for 3 seconds. Used to display picked up resources - void showComponent(const Component & comp, std::string message); + /// show components for 3 seconds. Used to display picked up resources. Can display up to 8 components + void showComponents(const std::vector & comps, std::string message); /// print enemy turn progress void startEnemyTurn(PlayerColor color); diff --git a/client/widgets/CComponent.cpp b/client/widgets/CComponent.cpp index c5a5bd8f3..203bf4a96 100644 --- a/client/widgets/CComponent.cpp +++ b/client/widgets/CComponent.cpp @@ -336,9 +336,6 @@ Point CComponentBox::getOrTextPos(CComponent *left, CComponent *right) int CComponentBox::getDistance(CComponent *left, CComponent *right) { - static const int betweenImagesMin = 20; - static const int betweenSubtitlesMin = 10; - int leftSubtitle = ( left->pos.w - left->image->pos.w) / 2; int rightSubtitle = (right->pos.w - right->image->pos.w) / 2; int subtitlesOffset = leftSubtitle + rightSubtitle; @@ -348,8 +345,6 @@ int CComponentBox::getDistance(CComponent *left, CComponent *right) void CComponentBox::placeComponents(bool selectable) { - static const int betweenRows = 22; - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); if (components.empty()) return; @@ -450,7 +445,15 @@ void CComponentBox::placeComponents(bool selectable) } CComponentBox::CComponentBox(std::vector> _components, Rect position): - components(_components) + CComponentBox(_components, position, defaultBetweenImagesMin, defaultBetweenSubtitlesMin, defaultBetweenRows) +{ +} + +CComponentBox::CComponentBox(std::vector> _components, Rect position, int betweenImagesMin, int betweenSubtitlesMin, int betweenRows): + components(_components), + betweenImagesMin(betweenImagesMin), + betweenSubtitlesMin(betweenSubtitlesMin), + betweenRows(betweenRows) { type |= REDRAW_PARENT; pos = position + pos.topLeft(); @@ -458,8 +461,16 @@ CComponentBox::CComponentBox(std::vector> _component } CComponentBox::CComponentBox(std::vector> _components, Rect position, std::function _onSelect): + CComponentBox(_components, position, _onSelect, defaultBetweenImagesMin, defaultBetweenSubtitlesMin, defaultBetweenRows) +{ +} + +CComponentBox::CComponentBox(std::vector> _components, Rect position, std::function _onSelect, int betweenImagesMin, int betweenSubtitlesMin, int betweenRows): components(_components.begin(), _components.end()), - onSelect(_onSelect) + onSelect(_onSelect), + betweenImagesMin(betweenImagesMin), + betweenSubtitlesMin(betweenSubtitlesMin), + betweenRows(betweenRows) { type |= REDRAW_PARENT; pos = position + pos.topLeft(); diff --git a/client/widgets/CComponent.h b/client/widgets/CComponent.h index ba7ad3065..b56453f99 100644 --- a/client/widgets/CComponent.h +++ b/client/widgets/CComponent.h @@ -94,6 +94,14 @@ class CComponentBox : public CIntObject std::shared_ptr selected; std::function onSelect; + static constexpr int defaultBetweenImagesMin = 20; + static constexpr int defaultBetweenSubtitlesMin = 10; + static constexpr int defaultBetweenRows = 22; + + int betweenImagesMin; + int betweenSubtitlesMin; + int betweenRows; + void selectionChanged(std::shared_ptr newSelection); //get position of "or" text between these comps @@ -108,11 +116,13 @@ public: /// return index of selected item int selectedIndex(); - /// constructor for non-selectable components + /// constructors for non-selectable components CComponentBox(std::vector> components, Rect position); + CComponentBox(std::vector> components, Rect position, int betweenImagesMin, int betweenSubtitlesMin, int betweenRows); /// constructor for selectable components /// will also create "or" labels between components /// onSelect - optional function that will be called every time on selection change CComponentBox(std::vector> components, Rect position, std::function onSelect = nullptr); + CComponentBox(std::vector> components, Rect position, std::function onSelect, int betweenImagesMin, int betweenSubtitlesMin, int betweenRows); }; diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index 2d7a34105..6208ad349 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -21,7 +21,6 @@ struct GiveBonus; struct BlockingDialog; struct TeleportDialog; struct MetaString; -struct ShowInInfobox; struct StackLocation; struct ArtifactLocation; class CCreatureSet; @@ -113,7 +112,6 @@ public: virtual void removeArtifact(const ArtifactLocation &al) = 0; virtual bool moveArtifact(const ArtifactLocation &al1, const ArtifactLocation &al2) = 0; - virtual void showCompInfo(ShowInInfobox * comp)=0; virtual void heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero)=0; virtual void visitCastleObjects(const CGTownInstance * obj, const CGHeroInstance * hero)=0; virtual void stopHeroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero)=0; diff --git a/lib/IGameEventsReceiver.h b/lib/IGameEventsReceiver.h index cc9964efc..a1da28237 100644 --- a/lib/IGameEventsReceiver.h +++ b/lib/IGameEventsReceiver.h @@ -10,6 +10,7 @@ #pragma once +#include "NetPacksBase.h" #include "battle/BattleHex.h" #include "GameConstants.h" #include "int3.h" @@ -103,7 +104,7 @@ public: virtual void heroMovePointsChanged(const CGHeroInstance * hero){} //not called at the beginning of turn and after movement virtual void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town){}; virtual void receivedResource(){}; - virtual void showInfoDialog(const std::string & text, const std::vector & components, int soundID){}; + virtual void showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector & components, int soundID){}; virtual void showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level){} virtual void showShipyardDialog(const IShipyard *obj){} //obj may be town or shipyard; state: 0 - can buid, 1 - lack of resources, 2 - dest tile is blocked, 3 - no water @@ -132,7 +133,6 @@ public: virtual void playerBlocked(int reason, bool start){}; //reason: 0 - upcoming battle virtual void gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult) {}; //player lost or won the game virtual void playerStartsTurn(PlayerColor player){}; - virtual void showComp(const Component &comp, std::string message) {}; //display component in the advmapint infobox //TODO shouldn't be moved down the tree? virtual void heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID queryID){}; diff --git a/lib/NetPackVisitor.h b/lib/NetPackVisitor.h index 642b90c5a..7cef3d188 100644 --- a/lib/NetPackVisitor.h +++ b/lib/NetPackVisitor.h @@ -106,7 +106,6 @@ public: virtual void visitBattleSetStackProperty(BattleSetStackProperty & pack) {} virtual void visitBattleTriggerEffect(BattleTriggerEffect & pack) {} virtual void visitBattleUpdateGateState(BattleUpdateGateState & pack) {} - virtual void visitShowInInfobox(ShowInInfobox & pack) {} virtual void visitAdvmapSpellCast(AdvmapSpellCast & pack) {} virtual void visitShowWorldViewEx(ShowWorldViewEx & pack) {} virtual void visitEndTurn(EndTurn & pack) {} diff --git a/lib/NetPacks.h b/lib/NetPacks.h index 4d823544f..c1d32d263 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -1150,6 +1150,7 @@ struct DLL_LINKAGE NewTurn : public CPackForClient struct DLL_LINKAGE InfoWindow : public CPackForClient //103 - displays simple info window { + EInfoWindowMode type = EInfoWindowMode::MODAL; MetaString text; std::vector components; PlayerColor player; @@ -1159,6 +1160,7 @@ struct DLL_LINKAGE InfoWindow : public CPackForClient //103 - displays simple i template void serialize(Handler & h, const int version) { + h & type; h & text; h & components; h & player; @@ -1873,22 +1875,6 @@ protected: virtual void visitTyped(ICPackVisitor & visitor) override; }; -struct DLL_LINKAGE ShowInInfobox : public CPackForClient -{ - PlayerColor player; - Component c; - MetaString text; - template void serialize(Handler & h, const int version) - { - h & player; - h & c; - h & text; - } - -protected: - virtual void visitTyped(ICPackVisitor & visitor) override; -}; - struct DLL_LINKAGE AdvmapSpellCast : public CPackForClient { ObjectInstanceID casterID; diff --git a/lib/NetPacksBase.h b/lib/NetPacksBase.h index 16b322c3e..29c0d09fb 100644 --- a/lib/NetPacksBase.h +++ b/lib/NetPacksBase.h @@ -35,6 +35,13 @@ struct ArtSlotInfo; class ICPackVisitor; +enum class EInfoWindowMode : uint8_t +{ + AUTO, + MODAL, + INFO +}; + struct DLL_LINKAGE CPack { std::shared_ptr c; // Pointer to connection that pack received from diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 11c80d8ee..279af9bc8 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -492,11 +492,6 @@ void BattleUpdateGateState::visitTyped(ICPackVisitor & visitor) visitor.visitBattleUpdateGateState(*this); } -void ShowInInfobox::visitTyped(ICPackVisitor & visitor) -{ - visitor.visitShowInInfobox(*this); -} - void AdvmapSpellCast::visitTyped(ICPackVisitor & visitor) { visitor.visitAdvmapSpellCast(*this); diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index cdb1dddac..5f48f8ebf 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -881,27 +881,30 @@ void CGResource::onHeroVisit( const CGHeroInstance * h ) const } } else - { - if(message.length()) - { - InfoWindow iw; - iw.player = h->tempOwner; - iw.text << message; - cb->showInfoDialog(&iw); - } collectRes(h->getOwner()); - } } void CGResource::collectRes(const PlayerColor & player) const { cb->giveResource(player, static_cast(subID), amount); - ShowInInfobox sii; + InfoWindow sii; sii.player = player; - sii.c = Component(Component::RESOURCE,subID,amount,0); + if(!message.empty()) + { + sii.type = EInfoWindowMode::AUTO; + sii.text << message; + } + else + { + sii.type = EInfoWindowMode::INFO; + sii.text.addTxt(MetaString::ADVOB_TXT,113); + sii.text.addReplacement(MetaString::RES_NAMES, subID); + } + sii.components.emplace_back(Component::RESOURCE,subID,amount,0); sii.text.addTxt(MetaString::ADVOB_TXT,113); sii.text.addReplacement(MetaString::RES_NAMES, subID); - cb->showCompInfo(&sii); + sii.soundID = soundBase::pickup01 + CRandomGenerator::getDefault().nextInt(6); + cb->showInfoDialog(&sii); cb->removeObject(this); } diff --git a/lib/registerTypes/RegisterTypes.h b/lib/registerTypes/RegisterTypes.h index cb543bd4c..e922c8aae 100644 --- a/lib/registerTypes/RegisterTypes.h +++ b/lib/registerTypes/RegisterTypes.h @@ -243,7 +243,6 @@ void registerTypesClientPacks1(Serializer &s) s.template registerType(); s.template registerType(); s.template registerType(); - s.template registerType(); s.template registerType(); s.template registerType(); s.template registerType(); diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 4b979b028..4534b1618 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -2657,10 +2657,6 @@ void CGameHandler::takeCreatures(ObjectInstanceID objid, const std::vector