Fully implemented delete, added an easy-to-use ID lookup system for undo commands, fixed a bunch of crashes when undoing/redoing after creating/deleting an object

This commit is contained in:
parax0 2016-03-16 19:09:59 -06:00
parent 63812ae4b2
commit c4e05610f3
66 changed files with 992 additions and 569 deletions

View File

@ -158,16 +158,7 @@ CScriptObject* CGameArea::SpawnInstance(CScriptTemplate *pTemplate,
if (InstanceID == -1) if (InstanceID == -1)
{ {
// Determine layer index // Determine layer index
u32 LayerIndex = -1; u32 LayerIndex = pLayer->AreaIndex();
for (u32 iLyr = 0; iLyr < mScriptLayers.size(); iLyr++)
{
if (mScriptLayers[iLyr] == pLayer)
{
LayerIndex = iLyr;
break;
}
}
if (LayerIndex == -1) if (LayerIndex == -1)
{ {
@ -202,8 +193,16 @@ CScriptObject* CGameArea::SpawnInstance(CScriptTemplate *pTemplate,
return pInstance; 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) void CGameArea::DeleteInstance(CScriptObject *pInstance)
{ {
pInstance->BreakAllLinks();
pInstance->Layer()->RemoveInstance(pInstance); pInstance->Layer()->RemoveInstance(pInstance);
pInstance->Template()->RemoveObject(pInstance); pInstance->Template()->RemoveObject(pInstance);
@ -213,6 +212,5 @@ void CGameArea::DeleteInstance(CScriptObject *pInstance)
if (mpPoiToWorldMap && mpPoiToWorldMap->HasPoiMappings(pInstance->InstanceID())) if (mpPoiToWorldMap && mpPoiToWorldMap->HasPoiMappings(pInstance->InstanceID()))
mpPoiToWorldMap->RemovePoi(pInstance->InstanceID()); mpPoiToWorldMap->RemovePoi(pInstance->InstanceID());
pInstance->BreakAllLinks();
delete pInstance; delete pInstance;
} }

View File

@ -74,6 +74,7 @@ public:
const CQuaternion& rkRotation = CQuaternion::skIdentity, const CQuaternion& rkRotation = CQuaternion::skIdentity,
const CVector3f& rkScale = CVector3f::skOne, const CVector3f& rkScale = CVector3f::skOne,
u32 SuggestedID = -1, u32 SuggestedLayerIndex = -1); u32 SuggestedID = -1, u32 SuggestedLayerIndex = -1);
void AddInstanceToArea(CScriptObject *pInstance);
void DeleteInstance(CScriptObject *pInstance); void DeleteInstance(CScriptObject *pInstance);
// Inline Accessors // Inline Accessors

View File

@ -292,3 +292,15 @@ void CScriptCooker::WriteLayer(EGame Game, CScriptLayer *pLayer, IOutputStream&
else else
Cooker.WriteLayerMP2(pLayer); 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);
}

View File

@ -20,6 +20,7 @@ class CScriptCooker
public: public:
static void WriteLayer(EGame Game, CScriptLayer *pLayer, IOutputStream& rOut); static void WriteLayer(EGame Game, CScriptLayer *pLayer, IOutputStream& rOut);
static void CookInstance(EGame Game, CScriptObject *pInstance, IOutputStream& rOut);
}; };
#endif // CSCRIPTCOOKER_H #endif // CSCRIPTCOOKER_H

View File

