BVB Source Codes

CRYENGINE Show DialogLoader.cpp Source code

Return Download CRYENGINE: download DialogLoader.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. // -------------------------------------------------------------------------
  4. //  File name:   DialogLoader.cpp
  5. //  Version:     v1.00
  6. //  Created:     07/07/2006 by AlexL
  7. //  Compilers:   Visual Studio.NET
  8. //  Description: Dialog Loader
  9. // -------------------------------------------------------------------------
  10. //  History:
  11. //
  12. ////////////////////////////////////////////////////////////////////////////
  13. #include "StdAfx.h"
  14. #include "DialogLoader.h"
  15. #include "DialogCommon.h"
  16. #include <CryString/StringUtils.h>
  17.  
  18. ////////////////////////////////////////////////////////////////////////////
  19. CDialogLoader::CDialogLoader(CDialogSystem* pDS) : m_pDS(pDS)
  20. {
  21.  
  22. }
  23.  
  24. ////////////////////////////////////////////////////////////////////////////
  25. CDialogLoader::~CDialogLoader()
  26. {
  27.  
  28. }
  29.  
  30. ////////////////////////////////////////////////////////////////////////////
  31. bool CDialogLoader::LoadScriptsFromPath(const string& path, TDialogScriptMap& outScriptMap)
  32. {
  33.         ICryPak* pCryPak = gEnv->pCryPak;
  34.         _finddata_t fd;
  35.         int numLoaded = 0;
  36.  
  37.         string realPath(path);
  38.         realPath.TrimRight("/\\");
  39.         string search(realPath);
  40.         search += "/*.xml";
  41.  
  42.         intptr_t handle = pCryPak->FindFirst(search.c_str(), &fd);
  43.         if (handle != -1)
  44.         {
  45.                 do
  46.                 {
  47.                         // fd.name contains the profile name
  48.                         string filename = realPath;
  49.                         filename += "/";
  50.                         filename += fd.name;
  51.                         bool ok = LoadScript(filename, outScriptMap);
  52.                         if (ok)
  53.                                 ++numLoaded;
  54.                 }
  55.                 while (pCryPak->FindNext(handle, &fd) >= 0);
  56.  
  57.                 pCryPak->FindClose(handle);
  58.         }
  59.  
  60.         return numLoaded > 0;
  61. }
  62.  
  63. ////////////////////////////////////////////////////////////////////////////
  64. bool CDialogLoader::LoadScript(const string& filename, TDialogScriptMap& outScriptMap)
  65. {
  66.         // parse MS Excel spreadsheet
  67.         XmlNodeRef rootNode = GetISystem()->LoadXmlFromFile(filename);
  68.         if (!rootNode)
  69.         {
  70.                 GameWarning("[DIALOG] CDialogLoader::LoadScripts: Cannot find file '%s'", filename.c_str());
  71.                 return false;
  72.         }
  73.  
  74.         // iterate over all children and load all worksheets
  75.         int nChilds = rootNode->getChildCount();
  76.         if (nChilds == 0)
  77.         {
  78.                 GameWarning("[DIALOG] CDialogLoader::LoadScripts: Cannot find any 'Worksheet's in file '%s'", filename.c_str());
  79.                 return false;
  80.         }
  81.  
  82.         int numScripts = 0;
  83.  
  84.         string baseName = PathUtil::GetFileName(filename);
  85.  
  86.         for (int i = 0; i < nChilds; ++i)
  87.         {
  88.                 XmlNodeRef childNode = rootNode->getChild(i);
  89.                 if (childNode && childNode->isTag("Worksheet"))
  90.                 {
  91.                         const char* wsName = childNode->getAttr("ss:Name");
  92.                         XmlNodeRef tableNode = childNode->findChild("Table");
  93.                         if (!tableNode)
  94.                         {
  95.                                 GameWarning("[DIALOG] CDialogLoader::LoadScripts: Worksheet '%s' in file '%s' has no Table", wsName ? wsName : "<noname>", filename.c_str());
  96.                         }
  97.                         else
  98.                         {
  99.                                 const string& groupName = baseName; // maybe we add the Worksheets name later on!
  100.                                 numScripts = LoadFromTable(tableNode, groupName, outScriptMap);
  101.                                 break; // only load first worksheet
  102.                         }
  103.                 }
  104.         }
  105.  
  106.         return numScripts > 0;
  107. }
  108.  
  109. static const int MAX_CELL_COUNT = 16;  // must fit into unsigned char!
  110.  
  111. static const char* sColumnNames[] =
  112. {
  113.         "Dialog",
  114.         "Actor",
  115.         "Sound",
  116.         "Animation",
  117.         "Facial Expression",
  118.         "LookAtTarget",
  119.         "Delay",
  120.         "",
  121. };
  122.  
  123. enum eAttrType
  124. {
  125.         ATTR_DIALOG = 0,
  126.         ATTR_ACTOR,
  127.         ATTR_AUDIO,
  128.         ATTR_ANIM,
  129.         ATTR_FACIAL,
  130.         ATTR_LOOKAT,
  131.         ATTR_DELAY,
  132.         ATTR_SKIP
  133. };
  134.  
  135. void FillMapping(XmlNodeRef row, unsigned char* pIndexToAttrMap)
  136. {
  137.         int nCellIndex = 0;
  138.         int nNewIndex = 0;
  139.         for (int cell = 0; cell < row->getChildCount(); ++cell)
  140.         {
  141.                 if (cell >= MAX_CELL_COUNT)
  142.                         continue;
  143.  
  144.                 XmlNodeRef nodeCell = row->getChild(cell);
  145.                 if (!nodeCell->isTag("Cell"))
  146.                         continue;
  147.  
  148.                 if (nodeCell->getAttr("ss:Index", nNewIndex))
  149.                 {
  150.                         // Check if some cells are skipped.
  151.                         nCellIndex = nNewIndex - 1;
  152.                 }
  153.  
  154.                 XmlNodeRef nodeCellData = nodeCell->findChild("Data");
  155.                 if (!nodeCellData)
  156.                 {
  157.                         ++nCellIndex;
  158.                         continue;
  159.                 }
  160.  
  161.                 const char* sCellContent = nodeCellData->getContent();
  162.  
  163.                 for (int i = 0; i < sizeof(sColumnNames) / sizeof(*sColumnNames); ++i)
  164.                 {
  165.                         // this is a begins-with-check!
  166.                         if (CryStringUtils::stristr(sCellContent, sColumnNames[i]) == sCellContent)
  167.                         {
  168.                                 pIndexToAttrMap[nCellIndex] = i;
  169.                                 break;
  170.                         }
  171.                 }
  172.                 ++nCellIndex;
  173.         }
  174. }
  175.  
  176. ////////////////////////////////////////////////////////////////////////////
  177. int CDialogLoader::LoadFromTable(XmlNodeRef tableNode, const string& groupName, TDialogScriptMap& outScriptMap)
  178. {
  179.         unsigned char nCellIndexToType[MAX_CELL_COUNT];
  180.         memset(nCellIndexToType, ATTR_SKIP, sizeof(nCellIndexToType));
  181.  
  182.         IMScript theScript;
  183.  
  184.         int nNumGoodScripts = 0;
  185.         int nRowIndex = 0;
  186.         int nChilds = tableNode->getChildCount();
  187.         for (int i = 0; i < nChilds; ++i)
  188.         {
  189.                 XmlNodeRef rowNode = tableNode->getChild(i);
  190.                 if (!rowNode || !rowNode->isTag("Row"))
  191.                         continue;
  192.  
  193.                 ++nRowIndex;
  194.  
  195.                 // skip first row as it should only contain column description
  196.                 if (nRowIndex == 1)
  197.                 {
  198.                         FillMapping(rowNode, nCellIndexToType);
  199.                         continue;
  200.                 }
  201.  
  202.                 IMScriptLine scriptLine;
  203.  
  204.                 bool bLineValid = false;
  205.                 int nColCount = rowNode->getChildCount();
  206.                 int nCellIndex = 0;
  207.                 for (int j = 0; j < nColCount; ++j)
  208.                 {
  209.                         XmlNodeRef cellNode = rowNode->getChild(j);
  210.                         if (!cellNode || !cellNode->isTag("Cell"))
  211.                                 continue;
  212.  
  213.                         int tmpIndex = 0;
  214.                         if (cellNode->getAttr("ss:Index", tmpIndex))
  215.                         {
  216.                                 nCellIndex = tmpIndex - 1;
  217.                         }
  218.  
  219.                         if (nCellIndex < 0 || nCellIndex >= MAX_CELL_COUNT)
  220.                                 break;
  221.  
  222.                         XmlNodeRef cellDataNode = cellNode->findChild("Data");
  223.                         if (!cellDataNode)
  224.                         {
  225.                                 ++nCellIndex;
  226.                                 continue;
  227.                         }
  228.  
  229.                         unsigned char nCellType = nCellIndexToType[nCellIndex];
  230.  
  231.                         const char* content = cellDataNode->getContent();
  232.  
  233.                         // nRowIndex and nCellIndex should be correct now [1-based, not 0-based!]
  234.                         switch (nCellType)
  235.                         {
  236.                         case ATTR_SKIP:
  237.                                 break;
  238.                         case ATTR_DIALOG:
  239.                                 if (theScript.IsValid())
  240.                                 {
  241.                                         const bool ok = ProcessScript(theScript, groupName, outScriptMap);
  242.                                         if (ok)
  243.                                                 ++nNumGoodScripts;
  244.                                         theScript.Reset();
  245.                                 }
  246.                                 theScript.name = content;
  247.                                 break;
  248.                         case ATTR_ACTOR:
  249.                                 scriptLine.actor = content;
  250.                                 bLineValid = true;
  251.                                 break;
  252.                         case ATTR_AUDIO:
  253.                                 if (bLineValid)
  254.                                 {
  255.                                         if (content == 0)
  256.                                                 scriptLine.audioID = INVALID_AUDIO_CONTROL_ID;
  257.                                         else
  258.                                                 gEnv->pAudioSystem->GetAudioTriggerId(content, scriptLine.audioID);
  259.                                 }
  260.                                 break;
  261.                         case ATTR_ANIM:
  262.                                 if (bLineValid)
  263.                                         scriptLine.anim = content;
  264.                                 break;
  265.                         case ATTR_FACIAL:
  266.                                 if (bLineValid)
  267.                                 {
  268.                                         size_t n = strcspn(content, ":; ");
  269.                                         if (n == strlen(content))
  270.                                         {
  271.                                                 scriptLine.facial = content;
  272.                                                 scriptLine.facialWeight = 0.5f;
  273.                                                 scriptLine.facialFadeTime = 0.5f;
  274.                                         }
  275.                                         else
  276.                                         {
  277.                                                 scriptLine.facial.assign(content, n);
  278.                                                 float w = 0.5f;
  279.                                                 float t = 0.5f;
  280.                                                 int nGood = sscanf(content + n + 1, "%f%*[:; ]%f", &w, &t);
  281.                                                 if (nGood != 1 && nGood != 2)
  282.                                                 {
  283.                                                         GameWarning("[DIALOG] CDialogLoader::LoadFromTable: DialogScript '%s' has invalid Facial Expression Content '%s'. Using weight=%f fadetime=%f.", groupName.c_str(), content, w, t);
  284.                                                 }
  285.                                                 scriptLine.facialWeight = w;
  286.                                                 scriptLine.facialFadeTime = t;
  287.                                         }
  288.                                 }
  289.                                 break;
  290.                         case ATTR_LOOKAT:
  291.                                 if (bLineValid)
  292.                                         scriptLine.lookat = content;
  293.                                 break;
  294.                         case ATTR_DELAY:
  295.                                 if (bLineValid)
  296.                                 {
  297.                                         float val = 0.0f;
  298.                                         int n = sscanf(content, "%f", &val);
  299.                                         if (n == 1)
  300.                                         {
  301.                                                 scriptLine.delay = val;
  302.                                         }
  303.                                 }
  304.                                 break;
  305.                         default:
  306.                                 break;
  307.                         }
  308.  
  309.                         ++nCellIndex;
  310.                 }
  311.                 if (scriptLine.IsValid())
  312.                 {
  313.                         theScript.lines.push_back(scriptLine);
  314.                 }
  315.         }
  316.         if (theScript.IsValid())
  317.         {
  318.                 const bool ok = ProcessScript(theScript, groupName, outScriptMap);
  319.                 if (ok)
  320.                         ++nNumGoodScripts;
  321.         }
  322.  
  323.         return nNumGoodScripts;
  324. }
  325.  
  326. // returns actor's ID in outID [1 based]
  327. // or 0, when not found
  328. ////////////////////////////////////////////////////////////////////////////
  329. bool CDialogLoader::GetActor(const char* actor, int& outID)
  330. {
  331.         static const char* actorPrefix = "actor";
  332.         static const int actorPrefixLen = strlen(actorPrefix);
  333.  
  334.         assert(actor != 0 && *actor != '\0');
  335.         if (actor == 0 || *actor == '\0') // safety
  336.         {
  337.                 outID = 0;
  338.                 return true;
  339.         }
  340.  
  341.         const char* found = CryStringUtils::stristr(actor, actorPrefix);
  342.         if (found && sscanf(found + actorPrefixLen, "%d", &outID) == 1)
  343.                 return true;
  344.         outID = 0;
  345.         return false;
  346. }
  347.  
  348. // returns actor's ID in outID [1 based]
  349. // or 0, when not found
  350. ////////////////////////////////////////////////////////////////////////////
  351. bool CDialogLoader::GetLookAtActor(const char* actor, int& outID, bool& outSticky)
  352. {
  353.         static const char* actorPrefix = "actor";
  354.         static const int actorPrefixLen = strlen(actorPrefix);
  355.  
  356.         assert(actor != 0 && *actor != '\0');
  357.         if (actor == 0 || *actor == '\0') // safety
  358.         {
  359.                 outID = 0;
  360.                 outSticky = false;
  361.                 return true;
  362.         }
  363.  
  364.         if (actor[0] == '$')
  365.         {
  366.                 outSticky = true;
  367.                 ++actor;
  368.         }
  369.         else
  370.                 outSticky = false;
  371.  
  372.         const char* found = CryStringUtils::stristr(actor, actorPrefix);
  373.         if (found && sscanf(found + actorPrefixLen, "%d", &outID) == 1)
  374.                 return true;
  375.         outID = 0;
  376.         return false;
  377. }
  378.  
  379. ////////////////////////////////////////////////////////////////////////////
  380. bool CDialogLoader::ProcessScript(IMScript& script, const string& groupName, TDialogScriptMap& outScriptMap)
  381. {
  382. #if 0
  383.         DiaLOG::Log(DiaLOG::eAlways, "Script: %s with %d lines", script.name, script.lines.size());
  384.         for (int i = 0; i < script.lines.size(); ++i)
  385.         {
  386.                 IMScriptLine& line = script.lines[i];
  387.                 DiaLOG::Log(DiaLOG::eAlways, "actor=%s sound=%s anim=%s facial=%s lookat=%s delay=%f",
  388.                             line.actor, line.sound, line.anim, line.facial, line.lookat, line.delay);
  389.         }
  390. #endif
  391.  
  392.         string scriptName(groupName);
  393.         scriptName += ".";
  394.         scriptName += script.name;
  395.  
  396.         if (script.lines.empty())
  397.         {
  398.                 GameWarning("[DIALOG] CDialogLoader::ProcessScript: DialogScript '%s' has no lines. Discarded.", scriptName.c_str());
  399.                 return false;
  400.         }
  401.  
  402.         CDialogScript* pScript = new CDialogScript(scriptName);
  403.         pScript->SetVersionFlags(CDialogScript::VF_EXCEL_BASED, true);
  404.  
  405.         bool bDiscard = false;
  406.         int nLine = 1;
  407.         std::vector<IMScriptLine>::iterator iter = script.lines.begin();
  408.         std::vector<IMScriptLine>::iterator end = script.lines.end();
  409.  
  410.         string animName;
  411.  
  412.         for (; iter != end; ++iter, ++nLine)
  413.         {
  414.                 // process the line
  415.                 const IMScriptLine& line = *iter;
  416.                 int actor = 0;
  417.                 int lookAt = 0;
  418.  
  419.                 // Actor
  420.                 if (!GetActor(line.actor, actor))
  421.                 {
  422.                         bDiscard = true;
  423.                         GameWarning("[DIALOG] CDialogLoader::ProcessScript '%s': Line %d: Cannot parse 'Actor' statement. Discarding.", scriptName.c_str(), nLine);
  424.                         break;
  425.                 }
  426.                 if (actor < 1 || actor > CDialogScript::MAX_ACTORS)
  427.                 {
  428.                         bDiscard = true;
  429.                         GameWarning("[DIALOG] CDialogLoader::ProcessScript '%s': Line %d: Actor%d given. Must be within [1..%d]. Discarding.", scriptName.c_str(), nLine, actor, CDialogScript::MAX_ACTORS);
  430.                         break;
  431.                 }
  432.  
  433.                 bool bUseAGEP = false;
  434.                 bool bUseAGSignal = false;
  435.                 bool bSoundStopsAnim = false;
  436.  
  437.                 const char* lineAnimName = line.anim;
  438.                 if (CryStringUtils::stristr(lineAnimName, "ex_") == lineAnimName)
  439.                 {
  440.                         // use AG Exact Positioning
  441.                         bUseAGEP = true;
  442.                         lineAnimName += 3;
  443.  
  444.                         if (*lineAnimName == 0)
  445.                         {
  446.                                 bDiscard = true;
  447.                                 GameWarning("[DIALOG] CDialogLoader::ProcessScript '%s': Line %d: Invalid AnimName '%s'. Discarding", scriptName.c_str(), nLine, line.anim);
  448.                                 break;
  449.                         }
  450.                 }
  451.  
  452.                 if (lineAnimName[0] == '$')
  453.                 {
  454.                         // use AG Signal
  455.                         bUseAGSignal = true;
  456.                         ++lineAnimName;
  457.  
  458.                         if (*lineAnimName == 0)
  459.                         {
  460.                                 bDiscard = true;
  461.                                 GameWarning("[DIALOG] CDialogLoader::ProcessScript '%s': Line %d: Invalid AnimName '%s'. Discarding", scriptName.c_str(), nLine, line.anim);
  462.                                 break;
  463.                         }
  464.                 }
  465.  
  466.                 int animNameLen = strlen(lineAnimName);
  467.                 if (animNameLen >= 2 && lineAnimName[animNameLen - 1] == '$')
  468.                 {
  469.                         bSoundStopsAnim = true;
  470.                         --animNameLen;
  471.                 }
  472.                 animName.assign(lineAnimName, animNameLen);
  473.  
  474.                 // LookAtTarget
  475.                 bool bLookAtGiven = line.lookat && line.lookat[0] != '\0';
  476.                 bool bLookAtSticky = false;
  477.                 bool bResetLookAt = false;
  478.                 if (bLookAtGiven && CryStringUtils::stristr(line.lookat, "$reset") != 0)
  479.                 {
  480.                         bResetLookAt = true;
  481.                         bLookAtGiven = false;
  482.                 }
  483.                 else if (bLookAtGiven && !GetLookAtActor(line.lookat, lookAt, bLookAtSticky))
  484.                 {
  485.                         bDiscard = true;
  486.                         GameWarning("[DIALOG] CDialogLoader::ProcessScript: %s Line %d: Cannot parse 'LookAtTarget' statement. Discarding.", scriptName.c_str(), nLine);
  487.                         break;
  488.                 }
  489.                 if (bLookAtGiven && (lookAt < 1 || lookAt > CDialogScript::MAX_ACTORS))
  490.                 {
  491.                         bDiscard = true;
  492.                         GameWarning("[DIALOG] CDialogLoader::ProcessScript '%s': Line %d: LookAtTarget Actor%d given. Must be within [1..%d]. Discarding.", scriptName.c_str(), nLine, lookAt, CDialogScript::MAX_ACTORS);
  493.                         break;
  494.                 }
  495.  
  496.                 const char* facialExpression = line.facial.c_str();
  497.                 bool bResetFacial = false;
  498.                 if (CryStringUtils::stristr(facialExpression, "$reset") != 0)
  499.                 {
  500.                         bResetFacial = true;
  501.                         facialExpression = "";
  502.                 }
  503.  
  504.                 const CDialogScript::TActorID actorID = static_cast<CDialogScript::TActorID>(actor - 1);
  505.                 const CDialogScript::TActorID lookAtID = lookAt <= 0 ? CDialogScript::NO_ACTOR_ID : static_cast<CDialogScript::TActorID>(lookAt - 1);
  506.                 const bool bSuccess = pScript->AddLine(actorID, line.audioID, animName.c_str(), facialExpression, lookAtID, line.delay, line.facialWeight, line.facialFadeTime, bLookAtSticky, bResetFacial, bResetLookAt, bSoundStopsAnim, bUseAGSignal, bUseAGEP);
  507.                 if (!bSuccess)
  508.                 {
  509.                         bDiscard = true;
  510.                         GameWarning("[DIALOG] CDialogLoader::ProcessScript '%s': Cannot add line %d. Discarding", scriptName.c_str(), nLine);
  511.                         break;
  512.                 }
  513.         }
  514.  
  515.         if (bDiscard == false)
  516.         {
  517.                 // try to complete the script
  518.                 if (pScript->Complete() == true)
  519.                 {
  520.                         // add it to the map
  521.                         std::pair<TDialogScriptMap::iterator, bool> inserted =
  522.                           outScriptMap.insert(TDialogScriptMap::value_type(pScript->GetID(), pScript));
  523.                         if (inserted.second == false)
  524.                         {
  525.                                 bDiscard = true;
  526.                                 GameWarning("[DIALOG] CDialogLoader::ProcessScript '%s': Script already defined. Discarded", scriptName.c_str());
  527.                         }
  528.                 }
  529.                 // completion not successful -> discard
  530.                 else
  531.                 {
  532.                         bDiscard = true;
  533.                         GameWarning("[DIALOG] CDialogLoader::ProcessScript '%s': Cannot complete Script. Discarded.", scriptName.c_str());
  534.                 }
  535.         }
  536.  
  537.         // discard pScript
  538.         if (bDiscard)
  539.         {
  540.                 delete pScript;
  541.         }
  542.  
  543.         return bDiscard == false;
  544. }
  545.  
downloadDialogLoader.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top