PrimeWorldEditor/src/Editor/Undo/CDeleteSelectionCommand.cpp

173 lines
6.4 KiB
C++

#include "CDeleteSelectionCommand.h"
#include "Editor/CSelectionIterator.h"
#include <Common/FileIO.h>
#include <Core/Resource/Cooker/CScriptCooker.h>
#include <Core/Resource/Factory/CScriptLoader.h>
CDeleteSelectionCommand::CDeleteSelectionCommand(CWorldEditor *pEditor, const QString& rkCommandName /*= "Delete"*/)
: IUndoCommand(rkCommandName)
, mpEditor(pEditor)
{
QSet<CLink*> Links;
QList<CScriptObject*> LinkedInstances;
for (CSelectionIterator It(pEditor->Selection()); It; ++It)
{
mOldSelection << *It;
if (It->NodeType() == ENodeType::Script)
{
CScriptNode *pScript = static_cast<CScriptNode*>(*It);
CScriptObject *pInst = pScript->Instance();
mDeletedNodes.push_back(SDeletedNode());
SDeletedNode& rNode = mDeletedNodes.back();
rNode.NodePtr = CNodePtr(pScript);
rNode.NodeID = pScript->ID();
rNode.Position = pScript->LocalPosition();
rNode.Rotation = pScript->LocalRotation();
rNode.Scale = pScript->LocalScale();
rNode.pArea = pInst->Area();
rNode.pLayer = pInst->Layer();
rNode.LayerIndex = pInst->LayerIndex();
for (uint32 iType = 0; iType < 2; iType++)
{
ELinkType Type = (iType == 0 ? ELinkType::Outgoing : ELinkType::Incoming);
for (uint32 iLink = 0; iLink < pInst->NumLinks(Type); iLink++)
{
CLink *pLink = pInst->Link(Type, iLink);
if (!Links.contains(pLink))
{
SDeletedLink Link;
Link.State = pLink->State();
Link.Message = pLink->Message();
Link.SenderID = pLink->SenderID();
Link.SenderIndex = pLink->SenderIndex();
Link.ReceiverID = pLink->ReceiverID();
Link.ReceiverIndex = pLink->ReceiverIndex();
Link.pSender = pLink->Sender();
Link.pReceiver = pLink->Receiver();
mDeletedLinks << Link;
Links << pLink;
if (!LinkedInstances.contains(pLink->Sender()))
LinkedInstances << pLink->Sender();
if (!LinkedInstances.contains(pLink->Receiver()))
LinkedInstances << pLink->Receiver();
}
}
}
CVectorOutStream PropertyDataOut(&rNode.InstanceData, EEndian::BigEndian);
CScriptCooker Cooker(pEditor->CurrentGame());
Cooker.WriteInstance(PropertyDataOut, pInst);
}
else
mNewSelection << *It;
}
// Remove selected objects from the linked instances list.
LinkedInstances.removeAll(nullptr);
foreach (CScriptObject *pInst, LinkedInstances)
{
if (mpEditor->Scene()->NodeForInstance(pInst)->IsSelected())
LinkedInstances.removeOne(pInst);
}
mLinkedInstances = LinkedInstances;
}
void CDeleteSelectionCommand::undo()
{
QList<CSceneNode*> NewNodes;
QList<uint32> NewInstanceIDs;
// Spawn nodes
for (int iNode = 0; iNode < mDeletedNodes.size(); iNode++)
{
SDeletedNode& rNode = mDeletedNodes[iNode];
mpEditor->NotifyNodeAboutToBeSpawned();
CMemoryInStream Mem(rNode.InstanceData.data(), rNode.InstanceData.size(), EEndian::BigEndian);
CScriptObject *pInstance = CScriptLoader::LoadInstance(Mem, rNode.pArea, rNode.pLayer, rNode.pArea->Game(), true);
CScriptNode *pNode = mpEditor->Scene()->CreateScriptNode(pInstance, rNode.NodeID);
rNode.pArea->AddInstanceToArea(pInstance);
rNode.pLayer->AddInstance(pInstance, rNode.LayerIndex);
pNode->SetPosition(rNode.Position);
pNode->SetRotation(rNode.Rotation);
pNode->SetScale(rNode.Scale);
NewNodes << pNode;
NewInstanceIDs << pInstance->InstanceID();
mpEditor->NotifyNodeSpawned(*rNode.NodePtr);
}
// Sort links by sender index, add outgoing
std::sort(mDeletedLinks.begin(), mDeletedLinks.end(), [](SDeletedLink& rLeft, SDeletedLink& rRight) -> bool {
return (rLeft.SenderIndex < rRight.SenderIndex);
});
for (int iLink = 0; iLink < mDeletedLinks.size(); iLink++)
{
SDeletedLink& rLink = mDeletedLinks[iLink];
// Adding to the sender is only needed if the sender is not one of the nodes we just spawned. If it is, it already has this link.
if (!NewInstanceIDs.contains(rLink.SenderID) && *rLink.pSender)
{
CLink *pLink = new CLink(rLink.pSender->Area(), rLink.State, rLink.Message, rLink.SenderID, rLink.ReceiverID);
rLink.pSender->AddLink(ELinkType::Outgoing, pLink, rLink.SenderIndex);
}
}
// Sort links by receiver index, add incoming
std::sort(mDeletedLinks.begin(), mDeletedLinks.end(), [](SDeletedLink& rLeft, SDeletedLink& rRight) -> bool {
return (rLeft.ReceiverIndex < rRight.ReceiverIndex);
});
for (int iLink = 0; iLink < mDeletedLinks.size(); iLink++)
{
SDeletedLink& rLink = mDeletedLinks[iLink];
if (*rLink.pReceiver)
{
CLink *pLink = (*rLink.pSender ? rLink.pSender->Link(ELinkType::Outgoing, rLink.SenderIndex) : new CLink(rLink.pReceiver->Area(), rLink.State, rLink.Message, rLink.SenderID, rLink.ReceiverID));
rLink.pReceiver->AddLink(ELinkType::Incoming, pLink, rLink.ReceiverIndex);
}
}
// Run OnLoadFinished
foreach (CSceneNode *pNode, NewNodes)
pNode->OnLoadFinished();
// Add selection and done
mpEditor->Selection()->SetSelectedNodes(mOldSelection.DereferenceList());
mpEditor->OnLinksModified(mLinkedInstances.DereferenceList());
}
void CDeleteSelectionCommand::redo()
{
mpEditor->Selection()->SetSelectedNodes(mNewSelection.DereferenceList());
for (int iNode = 0; iNode < mDeletedNodes.size(); iNode++)
{
SDeletedNode& rNode = mDeletedNodes[iNode];
CSceneNode *pNode = *rNode.NodePtr;
CScriptObject *pInst = static_cast<CScriptNode*>(pNode)->Instance();
mpEditor->NotifyNodeAboutToBeDeleted(pNode);
mpEditor->Scene()->DeleteNode(pNode);
mpEditor->ActiveArea()->DeleteInstance(pInst);
mpEditor->NotifyNodeDeleted();
}
mpEditor->OnLinksModified(mLinkedInstances.DereferenceList());
}