From 8b84b638ac5e9fa7e57f99f3759b45d327e9c30c Mon Sep 17 00:00:00 2001 From: Aruki Date: Wed, 5 Jul 2017 01:10:57 -0600 Subject: [PATCH] Fixed all DKCR name generation issues --- src/Common/FileUtil.cpp | 19 ++++++++++--------- src/Common/TString.cpp | 10 ++++++++++ src/Common/TString.h | 10 ++++++++++ src/Core/GameProject/AssetNameGeneration.cpp | 6 +++--- src/Core/GameProject/CVirtualDirectory.cpp | 5 ++++- .../Resource/Animation/IMetaAnimation.cpp | 7 +++++++ src/Core/Resource/Animation/IMetaAnimation.h | 7 +++++++ src/Core/Resource/Factory/CAnimSetLoader.cpp | 9 ++++++++- src/Core/Resource/Factory/CAreaLoader.cpp | 4 +++- .../ResourceBrowser/CResourceBrowser.cpp | 3 +++ templates/dkcr/Script/AreaNode.xml | 4 ++++ 11 files changed, 69 insertions(+), 15 deletions(-) diff --git a/src/Common/FileUtil.cpp b/src/Common/FileUtil.cpp index 100ab243..7952e5b3 100644 --- a/src/Common/FileUtil.cpp +++ b/src/Common/FileUtil.cpp @@ -9,6 +9,7 @@ using namespace boost::filesystem; // Macro encapsulating a TString -> boost::filesystem::path conversion // boost does not handle conversion from UTF-8 correctly so we need to do it manually #define TO_PATH(String) path( *String.ToUTF16() ) +#define FROM_PATH(Path) TWideString( Path.native() ).ToUTF8() namespace FileUtil { @@ -203,7 +204,7 @@ u64 LastModifiedTime(const TString& rkFilePath) TString WorkingDirectory() { - return boost::filesystem::current_path().string(); + return FROM_PATH( boost::filesystem::current_path() ); } TString MakeAbsolute(TString Path) @@ -305,11 +306,11 @@ TString SanitizeName(TString Name, bool Directory, bool RootDir /*= false*/) return Name; // Remove illegal characters from path - u32 NumIllegalChars = sizeof(gskIllegalNameChars) / sizeof(wchar_t); + u32 NumIllegalChars = sizeof(gskIllegalNameChars) / sizeof(char); for (u32 iChr = 0; iChr < Name.Size(); iChr++) { - wchar_t Chr = Name[iChr]; + char Chr = Name[iChr]; bool Remove = false; if (Chr >= 0 && Chr <= 31) @@ -345,7 +346,7 @@ TString SanitizeName(TString Name, bool Directory, bool RootDir /*= false*/) for (int iChr = (int) Name.Size() - 1; iChr >= 0; iChr--) { - wchar_t Chr = Name[iChr]; + char Chr = Name[iChr]; if (Chr == ' ' || Chr == '.') ChopNum++; @@ -405,7 +406,7 @@ bool IsValidName(const TString& rkName, bool Directory, bool RootDir /*= false*/ if (rkName.Size() > 255) return false; - u32 NumIllegalChars = sizeof(gskIllegalNameChars) / sizeof(wchar_t); + u32 NumIllegalChars = sizeof(gskIllegalNameChars) / sizeof(char); if (Directory && (rkName == "." || rkName == "..")) return true; @@ -413,7 +414,7 @@ bool IsValidName(const TString& rkName, bool Directory, bool RootDir /*= false*/ // Check for banned characters for (u32 iChr = 0; iChr < rkName.Size(); iChr++) { - wchar_t Chr = rkName[iChr]; + char Chr = rkName[iChr]; if (Chr >= 0 && Chr <= 31) return false; @@ -476,7 +477,7 @@ void GetDirectoryContents(TString DirPath, TStringList& rOut, bool Recursive /*= { for (recursive_directory_iterator It( TO_PATH(DirPath) ); It != recursive_directory_iterator(); ++It) { - AddFileLambda( It->path().string() ); + AddFileLambda( FROM_PATH(It->path()) ); } } @@ -484,7 +485,7 @@ void GetDirectoryContents(TString DirPath, TStringList& rOut, bool Recursive /*= { for (directory_iterator It( TO_PATH(DirPath) ); It != directory_iterator(); ++It) { - AddFileLambda( It->path().string() ); + AddFileLambda( FROM_PATH(It->path()) ); } } } @@ -494,7 +495,7 @@ TString FindFileExtension(const TString& rkDir, const TString& rkName) { for (directory_iterator It( TO_PATH(rkDir) ); It != directory_iterator(); ++It) { - TString Name = It->path().filename().string(); + TString Name = FROM_PATH( It->path().filename() ); if (Name.GetFileName(false) == rkName) return Name.GetFileExtension(); } diff --git a/src/Common/TString.cpp b/src/Common/TString.cpp index a1972f46..2e4b2b23 100644 --- a/src/Common/TString.cpp +++ b/src/Common/TString.cpp @@ -22,6 +22,8 @@ u64 TString::Hash64() const TWideString TString::ToUTF16() const { TWideString Out; + Out.Reserve(Size()); + const char *pkCStr = CString(); while (pkCStr[0]) @@ -86,12 +88,20 @@ TWideString TString::ToUTF16() const pkCStr += 6; } + // Invalid? + else + { + CodePoint = pkCStr[0]; + pkCStr++; + } + // Step 2: Append to output string if ( ((CodePoint >= 0) && (CodePoint <= 0xD7FF)) || ((CodePoint >= 0xE000) && (CodePoint <= 0xFFFF)) ) Out.Append((wchar_t) (CodePoint & 0xFFFF)); } + Out.Shrink(); return Out; } diff --git a/src/Common/TString.h b/src/Common/TString.h index 3e04eea3..cb8b5bbb 100644 --- a/src/Common/TString.h +++ b/src/Common/TString.h @@ -214,6 +214,16 @@ public: return mInternalString.substr(StartPos, Length); } + inline void Reserve(u32 Amount) + { + mInternalString.reserve(Amount); + } + + inline void Shrink() + { + mInternalString.shrink_to_fit(); + } + inline void Insert(u32 Pos, CharType Chr) { #ifdef _DEBUG diff --git a/src/Core/GameProject/AssetNameGeneration.cpp b/src/Core/GameProject/AssetNameGeneration.cpp index 0ac8caa6..ef5ebe8f 100644 --- a/src/Core/GameProject/AssetNameGeneration.cpp +++ b/src/Core/GameProject/AssetNameGeneration.cpp @@ -97,7 +97,7 @@ void GenerateAssetNames(CGameProject *pProj) TString NewDir = (HasCustomDir ? It->DirectoryPath() : "Uncategorized/"); TString NewName = (HasCustomName ? It->Name() : It->ID().ToString()); - It->Move(NewDir, NewName); + It->Move(NewDir, NewName, true, true); } #endif @@ -131,7 +131,7 @@ void GenerateAssetNames(CGameProject *pProj) for (TResourceIterator It(pStore); It; ++It) { // Set world name - CWorld *pWorld = (CWorld*) It->Load(); + TResPtr pWorld = It->Load(); TString WorldName = pWorld->Name(); TString WorldDir = kWorldsRoot + WorldName + '/'; @@ -205,7 +205,7 @@ void GenerateAssetNames(CGameProject *pProj) // Rename area stuff CResourceEntry *pAreaEntry = pStore->FindEntry(AreaID); - ASSERT(pAreaEntry != nullptr); + if (!pAreaEntry) continue; // Some DKCR worlds reference areas that don't exist ApplyGeneratedName(pAreaEntry, WorldMasterDir, AreaName); CStringTable *pAreaNameTable = pWorld->AreaName(iArea); diff --git a/src/Core/GameProject/CVirtualDirectory.cpp b/src/Core/GameProject/CVirtualDirectory.cpp index a3392cf3..bc7039e7 100644 --- a/src/Core/GameProject/CVirtualDirectory.cpp +++ b/src/Core/GameProject/CVirtualDirectory.cpp @@ -204,7 +204,7 @@ bool CVirtualDirectory::RemoveChildDirectory(CVirtualDirectory *pSubdir) // If this is part of the resource store, delete the corresponding filesystem directory if (mpStore && pSubdir->GetRoot() == mpStore->RootDirectory()) { - TString AbsPath = mpStore->DatabaseRootPath() + pSubdir->FullPath(); + TString AbsPath = mpStore->ResourcesDir() + pSubdir->FullPath(); FileUtil::DeleteDirectory(AbsPath, true); } @@ -237,7 +237,10 @@ void CVirtualDirectory::RemoveEmptySubdirectories() CVirtualDirectory *pDir = mSubdirectories[SubdirIdx]; if (pDir->IsEmpty()) + { RemoveChildDirectory(pDir); + SubdirIdx--; + } else pDir->RemoveEmptySubdirectories(); } diff --git a/src/Core/Resource/Animation/IMetaAnimation.cpp b/src/Core/Resource/Animation/IMetaAnimation.cpp index e7752cdf..6dbec57c 100644 --- a/src/Core/Resource/Animation/IMetaAnimation.cpp +++ b/src/Core/Resource/Animation/IMetaAnimation.cpp @@ -29,6 +29,13 @@ IMetaAnimation* CMetaAnimFactory::LoadFromStream(IInputStream& rInput, EGame Gam } // ************ CMetaAnimationPlay ************ +CMetaAnimPlay::CMetaAnimPlay(const CAnimPrimitive& rkPrimitive, float UnkA, u32 UnkB) + : mPrimitive(rkPrimitive) + , mUnknownA(UnkA) + , mUnknownB(UnkB) +{ +} + CMetaAnimPlay::CMetaAnimPlay(IInputStream& rInput, EGame Game) { mPrimitive = CAnimPrimitive(rInput, Game); diff --git a/src/Core/Resource/Animation/IMetaAnimation.h b/src/Core/Resource/Animation/IMetaAnimation.h index e72bb29f..dded5923 100644 --- a/src/Core/Resource/Animation/IMetaAnimation.h +++ b/src/Core/Resource/Animation/IMetaAnimation.h @@ -32,6 +32,12 @@ class CAnimPrimitive public: CAnimPrimitive() : mID(0) {} + CAnimPrimitive(const CAssetID& rkAnimAssetID, u32 CharAnimID, const TString& rkAnimName) + : mID(CharAnimID), mName(rkAnimName) + { + mpAnim = gpResourceStore->LoadResource(rkAnimAssetID); + } + CAnimPrimitive(IInputStream& rInput, EGame Game) { mpAnim = gpResourceStore->LoadResource( CAssetID(rInput, Game) ); @@ -70,6 +76,7 @@ protected: u32 mUnknownB; public: + CMetaAnimPlay(const CAnimPrimitive& rkPrimitive, float UnkA, u32 UnkB); CMetaAnimPlay(IInputStream& rInput, EGame Game); virtual EMetaAnimationType Type() const; virtual void GetUniquePrimitives(std::set& rPrimSet) const; diff --git a/src/Core/Resource/Factory/CAnimSetLoader.cpp b/src/Core/Resource/Factory/CAnimSetLoader.cpp index 8087c697..9bf2ffed 100644 --- a/src/Core/Resource/Factory/CAnimSetLoader.cpp +++ b/src/Core/Resource/Factory/CAnimSetLoader.cpp @@ -137,10 +137,16 @@ CAnimSet* CAnimSetLoader::LoadReturnsCHAR(IInputStream& rCHAR) for (u32 AnimIdx = 0; AnimIdx < NumAnims; AnimIdx++) { - rCHAR.ReadString(); + TString AnimName = rCHAR.ReadString(); CAssetID AnimID(rCHAR, eReturns); rCHAR.Skip(0x25); rChar.DKDependencies.push_back(AnimID); + + // small hack - create a meta-anim for it so we can generate asset names for the ANIM files correctly + SAnimation Anim; + Anim.Name = AnimName; + Anim.pMetaAnim = new CMetaAnimPlay( CAnimPrimitive(AnimID, AnimIdx, AnimName), 0.f, 0 ); + pSet->mAnimations.push_back(Anim); } // The only other thing we care about right now is the dependency list. If this file doesn't have a dependency list, exit out. @@ -229,6 +235,7 @@ CAnimSet* CAnimSetLoader::LoadReturnsCHAR(IInputStream& rCHAR) } } + ProcessPrimitives(); return pSet; } diff --git a/src/Core/Resource/Factory/CAreaLoader.cpp b/src/Core/Resource/Factory/CAreaLoader.cpp index c63888d5..ab12dc9d 100644 --- a/src/Core/Resource/Factory/CAreaLoader.cpp +++ b/src/Core/Resource/Factory/CAreaLoader.cpp @@ -624,7 +624,9 @@ void CAreaLoader::SetUpObjects(CScriptLayer *pGenLayer) // Check if this is a duplicate of an existing instance (this only happens with DKCR GenericCreature as far as I'm aware) if (mpArea->InstanceByID(InstanceID) != nullptr) { - Log::Write("Duplicate SCGN object: [" + pInst->Template()->Name() + "] " + pInst->InstanceName() + " (" + TString::HexString(pInst->InstanceID(), 8, false) + ")"); + if (pInst->ObjectTypeID() != FOURCC('GCTR')) + Log::Write("Duplicate SCGN object: [" + pInst->Template()->Name() + "] " + pInst->InstanceName() + " (" + TString::HexString(pInst->InstanceID(), 8, false) + ")"); + pGenLayer->RemoveInstance(pInst); delete pInst; } diff --git a/src/Editor/ResourceBrowser/CResourceBrowser.cpp b/src/Editor/ResourceBrowser/CResourceBrowser.cpp index 69b2f789..548a0fb7 100644 --- a/src/Editor/ResourceBrowser/CResourceBrowser.cpp +++ b/src/Editor/ResourceBrowser/CResourceBrowser.cpp @@ -335,6 +335,9 @@ void CResourceBrowser::OnGenerateAssetNames() Dialog.DisallowCanceling(); Dialog.SetOneShotTask("Generating asset names"); + // Temporarily set root to null to ensure the window doesn't access the resource store while we're running. + mpDirectoryModel->SetRoot(mpStore->RootDirectory()); + QFuture Future = QtConcurrent::run(&GenerateAssetNames, mpStore->Project()); Dialog.WaitForResults(Future); diff --git a/templates/dkcr/Script/AreaNode.xml b/templates/dkcr/Script/AreaNode.xml index ae47be49..132f8480 100644 --- a/templates/dkcr/Script/AreaNode.xml +++ b/templates/dkcr/Script/AreaNode.xml @@ -71,6 +71,10 @@ 0.0, 0.0, 0.0, 1.0 + + false + This property was likely used in debug builds. It is not read by the game and has no ingame effect. +