diff --git a/src/Core/Core.pro b/src/Core/Core.pro index 56a6688e..d8ce220e 100644 --- a/src/Core/Core.pro +++ b/src/Core/Core.pro @@ -251,7 +251,8 @@ HEADERS += \ Resource/StringTable/ELanguage.h \ Tweaks/CTweakManager.h \ Tweaks/CTweakData.h \ - Tweaks/CTweakLoader.h + Tweaks/CTweakLoader.h \ + Tweaks/CTweakCooker.h # Source Files SOURCES += \ @@ -365,7 +366,8 @@ SOURCES += \ Resource/Script/NGameList.cpp \ Resource/StringTable/CStringTable.cpp \ Tweaks/CTweakManager.cpp \ - Tweaks/CTweakLoader.cpp + Tweaks/CTweakLoader.cpp \ + Tweaks/CTweakCooker.cpp # Codegen CODEGEN_DIR = $$EXTERNALS_DIR/CodeGen diff --git a/src/Core/GameProject/CResourceEntry.cpp b/src/Core/GameProject/CResourceEntry.cpp index 22e5ef65..9aeec781 100644 --- a/src/Core/GameProject/CResourceEntry.cpp +++ b/src/Core/GameProject/CResourceEntry.cpp @@ -321,15 +321,15 @@ bool CResourceEntry::Save(bool SkipCacheSave /*= false*/) if (!SkipCacheSave) { mpStore->ConditionalSaveStore(); + } - // Flag dirty any packages that contain this resource. - for (uint32 iPkg = 0; iPkg < mpStore->Project()->NumPackages(); iPkg++) - { - CPackage *pPkg = mpStore->Project()->PackageByIndex(iPkg); + // Flag dirty any packages that contain this resource. + for (uint32 iPkg = 0; iPkg < mpStore->Project()->NumPackages(); iPkg++) + { + CPackage *pPkg = mpStore->Project()->PackageByIndex(iPkg); - if (pPkg->ContainsAsset(ID())) - pPkg->MarkDirty(); - } + if (pPkg->ContainsAsset(ID())) + pPkg->MarkDirty(); } if (ShouldCollectGarbage) diff --git a/src/Core/Resource/Cooker/CResourceCooker.h b/src/Core/Resource/Cooker/CResourceCooker.h index b9c03f82..4620b07c 100644 --- a/src/Core/Resource/Cooker/CResourceCooker.h +++ b/src/Core/Resource/Cooker/CResourceCooker.h @@ -6,6 +6,8 @@ #include "CPoiToWorldCooker.h" #include "CWorldCooker.h" +#include "Core/Tweaks/CTweakCooker.h" + #include "Core/GameProject/CResourceEntry.h" class CResourceCooker @@ -23,6 +25,7 @@ public: case EResourceType::Area: return CAreaCooker::CookMREA((CGameArea*) pRes, rOutput); case EResourceType::Model: return CModelCooker::CookCMDL((CModel*) pRes, rOutput); case EResourceType::StaticGeometryMap: return CPoiToWorldCooker::CookEGMC((CPoiToWorld*) pRes, rOutput); + case EResourceType::Tweaks: return CTweakCooker::CookCTWK((CTweakData*) pRes, rOutput); case EResourceType::World: return CWorldCooker::CookMLVL((CWorld*) pRes, rOutput); default: diff --git a/src/Core/Resource/Cooker/CScriptCooker.cpp b/src/Core/Resource/Cooker/CScriptCooker.cpp index 46445905..96c38f81 100644 --- a/src/Core/Resource/Cooker/CScriptCooker.cpp +++ b/src/Core/Resource/Cooker/CScriptCooker.cpp @@ -5,10 +5,9 @@ #include #include -void CScriptCooker::WriteProperty(IOutputStream& rOut, IProperty* pProperty, bool InAtomicStruct) +void CScriptCooker::WriteProperty(IOutputStream& rOut, IProperty* pProperty, void* pData, bool InAtomicStruct) { uint32 SizeOffset = 0, PropStart = 0; - void* pData = (mpArrayItemData ? mpArrayItemData : mpObject->PropertyData()); if (mGame >= EGame::EchoesDemo && !InAtomicStruct) { @@ -197,7 +196,7 @@ void CScriptCooker::WriteProperty(IOutputStream& rOut, IProperty* pProperty, boo } for (uint32 PropertyIdx = 0; PropertyIdx < PropertiesToWrite.size(); PropertyIdx++) - WriteProperty(rOut, PropertiesToWrite[PropertyIdx], pStruct->IsAtomic()); + WriteProperty(rOut, PropertiesToWrite[PropertyIdx], pData, pStruct->IsAtomic()); break; } @@ -208,15 +207,11 @@ void CScriptCooker::WriteProperty(IOutputStream& rOut, IProperty* pProperty, boo uint32 Count = pArray->ArrayCount(pData); rOut.WriteLong(Count); - void* pOldItemData = mpArrayItemData; - for (uint32 ElementIdx = 0; ElementIdx < pArray->ArrayCount(pData); ElementIdx++) { - mpArrayItemData = pArray->ItemPointer(pData, ElementIdx); - WriteProperty(rOut, pArray->ItemArchetype(), true); + WriteProperty(rOut, pArray->ItemArchetype(), pArray->ItemPointer(pData, ElementIdx), true); } - mpArrayItemData = pOldItemData; break; } @@ -231,7 +226,6 @@ void CScriptCooker::WriteProperty(IOutputStream& rOut, IProperty* pProperty, boo } } -// ************ PUBLIC ************ void CScriptCooker::WriteInstance(IOutputStream& rOut, CScriptObject *pInstance) { ASSERT(pInstance->Area()->Game() == mGame); @@ -261,8 +255,7 @@ void CScriptCooker::WriteInstance(IOutputStream& rOut, CScriptObject *pInstance) rOut.WriteLong(pLink->ReceiverID()); } - mpObject = pInstance; - WriteProperty(rOut, pInstance->Template()->Properties(), false); + WriteProperty(rOut, pInstance->Template()->Properties(), pInstance->PropertyData(), false); uint32 InstanceEnd = rOut.Tell(); rOut.Seek(SizeOffset, SEEK_SET); diff --git a/src/Core/Resource/Cooker/CScriptCooker.h b/src/Core/Resource/Cooker/CScriptCooker.h index 50ba2a2c..5db5206c 100644 --- a/src/Core/Resource/Cooker/CScriptCooker.h +++ b/src/Core/Resource/Cooker/CScriptCooker.h @@ -10,21 +10,16 @@ class CScriptCooker { EGame mGame; - CScriptObject* mpObject; - void* mpArrayItemData; std::vector mGeneratedObjects; bool mWriteGeneratedSeparately; - void WriteProperty(IOutputStream& rOut, IProperty* pProperty, bool InAtomicStruct); - public: CScriptCooker(EGame Game, bool WriteGeneratedObjectsSeparately = true) : mGame(Game) - , mpObject(nullptr) - , mpArrayItemData(nullptr) , mWriteGeneratedSeparately(WriteGeneratedObjectsSeparately && mGame >= EGame::EchoesDemo) {} + void WriteProperty(IOutputStream& rOut, IProperty* pProperty, void* pData, bool InAtomicStruct); void WriteInstance(IOutputStream& rOut, CScriptObject *pInstance); void WriteLayer(IOutputStream& rOut, CScriptLayer *pLayer); void WriteGeneratedLayer(IOutputStream& rOut); diff --git a/src/Core/Tweaks/CTweakCooker.cpp b/src/Core/Tweaks/CTweakCooker.cpp new file mode 100644 index 00000000..177197ec --- /dev/null +++ b/src/Core/Tweaks/CTweakCooker.cpp @@ -0,0 +1,17 @@ +#include "CTweakCooker.h" +#include "Core/Resource/Cooker/CScriptCooker.h" + +/** Cooker entry point */ +bool CTweakCooker::CookCTWK(CTweakData* pTweakData, IOutputStream& CTWK) +{ + CStructRef TweakProperties = pTweakData->TweakData(); + CScriptCooker ScriptCooker(pTweakData->Game()); + ScriptCooker.WriteProperty(CTWK, TweakProperties.Property(), TweakProperties.DataPointer(), true); + return true; +} + +bool CTweakCooker::CookNTWK(const std::vector& kTweaks, IOutputStream& NTWK) +{ + // Unimplemented + return false; +} diff --git a/src/Core/Tweaks/CTweakCooker.h b/src/Core/Tweaks/CTweakCooker.h new file mode 100644 index 00000000..06232f19 --- /dev/null +++ b/src/Core/Tweaks/CTweakCooker.h @@ -0,0 +1,18 @@ +#ifndef CTWEAKCOOKER_H +#define CTWEAKCOOKER_H + +#include "CTweakData.h" + +/** Class responsible for cooking tweak data */ +class CTweakCooker +{ + /** Private constructor */ + CTweakCooker() {} + +public: + /** Cooker entry point */ + static bool CookCTWK(CTweakData* pTweakData, IOutputStream& CTWK); + static bool CookNTWK(const std::vector& kTweaks, IOutputStream& NTWK); +}; + +#endif // CTWEAKCOOKER_H diff --git a/src/Editor/CTweakEditor.cpp b/src/Editor/CTweakEditor.cpp index eb189a12..ed82afd8 100644 --- a/src/Editor/CTweakEditor.cpp +++ b/src/Editor/CTweakEditor.cpp @@ -15,6 +15,8 @@ CTweakEditor::CTweakEditor(QWidget* pParent) SET_WINDOWTITLE_APPVARS("%APP_FULL_NAME% - Tweak Editor[*]"); connect(mpUI->TweakTabs, SIGNAL(currentChanged(int)), this, SLOT(OnTweakTabClicked(int))); + connect(mpUI->ActionSave, SIGNAL(triggered(bool)), this, SLOT(Save())); + connect(mpUI->ActionSaveAndRepack, SIGNAL(triggered(bool)), this, SLOT(SaveAndRepack())); } CTweakEditor::~CTweakEditor() @@ -27,6 +29,31 @@ bool CTweakEditor::HasTweaks() return !mTweakAssets.isEmpty(); } +bool CTweakEditor::Save() +{ + bool SavedAll = true; + + foreach (CTweakData* pData, mTweakAssets) + { + if (!pData->Entry()->Save()) + { + SavedAll = false; + } + } + + if (!SavedAll) + { + UICommon::ErrorMsg(this, "Tweaks failed to save!"); + return false; + } + else + { + UndoStack().setClean(); + setWindowModified(false); + return true; + } +} + void CTweakEditor::showEvent(QShowEvent* pEvent) { // Perform first-time UI initialization diff --git a/src/Editor/CTweakEditor.h b/src/Editor/CTweakEditor.h index c1fe2556..72f135ed 100644 --- a/src/Editor/CTweakEditor.h +++ b/src/Editor/CTweakEditor.h @@ -28,6 +28,7 @@ public: ~CTweakEditor(); bool HasTweaks(); + virtual bool Save() override; virtual void showEvent(QShowEvent* pEvent) override; public slots: diff --git a/src/Editor/IEditor.h b/src/Editor/IEditor.h index 2195a764..0f96c055 100644 --- a/src/Editor/IEditor.h +++ b/src/Editor/IEditor.h @@ -38,7 +38,7 @@ public slots: { // Default implementation for editor windows that do not support resaving assets. // This should not be called. - warnf("Base IEditor::Save() implementation called. Changes will not be saved."); + errorf("Base IEditor::Save() implementation called. Changes will not be saved."); return true; }