1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
4 #include "EntityScript.h"
5 #include "EntityObject.h"
7 #include <CryScriptSystem/IScriptSystem.h>
8 #include <CryEntitySystem/IEntitySystem.h>
9 #include "LuaCommentParser.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);
29 methods
.push_back(sName
);
35 enum EScriptParamFlags
37 SCRIPTPARAM_POSITIVE
= 0x01,
40 //////////////////////////////////////////////////////////////////////////
44 IVariable::EType type
;
45 IVariable::EDataType dataType
;
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 },
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
126 std::vector
<Variable
> m_elements
;
128 CVarBlock
* m_varBlock
;
129 IVariable
* m_parentVar
;
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
)
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)
162 //////////////////////////////////////////////////////////////////////////
163 IVariable
* CreateVarByType(IVariable::EType type
)
167 case IVariable::FLOAT
:
168 return new CVariable
<float>;
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
>;
185 //////////////////////////////////////////////////////////////////////////
186 IVariable
* CreateVar(const char* name
, IVariable::EType defaultType
, const char*& displayName
)
189 // Resolve type from variable name.
190 int nameLen
= strlen(name
);
196 nFlags
|= IVariable::UI_INVISIBLE
;
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] == '_')
211 if (displayName
[0] == '\0')
216 IVariable::EType type
= s_scriptParamTypes
[i
].type
;
217 IVariable::EDataType dataType
= s_scriptParamTypes
[i
].dataType
;
220 if (type
== IVariable::STRING
&&
221 (dataType
== IVariable::DT_AITERRITORY
|| dataType
== IVariable::DT_AIWAVE
))
223 var
= new CVariableEnum
<string
>;
227 var
= CreateVarByType(type
);
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);
250 if (defaultType
!= IVariable::UNKNOWN
)
252 IVariable
* var
= CreateVarByType(defaultType
);
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)
273 m_elements
.push_back(var
);
277 //////////////////////////////////////////////////////////////////////////
278 void Dump(IScriptTable
* pObject
, string sTablePath
)
280 m_elements
.reserve(20);
282 typedef std::map
<string
, IVariablePtr
, stl::less_stricmp
<string
>> NodesMap
;
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
)
296 pObject
->GetValue(sName
, fVal
);
297 IVariable
* var
= CreateVar(sName
, IVariable::FLOAT
, sDisplayName
);
302 //use lua comment parser to read comment about limit settings
303 float minVal
, maxVal
, stepVal
;
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
)
317 pObject
->GetValue(sName
, sVal
);
318 IVariable
* var
= CreateVar(sName
, IVariable::STRING
, sDisplayName
);
322 nodes
[sDisplayName
] = var
;
325 else if (type
== svtBool
)
328 pObject
->GetValue(sName
, val
);
329 IVariable
* pVar
= CreateVar(sName
, IVariable::BOOL
, sDisplayName
);
333 nodes
[sDisplayName
] = pVar
;
336 else if (type
== svtFunction
)
340 else if (type
== svtObject
)
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
;
351 if (pTable
->GetValue("x", x
) && pTable
->GetValue("y", y
) && pTable
->GetValue("z", z
))
353 var
->Set(Vec3(x
, y
, z
));
360 var
->Set(Vec3(x
, y
, z
));
370 var
= new CVariableArray
;
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
++)
385 m_parentVar
->AddVariable(nit
->second
);
389 m_varBlock
->AddVariable(nit
->second
);
393 for (NodesMap::iterator nit1
= listNodes
.begin(); nit1
!= listNodes
.end(); nit1
++)
397 m_parentVar
->AddVariable(nit1
->second
);
401 m_varBlock
->AddVariable(nit1
->second
);
407 //////////////////////////////////////////////////////////////////////////
408 //////////////////////////////////////////////////////////////////////////
410 //////////////////////////////////////////////////////////////////////////
411 CEntityScript::CEntityScript(IEntityClass
* pClass
)
415 m_haveEventsTable
= false;
416 m_visibilityMask
= 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
)
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
);
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()
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();
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());
509 // No script file: parse the script tables
510 // which should have been specified by game code.
517 //////////////////////////////////////////////////////////////////////////
518 bool CEntityScript::ParseScript()
521 IScriptSystem
* script
= GetIEditorImpl()->GetSystem()->GetIScriptSystem();
523 SmartScriptTable
pEntity(script
, true);
524 if (!script
->GetGlobalValue(GetName(), pEntity
))
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
);
609 m_nFlags
|= ENTITY_SCRIPT_SHOWBOUNDS
;
613 m_nFlags
&= ~ENTITY_SCRIPT_SHOWBOUNDS
;
616 bool isScalable
= true;
617 pEditorTable
->GetValue("IsScalable", isScalable
);
620 m_nFlags
|= ENTITY_SCRIPT_ISNOTSCALABLE
;
624 m_nFlags
&= ~ENTITY_SCRIPT_ISNOTSCALABLE
;
627 bool isRotatable
= true;
628 pEditorTable
->GetValue("IsRotatable", isRotatable
);
631 m_nFlags
|= ENTITY_SCRIPT_ISNOTROTATABLE
;
635 m_nFlags
&= ~ENTITY_SCRIPT_ISNOTROTATABLE
;
638 bool bAbsoluteRadius
= false;
639 pEditorTable
->GetValue("AbsoluteRadius", bAbsoluteRadius
);
642 m_nFlags
|= ENTITY_SCRIPT_ABSOLUTERADIUS
;
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
);
659 pEditorTable
->GetValue("DisplayArrow", bArrow
);
662 m_nFlags
|= ENTITY_SCRIPT_DISPLAY_ARROW
;
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
);
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();
706 // First try compiling script and see if it have any errors.
707 bool bLoadScript
= CFileUtil::CompileLuaFile(m_pClass
->GetScriptFile());
710 bReloaded
= m_pClass
->LoadScript(true);
716 // Script compiled successfully.
721 //////////////////////////////////////////////////////////////////////////
722 void CEntityScript::GotoMethod(const string
& method
)
725 line
.Format("%s:%s", (const char*)GetName(), (const char*)method
);
727 // Search this line in script file.
728 int lineNum
= FindLineNum(line
);
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");
743 fprintf(f
, "-------------------------------------------------------\n");
744 fprintf(f
, "function %s:%s()\n", (const char*)m_pClass
->GetName(), (const char*)method
);
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();
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
;
777 //////////////////////////////////////////////////////////////////////////
778 int CEntityScript::FindLineNum(const string
& line
)
780 FILE* fileHandle
= fopen(GetFile(), "rb");
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
);
797 char* token
= strtok(text
, "\n");
800 if (strstr(token
, line
) != 0)
805 token
= strtok(NULL
, "\n");
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
)
835 assert(pEntity
!= 0);
836 assert(pVarBlock
!= 0);
838 IScriptTable
* scriptTable
= pEntity
->GetScriptTable();
841 // ENTITY TODO: Don't create CEntityScript in this case
845 IScriptSystem
* pScriptSystem
= GetIEditorImpl()->GetSystem()->GetIScriptSystem();
847 SmartScriptTable
table(pScriptSystem
, true);
848 if (!scriptTable
->GetValue(tableKey
, table
))
853 for (int i
= 0; i
< pVarBlock
->GetNumVariables(); i
++)
855 VarToScriptTable(pVarBlock
->GetVariable(i
), table
);
860 CallOnPropertyChange(pEntity
);
864 //////////////////////////////////////////////////////////////////////////
865 void CEntityScript::CallOnPropertyChange(IEntity
* pEntity
)
872 if (m_pOnPropertyChangedFunc
)
874 assert(pEntity
!= 0);
875 IScriptTable
* pScriptObject
= pEntity
->GetScriptTable();
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
)
890 IScriptSystem
* pScriptSystem
= GetIEditorImpl()->GetSystem()->GetIScriptSystem();
892 if (pVariable
->GetType() == IVariable::ARRAY
)
894 int type
= pScriptTable
->GetValueType(pVariable
->GetName());
895 if (type
!= svtObject
)
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
);
912 const char* name
= pVariable
->GetName();
913 int type
= pScriptTable
->GetValueType(name
);
915 if (type
== svtString
)
918 pVariable
->Get(value
);
919 pScriptTable
->SetValue(name
, (const char*)value
);
921 else if (type
== svtNumber
)
925 pScriptTable
->SetValue(name
, val
);
927 else if (type
== svtBool
)
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
)
945 if (table
->GetValue("x", temp
))
948 table
->SetValue("x", vec
.x
);
949 table
->SetValue("y", vec
.y
);
950 table
->SetValue("z", vec
.z
);
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
)
984 assert(pEntity
!= 0);
985 assert(pVarBlock
!= 0);
987 IScriptTable
* scriptTable
= pEntity
->GetScriptTable();
993 IScriptSystem
* pScriptSystem
= GetIEditorImpl()->GetSystem()->GetIScriptSystem();
995 SmartScriptTable
table(pScriptSystem
, true);
996 if (!scriptTable
->GetValue(tableKey
, table
))
1001 for (int i
= 0; i
< pVarBlock
->GetNumVariables(); i
++)
1003 ScriptTableToVar(table
, pVarBlock
->GetVariable(i
));
1007 //////////////////////////////////////////////////////////////////////////
1008 void CEntityScript::ScriptTableToVar(IScriptTable
* pScriptTable
, IVariable
* pVariable
)
1012 IScriptSystem
* pScriptSystem
= GetIEditorImpl()->GetSystem()->GetIScriptSystem();
1014 if (pVariable
->GetType() == IVariable::ARRAY
)
1016 int type
= pScriptTable
->GetValueType(pVariable
->GetName());
1017 if (type
!= svtObject
)
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
);
1034 const char* name
= pVariable
->GetName();
1035 int type
= pScriptTable
->GetValueType(name
);
1037 if (type
== svtString
)
1040 pScriptTable
->GetValue(name
, value
);
1041 pVariable
->Set(value
);
1043 else if (type
== svtNumber
)
1046 pScriptTable
->GetValue(name
, val
);
1047 pVariable
->Set(val
);
1049 else if (type
== svtBool
)
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
)
1066 if (table
->GetValue("x", temp
))
1069 table
->GetValue("x", vec
.x
);
1070 table
->GetValue("y", vec
.y
);
1071 table
->GetValue("z", vec
.z
);
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
)
1095 assert(pEntity
!= 0);
1097 IScriptTable
* scriptTable
= pEntity
->GetScriptTable();
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
);
1118 pScriptProxy
->CallEvent(method
);
1122 //////////////////////////////////////////////////////////////////////////
1123 void CEntityScript::SetEventsTable(CEntityObject
* pEntity
)
1129 assert(pEntity
!= 0);
1131 IEntity
* ientity
= pEntity
->GetIEntity();
1137 IScriptTable
* scriptTable
= ientity
->GetScriptTable();
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;
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;
1183 if (et
.target
->IsKindOf(RUNTIME_CLASS(CEntityObject
)))
1185 entityId
= ((CEntityObject
*)et
.target
)->GetEntityId();
1189 SmartScriptTable
pTrgEvent(scriptSystem
, false);
1190 pTrgEvents
->SetAt(trgEventIndex
, *pTrgEvent
);
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
)
1208 // Try to call a function GetEditorIcon on the script, to give it a change to return
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()
1243 gEnv
->pEntitySystem
->GetClassRegistry()->UnregisterListener(this);
1244 GetIEditorImpl()->UnregisterNotifyListener(this);
1247 //////////////////////////////////////////////////////////////////////////
1248 void CEntityScriptRegistry::OnEntityClassRegistryEvent(EEntityClassRegistryEvent event
, const IEntityClass
* pEntityClass
)
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
));
1262 pEntityScript
= Insert(const_cast<IEntityClass
*>(pEntityClass
));
1267 if (event
== ECRE_CLASS_REGISTERED
)
1269 m_scriptAdded(pEntityScript
.get());
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;
1284 case ECRE_CLASS_UNREGISTERED
:
1286 auto pEntityScript
= Find(pEntityClass
->GetName());
1288 m_scriptRemoved(pEntityScript
.get());
1289 m_scripts
.erase(pEntityClass
->GetName());
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())
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
))
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);
1374 //////////////////////////////////////////////////////////////////////////
1375 void CEntityScriptRegistry::LoadScripts()
1379 IEntityClassRegistry
* pClassRegistry
= gEnv
->pEntitySystem
->GetClassRegistry();
1380 IEntityClass
* pClass
= NULL
;
1381 pClassRegistry
->IteratorMoveFirst();
1382 while (pClass
= pClassRegistry
->IteratorNext())
1388 //////////////////////////////////////////////////////////////////////////
1389 CEntityScriptRegistry
* CEntityScriptRegistry::Instance()
1393 m_instance
= new CEntityScriptRegistry
;
1398 //////////////////////////////////////////////////////////////////////////
1399 void CEntityScriptRegistry::Release()