@ -11,7 +11,7 @@ CScriptLoader::CScriptLoader()
mpObj = nullptr; mpObj = nullptr;
} }
void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY) void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& rSCLY)
{ {
IPropertyTemplate *pTemp = pProp->Template(); IPropertyTemplate *pTemp = pProp->Template();
@ -20,31 +20,31 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY)
case eBoolProperty: { case eBoolProperty: {
TBoolProperty *pBoolCast = static_cast<TBoolProperty*>(pProp); TBoolProperty *pBoolCast = static_cast<TBoolProperty*>(pProp);
pBoolCast->Set( (SCLY.ReadByte() != 0) ); pBoolCast->Set( (rSCLY.ReadByte() != 0) );
break; break;
} }
case eByteProperty: { case eByteProperty: {
TByteProperty *pByteCast = static_cast<TByteProperty*>(pProp); TByteProperty *pByteCast = static_cast<TByteProperty*>(pProp);
pByteCast->Set(SCLY.ReadByte()); pByteCast->Set(rSCLY.ReadByte());
break; break;
} }
case eShortProperty: { case eShortProperty: {
TShortProperty *pShortCast = static_cast<TShortProperty*>(pProp); TShortProperty *pShortCast = static_cast<TShortProperty*>(pProp);
pShortCast->Set(SCLY.ReadShort()); pShortCast->Set(rSCLY.ReadShort());
break; break;
} }
case eLongProperty: { case eLongProperty: {
TLongProperty *pLongCast = static_cast<TLongProperty*>(pProp); TLongProperty *pLongCast = static_cast<TLongProperty*>(pProp);
pLongCast->Set(SCLY.ReadLong()); pLongCast->Set(rSCLY.ReadLong());
break; break;
} }
case eBitfieldProperty: { case eBitfieldProperty: {
TBitfieldProperty *pBitfieldCast = static_cast<TBitfieldProperty*>(pProp); TBitfieldProperty *pBitfieldCast = static_cast<TBitfieldProperty*>(pProp);
pBitfieldCast->Set(SCLY.ReadLong()); pBitfieldCast->Set(rSCLY.ReadLong());
// Validate // Validate
u32 mask = 0; u32 mask = 0;
@ -54,7 +54,7 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY)
u32 check = pBitfieldCast->Get() & ~mask; u32 check = pBitfieldCast->Get() & ~mask;
if (check != 0) 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; break;
} }
@ -62,11 +62,11 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY)
case eEnumProperty: { case eEnumProperty: {
TEnumProperty *pEnumCast = static_cast<TEnumProperty*>(pProp); TEnumProperty *pEnumCast = static_cast<TEnumProperty*>(pProp);
CEnumTemplate *pEnumTemp = static_cast<CEnumTemplate*>(pTemp); CEnumTemplate *pEnumTemp = static_cast<CEnumTemplate*>(pTemp);
u32 ID = SCLY.ReadLong(); u32 ID = rSCLY.ReadLong();
// Validate // Validate
u32 Index = pEnumTemp->EnumeratorIndex(ID); 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); pEnumCast->Set(ID);
break; break;
@ -74,32 +74,32 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY)
case eFloatProperty: { case eFloatProperty: {
TFloatProperty *pFloatCast = static_cast<TFloatProperty*>(pProp); TFloatProperty *pFloatCast = static_cast<TFloatProperty*>(pProp);
pFloatCast->Set(SCLY.ReadFloat()); pFloatCast->Set(rSCLY.ReadFloat());
break; break;
} }
case eStringProperty: { case eStringProperty: {
TStringProperty *pStringCast = static_cast<TStringProperty*>(pProp); TStringProperty *pStringCast = static_cast<TStringProperty*>(pProp);
pStringCast->Set(SCLY.ReadString()); pStringCast->Set(rSCLY.ReadString());
break; break;
} }
case eVector3Property: { case eVector3Property: {
TVector3Property *pVector3Cast = static_cast<TVector3Property*>(pProp); TVector3Property *pVector3Cast = static_cast<TVector3Property*>(pProp);
pVector3Cast->Set(CVector3f(SCLY)); pVector3Cast->Set(CVector3f(rSCLY));
break; break;
} }
case eColorProperty: { case eColorProperty: {
TColorProperty *pColorCast = static_cast<TColorProperty*>(pProp); TColorProperty *pColorCast = static_cast<TColorProperty*>(pProp);
pColorCast->Set(CColor(SCLY)); pColorCast->Set(CColor(rSCLY));
break; break;
} }
case eFileProperty: { case eFileProperty: {
TFileProperty *pFileCast = static_cast<TFileProperty*>(pProp); TFileProperty *pFileCast = static_cast<TFileProperty*>(pProp);
CUniqueID ResID = (mVersion < eCorruptionProto ? SCLY.ReadLong() : SCLY.ReadLongLong()); CUniqueID ResID = (mVersion < eCorruptionProto ? rSCLY.ReadLong() : rSCLY.ReadLongLong());
const TStringList& rkExtensions = static_cast<CFileTemplate*>(pTemp)->Extensions(); const TStringList& rkExtensions = static_cast<CFileTemplate*>(pTemp)->Extensions();
CResourceInfo Info(ResID, CFourCC(!rkExtensions.empty() ? rkExtensions.front() : "UNKN")); 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<CPropertyStruct*>(pProp); CPropertyStruct *pStructCast = static_cast<CPropertyStruct*>(pProp);
if (mVersion < eEchoesDemo) if (mVersion < eEchoesDemo)
LoadStructMP1(SCLY, pStructCast, static_cast<CStructTemplate*>(pStructCast->Template())); LoadStructMP1(rSCLY, pStructCast, static_cast<CStructTemplate*>(pStructCast->Template()));
else else
LoadStructMP2(SCLY, pStructCast, static_cast<CStructTemplate*>(pTemp)); LoadStructMP2(rSCLY, pStructCast, static_cast<CStructTemplate*>(pTemp));
break; break;
} }
case eArrayProperty: { case eArrayProperty: {
CArrayProperty *pArrayCast = static_cast<CArrayProperty*>(pProp); CArrayProperty *pArrayCast = static_cast<CArrayProperty*>(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) if (mVersion < eEchoesDemo)
LoadStructMP1(SCLY, static_cast<CPropertyStruct*>(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate()); LoadStructMP1(rSCLY, static_cast<CPropertyStruct*>(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate());
else else
LoadStructMP2(SCLY, static_cast<CPropertyStruct*>(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate()); LoadStructMP2(rSCLY, static_cast<CPropertyStruct*>(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate());
} }
break; break;
} }
case eCharacterProperty: { case eCharacterProperty: {
TCharacterProperty *pAnimCast = static_cast<TCharacterProperty*>(pProp); TCharacterProperty *pAnimCast = static_cast<TCharacterProperty*>(pProp);
pAnimCast->Set(CAnimationParameters(SCLY, mVersion)); pAnimCast->Set(CAnimationParameters(rSCLY, mpMaster->GetGame()));
break; break;
} }
case eMayaSplineProperty: { case eMayaSplineProperty: {
TMayaSplineProperty *pSplineCast = static_cast<TMayaSplineProperty*>(pProp); TMayaSplineProperty *pSplineCast = static_cast<TMayaSplineProperty*>(pProp);
std::vector<u8> Buffer(Size); std::vector<u8> Buffer(Size);
SCLY.ReadBytes(Buffer.data(), Buffer.size()); rSCLY.ReadBytes(Buffer.data(), Buffer.size());
pSplineCast->Set(Buffer); pSplineCast->Set(Buffer);
break; break;
} }
@ -157,16 +157,16 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& SCLY)
case eUnknownProperty: { case eUnknownProperty: {
TUnknownProperty *pUnknownCast = static_cast<TUnknownProperty*>(pProp); TUnknownProperty *pUnknownCast = static_cast<TUnknownProperty*>(pProp);
std::vector<u8> Buffer(Size); std::vector<u8> Buffer(Size);
SCLY.ReadBytes(Buffer.data(), Buffer.size()); rSCLY.ReadBytes(Buffer.data(), Buffer.size());
pUnknownCast->Set(Buffer); pUnknownCast->Set(Buffer);
break; 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 // Verify property count
u32 PropCount = pTemp->Count(); u32 PropCount = pTemp->Count();
@ -174,7 +174,7 @@ void CScriptLoader::LoadStructMP1(IInputStream& SCLY, CPropertyStruct *pStruct,
if (!pTemp->IsSingleProperty()) if (!pTemp->IsSingleProperty())
{ {
u32 FilePropCount = SCLY.ReadLong(); u32 FilePropCount = rSCLY.ReadLong();
Version = pTemp->VersionForPropertyCount(FilePropCount); Version = pTemp->VersionForPropertyCount(FilePropCount);
if (Version == -1) if (Version == -1)
@ -182,7 +182,7 @@ void CScriptLoader::LoadStructMP1(IInputStream& SCLY, CPropertyStruct *pStruct,
TIDString IDString = pTemp->IDString(true); TIDString IDString = pTemp->IDString(true);
if (!IDString.IsEmpty()) IDString = " (" + IDString + ")"; 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; Version = 0;
} }
} }
@ -194,38 +194,38 @@ void CScriptLoader::LoadStructMP1(IInputStream& SCLY, CPropertyStruct *pStruct,
IProperty *pProp = pStruct->PropertyByIndex(iProp); IProperty *pProp = pStruct->PropertyByIndex(iProp);
if (pPropTemp->CookPreference() != eNeverCook && pPropTemp->IsInVersion(Version)) 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(); u32 ObjStart = rSCLY.Tell();
u8 Type = SCLY.ReadByte(); u8 Type = rSCLY.ReadByte();
u32 Size = SCLY.ReadLong(); u32 Size = rSCLY.ReadLong();
u32 End = SCLY.Tell() + Size; u32 End = rSCLY.Tell() + Size;
CScriptTemplate *pTemp = mpMaster->TemplateByID((u32) Type); CScriptTemplate *pTemp = mpMaster->TemplateByID((u32) Type);
if (!pTemp) if (!pTemp)
{ {
// No valid template for this object; can't load // No valid template for this object; can't load
Log::FileError(SCLY.GetSourceString(), ObjStart, "Unknown object ID encountered: " + TString::HexString(Type)); Log::FileError(rSCLY.GetSourceString(), ObjStart, "Unknown object ID encountered: " + TString::HexString(Type));
SCLY.Seek(End, SEEK_SET); rSCLY.Seek(End, SEEK_SET);
return nullptr; return nullptr;
} }
u32 InstanceID = SCLY.ReadLong(); u32 InstanceID = rSCLY.ReadLong();
mpObj = new CScriptObject(InstanceID, mpArea, mpLayer, pTemp); mpObj = new CScriptObject(InstanceID, mpArea, mpLayer, pTemp);
// Load connections // Load connections
u32 NumLinks = SCLY.ReadLong(); u32 NumLinks = rSCLY.ReadLong();
mpObj->mOutLinks.reserve(NumLinks); mpObj->mOutLinks.reserve(NumLinks);
for (u32 iLink = 0; iLink < NumLinks; iLink++) for (u32 iLink = 0; iLink < NumLinks; iLink++)
{ {
u32 State = SCLY.ReadLong(); u32 State = rSCLY.ReadLong();
u32 Message = SCLY.ReadLong(); u32 Message = rSCLY.ReadLong();
u32 ReceiverID = SCLY.ReadLong(); u32 ReceiverID = rSCLY.ReadLong();
CLink *pLink = new CLink(mpArea, State, Message, mpObj->mInstanceID, ReceiverID); CLink *pLink = new CLink(mpArea, State, Message, mpObj->mInstanceID, ReceiverID);
mpObj->mOutLinks.push_back(pLink); mpObj->mOutLinks.push_back(pLink);
@ -233,54 +233,54 @@ CScriptObject* CScriptLoader::LoadObjectMP1(IInputStream& SCLY)
// Load object... // Load object...
CPropertyStruct *pBase = mpObj->mpProperties; CPropertyStruct *pBase = mpObj->mpProperties;
LoadStructMP1(SCLY, pBase, static_cast<CStructTemplate*>(pBase->Template())); LoadStructMP1(rSCLY, pBase, static_cast<CStructTemplate*>(pBase->Template()));
// Cleanup and return // Cleanup and return
SCLY.Seek(End, SEEK_SET); rSCLY.Seek(End, SEEK_SET);
mpObj->EvaluateProperties(); mpObj->EvaluateProperties();
return mpObj; 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 rSCLY.Seek(0x1, SEEK_CUR); // One unknown byte at the start of each layer
u32 NumObjects = SCLY.ReadLong(); u32 NumObjects = rSCLY.ReadLong();
mpLayer = new CScriptLayer(mpArea); mpLayer = new CScriptLayer(mpArea);
mpLayer->Reserve(NumObjects); mpLayer->Reserve(NumObjects);
for (u32 iObj = 0; iObj < NumObjects; iObj++) for (u32 iObj = 0; iObj < NumObjects; iObj++)
{ {
CScriptObject *pObj = LoadObjectMP1(SCLY); CScriptObject *pObj = LoadObjectMP1(rSCLY);
if (pObj) if (pObj)
mpLayer->AddInstance(pObj); mpLayer->AddInstance(pObj);
} }
// Layer sizes are always a multiple of 32 - skip end padding before returning // Layer sizes are always a multiple of 32 - skip end padding before returning
u32 Remaining = 32 - ((SCLY.Tell() - LayerStart) & 0x1F); u32 Remaining = 32 - ((rSCLY.Tell() - LayerStart) & 0x1F);
SCLY.Seek(Remaining, SEEK_CUR); rSCLY.Seek(Remaining, SEEK_CUR);
return mpLayer; return mpLayer;
} }
void CScriptLoader::LoadStructMP2(IInputStream& SCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp) void CScriptLoader::LoadStructMP2(IInputStream& rSCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp)
{ {
// Verify property count // Verify property count
u32 StructStart = SCLY.Tell(); u32 StructStart = rSCLY.Tell();
StructStart += 0; StructStart += 0;
u32 PropCount = pTemp->Count(); u32 PropCount = pTemp->Count();
if (!pTemp->IsSingleProperty()) if (!pTemp->IsSingleProperty())
PropCount = SCLY.ReadShort(); PropCount = rSCLY.ReadShort();
// Parse properties // Parse properties
for (u32 iProp = 0; iProp < PropCount; iProp++) for (u32 iProp = 0; iProp < PropCount; iProp++)
{ {
IProperty *pProp; IProperty *pProp;
IPropertyTemplate *pPropTemp; IPropertyTemplate *pPropTemp;
u32 PropertyStart = SCLY.Tell(); u32 PropertyStart = rSCLY.Tell();
u32 PropertyID = -1; u32 PropertyID = -1;
u16 PropertyLength = 0; u16 PropertyLength = 0;
u32 NextProperty = 0; u32 NextProperty = 0;
@ -292,79 +292,79 @@ void CScriptLoader::LoadStructMP2(IInputStream& SCLY, CPropertyStruct *pStruct,
} }
else else
{ {
PropertyID = SCLY.ReadLong(); PropertyID = rSCLY.ReadLong();
PropertyLength = SCLY.ReadShort(); PropertyLength = rSCLY.ReadShort();
NextProperty = SCLY.Tell() + PropertyLength; NextProperty = rSCLY.Tell() + PropertyLength;
pProp = pStruct->PropertyByID(PropertyID); pProp = pStruct->PropertyByID(PropertyID);
pPropTemp = pTemp->PropertyByID(PropertyID); pPropTemp = pTemp->PropertyByID(PropertyID);
} }
if (!pPropTemp) 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 else
ReadProperty(pProp, PropertyLength, SCLY); ReadProperty(pProp, PropertyLength, rSCLY);
if (NextProperty > 0) 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 ObjStart = rSCLY.Tell();
u32 ObjectID = SCLY.ReadLong(); u32 ObjectID = rSCLY.ReadLong();
u16 ObjectSize = SCLY.ReadShort(); u16 ObjectSize = rSCLY.ReadShort();
u32 ObjEnd = SCLY.Tell() + ObjectSize; u32 ObjEnd = rSCLY.Tell() + ObjectSize;
CScriptTemplate *pTemplate = mpMaster->TemplateByID(ObjectID); CScriptTemplate *pTemplate = mpMaster->TemplateByID(ObjectID);
if (!pTemplate) if (!pTemplate)
{ {
Log::FileError(SCLY.GetSourceString(), ObjStart, "Unknown object ID encountered: " + CFourCC(ObjectID).ToString()); Log::FileError(rSCLY.GetSourceString(), ObjStart, "Unknown object ID encountered: " + CFourCC(ObjectID).ToString());
SCLY.Seek(ObjEnd, SEEK_SET); rSCLY.Seek(ObjEnd, SEEK_SET);
return nullptr; return nullptr;
} }
u32 InstanceID = SCLY.ReadLong(); u32 InstanceID = rSCLY.ReadLong();
mpObj = new CScriptObject(InstanceID, mpArea, mpLayer, pTemplate); mpObj = new CScriptObject(InstanceID, mpArea, mpLayer, pTemplate);
// Load connections // Load connections
u32 NumConnections = SCLY.ReadShort(); u32 NumConnections = rSCLY.ReadShort();
mpObj->mOutLinks.reserve(NumConnections); mpObj->mOutLinks.reserve(NumConnections);
for (u32 iCon = 0; iCon < NumConnections; iCon++) for (u32 iCon = 0; iCon < NumConnections; iCon++)
{ {
u32 State = SCLY.ReadLong(); u32 State = rSCLY.ReadLong();
u32 Message = SCLY.ReadLong(); u32 Message = rSCLY.ReadLong();
u32 ReceiverID = SCLY.ReadLong(); u32 ReceiverID = rSCLY.ReadLong();
CLink *pLink = new CLink(mpArea, State, Message, mpObj->mInstanceID, ReceiverID); CLink *pLink = new CLink(mpArea, State, Message, mpObj->mInstanceID, ReceiverID);
mpObj->mOutLinks.push_back(pLink); mpObj->mOutLinks.push_back(pLink);
} }
// Load object // Load object
SCLY.Seek(0x6, SEEK_CUR); // Skip base struct ID + size rSCLY.Seek(0x6, SEEK_CUR); // Skip base struct ID + size
LoadStructMP2(SCLY, mpObj->mpProperties, mpObj->mpTemplate->BaseStruct()); LoadStructMP2(rSCLY, mpObj->mpProperties, mpObj->mpTemplate->BaseStruct());
// Cleanup and return // Cleanup and return
SCLY.Seek(ObjEnd, SEEK_SET); rSCLY.Seek(ObjEnd, SEEK_SET);
mpObj->EvaluateProperties(); mpObj->EvaluateProperties();
return mpObj; return mpObj;
} }
CScriptLayer* CScriptLoader::LoadLayerMP2(IInputStream& SCLY) CScriptLayer* CScriptLoader::LoadLayerMP2(IInputStream& rSCLY)
{ {
SCLY.Seek(0x1, SEEK_CUR); // Skipping version. todo: verify this? rSCLY.Seek(0x1, SEEK_CUR); // Skipping version. todo: verify this?
u32 NumObjects = SCLY.ReadLong(); u32 NumObjects = rSCLY.ReadLong();
mpLayer = new CScriptLayer(mpArea); mpLayer = new CScriptLayer(mpArea);
mpLayer->Reserve(NumObjects); mpLayer->Reserve(NumObjects);
for (u32 iObj = 0; iObj < NumObjects; iObj++) for (u32 iObj = 0; iObj < NumObjects; iObj++)
{ {
CScriptObject *pObj = LoadObjectMP2(SCLY); CScriptObject *pObj = LoadObjectMP2(rSCLY);
if (pObj) if (pObj)
mpLayer->AddInstance(pObj); mpLayer->AddInstance(pObj);
} }
@ -396,3 +396,28 @@ CScriptLayer* CScriptLoader::LoadLayer(IInputStream& rSCLY, CGameArea *pArea, EG
else else
return Loader.LoadLayerMP2(rSCLY); 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);
}

View File

@ -16,18 +16,19 @@ class CScriptLoader
CMasterTemplate *mpMaster; CMasterTemplate *mpMaster;
CScriptLoader(); 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); void LoadStructMP1(IInputStream& rSCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp);
CScriptObject* LoadObjectMP1(IInputStream& SCLY); CScriptObject* LoadObjectMP1(IInputStream& rSCLY);
CScriptLayer* LoadLayerMP1(IInputStream& SCLY); CScriptLayer* LoadLayerMP1(IInputStream& rSCLY);
void LoadStructMP2(IInputStream& SCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp); void LoadStructMP2(IInputStream& rSCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp);
CScriptObject* LoadObjectMP2(IInputStream& SCLY); CScriptObject* LoadObjectMP2(IInputStream& rSCLY);
CScriptLayer* LoadLayerMP2(IInputStream& SCLY); CScriptLayer* LoadLayerMP2(IInputStream& rSCLY);
public: 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 #endif // CSCRIPTLOADER_H

View File

@ -15,7 +15,7 @@ CScriptObject::CScriptObject(u32 InstanceID, CGameArea *pArea, CScriptLayer *pLa
, mIsCheckingNearVisibleActivation(false) , mIsCheckingNearVisibleActivation(false)
{ {
mpTemplate->AddObject(this); mpTemplate->AddObject(this);
mpProperties = (CPropertyStruct*) pTemplate->BaseStruct()->InstantiateProperty(nullptr); mpProperties = (CPropertyStruct*) pTemplate->BaseStruct()->InstantiateProperty(this, nullptr);
} }
CScriptObject::~CScriptObject() CScriptObject::~CScriptObject()
@ -80,14 +80,16 @@ void CScriptObject::SetLayer(CScriptLayer *pLayer, u32 NewLayerIndex)
{ {
if (pLayer != mpLayer) if (pLayer != mpLayer)
{ {
mpLayer->RemoveInstance(this); if (mpLayer) mpLayer->RemoveInstance(this);
mpLayer = pLayer; mpLayer = pLayer;
mpLayer->AddInstance(this, NewLayerIndex); if (mpLayer) mpLayer->AddInstance(this, NewLayerIndex);
} }
} }
u32 CScriptObject::LayerIndex() const u32 CScriptObject::LayerIndex() const
{ {
if (!mpLayer) return -1;
for (u32 iInst = 0; iInst < mpLayer->NumInstances(); iInst++) for (u32 iInst = 0; iInst < mpLayer->NumInstances(); iInst++)
{ {
if (mpLayer->InstanceByIndex(iInst) == this) if (mpLayer->InstanceByIndex(iInst) == this)

View File

@ -32,13 +32,44 @@ TString IProperty::Name() const
u32 IProperty::ID() 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 TIDString IProperty::IDString(bool FullPath) const
{ {
// todo: since this function just returns the template ID string, it doesn't correctly account for array properties; TIDString Out;
return mpTemplate->IDString(FullPath);
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<CArrayProperty>(mpParent);
if (pArray)
{
for (u32 iSub = 0; iSub < pArray->Count(); iSub++)
{
if (pArray->PropertyByIndex(iSub) == this)
return iSub;
}
}
return -1;
} }
bool IProperty::ShouldCook() bool IProperty::ShouldCook()
@ -74,7 +105,7 @@ void CPropertyStruct::Copy(const IProperty *pkProp)
mProperties.resize(pkSource->mProperties.size()); mProperties.resize(pkSource->mProperties.size());
for (u32 iSub = 0; iSub < mProperties.size(); iSub++) 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() bool CPropertyStruct::ShouldCook()
@ -138,7 +169,7 @@ CPropertyStruct* CPropertyStruct::StructByIndex(u32 index) const
{ {
IProperty *pProp = PropertyByIndex(index); IProperty *pProp = PropertyByIndex(index);
if (pProp->Type() == eStructProperty) if (pProp->Type() == eStructProperty || pProp->Type() == eArrayProperty)
return static_cast<CPropertyStruct*>(pProp); return static_cast<CPropertyStruct*>(pProp);
else else
return nullptr; return nullptr;
@ -148,7 +179,7 @@ CPropertyStruct* CPropertyStruct::StructByID(u32 ID) const
{ {
IProperty *pProp = PropertyByID(ID); IProperty *pProp = PropertyByID(ID);
if (pProp->Type() == eStructProperty) if (pProp->Type() == eStructProperty || pProp->Type() == eArrayProperty)
return static_cast<CPropertyStruct*>(pProp); return static_cast<CPropertyStruct*>(pProp);
else else
return nullptr; return nullptr;
@ -158,7 +189,7 @@ CPropertyStruct* CPropertyStruct::StructByIDString(const TIDString& rkStr) const
{ {
IProperty *pProp = PropertyByIDString(rkStr); IProperty *pProp = PropertyByIDString(rkStr);
if (pProp->Type() == eStructProperty) if (pProp->Type() == eStructProperty || pProp->Type() == eArrayProperty)
return static_cast<CPropertyStruct*>(pProp); return static_cast<CPropertyStruct*>(pProp);
else else
return nullptr; return nullptr;
@ -186,7 +217,7 @@ void CArrayProperty::Resize(int Size)
if (Size > OldSize) if (Size > OldSize)
{ {
for (int iProp = OldSize; iProp < Size; iProp++) for (int iProp = OldSize; iProp < Size; iProp++)
mProperties[iProp] = static_cast<CArrayTemplate*>(mpTemplate)->CreateSubStruct(this); mProperties[iProp] = static_cast<CArrayTemplate*>(mpTemplate)->CreateSubStruct(Instance(), this);
} }
} }

View File

@ -13,6 +13,7 @@
#include <Math/CVector3f.h> #include <Math/CVector3f.h>
#include <list> #include <list>
class CScriptObject;
class CScriptTemplate; class CScriptTemplate;
class CStructTemplate; class CStructTemplate;
class IPropertyTemplate; class IPropertyTemplate;
@ -28,11 +29,13 @@ class IProperty
protected: protected:
class CPropertyStruct *mpParent; class CPropertyStruct *mpParent;
CScriptObject *mpInstance;
IPropertyTemplate *mpTemplate; IPropertyTemplate *mpTemplate;
public: public:
IProperty(IPropertyTemplate *pTemp, CPropertyStruct *pParent) IProperty(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent)
: mpParent(pParent) : mpParent(pParent)
, mpInstance(pInstance)
, mpTemplate(pTemp) , mpTemplate(pTemp)
{ {
} }
@ -42,12 +45,13 @@ public:
virtual TString ToString() const { return ""; } virtual TString ToString() const { return ""; }
virtual IPropertyValue* RawValue() { return nullptr; } virtual IPropertyValue* RawValue() { return nullptr; }
virtual void Copy(const IProperty *pkProp) = 0; 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 Matches(const IProperty *pkProp) const = 0;
virtual bool ShouldCook(); // Can't be const because it calls MatchesDefault() virtual bool ShouldCook(); // Can't be const because it calls MatchesDefault()
virtual bool MatchesDefault(); // Can't be const because RawValue() isn't const 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 CPropertyStruct* Parent() const { return mpParent; }
inline void SetParent(CPropertyStruct *pParent) { mpParent = pParent; } inline void SetParent(CPropertyStruct *pParent) { mpParent = pParent; }
@ -59,6 +63,7 @@ public:
TString Name() const; TString Name() const;
u32 ID() const; u32 ID() const;
TIDString IDString(bool FullPath) const; TIDString IDString(bool FullPath) const;
u32 ArrayIndex() const;
}; };
/* /*
@ -70,11 +75,11 @@ class TTypedProperty : public IProperty
friend class CScriptLoader; friend class CScriptLoader;
ValueClass mValue; ValueClass mValue;
public: public:
TTypedProperty(IPropertyTemplate *pTemp, CPropertyStruct *pParent) TTypedProperty(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent)
: IProperty(pTemp, pParent) {} : IProperty(pTemp, pInstance, pParent) {}
TTypedProperty(IPropertyTemplate *pTemp, CPropertyStruct *pParent, ValueType v) TTypedProperty(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent, ValueType v)
: IProperty(pTemp, pParent), mValue(v) {} : IProperty(pTemp, pInstance, pParent), mValue(v) {}
~TTypedProperty() {} ~TTypedProperty() {}
virtual EPropertyType Type() const { return TypeEnum; } virtual EPropertyType Type() const { return TypeEnum; }
@ -89,11 +94,11 @@ public:
mValue.Set(pkCast->mValue.Get()); mValue.Set(pkCast->mValue.Get());
} }
virtual TTypedProperty* Clone(CPropertyStruct *pParent) const virtual TTypedProperty* Clone(class CScriptObject *pInstance, CPropertyStruct *pParent) const
{ {
if (!pParent) pParent = mpParent; if (!pParent) pParent = mpParent;
TTypedProperty *pOut = new TTypedProperty(mpTemplate, pParent); TTypedProperty *pOut = new TTypedProperty(mpTemplate, pInstance, pParent);
pOut->Copy(this); pOut->Copy(this);
return pOut; return pOut;
} }
@ -123,11 +128,11 @@ typedef TTypedProperty<std::vector<u8>, eUnknownProperty, CUnknownValue>
* TStringProperty, TFileProperty, and TCharacterProperty get little subclasses in order to override some virtual functions. * TStringProperty, TFileProperty, and TCharacterProperty get little subclasses in order to override some virtual functions.
*/ */
#define IMPLEMENT_PROPERTY_CTORS(ClassName, ValueType) \ #define IMPLEMENT_PROPERTY_CTORS(ClassName, ValueType) \
ClassName(IPropertyTemplate *pTemp, CPropertyStruct *pParent) \ ClassName(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent) \
: TTypedProperty(pTemp, pParent) {} \ : TTypedProperty(pTemp, pInstance, pParent) {} \
\ \
ClassName(IPropertyTemplate *pTemp, CPropertyStruct *pParent, ValueType v) \ ClassName(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent, ValueType v) \
: TTypedProperty(pTemp, pParent, v) {} : TTypedProperty(pTemp, pInstance, pParent, v) {}
class TStringProperty : public TTypedProperty<TString, eStringProperty, CStringValue> class TStringProperty : public TTypedProperty<TString, eStringProperty, CStringValue>
{ {
@ -169,8 +174,8 @@ class CPropertyStruct : public IProperty
protected: protected:
std::vector<IProperty*> mProperties; std::vector<IProperty*> mProperties;
public: public:
CPropertyStruct(IPropertyTemplate *pTemp, CPropertyStruct *pParent) CPropertyStruct(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent)
: IProperty(pTemp, pParent) {} : IProperty(pTemp, pInstance, pParent) {}
~CPropertyStruct() ~CPropertyStruct()
{ {
@ -183,10 +188,10 @@ public:
virtual void Copy(const IProperty *pkProp); virtual void Copy(const IProperty *pkProp);
virtual IProperty* Clone(CPropertyStruct *pParent) const virtual IProperty* Clone(CScriptObject *pInstance, CPropertyStruct *pParent) const
{ {
if (!pParent) pParent = mpParent; if (!pParent) pParent = mpParent;
CPropertyStruct *pOut = new CPropertyStruct(mpTemplate, pParent); CPropertyStruct *pOut = new CPropertyStruct(mpTemplate, pInstance, pParent);
pOut->Copy(this); pOut->Copy(this);
return pOut; return pOut;
} }
@ -245,16 +250,16 @@ class CArrayProperty : public CPropertyStruct
friend class CScriptLoader; friend class CScriptLoader;
public: public:
CArrayProperty(IPropertyTemplate *pTemp, CPropertyStruct *pParent) CArrayProperty(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent)
: CPropertyStruct(pTemp, pParent) {} : CPropertyStruct(pTemp, pInstance, pParent) {}
EPropertyType Type() const { return eArrayProperty; } EPropertyType Type() const { return eArrayProperty; }
static inline EPropertyType StaticType() { 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; if (!pParent) pParent = mpParent;
CArrayProperty *pOut = new CArrayProperty(mpTemplate, pParent); CArrayProperty *pOut = new CArrayProperty(mpTemplate, pInstance, pParent);
pOut->Copy(this); pOut->Copy(this);
return pOut; return pOut;
} }

View File

@ -64,7 +64,7 @@ public:
virtual EPropertyType Type() const = 0; virtual EPropertyType Type() const = 0;
virtual bool CanHaveDefault() const = 0; virtual bool CanHaveDefault() const = 0;
virtual bool IsNumerical() 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 IPropertyTemplate* Clone(CScriptTemplate *pScript, CStructTemplate *pParent = 0) const = 0;
virtual void Copy(const IPropertyTemplate *pkTemp) virtual void Copy(const IPropertyTemplate *pkTemp)
@ -164,10 +164,10 @@ public:
virtual bool CanHaveDefault() const { return CanHaveDefaultValue; } virtual bool CanHaveDefault() const { return CanHaveDefaultValue; }
virtual bool IsNumerical() const { return false; } virtual bool IsNumerical() const { return false; }
virtual IProperty* InstantiateProperty(CPropertyStruct *pParent) virtual IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent)
{ {
typedef TTypedProperty<PropType, PropTypeEnum, ValueClass> TPropertyType; typedef TTypedProperty<PropType, PropTypeEnum, ValueClass> TPropertyType;
TPropertyType *pOut = new TPropertyType(this, pParent, GetDefaultValue()); TPropertyType *pOut = new TPropertyType(this, pInstance, pParent, GetDefaultValue());
return pOut; return pOut;
} }
@ -321,9 +321,9 @@ public:
TCharacterTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0) TCharacterTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
: TTypedPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent) {} : 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) TStringTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
: TTypedPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent) {} : 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) TMayaSplineTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
: TTypedPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent) {} : 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 CanHaveDefault() const { return false; }
virtual bool IsNumerical() 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) IMPLEMENT_TEMPLATE_CLONE(CFileTemplate)
@ -451,9 +451,9 @@ public:
virtual bool CanHaveDefault() const { return true; } virtual bool CanHaveDefault() const { return true; }
virtual bool IsNumerical() const { return false; } 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()); pEnum->Set(GetDefaultValue());
return pEnum; return pEnum;
} }
@ -546,9 +546,9 @@ public:
virtual bool CanHaveDefault() const { return true; } virtual bool CanHaveDefault() const { return true; }
virtual bool IsNumerical() const { return false; } 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()); pBitfield->Set(GetDefaultValue());
return pBitfield; return pBitfield;
} }
@ -611,13 +611,13 @@ public:
bool CanHaveDefault() const { return false; } bool CanHaveDefault() const { return false; }
bool IsNumerical() 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++) for (u32 iSub = 0; iSub < mSubProperties.size(); iSub++)
{ {
IProperty *pSubProp = mSubProperties[iSub]->InstantiateProperty(pStruct); IProperty *pSubProp = mSubProperties[iSub]->InstantiateProperty(pInstance, pStruct);
pStruct->AddSubProperty(pSubProp); pStruct->AddSubProperty(pSubProp);
} }
@ -708,9 +708,9 @@ public:
EPropertyType Type() const { return eArrayProperty; } 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) IMPLEMENT_TEMPLATE_CLONE(CArrayTemplate)
@ -740,9 +740,9 @@ public:
TString ElementName() const { return mElementName; } TString ElementName() const { return mElementName; }
void SetElementName(const TString& rkName) { mElementName = rkName; } 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);
} }
}; };

