!XT (BREAK-16) (Sandbox) Remove double-newlines at the end of files.
[CRYENGINE.git] / Code / Sandbox / Plugins / DialogEditor / DialogManager.cpp
blobd1b030e8a96ce6d69501e0d4d56c753895e1a7ed
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
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/"
15 namespace
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)
24 n |= (0x01 << 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);
42 return n % 255;
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);
93 return false;
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);
99 return false;
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);
107 return true;
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];
131 else return 0;
134 ////////////////////////////////////////////////////////////////////////////
135 CDialogManager::CDialogManager()
140 ////////////////////////////////////////////////////////////////////////////
141 CDialogManager::~CDialogManager()
143 DeleteAllScripts();
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())
160 delete iter->second;
161 ++iter;
163 m_scripts.clear();
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;
182 path += filename;
183 path += ".dlg";
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('/', '.');
198 return filename;
201 ////////////////////////////////////////////////////////////////////////////
202 bool CDialogManager::ReloadScripts()
204 DeleteAllScripts();
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);
214 MakeID(dlgID);
216 string filename = path;
217 filename += files[iFile].filename;
219 // testing
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);
228 if (bOK)
230 TEditorDialogScriptMap::iterator iter = m_scripts.find(pScript->GetID());
231 if (iter != m_scripts.end())
232 delete iter->second;
233 m_scripts[pScript->GetID()] = pScript; // this overrides previous contents if any
235 else
237 delete pScript;
241 return true;
244 ////////////////////////////////////////////////////////////////////////////
245 bool CDialogManager::SaveAllScripts()
247 bool ok = true;
248 TEditorDialogScriptMap::iterator iter = m_scripts.begin();
249 while (iter != m_scripts.end())
251 ok &= SaveScript(iter->second, false);
252 ++iter;
254 SyncCryActionScripts();
255 return ok;
258 ////////////////////////////////////////////////////////////////////////////
259 CEditorDialogScript* CDialogManager::LoadScript(string& name, bool bReplace)
261 CEditorDialogScript* pScript = GetScript(name, false);
262 if (pScript && !bReplace)
263 return pScript;
264 if (pScript)
266 DeleteScript(pScript, false);
267 pScript = 0;
270 string id = name;
271 MakePath(id);
272 string path = PathUtil::GetGameFolder() + DIALOGSCRIPT_PATH;
273 path += id;
274 path += ".dlg";
276 // testing
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);
285 if (bOK)
287 m_scripts.insert(TEditorDialogScriptMap::value_type(pScript->GetID(), pScript));
289 else
291 delete pScript;
292 pScript = 0;
295 return 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);
304 if (bOK)
306 string idPath = pScript->GetID();
307 MakePath(idPath);
308 string path = PathUtil::GetGameFolder() + DIALOGSCRIPT_PATH;
309 path += idPath;
310 path += ".dlg";
311 // testing
312 CString sPath = ScriptToFilename(CString(pScript->GetID()));
314 // backup file
315 if (bBackup)
317 CFileUtil::BackupFile(path);
320 CFileUtil::CreateDirectory(PathUtil::GetPathWithoutFilename(path));
321 bOK = XmlHelpers::SaveXmlNode(node, path);
322 if (bSync)
324 SyncCryActionScripts();
327 return bOK;
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));
339 return pScript;
342 ////////////////////////////////////////////////////////////////////////////
343 CEditorDialogScript* CDialogManager::GetScript(const CString& name, bool bForceCreate)
345 string sName = name;
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())
354 return false;
356 assert(pScript == iter->second);
358 if (bDeleteFromDisk)
360 string idPath = pScript->GetID();
361 MakePath(idPath);
362 string path = PathUtil::GetGameFolder() + DIALOGSCRIPT_PATH;
363 path += idPath;
364 path += ".dlg";
365 ::DeleteFile(path);
368 delete pScript;
369 m_scripts.erase(iter);
371 if (bDeleteFromDisk)
373 SyncCryActionScripts();
376 return true;
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())
384 return false;
386 // can be renamed...
387 iter = m_scripts.find(pScript->GetID());
388 assert(pScript == iter->second);
390 string idPath = pScript->GetID();
391 MakePath(idPath);
392 string oldPath = PathUtil::GetGameFolder() + DIALOGSCRIPT_PATH;
393 oldPath += idPath;
394 oldPath += ".dlg";
396 // rename script
397 string newID = newName;
398 pScript->SetID(newName);
400 // save the script in new location
401 bool bSaveOK = SaveScript(pScript);
402 if (!bSaveOK)
403 return false;
405 // erase old from map and insert new
406 m_scripts.erase(iter);
407 m_scripts.insert(TEditorDialogScriptMap::value_type(newName, pScript));
409 if (bDeleteFromDisk)
411 // delete old file from disk
412 ::DeleteFile(oldPath);
413 SyncCryActionScripts();
416 return true;
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))
437 return false;
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))
442 return true;
444 if ((scAttr & SCC_FILE_ATTRIBUTE_MANAGED) && !(scAttr & SCC_FILE_ATTRIBUTE_CHECKEDOUT))
445 return false;
447 return true;
450 ////////////////////////////////////////////////////////////////////////////
451 CEditorDialogScriptSerializer::CEditorDialogScriptSerializer(CEditorDialogScript* pScript)
453 assert(pScript != 0);
454 m_pScript = pScript;
457 ////////////////////////////////////////////////////////////////////////////
458 bool CEditorDialogScriptSerializer::Load(XmlNodeRef node)
460 if (node->isTag("DialogScript") == false)
461 return 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
477 line.Reset();
478 if (ReadLine(lineNode, line) == true)
479 m_pScript->AddLine(line);
482 return true;
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);
497 return true;
500 ////////////////////////////////////////////////////////////////////////////
501 bool CEditorDialogScriptSerializer::ReadLine(const XmlNodeRef& lineNode, CEditorDialogScript::SScriptLine& line)
503 bool tmp;
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");
518 return true;
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);
537 return true;