1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
4 #include "DialogManager.h"
5 #include <CryString/CryPath.h>
6 #include <CryAudio/IAudioSystem.h>
7 #include <CryAudio/Dialog/IDialogSystem.h>
8 #include <ISourceControl.h>
9 #include <CryString/StringUtils.h>
10 #include "Util/FileUtil.h"
12 #define GameWarning Warning
13 #define DIALOGSCRIPT_PATH "/Libs/Dialogs/"
17 static const CEditorDialogScript::TActorID MASK_ALL
= ~CEditorDialogScript::TActorID(0);
18 static const CEditorDialogScript::TActorID MASK_01010101
= MASK_ALL
/ 3;
19 static const CEditorDialogScript::TActorID MASK_00110011
= MASK_ALL
/ 5;
20 static const CEditorDialogScript::TActorID MASK_00001111
= MASK_ALL
/ 17;
22 ILINE
void bit_set(CEditorDialogScript::TActorID
& n
, int which
)
27 ILINE
void bit_clear(CEditorDialogScript::TActorID
& n
, int which
)
29 n
&= ~(0x01 << which
);
32 ILINE
bool is_bit_set(CEditorDialogScript::TActorID
& n
, int which
)
34 return (n
& (0x01 << which
)) != 0;
37 ILINE
int bit_count(CEditorDialogScript::TActorID n
)
39 n
= (n
& MASK_01010101
) + ((n
>> 1) & MASK_01010101
);
40 n
= (n
& MASK_00110011
) + ((n
>> 2) & MASK_00110011
);
41 n
= (n
& MASK_00001111
) + ((n
>> 4) & MASK_00001111
);
46 void CEditorDialogScript::SActorSet::SetActor(TActorID id
)
48 bit_set(m_actorBits
, id
);
51 void CEditorDialogScript::SActorSet::ResetActor(TActorID id
)
53 bit_clear(m_actorBits
, id
);
56 bool CEditorDialogScript::SActorSet::HasActor(TActorID id
)
58 return is_bit_set(m_actorBits
, id
);
61 int CEditorDialogScript::SActorSet::NumActors() const
63 return bit_count(m_actorBits
);
66 bool CEditorDialogScript::SActorSet::Matches(const CEditorDialogScript::SActorSet
& other
) const
68 return m_actorBits
== other
.m_actorBits
;
71 bool CEditorDialogScript::SActorSet::Satisfies(const CEditorDialogScript::SActorSet
& other
) const
73 return (m_actorBits
& other
.m_actorBits
) == other
.m_actorBits
;
76 ////////////////////////////////////////////////////////////////////////////
77 CEditorDialogScript::CEditorDialogScript(const string
& dialogID
) : m_id(dialogID
), m_reqActorSet(0), m_scFileAttributes(SCC_FILE_ATTRIBUTE_INVALID
)
81 ////////////////////////////////////////////////////////////////////////////
82 CEditorDialogScript::~CEditorDialogScript()
86 ////////////////////////////////////////////////////////////////////////////
87 // Add one line after another
88 bool CEditorDialogScript::AddLine(const SScriptLine
& line
)
90 if (line
.m_actor
< 0 || line
.m_actor
>= MAX_ACTORS
)
92 CryWarning(VALIDATOR_MODULE_EDITOR
, VALIDATOR_WARNING
, "CEditorDialogScript::AddLine: Script='%s' Cannot add line because actorID %d is out of range [0..%d]", m_id
.c_str(), line
.m_actor
, MAX_ACTORS
- 1);
96 if (line
.m_lookatActor
!= NO_ACTOR_ID
&& line
.m_lookatActor
!= STICKY_LOOKAT_RESET_ID
&& (line
.m_lookatActor
< 0 || line
.m_lookatActor
>= MAX_ACTORS
))
98 CryWarning(VALIDATOR_MODULE_EDITOR
, VALIDATOR_WARNING
, "CEditorDialogScript::AddLine: Script='%s' Cannot add line because lookAtTargetID %d is out of range [0..%d]", m_id
.c_str(), line
.m_lookatActor
, MAX_ACTORS
- 1);
102 m_lines
.push_back(line
);
103 m_reqActorSet
.SetActor(line
.m_actor
);
104 if (line
.m_lookatActor
!= NO_ACTOR_ID
&& line
.m_lookatActor
!= STICKY_LOOKAT_RESET_ID
)
105 m_reqActorSet
.SetActor(line
.m_lookatActor
);
110 ////////////////////////////////////////////////////////////////////////////
111 // Retrieves number of required actors
112 int CEditorDialogScript::GetNumRequiredActors() const
114 return m_reqActorSet
.NumActors();
117 ////////////////////////////////////////////////////////////////////////////
118 // Get number of dialog lines
119 int CEditorDialogScript::GetNumLines() const
121 return m_lines
.size();
124 ////////////////////////////////////////////////////////////////////////////
125 // Get a certain line
126 const CEditorDialogScript::SScriptLine
* CEditorDialogScript::GetLine(int index
) const
128 assert(index
>= 0 && index
< m_lines
.size());
129 if (index
>= 0 && index
< m_lines
.size())
130 return &m_lines
[index
];
134 ////////////////////////////////////////////////////////////////////////////
135 CDialogManager::CDialogManager()
140 ////////////////////////////////////////////////////////////////////////////
141 CDialogManager::~CDialogManager()
144 SyncCryActionScripts();
147 ////////////////////////////////////////////////////////////////////////////
148 void CDialogManager::SyncCryActionScripts()
150 if (GetISystem()->GetIDialogSystem())
151 GetISystem()->GetIDialogSystem()->ReloadScripts(NULL
);
154 ////////////////////////////////////////////////////////////////////////////
155 void CDialogManager::DeleteAllScripts()
157 TEditorDialogScriptMap::iterator iter
= m_scripts
.begin();
158 while (iter
!= m_scripts
.end())
166 void MakeID(string
& path
)
168 path
.replace('/', '.');
171 void MakePath(string
& id
)
173 id
.replace('.', '/');
176 // Game relative path
177 CString
CDialogManager::ScriptToFilename(const CString
& id
)
179 CString filename
= id
;
180 filename
.Replace('.', '/');
181 CString path
= PathUtil::GetGameFolder() + DIALOGSCRIPT_PATH
;
184 return path
; // Path::GamePathToFullPath(path);
187 CString
CDialogManager::FilenameToScript(const CString
& id
)
189 CString filename
= PathUtil::RemoveExtension(id
.GetString()).c_str();
190 filename
= PathUtil::ToUnixPath(filename
.GetString()).c_str();
191 CString dataPath
= PathUtil::GetGameFolder() + DIALOGSCRIPT_PATH
;
192 dataPath
= PathUtil::ToUnixPath(dataPath
.GetString()).c_str();
193 if (filename
.GetLength() > (dataPath
.GetLength()) && strnicmp(filename
, dataPath
, dataPath
.GetLength()) == 0)
195 filename
= filename
.Mid(dataPath
.GetLength() + 1); // skip the slash...
197 filename
.Replace('/', '.');
201 ////////////////////////////////////////////////////////////////////////////
202 bool CDialogManager::ReloadScripts()
206 string path
= PathUtil::GetGameFolder() + DIALOGSCRIPT_PATH
;
208 std::vector
<CFileUtil::FileDesc
> files
;
209 CFileUtil::ScanDirectory(path
, "*.dlg", files
, true);
210 for (int iFile
= 0; iFile
< files
.size(); ++iFile
)
212 string dlgID
= PathUtil::ToUnixPath(files
[iFile
].filename
.GetString());
213 PathUtil::RemoveExtension(dlgID
);
216 string filename
= path
;
217 filename
+= files
[iFile
].filename
;
220 CString sID
= FilenameToScript(files
[iFile
].filename
.GetString());
222 XmlNodeRef node
= XmlHelpers::LoadXmlFromFile(filename
);
223 if (node
&& node
->isTag("DialogScript"))
225 CEditorDialogScript
* pScript
= new CEditorDialogScript(dlgID
);
226 CEditorDialogScriptSerializer
ser(pScript
);
227 bool bOK
= ser
.Load(node
);
230 TEditorDialogScriptMap::iterator iter
= m_scripts
.find(pScript
->GetID());
231 if (iter
!= m_scripts
.end())
233 m_scripts
[pScript
->GetID()] = pScript
; // this overrides previous contents if any
244 ////////////////////////////////////////////////////////////////////////////
245 bool CDialogManager::SaveAllScripts()
248 TEditorDialogScriptMap::iterator iter
= m_scripts
.begin();
249 while (iter
!= m_scripts
.end())
251 ok
&= SaveScript(iter
->second
, false);
254 SyncCryActionScripts();
258 ////////////////////////////////////////////////////////////////////////////
259 CEditorDialogScript
* CDialogManager::LoadScript(string
& name
, bool bReplace
)
261 CEditorDialogScript
* pScript
= GetScript(name
, false);
262 if (pScript
&& !bReplace
)
266 DeleteScript(pScript
, false);
272 string path
= PathUtil::GetGameFolder() + DIALOGSCRIPT_PATH
;
277 CString sPath
= ScriptToFilename(CString(name
));
279 XmlNodeRef node
= XmlHelpers::LoadXmlFromFile(path
);
280 if (node
&& node
->isTag("DialogScript"))
282 pScript
= new CEditorDialogScript(name
);
283 CEditorDialogScriptSerializer
ser(pScript
);
284 bool bOK
= ser
.Load(node
);
287 m_scripts
.insert(TEditorDialogScriptMap::value_type(pScript
->GetID(), pScript
));
298 ////////////////////////////////////////////////////////////////////////////
299 bool CDialogManager::SaveScript(CEditorDialogScript
* pScript
, bool bSync
, bool bBackup
)
301 CEditorDialogScriptSerializer
ser(pScript
);
302 XmlNodeRef node
= XmlHelpers::CreateXmlNode("DialogScript");
303 bool bOK
= ser
.Save(node
);
306 string idPath
= pScript
->GetID();
308 string path
= PathUtil::GetGameFolder() + DIALOGSCRIPT_PATH
;
312 CString sPath
= ScriptToFilename(CString(pScript
->GetID()));
317 CFileUtil::BackupFile(path
);
320 CFileUtil::CreateDirectory(PathUtil::GetPathWithoutFilename(path
));
321 bOK
= XmlHelpers::SaveXmlNode(node
, path
);
324 SyncCryActionScripts();
330 ////////////////////////////////////////////////////////////////////////////
331 CEditorDialogScript
* CDialogManager::GetScript(const string
& name
, bool bForceCreate
)
333 CEditorDialogScript
* pScript
= stl::find_in_map(m_scripts
, name
, 0);
334 if (pScript
== 0 && bForceCreate
)
336 pScript
= new CEditorDialogScript(name
);
337 m_scripts
.insert(TEditorDialogScriptMap::value_type(name
, pScript
));
342 ////////////////////////////////////////////////////////////////////////////
343 CEditorDialogScript
* CDialogManager::GetScript(const CString
& name
, bool bForceCreate
)
346 return GetScript(sName
, bForceCreate
);
349 ////////////////////////////////////////////////////////////////////////////
350 bool CDialogManager::DeleteScript(CEditorDialogScript
* pScript
, bool bDeleteFromDisk
)
352 TEditorDialogScriptMap::iterator iter
= m_scripts
.find(pScript
->GetID());
353 if (iter
== m_scripts
.end())
356 assert(pScript
== iter
->second
);
360 string idPath
= pScript
->GetID();
362 string path
= PathUtil::GetGameFolder() + DIALOGSCRIPT_PATH
;
369 m_scripts
.erase(iter
);
373 SyncCryActionScripts();
379 ////////////////////////////////////////////////////////////////////////////
380 bool CDialogManager::RenameScript(CEditorDialogScript
* pScript
, string
& newName
, bool bDeleteFromDisk
)
382 TEditorDialogScriptMap::iterator iter
= m_scripts
.find(newName
);
383 if (iter
!= m_scripts
.end())
387 iter
= m_scripts
.find(pScript
->GetID());
388 assert(pScript
== iter
->second
);
390 string idPath
= pScript
->GetID();
392 string oldPath
= PathUtil::GetGameFolder() + DIALOGSCRIPT_PATH
;
397 string newID
= newName
;
398 pScript
->SetID(newName
);
400 // save the script in new location
401 bool bSaveOK
= SaveScript(pScript
);
405 // erase old from map and insert new
406 m_scripts
.erase(iter
);
407 m_scripts
.insert(TEditorDialogScriptMap::value_type(newName
, pScript
));
411 // delete old file from disk
412 ::DeleteFile(oldPath
);
413 SyncCryActionScripts();
419 ////////////////////////////////////////////////////////////////////////////
420 uint32
CDialogManager::GetFileAttrs(CEditorDialogScript
* pScript
, bool bUpdateFromFile
)
422 CString id
= pScript
->GetID();
423 CString filename
= ScriptToFilename(id
);
424 if (bUpdateFromFile
|| pScript
->m_scFileAttributes
== SCC_FILE_ATTRIBUTE_INVALID
)
426 pScript
->m_scFileAttributes
= CFileUtil::GetAttributes(filename
);
428 return pScript
->m_scFileAttributes
;
431 ////////////////////////////////////////////////////////////////////////////
432 bool CDialogManager::CanModify(CEditorDialogScript
* pScript
)
434 uint32 scAttr
= GetFileAttrs(pScript
, true);
435 // If read only or in pack, do not save.
436 if (scAttr
& (SCC_FILE_ATTRIBUTE_READONLY
| SCC_FILE_ATTRIBUTE_INPAK
))
439 // Managed file must be checked out or not read-only
441 if ((scAttr
& SCC_FILE_ATTRIBUTE_MANAGED
) && (scAttr
& SCC_FILE_ATTRIBUTE_NORMAL
) && !(scAttr
& SCC_FILE_ATTRIBUTE_READONLY
))
444 if ((scAttr
& SCC_FILE_ATTRIBUTE_MANAGED
) && !(scAttr
& SCC_FILE_ATTRIBUTE_CHECKEDOUT
))
450 ////////////////////////////////////////////////////////////////////////////
451 CEditorDialogScriptSerializer::CEditorDialogScriptSerializer(CEditorDialogScript
* pScript
)
453 assert(pScript
!= 0);
457 ////////////////////////////////////////////////////////////////////////////
458 bool CEditorDialogScriptSerializer::Load(XmlNodeRef node
)
460 if (node
->isTag("DialogScript") == false)
463 const char* storedId
= node
->getAttr("Name");
464 if (storedId
&& stricmp(storedId
, m_pScript
->m_id
.c_str()) == 0)
466 m_pScript
->m_id
= storedId
;
469 m_pScript
->m_description
= node
->getAttr("Description");
470 CEditorDialogScript::SScriptLine line
;
471 for (int i
= 0; i
< node
->getChildCount(); ++i
)
473 XmlNodeRef lineNode
= node
->getChild(i
);
474 if (lineNode
&& lineNode
->isTag("Line"))
476 // read line attributes
478 if (ReadLine(lineNode
, line
) == true)
479 m_pScript
->AddLine(line
);
485 ////////////////////////////////////////////////////////////////////////////
486 bool CEditorDialogScriptSerializer::Save(XmlNodeRef node
)
488 node
->setAttr("Name", m_pScript
->m_id
);
489 node
->setAttr("Description", m_pScript
->m_description
);
490 int nLineCount
= m_pScript
->GetNumLines();
491 for (int i
= 0; i
< nLineCount
; ++i
)
493 XmlNodeRef lineNode
= node
->newChild("Line");
494 const CEditorDialogScript::SScriptLine
* pLine
= m_pScript
->GetLine(i
);
495 WriteLine(lineNode
, *pLine
);
500 ////////////////////////////////////////////////////////////////////////////
501 bool CEditorDialogScriptSerializer::ReadLine(const XmlNodeRef
& lineNode
, CEditorDialogScript::SScriptLine
& line
)
504 lineNode
->getAttr("actor", line
.m_actor
);
505 lineNode
->getAttr("lookatActor", line
.m_lookatActor
);
506 if (lineNode
->getAttr("flagLookAtSticky", tmp
)) line
.m_flagLookAtSticky
= tmp
;
507 if (lineNode
->getAttr("flagSoundStopsAnim", tmp
)) line
.m_flagSoundStopsAnim
= tmp
;
508 if (lineNode
->getAttr("flagAGSignal", tmp
)) line
.m_flagAGSignal
= tmp
;
509 if (lineNode
->getAttr("flagAGEP", tmp
)) line
.m_flagAGEP
= tmp
;
510 //lineNode->getAttr("audioID", line.m_audioID);
511 line
.m_audioTriggerName
= lineNode
->getAttr("audioID");
512 line
.m_anim
= lineNode
->getAttr("anim");
513 line
.m_facial
= lineNode
->getAttr("facial");
514 lineNode
->getAttr("delay", line
.m_delay
);
515 lineNode
->getAttr("facialWeight", line
.m_facialWeight
);
516 lineNode
->getAttr("facialFadeTime", line
.m_facialFadeTime
);
517 line
.m_desc
= lineNode
->getAttr("desc");
521 ////////////////////////////////////////////////////////////////////////////
522 bool CEditorDialogScriptSerializer::WriteLine(XmlNodeRef lineNode
, const CEditorDialogScript::SScriptLine
& line
)
524 lineNode
->setAttr("actor", line
.m_actor
);
525 lineNode
->setAttr("lookatActor", line
.m_lookatActor
);
526 lineNode
->setAttr("flagLookAtSticky", line
.m_flagLookAtSticky
);
527 lineNode
->setAttr("flagSoundStopsAnim", line
.m_flagSoundStopsAnim
);
528 lineNode
->setAttr("flagAGSignal", line
.m_flagAGSignal
);
529 lineNode
->setAttr("flagAGEP", line
.m_flagAGEP
);
530 lineNode
->setAttr("audioID", line
.m_audioTriggerName
);
531 lineNode
->setAttr("anim", line
.m_anim
);
532 lineNode
->setAttr("facial", line
.m_facial
);
533 lineNode
->setAttr("delay", line
.m_delay
);
534 lineNode
->setAttr("facialWeight", line
.m_facialWeight
);
535 lineNode
->setAttr("facialFadeTime", line
.m_facialFadeTime
);
536 lineNode
->setAttr("desc", line
.m_desc
);