View File

@ -3,8 +3,8 @@
#include "Core/Render/CGraphics.h" #include "Core/Render/CGraphics.h"
#include "Core/Render/CRenderer.h" #include "Core/Render/CRenderer.h"
CCollisionNode::CCollisionNode(CScene *pScene, CSceneNode *pParent, CCollisionMeshGroup *pCollision) CCollisionNode::CCollisionNode(CScene *pScene, u32 NodeID, CSceneNode *pParent, CCollisionMeshGroup *pCollision)
: CSceneNode(pScene, pParent) : CSceneNode(pScene, NodeID, pParent)
{ {
SetCollision(pCollision); SetCollision(pCollision);
SetName("Collision"); SetName("Collision");

View File

@ -9,7 +9,7 @@ class CCollisionNode : public CSceneNode
TResPtr<CCollisionMeshGroup> mpCollision; TResPtr<CCollisionMeshGroup> mpCollision;
public: public:
CCollisionNode(CScene *pScene, CSceneNode *pParent = 0, CCollisionMeshGroup *pCollision = 0); CCollisionNode(CScene *pScene, u32 NodeID, CSceneNode *pParent = 0, CCollisionMeshGroup *pCollision = 0);
ENodeType NodeType(); ENodeType NodeType();
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo); void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);
void Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& ViewInfo); void Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& ViewInfo);

View File

@ -4,8 +4,8 @@
#include "Core/Render/CRenderer.h" #include "Core/Render/CRenderer.h"
#include <Math/MathUtil.h> #include <Math/MathUtil.h>
CLightNode::CLightNode(CScene *pScene, CSceneNode *pParent, CLight *Light) CLightNode::CLightNode(CScene *pScene, u32 NodeID, CSceneNode *pParent, CLight *Light)
: CSceneNode(pScene, pParent) : CSceneNode(pScene, NodeID, pParent)
{ {
mpLight = Light; mpLight = Light;
mLocalAABox = CAABox::skOne; mLocalAABox = CAABox::skOne;

View File

@ -8,7 +8,7 @@ class CLightNode : public CSceneNode
{ {
CLight *mpLight; CLight *mpLight;
public: public:
CLightNode(CScene *pScene, CSceneNode *pParent = 0, CLight *Light = 0); CLightNode(CScene *pScene, u32 NodeID, CSceneNode *pParent = 0, CLight *Light = 0);
ENodeType NodeType(); ENodeType NodeType();
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo); void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);
void Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& ViewInfo); void Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& ViewInfo);

View File

@ -4,7 +4,8 @@
#include "Core/Render/CGraphics.h" #include "Core/Render/CGraphics.h"
#include <Math/MathUtil.h> #include <Math/MathUtil.h>
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); SetModel(pModel);
mScale = CVector3f(1.f); mScale = CVector3f(1.f);

View File

@ -15,7 +15,7 @@ class CModelNode : public CSceneNode
CColor mScanOverlayColor; CColor mScanOverlayColor;
public: 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 ENodeType NodeType();
virtual void PostLoad(); virtual void PostLoad();

View File

@ -8,7 +8,8 @@
class CRootNode : public CSceneNode class CRootNode : public CSceneNode
{ {
public: 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() {} ~CRootNode() {}
ENodeType NodeType() { ENodeType NodeType() {

View File

@ -17,7 +17,7 @@ CScene::CScene()
: mSplitTerrain(true) : mSplitTerrain(true)
, mRanPostLoad(false) , mRanPostLoad(false)
, mNumNodes(0) , mNumNodes(0)
, mpSceneRootNode(new CRootNode(this, nullptr)) , mpSceneRootNode(new CRootNode(this, -1, nullptr))
, mpArea(nullptr) , mpArea(nullptr)
, mpWorld(nullptr) , mpWorld(nullptr)
, mpAreaRootNode(nullptr) , mpAreaRootNode(nullptr)
@ -29,43 +29,76 @@ CScene::~CScene()
ClearScene(); 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; 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); mNodes[eModelNode].push_back(pNode);
mNodeMap[ID] = pNode;
mNumNodes++; mNumNodes++;
return pNode; return pNode;
} }
CStaticNode* CScene::CreateStaticNode(CStaticModel *pModel) CStaticNode* CScene::CreateStaticNode(CStaticModel *pModel, u32 NodeID /*= -1*/)
{ {
if (pModel == nullptr) return nullptr; 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); mNodes[eStaticNode].push_back(pNode);
mNodeMap[ID] = pNode;
mNumNodes++; mNumNodes++;
return pNode; return pNode;
} }
CCollisionNode* CScene::CreateCollisionNode(CCollisionMeshGroup *pMesh) CCollisionNode* CScene::CreateCollisionNode(CCollisionMeshGroup *pMesh, u32 NodeID /*= -1*/)
{ {
if (pMesh == nullptr) return nullptr; 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); mNodes[eCollisionNode].push_back(pNode);
mNodeMap[ID] = pNode;
mNumNodes++; mNumNodes++;
return pNode; return pNode;
} }
CScriptNode* CScene::CreateScriptNode(CScriptObject *pObj) CScriptNode* CScene::CreateScriptNode(CScriptObject *pObj, u32 NodeID /*= -1*/)
{ {
if (pObj == nullptr) return nullptr; 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); mNodes[eScriptNode].push_back(pNode);
mScriptNodeMap[pObj->InstanceID()] = pNode; mNodeMap[ID] = pNode;
mScriptMap[InstanceID] = pNode;
pNode->BuildLightList(mpArea); pNode->BuildLightList(mpArea);
// AreaAttributes check // AreaAttributes check
@ -81,12 +114,14 @@ CScriptNode* CScene::CreateScriptNode(CScriptObject *pObj)
return pNode; return pNode;
} }
CLightNode* CScene::CreateLightNode(CLight *pLight) CLightNode* CScene::CreateLightNode(CLight *pLight, u32 NodeID /*= -1*/)
{ {
if (pLight == nullptr) return nullptr; 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); mNodes[eLightNode].push_back(pNode);
mNodeMap[ID] = pNode;
mNumNodes++; mNumNodes++;
return pNode; 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) if (Type == eScriptNode)
{ {
CScriptNode *pScript = static_cast<CScriptNode*>(pNode); CScriptNode *pScript = static_cast<CScriptNode*>(pNode);
auto ScriptMapIt = mScriptNodeMap.find(pScript->Object()->InstanceID()); auto it = mScriptMap.find(pScript->Object()->InstanceID());
if (ScriptMapIt != mScriptNodeMap.end()) if (it != mScriptMap.end())
mScriptNodeMap.erase(ScriptMapIt); mScriptMap.erase(it);
switch (pScript->Object()->ObjectTypeID()) switch (pScript->Object()->ObjectTypeID())
{ {
@ -140,7 +179,7 @@ void CScene::SetActiveArea(CGameArea *pArea)
// Create nodes for new area // Create nodes for new area
mpArea = pArea; mpArea = pArea;
mpAreaRootNode = new CRootNode(this, mpSceneRootNode); mpAreaRootNode = new CRootNode(this, -1, mpSceneRootNode);
// Create static nodes // Create static nodes
u32 Count = mpArea->GetStaticModelCount(); u32 Count = mpArea->GetStaticModelCount();
@ -190,10 +229,11 @@ void CScene::SetActiveArea(CGameArea *pArea)
} }
// Ensure script nodes have valid positions + build light lists // 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(); CScriptNode *pScript = static_cast<CScriptNode*>(*It);
it->second->BuildLightList(mpArea); pScript->GeneratePosition();
pScript->BuildLightList(mpArea);
} }
u32 NumLightLayers = mpArea->GetLightLayerCount(); u32 NumLightLayers = mpArea->GetLightLayerCount();
@ -239,7 +279,7 @@ void CScene::ClearScene()
mNodes.clear(); mNodes.clear();
mAreaAttributesObjects.clear(); mAreaAttributesObjects.clear();
mScriptNodeMap.clear(); mNodeMap.clear();
mNumNodes = 0; mNumNodes = 0;
mpArea = nullptr; mpArea = nullptr;
@ -277,17 +317,25 @@ SRayIntersection CScene::SceneRayCast(const CRay& Ray, const SViewInfo& ViewInfo
return Tester.TestNodes(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; else return nullptr;
} }
CScriptNode* CScene::NodeForObject(CScriptObject *pObj) CScriptNode* CScene::NodeForObject(CScriptObject *pObj)
{ {
return ScriptNodeByID(pObj->InstanceID()); return NodeForInstanceID(pObj->InstanceID());
} }
CLightNode* CScene::NodeForLight(CLight *pLight) CLightNode* CScene::NodeForLight(CLight *pLight)

View File

