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

Switching costume

This commit is contained in:
SoundSSGood 2024-04-19 17:14:41 +03:00
parent 25dea7e364
commit ce9d2d8ab8
17 changed files with 154 additions and 115 deletions

View File

@ -195,8 +195,6 @@ void CCallback::scrollBackpackArtifacts(ObjectInstanceID hero, bool left)
void CCallback::manageHeroCostume(ObjectInstanceID hero, size_t costumeIndex, bool saveCostume) void CCallback::manageHeroCostume(ObjectInstanceID hero, size_t costumeIndex, bool saveCostume)
{ {
assert(costumeIndex < GameConstants::HERO_COSTUMES_ARTIFACTS);
ManageEquippedArtifacts mea(hero, costumeIndex, saveCostume); ManageEquippedArtifacts mea(hero, costumeIndex, saveCostume);
sendRequest(&mea); sendRequest(&mea);
} }

View File

@ -314,12 +314,20 @@ CKeyShortcut::CKeyShortcut(EShortcut key)
{ {
} }
CKeyShortcut::CKeyShortcut(const EShortcut & key, const KeyPressedFunctor & keyPressedCallback)
: CKeyShortcut(key)
{
this->keyPressedCallback = keyPressedCallback;
}
void CKeyShortcut::keyPressed(EShortcut key) void CKeyShortcut::keyPressed(EShortcut key)
{ {
if( assignedKey == key && assignedKey != EShortcut::NONE && !shortcutPressed) if( assignedKey == key && assignedKey != EShortcut::NONE && !shortcutPressed)
{ {
shortcutPressed = true; shortcutPressed = true;
clickPressed(GH.getCursorPosition()); clickPressed(GH.getCursorPosition());
if(keyPressedCallback)
keyPressedCallback();
} }
} }

View File

@ -133,14 +133,19 @@ public:
/// Classes wanting use it should have it as one of their base classes /// Classes wanting use it should have it as one of their base classes
class CKeyShortcut : public virtual CIntObject class CKeyShortcut : public virtual CIntObject
{ {
bool shortcutPressed;
public: public:
using KeyPressedFunctor = std::function<void()>;
EShortcut assignedKey; EShortcut assignedKey;
CKeyShortcut(); CKeyShortcut();
CKeyShortcut(EShortcut key); CKeyShortcut(EShortcut key);
CKeyShortcut(const EShortcut & key, const KeyPressedFunctor & keyPressedCallback);
void keyPressed(EShortcut key) override; void keyPressed(EShortcut key) override;
void keyReleased(EShortcut key) override; void keyReleased(EShortcut key) override;
private:
bool shortcutPressed;
KeyPressedFunctor keyPressedCallback;
}; };
class WindowBase : public CIntObject class WindowBase : public CIntObject

View File

