diff --git a/src/Core/Resource/CGameArea.cpp b/src/Core/Resource/CGameArea.cpp index a3ddf0a9..f2c004fb 100644 --- a/src/Core/Resource/CGameArea.cpp +++ b/src/Core/Resource/CGameArea.cpp @@ -158,16 +158,7 @@ CScriptObject* CGameArea::SpawnInstance(CScriptTemplate *pTemplate, if (InstanceID == -1) { // Determine layer index - u32 LayerIndex = -1; - - for (u32 iLyr = 0; iLyr < mScriptLayers.size(); iLyr++) - { - if (mScriptLayers[iLyr] == pLayer) - { - LayerIndex = iLyr; - break; - } - } + u32 LayerIndex = pLayer->AreaIndex(); if (LayerIndex == -1) { @@ -202,8 +193,16 @@ CScriptObject* CGameArea::SpawnInstance(CScriptTemplate *pTemplate, return pInstance; } +void CGameArea::AddInstanceToArea(CScriptObject *pInstance) +{ + // Used for undo after deleting an instance. + // In the future the script loader should go through SpawnInstance to avoid the need for this function. + mObjectMap[pInstance->InstanceID()] = pInstance; +} + void CGameArea::DeleteInstance(CScriptObject *pInstance) { + pInstance->BreakAllLinks(); pInstance->Layer()->RemoveInstance(pInstance); pInstance->Template()->RemoveObject(pInstance); @@ -213,6 +212,5 @@ void CGameArea::DeleteInstance(CScriptObject *pInstance) if (mpPoiToWorldMap && mpPoiToWorldMap->HasPoiMappings(pInstance->InstanceID())) mpPoiToWorldMap->RemovePoi(pInstance->InstanceID()); - pInstance->BreakAllLinks(); delete pInstance; } diff --git a/src/Core/Resource/CGameArea.h b/src/Core/Resource/CGameArea.h index 9fc863f3..ce96a38b 100644 --- a/src/Core/Resource/CGameArea.h +++ b/src/Core/Resource/CGameArea.h @@ -74,6 +74,7 @@ public: const CQuaternion& rkRotation = CQuaternion::skIdentity, const CVector3f& rkScale = CVector3f::skOne, u32 SuggestedID = -1, u32 SuggestedLayerIndex = -1); + void AddInstanceToArea(CScriptObject *pInstance); void DeleteInstance(CScriptObject *pInstance); // Inline Accessors diff --git a/src/Core/Resource/Cooker/CScriptCooker.cpp b/src/Core/Resource/Cooker/CScriptCooker.cpp index e1818414..9ef065d0 100644 --- a/src/Core/Resource/Cooker/CScriptCooker.cpp +++ b/src/Core/Resource/Cooker/CScriptCooker.cpp @@ -292,3 +292,15 @@ void CScriptCooker::WriteLayer(EGame Game, CScriptLayer *pLayer, IOutputStream& else Cooker.WriteLayerMP2(pLayer); } + +void CScriptCooker::CookInstance(EGame Game, CScriptObject *pInstance, IOutputStream& rOut) +{ + CScriptCooker Cooker; + Cooker.mpSCLY = &rOut; + Cooker.mVersion = Game; + + if (Game <= ePrime) + Cooker.WriteInstanceMP1(pInstance); + else + Cooker.WriteInstanceMP2(pInstance); +} diff --git a/src/Core/Resource/Cooker/CScriptCooker.h b/src/Core/Resource/Cooker/CScriptCooker.h index fd8fbdec..932f55d8 100644 --- a/src/Core/Resource/Cooker/CScriptCooker.h +++ b/src/Core/Resource/Cooker/CScriptCooker.h @@ -20,6 +20,7 @@ class CScriptCooker public: static void WriteLayer(EGame Game, CScriptLayer *pLayer, IOutputStream& rOut); + static void CookInstance(EGame Game, CScriptObject *pInstance, IOutputStream& rOut); }; #endif // CSCRIPTCOOKER_H diff --git a/src/Core/Resource/Factory/CScriptLoader.cpp b/src/Core/Resource/Factory/CScriptLoader.cpp index 29acb3c2..40b75436 100644 --- a/src/Core/Resource/Factory/CScriptLoader.cpp +++ b/src/Core/Resource/Factory/CScriptLoader.cpp @@ -11,7 +11,7 @@ CScriptLoader::CScriptLoader() mpObj = nullptr; } -void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY) +void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& rSCLY) { IPropertyTemplate *pTemp = pProp->Template(); @@ -20,31 +20,31 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY) case eBoolProperty: { TBoolProperty *pBoolCast = static_cast(pProp); - pBoolCast->Set( (SCLY.ReadByte() != 0) ); + pBoolCast->Set( (rSCLY.ReadByte() != 0) ); break; } case eByteProperty: { TByteProperty *pByteCast = static_cast(pProp); - pByteCast->Set(SCLY.ReadByte()); + pByteCast->Set(rSCLY.ReadByte()); break; } case eShortProperty: { TShortProperty *pShortCast = static_cast(pProp); - pShortCast->Set(SCLY.ReadShort()); + pShortCast->Set(rSCLY.ReadShort()); break; } case eLongProperty: { TLongProperty *pLongCast = static_cast(pProp); - pLongCast->Set(SCLY.ReadLong()); + pLongCast->Set(rSCLY.ReadLong()); break; } case eBitfieldProperty: { TBitfieldProperty *pBitfieldCast = static_cast(pProp); - pBitfieldCast->Set(SCLY.ReadLong()); + pBitfieldCast->Set(rSCLY.ReadLong()); // Validate u32 mask = 0; @@ -54,7 +54,7 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY) u32 check = pBitfieldCast->Get() & ~mask; if (check != 0) - Log::FileWarning(SCLY.GetSourceString(), SCLY.Tell() - 4, "Bitfield property \"" + pBitfieldTemp->Name() + "\" in struct \"" + pTemp->Name() + "\" has flags set that aren't in the template: " + TString::HexString(check, true, true, 8)); + Log::FileWarning(rSCLY.GetSourceString(), rSCLY.Tell() - 4, "Bitfield property \"" + pBitfieldTemp->Name() + "\" in struct \"" + pTemp->Name() + "\" has flags set that aren't in the template: " + TString::HexString(check, true, true, 8)); break; } @@ -62,11 +62,11 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY) case eEnumProperty: { TEnumProperty *pEnumCast = static_cast(pProp); CEnumTemplate *pEnumTemp = static_cast(pTemp); - u32 ID = SCLY.ReadLong(); + u32 ID = rSCLY.ReadLong(); // Validate u32 Index = pEnumTemp->EnumeratorIndex(ID); - if (Index == -1) Log::FileError(SCLY.GetSourceString(), SCLY.Tell() - 4, "Enum property \"" + pEnumTemp->Name() + "\" in struct \"" + pTemp->Name() + "\" has invalid enumerator value: " + TString::HexString(ID, true, true, 8)); + if (Index == -1) Log::FileError(rSCLY.GetSourceString(), rSCLY.Tell() - 4, "Enum property \"" + pEnumTemp->Name() + "\" in struct \"" + pTemp->Name() + "\" has invalid enumerator value: " + TString::HexString(ID, true, true, 8)); pEnumCast->Set(ID); break; @@ -74,32 +74,32 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY) case eFloatProperty: { TFloatProperty *pFloatCast = static_cast(pProp); - pFloatCast->Set(SCLY.ReadFloat()); + pFloatCast->Set(rSCLY.ReadFloat()); break; } case eStringProperty: { TStringProperty *pStringCast = static_cast(pProp); - pStringCast->Set(SCLY.ReadString()); + pStringCast->Set(rSCLY.ReadString()); break; } case eVector3Property: { TVector3Property *pVector3Cast = static_cast(pProp); - pVector3Cast->Set(CVector3f(SCLY)); + pVector3Cast->Set(CVector3f(rSCLY)); break; } case eColorProperty: { TColorProperty *pColorCast = static_cast(pProp); - pColorCast->Set(CColor(SCLY)); + pColorCast->Set(CColor(rSCLY)); break; } case eFileProperty: { TFileProperty *pFileCast = static_cast(pProp); - CUniqueID ResID = (mVersion < eCorruptionProto ? SCLY.ReadLong() : SCLY.ReadLongLong()); + CUniqueID ResID = (mVersion < eCorruptionProto ? rSCLY.ReadLong() : rSCLY.ReadLongLong()); const TStringList& rkExtensions = static_cast(pTemp)->Extensions(); CResourceInfo Info(ResID, CFourCC(!rkExtensions.empty() ? rkExtensions.front() : "UNKN")); @@ -118,38 +118,38 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY) CPropertyStruct *pStructCast = static_cast(pProp); if (mVersion < eEchoesDemo) - LoadStructMP1(SCLY, pStructCast, static_cast(pStructCast->Template())); + LoadStructMP1(rSCLY, pStructCast, static_cast(pStructCast->Template())); else - LoadStructMP2(SCLY, pStructCast, static_cast(pTemp)); + LoadStructMP2(rSCLY, pStructCast, static_cast(pTemp)); break; } case eArrayProperty: { CArrayProperty *pArrayCast = static_cast(pProp); - int Size = SCLY.ReadLong(); + int Count = rSCLY.ReadLong(); - pArrayCast->Resize(Size); + pArrayCast->Resize(Count); - for (int iElem = 0; iElem < Size; iElem++) + for (int iElem = 0; iElem < Count; iElem++) { if (mVersion < eEchoesDemo) - LoadStructMP1(SCLY, static_cast(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate()); + LoadStructMP1(rSCLY, static_cast(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate()); else - LoadStructMP2(SCLY, static_cast(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate()); + LoadStructMP2(rSCLY, static_cast(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate()); } break; } case eCharacterProperty: { TCharacterProperty *pAnimCast = static_cast(pProp); - pAnimCast->Set(CAnimationParameters(SCLY, mVersion)); + pAnimCast->Set(CAnimationParameters(rSCLY, mpMaster->GetGame())); break; } case eMayaSplineProperty: { TMayaSplineProperty *pSplineCast = static_cast(pProp); std::vector Buffer(Size); - SCLY.ReadBytes(Buffer.data(), Buffer.size()); + rSCLY.ReadBytes(Buffer.data(), Buffer.size()); pSplineCast->Set(Buffer); break; } @@ -157,16 +157,16 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY) case eUnknownProperty: { TUnknownProperty *pUnknownCast = static_cast(pProp); std::vector Buffer(Size); - SCLY.ReadBytes(Buffer.data(), Buffer.size()); + rSCLY.ReadBytes(Buffer.data(), Buffer.size()); pUnknownCast->Set(Buffer); break; } } } -void CScriptLoader::LoadStructMP1(IInputStream& SCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp) +void CScriptLoader::LoadStructMP1(IInputStream& rSCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp) { - u32 StructStart = SCLY.Tell(); + u32 StructStart = rSCLY.Tell(); // Verify property count u32 PropCount = pTemp->Count(); @@ -174,7 +174,7 @@ void CScriptLoader::LoadStructMP1(IInputStream& SCLY, CPropertyStruct *pStruct, if (!pTemp->IsSingleProperty()) { - u32 FilePropCount = SCLY.ReadLong(); + u32 FilePropCount = rSCLY.ReadLong(); Version = pTemp->VersionForPropertyCount(FilePropCount); if (Version == -1) @@ -182,7 +182,7 @@ void CScriptLoader::LoadStructMP1(IInputStream& SCLY, CPropertyStruct *pStruct, TIDString IDString = pTemp->IDString(true); if (!IDString.IsEmpty()) IDString = " (" + IDString + ")"; - Log::FileWarning(SCLY.GetSourceString(), StructStart, "Struct \"" + pTemp->Name() + "\"" + IDString + " template prop count doesn't match file; template is " + TString::HexString(PropCount, true, true, 2) + ", file is " + TString::HexString(FilePropCount, true, true, 2)); + Log::FileWarning(rSCLY.GetSourceString(), StructStart, "Struct \"" + pTemp->Name() + "\"" + IDString + " template prop count doesn't match file; template is " + TString::HexString(PropCount, true, true, 2) + ", file is " + TString::HexString(FilePropCount, true, true, 2)); Version = 0; } } @@ -194,38 +194,38 @@ void CScriptLoader::LoadStructMP1(IInputStream& SCLY, CPropertyStruct *pStruct, IProperty *pProp = pStruct->PropertyByIndex(iProp); if (pPropTemp->CookPreference() != eNeverCook && pPropTemp->IsInVersion(Version)) - ReadProperty(pProp, 0, SCLY); + ReadProperty(pProp, 0, rSCLY); } } -CScriptObject* CScriptLoader::LoadObjectMP1(IInputStream& SCLY) +CScriptObject* CScriptLoader::LoadObjectMP1(IInputStream& rSCLY) { - u32 ObjStart = SCLY.Tell(); - u8 Type = SCLY.ReadByte(); - u32 Size = SCLY.ReadLong(); - u32 End = SCLY.Tell() + Size; + u32 ObjStart = rSCLY.Tell(); + u8 Type = rSCLY.ReadByte(); + u32 Size = rSCLY.ReadLong(); + u32 End = rSCLY.Tell() + Size; CScriptTemplate *pTemp = mpMaster->TemplateByID((u32) Type); if (!pTemp) { // No valid template for this object; can't load - Log::FileError(SCLY.GetSourceString(), ObjStart, "Unknown object ID encountered: " + TString::HexString(Type)); - SCLY.Seek(End, SEEK_SET); + Log::FileError(rSCLY.GetSourceString(), ObjStart, "Unknown object ID encountered: " + TString::HexString(Type)); + rSCLY.Seek(End, SEEK_SET); return nullptr; } - u32 InstanceID = SCLY.ReadLong(); + u32 InstanceID = rSCLY.ReadLong(); mpObj = new CScriptObject(InstanceID, mpArea, mpLayer, pTemp); // Load connections - u32 NumLinks = SCLY.ReadLong(); + u32 NumLinks = rSCLY.ReadLong(); mpObj->mOutLinks.reserve(NumLinks); for (u32 iLink = 0; iLink < NumLinks; iLink++) { - u32 State = SCLY.ReadLong(); - u32 Message = SCLY.ReadLong(); - u32 ReceiverID = SCLY.ReadLong(); + u32 State = rSCLY.ReadLong(); + u32 Message = rSCLY.ReadLong(); + u32 ReceiverID = rSCLY.ReadLong(); CLink *pLink = new CLink(mpArea, State, Message, mpObj->mInstanceID, ReceiverID); mpObj->mOutLinks.push_back(pLink); @@ -233,54 +233,54 @@ CScriptObject* CScriptLoader::LoadObjectMP1(IInputStream& SCLY) // Load object... CPropertyStruct *pBase = mpObj->mpProperties; - LoadStructMP1(SCLY, pBase, static_cast(pBase->Template())); + LoadStructMP1(rSCLY, pBase, static_cast(pBase->Template())); // Cleanup and return - SCLY.Seek(End, SEEK_SET); + rSCLY.Seek(End, SEEK_SET); mpObj->EvaluateProperties(); return mpObj; } -CScriptLayer* CScriptLoader::LoadLayerMP1(IInputStream &SCLY) +CScriptLayer* CScriptLoader::LoadLayerMP1(IInputStream& rSCLY) { - u32 LayerStart = SCLY.Tell(); + u32 LayerStart = rSCLY.Tell(); - SCLY.Seek(0x1, SEEK_CUR); // One unknown byte at the start of each layer - u32 NumObjects = SCLY.ReadLong(); + rSCLY.Seek(0x1, SEEK_CUR); // One unknown byte at the start of each layer + u32 NumObjects = rSCLY.ReadLong(); mpLayer = new CScriptLayer(mpArea); mpLayer->Reserve(NumObjects); for (u32 iObj = 0; iObj < NumObjects; iObj++) { - CScriptObject *pObj = LoadObjectMP1(SCLY); + CScriptObject *pObj = LoadObjectMP1(rSCLY); if (pObj) mpLayer->AddInstance(pObj); } // Layer sizes are always a multiple of 32 - skip end padding before returning - u32 Remaining = 32 - ((SCLY.Tell() - LayerStart) & 0x1F); - SCLY.Seek(Remaining, SEEK_CUR); + u32 Remaining = 32 - ((rSCLY.Tell() - LayerStart) & 0x1F); + rSCLY.Seek(Remaining, SEEK_CUR); return mpLayer; } -void CScriptLoader::LoadStructMP2(IInputStream& SCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp) +void CScriptLoader::LoadStructMP2(IInputStream& rSCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp) { // Verify property count - u32 StructStart = SCLY.Tell(); + u32 StructStart = rSCLY.Tell(); StructStart += 0; u32 PropCount = pTemp->Count(); if (!pTemp->IsSingleProperty()) - PropCount = SCLY.ReadShort(); + PropCount = rSCLY.ReadShort(); // Parse properties for (u32 iProp = 0; iProp < PropCount; iProp++) { IProperty *pProp; IPropertyTemplate *pPropTemp; - u32 PropertyStart = SCLY.Tell(); + u32 PropertyStart = rSCLY.Tell(); u32 PropertyID = -1; u16 PropertyLength = 0; u32 NextProperty = 0; @@ -292,79 +292,79 @@ void CScriptLoader::LoadStructMP2(IInputStream& SCLY, CPropertyStruct *pStruct, } else { - PropertyID = SCLY.ReadLong(); - PropertyLength = SCLY.ReadShort(); - NextProperty = SCLY.Tell() + PropertyLength; + PropertyID = rSCLY.ReadLong(); + PropertyLength = rSCLY.ReadShort(); + NextProperty = rSCLY.Tell() + PropertyLength; pProp = pStruct->PropertyByID(PropertyID); pPropTemp = pTemp->PropertyByID(PropertyID); } if (!pPropTemp) - Log::FileError(SCLY.GetSourceString(), PropertyStart, "Can't find template for property " + TString::HexString(PropertyID) + " - skipping"); + Log::FileError(rSCLY.GetSourceString(), PropertyStart, "Can't find template for property " + TString::HexString(PropertyID) + " - skipping"); else - ReadProperty(pProp, PropertyLength, SCLY); + ReadProperty(pProp, PropertyLength, rSCLY); if (NextProperty > 0) - SCLY.Seek(NextProperty, SEEK_SET); + rSCLY.Seek(NextProperty, SEEK_SET); } } -CScriptObject* CScriptLoader::LoadObjectMP2(IInputStream& SCLY) +CScriptObject* CScriptLoader::LoadObjectMP2(IInputStream& rSCLY) { - u32 ObjStart = SCLY.Tell(); - u32 ObjectID = SCLY.ReadLong(); - u16 ObjectSize = SCLY.ReadShort(); - u32 ObjEnd = SCLY.Tell() + ObjectSize; + u32 ObjStart = rSCLY.Tell(); + u32 ObjectID = rSCLY.ReadLong(); + u16 ObjectSize = rSCLY.ReadShort(); + u32 ObjEnd = rSCLY.Tell() + ObjectSize; CScriptTemplate *pTemplate = mpMaster->TemplateByID(ObjectID); if (!pTemplate) { - Log::FileError(SCLY.GetSourceString(), ObjStart, "Unknown object ID encountered: " + CFourCC(ObjectID).ToString()); - SCLY.Seek(ObjEnd, SEEK_SET); + Log::FileError(rSCLY.GetSourceString(), ObjStart, "Unknown object ID encountered: " + CFourCC(ObjectID).ToString()); + rSCLY.Seek(ObjEnd, SEEK_SET); return nullptr; } - u32 InstanceID = SCLY.ReadLong(); + u32 InstanceID = rSCLY.ReadLong(); mpObj = new CScriptObject(InstanceID, mpArea, mpLayer, pTemplate); // Load connections - u32 NumConnections = SCLY.ReadShort(); + u32 NumConnections = rSCLY.ReadShort(); mpObj->mOutLinks.reserve(NumConnections); for (u32 iCon = 0; iCon < NumConnections; iCon++) { - u32 State = SCLY.ReadLong(); - u32 Message = SCLY.ReadLong(); - u32 ReceiverID = SCLY.ReadLong(); + u32 State = rSCLY.ReadLong(); + u32 Message = rSCLY.ReadLong(); + u32 ReceiverID = rSCLY.ReadLong(); CLink *pLink = new CLink(mpArea, State, Message, mpObj->mInstanceID, ReceiverID); mpObj->mOutLinks.push_back(pLink); } // Load object - SCLY.Seek(0x6, SEEK_CUR); // Skip base struct ID + size - LoadStructMP2(SCLY, mpObj->mpProperties, mpObj->mpTemplate->BaseStruct()); + rSCLY.Seek(0x6, SEEK_CUR); // Skip base struct ID + size + LoadStructMP2(rSCLY, mpObj->mpProperties, mpObj->mpTemplate->BaseStruct()); // Cleanup and return - SCLY.Seek(ObjEnd, SEEK_SET); + rSCLY.Seek(ObjEnd, SEEK_SET); mpObj->EvaluateProperties(); return mpObj; } -CScriptLayer* CScriptLoader::LoadLayerMP2(IInputStream& SCLY) +CScriptLayer* CScriptLoader::LoadLayerMP2(IInputStream& rSCLY) { - SCLY.Seek(0x1, SEEK_CUR); // Skipping version. todo: verify this? - u32 NumObjects = SCLY.ReadLong(); + rSCLY.Seek(0x1, SEEK_CUR); // Skipping version. todo: verify this? + u32 NumObjects = rSCLY.ReadLong(); mpLayer = new CScriptLayer(mpArea); mpLayer->Reserve(NumObjects); for (u32 iObj = 0; iObj < NumObjects; iObj++) { - CScriptObject *pObj = LoadObjectMP2(SCLY); + CScriptObject *pObj = LoadObjectMP2(rSCLY); if (pObj) mpLayer->AddInstance(pObj); } @@ -396,3 +396,28 @@ CScriptLayer* CScriptLoader::LoadLayer(IInputStream& rSCLY, CGameArea *pArea, EG else return Loader.LoadLayerMP2(rSCLY); } + +CScriptObject* CScriptLoader::LoadInstance(IInputStream& rSCLY, CGameArea *pArea, CScriptLayer *pLayer, EGame Version, bool ForceReturnsFormat) +{ + if (!rSCLY.IsValid()) return nullptr; + + CScriptLoader Loader; + Loader.mVersion = (ForceReturnsFormat ? eReturns : Version); + Loader.mpMaster = CMasterTemplate::GetMasterForGame(Version); + Loader.mpArea = pArea; + Loader.mpLayer = pLayer; + + if (!Loader.mpMaster) + { + Log::Write("This game doesn't have a master template; couldn't load script instance"); + return nullptr; + } + + if (!Loader.mpMaster->IsLoadedSuccessfully()) + CTemplateLoader::LoadGameTemplates(Version); + + if (Loader.mVersion <= ePrime) + return Loader.LoadObjectMP1(rSCLY); + else + return Loader.LoadObjectMP2(rSCLY); +} diff --git a/src/Core/Resource/Factory/CScriptLoader.h b/src/Core/Resource/Factory/CScriptLoader.h index 61545c07..adc43e3c 100644 --- a/src/Core/Resource/Factory/CScriptLoader.h +++ b/src/Core/Resource/Factory/CScriptLoader.h @@ -16,18 +16,19 @@ class CScriptLoader CMasterTemplate *mpMaster; CScriptLoader(); - void ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY); + void ReadProperty(IProperty *pProp, u32 Size, IInputStream& rSCLY); - void LoadStructMP1(IInputStream& SCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp); - CScriptObject* LoadObjectMP1(IInputStream& SCLY); - CScriptLayer* LoadLayerMP1(IInputStream& SCLY); + void LoadStructMP1(IInputStream& rSCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp); + CScriptObject* LoadObjectMP1(IInputStream& rSCLY); + CScriptLayer* LoadLayerMP1(IInputStream& rSCLY); - void LoadStructMP2(IInputStream& SCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp); - CScriptObject* LoadObjectMP2(IInputStream& SCLY); - CScriptLayer* LoadLayerMP2(IInputStream& SCLY); + void LoadStructMP2(IInputStream& rSCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp); + CScriptObject* LoadObjectMP2(IInputStream& rSCLY); + CScriptLayer* LoadLayerMP2(IInputStream& rSCLY); public: - static CScriptLayer* LoadLayer(IInputStream& SCLY, CGameArea *pArea, EGame version); + static CScriptLayer* LoadLayer(IInputStream& rSCLY, CGameArea *pArea, EGame Version); + static CScriptObject* LoadInstance(IInputStream& rSCLY, CGameArea *pArea, CScriptLayer *pLayer,EGame Version, bool ForceReturnsFormat); }; #endif // CSCRIPTLOADER_H diff --git a/src/Core/Resource/Script/CScriptObject.cpp b/src/Core/Resource/Script/CScriptObject.cpp index 1ed8538e..26312980 100644 --- a/src/Core/Resource/Script/CScriptObject.cpp +++ b/src/Core/Resource/Script/CScriptObject.cpp @@ -15,7 +15,7 @@ CScriptObject::CScriptObject(u32 InstanceID, CGameArea *pArea, CScriptLayer *pLa , mIsCheckingNearVisibleActivation(false) { mpTemplate->AddObject(this); - mpProperties = (CPropertyStruct*) pTemplate->BaseStruct()->InstantiateProperty(nullptr); + mpProperties = (CPropertyStruct*) pTemplate->BaseStruct()->InstantiateProperty(this, nullptr); } CScriptObject::~CScriptObject() @@ -80,14 +80,16 @@ void CScriptObject::SetLayer(CScriptLayer *pLayer, u32 NewLayerIndex) { if (pLayer != mpLayer) { - mpLayer->RemoveInstance(this); + if (mpLayer) mpLayer->RemoveInstance(this); mpLayer = pLayer; - mpLayer->AddInstance(this, NewLayerIndex); + if (mpLayer) mpLayer->AddInstance(this, NewLayerIndex); } } u32 CScriptObject::LayerIndex() const { + if (!mpLayer) return -1; + for (u32 iInst = 0; iInst < mpLayer->NumInstances(); iInst++) { if (mpLayer->InstanceByIndex(iInst) == this) diff --git a/src/Core/Resource/Script/IProperty.cpp b/src/Core/Resource/Script/IProperty.cpp index c3cb0a51..c026141a 100644 --- a/src/Core/Resource/Script/IProperty.cpp +++ b/src/Core/Resource/Script/IProperty.cpp @@ -32,13 +32,44 @@ TString IProperty::Name() const u32 IProperty::ID() const { - return mpTemplate->PropertyID(); + if (mpParent && mpParent->Type() == eArrayProperty) + return ArrayIndex(); + else + return mpTemplate->PropertyID(); } TIDString IProperty::IDString(bool FullPath) const { - // todo: since this function just returns the template ID string, it doesn't correctly account for array properties; - return mpTemplate->IDString(FullPath); + TIDString Out; + + if (ID() != 0xFFFFFFFF) + { + if (mpParent && FullPath) + { + Out = mpParent->IDString(true); + if (!Out.IsEmpty()) Out += ":"; + } + + Out += TString::HexString(ID(), true, true, 8); + } + + return Out; +} + +u32 IProperty::ArrayIndex() const +{ + CArrayProperty *pArray = TPropCast(mpParent); + + if (pArray) + { + for (u32 iSub = 0; iSub < pArray->Count(); iSub++) + { + if (pArray->PropertyByIndex(iSub) == this) + return iSub; + } + } + + return -1; } bool IProperty::ShouldCook() @@ -74,7 +105,7 @@ void CPropertyStruct::Copy(const IProperty *pkProp) mProperties.resize(pkSource->mProperties.size()); for (u32 iSub = 0; iSub < mProperties.size(); iSub++) - mProperties[iSub] = pkSource->mProperties[iSub]->Clone(this); + mProperties[iSub] = pkSource->mProperties[iSub]->Clone(Instance(), this); } bool CPropertyStruct::ShouldCook() @@ -138,7 +169,7 @@ CPropertyStruct* CPropertyStruct::StructByIndex(u32 index) const { IProperty *pProp = PropertyByIndex(index); - if (pProp->Type() == eStructProperty) + if (pProp->Type() == eStructProperty || pProp->Type() == eArrayProperty) return static_cast(pProp); else return nullptr; @@ -148,7 +179,7 @@ CPropertyStruct* CPropertyStruct::StructByID(u32 ID) const { IProperty *pProp = PropertyByID(ID); - if (pProp->Type() == eStructProperty) + if (pProp->Type() == eStructProperty || pProp->Type() == eArrayProperty) return static_cast(pProp); else return nullptr; @@ -158,7 +189,7 @@ CPropertyStruct* CPropertyStruct::StructByIDString(const TIDString& rkStr) const { IProperty *pProp = PropertyByIDString(rkStr); - if (pProp->Type() == eStructProperty) + if (pProp->Type() == eStructProperty || pProp->Type() == eArrayProperty) return static_cast(pProp); else return nullptr; @@ -186,7 +217,7 @@ void CArrayProperty::Resize(int Size) if (Size > OldSize) { for (int iProp = OldSize; iProp < Size; iProp++) - mProperties[iProp] = static_cast(mpTemplate)->CreateSubStruct(this); + mProperties[iProp] = static_cast(mpTemplate)->CreateSubStruct(Instance(), this); } } diff --git a/src/Core/Resource/Script/IProperty.h b/src/Core/Resource/Script/IProperty.h index e14f6f02..7bc1de0a 100644 --- a/src/Core/Resource/Script/IProperty.h +++ b/src/Core/Resource/Script/IProperty.h @@ -13,6 +13,7 @@ #include #include +class CScriptObject; class CScriptTemplate; class CStructTemplate; class IPropertyTemplate; @@ -28,11 +29,13 @@ class IProperty protected: class CPropertyStruct *mpParent; + CScriptObject *mpInstance; IPropertyTemplate *mpTemplate; public: - IProperty(IPropertyTemplate *pTemp, CPropertyStruct *pParent) + IProperty(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent) : mpParent(pParent) + , mpInstance(pInstance) , mpTemplate(pTemp) { } @@ -42,12 +45,13 @@ public: virtual TString ToString() const { return ""; } virtual IPropertyValue* RawValue() { return nullptr; } virtual void Copy(const IProperty *pkProp) = 0; - virtual IProperty* Clone(CPropertyStruct *pParent = 0) const = 0; + virtual IProperty* Clone(CScriptObject *pInstance, CPropertyStruct *pParent = 0) const = 0; virtual bool Matches(const IProperty *pkProp) const = 0; virtual bool ShouldCook(); // Can't be const because it calls MatchesDefault() virtual bool MatchesDefault(); // Can't be const because RawValue() isn't const + inline CScriptObject* Instance() const { return mpInstance; } inline CPropertyStruct* Parent() const { return mpParent; } inline void SetParent(CPropertyStruct *pParent) { mpParent = pParent; } @@ -59,6 +63,7 @@ public: TString Name() const; u32 ID() const; TIDString IDString(bool FullPath) const; + u32 ArrayIndex() const; }; /* @@ -70,11 +75,11 @@ class TTypedProperty : public IProperty friend class CScriptLoader; ValueClass mValue; public: - TTypedProperty(IPropertyTemplate *pTemp, CPropertyStruct *pParent) - : IProperty(pTemp, pParent) {} + TTypedProperty(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent) + : IProperty(pTemp, pInstance, pParent) {} - TTypedProperty(IPropertyTemplate *pTemp, CPropertyStruct *pParent, ValueType v) - : IProperty(pTemp, pParent), mValue(v) {} + TTypedProperty(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent, ValueType v) + : IProperty(pTemp, pInstance, pParent), mValue(v) {} ~TTypedProperty() {} virtual EPropertyType Type() const { return TypeEnum; } @@ -89,11 +94,11 @@ public: mValue.Set(pkCast->mValue.Get()); } - virtual TTypedProperty* Clone(CPropertyStruct *pParent) const + virtual TTypedProperty* Clone(class CScriptObject *pInstance, CPropertyStruct *pParent) const { if (!pParent) pParent = mpParent; - TTypedProperty *pOut = new TTypedProperty(mpTemplate, pParent); + TTypedProperty *pOut = new TTypedProperty(mpTemplate, pInstance, pParent); pOut->Copy(this); return pOut; } @@ -123,11 +128,11 @@ typedef TTypedProperty, eUnknownProperty, CUnknownValue> * TStringProperty, TFileProperty, and TCharacterProperty get little subclasses in order to override some virtual functions. */ #define IMPLEMENT_PROPERTY_CTORS(ClassName, ValueType) \ - ClassName(IPropertyTemplate *pTemp, CPropertyStruct *pParent) \ - : TTypedProperty(pTemp, pParent) {} \ + ClassName(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent) \ + : TTypedProperty(pTemp, pInstance, pParent) {} \ \ - ClassName(IPropertyTemplate *pTemp, CPropertyStruct *pParent, ValueType v) \ - : TTypedProperty(pTemp, pParent, v) {} + ClassName(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent, ValueType v) \ + : TTypedProperty(pTemp, pInstance, pParent, v) {} class TStringProperty : public TTypedProperty { @@ -169,8 +174,8 @@ class CPropertyStruct : public IProperty protected: std::vector mProperties; public: - CPropertyStruct(IPropertyTemplate *pTemp, CPropertyStruct *pParent) - : IProperty(pTemp, pParent) {} + CPropertyStruct(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent) + : IProperty(pTemp, pInstance, pParent) {} ~CPropertyStruct() { @@ -183,10 +188,10 @@ public: virtual void Copy(const IProperty *pkProp); - virtual IProperty* Clone(CPropertyStruct *pParent) const + virtual IProperty* Clone(CScriptObject *pInstance, CPropertyStruct *pParent) const { if (!pParent) pParent = mpParent; - CPropertyStruct *pOut = new CPropertyStruct(mpTemplate, pParent); + CPropertyStruct *pOut = new CPropertyStruct(mpTemplate, pInstance, pParent); pOut->Copy(this); return pOut; } @@ -245,16 +250,16 @@ class CArrayProperty : public CPropertyStruct friend class CScriptLoader; public: - CArrayProperty(IPropertyTemplate *pTemp, CPropertyStruct *pParent) - : CPropertyStruct(pTemp, pParent) {} + CArrayProperty(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent) + : CPropertyStruct(pTemp, pInstance, pParent) {} EPropertyType Type() const { return eArrayProperty; } static inline EPropertyType StaticType() { return eArrayProperty; } - virtual IProperty* Clone(CPropertyStruct *pParent) const + virtual IProperty* Clone(CScriptObject *pInstance, CPropertyStruct *pParent) const { if (!pParent) pParent = mpParent; - CArrayProperty *pOut = new CArrayProperty(mpTemplate, pParent); + CArrayProperty *pOut = new CArrayProperty(mpTemplate, pInstance, pParent); pOut->Copy(this); return pOut; } diff --git a/src/Core/Resource/Script/IPropertyTemplate.h b/src/Core/Resource/Script/IPropertyTemplate.h index 863ef96b..778858e4 100644 --- a/src/Core/Resource/Script/IPropertyTemplate.h +++ b/src/Core/Resource/Script/IPropertyTemplate.h @@ -64,7 +64,7 @@ public: virtual EPropertyType Type() const = 0; virtual bool CanHaveDefault() const = 0; virtual bool IsNumerical() const = 0; - virtual IProperty* InstantiateProperty(CPropertyStruct *pParent) = 0; + virtual IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent) = 0; virtual IPropertyTemplate* Clone(CScriptTemplate *pScript, CStructTemplate *pParent = 0) const = 0; virtual void Copy(const IPropertyTemplate *pkTemp) @@ -164,10 +164,10 @@ public: virtual bool CanHaveDefault() const { return CanHaveDefaultValue; } virtual bool IsNumerical() const { return false; } - virtual IProperty* InstantiateProperty(CPropertyStruct *pParent) + virtual IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent) { typedef TTypedProperty TPropertyType; - TPropertyType *pOut = new TPropertyType(this, pParent, GetDefaultValue()); + TPropertyType *pOut = new TPropertyType(this, pInstance, pParent, GetDefaultValue()); return pOut; } @@ -321,9 +321,9 @@ public: TCharacterTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0) : TTypedPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent) {} - IProperty* InstantiateProperty(CPropertyStruct *pParent) + IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent) { - return new TCharacterProperty(this, pParent, CAnimationParameters(Game())); + return new TCharacterProperty(this, pInstance, pParent, CAnimationParameters(Game())); } }; @@ -339,9 +339,9 @@ public: TStringTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0) : TTypedPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent) {} - IProperty* InstantiateProperty(CPropertyStruct *pParent) + IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent) { - return new TStringProperty(this, pParent); + return new TStringProperty(this, pInstance, pParent); } }; @@ -357,9 +357,9 @@ public: TMayaSplineTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0) : TTypedPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent) {} - IProperty* InstantiateProperty(CPropertyStruct *pParent) + IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent) { - return new TMayaSplineProperty(this, pParent); + return new TMayaSplineProperty(this, pInstance, pParent); } }; @@ -382,9 +382,9 @@ public: virtual bool CanHaveDefault() const { return false; } virtual bool IsNumerical() const { return false; } - IProperty* InstantiateProperty(CPropertyStruct *pParent) + IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent) { - return new TFileProperty(this, pParent); + return new TFileProperty(this, pInstance, pParent); } IMPLEMENT_TEMPLATE_CLONE(CFileTemplate) @@ -451,9 +451,9 @@ public: virtual bool CanHaveDefault() const { return true; } virtual bool IsNumerical() const { return false; } - virtual IProperty* InstantiateProperty(CPropertyStruct *pParent) + virtual IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent) { - TEnumProperty *pEnum = new TEnumProperty(this, pParent); + TEnumProperty *pEnum = new TEnumProperty(this, pInstance, pParent); pEnum->Set(GetDefaultValue()); return pEnum; } @@ -546,9 +546,9 @@ public: virtual bool CanHaveDefault() const { return true; } virtual bool IsNumerical() const { return false; } - virtual IProperty* InstantiateProperty(CPropertyStruct *pParent) + virtual IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent) { - TBitfieldProperty *pBitfield = new TBitfieldProperty(this, pParent); + TBitfieldProperty *pBitfield = new TBitfieldProperty(this, pInstance, pParent); pBitfield->Set(GetDefaultValue()); return pBitfield; } @@ -611,13 +611,13 @@ public: bool CanHaveDefault() const { return false; } bool IsNumerical() const { return false; } - IProperty* InstantiateProperty(CPropertyStruct *pParent) + IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent) { - CPropertyStruct *pStruct = new CPropertyStruct(this, pParent); + CPropertyStruct *pStruct = new CPropertyStruct(this, pInstance, pParent); for (u32 iSub = 0; iSub < mSubProperties.size(); iSub++) { - IProperty *pSubProp = mSubProperties[iSub]->InstantiateProperty(pStruct); + IProperty *pSubProp = mSubProperties[iSub]->InstantiateProperty(pInstance, pStruct); pStruct->AddSubProperty(pSubProp); } @@ -708,9 +708,9 @@ public: EPropertyType Type() const { return eArrayProperty; } - IProperty* InstantiateProperty(CPropertyStruct *pParent) + IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent) { - return new CArrayProperty(this, pParent); + return new CArrayProperty(this, pInstance, pParent); } IMPLEMENT_TEMPLATE_CLONE(CArrayTemplate) @@ -740,9 +740,9 @@ public: TString ElementName() const { return mElementName; } void SetElementName(const TString& rkName) { mElementName = rkName; } - CPropertyStruct* CreateSubStruct(CArrayProperty *pArray) + CPropertyStruct* CreateSubStruct(CScriptObject *pInstance, CArrayProperty *pArray) { - return (CPropertyStruct*) CStructTemplate::InstantiateProperty(pArray); + return (CPropertyStruct*) CStructTemplate::InstantiateProperty(pInstance, pArray); } }; diff --git a/src/Core/Scene/CCollisionNode.cpp b/src/Core/Scene/CCollisionNode.cpp index 880754db..3c20500f 100644 --- a/src/Core/Scene/CCollisionNode.cpp +++ b/src/Core/Scene/CCollisionNode.cpp @@ -3,8 +3,8 @@ #include "Core/Render/CGraphics.h" #include "Core/Render/CRenderer.h" -CCollisionNode::CCollisionNode(CScene *pScene, CSceneNode *pParent, CCollisionMeshGroup *pCollision) - : CSceneNode(pScene, pParent) +CCollisionNode::CCollisionNode(CScene *pScene, u32 NodeID, CSceneNode *pParent, CCollisionMeshGroup *pCollision) + : CSceneNode(pScene, NodeID, pParent) { SetCollision(pCollision); SetName("Collision"); diff --git a/src/Core/Scene/CCollisionNode.h b/src/Core/Scene/CCollisionNode.h index 5837c01c..b0614092 100644 --- a/src/Core/Scene/CCollisionNode.h +++ b/src/Core/Scene/CCollisionNode.h @@ -9,7 +9,7 @@ class CCollisionNode : public CSceneNode TResPtr mpCollision; public: - CCollisionNode(CScene *pScene, CSceneNode *pParent = 0, CCollisionMeshGroup *pCollision = 0); + CCollisionNode(CScene *pScene, u32 NodeID, CSceneNode *pParent = 0, CCollisionMeshGroup *pCollision = 0); ENodeType NodeType(); void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo); void Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& ViewInfo); diff --git a/src/Core/Scene/CLightNode.cpp b/src/Core/Scene/CLightNode.cpp index c7f025a3..c366d55e 100644 --- a/src/Core/Scene/CLightNode.cpp +++ b/src/Core/Scene/CLightNode.cpp @@ -4,8 +4,8 @@ #include "Core/Render/CRenderer.h" #include -CLightNode::CLightNode(CScene *pScene, CSceneNode *pParent, CLight *Light) - : CSceneNode(pScene, pParent) +CLightNode::CLightNode(CScene *pScene, u32 NodeID, CSceneNode *pParent, CLight *Light) + : CSceneNode(pScene, NodeID, pParent) { mpLight = Light; mLocalAABox = CAABox::skOne; diff --git a/src/Core/Scene/CLightNode.h b/src/Core/Scene/CLightNode.h index c3e4adc4..798f5157 100644 --- a/src/Core/Scene/CLightNode.h +++ b/src/Core/Scene/CLightNode.h @@ -8,7 +8,7 @@ class CLightNode : public CSceneNode { CLight *mpLight; public: - CLightNode(CScene *pScene, CSceneNode *pParent = 0, CLight *Light = 0); + CLightNode(CScene *pScene, u32 NodeID, CSceneNode *pParent = 0, CLight *Light = 0); ENodeType NodeType(); void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo); void Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& ViewInfo); diff --git a/src/Core/Scene/CModelNode.cpp b/src/Core/Scene/CModelNode.cpp index f0d157ca..f0c583de 100644 --- a/src/Core/Scene/CModelNode.cpp +++ b/src/Core/Scene/CModelNode.cpp @@ -4,7 +4,8 @@ #include "Core/Render/CGraphics.h" #include -CModelNode::CModelNode(CScene *pScene, CSceneNode *pParent, CModel *pModel) : CSceneNode(pScene, pParent) +CModelNode::CModelNode(CScene *pScene, u32 NodeID, CSceneNode *pParent, CModel *pModel) + : CSceneNode(pScene, NodeID, pParent) { SetModel(pModel); mScale = CVector3f(1.f); diff --git a/src/Core/Scene/CModelNode.h b/src/Core/Scene/CModelNode.h index edded4cf..799d5476 100644 --- a/src/Core/Scene/CModelNode.h +++ b/src/Core/Scene/CModelNode.h @@ -15,7 +15,7 @@ class CModelNode : public CSceneNode CColor mScanOverlayColor; public: - explicit CModelNode(CScene *pScene, CSceneNode *pParent = 0, CModel *pModel = 0); + explicit CModelNode(CScene *pScene, u32 NodeID, CSceneNode *pParent = 0, CModel *pModel = 0); virtual ENodeType NodeType(); virtual void PostLoad(); diff --git a/src/Core/Scene/CRootNode.h b/src/Core/Scene/CRootNode.h index f552b7f1..2389be67 100644 --- a/src/Core/Scene/CRootNode.h +++ b/src/Core/Scene/CRootNode.h @@ -8,7 +8,8 @@ class CRootNode : public CSceneNode { public: - explicit CRootNode(CScene *pScene, CSceneNode *pParent = 0) : CSceneNode(pScene, pParent) {} + explicit CRootNode(CScene *pScene, u32 NodeID, CSceneNode *pParent = 0) + : CSceneNode(pScene, NodeID, pParent) {} ~CRootNode() {} ENodeType NodeType() { diff --git a/src/Core/Scene/CScene.cpp b/src/Core/Scene/CScene.cpp index 45c16089..fabc5c79 100644 --- a/src/Core/Scene/CScene.cpp +++ b/src/Core/Scene/CScene.cpp @@ -17,7 +17,7 @@ CScene::CScene() : mSplitTerrain(true) , mRanPostLoad(false) , mNumNodes(0) - , mpSceneRootNode(new CRootNode(this, nullptr)) + , mpSceneRootNode(new CRootNode(this, -1, nullptr)) , mpArea(nullptr) , mpWorld(nullptr) , mpAreaRootNode(nullptr) @@ -29,43 +29,76 @@ CScene::~CScene() ClearScene(); } -CModelNode* CScene::CreateModelNode(CModel *pModel) +bool CScene::IsNodeIDUsed(u32 ID) const +{ + return (mNodeMap.find(ID) != mNodeMap.end()); +} + +u32 CScene::CreateNodeID(u32 SuggestedID /*= -1*/) const +{ + if (SuggestedID != -1) + { + if (IsNodeIDUsed(SuggestedID)) + Log::Error("Suggested node ID is already being used! New ID will be created."); + else + return SuggestedID; + } + + u32 ID = 0; + + while (IsNodeIDUsed(ID)) + ID++; + + return ID; +} + +CModelNode* CScene::CreateModelNode(CModel *pModel, u32 NodeID /*= -1*/) { if (pModel == nullptr) return nullptr; - CModelNode *pNode = new CModelNode(this, mpAreaRootNode, pModel); + u32 ID = CreateNodeID(NodeID); + CModelNode *pNode = new CModelNode(this, ID, mpAreaRootNode, pModel); mNodes[eModelNode].push_back(pNode); + mNodeMap[ID] = pNode; mNumNodes++; return pNode; } -CStaticNode* CScene::CreateStaticNode(CStaticModel *pModel) +CStaticNode* CScene::CreateStaticNode(CStaticModel *pModel, u32 NodeID /*= -1*/) { if (pModel == nullptr) return nullptr; - CStaticNode *pNode = new CStaticNode(this, mpAreaRootNode, pModel); + u32 ID = CreateNodeID(NodeID); + CStaticNode *pNode = new CStaticNode(this, ID, mpAreaRootNode, pModel); mNodes[eStaticNode].push_back(pNode); + mNodeMap[ID] = pNode; mNumNodes++; return pNode; } -CCollisionNode* CScene::CreateCollisionNode(CCollisionMeshGroup *pMesh) +CCollisionNode* CScene::CreateCollisionNode(CCollisionMeshGroup *pMesh, u32 NodeID /*= -1*/) { if (pMesh == nullptr) return nullptr; - CCollisionNode *pNode = new CCollisionNode(this, mpAreaRootNode, pMesh); + u32 ID = CreateNodeID(NodeID); + CCollisionNode *pNode = new CCollisionNode(this, ID, mpAreaRootNode, pMesh); mNodes[eCollisionNode].push_back(pNode); + mNodeMap[ID] = pNode; mNumNodes++; return pNode; } -CScriptNode* CScene::CreateScriptNode(CScriptObject *pObj) +CScriptNode* CScene::CreateScriptNode(CScriptObject *pObj, u32 NodeID /*= -1*/) { if (pObj == nullptr) return nullptr; - CScriptNode *pNode = new CScriptNode(this, mpAreaRootNode, pObj); + u32 ID = CreateNodeID(NodeID); + u32 InstanceID = pObj->InstanceID(); + + CScriptNode *pNode = new CScriptNode(this, ID, mpAreaRootNode, pObj); mNodes[eScriptNode].push_back(pNode); - mScriptNodeMap[pObj->InstanceID()] = pNode; + mNodeMap[ID] = pNode; + mScriptMap[InstanceID] = pNode; pNode->BuildLightList(mpArea); // AreaAttributes check @@ -81,12 +114,14 @@ CScriptNode* CScene::CreateScriptNode(CScriptObject *pObj) return pNode; } -CLightNode* CScene::CreateLightNode(CLight *pLight) +CLightNode* CScene::CreateLightNode(CLight *pLight, u32 NodeID /*= -1*/) { if (pLight == nullptr) return nullptr; - CLightNode *pNode = new CLightNode(this, mpAreaRootNode, pLight); + u32 ID = CreateNodeID(NodeID); + CLightNode *pNode = new CLightNode(this, ID, mpAreaRootNode, pLight); mNodes[eLightNode].push_back(pNode); + mNodeMap[ID] = pNode; mNumNodes++; return pNode; } @@ -104,13 +139,17 @@ void CScene::DeleteNode(CSceneNode *pNode) } } + auto MapIt = mNodeMap.find(pNode->ID()); + if (MapIt != mNodeMap.end()) + mNodeMap.erase(MapIt); + if (Type == eScriptNode) { CScriptNode *pScript = static_cast(pNode); - auto ScriptMapIt = mScriptNodeMap.find(pScript->Object()->InstanceID()); - if (ScriptMapIt != mScriptNodeMap.end()) - mScriptNodeMap.erase(ScriptMapIt); + auto it = mScriptMap.find(pScript->Object()->InstanceID()); + if (it != mScriptMap.end()) + mScriptMap.erase(it); switch (pScript->Object()->ObjectTypeID()) { @@ -140,7 +179,7 @@ void CScene::SetActiveArea(CGameArea *pArea) // Create nodes for new area mpArea = pArea; - mpAreaRootNode = new CRootNode(this, mpSceneRootNode); + mpAreaRootNode = new CRootNode(this, -1, mpSceneRootNode); // Create static nodes u32 Count = mpArea->GetStaticModelCount(); @@ -190,10 +229,11 @@ void CScene::SetActiveArea(CGameArea *pArea) } // Ensure script nodes have valid positions + build light lists - for (auto it = mScriptNodeMap.begin(); it != mScriptNodeMap.end(); it++) + for (CSceneIterator It(this, eScriptNode, true); It; ++It) { - it->second->GeneratePosition(); - it->second->BuildLightList(mpArea); + CScriptNode *pScript = static_cast(*It); + pScript->GeneratePosition(); + pScript->BuildLightList(mpArea); } u32 NumLightLayers = mpArea->GetLightLayerCount(); @@ -239,7 +279,7 @@ void CScene::ClearScene() mNodes.clear(); mAreaAttributesObjects.clear(); - mScriptNodeMap.clear(); + mNodeMap.clear(); mNumNodes = 0; mpArea = nullptr; @@ -277,17 +317,25 @@ SRayIntersection CScene::SceneRayCast(const CRay& Ray, const SViewInfo& ViewInfo return Tester.TestNodes(ViewInfo); } -CScriptNode* CScene::ScriptNodeByID(u32 InstanceID) +CSceneNode* CScene::NodeByID(u32 NodeID) { - auto it = mScriptNodeMap.find(InstanceID); + auto it = mNodeMap.find(NodeID); - if (it != mScriptNodeMap.end()) return it->second; + if (it != mNodeMap.end()) return it->second; + else return nullptr; +} + +CScriptNode* CScene::NodeForInstanceID(u32 InstanceID) +{ + auto it = mScriptMap.find(InstanceID); + + if (it != mScriptMap.end()) return it->second; else return nullptr; } CScriptNode* CScene::NodeForObject(CScriptObject *pObj) { - return ScriptNodeByID(pObj->InstanceID()); + return NodeForInstanceID(pObj->InstanceID()); } CLightNode* CScene::NodeForLight(CLight *pLight) diff --git a/src/Core/Scene/CScene.h b/src/Core/Scene/CScene.h index 3216d7f2..255f2d35 100644 --- a/src/Core/Scene/CScene.h +++ b/src/Core/Scene/CScene.h @@ -38,19 +38,23 @@ class CScene // Environment std::vector mAreaAttributesObjects; - // Objects - std::unordered_map mScriptNodeMap; + // Node Management + std::unordered_map mNodeMap; + std::unordered_map mScriptMap; public: CScene(); ~CScene(); // Scene Management - CModelNode* CreateModelNode(CModel *pModel); - CStaticNode* CreateStaticNode(CStaticModel *pModel); - CCollisionNode* CreateCollisionNode(CCollisionMeshGroup *pMesh); - CScriptNode* CreateScriptNode(CScriptObject *pObj); - CLightNode* CreateLightNode(CLight *pLight); + bool IsNodeIDUsed(u32 ID) const; + u32 CreateNodeID(u32 SuggestedID = -1) const; + + CModelNode* CreateModelNode(CModel *pModel, u32 NodeID = -1); + CStaticNode* CreateStaticNode(CStaticModel *pModel, u32 NodeID = -1); + CCollisionNode* CreateCollisionNode(CCollisionMeshGroup *pMesh, u32 NodeID = -1); + CScriptNode* CreateScriptNode(CScriptObject *pObj, u32 NodeID = -1); + CLightNode* CreateLightNode(CLight *pLight, u32 NodeID = -1); void DeleteNode(CSceneNode *pNode); void SetActiveArea(CGameArea *pArea); void SetActiveWorld(CWorld *pWorld); @@ -58,7 +62,8 @@ public: void ClearScene(); void AddSceneToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo); SRayIntersection SceneRayCast(const CRay& rkRay, const SViewInfo& rkViewInfo); - CScriptNode* ScriptNodeByID(u32 InstanceID); + CSceneNode* NodeByID(u32 NodeID); + CScriptNode* NodeForInstanceID(u32 InstanceID); CScriptNode* NodeForObject(CScriptObject *pObj); CLightNode* NodeForLight(CLight *pLight); diff --git a/src/Core/Scene/CSceneNode.cpp b/src/Core/Scene/CSceneNode.cpp index 8abf912f..99975881 100644 --- a/src/Core/Scene/CSceneNode.cpp +++ b/src/Core/Scene/CSceneNode.cpp @@ -12,11 +12,12 @@ u32 CSceneNode::smNumNodes = 0; CColor CSceneNode::skSelectionTint = CColor::Integral(39, 154, 167); -CSceneNode::CSceneNode(CScene *pScene, CSceneNode *pParent) +CSceneNode::CSceneNode(CScene *pScene, u32 NodeID, CSceneNode *pParent) { smNumNodes++; mpScene = pScene; mpParent = pParent; + _mID = NodeID; mPosition = CVector3f::skZero; mRotation = CQuaternion::skIdentity; @@ -341,6 +342,11 @@ CScene* CSceneNode::Scene() const return mpScene; } +u32 CSceneNode::ID() const +{ + return _mID; +} + CVector3f CSceneNode::LocalPosition() const { return mPosition; diff --git a/src/Core/Scene/CSceneNode.h b/src/Core/Scene/CSceneNode.h index f3b42ff4..99daa083 100644 --- a/src/Core/Scene/CSceneNode.h +++ b/src/Core/Scene/CSceneNode.h @@ -29,6 +29,8 @@ private: bool _mInheritsRotation; bool _mInheritsScale; + u32 _mID; + protected: static u32 smNumNodes; TString mName; @@ -51,7 +53,7 @@ protected: CColor mAmbientColor; public: - explicit CSceneNode(CScene *pScene, CSceneNode *pParent = 0); + explicit CSceneNode(CScene *pScene, u32 NodeID, CSceneNode *pParent = 0); virtual ~CSceneNode(); virtual ENodeType NodeType() = 0; virtual void PostLoad() {} @@ -94,6 +96,7 @@ public: TString Name() const; CSceneNode* Parent() const; CScene* Scene() const; + u32 ID() const; CVector3f LocalPosition() const; CVector3f AbsolutePosition() const; CQuaternion LocalRotation() const; diff --git a/src/Core/Scene/CScriptNode.cpp b/src/Core/Scene/CScriptNode.cpp index 7e4af39d..345c1d65 100644 --- a/src/Core/Scene/CScriptNode.cpp +++ b/src/Core/Scene/CScriptNode.cpp @@ -10,8 +10,8 @@ #include #include -CScriptNode::CScriptNode(CScene *pScene, CSceneNode *pParent, CScriptObject *pObject) - : CSceneNode(pScene, pParent) +CScriptNode::CScriptNode(CScene *pScene, u32 NodeID, CSceneNode *pParent, CScriptObject *pObject) + : CSceneNode(pScene, NodeID, pParent) , mGameModeVisibility(eUntested) { mpVolumePreviewNode = nullptr; @@ -21,7 +21,7 @@ CScriptNode::CScriptNode(CScene *pScene, CSceneNode *pParent, CScriptObject *pOb mpInstance = pObject; SetActiveModel(nullptr); mpBillboard = nullptr; - mpCollisionNode = new CCollisionNode(pScene, this); + mpCollisionNode = new CCollisionNode(pScene, -1, this); mpCollisionNode->SetInheritance(true, true, false); if (mpInstance) @@ -43,7 +43,7 @@ CScriptNode::CScriptNode(CScene *pScene, CSceneNode *pParent, CScriptObject *pOb mpCollisionNode->SetCollision(mpInstance->GetCollision()); // Create preview volume node - mpVolumePreviewNode = new CModelNode(pScene, this, nullptr); + mpVolumePreviewNode = new CModelNode(pScene, -1, this, nullptr); if (pTemp->ScaleType() == CScriptTemplate::eScaleVolume) { @@ -259,14 +259,14 @@ void CScriptNode::DrawSelection() { // Don't draw in links if the other object is selected. CLink *pLink = mpInstance->Link(eIncoming, iIn); - CScriptNode *pLinkNode = mpScene->ScriptNodeByID(pLink->SenderID()); + CScriptNode *pLinkNode = mpScene->NodeForInstanceID(pLink->SenderID()); if (pLinkNode && !pLinkNode->IsSelected()) CDrawUtil::DrawLine(CenterPoint(), pLinkNode->CenterPoint(), CColor::skTransparentRed); } for (u32 iOut = 0; iOut < mpInstance->NumLinks(eOutgoing); iOut++) { CLink *pLink = mpInstance->Link(eOutgoing, iOut); - CScriptNode *pLinkNode = mpScene->ScriptNodeByID(pLink->ReceiverID()); + CScriptNode *pLinkNode = mpScene->NodeForInstanceID(pLink->ReceiverID()); if (pLinkNode) CDrawUtil::DrawLine(CenterPoint(), pLinkNode->CenterPoint(), CColor::skTransparentGreen); } } @@ -549,7 +549,7 @@ void CScriptNode::GeneratePosition() if (NumLinks == 1) { u32 LinkedID = (mpInstance->NumLinks(eIncoming) > 0 ? mpInstance->Link(eIncoming, 0)->SenderID() : mpInstance->Link(eOutgoing, 0)->ReceiverID()); - CScriptNode *pNode = mpScene->ScriptNodeByID(LinkedID); + CScriptNode *pNode = mpScene->NodeForInstanceID(LinkedID); pNode->GeneratePosition(); mPosition = pNode->AbsolutePosition(); mPosition.z += (pNode->AABox().Size().z / 2.f); @@ -564,7 +564,7 @@ void CScriptNode::GeneratePosition() for (u32 iIn = 0; iIn < mpInstance->NumLinks(eIncoming); iIn++) { - CScriptNode *pNode = mpScene->ScriptNodeByID(mpInstance->Link(eIncoming, iIn)->SenderID()); + CScriptNode *pNode = mpScene->NodeForInstanceID(mpInstance->Link(eIncoming, iIn)->SenderID()); if (pNode) { @@ -575,7 +575,7 @@ void CScriptNode::GeneratePosition() for (u32 iOut = 0; iOut < mpInstance->NumLinks(eOutgoing); iOut++) { - CScriptNode *pNode = mpScene->ScriptNodeByID(mpInstance->Link(eOutgoing, iOut)->ReceiverID()); + CScriptNode *pNode = mpScene->NodeForInstanceID(mpInstance->Link(eOutgoing, iOut)->ReceiverID()); if (pNode) { diff --git a/src/Core/Scene/CScriptNode.h b/src/Core/Scene/CScriptNode.h index e22c3996..2e1b6ba5 100644 --- a/src/Core/Scene/CScriptNode.h +++ b/src/Core/Scene/CScriptNode.h @@ -30,7 +30,7 @@ class CScriptNode : public CSceneNode } mGameModeVisibility; public: - CScriptNode(CScene *pScene, CSceneNode *pParent = 0, CScriptObject *pObject = 0); + CScriptNode(CScene *pScene, u32 NodeID, CSceneNode *pParent = 0, CScriptObject *pObject = 0); ENodeType NodeType(); void PostLoad(); void OnTransformed(); diff --git a/src/Core/Scene/CStaticNode.cpp b/src/Core/Scene/CStaticNode.cpp index aece22f4..cd714940 100644 --- a/src/Core/Scene/CStaticNode.cpp +++ b/src/Core/Scene/CStaticNode.cpp @@ -5,8 +5,8 @@ #include #include -CStaticNode::CStaticNode(CScene *pScene, CSceneNode *pParent, CStaticModel *pModel) - : CSceneNode(pScene, pParent) +CStaticNode::CStaticNode(CScene *pScene, u32 NodeID, CSceneNode *pParent, CStaticModel *pModel) + : CSceneNode(pScene, NodeID, pParent) { mpModel = pModel; mLocalAABox = mpModel->AABox(); diff --git a/src/Core/Scene/CStaticNode.h b/src/Core/Scene/CStaticNode.h index d328444c..022c519d 100644 --- a/src/Core/Scene/CStaticNode.h +++ b/src/Core/Scene/CStaticNode.h @@ -9,7 +9,7 @@ class CStaticNode : public CSceneNode CStaticModel *mpModel; public: - CStaticNode(CScene *pScene, CSceneNode *pParent = 0, CStaticModel *pModel = 0); + CStaticNode(CScene *pScene, u32 NodeID, CSceneNode *pParent = 0, CStaticModel *pModel = 0); ENodeType NodeType(); void PostLoad(); void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo); diff --git a/src/Core/ScriptExtra/CScriptExtra.h b/src/Core/ScriptExtra/CScriptExtra.h index 02345d10..7b9cf41b 100644 --- a/src/Core/ScriptExtra/CScriptExtra.h +++ b/src/Core/ScriptExtra/CScriptExtra.h @@ -20,7 +20,7 @@ protected: public: explicit CScriptExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent = 0) - : CSceneNode(pScene, pParent), + : CSceneNode(pScene, -1, pParent), mpInstance(pInstance), mGame(pInstance->Template()->Game()) { diff --git a/src/Core/ScriptExtra/CSplinePathExtra.cpp b/src/Core/ScriptExtra/CSplinePathExtra.cpp index f86e8452..d55c955d 100644 --- a/src/Core/ScriptExtra/CSplinePathExtra.cpp +++ b/src/Core/ScriptExtra/CSplinePathExtra.cpp @@ -53,7 +53,7 @@ void CSplinePathExtra::AddWaypoints() if ( (pLink->State() == 0x49533030 && pLink->Message() == 0x41544348) || // InternalState00/Attach (pLink->State() == 0x4D4F5450 && pLink->Message() == 0x41544348) ) // MotionPath/Attach { - CScriptNode *pNode = mpScene->ScriptNodeByID(pLink->ReceiverID()); + CScriptNode *pNode = mpScene->NodeForInstanceID(pLink->ReceiverID()); if (pNode && pNode->Object()->ObjectTypeID() == 0x57415950) // Waypoint { diff --git a/src/Core/ScriptExtra/CWaypointExtra.cpp b/src/Core/ScriptExtra/CWaypointExtra.cpp index bba91a53..b7ff464a 100644 --- a/src/Core/ScriptExtra/CWaypointExtra.cpp +++ b/src/Core/ScriptExtra/CWaypointExtra.cpp @@ -85,7 +85,7 @@ void CWaypointExtra::BuildLinks() if (IsPathLink(pLink)) { - CScriptNode *pNode = mpScene->ScriptNodeByID(pLink->ReceiverID()); + CScriptNode *pNode = mpScene->NodeForInstanceID(pLink->ReceiverID()); SWaypointLink Link; Link.pWaypoint = pNode; @@ -117,7 +117,7 @@ bool CWaypointExtra::IsPathLink(CLink *pLink) if (Valid) { - CScriptNode *pNode = mpScene->ScriptNodeByID(pLink->ReceiverID()); + CScriptNode *pNode = mpScene->NodeForInstanceID(pLink->ReceiverID()); if (pNode) return pNode->Object()->ObjectTypeID() == mpInstance->ObjectTypeID(); diff --git a/src/Editor/Editor.pro b/src/Editor/Editor.pro index 6253a4ec..908fe0e9 100644 --- a/src/Editor/Editor.pro +++ b/src/Editor/Editor.pro @@ -138,7 +138,6 @@ HEADERS += \ WorldEditor/CInstancesModel.h \ Undo/CEditScriptPropertyCommand.h \ Undo/CResizeScriptArrayCommand.h \ - Undo/CBasicPropertyCommand.h \ Undo/IUndoCommand.h \ WorldEditor/WEditorProperties.h \ Undo/CChangeLayerCommand.h \ @@ -154,7 +153,8 @@ HEADERS += \ Undo/CCreateInstanceCommand.h \ WorldEditor/CTemplateMimeData.h \ WorldEditor/CTemplateListView.h \ - CSelectionIterator.h + CSelectionIterator.h \ + Undo/ObjReferences.h # Source Files SOURCES += \ @@ -202,7 +202,6 @@ SOURCES += \ WorldEditor/CInstancesModel.cpp \ Undo/CEditScriptPropertyCommand.cpp \ Undo/CResizeScriptArrayCommand.cpp \ - Undo/CBasicPropertyCommand.cpp \ WorldEditor/WEditorProperties.cpp \ Undo/CChangeLayerCommand.cpp \ WorldEditor/CTemplateEditDialog.cpp \ diff --git a/src/Editor/ModelEditor/CModelEditorWindow.cpp b/src/Editor/ModelEditor/CModelEditorWindow.cpp index 019938c8..4a292503 100644 --- a/src/Editor/ModelEditor/CModelEditorWindow.cpp +++ b/src/Editor/ModelEditor/CModelEditorWindow.cpp @@ -31,7 +31,7 @@ CModelEditorWindow::CModelEditorWindow(QWidget *parent) : mpScene = new CScene(); mpCurrentMat = nullptr; mpCurrentModel = nullptr; - mpCurrentModelNode = new CModelNode(mpScene); + mpCurrentModelNode = new CModelNode(mpScene, -1); mpCurrentPass = nullptr; mIgnoreSignals = false; diff --git a/src/Editor/Undo/CAddLinkCommand.cpp b/src/Editor/Undo/CAddLinkCommand.cpp index 4a93e9a0..11523c72 100644 --- a/src/Editor/Undo/CAddLinkCommand.cpp +++ b/src/Editor/Undo/CAddLinkCommand.cpp @@ -8,7 +8,7 @@ CAddLinkCommand::CAddLinkCommand(CWorldEditor *pEditor, CLink Link) { mAffectedInstances << mLink.Sender(); - if (mLink.Sender() != mLink.Receiver()) + if (mLink.SenderID() != mLink.ReceiverID()) mAffectedInstances << mLink.Receiver(); } @@ -22,7 +22,7 @@ void CAddLinkCommand::undo() pReceiver->RemoveLink(eIncoming, pLink); delete pLink; - mpEditor->InstanceLinksModified(mAffectedInstances); + mpEditor->InstanceLinksModified(mAffectedInstances.DereferenceList()); } void CAddLinkCommand::redo() @@ -31,5 +31,5 @@ void CAddLinkCommand::redo() pLink->Sender()->AddLink(eOutgoing, pLink, -1); pLink->Receiver()->AddLink(eIncoming, pLink, -1); - mpEditor->InstanceLinksModified(mAffectedInstances); + mpEditor->InstanceLinksModified(mAffectedInstances.DereferenceList()); } diff --git a/src/Editor/Undo/CAddLinkCommand.h b/src/Editor/Undo/CAddLinkCommand.h index 23b479bd..20de2ec1 100644 --- a/src/Editor/Undo/CAddLinkCommand.h +++ b/src/Editor/Undo/CAddLinkCommand.h @@ -2,6 +2,7 @@ #define CADDLINKCOMMAND_H #include "IUndoCommand.h" +#include "ObjReferences.h" #include "Editor/WorldEditor/CWorldEditor.h" #include @@ -9,7 +10,7 @@ class CAddLinkCommand : public IUndoCommand { CWorldEditor *mpEditor; CLink mLink; - QList mAffectedInstances; + CInstancePtrList mAffectedInstances; public: CAddLinkCommand(CWorldEditor *pEditor, CLink Link); diff --git a/src/Editor/Undo/CBasicPropertyCommand.cpp b/src/Editor/Undo/CBasicPropertyCommand.cpp deleted file mode 100644 index 07ab7060..00000000 --- a/src/Editor/Undo/CBasicPropertyCommand.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "CBasicPropertyCommand.h" -#include - -CBasicPropertyCommand::CBasicPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, const QString& rkCommandName /*="Edit Property"*/) - : IUndoCommand(rkCommandName) - , mpProperty(pProp) - , mpTemplate(mpProperty->Template()) - , mpBaseStruct(pProp->RootStruct()) - , mpEditor(pEditor) - , mIsInArray(false) -{ - // Check for array - IProperty *pChild = mpProperty; - IProperty *pParent = mpProperty->Parent(); - - while (pParent) - { - if (pParent->Type() == eArrayProperty) - { - mIsInArray = true; - - // Find array index - CArrayProperty *pArray = static_cast(pParent); - - for (u32 iSub = 0; iSub < pArray->Count(); iSub++) - { - if (pArray->PropertyByIndex(iSub) == pChild) - { - mArrayIndices << iSub; - break; - } - } - } - pChild = pParent; - pParent = pParent->Parent(); - } -} - -void CBasicPropertyCommand::UpdateArraySubProperty() -{ - // If an array has been sized down and then back up, then we might have a pointer to an invalid property. - // Since we can't assume our pointer is still valid, we'll use the template to find the corresponding property. - IPropertyTemplate *pTemp = mpTemplate; - CStructTemplate *pParent = mpTemplate->Parent(); - - QVector SubIndices; - int IndexIndex = 0; - - while (pParent) - { - if (pParent->Type() != eArrayProperty || static_cast(pParent)->Count() > 1) - { - for (u32 iSub = 0; iSub < pParent->Count(); iSub++) - { - if (pParent->PropertyByIndex(iSub) == pTemp) - { - SubIndices << iSub; - break; - } - } - } - else - SubIndices << 0; - - if (pParent->Type() == eArrayProperty) - { - SubIndices << mArrayIndices[IndexIndex]; - IndexIndex++; - } - - pTemp = pParent; - pParent = pParent->Parent(); - } - - // Find corresponding property - mpProperty = mpBaseStruct; - - for (int iChild = SubIndices.size() - 1; iChild >= 0; iChild--) - mpProperty = static_cast(mpProperty)->PropertyByIndex(SubIndices[iChild]); -} diff --git a/src/Editor/Undo/CBasicPropertyCommand.h b/src/Editor/Undo/CBasicPropertyCommand.h deleted file mode 100644 index 9d4add4a..00000000 --- a/src/Editor/Undo/CBasicPropertyCommand.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef CBASICPROPERTYCOMMAND_H -#define CBASICPROPERTYCOMMAND_H - -#include "IUndoCommand.h" -#include "Editor/PropertyEdit/CPropertyModel.h" -#include "Editor/WorldEditor/CWorldEditor.h" - -class CBasicPropertyCommand : public IUndoCommand -{ -protected: - IProperty *mpProperty; - IPropertyTemplate *mpTemplate; - CPropertyStruct *mpBaseStruct; - CWorldEditor *mpEditor; - - bool mIsInArray; - QVector mArrayIndices; - -public: - CBasicPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, const QString& rkCommandName = "Edit Property"); - virtual void UpdateArraySubProperty(); - virtual bool AffectsCleanState() const { return true; } -}; - -#endif // CBASICPROPERTYCOMMAND_H diff --git a/src/Editor/Undo/CChangeLayerCommand.cpp b/src/Editor/Undo/CChangeLayerCommand.cpp index 1911be9b..2ed1121d 100644 --- a/src/Editor/Undo/CChangeLayerCommand.cpp +++ b/src/Editor/Undo/CChangeLayerCommand.cpp @@ -2,41 +2,46 @@ CChangeLayerCommand::CChangeLayerCommand(CWorldEditor *pEditor, const QList& rkNodeList, CScriptLayer *pNewLayer) : IUndoCommand("Change Layer") - , mNodeList(rkNodeList) , mpNewLayer(pNewLayer) , mpEditor(pEditor) { - foreach (CScriptNode *pNode, mNodeList) + foreach (CScriptNode *pNode, rkNodeList) { CScriptLayer *pLayer = pNode->Object()->Layer(); - if (pLayer == pNewLayer) + if (pLayer != pNewLayer && !mNodes.contains(pNode)) { - mNodeList.removeOne(pNode); - continue; + mNodes << pNode; + mOldLayers[pNode->ID()] = pLayer; } - - mOldLayers[pNode] = pLayer; } } void CChangeLayerCommand::undo() { mpEditor->InstancesLayerAboutToChange(); + QList Nodes = mNodes.DereferenceList(); - foreach (CScriptNode *pNode, mNodeList) - pNode->Object()->SetLayer(mOldLayers[pNode]); + QList ScriptNodes; + foreach (CSceneNode *pNode, Nodes) ScriptNodes << static_cast(pNode); - mpEditor->InstancesLayerChanged(mNodeList); + foreach (CScriptNode *pNode, ScriptNodes) + pNode->Object()->SetLayer(mOldLayers[pNode->ID()]); + + mpEditor->InstancesLayerChanged(ScriptNodes); } void CChangeLayerCommand::redo() { mpEditor->InstancesLayerAboutToChange(); + QList Nodes = mNodes.DereferenceList(); - foreach (CScriptNode *pNode, mNodeList) + QList ScriptNodes; + foreach (CSceneNode *pNode, Nodes) ScriptNodes << static_cast(pNode); + + foreach (CScriptNode *pNode, ScriptNodes) pNode->Object()->SetLayer(mpNewLayer); - mpEditor->InstancesLayerChanged(mNodeList); + mpEditor->InstancesLayerChanged(ScriptNodes); } diff --git a/src/Editor/Undo/CChangeLayerCommand.h b/src/Editor/Undo/CChangeLayerCommand.h index 589ef50f..ecfcf2d5 100644 --- a/src/Editor/Undo/CChangeLayerCommand.h +++ b/src/Editor/Undo/CChangeLayerCommand.h @@ -2,13 +2,14 @@ #define CCHANGELAYERCOMMAND_H #include "IUndoCommand.h" +#include "ObjReferences.h" #include "Editor/WorldEditor/CWorldEditor.h" #include class CChangeLayerCommand : public IUndoCommand { - QList mNodeList; - QMap mOldLayers; + CNodePtrList mNodes; + QMap mOldLayers; CScriptLayer *mpNewLayer; CWorldEditor *mpEditor; diff --git a/src/Editor/Undo/CClearSelectionCommand.h b/src/Editor/Undo/CClearSelectionCommand.h index cfa2a6fa..e6d48a7c 100644 --- a/src/Editor/Undo/CClearSelectionCommand.h +++ b/src/Editor/Undo/CClearSelectionCommand.h @@ -2,22 +2,26 @@ #define CCLEARSELECTIONCOMMAND_H #include "IUndoCommand.h" +#include "ObjReferences.h" +#include "Editor/CSelectionIterator.h" #include "Editor/INodeEditor.h" #include class CClearSelectionCommand : public IUndoCommand { - QList mOldSelection; CNodeSelection *mpSelection; + CNodePtrList mOldSelection; public: CClearSelectionCommand(CNodeSelection *pSelection) : IUndoCommand("Clear Selection"), - mOldSelection(pSelection->SelectedNodeList()), mpSelection(pSelection) - {} + { + for (CSelectionIterator It(pSelection); It; ++It) + mOldSelection << *It; + } - void undo() { mpSelection->SetSelectedNodes(mOldSelection); } + void undo() { mpSelection->SetSelectedNodes(mOldSelection.DereferenceList()); } void redo() { mpSelection->Clear(); } bool AffectsCleanState() const { return false; } }; diff --git a/src/Editor/Undo/CCreateInstanceCommand.cpp b/src/Editor/Undo/CCreateInstanceCommand.cpp index 18f3cf5b..f7a40e8e 100644 --- a/src/Editor/Undo/CCreateInstanceCommand.cpp +++ b/src/Editor/Undo/CCreateInstanceCommand.cpp @@ -16,13 +16,14 @@ CCreateInstanceCommand::CCreateInstanceCommand(CWorldEditor *pEditor, CScriptTem void CCreateInstanceCommand::undo() { - mpEditor->NotifyNodeAboutToBeDeleted(mpNewNode); - mpEditor->Selection()->SetSelectedNodes(mOldSelection); - mpScene->DeleteNode(mpNewNode); - mpArea->DeleteInstance(mpNewInstance); + mpEditor->NotifyNodeAboutToBeDeleted(*mpNewNode); + mpEditor->Selection()->SetSelectedNodes(mOldSelection.DereferenceList()); + mpScene->DeleteNode(*mpNewNode); + mpArea->DeleteInstance(*mpNewInstance); + mpEditor->NotifyNodeDeleted(); + mpNewNode = nullptr; mpNewInstance = nullptr; - mpEditor->NotifyNodeDeleted(); } void CCreateInstanceCommand::redo() @@ -30,10 +31,12 @@ void CCreateInstanceCommand::redo() mpEditor->NotifyNodeAboutToBeSpawned(); CScriptLayer *pLayer = (mLayerIndex == -1 ? mpArea->GetGeneratorLayer() : mpArea->GetScriptLayer(mLayerIndex)); - mpNewInstance = mpArea->SpawnInstance(mpTemplate, pLayer, mSpawnPosition); - mpNewNode = mpScene->CreateScriptNode(mpNewInstance); - mpNewNode->SetPosition(mSpawnPosition); + CScriptObject *pNewInst = mpArea->SpawnInstance(mpTemplate, pLayer, mSpawnPosition); + CScriptNode *pNewNode = mpScene->CreateScriptNode(pNewInst); + pNewNode->SetPosition(mSpawnPosition); + mpEditor->NotifyNodeSpawned(pNewNode); + mpEditor->Selection()->ClearAndSelectNode(pNewNode); - mpEditor->NotifyNodeSpawned(mpNewNode); - mpEditor->Selection()->ClearAndSelectNode(mpNewNode); + mpNewInstance = pNewInst; + mpNewNode = pNewNode; } diff --git a/src/Editor/Undo/CCreateInstanceCommand.h b/src/Editor/Undo/CCreateInstanceCommand.h index a03714fe..32e68168 100644 --- a/src/Editor/Undo/CCreateInstanceCommand.h +++ b/src/Editor/Undo/CCreateInstanceCommand.h @@ -18,9 +18,9 @@ class CCreateInstanceCommand : public IUndoCommand u32 mLayerIndex; CVector3f mSpawnPosition; - QList mOldSelection; - CScriptObject *mpNewInstance; - CScriptNode *mpNewNode; + CNodePtrList mOldSelection; + CInstancePtr mpNewInstance; + CNodePtr mpNewNode; public: CCreateInstanceCommand(CWorldEditor *pEditor, CScriptTemplate *pTemplate, CScriptLayer *pLayer, const CVector3f& rkPosition); diff --git a/src/Editor/Undo/CDeleteLinksCommand.cpp b/src/Editor/Undo/CDeleteLinksCommand.cpp index 668bc3e5..fd335680 100644 --- a/src/Editor/Undo/CDeleteLinksCommand.cpp +++ b/src/Editor/Undo/CDeleteLinksCommand.cpp @@ -48,7 +48,7 @@ void CDeleteLinksCommand::undo() SNewLink Link; Link.pDelLink = &mLinks[iLink]; - Link.pLink = new CLink(mpEditor->ActiveArea(), rDelLink.State, rDelLink.Message, rDelLink.pSender->InstanceID(), rDelLink.pReceiver->InstanceID()); + Link.pLink = new CLink(mpEditor->ActiveArea(), rDelLink.State, rDelLink.Message, rDelLink.pSender.InstanceID(), rDelLink.pReceiver.InstanceID()); NewLinks << Link; } @@ -71,7 +71,7 @@ void CDeleteLinksCommand::undo() } // Notify world editor - mpEditor->OnLinksModified(mAffectedInstances); + mpEditor->OnLinksModified(mAffectedInstances.DereferenceList()); } void CDeleteLinksCommand::redo() @@ -93,5 +93,5 @@ void CDeleteLinksCommand::redo() } // Notify world editor - mpEditor->OnLinksModified(mAffectedInstances); + mpEditor->OnLinksModified(mAffectedInstances.DereferenceList()); } diff --git a/src/Editor/Undo/CDeleteLinksCommand.h b/src/Editor/Undo/CDeleteLinksCommand.h index b599189a..c5fa84a6 100644 --- a/src/Editor/Undo/CDeleteLinksCommand.h +++ b/src/Editor/Undo/CDeleteLinksCommand.h @@ -2,25 +2,27 @@ #define CDELETELINKSCOMMAND_H #include "IUndoCommand.h" +#include "ObjReferences.h" #include "Editor/WorldEditor/CWorldEditor.h" class CDeleteLinksCommand : public IUndoCommand { CWorldEditor *mpEditor; - QList mAffectedInstances; + CInstancePtrList mAffectedInstances; struct SDeletedLink { u32 State; u32 Message; - CScriptObject *pSender; - CScriptObject *pReceiver; + CInstancePtr pSender; + CInstancePtr pReceiver; u32 SenderIndex; u32 ReceiverIndex; }; QVector mLinks; public: + CDeleteLinksCommand() {} CDeleteLinksCommand(CWorldEditor *pEditor, CScriptObject *pObject, ELinkType Type, const QVector& rkIndices); void undo(); void redo(); diff --git a/src/Editor/Undo/CDeleteSelectionCommand.cpp b/src/Editor/Undo/CDeleteSelectionCommand.cpp index 83405975..318a00f6 100644 --- a/src/Editor/Undo/CDeleteSelectionCommand.cpp +++ b/src/Editor/Undo/CDeleteSelectionCommand.cpp @@ -1,35 +1,142 @@ #include "CDeleteSelectionCommand.h" #include "Editor/CSelectionIterator.h" +#include +#include +#include CDeleteSelectionCommand::CDeleteSelectionCommand(CWorldEditor *pEditor) : IUndoCommand("Delete") , mpEditor(pEditor) { - mOldSelection = pEditor->Selection()->SelectedNodeList(); + QSet Links; for (CSelectionIterator It(pEditor->Selection()); It; ++It) { + mOldSelection << *It; + if (It->NodeType() == eScriptNode) - mNodesToDelete << *It; + { + CScriptNode *pScript = static_cast(*It); + CScriptObject *pInst = pScript->Object(); + + 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 (u32 iType = 0; iType < 2; iType++) + { + ELinkType Type = (iType == 0 ? eOutgoing : eIncoming); + + for (u32 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; + } + } + } + + CVectorOutStream PropertyDataOut(&rNode.InstanceData, IOUtil::eBigEndian); + CScriptCooker::CookInstance(eReturns, pInst, PropertyDataOut); + } + else mNewSelection << *It; } + + qSort(mDeletedNodes.begin(), mDeletedNodes.end(), [](SDeletedNode& rLeft, SDeletedNode& rRight) -> bool { + return (rLeft.NodeID < rRight.NodeID); + }); } void CDeleteSelectionCommand::undo() { - //foreach (CSceneNode *pNode, mNodesToDelete) - // pNode->SetDeleted(false); - //mpEditor->Selection()->SetSelectedNodes(mOldSelection); + QList 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(), IOUtil::eBigEndian); + CScriptObject *pInstance = CScriptLoader::LoadInstance(Mem, rNode.pArea, rNode.pLayer, rNode.pArea->Version(), true); + CScriptNode *pNode = mpEditor->Scene()->CreateScriptNode(pInstance, rNode.NodeID); + rNode.pArea->AddInstanceToArea(pInstance); + rNode.pLayer->AddInstance(pInstance, rNode.LayerIndex); + + if (!pInstance->PositionProperty()) pNode->SetPosition(rNode.Position); + if (!pInstance->RotationProperty()) pNode->SetRotation(rNode.Rotation); + if (!pInstance->ScaleProperty()) pNode->SetScale(rNode.Scale); + + NewInstanceIDs << pInstance->InstanceID(); + mpEditor->NotifyNodeSpawned(*rNode.NodePtr); + } + + // Sort links by sender index, add outgoing + qSort(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)) + { + CLink *pLink = new CLink(rLink.pSender->Area(), rLink.State, rLink.Message, rLink.SenderID, rLink.ReceiverID); + rLink.pSender->AddLink(eOutgoing, pLink, rLink.SenderIndex); + } + } + + // Sort links by receiver index, add incoming + qSort(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]; + CLink *pLink = rLink.pSender->Link(eOutgoing, rLink.SenderIndex); + rLink.pReceiver->AddLink(eIncoming, pLink, rLink.ReceiverIndex); + } + + // Add selection and done + mpEditor->Selection()->SetSelectedNodes(mOldSelection.DereferenceList()); } void CDeleteSelectionCommand::redo() { - mpEditor->Selection()->SetSelectedNodes(mNewSelection); + mpEditor->Selection()->SetSelectedNodes(mNewSelection.DereferenceList()); - foreach (CSceneNode *pNode, mNodesToDelete) + for (int iNode = 0; iNode < mDeletedNodes.size(); iNode++) { + SDeletedNode& rNode = mDeletedNodes[iNode]; + CSceneNode *pNode = *rNode.NodePtr; CScriptObject *pInst = static_cast(pNode)->Object(); + mpEditor->NotifyNodeAboutToBeDeleted(pNode); mpEditor->Scene()->DeleteNode(pNode); mpEditor->ActiveArea()->DeleteInstance(pInst); diff --git a/src/Editor/Undo/CDeleteSelectionCommand.h b/src/Editor/Undo/CDeleteSelectionCommand.h index 04c4f470..cb463453 100644 --- a/src/Editor/Undo/CDeleteSelectionCommand.h +++ b/src/Editor/Undo/CDeleteSelectionCommand.h @@ -1,16 +1,49 @@ #ifndef CDELETESELECTIONCOMMAND_H #define CDELETESELECTIONCOMMAND_H +#include "CDeleteLinksCommand.h" #include "IUndoCommand.h" +#include "ObjReferences.h" #include "Editor/WorldEditor/CWorldEditor.h" #include +// todo: currently only supports deleting script nodes; needs support for light nodes as well +// plus maybe it should be extensible enough to support other possible types class CDeleteSelectionCommand : public IUndoCommand { CWorldEditor *mpEditor; - QList mNodesToDelete; - QList mOldSelection; - QList mNewSelection; + CNodePtrList mOldSelection; + CNodePtrList mNewSelection; + + struct SDeletedNode + { + // Node Info + CNodePtr NodePtr; + u32 NodeID; + CVector3f Position; + CQuaternion Rotation; + CVector3f Scale; + + // Instance Info + CGameArea *pArea; + CScriptLayer *pLayer; + u32 LayerIndex; + std::vector InstanceData; + }; + QVector mDeletedNodes; + + struct SDeletedLink + { + u32 State; + u32 Message; + u32 SenderID; + u32 SenderIndex; + u32 ReceiverID; + u32 ReceiverIndex; + CInstancePtr pSender; + CInstancePtr pReceiver; + }; + QVector mDeletedLinks; public: CDeleteSelectionCommand(CWorldEditor *pEditor); diff --git a/src/Editor/Undo/CDeselectNodeCommand.h b/src/Editor/Undo/CDeselectNodeCommand.h index ccb96715..a7a4a438 100644 --- a/src/Editor/Undo/CDeselectNodeCommand.h +++ b/src/Editor/Undo/CDeselectNodeCommand.h @@ -2,12 +2,13 @@ #define CDESELECTNODECOMMAND_H #include "IUndoCommand.h" +#include "ObjReferences.h" #include "Editor/INodeEditor.h" #include class CDeselectNodeCommand : public IUndoCommand { - CSceneNode *mpNode; + CNodePtr mpNode; CNodeSelection *mpSelection; public: CDeselectNodeCommand(CNodeSelection *pSelection, CSceneNode *pNode) @@ -16,8 +17,8 @@ public: , mpSelection(pSelection) {} - void undo() { mpSelection->SelectNode(mpNode); } - void redo() { mpSelection->DeselectNode(mpNode); } + void undo() { mpSelection->SelectNode(*mpNode); } + void redo() { mpSelection->DeselectNode(*mpNode); } bool AffectsCleanState() const { return false; } }; diff --git a/src/Editor/Undo/CEditLinkCommand.cpp b/src/Editor/Undo/CEditLinkCommand.cpp index d584f0bb..8598edde 100644 --- a/src/Editor/Undo/CEditLinkCommand.cpp +++ b/src/Editor/Undo/CEditLinkCommand.cpp @@ -9,42 +9,49 @@ CEditLinkCommand::CEditLinkCommand(CWorldEditor *pEditor, CLink *pLink, CLink Ne { mOldSenderIndex = pLink->SenderIndex(); mOldReceiverIndex = pLink->ReceiverIndex(); + mAffectedInstances << pLink->Sender(); - if (pLink->Receiver() != pLink->Sender()) mAffectedInstances << pLink->Receiver(); - if (NewLink.Sender() != pLink->Sender()) mAffectedInstances << NewLink.Sender(); - if (NewLink.Receiver() != pLink->Receiver()) mAffectedInstances << NewLink.Receiver(); + if (pLink->ReceiverID() != pLink->SenderID()) mAffectedInstances << pLink->Receiver(); + if (NewLink.SenderID() != pLink->SenderID()) mAffectedInstances << NewLink.Sender(); + if (NewLink.ReceiverID() != pLink->ReceiverID()) mAffectedInstances << NewLink.Receiver(); } void CEditLinkCommand::undo() { + CLink *pLink = *mpEditLink; + if (mOldLink.Sender() != mNewLink.Sender()) { - mNewLink.Sender()->RemoveLink(eOutgoing, mpEditLink); - mOldLink.Sender()->AddLink(eOutgoing, mpEditLink, mOldSenderIndex); + mNewLink.Sender()->RemoveLink(eOutgoing, pLink); + mOldLink.Sender()->AddLink(eOutgoing, pLink, mOldSenderIndex); } if (mOldLink.Receiver() != mNewLink.Receiver()) { - mNewLink.Receiver()->RemoveLink(eIncoming, mpEditLink); - mOldLink.Receiver()->AddLink(eIncoming, mpEditLink, mOldReceiverIndex); + mNewLink.Receiver()->RemoveLink(eIncoming, pLink); + mOldLink.Receiver()->AddLink(eIncoming, pLink, mOldReceiverIndex); } - *mpEditLink = mOldLink; - mpEditor->OnLinksModified(mAffectedInstances); + *pLink = mOldLink; + mpEditor->OnLinksModified(mAffectedInstances.DereferenceList()); + mpEditLink.SetLink(pLink); // note: This is done to account for situations where the sender has changed } void CEditLinkCommand::redo() { + CLink *pLink = *mpEditLink; + if (mOldLink.Sender() != mNewLink.Sender()) { - mOldLink.Sender()->RemoveLink(eOutgoing, mpEditLink); - mNewLink.Sender()->AddLink(eOutgoing, mpEditLink); + mOldLink.Sender()->RemoveLink(eOutgoing, pLink); + mNewLink.Sender()->AddLink(eOutgoing, pLink); } if (mOldLink.Receiver() != mNewLink.Receiver()) { - mOldLink.Receiver()->RemoveLink(eIncoming, mpEditLink); - mNewLink.Receiver()->AddLink(eIncoming, mpEditLink); + mOldLink.Receiver()->RemoveLink(eIncoming, pLink); + mNewLink.Receiver()->AddLink(eIncoming, pLink); } - *mpEditLink = mNewLink; - mpEditor->OnLinksModified(mAffectedInstances); + *pLink = mNewLink; + mpEditor->OnLinksModified(mAffectedInstances.DereferenceList()); + mpEditLink.SetLink(pLink); } diff --git a/src/Editor/Undo/CEditLinkCommand.h b/src/Editor/Undo/CEditLinkCommand.h index 901c1457..afb1570b 100644 --- a/src/Editor/Undo/CEditLinkCommand.h +++ b/src/Editor/Undo/CEditLinkCommand.h @@ -2,23 +2,25 @@ #define CEDITLINKCOMMAND_H #include "IUndoCommand.h" +#include "ObjReferences.h" #include "Editor/WorldEditor/CWorldEditor.h" #include class CEditLinkCommand : public IUndoCommand { CWorldEditor *mpEditor; - CLink *mpEditLink; + CLinkPtr mpEditLink; CLink mOldLink; CLink mNewLink; u32 mOldSenderIndex; u32 mOldReceiverIndex; - QList mAffectedInstances; + CInstancePtrList mAffectedInstances; public: CEditLinkCommand(CWorldEditor *pEditor, CLink *pLink, CLink NewLink); + QList AffectedInstances() const; void undo(); void redo(); bool AffectsCleanState() const { return true; } diff --git a/src/Editor/Undo/CEditScriptPropertyCommand.cpp b/src/Editor/Undo/CEditScriptPropertyCommand.cpp index 67bd3f1a..b1b12f08 100644 --- a/src/Editor/Undo/CEditScriptPropertyCommand.cpp +++ b/src/Editor/Undo/CEditScriptPropertyCommand.cpp @@ -2,11 +2,13 @@ #include "EUndoCommand.h" CEditScriptPropertyCommand::CEditScriptPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, IPropertyValue *pOldValue, bool IsDone, const QString& rkCommandName /*= "Edit Property"*/) - : CBasicPropertyCommand(pProp, pEditor, rkCommandName) + : IUndoCommand(rkCommandName) + , mpProp(pProp) + , mpEditor(pEditor) , mCommandEnded(IsDone) { mpOldValue = pOldValue; - mpNewValue = mpProperty->RawValue()->Clone(); + mpNewValue = pProp->RawValue()->Clone(); } CEditScriptPropertyCommand::~CEditScriptPropertyCommand() @@ -26,7 +28,7 @@ bool CEditScriptPropertyCommand::mergeWith(const QUndoCommand *pkOther) { const CEditScriptPropertyCommand *pkCmd = static_cast(pkOther); - if (pkCmd->mpProperty == mpProperty) + if (pkCmd->mpProp == mpProp) { mpNewValue->Copy(pkCmd->mpNewValue); mCommandEnded = pkCmd->mCommandEnded; @@ -39,15 +41,15 @@ bool CEditScriptPropertyCommand::mergeWith(const QUndoCommand *pkOther) void CEditScriptPropertyCommand::undo() { - if (mIsInArray) UpdateArraySubProperty(); - mpProperty->RawValue()->Copy(mpOldValue); - mpEditor->OnPropertyModified(mpProperty); + IProperty *pProp = *mpProp; + pProp->RawValue()->Copy(mpOldValue); + mpEditor->OnPropertyModified(pProp); mCommandEnded = true; } void CEditScriptPropertyCommand::redo() { - if (mIsInArray) UpdateArraySubProperty(); - mpProperty->RawValue()->Copy(mpNewValue); - mpEditor->OnPropertyModified(mpProperty); + IProperty *pProp = *mpProp; + pProp->RawValue()->Copy(mpNewValue); + mpEditor->OnPropertyModified(pProp); } diff --git a/src/Editor/Undo/CEditScriptPropertyCommand.h b/src/Editor/Undo/CEditScriptPropertyCommand.h index 49ff9cc3..63efad5c 100644 --- a/src/Editor/Undo/CEditScriptPropertyCommand.h +++ b/src/Editor/Undo/CEditScriptPropertyCommand.h @@ -1,11 +1,15 @@ #ifndef CEDITSCRIPTPROPERTYCOMMAND_H #define CEDITSCRIPTPROPERTYCOMMAND_H -#include "CBasicPropertyCommand.h" +#include "IUndoCommand.h" +#include "ObjReferences.h" #include "Editor/PropertyEdit/CPropertyModel.h" +#include "Editor/WorldEditor/CWorldEditor.h" -class CEditScriptPropertyCommand : public CBasicPropertyCommand +class CEditScriptPropertyCommand : public IUndoCommand { + CWorldEditor *mpEditor; + CPropertyPtr mpProp; IPropertyValue *mpOldValue; IPropertyValue *mpNewValue; bool mCommandEnded; @@ -17,6 +21,7 @@ public: bool mergeWith(const QUndoCommand *pkOther); void undo(); void redo(); + bool AffectsCleanState() const { return true; } }; #endif // CEDITSCRIPTPROPERTYCOMMAND_H diff --git a/src/Editor/Undo/CInvertSelectionCommand.h b/src/Editor/Undo/CInvertSelectionCommand.h index 0723105b..fd29e289 100644 --- a/src/Editor/Undo/CInvertSelectionCommand.h +++ b/src/Editor/Undo/CInvertSelectionCommand.h @@ -2,14 +2,15 @@ #define CINVERTSELECTIONCOMMAND_H #include "IUndoCommand.h" +#include "ObjReferences.h" #include "Editor/INodeEditor.h" #include class CInvertSelectionCommand : public IUndoCommand { CNodeSelection *mpSelection; - QList mOldSelection; - QList mNewSelection; + CNodePtrList mOldSelection; + CNodePtrList mNewSelection; public: CInvertSelectionCommand(CNodeSelection *pSelection, CScene *pScene, FNodeFlags NodeFlags) @@ -25,8 +26,8 @@ public: } } - void undo() { mpSelection->SetSelectedNodes(mOldSelection); } - void redo() { mpSelection->SetSelectedNodes(mNewSelection); } + void undo() { mpSelection->SetSelectedNodes(mOldSelection.DereferenceList()); } + void redo() { mpSelection->SetSelectedNodes(mNewSelection.DereferenceList()); } bool AffectsCleanState() const { return false; } }; diff --git a/src/Editor/Undo/CResizeScriptArrayCommand.cpp b/src/Editor/Undo/CResizeScriptArrayCommand.cpp index 4c1af966..d36b2e06 100644 --- a/src/Editor/Undo/CResizeScriptArrayCommand.cpp +++ b/src/Editor/Undo/CResizeScriptArrayCommand.cpp @@ -1,19 +1,22 @@ #include "CResizeScriptArrayCommand.h" CResizeScriptArrayCommand::CResizeScriptArrayCommand(IProperty *pProp, CWorldEditor *pEditor, CPropertyModel *pModel, int NewSize) - : CBasicPropertyCommand(pProp, pEditor) - , mpArray(static_cast(mpProperty)) + : IUndoCommand("Edit Property") + , mpEditor(pEditor) + , mpArray(pProp) , mpModel(pModel) - , mOldSize(mpArray->Count()) + , mOldSize(static_cast(pProp)->Count()) , mNewSize(NewSize) { mNewSizeLarger = mNewSize > mOldSize; if (!mNewSizeLarger) { + CArrayProperty *pArray = static_cast(pProp); + for (int iSub = mNewSize; iSub < mOldSize; iSub++) { - mDeletedProperties << mpArray->PropertyByIndex(iSub)->Clone(); + mDeletedProperties << pArray->PropertyByIndex(iSub)->Clone(nullptr); } } } @@ -28,11 +31,16 @@ void CResizeScriptArrayCommand::undo() { if (mNewSize != mOldSize) { - if (mIsInArray) UpdateArraySubProperty(); + // Update parents + CArrayProperty *pArray = static_cast(*mpArray); - QModelIndex Index = mpModel->IndexForProperty(mpProperty); + foreach (IProperty *pProp, mDeletedProperties) + pProp->SetParent(pArray); + + // Resize array + QModelIndex Index = mpModel->IndexForProperty(pArray); mpModel->ArrayAboutToBeResized(Index, (u32) mOldSize); - mpArray->Resize(mOldSize); + pArray->Resize(mOldSize); if (!mNewSizeLarger) { @@ -41,7 +49,7 @@ void CResizeScriptArrayCommand::undo() for (int iSub = 0; iSub < NumNewElements; iSub++) { u32 Idx = iSub + mNewSize; - mpArray->PropertyByIndex(Idx)->Copy(mDeletedProperties[iSub]); + pArray->PropertyByIndex(Idx)->Copy(mDeletedProperties[iSub]); } } @@ -54,24 +62,10 @@ void CResizeScriptArrayCommand::redo() // Whether we're increasing or decreasing in size, there's no need to restore deleted properties on redo. if (mNewSize != mOldSize) { - if (mIsInArray) UpdateArraySubProperty(); - - QModelIndex Index = mpModel->IndexForProperty(mpProperty); + CArrayProperty *pArray = static_cast(*mpArray); + QModelIndex Index = mpModel->IndexForProperty(pArray); mpModel->ArrayAboutToBeResized(Index, (u32) mNewSize); - mpArray->Resize(mNewSize); + pArray->Resize(mNewSize); mpModel->ArrayResized(Index, (u32) mOldSize); } } - -void CResizeScriptArrayCommand::UpdateArraySubProperty() -{ - CArrayProperty *pOldArray = mpArray; - CBasicPropertyCommand::UpdateArraySubProperty(); - mpArray = static_cast(mpProperty); - - if (pOldArray != mpArray) - { - for (int iDel = 0; iDel < mDeletedProperties.size(); iDel++) - mDeletedProperties[iDel]->SetParent(mpArray); - } -} diff --git a/src/Editor/Undo/CResizeScriptArrayCommand.h b/src/Editor/Undo/CResizeScriptArrayCommand.h index 05e072dd..a5b89ec3 100644 --- a/src/Editor/Undo/CResizeScriptArrayCommand.h +++ b/src/Editor/Undo/CResizeScriptArrayCommand.h @@ -1,13 +1,17 @@ #ifndef CRESIZESCRIPTARRAYCOMMAND_H #define CRESIZESCRIPTARRAYCOMMAND_H -#include "CBasicPropertyCommand.h" +#include "IUndoCommand.h" +#include "ObjReferences.h" #include "Editor/PropertyEdit/CPropertyModel.h" +#include "Editor/WorldEditor/CWorldEditor.h" #include -class CResizeScriptArrayCommand : public CBasicPropertyCommand +// todo: make this more general... it shouldn't be relying on a CPropertyModel pointer +class CResizeScriptArrayCommand : public IUndoCommand { - CArrayProperty *mpArray; + CWorldEditor *mpEditor; + CPropertyPtr mpArray; QVector mDeletedProperties; CPropertyModel *mpModel; @@ -20,7 +24,7 @@ public: ~CResizeScriptArrayCommand(); void undo(); void redo(); - virtual void UpdateArraySubProperty(); + bool AffectsCleanState() const { return true; } }; #endif // CRESIZESCRIPTARRAYCOMMAND_H diff --git a/src/Editor/Undo/CRotateNodeCommand.cpp b/src/Editor/Undo/CRotateNodeCommand.cpp index d52fb51f..aea4f136 100644 --- a/src/Editor/Undo/CRotateNodeCommand.cpp +++ b/src/Editor/Undo/CRotateNodeCommand.cpp @@ -9,23 +9,23 @@ CRotateNodeCommand::CRotateNodeCommand() { } -CRotateNodeCommand::CRotateNodeCommand(INodeEditor *pEditor, const QList& nodes, const CVector3f& /*pivot*/, const CQuaternion& delta, ETransformSpace transformSpace) +CRotateNodeCommand::CRotateNodeCommand(INodeEditor *pEditor, const QList& rkNodes, const CVector3f& /*rkPivot*/, const CQuaternion& rkDelta, ETransformSpace TransformSpace) : IUndoCommand("Rotate"), mpEditor(pEditor), mCommandEnded(false) { - mNodeList.reserve(nodes.size()); + mNodeList.reserve(rkNodes.size()); - foreach (CSceneNode *pNode, nodes) + foreach (CSceneNode *pNode, rkNodes) { - SNodeRotate rotate; - rotate.pNode = pNode; - rotate.initialPos = pNode->LocalPosition(); - rotate.initialRot = pNode->LocalRotation(); - pNode->Rotate(delta, transformSpace); - rotate.newPos = pNode->LocalPosition(); - rotate.newRot = pNode->LocalRotation(); - mNodeList.push_back(rotate); + SNodeRotate Rotate; + Rotate.pNode = pNode; + Rotate.InitialPos = pNode->LocalPosition(); + Rotate.InitialRot = pNode->LocalRotation(); + pNode->Rotate(rkDelta, TransformSpace); + Rotate.NewPos = pNode->LocalPosition(); + Rotate.NewRot = pNode->LocalRotation(); + mNodeList.push_back(Rotate); } mpEditor->NotifySelectionTransformed(); @@ -40,26 +40,26 @@ int CRotateNodeCommand::id() const return eRotateNodeCmd; } -bool CRotateNodeCommand::mergeWith(const QUndoCommand *other) +bool CRotateNodeCommand::mergeWith(const QUndoCommand *pkOther) { if (mCommandEnded) return false; - if (other->id() == eRotateNodeCmd) + if (pkOther->id() == eRotateNodeCmd) { - const CRotateNodeCommand *pCmd = static_cast(other); + const CRotateNodeCommand *pkCmd = static_cast(pkOther); - if (pCmd->mCommandEnded) + if (pkCmd->mCommandEnded) { mCommandEnded = true; return true; } - if ((mpEditor == pCmd->mpEditor) && (mNodeList.size() == pCmd->mNodeList.size())) + if ((mpEditor == pkCmd->mpEditor) && (mNodeList.size() == pkCmd->mNodeList.size())) { for (int iNode = 0; iNode < mNodeList.size(); iNode++) { - mNodeList[iNode].newPos = pCmd->mNodeList[iNode].newPos; - mNodeList[iNode].newRot = pCmd->mNodeList[iNode].newRot; + mNodeList[iNode].NewPos = pkCmd->mNodeList[iNode].NewPos; + mNodeList[iNode].NewRot = pkCmd->mNodeList[iNode].NewRot; } return true; @@ -73,10 +73,10 @@ void CRotateNodeCommand::undo() { if (!mpEditor) return; - foreach (SNodeRotate rotate, mNodeList) + foreach (SNodeRotate Rotate, mNodeList) { - rotate.pNode->SetPosition(rotate.initialPos); - rotate.pNode->SetRotation(rotate.initialRot); + Rotate.pNode->SetPosition(Rotate.InitialPos); + Rotate.pNode->SetRotation(Rotate.InitialRot); } mpEditor->NotifySelectionTransformed(); @@ -87,10 +87,10 @@ void CRotateNodeCommand::redo() { if (!mpEditor) return; - foreach (SNodeRotate rotate, mNodeList) + foreach (SNodeRotate Rotate, mNodeList) { - rotate.pNode->SetPosition(rotate.newPos); - rotate.pNode->SetRotation(rotate.newRot); + Rotate.pNode->SetPosition(Rotate.NewPos); + Rotate.pNode->SetRotation(Rotate.NewRot); } mpEditor->NotifySelectionTransformed(); diff --git a/src/Editor/Undo/CRotateNodeCommand.h b/src/Editor/Undo/CRotateNodeCommand.h index e6e4cdf6..46aa86fa 100644 --- a/src/Editor/Undo/CRotateNodeCommand.h +++ b/src/Editor/Undo/CRotateNodeCommand.h @@ -2,6 +2,7 @@ #define CROTATENODECOMMAND_H #include "IUndoCommand.h" +#include "ObjReferences.h" #include "Editor/INodeEditor.h" #include #include @@ -10,11 +11,11 @@ class CRotateNodeCommand : public IUndoCommand { struct SNodeRotate { - CSceneNode *pNode; - CVector3f initialPos; - CQuaternion initialRot; - CVector3f newPos; - CQuaternion newRot; + CNodePtr pNode; + CVector3f InitialPos; + CQuaternion InitialRot; + CVector3f NewPos; + CQuaternion NewRot; }; QList mNodeList; INodeEditor *mpEditor; @@ -22,10 +23,10 @@ class CRotateNodeCommand : public IUndoCommand public: CRotateNodeCommand(); - CRotateNodeCommand(INodeEditor *pEditor, const QList& nodes, const CVector3f& pivot, const CQuaternion& delta, ETransformSpace transformSpace); + CRotateNodeCommand(INodeEditor *pEditor, const QList& rkNodes, const CVector3f& rkPivot, const CQuaternion& rkDelta, ETransformSpace TransformSpace); ~CRotateNodeCommand(); int id() const; - bool mergeWith(const QUndoCommand *other); + bool mergeWith(const QUndoCommand *pkOther); void undo(); void redo(); bool AffectsCleanState() const { return true; } diff --git a/src/Editor/Undo/CScaleNodeCommand.cpp b/src/Editor/Undo/CScaleNodeCommand.cpp index f7921725..34acd392 100644 --- a/src/Editor/Undo/CScaleNodeCommand.cpp +++ b/src/Editor/Undo/CScaleNodeCommand.cpp @@ -9,23 +9,23 @@ CScaleNodeCommand::CScaleNodeCommand() { } -CScaleNodeCommand::CScaleNodeCommand(INodeEditor *pEditor, const QList& nodes, const CVector3f& /*pivot*/, const CVector3f& delta) +CScaleNodeCommand::CScaleNodeCommand(INodeEditor *pEditor, const QList& rkNodes, const CVector3f& /*rkPivot*/, const CVector3f& rkDelta) : IUndoCommand("Scale"), mpEditor(pEditor), mCommandEnded(false) { - mNodeList.reserve(nodes.size()); + mNodeList.reserve(rkNodes.size()); - foreach (CSceneNode *pNode, nodes) + foreach (CSceneNode *pNode, rkNodes) { - SNodeScale scale; - scale.pNode = pNode; - scale.initialPos = pNode->LocalPosition(); - scale.initialScale = pNode->LocalScale(); - pNode->Scale(delta); - scale.newPos = pNode->LocalPosition(); - scale.newScale = pNode->LocalScale(); - mNodeList.push_back(scale); + SNodeScale Scale; + Scale.pNode = pNode; + Scale.InitialPos = pNode->LocalPosition(); + Scale.InitialScale = pNode->LocalScale(); + pNode->Scale(rkDelta); + Scale.NewPos = pNode->LocalPosition(); + Scale.NewScale = pNode->LocalScale(); + mNodeList.push_back(Scale); } mpEditor->NotifySelectionTransformed(); @@ -40,26 +40,26 @@ int CScaleNodeCommand::id() const return eScaleNodeCmd; } -bool CScaleNodeCommand::mergeWith(const QUndoCommand *other) +bool CScaleNodeCommand::mergeWith(const QUndoCommand *pkOther) { if (mCommandEnded) return false; - if (other->id() == eScaleNodeCmd) + if (pkOther->id() == eScaleNodeCmd) { - const CScaleNodeCommand *pCmd = static_cast(other); + const CScaleNodeCommand *pkCmd = static_cast(pkOther); - if (pCmd->mCommandEnded) + if (pkCmd->mCommandEnded) { mCommandEnded = true; return true; } - if ((mpEditor == pCmd->mpEditor) && (mNodeList.size() == pCmd->mNodeList.size())) + if ((mpEditor == pkCmd->mpEditor) && (mNodeList.size() == pkCmd->mNodeList.size())) { for (int iNode = 0; iNode < mNodeList.size(); iNode++) { - mNodeList[iNode].newPos = pCmd->mNodeList[iNode].newPos; - mNodeList[iNode].newScale = pCmd->mNodeList[iNode].newScale; + mNodeList[iNode].NewPos = pkCmd->mNodeList[iNode].NewPos; + mNodeList[iNode].NewScale = pkCmd->mNodeList[iNode].NewScale; } return true; @@ -73,10 +73,10 @@ void CScaleNodeCommand::undo() { if (!mpEditor) return; - foreach (SNodeScale scale, mNodeList) + foreach (SNodeScale Scale, mNodeList) { - scale.pNode->SetPosition(scale.initialPos); - scale.pNode->SetScale(scale.initialScale); + Scale.pNode->SetPosition(Scale.InitialPos); + Scale.pNode->SetScale(Scale.InitialScale); } mpEditor->NotifySelectionTransformed(); @@ -87,10 +87,10 @@ void CScaleNodeCommand::redo() { if (!mpEditor) return; - foreach (SNodeScale scale, mNodeList) + foreach (SNodeScale Scale, mNodeList) { - scale.pNode->SetPosition(scale.newPos); - scale.pNode->SetScale(scale.newScale); + Scale.pNode->SetPosition(Scale.NewPos); + Scale.pNode->SetScale(Scale.NewScale); } mpEditor->NotifySelectionTransformed(); diff --git a/src/Editor/Undo/CScaleNodeCommand.h b/src/Editor/Undo/CScaleNodeCommand.h index dae68c26..24d821d5 100644 --- a/src/Editor/Undo/CScaleNodeCommand.h +++ b/src/Editor/Undo/CScaleNodeCommand.h @@ -2,6 +2,7 @@ #define CSCALENODECOMMAND_H #include "IUndoCommand.h" +#include "ObjReferences.h" #include "Editor/INodeEditor.h" #include #include @@ -10,11 +11,11 @@ class CScaleNodeCommand : public IUndoCommand { struct SNodeScale { - CSceneNode *pNode; - CVector3f initialPos; - CVector3f initialScale; - CVector3f newPos; - CVector3f newScale; + CNodePtr pNode; + CVector3f InitialPos; + CVector3f InitialScale; + CVector3f NewPos; + CVector3f NewScale; }; QList mNodeList; INodeEditor *mpEditor; @@ -22,10 +23,10 @@ class CScaleNodeCommand : public IUndoCommand public: CScaleNodeCommand(); - CScaleNodeCommand(INodeEditor *pEditor, const QList& nodes, const CVector3f& pivot, const CVector3f& delta); + CScaleNodeCommand(INodeEditor *pEditor, const QList& rkNodes, const CVector3f& rkPivot, const CVector3f& rkDelta); ~CScaleNodeCommand(); int id() const; - bool mergeWith(const QUndoCommand *other); + bool mergeWith(const QUndoCommand *pkOther); void undo(); void redo(); bool AffectsCleanState() const { return true; } diff --git a/src/Editor/Undo/CSelectAllCommand.h b/src/Editor/Undo/CSelectAllCommand.h index b4b5e929..9a051529 100644 --- a/src/Editor/Undo/CSelectAllCommand.h +++ b/src/Editor/Undo/CSelectAllCommand.h @@ -2,27 +2,30 @@ #define CSELECTALLCOMMAND_H #include "IUndoCommand.h" +#include "ObjReferences.h" +#include "Editor/CSelectionIterator.h" #include "Editor/INodeEditor.h" #include class CSelectAllCommand : public IUndoCommand { - QList mOldSelection; - QList mNewSelection; + CNodePtrList mOldSelection; + CNodePtrList mNewSelection; CNodeSelection *mpSelection; public: CSelectAllCommand(CNodeSelection *pSelection, CScene *pScene, FNodeFlags NodeFlags) : IUndoCommand("Select All") - , mOldSelection(pSelection->SelectedNodeList()) , mpSelection(pSelection) { + for (CSelectionIterator It(pSelection); It; ++It) + mOldSelection << *It; for (CSceneIterator It(pScene, NodeFlags); It; ++It) mNewSelection << *It; } - void undo() { mpSelection->SetSelectedNodes(mOldSelection); } - void redo() { mpSelection->SetSelectedNodes(mNewSelection); } + void undo() { mpSelection->SetSelectedNodes(mOldSelection.DereferenceList()); } + void redo() { mpSelection->SetSelectedNodes(mNewSelection.DereferenceList()); } bool AffectsCleanState() const { return false; } }; diff --git a/src/Editor/Undo/CSelectNodeCommand.h b/src/Editor/Undo/CSelectNodeCommand.h index cc8e9c3c..f20443f3 100644 --- a/src/Editor/Undo/CSelectNodeCommand.h +++ b/src/Editor/Undo/CSelectNodeCommand.h @@ -2,12 +2,13 @@ #define CSELECTNODECOMMAND_H #include "IUndoCommand.h" +#include "ObjReferences.h" #include "Editor/INodeEditor.h" #include class CSelectNodeCommand : public IUndoCommand { - CSceneNode *mpNode; + CNodePtr mpNode; CNodeSelection *mpSelection; public: @@ -17,8 +18,8 @@ public: , mpSelection(pSelection) {} - void undo() { mpSelection->DeselectNode(mpNode); } - void redo() { mpSelection->SelectNode(mpNode); } + void undo() { mpSelection->DeselectNode(*mpNode); } + void redo() { mpSelection->SelectNode(*mpNode); } bool AffectsCleanState() const { return false; } }; diff --git a/src/Editor/Undo/CTranslateNodeCommand.cpp b/src/Editor/Undo/CTranslateNodeCommand.cpp index e0be7eb8..535a1056 100644 --- a/src/Editor/Undo/CTranslateNodeCommand.cpp +++ b/src/Editor/Undo/CTranslateNodeCommand.cpp @@ -9,53 +9,49 @@ CTranslateNodeCommand::CTranslateNodeCommand() { } -CTranslateNodeCommand::CTranslateNodeCommand(INodeEditor *pEditor, const QList& nodes, const CVector3f& delta, ETransformSpace transformSpace) +CTranslateNodeCommand::CTranslateNodeCommand(INodeEditor *pEditor, const QList& rkNodes, const CVector3f& Delta, ETransformSpace TransformSpace) : IUndoCommand("Translate"), mpEditor(pEditor), mCommandEnded(false) { - mNodeList.reserve(nodes.size()); + mNodeList.reserve(rkNodes.size()); - foreach (CSceneNode *pNode, nodes) + foreach (CSceneNode *pNode, rkNodes) { - SNodeTranslate translate; - translate.pNode = pNode; - translate.initialPos = pNode->LocalPosition(); - pNode->Translate(delta, transformSpace); - translate.newPos = pNode->LocalPosition(); - mNodeList.push_back(translate); + SNodeTranslate Translate; + Translate.pNode = pNode; + Translate.InitialPos = pNode->LocalPosition(); + pNode->Translate(Delta, TransformSpace); + Translate.NewPos = pNode->LocalPosition(); + mNodeList.push_back(Translate); } mpEditor->NotifySelectionTransformed(); } -CTranslateNodeCommand::~CTranslateNodeCommand() -{ -} - int CTranslateNodeCommand::id() const { return eTranslateNodeCmd; } -bool CTranslateNodeCommand::mergeWith(const QUndoCommand *other) +bool CTranslateNodeCommand::mergeWith(const QUndoCommand *pkOther) { if (mCommandEnded) return false; - if (other->id() == eTranslateNodeCmd) + if (pkOther->id() == eTranslateNodeCmd) { - const CTranslateNodeCommand *pCmd = static_cast(other); + const CTranslateNodeCommand *pkCmd = static_cast(pkOther); - if (pCmd->mCommandEnded) + if (pkCmd->mCommandEnded) { mCommandEnded = true; return true; } - if ((mpEditor == pCmd->mpEditor) && (mNodeList.size() == pCmd->mNodeList.size())) + if ((mpEditor == pkCmd->mpEditor) && (mNodeList.size() == pkCmd->mNodeList.size())) { for (int iNode = 0; iNode < mNodeList.size(); iNode++) - mNodeList[iNode].newPos = pCmd->mNodeList[iNode].newPos; + mNodeList[iNode].NewPos = pkCmd->mNodeList[iNode].NewPos; return true; } @@ -68,8 +64,8 @@ void CTranslateNodeCommand::undo() { if (!mpEditor) return; - foreach (SNodeTranslate translate, mNodeList) - translate.pNode->SetPosition(translate.initialPos); + foreach (SNodeTranslate Translate, mNodeList) + Translate.pNode->SetPosition(Translate.InitialPos); mpEditor->NotifySelectionTransformed(); mpEditor->UpdateGizmoUI(); @@ -79,8 +75,8 @@ void CTranslateNodeCommand::redo() { if (!mpEditor) return; - foreach (SNodeTranslate translate, mNodeList) - translate.pNode->SetPosition(translate.newPos); + foreach (SNodeTranslate Translate, mNodeList) + Translate.pNode->SetPosition(Translate.NewPos); mpEditor->NotifySelectionTransformed(); mpEditor->UpdateGizmoUI(); diff --git a/src/Editor/Undo/CTranslateNodeCommand.h b/src/Editor/Undo/CTranslateNodeCommand.h index 1cc7c00d..21f5e9c5 100644 --- a/src/Editor/Undo/CTranslateNodeCommand.h +++ b/src/Editor/Undo/CTranslateNodeCommand.h @@ -2,6 +2,7 @@ #define CTRANSLATENODECOMMAND_H #include "IUndoCommand.h" +#include "ObjReferences.h" #include #include "Editor/INodeEditor.h" #include @@ -10,9 +11,9 @@ class CTranslateNodeCommand : public IUndoCommand { struct SNodeTranslate { - CSceneNode *pNode; - CVector3f initialPos; - CVector3f newPos; + CNodePtr pNode; + CVector3f InitialPos; + CVector3f NewPos; }; QList mNodeList; INodeEditor *mpEditor; @@ -20,10 +21,9 @@ class CTranslateNodeCommand : public IUndoCommand public: CTranslateNodeCommand(); - CTranslateNodeCommand(INodeEditor *pEditor, const QList& nodes, const CVector3f& delta, ETransformSpace transformSpace); - ~CTranslateNodeCommand(); + CTranslateNodeCommand(INodeEditor *pEditor, const QList& rkNodes, const CVector3f& rkDelta, ETransformSpace TransformSpace); int id() const; - bool mergeWith(const QUndoCommand *other); + bool mergeWith(const QUndoCommand *pkOther); void undo(); void redo(); bool AffectsCleanState() const { return true; } diff --git a/src/Editor/Undo/ObjReferences.h b/src/Editor/Undo/ObjReferences.h new file mode 100644 index 00000000..b95f6375 --- /dev/null +++ b/src/Editor/Undo/ObjReferences.h @@ -0,0 +1,177 @@ +#ifndef OBJREFERENCES +#define OBJREFERENCES + +#include +#include +#include +#include +#include +#include + +/* + * The basic idea here is that over the course of editing and generally making changes + * in the editor, stuff tends to get created and deleted. When things are deleted they + * are actually deleted from memory, and recreated from scratch on undo. This poses a + * problem for undo actions that need to operate on a specific object because if their + * target object has been deleted and remade then the undo actions are stuck with a + * garbage pointer to deleted data. This generally results in crashes. + * + * These pointer classes solve the problem by encapsulating a reference to the object + * using IDs and indices instead of storing a direct pointer to the object itself. This + * way the correct object is always looked up from the area/scene/etc that it's from and + * the pointer is always valid. They are designed to be as easy and pain-free to use as + * possible. + * + * Most of this stuff could be moved to Core if it turns out to be useful in other places. + * QList dependencies would need to be removed but they could easily be replaced with + * std::list instead. + */ + +#define DEFINE_PTR_LIST_CLASS(ClassName, PtrClassName, DereferencedClassName) \ + class ClassName : public QList \ + { \ + public: \ + ClassName() : QList() {} \ + \ + ClassName(const QList& rkIn) \ + { \ + foreach (DereferencedClassName InObj, rkIn) \ + { \ + *this << InObj; \ + } \ + } \ + \ + QList DereferenceList() const \ + { \ + QList Out; \ + \ + foreach (const PtrClassName& rkPtr, *this) \ + Out << *rkPtr; \ + \ + return Out; \ + } \ + }; + +class CNodePtr +{ + u32 mNodeID; + CScene *mpScene; + bool mValid; + +public: + CNodePtr() { SetNode(nullptr); } + CNodePtr(CSceneNode *pNode) { SetNode(pNode); } + + inline void SetNode(CSceneNode *pNode) + { + mNodeID = pNode ? pNode->ID() : 0; + mpScene = pNode ? pNode->Scene() : nullptr; + mValid = pNode ? true : false; + } + + inline bool Valid() const { return mValid; } + inline u32 NodeID() const { return mNodeID; } + inline CScene* Scene() const { return mpScene; } + inline CSceneNode* operator* () const { return mValid ? mpScene->NodeByID(mNodeID) : nullptr; } + inline CSceneNode* operator->() const { return mValid ? mpScene->NodeByID(mNodeID) : nullptr; } + inline CNodePtr& operator=(CSceneNode *pNode) { SetNode(pNode); return *this; } + + inline bool operator==(const CNodePtr& rkOther) const + { + return (mNodeID == rkOther.mNodeID && mpScene == rkOther.mpScene); + } +}; + +class CInstancePtr +{ + u32 mInstanceID; + CGameArea *mpArea; + bool mValid; + +public: + CInstancePtr() { SetInstance(nullptr); } + CInstancePtr(CScriptObject *pInst) { SetInstance(pInst); } + + inline void SetInstance(CScriptObject *pInst) + { + mInstanceID = pInst ? pInst->InstanceID() : 0; + mpArea = pInst ? pInst->Area() : nullptr; + mValid = pInst ? true : false; + } + + inline u32 InstanceID() const { return mInstanceID; } + inline CGameArea* Area() const { return mpArea; } + inline CScriptObject* operator* () const { return mValid ? mpArea->InstanceByID(mInstanceID) : nullptr; } + inline CScriptObject* operator->() const { return mValid ? mpArea->InstanceByID(mInstanceID) : nullptr; } + inline CInstancePtr& operator=(CScriptObject *pInst) { SetInstance(pInst); return *this; } + + inline bool operator==(const CInstancePtr& rkOther) const + { + return (mInstanceID == rkOther.mInstanceID && mpArea == rkOther.mpArea); + } +}; + +class CPropertyPtr +{ + CInstancePtr mpInstance; + TIDString mPropertyID; + bool mValid; + +public: + CPropertyPtr() { SetProperty(nullptr); } + CPropertyPtr(IProperty *pProp) { SetProperty(pProp); } + + inline void SetProperty(IProperty *pProp) + { + mpInstance = pProp ? pProp->Instance() : nullptr; + mPropertyID = pProp ? pProp->IDString(true) : ""; + mValid = pProp ? true : false; + } + + inline CInstancePtr InstancePtr() const { return mpInstance; } + inline TIDString PropertyID() const { return mPropertyID; } + inline IProperty* operator* () const { return mValid ? mpInstance->PropertyByIDString(mPropertyID) : nullptr; } + inline IProperty* operator->() const { return mValid ? mpInstance->PropertyByIDString(mPropertyID) : nullptr; } + inline CPropertyPtr& operator=(IProperty *pProp) { SetProperty(pProp); return *this; } + + inline bool operator==(const CPropertyPtr& rkOther) const + { + return (mpInstance == rkOther.mpInstance && mPropertyID == rkOther.mPropertyID); + } +}; + +class CLinkPtr +{ + CInstancePtr mpInstance; + u32 mLinkIndex; + bool mValid; + +public: + CLinkPtr() { SetLink(nullptr); } + CLinkPtr(CLink *pLink) { SetLink(pLink); } + + inline void SetLink(CLink *pLink) + { + mpInstance = pLink ? pLink->Sender() : 0; + mLinkIndex = pLink ? pLink->SenderIndex() : 0; + mValid = pLink ? true : false; + } + + inline u32 LinkIndex() const { return mLinkIndex; } + inline CLink* operator* () const { return mValid ? mpInstance->Link(eOutgoing, mLinkIndex) : nullptr; } + inline CLink* operator->() const { return mValid ? mpInstance->Link(eOutgoing, mLinkIndex) : nullptr; } + inline CLinkPtr& operator=(CLink *pLink) { SetLink(pLink); return *this; } + + inline bool operator==(const CLinkPtr& rkOther) const + { + return (mpInstance == rkOther.mpInstance && mLinkIndex == rkOther.mLinkIndex); + } +}; + +DEFINE_PTR_LIST_CLASS(CNodePtrList, CNodePtr, CSceneNode*) +DEFINE_PTR_LIST_CLASS(CInstancePtrList, CInstancePtr, CScriptObject*) +DEFINE_PTR_LIST_CLASS(CPropertyPtrList, CPropertyPtr, IProperty*) +DEFINE_PTR_LIST_CLASS(CLinkPtrList, CLinkPtr, CLink*) + +#endif // OBJREFERENCES + diff --git a/src/Editor/WorldEditor/CInstancesModel.cpp b/src/Editor/WorldEditor/CInstancesModel.cpp index 62c0284e..f858eeb9 100644 --- a/src/Editor/WorldEditor/CInstancesModel.cpp +++ b/src/Editor/WorldEditor/CInstancesModel.cpp @@ -35,7 +35,7 @@ CInstancesModel::CInstancesModel(QObject *pParent) : QAbstractItemModel(pParent) mModelType = eLayers; mShowColumnEnabled = true; mBaseItems << "Script"; - mAddingOrRemovingRows = false; + mChangingLayout = false; } CInstancesModel::~CInstancesModel() @@ -377,15 +377,21 @@ CScriptObject* CInstancesModel::IndexObject(const QModelIndex& index) const // ************ PUBLIC SLOTS ************ void CInstancesModel::NodeAboutToBeCreated() { - if (!mAddingOrRemovingRows) + if (!mChangingLayout) { emit layoutAboutToBeChanged(); - mAddingOrRemovingRows = true; + mChangingLayout = true; } } void CInstancesModel::NodeCreated(CSceneNode *pNode) { + if (mChangingLayout) + { + emit layoutChanged(); + mChangingLayout = false; + } + if (mModelType == eTypes) { if (pNode->NodeType() == eScriptNode) @@ -411,22 +417,13 @@ void CInstancesModel::NodeCreated(CSceneNode *pNode) } } } - - emit layoutChanged(); - mAddingOrRemovingRows = false; } void CInstancesModel::NodeAboutToBeDeleted(CSceneNode *pNode) { - if (!mAddingOrRemovingRows) + if (pNode->NodeType() == eScriptNode) { - emit layoutAboutToBeChanged(); - mAddingOrRemovingRows = true; - } - - if (mModelType == eTypes) - { - if (pNode->NodeType() == eScriptNode) + if (mModelType == eTypes) { CScriptNode *pScript = static_cast(pNode); CScriptObject *pObj = pScript->Object(); @@ -439,14 +436,29 @@ void CInstancesModel::NodeAboutToBeDeleted(CSceneNode *pNode) mTemplateList.removeOne(pObj->Template()); endRemoveRows(); } + + else if (!mChangingLayout) + { + emit layoutAboutToBeChanged(); + mChangingLayout = true; + } + } + + else if (!mChangingLayout) + { + emit layoutAboutToBeChanged(); + mChangingLayout = true; } } } void CInstancesModel::NodeDeleted() { - emit layoutChanged(); - mAddingOrRemovingRows = false; + if (mChangingLayout) + { + emit layoutChanged(); + mChangingLayout = false; + } } void CInstancesModel::PropertyModified(CScriptObject *pInst, IProperty *pProp) diff --git a/src/Editor/WorldEditor/CInstancesModel.h b/src/Editor/WorldEditor/CInstancesModel.h index e17825a0..8aadd4f4 100644 --- a/src/Editor/WorldEditor/CInstancesModel.h +++ b/src/Editor/WorldEditor/CInstancesModel.h @@ -37,7 +37,7 @@ private: QList mTemplateList; QStringList mBaseItems; bool mShowColumnEnabled; - bool mAddingOrRemovingRows; + bool mChangingLayout; public: explicit CInstancesModel(QObject *pParent = 0); diff --git a/src/Editor/WorldEditor/CPoiMapModel.cpp b/src/Editor/WorldEditor/CPoiMapModel.cpp index 3a165462..0709fc4c 100644 --- a/src/Editor/WorldEditor/CPoiMapModel.cpp +++ b/src/Editor/WorldEditor/CPoiMapModel.cpp @@ -25,7 +25,7 @@ CPoiMapModel::CPoiMapModel(CWorldEditor *pEditor, QObject *pParent /*= 0*/) for (u32 iPoi = 0; iPoi < mpPoiToWorld->NumMappedPOIs(); iPoi++) { const CPoiToWorld::SPoiMap *pkMap = mpPoiToWorld->MapByIndex(iPoi); - CScriptNode *pPoiNode = mpEditor->Scene()->ScriptNodeByID(pkMap->PoiID); + CScriptNode *pPoiNode = mpEditor->Scene()->NodeForInstanceID(pkMap->PoiID); if (pPoiNode) { @@ -183,7 +183,7 @@ CScriptNode* CPoiMapModel::PoiNodePointer(const QModelIndex& rkIndex) const if ((u32) rkIndex.row() < mpPoiToWorld->NumMappedPOIs()) { const CPoiToWorld::SPoiMap *pkMap = mpPoiToWorld->MapByIndex(rkIndex.row()); - return mpEditor->Scene()->ScriptNodeByID(pkMap->PoiID); + return mpEditor->Scene()->NodeForInstanceID(pkMap->PoiID); } return nullptr; diff --git a/src/Editor/WorldEditor/WModifyTab.cpp b/src/Editor/WorldEditor/WModifyTab.cpp index 49c7996e..5f3460f1 100644 --- a/src/Editor/WorldEditor/WModifyTab.cpp +++ b/src/Editor/WorldEditor/WModifyTab.cpp @@ -260,7 +260,7 @@ void WModifyTab::OnLinkTableDoubleClick(QModelIndex Index) else if (sender() == ui->OutLinksTableView) InstanceID = pNode->Object()->Link(eOutgoing, Index.row())->ReceiverID(); - CScriptNode *pLinkedNode = pNode->Scene()->ScriptNodeByID(InstanceID); + CScriptNode *pLinkedNode = pNode->Scene()->NodeForInstanceID(InstanceID); if (pLinkedNode) mpWorldEditor->ClearAndSelectNode(pLinkedNode); diff --git a/src/FileIO/CVectorOutStream.cpp b/src/FileIO/CVectorOutStream.cpp index 41bd803d..e1f82c7c 100644 --- a/src/FileIO/CVectorOutStream.cpp +++ b/src/FileIO/CVectorOutStream.cpp @@ -3,6 +3,8 @@ CVectorOutStream::CVectorOutStream() { mDataEndianness = IOUtil::eBigEndian; + mpVector = new std::vector; + mOwnsVector = true; mPos = 0; mUsed = 0; } @@ -10,6 +12,8 @@ CVectorOutStream::CVectorOutStream() CVectorOutStream::CVectorOutStream(IOUtil::EEndianness DataEndianness) { mDataEndianness = DataEndianness; + mpVector = new std::vector; + mOwnsVector = true; mPos = 0; mUsed = 0; } @@ -17,23 +21,34 @@ CVectorOutStream::CVectorOutStream(IOUtil::EEndianness DataEndianness) CVectorOutStream::CVectorOutStream(unsigned long InitialSize, IOUtil::EEndianness DataEndianness) { mDataEndianness = DataEndianness; - mVector.resize(InitialSize); + mpVector = new std::vector(InitialSize); + mOwnsVector = true; + mPos = 0; + mUsed = 0; +} + +CVectorOutStream::CVectorOutStream(std::vector *pVector, IOUtil::EEndianness DataEndianness) +{ + mDataEndianness = DataEndianness; + mpVector = pVector; + mOwnsVector = false; mPos = 0; mUsed = 0; } CVectorOutStream::~CVectorOutStream() { + if (mOwnsVector) delete mpVector; } void CVectorOutStream::WriteBytes(void *pSrc, unsigned long Count) { if (!IsValid()) return; - if ((mPos + Count) > mVector.size()) - mVector.resize(mPos + Count); + if ((mPos + Count) > mpVector->size()) + mpVector->resize(mPos + Count); - memcpy(mVector.data() + mPos, pSrc, Count); + memcpy(mpVector->data() + mPos, pSrc, Count); mPos += Count; if (mPos > mUsed) mUsed = mPos; } @@ -68,8 +83,8 @@ bool CVectorOutStream::Seek(long Offset, long Origin) if (mPos > mUsed) mUsed = mPos; - if (mPos > (signed long) mVector.size()) - mVector.resize(mPos); + if (mPos > (signed long) mpVector->size()) + mpVector->resize(mPos); return true; } @@ -96,27 +111,35 @@ long CVectorOutStream::Size() const long CVectorOutStream::SizeRemaining() const { - return mVector.size() - mPos; + return mpVector->size() - mPos; +} + +void CVectorOutStream::SetVector(std::vector *pVector) +{ + if (mOwnsVector) delete mpVector; + mpVector = pVector; + mPos = 0; + mUsed = 0; } void* CVectorOutStream::Data() { - return mVector.data(); + return mpVector->data(); } void* CVectorOutStream::DataAtPosition() { - return mVector.data() + mPos; + return mpVector->data() + mPos; } void CVectorOutStream::Expand(unsigned long Amount) { - mVector.resize(mVector.size() + Amount); + mpVector->resize(mpVector->size() + Amount); } -void CVectorOutStream::Contract() +void CVectorOutStream::Shrink() { - mVector.resize(mUsed); + mpVector->resize(mUsed); } void CVectorOutStream::Reset() @@ -127,6 +150,6 @@ void CVectorOutStream::Reset() void CVectorOutStream::Clear() { - mVector.clear(); + mpVector->clear(); Reset(); } diff --git a/src/FileIO/CVectorOutStream.h b/src/FileIO/CVectorOutStream.h index 621163c1..bfcaef81 100644 --- a/src/FileIO/CVectorOutStream.h +++ b/src/FileIO/CVectorOutStream.h @@ -6,7 +6,8 @@ class CVectorOutStream : public IOutputStream { - std::vector mVector; + std::vector *mpVector; + bool mOwnsVector; long mPos; long mUsed; @@ -14,6 +15,7 @@ public: CVectorOutStream(); CVectorOutStream(IOUtil::EEndianness DataEndianness); CVectorOutStream(unsigned long InitialSize, IOUtil::EEndianness DataEndianness); + CVectorOutStream(std::vector *pVector, IOUtil::EEndianness DataEndianness); ~CVectorOutStream(); void WriteBytes(void *pSrc, unsigned long Count); @@ -23,10 +25,11 @@ public: bool IsValid() const; long Size() const; long SizeRemaining() const; + void SetVector(std::vector *pVector); void *Data(); void *DataAtPosition(); void Expand(unsigned long Amount); - void Contract(); + void Shrink(); void Reset(); void Clear(); };