@ -38,19 +38,23 @@ class CScene
// Environment // Environment
std::vector<CAreaAttributes> mAreaAttributesObjects; std::vector<CAreaAttributes> mAreaAttributesObjects;
// Objects // Node Management
std::unordered_map<u32, CScriptNode*> mScriptNodeMap; std::unordered_map<u32, CSceneNode*> mNodeMap;
std::unordered_map<u32, CScriptNode*> mScriptMap;
public: public:
CScene(); CScene();
~CScene(); ~CScene();
// Scene Management // Scene Management
CModelNode* CreateModelNode(CModel *pModel); bool IsNodeIDUsed(u32 ID) const;
CStaticNode* CreateStaticNode(CStaticModel *pModel); u32 CreateNodeID(u32 SuggestedID = -1) const;
CCollisionNode* CreateCollisionNode(CCollisionMeshGroup *pMesh);
CScriptNode* CreateScriptNode(CScriptObject *pObj); CModelNode* CreateModelNode(CModel *pModel, u32 NodeID = -1);
CLightNode* CreateLightNode(CLight *pLight); 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 DeleteNode(CSceneNode *pNode);
void SetActiveArea(CGameArea *pArea); void SetActiveArea(CGameArea *pArea);
void SetActiveWorld(CWorld *pWorld); void SetActiveWorld(CWorld *pWorld);
@ -58,7 +62,8 @@ public:
void ClearScene(); void ClearScene();
void AddSceneToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo); void AddSceneToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo);
SRayIntersection SceneRayCast(const CRay& rkRay, 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); CScriptNode* NodeForObject(CScriptObject *pObj);
CLightNode* NodeForLight(CLight *pLight); CLightNode* NodeForLight(CLight *pLight);

View File