@ -18,7 +18,7 @@
#include "../../CCallback.h" #include "../../CCallback.h"
#include "../../lib/networkPacks/ArtifactLocation.h" #include "../../lib/networkPacks/ArtifactLocation.h"
CArtifactsOfHeroMain::CArtifactsOfHeroMain(const Point & position, bool costumesEnabled) CArtifactsOfHeroMain::CArtifactsOfHeroMain(const Point & position)
{ {
init( init(
std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2), std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2),
@ -26,21 +26,6 @@ CArtifactsOfHeroMain::CArtifactsOfHeroMain(const Point & position, bool costumes
position, position,
std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, _1)); std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, _1));
addGestureCallback(std::bind(&CArtifactsOfHeroBase::gestureArtPlace, this, _1, _2)); addGestureCallback(std::bind(&CArtifactsOfHeroBase::gestureArtPlace, this, _1, _2));
if(costumesEnabled)
{
size_t costumeIndex = 0;
for(const auto & hotkey : hotkeys)
{
auto keyProc = costumesSwitchers.emplace_back(std::make_shared<CKeyShortcutWrapper>(hotkey,
[this, hotkey, costumeIndex]()
{
CArtifactsOfHeroMain::onCostumeSelect(costumeIndex);
}));
keyProc->addUsedEvents(AEventsReceiver::KEYBOARD);
costumeIndex++;
}
}
} }
CArtifactsOfHeroMain::~CArtifactsOfHeroMain() CArtifactsOfHeroMain::~CArtifactsOfHeroMain()
@ -48,19 +33,17 @@ CArtifactsOfHeroMain::~CArtifactsOfHeroMain()
CArtifactsOfHeroBase::putBackPickedArtifact(); CArtifactsOfHeroBase::putBackPickedArtifact();
} }
void CArtifactsOfHeroMain::onCostumeSelect(const size_t costumeIndex) void CArtifactsOfHeroMain::enableArtifactsCostumeSwitcher()
{ {
LOCPLINT->cb->manageHeroCostume(getHero()->id, costumeIndex, GH.isKeyboardCtrlDown()); size_t costumeIdx = 0;
} for(const auto & hotkey : costumesSwitcherHotkeys)
{
CArtifactsOfHeroMain::CKeyShortcutWrapper::CKeyShortcutWrapper(const EShortcut & key, const KeyPressedFunctor & onCostumeSelect) auto keyProc = costumesSwitcherProcessors.emplace_back(std::make_shared<CKeyShortcut>(hotkey,
: CKeyShortcut(key) [this, costumeIdx]()
, onCostumeSelect(onCostumeSelect) {
{ LOCPLINT->cb->manageHeroCostume(getHero()->id, costumeIdx, GH.isKeyboardCtrlDown());
} }));
keyProc->addUsedEvents(AEventsReceiver::KEYBOARD);
void CArtifactsOfHeroMain::CKeyShortcutWrapper::clickPressed(const Point & cursorPosition) costumeIdx++;
{ }
if(onCostumeSelect)
onCostumeSelect();
} }

View File

@ -16,24 +16,12 @@
class CArtifactsOfHeroMain : public CArtifactsOfHeroBase class CArtifactsOfHeroMain : public CArtifactsOfHeroBase
{ {
public: public:
CArtifactsOfHeroMain(const Point & position, bool costumesEnabled = false); CArtifactsOfHeroMain(const Point & position);
~CArtifactsOfHeroMain() override; ~CArtifactsOfHeroMain() override;
void enableArtifactsCostumeSwitcher();
private: private:
// TODO may be removed if CKeyShortcut supports callbacks const std::vector<EShortcut> costumesSwitcherHotkeys =
class CKeyShortcutWrapper : public CKeyShortcut
{
public:
using KeyPressedFunctor = std::function<void()>;
CKeyShortcutWrapper(const EShortcut & key, const KeyPressedFunctor & onCostumeSelect);
void clickPressed(const Point & cursorPosition) override;
private:
KeyPressedFunctor onCostumeSelect;
};
const std::array<EShortcut, GameConstants::HERO_COSTUMES_ARTIFACTS> hotkeys =
{ {
EShortcut::HERO_COSTUME_0, EShortcut::HERO_COSTUME_0,
EShortcut::HERO_COSTUME_1, EShortcut::HERO_COSTUME_1,
@ -46,7 +34,5 @@ private:
EShortcut::HERO_COSTUME_8, EShortcut::HERO_COSTUME_8,
EShortcut::HERO_COSTUME_9 EShortcut::HERO_COSTUME_9
}; };
std::vector<std::shared_ptr<CKeyShortcutWrapper>> costumesSwitchers; std::vector<std::shared_ptr<CKeyShortcut>> costumesSwitcherProcessors;
void onCostumeSelect(const size_t costumeIndex);
}; };

View File

@ -218,9 +218,10 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded)
} }
if(!arts) if(!arts)
{ {
arts = std::make_shared<CArtifactsOfHeroMain>(Point(-65, -8), true); arts = std::make_shared<CArtifactsOfHeroMain>(Point(-65, -8));
arts->setHero(curHero); arts->setHero(curHero);
addSetAndCallbacks(arts); addSetAndCallbacks(arts);
enableArtifactsCostumeSwitcher();
} }
int serial = LOCPLINT->cb->getHeroSerial(curHero, false); int serial = LOCPLINT->cb->getHeroSerial(curHero, false);

View File

