!XT (BREAK-16) (Sandbox) Remove double-newlines at the end of files.
[CRYENGINE.git] / Code / Sandbox / EditorQt / Objects / EntityScript.cpp
blobf2ca38d6bd21131a14dcbc8026a14eeab435809c
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
4 #include "EntityScript.h"
5 #include "EntityObject.h"
6 #include "CryEdit.h"
7 #include <CryScriptSystem/IScriptSystem.h>
8 #include <CryEntitySystem/IEntitySystem.h>
9 #include "LuaCommentParser.h"
10 #include "CryEdit.h"
12 struct CScriptMethodsDump : public IScriptTableDumpSink
14 std::vector<string> methods;
15 std::vector<string> events;
17 virtual void OnElementFound(int nIdx, ScriptVarType type) {}
19 virtual void OnElementFound(const char* sName, ScriptVarType type)
21 if (type == svtFunction)
23 if (strncmp(sName, EVENT_PREFIX, 6) == 0)
25 events.push_back(sName + 6);
27 else
29 methods.push_back(sName);
35 enum EScriptParamFlags
37 SCRIPTPARAM_POSITIVE = 0x01,
40 //////////////////////////////////////////////////////////////////////////
41 static struct
43 const char* prefix;
44 IVariable::EType type;
45 IVariable::EDataType dataType;
46 int flags;
47 bool bExactName;
48 } s_scriptParamTypes[] =
50 { "n", IVariable::INT, IVariable::DT_SIMPLE, SCRIPTPARAM_POSITIVE, false },
51 { "i", IVariable::INT, IVariable::DT_SIMPLE, 0, false },
52 { "b", IVariable::BOOL, IVariable::DT_SIMPLE, 0, false },
53 { "f", IVariable::FLOAT, IVariable::DT_SIMPLE, 0, false },
54 { "s", IVariable::STRING, IVariable::DT_SIMPLE, 0, false },
56 { "ei", IVariable::INT, IVariable::DT_UIENUM, 0, false },
57 { "es", IVariable::STRING, IVariable::DT_UIENUM, 0, false },
59 { "shader", IVariable::STRING, IVariable::DT_SHADER, 0, false },
60 { "clr", IVariable::VECTOR, IVariable::DT_COLOR, 0, false },
61 { "color", IVariable::VECTOR, IVariable::DT_COLOR, 0, false },
63 { "vector", IVariable::VECTOR, IVariable::DT_SIMPLE, 0, false },
65 { "tex", IVariable::STRING, IVariable::DT_TEXTURE, 0, false },
66 { "texture", IVariable::STRING, IVariable::DT_TEXTURE, 0, false },
68 { "obj", IVariable::STRING, IVariable::DT_OBJECT, 0, false },
69 { "object", IVariable::STRING, IVariable::DT_OBJECT, 0, false },
71 { "file", IVariable::STRING, IVariable::DT_FILE, 0, false },
72 { "aibehavior", IVariable::STRING, IVariable::DT_AI_BEHAVIOR, 0, false },
73 #ifdef USE_DEPRECATED_AI_CHARACTER_SYSTEM
74 { "aicharacter", IVariable::STRING, IVariable::DT_AI_CHARACTER, 0, false },
75 #endif
76 { "aipfpropertieslist", IVariable::STRING, IVariable::DT_AI_PFPROPERTIESLIST, 0, false },
77 { "aientityclasses", IVariable::STRING, IVariable::DT_AIENTITYCLASSES, 0, false },
78 { "aiterritory", IVariable::STRING, IVariable::DT_AITERRITORY, 0, false },
79 { "aiwave", IVariable::STRING, IVariable::DT_AIWAVE, 0, false },
81 { "text", IVariable::STRING, IVariable::DT_LOCAL_STRING, 0, false },
82 { "equip", IVariable::STRING, IVariable::DT_EQUIP, 0, false },
83 { "reverbpreset", IVariable::STRING, IVariable::DT_REVERBPRESET, 0, false },
84 { "eaxpreset", IVariable::STRING, IVariable::DT_REVERBPRESET, 0, false },
86 { "aianchor", IVariable::STRING, IVariable::DT_AI_ANCHOR, 0, false },
88 { "soclass", IVariable::STRING, IVariable::DT_SOCLASS, 0, false },
89 { "soclasses", IVariable::STRING, IVariable::DT_SOCLASSES, 0, false },
90 { "sostate", IVariable::STRING, IVariable::DT_SOSTATE, 0, false },
91 { "sostates", IVariable::STRING, IVariable::DT_SOSTATES, 0, false },
92 { "sopattern", IVariable::STRING, IVariable::DT_SOSTATEPATTERN, 0, false },
93 { "soaction", IVariable::STRING, IVariable::DT_SOACTION, 0, false },
94 { "sohelper", IVariable::STRING, IVariable::DT_SOHELPER, 0, false },
95 { "sonavhelper", IVariable::STRING, IVariable::DT_SONAVHELPER, 0, false },
96 { "soanimhelper", IVariable::STRING, IVariable::DT_SOANIMHELPER, 0, false },
97 { "soevent", IVariable::STRING, IVariable::DT_SOEVENT, 0, false },
98 { "sotemplate", IVariable::STRING, IVariable::DT_SOTEMPLATE, 0, false },
99 { "customaction", IVariable::STRING, IVariable::DT_CUSTOMACTION, 0, false },
100 { "gametoken", IVariable::STRING, IVariable::DT_GAMETOKEN, 0, false },
101 { "seq_", IVariable::STRING, IVariable::DT_SEQUENCE, 0, false },
102 { "mission_", IVariable::STRING, IVariable::DT_MISSIONOBJ, 0, false },
103 { "seqid_", IVariable::INT, IVariable::DT_SEQUENCE_ID, 0, false },
104 { "flare_", IVariable::STRING, IVariable::DT_FLARE, 0, false },
105 { "ParticleEffect", IVariable::STRING, IVariable::DT_PARTICLE_EFFECT, 0, true },
106 { "geomcache", IVariable::STRING, IVariable::DT_GEOM_CACHE, 0, false },
107 { "material", IVariable::STRING, IVariable::DT_MATERIAL, 0 },
108 { "audioTrigger", IVariable::STRING, IVariable::DT_AUDIO_TRIGGER, 0 },
109 { "audioSwitch", IVariable::STRING, IVariable::DT_AUDIO_SWITCH, 0 },
110 { "audioSwitchState", IVariable::STRING, IVariable::DT_AUDIO_SWITCH_STATE, 0 },
111 { "audioRTPC", IVariable::STRING, IVariable::DT_AUDIO_RTPC, 0 },
112 { "audioEnvironment", IVariable::STRING, IVariable::DT_AUDIO_ENVIRONMENT, 0 },
113 { "audioPreloadRequest", IVariable::STRING, IVariable::DT_AUDIO_PRELOAD_REQUEST, 0 },
116 //////////////////////////////////////////////////////////////////////////
117 struct CScriptPropertiesDump : public IScriptTableDumpSink
119 private:
120 struct Variable
122 string name;
123 ScriptVarType type;
126 std::vector<Variable> m_elements;
128 CVarBlock* m_varBlock;
129 IVariable* m_parentVar;
131 public:
132 explicit CScriptPropertiesDump(CVarBlock* pVarBlock, IVariable* pParentVar = NULL)
134 m_varBlock = pVarBlock;
135 m_parentVar = pParentVar;
138 //////////////////////////////////////////////////////////////////////////
139 inline bool IsPropertyTypeMatch(const char* type, const char* name, int nameLen, bool exactName)
141 if (exactName)
143 return strcmp(type, name) == 0;
146 // if starts from capital no type encoded.
147 int typeLen = strlen(type);
148 if (typeLen < nameLen && name[0] == tolower(name[0]))
150 // After type name Must follow Upper case or _.
151 if (name[typeLen] != tolower(name[typeLen]) || name[typeLen] == '_')
153 if (strncmp(name, type, strlen(type)) == 0)
155 return true;
159 return false;
162 //////////////////////////////////////////////////////////////////////////
163 IVariable* CreateVarByType(IVariable::EType type)
165 switch (type)
167 case IVariable::FLOAT:
168 return new CVariable<float>;
169 case IVariable::INT:
170 return new CVariable<int>;
171 case IVariable::STRING:
172 return new CVariable<string>;
173 case IVariable::BOOL:
174 return new CVariable<bool>;
175 case IVariable::VECTOR:
176 return new CVariable<Vec3>;
177 case IVariable::QUAT:
178 return new CVariable<Quat>;
179 default:
180 assert(0);
182 return NULL;
185 //////////////////////////////////////////////////////////////////////////
186 IVariable* CreateVar(const char* name, IVariable::EType defaultType, const char*& displayName)
188 displayName = name;
189 // Resolve type from variable name.
190 int nameLen = strlen(name);
192 int nFlags = 0;
193 int iStartIndex = 0;
194 if (name[0] == '_')
196 nFlags |= IVariable::UI_INVISIBLE;
197 iStartIndex++;
201 // Try to detect type.
202 for (int i = 0; i < CRY_ARRAY_COUNT(s_scriptParamTypes); i++)
204 if (IsPropertyTypeMatch(s_scriptParamTypes[i].prefix, name + iStartIndex, nameLen - iStartIndex, s_scriptParamTypes[i].bExactName))
206 displayName = name + strlen(s_scriptParamTypes[i].prefix) + iStartIndex;
207 if (displayName[0] == '_')
209 displayName++;
211 if (displayName[0] == '\0')
213 displayName = name;
216 IVariable::EType type = s_scriptParamTypes[i].type;
217 IVariable::EDataType dataType = s_scriptParamTypes[i].dataType;
219 IVariable* var;
220 if (type == IVariable::STRING &&
221 (dataType == IVariable::DT_AITERRITORY || dataType == IVariable::DT_AIWAVE))
223 var = new CVariableEnum<string>;
225 else
227 var = CreateVarByType(type);
230 if (!var)
232 continue;
235 var->SetName(name);
236 var->SetHumanName(displayName);
237 var->SetDataType(s_scriptParamTypes[i].dataType);
238 var->SetFlags(nFlags);
239 if (s_scriptParamTypes[i].flags & SCRIPTPARAM_POSITIVE)
241 float lmin = 0, lmax = 10000;
242 var->GetLimits(lmin, lmax);
243 // set min Limit to 0 hard, to make it positive only value.
244 var->SetLimits(0, lmax, true, false);
246 return var;
250 if (defaultType != IVariable::UNKNOWN)
252 IVariable* var = CreateVarByType(defaultType);
253 var->SetName(name);
254 return var;
256 return 0;
259 //////////////////////////////////////////////////////////////////////////
260 virtual void OnElementFound(int nIdx, ScriptVarType type)
262 /* ignore non string indexed values */
265 //////////////////////////////////////////////////////////////////////////
266 virtual void OnElementFound(const char* sName, ScriptVarType type)
268 if (sName && sName[0] != 0)
270 Variable var;
271 var.name = sName;
272 var.type = type;
273 m_elements.push_back(var);
277 //////////////////////////////////////////////////////////////////////////
278 void Dump(IScriptTable* pObject, string sTablePath)
280 m_elements.reserve(20);
281 pObject->Dump(this);
282 typedef std::map<string, IVariablePtr, stl::less_stricmp<string>> NodesMap;
283 NodesMap nodes;
284 NodesMap listNodes;
286 for (int i = 0; i < m_elements.size(); i++)
288 const char* sName = m_elements[i].name;
289 ScriptVarType type = m_elements[i].type;
291 const char* sDisplayName = sName;
293 if (type == svtNumber)
295 float fVal;
296 pObject->GetValue(sName, fVal);
297 IVariable* var = CreateVar(sName, IVariable::FLOAT, sDisplayName);
298 if (var)
300 var->Set(fVal);
302 //use lua comment parser to read comment about limit settings
303 float minVal, maxVal, stepVal;
304 string desc;
305 if (LuaCommentParser::GetInstance()->ParseComment(sTablePath, sName, &minVal, &maxVal, &stepVal, &desc))
307 var->SetLimits(minVal, maxVal, stepVal);
308 var->SetDescription(desc);
311 nodes[sDisplayName] = var;
314 else if (type == svtString)
316 const char* sVal;
317 pObject->GetValue(sName, sVal);
318 IVariable* var = CreateVar(sName, IVariable::STRING, sDisplayName);
319 if (var)
321 var->Set(sVal);
322 nodes[sDisplayName] = var;
325 else if (type == svtBool)
327 bool val = false;
328 pObject->GetValue(sName, val);
329 IVariable* pVar = CreateVar(sName, IVariable::BOOL, sDisplayName);
330 if (pVar)
332 pVar->Set(val);
333 nodes[sDisplayName] = pVar;
336 else if (type == svtFunction)
338 // Ignore functions.
340 else if (type == svtObject)
342 // Some Table.
343 SmartScriptTable pTable(GetIEditorImpl()->GetSystem()->GetIScriptSystem(), true);
344 if (pObject->GetValue(sName, pTable))
346 IVariable* var = CreateVar(sName, IVariable::UNKNOWN, sDisplayName);
347 if (var && var->GetType() == IVariable::VECTOR)
349 nodes[sDisplayName] = var;
350 float x, y, z;
351 if (pTable->GetValue("x", x) && pTable->GetValue("y", y) && pTable->GetValue("z", z))
353 var->Set(Vec3(x, y, z));
355 else
357 pTable->GetAt(1, x);
358 pTable->GetAt(2, y);
359 pTable->GetAt(3, z);
360 var->Set(Vec3(x, y, z));
363 else
365 if (var)
367 var->Release();
370 var = new CVariableArray;
371 var->SetName(sName);
372 listNodes[sName] = var;
374 CScriptPropertiesDump dump(m_varBlock, var);
375 dump.Dump(*pTable, sTablePath + "." + string(sName));
381 for (NodesMap::iterator nit = nodes.begin(); nit != nodes.end(); nit++)
383 if (m_parentVar)
385 m_parentVar->AddVariable(nit->second);
387 else
389 m_varBlock->AddVariable(nit->second);
393 for (NodesMap::iterator nit1 = listNodes.begin(); nit1 != listNodes.end(); nit1++)
395 if (m_parentVar)
397 m_parentVar->AddVariable(nit1->second);
399 else
401 m_varBlock->AddVariable(nit1->second);
407 //////////////////////////////////////////////////////////////////////////
408 //////////////////////////////////////////////////////////////////////////
410 //////////////////////////////////////////////////////////////////////////
411 CEntityScript::CEntityScript(IEntityClass* pClass)
413 SetClass(pClass);
414 m_bValid = false;
415 m_haveEventsTable = false;
416 m_visibilityMask = 0;
418 m_nFlags = 0;
419 m_pOnPropertyChangedFunc = 0;
422 //////////////////////////////////////////////////////////////////////////
423 CEntityScript::~CEntityScript()
425 if (m_pOnPropertyChangedFunc)
426 gEnv->pScriptSystem->ReleaseFunc(m_pOnPropertyChangedFunc);
429 //////////////////////////////////////////////////////////////////////////
430 void CEntityScript::SetClass(IEntityClass* pClass)
432 assert(pClass);
433 m_pClass = pClass;
434 m_usable = !(pClass->GetFlags() & ECLF_INVISIBLE);
437 //////////////////////////////////////////////////////////////////////////
438 string CEntityScript::GetName() const
440 return m_pClass->GetName();
443 //////////////////////////////////////////////////////////////////////////
444 string CEntityScript::GetFile() const
446 if (IEntityScriptFileHandler* pScriptFileHandler = m_pClass->GetScriptFileHandler())
447 return pScriptFileHandler->GetScriptFile();
449 return m_pClass->GetScriptFile();
452 //////////////////////////////////////////////////////////////////////////
453 int CEntityScript::GetEventCount()
455 if (IEntityEventHandler* pEventHandler = m_pClass->GetEventHandler())
456 return pEventHandler->GetEventCount();
458 return (int)m_events.size();
461 //////////////////////////////////////////////////////////////////////////
462 const char* CEntityScript::GetEvent(int i)
464 if (IEntityEventHandler* pEventHandler = m_pClass->GetEventHandler())
466 IEntityEventHandler::SEventInfo info;
467 pEventHandler->GetEventInfo(i, info);
469 return info.name;
472 return m_events[i];
475 //////////////////////////////////////////////////////////////////////////
476 int CEntityScript::GetEmptyLinkCount()
478 return (int)m_emptyLinks.size();
481 //////////////////////////////////////////////////////////////////////////
482 const string& CEntityScript::GetEmptyLink(int i)
484 return m_emptyLinks[i];
487 //////////////////////////////////////////////////////////////////////////
488 bool CEntityScript::Load()
490 m_bValid = true;
492 if (strlen(m_pClass->GetScriptFile()) > 0)
494 if (m_pClass->LoadScript(false))
496 //Feed script file to the lua comment parser for processing
497 LuaCommentParser::GetInstance()->OpenScriptFile(m_pClass->GetScriptFile());
499 // If class have script parse this script.
500 m_bValid = ParseScript();
502 LuaCommentParser::GetInstance()->CloseScriptFile();
504 else
505 CryWarning(VALIDATOR_MODULE_EDITOR, VALIDATOR_WARNING, "Entity class %s failed to load, (script: %s could not be loaded)", m_pClass->GetName(), m_pClass->GetScriptFile());
507 else
509 // No script file: parse the script tables
510 // which should have been specified by game code.
511 ParseScript();
514 return m_bValid;
517 //////////////////////////////////////////////////////////////////////////
518 bool CEntityScript::ParseScript()
520 // Parse .lua file.
521 IScriptSystem* script = GetIEditorImpl()->GetSystem()->GetIScriptSystem();
523 SmartScriptTable pEntity(script, true);
524 if (!script->GetGlobalValue(GetName(), pEntity))
526 return false;
529 m_bValid = true;
531 pEntity->GetValue("OnPropertyChange", m_pOnPropertyChangedFunc);
533 CScriptMethodsDump dump;
534 pEntity->Dump(&dump);
535 m_methods = dump.methods;
536 m_events = dump.events;
538 //! Sort methods and events.
539 std::sort(m_methods.begin(), m_methods.end());
540 std::sort(m_events.begin(), m_events.end());
542 m_emptyLinks.clear();
545 // Normal properties.
546 m_pDefaultProperties = 0;
547 SmartScriptTable pProps(script, true);
548 if (pEntity->GetValue(PROPERTIES_TABLE, pProps))
550 // Properties found in entity.
551 m_pDefaultProperties = new CVarBlock;
552 CScriptPropertiesDump dump(m_pDefaultProperties);
553 dump.Dump(*pProps, PROPERTIES_TABLE);
558 // Second set of properties.
559 m_pDefaultProperties2 = 0;
560 SmartScriptTable pProps(script, true);
561 if (pEntity->GetValue(PROPERTIES2_TABLE, pProps))
563 // Properties found in entity.
564 m_pDefaultProperties2 = new CVarBlock;
565 CScriptPropertiesDump dump(m_pDefaultProperties2);
566 dump.Dump(*pProps, PROPERTIES2_TABLE);
570 // Destroy variable block if empty.
571 /*if ( m_pDefaultProperties && m_pDefaultProperties->IsEmpty() )
573 m_pDefaultProperties = nullptr;
576 // Destroy variable block if empty.
577 if ( m_pDefaultProperties2 && m_pDefaultProperties2->IsEmpty() )
579 m_pDefaultProperties2 = nullptr;
582 if (m_pDefaultProperties != 0 && m_pDefaultProperties->GetNumVariables() < 1)
584 m_pDefaultProperties = 0;
587 // Destroy variable block if empty.
588 if (m_pDefaultProperties2 != 0 && m_pDefaultProperties2->GetNumVariables() < 1)
590 m_pDefaultProperties2 = 0;
593 // Load visual object.
594 SmartScriptTable pEditorTable(script, true);
595 if (pEntity->GetValue("Editor", pEditorTable))
597 SEditorClassInfo classInfo = m_pClass->GetEditorClassInfo();
599 const char* modelName;
600 if (pEditorTable->GetValue("Model", modelName))
602 classInfo.sHelper = modelName;
605 bool bShowBounds = false;
606 pEditorTable->GetValue("ShowBounds", bShowBounds);
607 if (bShowBounds)
609 m_nFlags |= ENTITY_SCRIPT_SHOWBOUNDS;
611 else
613 m_nFlags &= ~ENTITY_SCRIPT_SHOWBOUNDS;
616 bool isScalable = true;
617 pEditorTable->GetValue("IsScalable", isScalable);
618 if (!isScalable)
620 m_nFlags |= ENTITY_SCRIPT_ISNOTSCALABLE;
622 else
624 m_nFlags &= ~ENTITY_SCRIPT_ISNOTSCALABLE;
627 bool isRotatable = true;
628 pEditorTable->GetValue("IsRotatable", isRotatable);
629 if (!isRotatable)
631 m_nFlags |= ENTITY_SCRIPT_ISNOTROTATABLE;
633 else
635 m_nFlags &= ~ENTITY_SCRIPT_ISNOTROTATABLE;
638 bool bAbsoluteRadius = false;
639 pEditorTable->GetValue("AbsoluteRadius", bAbsoluteRadius);
640 if (bAbsoluteRadius)
642 m_nFlags |= ENTITY_SCRIPT_ABSOLUTERADIUS;
644 else
646 m_nFlags &= ~ENTITY_SCRIPT_ABSOLUTERADIUS;
649 const char* iconName = "";
650 if (pEditorTable->GetValue("Icon", iconName))
652 classInfo.sIcon = PathUtil::Make("%EDITOR%/ObjectIcons", iconName);
655 classInfo.bIconOnTop = false;
656 pEditorTable->GetValue("IconOnTop", classInfo.bIconOnTop);
658 bool bArrow = false;
659 pEditorTable->GetValue("DisplayArrow", bArrow);
660 if (bArrow)
662 m_nFlags |= ENTITY_SCRIPT_DISPLAY_ARROW;
664 else
666 m_nFlags &= ~ENTITY_SCRIPT_DISPLAY_ARROW;
669 SmartScriptTable pLinksTable(script, true);
670 if (pEditorTable->GetValue("Links", pLinksTable))
672 IScriptTable::Iterator iter = pLinksTable->BeginIteration();
673 while (pLinksTable->MoveNext(iter))
675 if (iter.value.GetType() == EScriptAnyType::String)
677 const char* sLinkName = iter.value.GetString();
678 m_emptyLinks.push_back(sLinkName);
681 pLinksTable->EndIteration(iter);
684 const char* editorPath = "";
685 if (pEditorTable->GetValue("EditorPath", editorPath))
687 m_userPath = editorPath;
690 m_pClass->SetEditorClassInfo(classInfo);
693 return true;
696 //////////////////////////////////////////////////////////////////////////
697 void CEntityScript::Reload()
699 if (IEntityScriptFileHandler* pScriptFileHandler = m_pClass->GetScriptFileHandler())
700 pScriptFileHandler->ReloadScriptFile();
702 bool bReloaded = false;
703 IEntityScript* pScript = m_pClass->GetIEntityScript();
704 if (pScript)
706 // First try compiling script and see if it have any errors.
707 bool bLoadScript = CFileUtil::CompileLuaFile(m_pClass->GetScriptFile());
708 if (bLoadScript)
710 bReloaded = m_pClass->LoadScript(true);
714 if (bReloaded)
716 // Script compiled successfully.
717 Load();
721 //////////////////////////////////////////////////////////////////////////
722 void CEntityScript::GotoMethod(const string& method)
724 string line;
725 line.Format("%s:%s", (const char*)GetName(), (const char*)method);
727 // Search this line in script file.
728 int lineNum = FindLineNum(line);
729 if (lineNum >= 0)
731 // Open UltraEdit32 with this line.
732 CFileUtil::EditTextFile(GetFile(), lineNum);
736 void CEntityScript::AddMethod(const string& method)
738 // Add a new method to the file. and start Editing it.
739 FILE* f = fopen(GetFile(), "at");
740 if (f)
742 fprintf(f, "\n");
743 fprintf(f, "-------------------------------------------------------\n");
744 fprintf(f, "function %s:%s()\n", (const char*)m_pClass->GetName(), (const char*)method);
745 fprintf(f, "end\n");
746 fclose(f);
750 const string& CEntityScript::GetDisplayPath()
752 if (m_userPath.IsEmpty())
754 IScriptSystem* script = GetIEditorImpl()->GetSystem()->GetIScriptSystem();
756 SmartScriptTable pEntity(script, true);
757 if (!script->GetGlobalValue(GetName(), pEntity))
759 m_userPath = "Default/" + GetName();
760 return m_userPath;
763 SmartScriptTable pEditorTable(script, true);
764 if (pEntity->GetValue("Editor", pEditorTable))
766 const char* editorPath = "";
767 if (pEditorTable->GetValue("EditorPath", editorPath))
769 m_userPath = editorPath;
774 return m_userPath;
777 //////////////////////////////////////////////////////////////////////////
778 int CEntityScript::FindLineNum(const string& line)
780 FILE* fileHandle = fopen(GetFile(), "rb");
781 if (!fileHandle)
783 return -1;
786 int lineFound = -1;
787 int lineNum = 1;
789 fseek(fileHandle, 0, SEEK_END);
790 int size = ftell(fileHandle);
791 fseek(fileHandle, 0, SEEK_SET);
793 char* text = new char[size + 16];
794 fread(text, size, 1, fileHandle);
795 text[size] = 0;
797 char* token = strtok(text, "\n");
798 while (token)
800 if (strstr(token, line) != 0)
802 lineFound = lineNum;
803 break;
805 token = strtok(NULL, "\n");
806 lineNum++;
809 fclose(fileHandle);
810 delete[]text;
812 return lineFound;
815 //////////////////////////////////////////////////////////////////////////
816 void CEntityScript::CopyPropertiesToScriptTable(IEntity* pEntity, CVarBlock* pVarBlock, bool bCallUpdate)
818 CopyPropertiesToScriptInternal(pEntity, pVarBlock, bCallUpdate, PROPERTIES_TABLE);
821 //////////////////////////////////////////////////////////////////////////
822 void CEntityScript::CopyProperties2ToScriptTable(IEntity* pEntity, CVarBlock* pVarBlock, bool bCallUpdate)
824 CopyPropertiesToScriptInternal(pEntity, pVarBlock, bCallUpdate, PROPERTIES2_TABLE);
827 //////////////////////////////////////////////////////////////////////////
828 void CEntityScript::CopyPropertiesToScriptInternal(IEntity* pEntity, CVarBlock* pVarBlock, bool bCallUpdate, const char* tableKey)
830 if (!IsValid())
832 return;
835 assert(pEntity != 0);
836 assert(pVarBlock != 0);
838 IScriptTable* scriptTable = pEntity->GetScriptTable();
839 if (!scriptTable)
841 // ENTITY TODO: Don't create CEntityScript in this case
842 return;
845 IScriptSystem* pScriptSystem = GetIEditorImpl()->GetSystem()->GetIScriptSystem();
847 SmartScriptTable table(pScriptSystem, true);
848 if (!scriptTable->GetValue(tableKey, table))
850 return;
853 for (int i = 0; i < pVarBlock->GetNumVariables(); i++)
855 VarToScriptTable(pVarBlock->GetVariable(i), table);
858 if (bCallUpdate)
860 CallOnPropertyChange(pEntity);
864 //////////////////////////////////////////////////////////////////////////
865 void CEntityScript::CallOnPropertyChange(IEntity* pEntity)
867 if (!IsValid())
869 return;
872 if (m_pOnPropertyChangedFunc)
874 assert(pEntity != 0);
875 IScriptTable* pScriptObject = pEntity->GetScriptTable();
876 if (!pScriptObject)
877 return;
878 Script::CallMethod(pScriptObject, m_pOnPropertyChangedFunc);
881 SEntityEvent entityEvent(ENTITY_EVENT_EDITOR_PROPERTY_CHANGED);
882 pEntity->SendEvent(entityEvent);
885 //////////////////////////////////////////////////////////////////////////
886 void CEntityScript::VarToScriptTable(IVariable* pVariable, IScriptTable* pScriptTable)
888 assert(pVariable);
890 IScriptSystem* pScriptSystem = GetIEditorImpl()->GetSystem()->GetIScriptSystem();
892 if (pVariable->GetType() == IVariable::ARRAY)
894 int type = pScriptTable->GetValueType(pVariable->GetName());
895 if (type != svtObject)
897 return;
900 SmartScriptTable table(pScriptSystem, true);
901 if (pScriptTable->GetValue(pVariable->GetName(), table))
903 for (int i = 0; i < pVariable->GetNumVariables(); i++)
905 IVariable* child = pVariable->GetVariable(i);
906 VarToScriptTable(child, table);
909 return;
912 const char* name = pVariable->GetName();
913 int type = pScriptTable->GetValueType(name);
915 if (type == svtString)
917 string value;
918 pVariable->Get(value);
919 pScriptTable->SetValue(name, (const char*)value);
921 else if (type == svtNumber)
923 float val = 0;
924 pVariable->Get(val);
925 pScriptTable->SetValue(name, val);
927 else if (type == svtBool)
929 bool val = false;
930 pVariable->Get(val);
931 pScriptTable->SetValue(name, val);
933 else if (type == svtObject)
935 // Probably Color/Vector.
936 SmartScriptTable table(pScriptSystem, true);
937 if (pScriptTable->GetValue(name, table))
939 if (pVariable->GetType() == IVariable::VECTOR)
941 Vec3 vec;
942 pVariable->Get(vec);
944 float temp;
945 if (table->GetValue("x", temp))
947 // Named vector.
948 table->SetValue("x", vec.x);
949 table->SetValue("y", vec.y);
950 table->SetValue("z", vec.z);
952 else
954 // Indexed vector.
955 table->SetAt(1, vec.x);
956 table->SetAt(2, vec.y);
957 table->SetAt(3, vec.z);
964 //////////////////////////////////////////////////////////////////////////
965 void CEntityScript::CopyPropertiesFromScriptTable(IEntity* pEntity, CVarBlock* pVarBlock)
967 CopyPropertiesFromScriptInternal(pEntity, pVarBlock, PROPERTIES_TABLE);
970 //////////////////////////////////////////////////////////////////////////
971 void CEntityScript::CopyProperties2FromScriptTable(IEntity* pEntity, CVarBlock* pVarBlock)
973 CopyPropertiesFromScriptInternal(pEntity, pVarBlock, PROPERTIES2_TABLE);
976 //////////////////////////////////////////////////////////////////////////
977 void CEntityScript::CopyPropertiesFromScriptInternal(IEntity* pEntity, CVarBlock* pVarBlock, const char* tableKey)
979 if (!IsValid())
981 return;
984 assert(pEntity != 0);
985 assert(pVarBlock != 0);
987 IScriptTable* scriptTable = pEntity->GetScriptTable();
988 if (!scriptTable)
990 return;
993 IScriptSystem* pScriptSystem = GetIEditorImpl()->GetSystem()->GetIScriptSystem();
995 SmartScriptTable table(pScriptSystem, true);
996 if (!scriptTable->GetValue(tableKey, table))
998 return;
1001 for (int i = 0; i < pVarBlock->GetNumVariables(); i++)
1003 ScriptTableToVar(table, pVarBlock->GetVariable(i));
1007 //////////////////////////////////////////////////////////////////////////
1008 void CEntityScript::ScriptTableToVar(IScriptTable* pScriptTable, IVariable* pVariable)
1010 assert(pVariable);
1012 IScriptSystem* pScriptSystem = GetIEditorImpl()->GetSystem()->GetIScriptSystem();
1014 if (pVariable->GetType() == IVariable::ARRAY)
1016 int type = pScriptTable->GetValueType(pVariable->GetName());
1017 if (type != svtObject)
1019 return;
1022 SmartScriptTable table(pScriptSystem, true);
1023 if (pScriptTable->GetValue(pVariable->GetName(), table))
1025 for (int i = 0; i < pVariable->GetNumVariables(); i++)
1027 IVariable* child = pVariable->GetVariable(i);
1028 ScriptTableToVar(table, child);
1031 return;
1034 const char* name = pVariable->GetName();
1035 int type = pScriptTable->GetValueType(name);
1037 if (type == svtString)
1039 const char* value;
1040 pScriptTable->GetValue(name, value);
1041 pVariable->Set(value);
1043 else if (type == svtNumber)
1045 float val = 0;
1046 pScriptTable->GetValue(name, val);
1047 pVariable->Set(val);
1049 else if (type == svtBool)
1051 bool val = false;
1052 pScriptTable->GetValue(name, val);
1053 pVariable->Set(val);
1055 else if (type == svtObject)
1057 // Probably Color/Vector.
1058 SmartScriptTable table(pScriptSystem, true);
1059 if (pScriptTable->GetValue(name, table))
1061 if (pVariable->GetType() == IVariable::VECTOR)
1063 Vec3 vec;
1065 float temp;
1066 if (table->GetValue("x", temp))
1068 // Named vector.
1069 table->GetValue("x", vec.x);
1070 table->GetValue("y", vec.y);
1071 table->GetValue("z", vec.z);
1073 else
1075 // Indexed vector.
1076 table->GetAt(1, vec.x);
1077 table->GetAt(2, vec.y);
1078 table->GetAt(3, vec.z);
1081 pVariable->Set(vec);
1087 //////////////////////////////////////////////////////////////////////////
1088 void CEntityScript::RunMethod(IEntity* pEntity, const string& method)
1090 if (!IsValid())
1092 return;
1095 assert(pEntity != 0);
1097 IScriptTable* scriptTable = pEntity->GetScriptTable();
1098 if (!scriptTable)
1100 return;
1103 IScriptSystem* scriptSystem = GetIEditorImpl()->GetSystem()->GetIScriptSystem();
1105 Script::CallMethod(scriptTable, (const char*)method);
1108 //////////////////////////////////////////////////////////////////////////
1109 void CEntityScript::SendEvent(IEntity* pEntity, const string& method)
1111 if (IEntityEventHandler* pEventHandler = m_pClass->GetEventHandler())
1112 pEventHandler->SendEvent(pEntity, method);
1114 // Fire event on Entity.
1115 IEntityScriptComponent* pScriptProxy = (IEntityScriptComponent*)pEntity->GetProxy(ENTITY_PROXY_SCRIPT);
1116 if (pScriptProxy)
1118 pScriptProxy->CallEvent(method);
1122 //////////////////////////////////////////////////////////////////////////
1123 void CEntityScript::SetEventsTable(CEntityObject* pEntity)
1125 if (!IsValid())
1127 return;
1129 assert(pEntity != 0);
1131 IEntity* ientity = pEntity->GetIEntity();
1132 if (!ientity)
1134 return;
1137 IScriptTable* scriptTable = ientity->GetScriptTable();
1138 if (!scriptTable)
1140 return;
1143 // If events target table is null, set event table to null either.
1144 if (pEntity->GetEventTargetCount() == 0)
1146 if (m_haveEventsTable)
1148 scriptTable->SetToNull("Events");
1150 m_haveEventsTable = false;
1151 return;
1154 IScriptSystem* scriptSystem = GetIEditorImpl()->GetSystem()->GetIScriptSystem();
1155 SmartScriptTable pEvents(scriptSystem, false);
1157 scriptTable->SetValue("Events", *pEvents);
1158 m_haveEventsTable = true;
1160 std::set<string> sourceEvents;
1161 for (int i = 0; i < pEntity->GetEventTargetCount(); i++)
1163 CEntityEventTarget& et = pEntity->GetEventTarget(i);
1164 sourceEvents.insert(et.sourceEvent);
1166 for (std::set<string>::iterator it = sourceEvents.begin(); it != sourceEvents.end(); it++)
1168 SmartScriptTable pTrgEvents(scriptSystem, false);
1169 string sourceEvent = *it;
1171 pEvents->SetValue(sourceEvent, *pTrgEvents);
1173 // Put target events to table.
1174 int trgEventIndex = 1;
1175 for (int i = 0; i < pEntity->GetEventTargetCount(); i++)
1177 CEntityEventTarget& et = pEntity->GetEventTarget(i);
1178 if (stricmp(et.sourceEvent, sourceEvent) == 0)
1180 EntityId entityId = 0;
1181 if (et.target)
1183 if (et.target->IsKindOf(RUNTIME_CLASS(CEntityObject)))
1185 entityId = ((CEntityObject*)et.target)->GetEntityId();
1189 SmartScriptTable pTrgEvent(scriptSystem, false);
1190 pTrgEvents->SetAt(trgEventIndex, *pTrgEvent);
1191 trgEventIndex++;
1193 ScriptHandle idHandle;
1194 idHandle.n = entityId;
1196 pTrgEvent->SetAt(1, idHandle);
1197 pTrgEvent->SetAt(2, (const char*)et.event);
1203 //////////////////////////////////////////////////////////////////////////
1204 void CEntityScript::UpdateTextureIcon(IEntity* pEntity)
1206 if (pEntity)
1208 // Try to call a function GetEditorIcon on the script, to give it a change to return
1209 // a custom icon.
1210 IScriptTable* pScriptTable = pEntity->GetScriptTable();
1211 if (pScriptTable != NULL && pScriptTable->GetValueType("GetEditorIcon") == svtFunction)
1213 SmartScriptTable iconData(gEnv->pScriptSystem);
1214 if (Script::CallMethod(pScriptTable, "GetEditorIcon", iconData))
1216 const char* iconName = NULL;
1217 iconData->GetValue("Icon", iconName);
1219 SEditorClassInfo classInfo = m_pClass->GetEditorClassInfo();
1220 classInfo.sIcon = PathUtil::Make("%EDITOR%/ObjectIcons", iconName);
1221 m_pClass->SetEditorClassInfo(classInfo);
1227 //////////////////////////////////////////////////////////////////////////
1228 // CEntityScriptRegistry implementation.
1229 //////////////////////////////////////////////////////////////////////////
1230 CEntityScriptRegistry* CEntityScriptRegistry::m_instance = 0;
1232 CEntityScriptRegistry::CEntityScriptRegistry() :
1233 m_needsScriptReload(false)
1235 gEnv->pEntitySystem->GetClassRegistry()->RegisterListener(this);
1236 GetIEditorImpl()->RegisterNotifyListener(this);
1239 CEntityScriptRegistry::~CEntityScriptRegistry()
1241 m_instance = 0;
1242 m_scripts.clear();
1243 gEnv->pEntitySystem->GetClassRegistry()->UnregisterListener(this);
1244 GetIEditorImpl()->UnregisterNotifyListener(this);
1247 //////////////////////////////////////////////////////////////////////////
1248 void CEntityScriptRegistry::OnEntityClassRegistryEvent(EEntityClassRegistryEvent event, const IEntityClass* pEntityClass)
1250 switch (event)
1252 case ECRE_CLASS_REGISTERED:
1253 case ECRE_CLASS_MODIFIED:
1255 auto pEntityScript = Find(pEntityClass->GetName());
1256 if (pEntityScript != nullptr)
1258 pEntityScript->SetClass(const_cast<IEntityClass*>(pEntityClass));
1260 else
1262 pEntityScript = Insert(const_cast<IEntityClass*>(pEntityClass));
1265 if (pEntityScript)
1267 if (event == ECRE_CLASS_REGISTERED)
1269 m_scriptAdded(pEntityScript.get());
1271 else
1273 m_scriptChanged(pEntityScript.get());
1277 // We only need to reload entities in case a script class was changed, since schematyc handles reloading themself.
1278 if (pEntityClass->GetScriptFile() != nullptr && pEntityClass->GetScriptFile()[0] != '\0')
1280 m_needsScriptReload = true;
1283 break;
1284 case ECRE_CLASS_UNREGISTERED:
1286 auto pEntityScript = Find(pEntityClass->GetName());
1288 m_scriptRemoved(pEntityScript.get());
1289 m_scripts.erase(pEntityClass->GetName());
1291 break;
1295 void CEntityScriptRegistry::OnEditorNotifyEvent(EEditorNotifyEvent event)
1297 if (event == eNotify_OnIdleUpdate && m_needsScriptReload)
1299 m_needsScriptReload = false;
1300 GetIEditorImpl()->GetICommandManager()->Execute("entity.reload_all_scripts");
1304 std::shared_ptr<CEntityScript> CEntityScriptRegistry::Find(const char* szName) const
1306 auto it = m_scripts.find(szName);
1307 if (it != m_scripts.end())
1309 return it->second;
1312 return nullptr;
1315 std::shared_ptr<CEntityScript> CEntityScriptRegistry::Insert(IEntityClass* pClass, const char* szAlias)
1317 if (strlen(szAlias) == 0)
1319 szAlias = pClass->GetName();
1322 auto scriptIt = m_scripts.find(szAlias);
1324 // Check if inserting already exist script, if so ignore.
1325 if (scriptIt != m_scripts.end())
1327 Error("Inserting duplicate Entity Script %s", szAlias);
1328 return scriptIt->second;
1331 scriptIt = m_scripts.emplace(std::make_pair(string(szAlias), std::make_shared<CEntityScript>(pClass))).first;
1333 SetClassCategory(scriptIt->second.get());
1334 return scriptIt->second;
1337 void CEntityScriptRegistry::SetClassCategory(CEntityScript* script)
1339 IScriptSystem* scriptSystem = GetIEditorImpl()->GetSystem()->GetIScriptSystem();
1341 SmartScriptTable pEntity(scriptSystem, true);
1342 if (!scriptSystem->GetGlobalValue(script->GetName(), pEntity))
1343 return;
1345 SmartScriptTable pEditor(scriptSystem, true);
1346 if (pEntity->GetValue("Editor", pEditor))
1348 const char* clsCategory;
1349 if (pEditor->GetValue("Category", clsCategory))
1351 SEditorClassInfo editorClassInfo(script->GetClass()->GetEditorClassInfo());
1352 editorClassInfo.sCategory = clsCategory;
1353 script->GetClass()->SetEditorClassInfo(editorClassInfo);
1358 void CEntityScriptRegistry::IterateOverScripts(std::function<void(CEntityScript&)> callback)
1360 for (auto it = m_scripts.begin(); it != m_scripts.end(); ++it)
1362 callback(*it->second);
1366 //////////////////////////////////////////////////////////////////////////
1367 void CEntityScriptRegistry::Reload()
1369 IEntityClassRegistry* pClassRegistry = gEnv->pEntitySystem->GetClassRegistry();
1370 pClassRegistry->LoadClasses("entities.xml", true);
1371 LoadScripts();
1374 //////////////////////////////////////////////////////////////////////////
1375 void CEntityScriptRegistry::LoadScripts()
1377 m_scripts.clear();
1379 IEntityClassRegistry* pClassRegistry = gEnv->pEntitySystem->GetClassRegistry();
1380 IEntityClass* pClass = NULL;
1381 pClassRegistry->IteratorMoveFirst();
1382 while (pClass = pClassRegistry->IteratorNext())
1384 Insert(pClass);
1388 //////////////////////////////////////////////////////////////////////////
1389 CEntityScriptRegistry* CEntityScriptRegistry::Instance()
1391 if (!m_instance)
1393 m_instance = new CEntityScriptRegistry;
1395 return m_instance;
1398 //////////////////////////////////////////////////////////////////////////
1399 void CEntityScriptRegistry::Release()
1401 if (m_instance)
1403 delete m_instance;
1405 m_instance = 0;