@ -12,11 +12,12 @@
u32 CSceneNode::smNumNodes = 0; u32 CSceneNode::smNumNodes = 0;
CColor CSceneNode::skSelectionTint = CColor::Integral(39, 154, 167); CColor CSceneNode::skSelectionTint = CColor::Integral(39, 154, 167);
CSceneNode::CSceneNode(CScene *pScene, CSceneNode *pParent) CSceneNode::CSceneNode(CScene *pScene, u32 NodeID, CSceneNode *pParent)
{ {
smNumNodes++; smNumNodes++;
mpScene = pScene; mpScene = pScene;
mpParent = pParent; mpParent = pParent;
_mID = NodeID;
mPosition = CVector3f::skZero; mPosition = CVector3f::skZero;
mRotation = CQuaternion::skIdentity; mRotation = CQuaternion::skIdentity;
@ -341,6 +342,11 @@ CScene* CSceneNode::Scene() const
return mpScene; return mpScene;
} }
u32 CSceneNode::ID() const
{
return _mID;
}
CVector3f CSceneNode::LocalPosition() const CVector3f CSceneNode::LocalPosition() const
{ {
return mPosition; return mPosition;

View File

@ -29,6 +29,8 @@ private:
bool _mInheritsRotation; bool _mInheritsRotation;
bool _mInheritsScale; bool _mInheritsScale;
u32 _mID;
protected: protected:
static u32 smNumNodes; static u32 smNumNodes;
TString mName; TString mName;
@ -51,7 +53,7 @@ protected:
CColor mAmbientColor; CColor mAmbientColor;
public: public:
explicit CSceneNode(CScene *pScene, CSceneNode *pParent = 0); explicit CSceneNode(CScene *pScene, u32 NodeID, CSceneNode *pParent = 0);
virtual ~CSceneNode(); virtual ~CSceneNode();
virtual ENodeType NodeType() = 0; virtual ENodeType NodeType() = 0;
virtual void PostLoad() {} virtual void PostLoad() {}
@ -94,6 +96,7 @@ public:
TString Name() const; TString Name() const;
CSceneNode* Parent() const; CSceneNode* Parent() const;
CScene* Scene() const; CScene* Scene() const;
u32 ID() const;
CVector3f LocalPosition() const; CVector3f LocalPosition() const;
CVector3f AbsolutePosition() const; CVector3f AbsolutePosition() const;
CQuaternion LocalRotation() const; CQuaternion LocalRotation() const;

View File

@ -10,8 +10,8 @@
#include <Common/AnimUtil.h> #include <Common/AnimUtil.h>
#include <Math/MathUtil.h> #include <Math/MathUtil.h>
CScriptNode::CScriptNode(CScene *pScene, CSceneNode *pParent, CScriptObject *pObject) CScriptNode::CScriptNode(CScene *pScene, u32 NodeID, CSceneNode *pParent, CScriptObject *pObject)
: CSceneNode(pScene, pParent) : CSceneNode(pScene, NodeID, pParent)
, mGameModeVisibility(eUntested) , mGameModeVisibility(eUntested)
{ {
mpVolumePreviewNode = nullptr; mpVolumePreviewNode = nullptr;
@ -21,7 +21,7 @@ CScriptNode::CScriptNode(CScene *pScene, CSceneNode *pParent, CScriptObject *pOb
mpInstance = pObject; mpInstance = pObject;
SetActiveModel(nullptr); SetActiveModel(nullptr);
mpBillboard = nullptr; mpBillboard = nullptr;
mpCollisionNode = new CCollisionNode(pScene, this); mpCollisionNode = new CCollisionNode(pScene, -1, this);
mpCollisionNode->SetInheritance(true, true, false); mpCollisionNode->SetInheritance(true, true, false);
if (mpInstance) if (mpInstance)
@ -43,7 +43,7 @@ CScriptNode::CScriptNode(CScene *pScene, CSceneNode *pParent, CScriptObject *pOb
mpCollisionNode->SetCollision(mpInstance->GetCollision()); mpCollisionNode->SetCollision(mpInstance->GetCollision());
// Create preview volume node // Create preview volume node
mpVolumePreviewNode = new CModelNode(pScene, this, nullptr); mpVolumePreviewNode = new CModelNode(pScene, -1, this, nullptr);
if (pTemp->ScaleType() == CScriptTemplate::eScaleVolume) if (pTemp->ScaleType() == CScriptTemplate::eScaleVolume)
{ {
@ -259,14 +259,14 @@ void CScriptNode::DrawSelection()
{ {
// Don't draw in links if the other object is selected. // Don't draw in links if the other object is selected.
CLink *pLink = mpInstance->Link(eIncoming, iIn); 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); if (pLinkNode && !pLinkNode->IsSelected()) CDrawUtil::DrawLine(CenterPoint(), pLinkNode->CenterPoint(), CColor::skTransparentRed);
} }
for (u32 iOut = 0; iOut < mpInstance->NumLinks(eOutgoing); iOut++) for (u32 iOut = 0; iOut < mpInstance->NumLinks(eOutgoing); iOut++)
{ {
CLink *pLink = mpInstance->Link(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); if (pLinkNode) CDrawUtil::DrawLine(CenterPoint(), pLinkNode->CenterPoint(), CColor::skTransparentGreen);
} }
} }
@ -549,7 +549,7 @@ void CScriptNode::GeneratePosition()
if (NumLinks == 1) if (NumLinks == 1)
{ {
u32 LinkedID = (mpInstance->NumLinks(eIncoming) > 0 ? mpInstance->Link(eIncoming, 0)->SenderID() : mpInstance->Link(eOutgoing, 0)->ReceiverID()); 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(); pNode->GeneratePosition();
mPosition = pNode->AbsolutePosition(); mPosition = pNode->AbsolutePosition();
mPosition.z += (pNode->AABox().Size().z / 2.f); mPosition.z += (pNode->AABox().Size().z / 2.f);
@ -564,7 +564,7 @@ void CScriptNode::GeneratePosition()
for (u32 iIn = 0; iIn < mpInstance->NumLinks(eIncoming); iIn++) 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) if (pNode)
{ {
@ -575,7 +575,7 @@ void CScriptNode::GeneratePosition()
for (u32 iOut = 0; iOut < mpInstance->NumLinks(eOutgoing); iOut++) 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) if (pNode)
{ {

View File

@ -30,7 +30,7 @@ class CScriptNode : public CSceneNode
} mGameModeVisibility; } mGameModeVisibility;
public: public:
CScriptNode(CScene *pScene, CSceneNode *pParent = 0, CScriptObject *pObject = 0); CScriptNode(CScene *pScene, u32 NodeID, CSceneNode *pParent = 0, CScriptObject *pObject = 0);
ENodeType NodeType(); ENodeType NodeType();
void PostLoad(); void PostLoad();
void OnTransformed(); void OnTransformed();

View File

@ -5,8 +5,8 @@
#include <Common/AnimUtil.h> #include <Common/AnimUtil.h>
#include <Math/MathUtil.h> #include <Math/MathUtil.h>
CStaticNode::CStaticNode(CScene *pScene, CSceneNode *pParent, CStaticModel *pModel) CStaticNode::CStaticNode(CScene *pScene, u32 NodeID, CSceneNode *pParent, CStaticModel *pModel)
: CSceneNode(pScene, pParent) : CSceneNode(pScene, NodeID, pParent)
{ {
mpModel = pModel; mpModel = pModel;
mLocalAABox = mpModel->AABox(); mLocalAABox = mpModel->AABox();

View File

@ -9,7 +9,7 @@ class CStaticNode : public CSceneNode
CStaticModel *mpModel; CStaticModel *mpModel;
public: public:
CStaticNode(CScene *pScene, CSceneNode *pParent = 0, CStaticModel *pModel = 0); CStaticNode(CScene *pScene, u32 NodeID, CSceneNode *pParent = 0, CStaticModel *pModel = 0);
ENodeType NodeType(); ENodeType NodeType();
void PostLoad(); void PostLoad();
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo); void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);

View File

@ -20,7 +20,7 @@ protected:
public: public:
explicit CScriptExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent = 0) explicit CScriptExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent = 0)
: CSceneNode(pScene, pParent), : CSceneNode(pScene, -1, pParent),
mpInstance(pInstance), mpInstance(pInstance),
mGame(pInstance->Template()->Game()) mGame(pInstance->Template()->Game())
{ {

View File

@ -53,7 +53,7 @@ void CSplinePathExtra::AddWaypoints()
if ( (pLink->State() == 0x49533030 && pLink->Message() == 0x41544348) || // InternalState00/Attach if ( (pLink->State() == 0x49533030 && pLink->Message() == 0x41544348) || // InternalState00/Attach
(pLink->State() == 0x4D4F5450 && pLink->Message() == 0x41544348) ) // MotionPath/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 if (pNode && pNode->Object()->ObjectTypeID() == 0x57415950) // Waypoint
{ {

View File

@ -85,7 +85,7 @@ void CWaypointExtra::BuildLinks()
if (IsPathLink(pLink)) if (IsPathLink(pLink))
{ {
CScriptNode *pNode = mpScene->ScriptNodeByID(pLink->ReceiverID()); CScriptNode *pNode = mpScene->NodeForInstanceID(pLink->ReceiverID());
SWaypointLink Link; SWaypointLink Link;
Link.pWaypoint = pNode; Link.pWaypoint = pNode;
@ -117,7 +117,7 @@ bool CWaypointExtra::IsPathLink(CLink *pLink)
if (Valid) if (Valid)
{ {
CScriptNode *pNode = mpScene->ScriptNodeByID(pLink->ReceiverID()); CScriptNode *pNode = mpScene->NodeForInstanceID(pLink->ReceiverID());
if (pNode) if (pNode)
return pNode->Object()->ObjectTypeID() == mpInstance->ObjectTypeID(); return pNode->Object()->ObjectTypeID() == mpInstance->ObjectTypeID();

View File

@ -138,7 +138,6 @@ HEADERS += \
WorldEditor/CInstancesModel.h \ WorldEditor/CInstancesModel.h \
Undo/CEditScriptPropertyCommand.h \ Undo/CEditScriptPropertyCommand.h \
Undo/CResizeScriptArrayCommand.h \ Undo/CResizeScriptArrayCommand.h \
Undo/CBasicPropertyCommand.h \
Undo/IUndoCommand.h \ Undo/IUndoCommand.h \
WorldEditor/WEditorProperties.h \ WorldEditor/WEditorProperties.h \
Undo/CChangeLayerCommand.h \ Undo/CChangeLayerCommand.h \
@ -154,7 +153,8 @@ HEADERS += \
Undo/CCreateInstanceCommand.h \ Undo/CCreateInstanceCommand.h \
WorldEditor/CTemplateMimeData.h \ WorldEditor/CTemplateMimeData.h \
WorldEditor/CTemplateListView.h \ WorldEditor/CTemplateListView.h \
CSelectionIterator.h CSelectionIterator.h \
Undo/ObjReferences.h
# Source Files # Source Files
SOURCES += \ SOURCES += \
@ -202,7 +202,6 @@ SOURCES += \
WorldEditor/CInstancesModel.cpp \ WorldEditor/CInstancesModel.cpp \
Undo/CEditScriptPropertyCommand.cpp \ Undo/CEditScriptPropertyCommand.cpp \
Undo/CResizeScriptArrayCommand.cpp \ Undo/CResizeScriptArrayCommand.cpp \
Undo/CBasicPropertyCommand.cpp \
WorldEditor/WEditorProperties.cpp \ WorldEditor/WEditorProperties.cpp \
Undo/CChangeLayerCommand.cpp \ Undo/CChangeLayerCommand.cpp \
WorldEditor/CTemplateEditDialog.cpp \ WorldEditor/CTemplateEditDialog.cpp \

View File

@ -31,7 +31,7 @@ CModelEditorWindow::CModelEditorWindow(QWidget *parent) :
mpScene = new CScene(); mpScene = new CScene();
mpCurrentMat = nullptr; mpCurrentMat = nullptr;
mpCurrentModel = nullptr; mpCurrentModel = nullptr;
mpCurrentModelNode = new CModelNode(mpScene); mpCurrentModelNode = new CModelNode(mpScene, -1);
mpCurrentPass = nullptr; mpCurrentPass = nullptr;
mIgnoreSignals = false; mIgnoreSignals = false;

View File

@ -8,7 +8,7 @@ CAddLinkCommand::CAddLinkCommand(CWorldEditor *pEditor, CLink Link)
{ {
mAffectedInstances << mLink.Sender(); mAffectedInstances << mLink.Sender();
if (mLink.Sender() != mLink.Receiver()) if (mLink.SenderID() != mLink.ReceiverID())
mAffectedInstances << mLink.Receiver(); mAffectedInstances << mLink.Receiver();
} }
@ -22,7 +22,7 @@ void CAddLinkCommand::undo()
pReceiver->RemoveLink(eIncoming, pLink); pReceiver->RemoveLink(eIncoming, pLink);
delete pLink; delete pLink;
mpEditor->InstanceLinksModified(mAffectedInstances); mpEditor->InstanceLinksModified(mAffectedInstances.DereferenceList());
} }
void CAddLinkCommand::redo() void CAddLinkCommand::redo()
@ -31,5 +31,5 @@ void CAddLinkCommand::redo()
pLink->Sender()->AddLink(eOutgoing, pLink, -1); pLink->Sender()->AddLink(eOutgoing, pLink, -1);
pLink->Receiver()->AddLink(eIncoming, pLink, -1); pLink->Receiver()->AddLink(eIncoming, pLink, -1);
mpEditor->InstanceLinksModified(mAffectedInstances); mpEditor->InstanceLinksModified(mAffectedInstances.DereferenceList());
} }

View File

@ -2,6 +2,7 @@
#define CADDLINKCOMMAND_H #define CADDLINKCOMMAND_H
#include "IUndoCommand.h" #include "IUndoCommand.h"
#include "ObjReferences.h"
#include "Editor/WorldEditor/CWorldEditor.h" #include "Editor/WorldEditor/CWorldEditor.h"
#include <Core/Resource/Script/CLink.h> #include <Core/Resource/Script/CLink.h>
@ -9,7 +10,7 @@ class CAddLinkCommand : public IUndoCommand
{ {
CWorldEditor *mpEditor; CWorldEditor *mpEditor;
CLink mLink; CLink mLink;
QList<CScriptObject*> mAffectedInstances; CInstancePtrList mAffectedInstances;
public: public:
CAddLinkCommand(CWorldEditor *pEditor, CLink Link); CAddLinkCommand(CWorldEditor *pEditor, CLink Link);

View File

@ -1,80 +0,0 @@
#include "CBasicPropertyCommand.h"
#include <Core/Resource/Script/IPropertyTemplate.h>
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<CArrayProperty*>(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<u32> SubIndices;
int IndexIndex = 0;
while (pParent)
{
if (pParent->Type() != eArrayProperty || static_cast<CArrayTemplate*>(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<CPropertyStruct*>(mpProperty)->PropertyByIndex(SubIndices[iChild]);
}

View File

@ -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<u32> mArrayIndices;
public:
CBasicPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, const QString& rkCommandName = "Edit Property");
virtual void UpdateArraySubProperty();
virtual bool AffectsCleanState() const { return true; }
};
#endif // CBASICPROPERTYCOMMAND_H

View File

@ -2,41 +2,46 @@
CChangeLayerCommand::CChangeLayerCommand(CWorldEditor *pEditor, const QList<CScriptNode*>& rkNodeList, CScriptLayer *pNewLayer) CChangeLayerCommand::CChangeLayerCommand(CWorldEditor *pEditor, const QList<CScriptNode*>& rkNodeList, CScriptLayer *pNewLayer)
: IUndoCommand("Change Layer") : IUndoCommand("Change Layer")
, mNodeList(rkNodeList)
, mpNewLayer(pNewLayer) , mpNewLayer(pNewLayer)
, mpEditor(pEditor) , mpEditor(pEditor)
{ {
foreach (CScriptNode *pNode, mNodeList) foreach (CScriptNode *pNode, rkNodeList)
{ {
CScriptLayer *pLayer = pNode->Object()->Layer(); CScriptLayer *pLayer = pNode->Object()->Layer();
if (pLayer == pNewLayer) if (pLayer != pNewLayer && !mNodes.contains(pNode))
{ {
mNodeList.removeOne(pNode); mNodes << pNode;
continue; mOldLayers[pNode->ID()] = pLayer;
} }
mOldLayers[pNode] = pLayer;
} }
} }
void CChangeLayerCommand::undo() void CChangeLayerCommand::undo()
{ {
mpEditor->InstancesLayerAboutToChange(); mpEditor->InstancesLayerAboutToChange();
QList<CSceneNode*> Nodes = mNodes.DereferenceList();
foreach (CScriptNode *pNode, mNodeList) QList<CScriptNode*> ScriptNodes;
pNode->Object()->SetLayer(mOldLayers[pNode]); foreach (CSceneNode *pNode, Nodes) ScriptNodes << static_cast<CScriptNode*>(pNode);
mpEditor->InstancesLayerChanged(mNodeList); foreach (CScriptNode *pNode, ScriptNodes)
pNode->Object()->SetLayer(mOldLayers[pNode->ID()]);
mpEditor->InstancesLayerChanged(ScriptNodes);
} }
void CChangeLayerCommand::redo() void CChangeLayerCommand::redo()
{ {
mpEditor->InstancesLayerAboutToChange(); mpEditor->InstancesLayerAboutToChange();
QList<CSceneNode*> Nodes = mNodes.DereferenceList();
foreach (CScriptNode *pNode, mNodeList) QList<CScriptNode*> ScriptNodes;
foreach (CSceneNode *pNode, Nodes) ScriptNodes << static_cast<CScriptNode*>(pNode);
foreach (CScriptNode *pNode, ScriptNodes)
pNode->Object()->SetLayer(mpNewLayer); pNode->Object()->SetLayer(mpNewLayer);
mpEditor->InstancesLayerChanged(mNodeList); mpEditor->InstancesLayerChanged(ScriptNodes);
} }

View File

@ -2,13 +2,14 @@
#define CCHANGELAYERCOMMAND_H #define CCHANGELAYERCOMMAND_H
#include "IUndoCommand.h" #include "IUndoCommand.h"
#include "ObjReferences.h"
#include "Editor/WorldEditor/CWorldEditor.h" #include "Editor/WorldEditor/CWorldEditor.h"
#include <Core/Scene/CScriptNode.h> #include <Core/Scene/CScriptNode.h>
class CChangeLayerCommand : public IUndoCommand class CChangeLayerCommand : public IUndoCommand
{ {
QList<CScriptNode*> mNodeList; CNodePtrList mNodes;
QMap<CScriptNode*, CScriptLayer*> mOldLayers; QMap<u32, CScriptLayer*> mOldLayers;
CScriptLayer *mpNewLayer; CScriptLayer *mpNewLayer;
CWorldEditor *mpEditor; CWorldEditor *mpEditor;

View File

@ -2,22 +2,26 @@
#define CCLEARSELECTIONCOMMAND_H #define CCLEARSELECTIONCOMMAND_H
#include "IUndoCommand.h" #include "IUndoCommand.h"
#include "ObjReferences.h"
#include "Editor/CSelectionIterator.h"
#include "Editor/INodeEditor.h" #include "Editor/INodeEditor.h"
#include <Core/Scene/CSceneNode.h> #include <Core/Scene/CSceneNode.h>
class CClearSelectionCommand : public IUndoCommand class CClearSelectionCommand : public IUndoCommand
{ {
QList<CSceneNode*> mOldSelection;
CNodeSelection *mpSelection; CNodeSelection *mpSelection;
CNodePtrList mOldSelection;
public: public:
CClearSelectionCommand(CNodeSelection *pSelection) CClearSelectionCommand(CNodeSelection *pSelection)
: IUndoCommand("Clear Selection"), : IUndoCommand("Clear Selection"),
mOldSelection(pSelection->SelectedNodeList()),
mpSelection(pSelection) 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(); } void redo() { mpSelection->Clear(); }
bool AffectsCleanState() const { return false; } bool AffectsCleanState() const { return false; }
}; };

View File

@ -16,13 +16,14 @@ CCreateInstanceCommand::CCreateInstanceCommand(CWorldEditor *pEditor, CScriptTem
void CCreateInstanceCommand::undo() void CCreateInstanceCommand::undo()
{ {
mpEditor->NotifyNodeAboutToBeDeleted(mpNewNode); mpEditor->NotifyNodeAboutToBeDeleted(*mpNewNode);
mpEditor->Selection()->SetSelectedNodes(mOldSelection); mpEditor->Selection()->SetSelectedNodes(mOldSelection.DereferenceList());
mpScene->DeleteNode(mpNewNode); mpScene->DeleteNode(*mpNewNode);
mpArea->DeleteInstance(mpNewInstance); mpArea->DeleteInstance(*mpNewInstance);
mpEditor->NotifyNodeDeleted();
mpNewNode = nullptr; mpNewNode = nullptr;
mpNewInstance = nullptr; mpNewInstance = nullptr;
mpEditor->NotifyNodeDeleted();
} }
void CCreateInstanceCommand::redo() void CCreateInstanceCommand::redo()
@ -30,10 +31,12 @@ void CCreateInstanceCommand::redo()
mpEditor->NotifyNodeAboutToBeSpawned(); mpEditor->NotifyNodeAboutToBeSpawned();
CScriptLayer *pLayer = (mLayerIndex == -1 ? mpArea->GetGeneratorLayer() : mpArea->GetScriptLayer(mLayerIndex)); CScriptLayer *pLayer = (mLayerIndex == -1 ? mpArea->GetGeneratorLayer() : mpArea->GetScriptLayer(mLayerIndex));
mpNewInstance = mpArea->SpawnInstance(mpTemplate, pLayer, mSpawnPosition); CScriptObject *pNewInst = mpArea->SpawnInstance(mpTemplate, pLayer, mSpawnPosition);
mpNewNode = mpScene->CreateScriptNode(mpNewInstance); CScriptNode *pNewNode = mpScene->CreateScriptNode(pNewInst);
mpNewNode->SetPosition(mSpawnPosition); pNewNode->SetPosition(mSpawnPosition);
mpEditor->NotifyNodeSpawned(pNewNode);
mpEditor->Selection()->ClearAndSelectNode(pNewNode);
mpEditor->NotifyNodeSpawned(mpNewNode); mpNewInstance = pNewInst;
mpEditor->Selection()->ClearAndSelectNode(mpNewNode); mpNewNode = pNewNode;
} }

View File

@ -18,9 +18,9 @@ class CCreateInstanceCommand : public IUndoCommand
u32 mLayerIndex; u32 mLayerIndex;
CVector3f mSpawnPosition; CVector3f mSpawnPosition;
QList<CSceneNode*> mOldSelection; CNodePtrList mOldSelection;
CScriptObject *mpNewInstance; CInstancePtr mpNewInstance;
CScriptNode *mpNewNode; CNodePtr mpNewNode;
public: public:
CCreateInstanceCommand(CWorldEditor *pEditor, CScriptTemplate *pTemplate, CScriptLayer *pLayer, const CVector3f& rkPosition); CCreateInstanceCommand(CWorldEditor *pEditor, CScriptTemplate *pTemplate, CScriptLayer *pLayer, const CVector3f& rkPosition);

View File

@ -48,7 +48,7 @@ void CDeleteLinksCommand::undo()
SNewLink Link; SNewLink Link;
Link.pDelLink = &mLinks[iLink]; 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; NewLinks << Link;
} }
@ -71,7 +71,7 @@ void CDeleteLinksCommand::undo()
} }
// Notify world editor // Notify world editor
mpEditor->OnLinksModified(mAffectedInstances); mpEditor->OnLinksModified(mAffectedInstances.DereferenceList());
} }
void CDeleteLinksCommand::redo() void CDeleteLinksCommand::redo()
@ -93,5 +93,5 @@ void CDeleteLinksCommand::redo()
} }
// Notify world editor // Notify world editor
mpEditor->OnLinksModified(mAffectedInstances); mpEditor->OnLinksModified(mAffectedInstances.DereferenceList());
} }

View File

@ -2,25 +2,27 @@
#define CDELETELINKSCOMMAND_H #define CDELETELINKSCOMMAND_H
#include "IUndoCommand.h" #include "IUndoCommand.h"
#include "ObjReferences.h"
#include "Editor/WorldEditor/CWorldEditor.h" #include "Editor/WorldEditor/CWorldEditor.h"
class CDeleteLinksCommand : public IUndoCommand class CDeleteLinksCommand : public IUndoCommand
{ {
CWorldEditor *mpEditor; CWorldEditor *mpEditor;
QList<CScriptObject*> mAffectedInstances; CInstancePtrList mAffectedInstances;
struct SDeletedLink struct SDeletedLink
{ {
u32 State; u32 State;
u32 Message; u32 Message;
CScriptObject *pSender; CInstancePtr pSender;
CScriptObject *pReceiver; CInstancePtr pReceiver;
u32 SenderIndex; u32 SenderIndex;
u32 ReceiverIndex; u32 ReceiverIndex;
}; };
QVector<SDeletedLink> mLinks; QVector<SDeletedLink> mLinks;
public: public:
CDeleteLinksCommand() {}
CDeleteLinksCommand(CWorldEditor *pEditor, CScriptObject *pObject, ELinkType Type, const QVector<u32>& rkIndices); CDeleteLinksCommand(CWorldEditor *pEditor, CScriptObject *pObject, ELinkType Type, const QVector<u32>& rkIndices);
void undo(); void undo();
void redo(); void redo();

View File

@ -1,35 +1,142 @@
#include "CDeleteSelectionCommand.h" #include "CDeleteSelectionCommand.h"
#include "Editor/CSelectionIterator.h" #include "Editor/CSelectionIterator.h"
#include <FileIO/FileIO.h>
#include <Core/Resource/Cooker/CScriptCooker.h>
#include <Core/Resource/Factory/CScriptLoader.h>
CDeleteSelectionCommand::CDeleteSelectionCommand(CWorldEditor *pEditor) CDeleteSelectionCommand::CDeleteSelectionCommand(CWorldEditor *pEditor)
: IUndoCommand("Delete") : IUndoCommand("Delete")
, mpEditor(pEditor) , mpEditor(pEditor)
{ {
mOldSelection = pEditor->Selection()->SelectedNodeList(); QSet<CLink*> Links;
for (CSelectionIterator It(pEditor->Selection()); It; ++It) for (CSelectionIterator It(pEditor->Selection()); It; ++It)
{ {
mOldSelection << *It;
if (It->NodeType() == eScriptNode) if (It->NodeType() == eScriptNode)
mNodesToDelete << *It; {
CScriptNode *pScript = static_cast<CScriptNode*>(*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 else
mNewSelection << *It; mNewSelection << *It;
} }
qSort(mDeletedNodes.begin(), mDeletedNodes.end(), [](SDeletedNode& rLeft, SDeletedNode& rRight) -> bool {
return (rLeft.NodeID < rRight.NodeID);
});
} }
void CDeleteSelectionCommand::undo() void CDeleteSelectionCommand::undo()
{ {
//foreach (CSceneNode *pNode, mNodesToDelete) QList<u32> NewInstanceIDs;
// pNode->SetDeleted(false);
//mpEditor->Selection()->SetSelectedNodes(mOldSelection); // 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() 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<CScriptNode*>(pNode)->Object(); CScriptObject *pInst = static_cast<CScriptNode*>(pNode)->Object();
mpEditor->NotifyNodeAboutToBeDeleted(pNode); mpEditor->NotifyNodeAboutToBeDeleted(pNode);
mpEditor->Scene()->DeleteNode(pNode); mpEditor->Scene()->DeleteNode(pNode);
mpEditor->ActiveArea()->DeleteInstance(pInst); mpEditor->ActiveArea()->DeleteInstance(pInst);

View File

@ -1,16 +1,49 @@
#ifndef CDELETESELECTIONCOMMAND_H #ifndef CDELETESELECTIONCOMMAND_H
#define CDELETESELECTIONCOMMAND_H #define CDELETESELECTIONCOMMAND_H
#include "CDeleteLinksCommand.h"
#include "IUndoCommand.h" #include "IUndoCommand.h"
#include "ObjReferences.h"
#include "Editor/WorldEditor/CWorldEditor.h" #include "Editor/WorldEditor/CWorldEditor.h"
#include <Core/Scene/CSceneNode.h> #include <Core/Scene/CSceneNode.h>
// 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 class CDeleteSelectionCommand : public IUndoCommand
{ {
CWorldEditor *mpEditor; CWorldEditor *mpEditor;
QList<CSceneNode*> mNodesToDelete; CNodePtrList mOldSelection;
QList<CSceneNode*> mOldSelection; CNodePtrList mNewSelection;
QList<CSceneNode*> 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<char> InstanceData;
};
QVector<SDeletedNode> mDeletedNodes;
struct SDeletedLink
{
u32 State;
u32 Message;
u32 SenderID;
u32 SenderIndex;
u32 ReceiverID;
u32 ReceiverIndex;
CInstancePtr pSender;
CInstancePtr pReceiver;
};
QVector<SDeletedLink> mDeletedLinks;
public: public:
CDeleteSelectionCommand(CWorldEditor *pEditor); CDeleteSelectionCommand(CWorldEditor *pEditor);

View File

@ -2,12 +2,13 @@
#define CDESELECTNODECOMMAND_H #define CDESELECTNODECOMMAND_H
#include "IUndoCommand.h" #include "IUndoCommand.h"
#include "ObjReferences.h"
#include "Editor/INodeEditor.h" #include "Editor/INodeEditor.h"
#include <Core/Scene/CSceneNode.h> #include <Core/Scene/CSceneNode.h>
class CDeselectNodeCommand : public IUndoCommand class CDeselectNodeCommand : public IUndoCommand
{ {
CSceneNode *mpNode; CNodePtr mpNode;
CNodeSelection *mpSelection; CNodeSelection *mpSelection;
public: public:
CDeselectNodeCommand(CNodeSelection *pSelection, CSceneNode *pNode) CDeselectNodeCommand(CNodeSelection *pSelection, CSceneNode *pNode)
@ -16,8 +17,8 @@ public:
, mpSelection(pSelection) , mpSelection(pSelection)
{} {}
void undo() { mpSelection->SelectNode(mpNode); } void undo() { mpSelection->SelectNode(*mpNode); }
void redo() { mpSelection->DeselectNode(mpNode); } void redo() { mpSelection->DeselectNode(*mpNode); }
bool AffectsCleanState() const { return false; } bool AffectsCleanState() const { return false; }
}; };

View File

@ -9,42 +9,49 @@ CEditLinkCommand::CEditLinkCommand(CWorldEditor *pEditor, CLink *pLink, CLink Ne
{ {
mOldSenderIndex = pLink->SenderIndex(); mOldSenderIndex = pLink->SenderIndex();
mOldReceiverIndex = pLink->ReceiverIndex(); mOldReceiverIndex = pLink->ReceiverIndex();
mAffectedInstances << pLink->Sender(); mAffectedInstances << pLink->Sender();
if (pLink->Receiver() != pLink->Sender()) mAffectedInstances << pLink->Receiver(); if (pLink->ReceiverID() != pLink->SenderID()) mAffectedInstances << pLink->Receiver();
if (NewLink.Sender() != pLink->Sender()) mAffectedInstances << NewLink.Sender(); if (NewLink.SenderID() != pLink->SenderID()) mAffectedInstances << NewLink.Sender();
if (NewLink.Receiver() != pLink->Receiver()) mAffectedInstances << NewLink.Receiver(); if (NewLink.ReceiverID() != pLink->ReceiverID()) mAffectedInstances << NewLink.Receiver();
} }
void CEditLinkCommand::undo() void CEditLinkCommand::undo()
{ {
CLink *pLink = *mpEditLink;
if (mOldLink.Sender() != mNewLink.Sender()) if (mOldLink.Sender() != mNewLink.Sender())
{ {
mNewLink.Sender()->RemoveLink(eOutgoing, mpEditLink); mNewLink.Sender()->RemoveLink(eOutgoing, pLink);
mOldLink.Sender()->AddLink(eOutgoing, mpEditLink, mOldSenderIndex); mOldLink.Sender()->AddLink(eOutgoing, pLink, mOldSenderIndex);
} }
if (mOldLink.Receiver() != mNewLink.Receiver()) if (mOldLink.Receiver() != mNewLink.Receiver())
{ {
mNewLink.Receiver()->RemoveLink(eIncoming, mpEditLink); mNewLink.Receiver()->RemoveLink(eIncoming, pLink);
mOldLink.Receiver()->AddLink(eIncoming, mpEditLink, mOldReceiverIndex); mOldLink.Receiver()->AddLink(eIncoming, pLink, mOldReceiverIndex);
} }
*mpEditLink = mOldLink; *pLink = mOldLink;
mpEditor->OnLinksModified(mAffectedInstances); mpEditor->OnLinksModified(mAffectedInstances.DereferenceList());
mpEditLink.SetLink(pLink); // note: This is done to account for situations where the sender has changed
} }
void CEditLinkCommand::redo() void CEditLinkCommand::redo()
{ {
CLink *pLink = *mpEditLink;
if (mOldLink.Sender() != mNewLink.Sender()) if (mOldLink.Sender() != mNewLink.Sender())
{ {
mOldLink.Sender()->RemoveLink(eOutgoing, mpEditLink); mOldLink.Sender()->RemoveLink(eOutgoing, pLink);
mNewLink.Sender()->AddLink(eOutgoing, mpEditLink); mNewLink.Sender()->AddLink(eOutgoing, pLink);
} }
if (mOldLink.Receiver() != mNewLink.Receiver()) if (mOldLink.Receiver() != mNewLink.Receiver())
{ {
mOldLink.Receiver()->RemoveLink(eIncoming, mpEditLink); mOldLink.Receiver()->RemoveLink(eIncoming, pLink);
mNewLink.Receiver()->AddLink(eIncoming, mpEditLink); mNewLink.Receiver()->AddLink(eIncoming, pLink);
} }
*mpEditLink = mNewLink; *pLink = mNewLink;
mpEditor->OnLinksModified(mAffectedInstances); mpEditor->OnLinksModified(mAffectedInstances.DereferenceList());
mpEditLink.SetLink(pLink);
} }

View File

@ -2,23 +2,25 @@
#define CEDITLINKCOMMAND_H #define CEDITLINKCOMMAND_H
#include "IUndoCommand.h" #include "IUndoCommand.h"
#include "ObjReferences.h"
#include "Editor/WorldEditor/CWorldEditor.h" #include "Editor/WorldEditor/CWorldEditor.h"
#include <Core/Resource/Script/CLink.h> #include <Core/Resource/Script/CLink.h>
class CEditLinkCommand : public IUndoCommand class CEditLinkCommand : public IUndoCommand
{ {
CWorldEditor *mpEditor; CWorldEditor *mpEditor;
CLink *mpEditLink; CLinkPtr mpEditLink;
CLink mOldLink; CLink mOldLink;
CLink mNewLink; CLink mNewLink;
u32 mOldSenderIndex; u32 mOldSenderIndex;
u32 mOldReceiverIndex; u32 mOldReceiverIndex;
QList<CScriptObject*> mAffectedInstances; CInstancePtrList mAffectedInstances;
public: public:
CEditLinkCommand(CWorldEditor *pEditor, CLink *pLink, CLink NewLink); CEditLinkCommand(CWorldEditor *pEditor, CLink *pLink, CLink NewLink);
QList<CScriptObject*> AffectedInstances() const;
void undo(); void undo();
void redo(); void redo();
bool AffectsCleanState() const { return true; } bool AffectsCleanState() const { return true; }

View File

@ -2,11 +2,13 @@
#include "EUndoCommand.h" #include "EUndoCommand.h"
CEditScriptPropertyCommand::CEditScriptPropertyCommand(IProperty *pProp, CWorldEditor *pEditor, IPropertyValue *pOldValue, bool IsDone, const QString& rkCommandName /*= "Edit Property"*/) 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) , mCommandEnded(IsDone)
{ {
mpOldValue = pOldValue; mpOldValue = pOldValue;
mpNewValue = mpProperty->RawValue()->Clone(); mpNewValue = pProp->RawValue()->Clone();
} }
CEditScriptPropertyCommand::~CEditScriptPropertyCommand() CEditScriptPropertyCommand::~CEditScriptPropertyCommand()
@ -26,7 +28,7 @@ bool CEditScriptPropertyCommand::mergeWith(const QUndoCommand *pkOther)
{ {
const CEditScriptPropertyCommand *pkCmd = static_cast<const CEditScriptPropertyCommand*>(pkOther); const CEditScriptPropertyCommand *pkCmd = static_cast<const CEditScriptPropertyCommand*>(pkOther);
if (pkCmd->mpProperty == mpProperty) if (pkCmd->mpProp == mpProp)
{ {
mpNewValue->Copy(pkCmd->mpNewValue); mpNewValue->Copy(pkCmd->mpNewValue);
mCommandEnded = pkCmd->mCommandEnded; mCommandEnded = pkCmd->mCommandEnded;
@ -39,15 +41,15 @@ bool CEditScriptPropertyCommand::mergeWith(const QUndoCommand *pkOther)
void CEditScriptPropertyCommand::undo() void CEditScriptPropertyCommand::undo()
{ {
if (mIsInArray) UpdateArraySubProperty(); IProperty *pProp = *mpProp;
mpProperty->RawValue()->Copy(mpOldValue); pProp->RawValue()->Copy(mpOldValue);
mpEditor->OnPropertyModified(mpProperty); mpEditor->OnPropertyModified(pProp);
mCommandEnded = true; mCommandEnded = true;
} }
void CEditScriptPropertyCommand::redo() void CEditScriptPropertyCommand::redo()
{ {
if (mIsInArray) UpdateArraySubProperty(); IProperty *pProp = *mpProp;
mpProperty->RawValue()->Copy(mpNewValue); pProp->RawValue()->Copy(mpNewValue);
mpEditor->OnPropertyModified(mpProperty); mpEditor->OnPropertyModified(pProp);
} }

View File

@ -1,11 +1,15 @@
#ifndef CEDITSCRIPTPROPERTYCOMMAND_H #ifndef CEDITSCRIPTPROPERTYCOMMAND_H
#define CEDITSCRIPTPROPERTYCOMMAND_H #define CEDITSCRIPTPROPERTYCOMMAND_H
#include "CBasicPropertyCommand.h" #include "IUndoCommand.h"
#include "ObjReferences.h"
#include "Editor/PropertyEdit/CPropertyModel.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 *mpOldValue;
IPropertyValue *mpNewValue; IPropertyValue *mpNewValue;
bool mCommandEnded; bool mCommandEnded;
@ -17,6 +21,7 @@ public:
bool mergeWith(const QUndoCommand *pkOther); bool mergeWith(const QUndoCommand *pkOther);
void undo(); void undo();
void redo(); void redo();
bool AffectsCleanState() const { return true; }
}; };
#endif // CEDITSCRIPTPROPERTYCOMMAND_H #endif // CEDITSCRIPTPROPERTYCOMMAND_H

View File

@ -2,14 +2,15 @@
#define CINVERTSELECTIONCOMMAND_H #define CINVERTSELECTIONCOMMAND_H
#include "IUndoCommand.h" #include "IUndoCommand.h"
#include "ObjReferences.h"
#include "Editor/INodeEditor.h" #include "Editor/INodeEditor.h"
#include <Core/Scene/CSceneNode.h> #include <Core/Scene/CSceneNode.h>
class CInvertSelectionCommand : public IUndoCommand class CInvertSelectionCommand : public IUndoCommand
{ {
CNodeSelection *mpSelection; CNodeSelection *mpSelection;
QList<CSceneNode*> mOldSelection; CNodePtrList mOldSelection;
QList<CSceneNode*> mNewSelection; CNodePtrList mNewSelection;
public: public:
CInvertSelectionCommand(CNodeSelection *pSelection, CScene *pScene, FNodeFlags NodeFlags) CInvertSelectionCommand(CNodeSelection *pSelection, CScene *pScene, FNodeFlags NodeFlags)
@ -25,8 +26,8 @@ public:
} }
} }
void undo() { mpSelection->SetSelectedNodes(mOldSelection); } void undo() { mpSelection->SetSelectedNodes(mOldSelection.DereferenceList()); }
void redo() { mpSelection->SetSelectedNodes(mNewSelection); } void redo() { mpSelection->SetSelectedNodes(mNewSelection.DereferenceList()); }
bool AffectsCleanState() const { return false; } bool AffectsCleanState() const { return false; }
}; };

View File

@ -1,19 +1,22 @@
#include "CResizeScriptArrayCommand.h" #include "CResizeScriptArrayCommand.h"
CResizeScriptArrayCommand::CResizeScriptArrayCommand(IProperty *pProp, CWorldEditor *pEditor, CPropertyModel *pModel, int NewSize) CResizeScriptArrayCommand::CResizeScriptArrayCommand(IProperty *pProp, CWorldEditor *pEditor, CPropertyModel *pModel, int NewSize)
: CBasicPropertyCommand(pProp, pEditor) : IUndoCommand("Edit Property")
, mpArray(static_cast<CArrayProperty*>(mpProperty)) , mpEditor(pEditor)
, mpArray(pProp)
, mpModel(pModel) , mpModel(pModel)
, mOldSize(mpArray->Count()) , mOldSize(static_cast<CArrayProperty*>(pProp)->Count())
, mNewSize(NewSize) , mNewSize(NewSize)
{ {
mNewSizeLarger = mNewSize > mOldSize; mNewSizeLarger = mNewSize > mOldSize;
if (!mNewSizeLarger) if (!mNewSizeLarger)
{ {
CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp);
for (int iSub = mNewSize; iSub < mOldSize; iSub++) 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 (mNewSize != mOldSize)
{ {
if (mIsInArray) UpdateArraySubProperty(); // Update parents
CArrayProperty *pArray = static_cast<CArrayProperty*>(*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); mpModel->ArrayAboutToBeResized(Index, (u32) mOldSize);
mpArray->Resize(mOldSize); pArray->Resize(mOldSize);
if (!mNewSizeLarger) if (!mNewSizeLarger)
{ {
@ -41,7 +49,7 @@ void CResizeScriptArrayCommand::undo()
for (int iSub = 0; iSub < NumNewElements; iSub++) for (int iSub = 0; iSub < NumNewElements; iSub++)
{ {
u32 Idx = iSub + mNewSize; 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. // Whether we're increasing or decreasing in size, there's no need to restore deleted properties on redo.
if (mNewSize != mOldSize) if (mNewSize != mOldSize)
{ {
if (mIsInArray) UpdateArraySubProperty(); CArrayProperty *pArray = static_cast<CArrayProperty*>(*mpArray);
QModelIndex Index = mpModel->IndexForProperty(pArray);
QModelIndex Index = mpModel->IndexForProperty(mpProperty);
mpModel->ArrayAboutToBeResized(Index, (u32) mNewSize); mpModel->ArrayAboutToBeResized(Index, (u32) mNewSize);
mpArray->Resize(mNewSize); pArray->Resize(mNewSize);
mpModel->ArrayResized(Index, (u32) mOldSize); mpModel->ArrayResized(Index, (u32) mOldSize);
} }
} }
void CResizeScriptArrayCommand::UpdateArraySubProperty()
{
CArrayProperty *pOldArray = mpArray;
CBasicPropertyCommand::UpdateArraySubProperty();
mpArray = static_cast<CArrayProperty*>(mpProperty);
if (pOldArray != mpArray)
{
for (int iDel = 0; iDel < mDeletedProperties.size(); iDel++)
mDeletedProperties[iDel]->SetParent(mpArray);
}
}

View File

@ -1,13 +1,17 @@
#ifndef CRESIZESCRIPTARRAYCOMMAND_H #ifndef CRESIZESCRIPTARRAYCOMMAND_H
#define CRESIZESCRIPTARRAYCOMMAND_H #define CRESIZESCRIPTARRAYCOMMAND_H
#include "CBasicPropertyCommand.h" #include "IUndoCommand.h"
#include "ObjReferences.h"
#include "Editor/PropertyEdit/CPropertyModel.h" #include "Editor/PropertyEdit/CPropertyModel.h"
#include "Editor/WorldEditor/CWorldEditor.h"
#include <QUndoCommand> #include <QUndoCommand>
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<IProperty*> mDeletedProperties; QVector<IProperty*> mDeletedProperties;
CPropertyModel *mpModel; CPropertyModel *mpModel;
@ -20,7 +24,7 @@ public:
~CResizeScriptArrayCommand(); ~CResizeScriptArrayCommand();
void undo(); void undo();
void redo(); void redo();
virtual void UpdateArraySubProperty(); bool AffectsCleanState() const { return true; }
}; };
#endif // CRESIZESCRIPTARRAYCOMMAND_H #endif // CRESIZESCRIPTARRAYCOMMAND_H

View File

@ -9,23 +9,23 @@ CRotateNodeCommand::CRotateNodeCommand()
{ {
} }
CRotateNodeCommand::CRotateNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& nodes, const CVector3f& /*pivot*/, const CQuaternion& delta, ETransformSpace transformSpace) CRotateNodeCommand::CRotateNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& rkNodes, const CVector3f& /*rkPivot*/, const CQuaternion& rkDelta, ETransformSpace TransformSpace)
: IUndoCommand("Rotate"), : IUndoCommand("Rotate"),
mpEditor(pEditor), mpEditor(pEditor),
mCommandEnded(false) mCommandEnded(false)
{ {
mNodeList.reserve(nodes.size()); mNodeList.reserve(rkNodes.size());
foreach (CSceneNode *pNode, nodes) foreach (CSceneNode *pNode, rkNodes)
{ {
SNodeRotate rotate; SNodeRotate Rotate;
rotate.pNode = pNode; Rotate.pNode = pNode;
rotate.initialPos = pNode->LocalPosition(); Rotate.InitialPos = pNode->LocalPosition();
rotate.initialRot = pNode->LocalRotation(); Rotate.InitialRot = pNode->LocalRotation();
pNode->Rotate(delta, transformSpace); pNode->Rotate(rkDelta, TransformSpace);
rotate.newPos = pNode->LocalPosition(); Rotate.NewPos = pNode->LocalPosition();
rotate.newRot = pNode->LocalRotation(); Rotate.NewRot = pNode->LocalRotation();
mNodeList.push_back(rotate); mNodeList.push_back(Rotate);
} }
mpEditor->NotifySelectionTransformed(); mpEditor->NotifySelectionTransformed();
@ -40,26 +40,26 @@ int CRotateNodeCommand::id() const
return eRotateNodeCmd; return eRotateNodeCmd;
} }
bool CRotateNodeCommand::mergeWith(const QUndoCommand *other) bool CRotateNodeCommand::mergeWith(const QUndoCommand *pkOther)
{ {
if (mCommandEnded) return false; if (mCommandEnded) return false;
if (other->id() == eRotateNodeCmd) if (pkOther->id() == eRotateNodeCmd)
{ {
const CRotateNodeCommand *pCmd = static_cast<const CRotateNodeCommand*>(other); const CRotateNodeCommand *pkCmd = static_cast<const CRotateNodeCommand*>(pkOther);
if (pCmd->mCommandEnded) if (pkCmd->mCommandEnded)
{ {
mCommandEnded = true; mCommandEnded = true;
return 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++) for (int iNode = 0; iNode < mNodeList.size(); iNode++)
{ {
mNodeList[iNode].newPos = pCmd->mNodeList[iNode].newPos; mNodeList[iNode].NewPos = pkCmd->mNodeList[iNode].NewPos;
mNodeList[iNode].newRot = pCmd->mNodeList[iNode].newRot; mNodeList[iNode].NewRot = pkCmd->mNodeList[iNode].NewRot;
} }
return true; return true;
@ -73,10 +73,10 @@ void CRotateNodeCommand::undo()
{ {
if (!mpEditor) return; if (!mpEditor) return;
foreach (SNodeRotate rotate, mNodeList) foreach (SNodeRotate Rotate, mNodeList)
{ {
rotate.pNode->SetPosition(rotate.initialPos); Rotate.pNode->SetPosition(Rotate.InitialPos);
rotate.pNode->SetRotation(rotate.initialRot); Rotate.pNode->SetRotation(Rotate.InitialRot);
} }
mpEditor->NotifySelectionTransformed(); mpEditor->NotifySelectionTransformed();
@ -87,10 +87,10 @@ void CRotateNodeCommand::redo()
{ {
if (!mpEditor) return; if (!mpEditor) return;
foreach (SNodeRotate rotate, mNodeList) foreach (SNodeRotate Rotate, mNodeList)
{ {
rotate.pNode->SetPosition(rotate.newPos); Rotate.pNode->SetPosition(Rotate.NewPos);
rotate.pNode->SetRotation(rotate.newRot); Rotate.pNode->SetRotation(Rotate.NewRot);
} }
mpEditor->NotifySelectionTransformed(); mpEditor->NotifySelectionTransformed();

View File

@ -2,6 +2,7 @@
#define CROTATENODECOMMAND_H #define CROTATENODECOMMAND_H
#include "IUndoCommand.h" #include "IUndoCommand.h"
#include "ObjReferences.h"
#include "Editor/INodeEditor.h" #include "Editor/INodeEditor.h"
#include <Core/Scene/CSceneNode.h> #include <Core/Scene/CSceneNode.h>
#include <QList> #include <QList>
@ -10,11 +11,11 @@ class CRotateNodeCommand : public IUndoCommand
{ {
struct SNodeRotate struct SNodeRotate
{ {
CSceneNode *pNode; CNodePtr pNode;
CVector3f initialPos; CVector3f InitialPos;
CQuaternion initialRot; CQuaternion InitialRot;
CVector3f newPos; CVector3f NewPos;
CQuaternion newRot; CQuaternion NewRot;
}; };
QList<SNodeRotate> mNodeList; QList<SNodeRotate> mNodeList;
INodeEditor *mpEditor; INodeEditor *mpEditor;
@ -22,10 +23,10 @@ class CRotateNodeCommand : public IUndoCommand
public: public:
CRotateNodeCommand(); CRotateNodeCommand();
CRotateNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& nodes, const CVector3f& pivot, const CQuaternion& delta, ETransformSpace transformSpace); CRotateNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& rkNodes, const CVector3f& rkPivot, const CQuaternion& rkDelta, ETransformSpace TransformSpace);
~CRotateNodeCommand(); ~CRotateNodeCommand();
int id() const; int id() const;
bool mergeWith(const QUndoCommand *other); bool mergeWith(const QUndoCommand *pkOther);
void undo(); void undo();
void redo(); void redo();
bool AffectsCleanState() const { return true; } bool AffectsCleanState() const { return true; }

View File

@ -9,23 +9,23 @@ CScaleNodeCommand::CScaleNodeCommand()
{ {
} }
CScaleNodeCommand::CScaleNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& nodes, const CVector3f& /*pivot*/, const CVector3f& delta) CScaleNodeCommand::CScaleNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& rkNodes, const CVector3f& /*rkPivot*/, const CVector3f& rkDelta)
: IUndoCommand("Scale"), : IUndoCommand("Scale"),
mpEditor(pEditor), mpEditor(pEditor),
mCommandEnded(false) mCommandEnded(false)
{ {
mNodeList.reserve(nodes.size()); mNodeList.reserve(rkNodes.size());
foreach (CSceneNode *pNode, nodes) foreach (CSceneNode *pNode, rkNodes)
{ {
SNodeScale scale; SNodeScale Scale;
scale.pNode = pNode; Scale.pNode = pNode;
scale.initialPos = pNode->LocalPosition(); Scale.InitialPos = pNode->LocalPosition();
scale.initialScale = pNode->LocalScale(); Scale.InitialScale = pNode->LocalScale();
pNode->Scale(delta); pNode->Scale(rkDelta);
scale.newPos = pNode->LocalPosition(); Scale.NewPos = pNode->LocalPosition();
scale.newScale = pNode->LocalScale(); Scale.NewScale = pNode->LocalScale();
mNodeList.push_back(scale); mNodeList.push_back(Scale);
} }
mpEditor->NotifySelectionTransformed(); mpEditor->NotifySelectionTransformed();
@ -40,26 +40,26 @@ int CScaleNodeCommand::id() const
return eScaleNodeCmd; return eScaleNodeCmd;
} }
bool CScaleNodeCommand::mergeWith(const QUndoCommand *other) bool CScaleNodeCommand::mergeWith(const QUndoCommand *pkOther)
{ {
if (mCommandEnded) return false; if (mCommandEnded) return false;
if (other->id() == eScaleNodeCmd) if (pkOther->id() == eScaleNodeCmd)
{ {
const CScaleNodeCommand *pCmd = static_cast<const CScaleNodeCommand*>(other); const CScaleNodeCommand *pkCmd = static_cast<const CScaleNodeCommand*>(pkOther);
if (pCmd->mCommandEnded) if (pkCmd->mCommandEnded)
{ {
mCommandEnded = true; mCommandEnded = true;
return 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++) for (int iNode = 0; iNode < mNodeList.size(); iNode++)
{ {
mNodeList[iNode].newPos = pCmd->mNodeList[iNode].newPos; mNodeList[iNode].NewPos = pkCmd->mNodeList[iNode].NewPos;
mNodeList[iNode].newScale = pCmd->mNodeList[iNode].newScale; mNodeList[iNode].NewScale = pkCmd->mNodeList[iNode].NewScale;
} }
return true; return true;
@ -73,10 +73,10 @@ void CScaleNodeCommand::undo()
{ {
if (!mpEditor) return; if (!mpEditor) return;
foreach (SNodeScale scale, mNodeList) foreach (SNodeScale Scale, mNodeList)
{ {
scale.pNode->SetPosition(scale.initialPos); Scale.pNode->SetPosition(Scale.InitialPos);
scale.pNode->SetScale(scale.initialScale); Scale.pNode->SetScale(Scale.InitialScale);
} }
mpEditor->NotifySelectionTransformed(); mpEditor->NotifySelectionTransformed();
@ -87,10 +87,10 @@ void CScaleNodeCommand::redo()
{ {
if (!mpEditor) return; if (!mpEditor) return;
foreach (SNodeScale scale, mNodeList) foreach (SNodeScale Scale, mNodeList)
{ {
scale.pNode->SetPosition(scale.newPos); Scale.pNode->SetPosition(Scale.NewPos);
scale.pNode->SetScale(scale.newScale); Scale.pNode->SetScale(Scale.NewScale);
} }
mpEditor->NotifySelectionTransformed(); mpEditor->NotifySelectionTransformed();

View File

@ -2,6 +2,7 @@
#define CSCALENODECOMMAND_H #define CSCALENODECOMMAND_H
#include "IUndoCommand.h" #include "IUndoCommand.h"
#include "ObjReferences.h"
#include "Editor/INodeEditor.h" #include "Editor/INodeEditor.h"
#include <Core/Scene/CSceneNode.h> #include <Core/Scene/CSceneNode.h>
#include <QList> #include <QList>
@ -10,11 +11,11 @@ class CScaleNodeCommand : public IUndoCommand
{ {
struct SNodeScale struct SNodeScale
{ {
CSceneNode *pNode; CNodePtr pNode;
CVector3f initialPos; CVector3f InitialPos;
CVector3f initialScale; CVector3f InitialScale;
CVector3f newPos; CVector3f NewPos;
CVector3f newScale; CVector3f NewScale;
}; };
QList<SNodeScale> mNodeList; QList<SNodeScale> mNodeList;
INodeEditor *mpEditor; INodeEditor *mpEditor;
@ -22,10 +23,10 @@ class CScaleNodeCommand : public IUndoCommand
public: public:
CScaleNodeCommand(); CScaleNodeCommand();
CScaleNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& nodes, const CVector3f& pivot, const CVector3f& delta); CScaleNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& rkNodes, const CVector3f& rkPivot, const CVector3f& rkDelta);
~CScaleNodeCommand(); ~CScaleNodeCommand();
int id() const; int id() const;
bool mergeWith(const QUndoCommand *other); bool mergeWith(const QUndoCommand *pkOther);
void undo(); void undo();
void redo(); void redo();
bool AffectsCleanState() const { return true; } bool AffectsCleanState() const { return true; }

View File

@ -2,27 +2,30 @@
#define CSELECTALLCOMMAND_H #define CSELECTALLCOMMAND_H
#include "IUndoCommand.h" #include "IUndoCommand.h"
#include "ObjReferences.h"
#include "Editor/CSelectionIterator.h"
#include "Editor/INodeEditor.h" #include "Editor/INodeEditor.h"
#include <Core/Scene/CSceneNode.h> #include <Core/Scene/CSceneNode.h>
class CSelectAllCommand : public IUndoCommand class CSelectAllCommand : public IUndoCommand
{ {
QList<CSceneNode*> mOldSelection; CNodePtrList mOldSelection;
QList<CSceneNode*> mNewSelection; CNodePtrList mNewSelection;
CNodeSelection *mpSelection; CNodeSelection *mpSelection;
public: public:
CSelectAllCommand(CNodeSelection *pSelection, CScene *pScene, FNodeFlags NodeFlags) CSelectAllCommand(CNodeSelection *pSelection, CScene *pScene, FNodeFlags NodeFlags)
: IUndoCommand("Select All") : IUndoCommand("Select All")
, mOldSelection(pSelection->SelectedNodeList())
, mpSelection(pSelection) , mpSelection(pSelection)
{ {
for (CSelectionIterator It(pSelection); It; ++It)
mOldSelection << *It;
for (CSceneIterator It(pScene, NodeFlags); It; ++It) for (CSceneIterator It(pScene, NodeFlags); It; ++It)
mNewSelection << *It; mNewSelection << *It;
} }
void undo() { mpSelection->SetSelectedNodes(mOldSelection); } void undo() { mpSelection->SetSelectedNodes(mOldSelection.DereferenceList()); }
void redo() { mpSelection->SetSelectedNodes(mNewSelection); } void redo() { mpSelection->SetSelectedNodes(mNewSelection.DereferenceList()); }
bool AffectsCleanState() const { return false; } bool AffectsCleanState() const { return false; }
}; };

View File

@ -2,12 +2,13 @@
#define CSELECTNODECOMMAND_H #define CSELECTNODECOMMAND_H
#include "IUndoCommand.h" #include "IUndoCommand.h"
#include "ObjReferences.h"
#include "Editor/INodeEditor.h" #include "Editor/INodeEditor.h"
#include <Core/Scene/CSceneNode.h> #include <Core/Scene/CSceneNode.h>
class CSelectNodeCommand : public IUndoCommand class CSelectNodeCommand : public IUndoCommand
{ {
CSceneNode *mpNode; CNodePtr mpNode;
CNodeSelection *mpSelection; CNodeSelection *mpSelection;
public: public:
@ -17,8 +18,8 @@ public:
, mpSelection(pSelection) , mpSelection(pSelection)
{} {}
void undo() { mpSelection->DeselectNode(mpNode); } void undo() { mpSelection->DeselectNode(*mpNode); }
void redo() { mpSelection->SelectNode(mpNode); } void redo() { mpSelection->SelectNode(*mpNode); }
bool AffectsCleanState() const { return false; } bool AffectsCleanState() const { return false; }
}; };

View File

@ -9,53 +9,49 @@ CTranslateNodeCommand::CTranslateNodeCommand()
{ {
} }
CTranslateNodeCommand::CTranslateNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& nodes, const CVector3f& delta, ETransformSpace transformSpace) CTranslateNodeCommand::CTranslateNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& rkNodes, const CVector3f& Delta, ETransformSpace TransformSpace)
: IUndoCommand("Translate"), : IUndoCommand("Translate"),
mpEditor(pEditor), mpEditor(pEditor),
mCommandEnded(false) mCommandEnded(false)
{ {
mNodeList.reserve(nodes.size()); mNodeList.reserve(rkNodes.size());
foreach (CSceneNode *pNode, nodes) foreach (CSceneNode *pNode, rkNodes)
{ {
SNodeTranslate translate; SNodeTranslate Translate;
translate.pNode = pNode; Translate.pNode = pNode;
translate.initialPos = pNode->LocalPosition(); Translate.InitialPos = pNode->LocalPosition();
pNode->Translate(delta, transformSpace); pNode->Translate(Delta, TransformSpace);
translate.newPos = pNode->LocalPosition(); Translate.NewPos = pNode->LocalPosition();
mNodeList.push_back(translate); mNodeList.push_back(Translate);
} }
mpEditor->NotifySelectionTransformed(); mpEditor->NotifySelectionTransformed();
} }
CTranslateNodeCommand::~CTranslateNodeCommand()
{
}
int CTranslateNodeCommand::id() const int CTranslateNodeCommand::id() const
{ {
return eTranslateNodeCmd; return eTranslateNodeCmd;
} }
bool CTranslateNodeCommand::mergeWith(const QUndoCommand *other) bool CTranslateNodeCommand::mergeWith(const QUndoCommand *pkOther)
{ {
if (mCommandEnded) return false; if (mCommandEnded) return false;
if (other->id() == eTranslateNodeCmd) if (pkOther->id() == eTranslateNodeCmd)
{ {
const CTranslateNodeCommand *pCmd = static_cast<const CTranslateNodeCommand*>(other); const CTranslateNodeCommand *pkCmd = static_cast<const CTranslateNodeCommand*>(pkOther);
if (pCmd->mCommandEnded) if (pkCmd->mCommandEnded)
{ {
mCommandEnded = true; mCommandEnded = true;
return 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++) for (int iNode = 0; iNode < mNodeList.size(); iNode++)
mNodeList[iNode].newPos = pCmd->mNodeList[iNode].newPos; mNodeList[iNode].NewPos = pkCmd->mNodeList[iNode].NewPos;
return true; return true;
} }
@ -68,8 +64,8 @@ void CTranslateNodeCommand::undo()
{ {
if (!mpEditor) return; if (!mpEditor) return;
foreach (SNodeTranslate translate, mNodeList) foreach (SNodeTranslate Translate, mNodeList)
translate.pNode->SetPosition(translate.initialPos); Translate.pNode->SetPosition(Translate.InitialPos);
mpEditor->NotifySelectionTransformed(); mpEditor->NotifySelectionTransformed();
mpEditor->UpdateGizmoUI(); mpEditor->UpdateGizmoUI();
@ -79,8 +75,8 @@ void CTranslateNodeCommand::redo()
{ {
if (!mpEditor) return; if (!mpEditor) return;
foreach (SNodeTranslate translate, mNodeList) foreach (SNodeTranslate Translate, mNodeList)
translate.pNode->SetPosition(translate.newPos); Translate.pNode->SetPosition(Translate.NewPos);
mpEditor->NotifySelectionTransformed(); mpEditor->NotifySelectionTransformed();
mpEditor->UpdateGizmoUI(); mpEditor->UpdateGizmoUI();

View File

@ -2,6 +2,7 @@
#define CTRANSLATENODECOMMAND_H #define CTRANSLATENODECOMMAND_H
#include "IUndoCommand.h" #include "IUndoCommand.h"
#include "ObjReferences.h"
#include <Core/Scene/CSceneNode.h> #include <Core/Scene/CSceneNode.h>
#include "Editor/INodeEditor.h" #include "Editor/INodeEditor.h"
#include <QList> #include <QList>
@ -10,9 +11,9 @@ class CTranslateNodeCommand : public IUndoCommand
{ {
struct SNodeTranslate struct SNodeTranslate
{ {
CSceneNode *pNode; CNodePtr pNode;
CVector3f initialPos; CVector3f InitialPos;
CVector3f newPos; CVector3f NewPos;
}; };
QList<SNodeTranslate> mNodeList; QList<SNodeTranslate> mNodeList;
INodeEditor *mpEditor; INodeEditor *mpEditor;
@ -20,10 +21,9 @@ class CTranslateNodeCommand : public IUndoCommand
public: public:
CTranslateNodeCommand(); CTranslateNodeCommand();
CTranslateNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& nodes, const CVector3f& delta, ETransformSpace transformSpace); CTranslateNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& rkNodes, const CVector3f& rkDelta, ETransformSpace TransformSpace);
~CTranslateNodeCommand();
int id() const; int id() const;
bool mergeWith(const QUndoCommand *other); bool mergeWith(const QUndoCommand *pkOther);
void undo(); void undo();
void redo(); void redo();
bool AffectsCleanState() const { return true; } bool AffectsCleanState() const { return true; }

View File

@ -0,0 +1,177 @@
#ifndef OBJREFERENCES
#define OBJREFERENCES
#include <Core/Resource/CGameArea.h>
#include <Core/Resource/Script/CLink.h>
#include <Core/Resource/Script/CScriptObject.h>
#include <Core/Scene/CScene.h>
#include <Core/Scene/CSceneNode.h>
#include <QList>
/*
* 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<PtrClassName> \
{ \
public: \
ClassName() : QList<PtrClassName>() {} \
\
ClassName(const QList<DereferencedClassName>& rkIn) \
{ \
foreach (DereferencedClassName InObj, rkIn) \
{ \
*this << InObj; \
} \
} \
\
QList<DereferencedClassName> DereferenceList() const \
{ \
QList<DereferencedClassName> 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

View File

@ -35,7 +35,7 @@ CInstancesModel::CInstancesModel(QObject *pParent) : QAbstractItemModel(pParent)
mModelType = eLayers; mModelType = eLayers;
mShowColumnEnabled = true; mShowColumnEnabled = true;
mBaseItems << "Script"; mBaseItems << "Script";
mAddingOrRemovingRows = false; mChangingLayout = false;
} }
CInstancesModel::~CInstancesModel() CInstancesModel::~CInstancesModel()
@ -377,15 +377,21 @@ CScriptObject* CInstancesModel::IndexObject(const QModelIndex& index) const
// ************ PUBLIC SLOTS ************ // ************ PUBLIC SLOTS ************
void CInstancesModel::NodeAboutToBeCreated() void CInstancesModel::NodeAboutToBeCreated()
{ {
if (!mAddingOrRemovingRows) if (!mChangingLayout)
{ {
emit layoutAboutToBeChanged(); emit layoutAboutToBeChanged();
mAddingOrRemovingRows = true; mChangingLayout = true;
} }
} }
void CInstancesModel::NodeCreated(CSceneNode *pNode) void CInstancesModel::NodeCreated(CSceneNode *pNode)
{ {
if (mChangingLayout)
{
emit layoutChanged();
mChangingLayout = false;
}
if (mModelType == eTypes) if (mModelType == eTypes)
{ {
if (pNode->NodeType() == eScriptNode) if (pNode->NodeType() == eScriptNode)
@ -411,22 +417,13 @@ void CInstancesModel::NodeCreated(CSceneNode *pNode)
} }
} }
} }
emit layoutChanged();
mAddingOrRemovingRows = false;
} }
void CInstancesModel::NodeAboutToBeDeleted(CSceneNode *pNode) void CInstancesModel::NodeAboutToBeDeleted(CSceneNode *pNode)
{ {
if (!mAddingOrRemovingRows) if (pNode->NodeType() == eScriptNode)
{ {
emit layoutAboutToBeChanged(); if (mModelType == eTypes)
mAddingOrRemovingRows = true;
}
if (mModelType == eTypes)
{
if (pNode->NodeType() == eScriptNode)
{ {
CScriptNode *pScript = static_cast<CScriptNode*>(pNode); CScriptNode *pScript = static_cast<CScriptNode*>(pNode);
CScriptObject *pObj = pScript->Object(); CScriptObject *pObj = pScript->Object();
@ -439,14 +436,29 @@ void CInstancesModel::NodeAboutToBeDeleted(CSceneNode *pNode)
mTemplateList.removeOne(pObj->Template()); mTemplateList.removeOne(pObj->Template());
endRemoveRows(); endRemoveRows();
} }
else if (!mChangingLayout)
{
emit layoutAboutToBeChanged();
mChangingLayout = true;
}
}
else if (!mChangingLayout)
{
emit layoutAboutToBeChanged();
mChangingLayout = true;
} }
} }
} }
void CInstancesModel::NodeDeleted() void CInstancesModel::NodeDeleted()
{ {
emit layoutChanged(); if (mChangingLayout)
mAddingOrRemovingRows = false; {
emit layoutChanged();
mChangingLayout = false;
}
} }
void CInstancesModel::PropertyModified(CScriptObject *pInst, IProperty *pProp) void CInstancesModel::PropertyModified(CScriptObject *pInst, IProperty *pProp)

View File

@ -37,7 +37,7 @@ private:
QList<CScriptTemplate*> mTemplateList; QList<CScriptTemplate*> mTemplateList;
QStringList mBaseItems; QStringList mBaseItems;
bool mShowColumnEnabled; bool mShowColumnEnabled;
bool mAddingOrRemovingRows; bool mChangingLayout;
public: public:
explicit CInstancesModel(QObject *pParent = 0); explicit CInstancesModel(QObject *pParent = 0);

View File

@ -25,7 +25,7 @@ CPoiMapModel::CPoiMapModel(CWorldEditor *pEditor, QObject *pParent /*= 0*/)
for (u32 iPoi = 0; iPoi < mpPoiToWorld->NumMappedPOIs(); iPoi++) for (u32 iPoi = 0; iPoi < mpPoiToWorld->NumMappedPOIs(); iPoi++)
{ {
const CPoiToWorld::SPoiMap *pkMap = mpPoiToWorld->MapByIndex(iPoi); const CPoiToWorld::SPoiMap *pkMap = mpPoiToWorld->MapByIndex(iPoi);
CScriptNode *pPoiNode = mpEditor->Scene()->ScriptNodeByID(pkMap->PoiID); CScriptNode *pPoiNode = mpEditor->Scene()->NodeForInstanceID(pkMap->PoiID);
if (pPoiNode) if (pPoiNode)
{ {
@ -183,7 +183,7 @@ CScriptNode* CPoiMapModel::PoiNodePointer(const QModelIndex& rkIndex) const
if ((u32) rkIndex.row() < mpPoiToWorld->NumMappedPOIs()) if ((u32) rkIndex.row() < mpPoiToWorld->NumMappedPOIs())
{ {
const CPoiToWorld::SPoiMap *pkMap = mpPoiToWorld->MapByIndex(rkIndex.row()); const CPoiToWorld::SPoiMap *pkMap = mpPoiToWorld->MapByIndex(rkIndex.row());
return mpEditor->Scene()->ScriptNodeByID(pkMap->PoiID); return mpEditor->Scene()->NodeForInstanceID(pkMap->PoiID);
} }
return nullptr; return nullptr;

View File

@ -260,7 +260,7 @@ void WModifyTab::OnLinkTableDoubleClick(QModelIndex Index)
else if (sender() == ui->OutLinksTableView) else if (sender() == ui->OutLinksTableView)
InstanceID = pNode->Object()->Link(eOutgoing, Index.row())->ReceiverID(); InstanceID = pNode->Object()->Link(eOutgoing, Index.row())->ReceiverID();
CScriptNode *pLinkedNode = pNode->Scene()->ScriptNodeByID(InstanceID); CScriptNode *pLinkedNode = pNode->Scene()->NodeForInstanceID(InstanceID);
if (pLinkedNode) if (pLinkedNode)
mpWorldEditor->ClearAndSelectNode(pLinkedNode); mpWorldEditor->ClearAndSelectNode(pLinkedNode);

View File

@ -3,6 +3,8 @@
CVectorOutStream::CVectorOutStream() CVectorOutStream::CVectorOutStream()
{ {
mDataEndianness = IOUtil::eBigEndian; mDataEndianness = IOUtil::eBigEndian;
mpVector = new std::vector<char>;
mOwnsVector = true;
mPos = 0; mPos = 0;
mUsed = 0; mUsed = 0;
} }
@ -10,6 +12,8 @@ CVectorOutStream::CVectorOutStream()
CVectorOutStream::CVectorOutStream(IOUtil::EEndianness DataEndianness) CVectorOutStream::CVectorOutStream(IOUtil::EEndianness DataEndianness)
{ {
mDataEndianness = DataEndianness; mDataEndianness = DataEndianness;
mpVector = new std::vector<char>;
mOwnsVector = true;
mPos = 0; mPos = 0;
mUsed = 0; mUsed = 0;
} }
@ -17,23 +21,34 @@ CVectorOutStream::CVectorOutStream(IOUtil::EEndianness DataEndianness)
CVectorOutStream::CVectorOutStream(unsigned long InitialSize, IOUtil::EEndianness DataEndianness) CVectorOutStream::CVectorOutStream(unsigned long InitialSize, IOUtil::EEndianness DataEndianness)
{ {
mDataEndianness = DataEndianness; mDataEndianness = DataEndianness;
mVector.resize(InitialSize); mpVector = new std::vector<char>(InitialSize);
mOwnsVector = true;
mPos = 0;
mUsed = 0;
}
CVectorOutStream::CVectorOutStream(std::vector<char> *pVector, IOUtil::EEndianness DataEndianness)
{
mDataEndianness = DataEndianness;
mpVector = pVector;
mOwnsVector = false;
mPos = 0; mPos = 0;
mUsed = 0; mUsed = 0;
} }
CVectorOutStream::~CVectorOutStream() CVectorOutStream::~CVectorOutStream()
{ {
if (mOwnsVector) delete mpVector;
} }
void CVectorOutStream::WriteBytes(void *pSrc, unsigned long Count) void CVectorOutStream::WriteBytes(void *pSrc, unsigned long Count)
{ {
if (!IsValid()) return; if (!IsValid()) return;
if ((mPos + Count) > mVector.size()) if ((mPos + Count) > mpVector->size())
mVector.resize(mPos + Count); mpVector->resize(mPos + Count);
memcpy(mVector.data() + mPos, pSrc, Count); memcpy(mpVector->data() + mPos, pSrc, Count);
mPos += Count; mPos += Count;
if (mPos > mUsed) mUsed = mPos; if (mPos > mUsed) mUsed = mPos;
} }
@ -68,8 +83,8 @@ bool CVectorOutStream::Seek(long Offset, long Origin)
if (mPos > mUsed) if (mPos > mUsed)
mUsed = mPos; mUsed = mPos;
if (mPos > (signed long) mVector.size()) if (mPos > (signed long) mpVector->size())
mVector.resize(mPos); mpVector->resize(mPos);
return true; return true;
} }
@ -96,27 +111,35 @@ long CVectorOutStream::Size() const
long CVectorOutStream::SizeRemaining() const long CVectorOutStream::SizeRemaining() const
{ {
return mVector.size() - mPos; return mpVector->size() - mPos;
}
void CVectorOutStream::SetVector(std::vector<char> *pVector)
{
if (mOwnsVector) delete mpVector;
mpVector = pVector;
mPos = 0;
mUsed = 0;
} }
void* CVectorOutStream::Data() void* CVectorOutStream::Data()
{ {
return mVector.data(); return mpVector->data();
} }
void* CVectorOutStream::DataAtPosition() void* CVectorOutStream::DataAtPosition()
{ {
return mVector.data() + mPos; return mpVector->data() + mPos;
} }
void CVectorOutStream::Expand(unsigned long Amount) 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() void CVectorOutStream::Reset()
@ -127,6 +150,6 @@ void CVectorOutStream::Reset()
void CVectorOutStream::Clear() void CVectorOutStream::Clear()
{ {
mVector.clear(); mpVector->clear();
Reset(); Reset();
} }

View File

@ -6,7 +6,8 @@
class CVectorOutStream : public IOutputStream class CVectorOutStream : public IOutputStream
{ {
std::vector<char> mVector; std::vector<char> *mpVector;
bool mOwnsVector;
long mPos; long mPos;
long mUsed; long mUsed;
@ -14,6 +15,7 @@ public:
CVectorOutStream(); CVectorOutStream();
CVectorOutStream(IOUtil::EEndianness DataEndianness); CVectorOutStream(IOUtil::EEndianness DataEndianness);
CVectorOutStream(unsigned long InitialSize, IOUtil::EEndianness DataEndianness); CVectorOutStream(unsigned long InitialSize, IOUtil::EEndianness DataEndianness);
CVectorOutStream(std::vector<char> *pVector, IOUtil::EEndianness DataEndianness);
~CVectorOutStream(); ~CVectorOutStream();
void WriteBytes(void *pSrc, unsigned long Count); void WriteBytes(void *pSrc, unsigned long Count);
@ -23,10 +25,11 @@ public:
bool IsValid() const; bool IsValid() const;
long Size() const; long Size() const;
long SizeRemaining() const; long SizeRemaining() const;
void SetVector(std::vector<char> *pVector);
void *Data(); void *Data();
void *DataAtPosition(); void *DataAtPosition();
void Expand(unsigned long Amount); void Expand(unsigned long Amount);
void Contract(); void Shrink();
void Reset(); void Reset();
void Clear(); void Clear();
}; };