@ -343,6 +343,20 @@ void CWindowWithArtifacts::deactivate()
CWindowObject::deactivate(); CWindowObject::deactivate();
} }
void CWindowWithArtifacts::enableArtifactsCostumeSwitcher()
{
for(auto artSet : artSets)
std::visit(
[](auto artSetWeak)
{
if constexpr(std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroMain>>)
{
const auto artSetPtr = artSetWeak.lock();
artSetPtr->enableArtifactsCostumeSwitcher();
}
}, artSet);
}
void CWindowWithArtifacts::artifactRemoved(const ArtifactLocation & artLoc) void CWindowWithArtifacts::artifactRemoved(const ArtifactLocation & artLoc)
{ {
update(); update();

View File

@ -42,6 +42,7 @@ public:
void gestureArtPlaceHero(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition); void gestureArtPlaceHero(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition);
void activate() override; void activate() override;
void deactivate() override; void deactivate() override;
void enableArtifactsCostumeSwitcher();
virtual void artifactRemoved(const ArtifactLocation & artLoc); virtual void artifactRemoved(const ArtifactLocation & artLoc);
virtual void artifactMoved(const ArtifactLocation & srcLoc, const ArtifactLocation & destLoc, bool withRedraw); virtual void artifactMoved(const ArtifactLocation & srcLoc, const ArtifactLocation & destLoc, bool withRedraw);

View File

@ -52,7 +52,7 @@ DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::unmovableSlots(
return positions; return positions;
} }
DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::constituentWornSlots() DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::commonWornSlots()
{ {
static const std::vector<ArtifactPosition> positions = static const std::vector<ArtifactPosition> positions =
{ {

View File

@ -30,7 +30,7 @@ namespace ArtifactUtils
DLL_LINKAGE ArtifactPosition getArtBackpackPosition(const CArtifactSet * target, const ArtifactID & aid); DLL_LINKAGE ArtifactPosition getArtBackpackPosition(const CArtifactSet * target, const ArtifactID & aid);
// TODO: Make this constexpr when the toolset is upgraded // TODO: Make this constexpr when the toolset is upgraded
DLL_LINKAGE const std::vector<ArtifactPosition> & unmovableSlots(); DLL_LINKAGE const std::vector<ArtifactPosition> & unmovableSlots();
DLL_LINKAGE const std::vector<ArtifactPosition> & constituentWornSlots(); DLL_LINKAGE const std::vector<ArtifactPosition> & commonWornSlots();
DLL_LINKAGE const std::vector<ArtifactPosition> & allWornSlots(); DLL_LINKAGE const std::vector<ArtifactPosition> & allWornSlots();
DLL_LINKAGE const std::vector<ArtifactPosition> & commanderSlots(); DLL_LINKAGE const std::vector<ArtifactPosition> & commanderSlots();
DLL_LINKAGE bool isArtRemovable(const std::pair<ArtifactPosition, ArtSlotInfo> & slot); DLL_LINKAGE bool isArtRemovable(const std::pair<ArtifactPosition, ArtSlotInfo> & slot);

View File

@ -1086,6 +1086,14 @@ CArtifactFittingSet::CArtifactFittingSet(ArtBearer::ArtBearer Bearer):
{ {
} }
CArtifactFittingSet::CArtifactFittingSet(const CArtifactSet & artSet)
: CArtifactFittingSet(artSet.bearerType())
{
artifactsWorn = artSet.artifactsWorn;
artifactsInBackpack = artSet.artifactsInBackpack;
artifactsTransitionPos = artSet.artifactsTransitionPos;
}
ArtBearer::ArtBearer CArtifactFittingSet::bearerType() const ArtBearer::ArtBearer CArtifactFittingSet::bearerType() const
{ {
return this->Bearer; return this->Bearer;

View File

@ -249,6 +249,7 @@ class DLL_LINKAGE CArtifactFittingSet : public CArtifactSet
{ {
public: public:
CArtifactFittingSet(ArtBearer::ArtBearer Bearer); CArtifactFittingSet(ArtBearer::ArtBearer Bearer);
CArtifactFittingSet(const CArtifactSet & artSet);
ArtBearer::ArtBearer bearerType() const override; ArtBearer::ArtBearer bearerType() const override;
protected: protected:

View File

@ -1075,7 +1075,7 @@ void ChangeObjectVisitors::applyGs(CGameState * gs) const
void ChangeArtifactsCostume::applyGs(CGameState * gs) const void ChangeArtifactsCostume::applyGs(CGameState * gs) const
{ {
auto & allCostumes = gs->getPlayerState(player)->costumesArtifacts; auto & allCostumes = gs->getPlayerState(player)->costumesArtifacts;
if(auto & costume = allCostumes.find(costumeIdx); costume != allCostumes.end()) if(const auto & costume = allCostumes.find(costumeIdx); costume != allCostumes.end())
costume->second = costumeSet; costume->second = costumeSet;
else else
allCostumes.emplace(costumeIdx, costumeSet); allCostumes.emplace(costumeIdx, costumeSet);
@ -1802,69 +1802,47 @@ void MoveArtifact::applyGs(CGameState * gs)
void BulkMoveArtifacts::applyGs(CGameState * gs) void BulkMoveArtifacts::applyGs(CGameState * gs)
{ {
enum class EBulkArtsOp const auto bulkArtsRemove = [](std::vector<LinkedSlots> & artsPack, CArtifactSet & artSet)
{ {
BULK_MOVE, std::vector<ArtifactPosition> packToRemove;
BULK_REMOVE, for(const auto & slotsPair : artsPack)
BULK_PUT packToRemove.push_back(slotsPair.srcPos);
std::sort(packToRemove.begin(), packToRemove.end(), [](const ArtifactPosition & slot0, const ArtifactPosition & slot1) -> bool
{
return slot0.num > slot1.num;
});
for(const auto & slot : packToRemove)
{
auto * art = artSet.getArt(slot);
assert(art);
art->removeFrom(artSet, slot);
}
}; };
auto bulkArtsOperation = [this, gs](std::vector<LinkedSlots> & artsPack, const auto bulkArtsPut = [](std::vector<LinkedSlots> & artsPack, CArtifactSet & initArtSet, CArtifactSet & dstArtSet)
CArtifactSet & artSet, EBulkArtsOp operation) -> void
{ {
int numBackpackArtifactsMoved = 0; for(const auto & slotsPair : artsPack)
for(auto & slot : artsPack)
{ {
// When an object gets removed from the backpack, the backpack shrinks auto * art = initArtSet.getArt(slotsPair.srcPos);
// so all the following indices will be affected. Thus, we need to update
// the subsequent artifact slots to account for that
auto srcPos = slot.srcPos;
if(ArtifactUtils::isSlotBackpack(srcPos) && (operation != EBulkArtsOp::BULK_PUT))
{
srcPos = ArtifactPosition(srcPos.num - numBackpackArtifactsMoved);
}
auto * art = artSet.getArt(srcPos);
assert(art); assert(art);
switch(operation) art->putAt(dstArtSet, slotsPair.dstPos);
{
case EBulkArtsOp::BULK_MOVE:
art->move(artSet, srcPos, *gs->getArtSet(ArtifactLocation(dstArtHolder, dstCreature)), slot.dstPos);
break;
case EBulkArtsOp::BULK_REMOVE:
art->removeFrom(artSet, srcPos);
break;
case EBulkArtsOp::BULK_PUT:
art->putAt(*gs->getArtSet(ArtifactLocation(srcArtHolder, srcCreature)), slot.dstPos);
break;
default:
break;
}
if(srcPos >= ArtifactPosition::BACKPACK_START)
{
numBackpackArtifactsMoved++;
}
} }
}; };
auto * leftSet = gs->getArtSet(ArtifactLocation(srcArtHolder, srcCreature)); auto * leftSet = gs->getArtSet(ArtifactLocation(srcArtHolder, srcCreature));
if(swap) assert(leftSet);
{
// Swap
auto * rightSet = gs->getArtSet(ArtifactLocation(dstArtHolder, dstCreature)); auto * rightSet = gs->getArtSet(ArtifactLocation(dstArtHolder, dstCreature));
CArtifactFittingSet artFittingSet(leftSet->bearerType()); assert(rightSet);
CArtifactFittingSet artInitialSetLeft(*leftSet);
artFittingSet.artifactsWorn = rightSet->artifactsWorn; bulkArtsRemove(artsPack0, *leftSet);
artFittingSet.artifactsInBackpack = rightSet->artifactsInBackpack; if(!artsPack1.empty())
bulkArtsOperation(artsPack1, *rightSet, EBulkArtsOp::BULK_REMOVE);
bulkArtsOperation(artsPack0, *leftSet, EBulkArtsOp::BULK_MOVE);
bulkArtsOperation(artsPack1, artFittingSet, EBulkArtsOp::BULK_PUT);
}
else
{ {
bulkArtsOperation(artsPack0, *leftSet, EBulkArtsOp::BULK_MOVE); CArtifactFittingSet artInitialSetRight(*rightSet);
bulkArtsRemove(artsPack1, *rightSet);
bulkArtsPut(artsPack1, artInitialSetRight, *leftSet);
} }
bulkArtsPut(artsPack0, artInitialSetLeft, *rightSet);
} }
void AssembledArtifact::applyGs(CGameState *gs) void AssembledArtifact::applyGs(CGameState *gs)

View File

@ -1291,8 +1291,8 @@ struct DLL_LINKAGE ChangeObjectVisitors : public CPackForClient
struct DLL_LINKAGE ChangeArtifactsCostume : public CPackForClient struct DLL_LINKAGE ChangeArtifactsCostume : public CPackForClient
{ {
std::map<ArtifactPosition, ArtifactID> costumeSet; std::map<ArtifactPosition, ArtifactID> costumeSet;
size_t costumeIdx; size_t costumeIdx = 0;
const PlayerColor player; const PlayerColor player = PlayerColor::NEUTRAL;
void applyGs(CGameState * gs) const; void applyGs(CGameState * gs) const;
void visitTyped(ICPackVisitor & visitor) override; void visitTyped(ICPackVisitor & visitor) override;

View File

@ -2896,13 +2896,11 @@ bool CGameHandler::saveArtifactsCostume(const PlayerColor & player, const Object
{ {
auto artSet = getArtSet(heroID); auto artSet = getArtSet(heroID);
COMPLAIN_RET_FALSE_IF(artSet == nullptr, "saveArtifactsCostume: wrong hero's ID"); COMPLAIN_RET_FALSE_IF(artSet == nullptr, "saveArtifactsCostume: wrong hero's ID");
COMPLAIN_RET_FALSE_IF(costumeIdx >= GameConstants::HERO_COSTUMES_ARTIFACTS, "saveArtifactsCostume: wrong costume index");
ChangeArtifactsCostume costume(player, costumeIdx); ChangeArtifactsCostume costume(player, costumeIdx);
for(const auto & slot : ArtifactUtils::constituentWornSlots()) for(const auto & slot : ArtifactUtils::commonWornSlots())
{ {
if(const auto & slotInfo = artSet->getSlot(slot)) if(const auto slotInfo = artSet->getSlot(slot); slotInfo != nullptr && !slotInfo->locked)
if(!slotInfo->locked)
costume.costumeSet.emplace(slot, slotInfo->getArt()->getTypeId()); costume.costumeSet.emplace(slot, slotInfo->getArt()->getTypeId());
} }
@ -2910,6 +2908,62 @@ bool CGameHandler::saveArtifactsCostume(const PlayerColor & player, const Object
return true; return true;
} }
bool CGameHandler::switchArtifactsCostume(const PlayerColor & player, const ObjectInstanceID heroID, size_t costumeIdx)
{
const auto artSet = getArtSet(heroID);
COMPLAIN_RET_FALSE_IF(artSet == nullptr, "switchArtifactsCostume: wrong hero's ID");
const auto playerState = getPlayerState(player);
COMPLAIN_RET_FALSE_IF(playerState == nullptr, "switchArtifactsCostume: wrong player");
if(auto costume = playerState->costumesArtifacts.find(costumeIdx); costume != playerState->costumesArtifacts.end())
{
CArtifactFittingSet artFittingSet(*artSet);
BulkMoveArtifacts bma(player, heroID, heroID, false);
auto costumeArtMap = costume->second;
auto estimateBackpackSize = artSet->artifactsInBackpack.size();
// First, find those artifacts that are already in place
for(const auto & slot : ArtifactUtils::commonWornSlots())
{
if(const auto * slotInfo = artFittingSet.getSlot(slot); slotInfo != nullptr && !slotInfo->locked)
if(const auto artPos = costumeArtMap.find(slot); artPos != costumeArtMap.end() && artPos->second == slotInfo->getArt()->getTypeId())
{
costumeArtMap.erase(artPos);
artFittingSet.removeArtifact(slot);
}
}
// Second, find the necessary artifacts for the costume
for(const auto & artPos : costumeArtMap)
{
if(const auto availableArts = artFittingSet.getAllArtPositions(artPos.second, false, false, false); !availableArts.empty())
{
bma.artsPack0.emplace_back(BulkMoveArtifacts::LinkedSlots
{
artSet->getSlotByInstance(artFittingSet.getArt(availableArts.front())),
artPos.first
});
artFittingSet.removeArtifact(availableArts.front());
if(ArtifactUtils::isSlotBackpack(availableArts.front()))
estimateBackpackSize--;
}
}
// Third, put unnecessary artifacts into backpack
for(const auto & slot : ArtifactUtils::commonWornSlots())
if(artFittingSet.getArt(slot))
{
bma.artsPack0.emplace_back(BulkMoveArtifacts::LinkedSlots{slot, ArtifactPosition::BACKPACK_START});
estimateBackpackSize++;
}
const auto backpackCap = VLC->settings()->getInteger(EGameSettings::HEROES_BACKPACK_CAP);
if((backpackCap < 0 || estimateBackpackSize <= backpackCap) && !bma.artsPack0.empty())
sendAndApply(&bma);
}
return true;
}
/** /**
* Assembles or disassembles a combination artifact. * Assembles or disassembles a combination artifact.
* @param heroID ID of hero holding the artifact(s). * @param heroID ID of hero holding the artifact(s).

View File

@ -131,6 +131,7 @@ public:
bool bulkMoveArtifacts(const PlayerColor & player, ObjectInstanceID srcId, ObjectInstanceID dstId, bool swap, bool equipped, bool backpack); bool bulkMoveArtifacts(const PlayerColor & player, ObjectInstanceID srcId, ObjectInstanceID dstId, bool swap, bool equipped, bool backpack);
bool scrollBackpackArtifacts(const PlayerColor & player, const ObjectInstanceID heroID, bool left); bool scrollBackpackArtifacts(const PlayerColor & player, const ObjectInstanceID heroID, bool left);
bool saveArtifactsCostume(const PlayerColor & player, const ObjectInstanceID heroID, size_t costumeIdx); bool saveArtifactsCostume(const PlayerColor & player, const ObjectInstanceID heroID, size_t costumeIdx);
bool switchArtifactsCostume(const PlayerColor & player, const ObjectInstanceID heroID, size_t costumeIdx);
bool eraseArtifactByClient(const ArtifactLocation & al); bool eraseArtifactByClient(const ArtifactLocation & al);
void synchronizeArtifactHandlerLists(); void synchronizeArtifactHandlerLists();

View File

@ -183,8 +183,9 @@ void ApplyGhNetPackVisitor::visitManageEquippedArtifacts(ManageEquippedArtifacts
{ {
gh.throwIfWrongOwner(&pack, pack.artHolder); gh.throwIfWrongOwner(&pack, pack.artHolder);
if(pack.saveCostume) if(pack.saveCostume)
gh.saveArtifactsCostume(pack.player, pack.artHolder, pack.costumeIdx); result = gh.saveArtifactsCostume(pack.player, pack.artHolder, pack.costumeIdx);
result = true; else
result = gh.switchArtifactsCostume(pack.player, pack.artHolder, pack.costumeIdx);
} }
void ApplyGhNetPackVisitor::visitAssembleArtifacts(AssembleArtifacts & pack) void ApplyGhNetPackVisitor::visitAssembleArtifacts(AssembleArtifacts & pack)