1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
4 #include "Deprecated/DocGraphNodes/DocGraphSwitchNode.h"
6 #include <CryString/CryStringUtils.h>
7 #include <CrySchematyc2/ICompiler.h>
8 #include <CrySchematyc2/LibUtils.h>
9 #include <CrySchematyc2/Deprecated/DocUtils.h>
10 #include <CrySchematyc2/Deprecated/IGlobalFunction.h>
11 #include <CrySchematyc2/Utils/ToString.h>
13 #include "AggregateTypeIdSerialize.h"
14 #include "Deprecated/DocGraphNodes/DocGraphNodeBase.h"
15 #include "Script/ScriptVariableDeclaration.h"
19 //////////////////////////////////////////////////////////////////////////
20 CDocGraphSwitchNode::CDocGraphSwitchNode(IScriptFile
& file
, IDocGraph
& graph
, const SGUID
& guid
, const SGUID
& contextGUID
, const SGUID
& refGUID
, Vec2 pos
)
21 : CDocGraphNodeBase(file
, graph
, guid
, "Switch", EScriptGraphNodeType::Switch
, contextGUID
, refGUID
, pos
)
23 if(const IEnvTypeDesc
* pTypeDesc
= gEnv
->pSchematyc2
->GetEnvRegistry().GetTypeDesc(GetEnvTypeId
<int32
>()))
25 m_typeId
= pTypeDesc
->GetTypeInfo().GetTypeId();
26 m_pValue
= pTypeDesc
->Create();
30 //////////////////////////////////////////////////////////////////////////
31 IAnyConstPtr
CDocGraphSwitchNode::GetCustomOutputDefault() const
33 return MakeScriptVariableValueShared(CDocGraphNodeBase::GetFile(), m_typeId
);
36 //////////////////////////////////////////////////////////////////////////
37 void CDocGraphSwitchNode::EnumerateOptionalOutputs(const ScriptGraphNodeOptionalOutputEnumerator
& enumerator
) {}
39 //////////////////////////////////////////////////////////////////////////
40 size_t CDocGraphSwitchNode::AddCustomOutput(const IAny
& value
)
42 char stringBuffer
[512] = "";
43 ToString(value
, stringBuffer
);
46 m_cases
.push_back(SCase(value
.Clone()));
47 return CDocGraphNodeBase::AddOutput(stringBuffer
, EScriptGraphPortFlags::Removable
| EScriptGraphPortFlags::Execute
);
52 //////////////////////////////////////////////////////////////////////////
53 size_t CDocGraphSwitchNode::AddOptionalOutput(const char* szName
, EScriptGraphPortFlags flags
, const CAggregateTypeId
& typeId
)
58 //////////////////////////////////////////////////////////////////////////
59 void CDocGraphSwitchNode::RemoveOutput(size_t outputIdx
)
61 CDocGraphNodeBase::RemoveOutput(outputIdx
);
62 m_cases
.erase(m_cases
.begin() + (outputIdx
- EOutputIdx::FirstCase
));
65 //////////////////////////////////////////////////////////////////////////
66 void CDocGraphSwitchNode::Refresh(const SScriptRefreshParams
& params
)
68 CRY_PROFILE_FUNCTION(PROFILE_LOADING_ONLY
);
70 CDocGraphNodeBase::Refresh(params
);
72 if(!ValidateScriptVariableTypeInfo(CDocGraphNodeBase::GetFile(), m_typeId
))
74 SetType(CAggregateTypeId());
77 CDocGraphNodeBase::AddInput("In", EScriptGraphPortFlags::MultiLink
| EScriptGraphPortFlags::Execute
);
78 CDocGraphNodeBase::AddInput("Value", EScriptGraphPortFlags::None
, m_pValue
? m_pValue
->GetTypeInfo().GetTypeId() : CAggregateTypeId());
79 CDocGraphNodeBase::AddOutput("Default", EScriptGraphPortFlags::Execute
| EScriptGraphPortFlags::SpacerBelow
);
81 uint32 invalidCaseCount
= 0;
82 for(SCase
& _case
: m_cases
)
84 char outputName
[512] = "";
87 ToString(*_case
.pValue
, outputName
);
91 cry_sprintf(outputName
, "INVALID_CASE[%d]", ++ invalidCaseCount
);
93 CDocGraphNodeBase::AddOutput(outputName
, EScriptGraphPortFlags::Removable
| EScriptGraphPortFlags::Execute
);
97 //////////////////////////////////////////////////////////////////////////
98 void CDocGraphSwitchNode::Serialize(Serialization::IArchive
& archive
)
100 CRY_PROFILE_FUNCTION(PROFILE_LOADING_ONLY
);
102 CDocGraphNodeBase::Serialize(archive
);
107 Serialization::StringList typeNames
;
108 if(const IEnvTypeDesc
* pTypeDesc
= gEnv
->pSchematyc2
->GetEnvRegistry().GetTypeDesc(GetEnvTypeId
<int32
>()))
110 typeIds
.push_back(pTypeDesc
->GetTypeInfo().GetTypeId());
111 typeNames
.push_back(pTypeDesc
->GetName());
113 if(const IEnvTypeDesc
* pTypeDesc
= gEnv
->pSchematyc2
->GetEnvRegistry().GetTypeDesc(GetEnvTypeId
<uint32
>()))
115 typeIds
.push_back(pTypeDesc
->GetTypeInfo().GetTypeId());
116 typeNames
.push_back(pTypeDesc
->GetName());
118 if(const IEnvTypeDesc
* pTypeDesc
= gEnv
->pSchematyc2
->GetEnvRegistry().GetTypeDesc(GetEnvTypeId
<CPoolString
>()))
120 typeIds
.push_back(pTypeDesc
->GetTypeInfo().GetTypeId());
121 typeNames
.push_back(pTypeDesc
->GetName());
124 STypeVisitor
typeVisitor(typeIds
, typeNames
);
125 gEnv
->pSchematyc2
->GetEnvRegistry().VisitTypeDescs(EnvTypeDescVisitor::FromMemberFunction
<STypeVisitor
, &STypeVisitor::VisitEnvTypeDesc
>(typeVisitor
));
126 ScriptIncludeRecursionUtils::VisitEnumerations(CDocGraphNodeBase::GetFile(), ScriptIncludeRecursionUtils::EnumerationVisitor::FromMemberFunction
<STypeVisitor
, &STypeVisitor::VisitScriptEnumeration
>(typeVisitor
), SGUID(), true);
128 if(archive
.isInput())
130 Serialization::StringListValue
typeName(typeNames
, 0);
131 archive(typeName
, "typeName", "Type");
132 SetType(typeIds
[typeName
.index()]);
134 else if(archive
.isOutput())
137 TypeIds::iterator itTypeId
= std::find(typeIds
.begin(), typeIds
.end(), m_typeId
);
138 if(itTypeId
!= typeIds
.end())
140 typeIdx
= static_cast<int>(itTypeId
- typeIds
.begin());
144 typeIds
.push_back(m_typeId
);
145 typeNames
.push_back("");
146 typeIdx
= static_cast<int>(typeIds
.size() - 1);
149 Serialization::StringListValue
typeName(typeNames
, typeIdx
);
150 archive(typeName
, "typeName", "Type");
155 archive(*m_pValue
, "value", "Value");
160 if(archive
.isInput())
162 CAggregateTypeId typeId
;
163 if(!archive(typeId
, "typeId"))
165 PatchAggregateTypeIdFromDocVariableTypeInfo(archive
, typeId
, "typeInfo");
169 else if(archive
.isOutput())
171 archive(m_typeId
, "typeId");
176 archive(*m_pValue
, "value");
180 Serialization::SContext
context(archive
, static_cast<CDocGraphSwitchNode
*>(this));
181 archive(m_cases
, "cases", "Cases");
183 if(archive
.isInput())
185 Refresh(SScriptRefreshParams(EScriptRefreshReason::Other
)); // #SchematycTODO : Should we really need to refresh manually or should the system take care of that?
188 if(archive
.isValidation())
194 //////////////////////////////////////////////////////////////////////////
195 void CDocGraphSwitchNode::PreCompileSequence(IDocGraphSequencePreCompiler
& preCompiler
, size_t outputIdx
) const {}
197 //////////////////////////////////////////////////////////////////////////
198 void CDocGraphSwitchNode::LinkSequence(IDocGraphSequenceLinker
& linker
, size_t outputIdx
, const LibFunctionId
& functionId
) const {}
200 //////////////////////////////////////////////////////////////////////////
201 void CDocGraphSwitchNode::Compile(IDocGraphNodeCompiler
& compiler
, EDocGraphSequenceStep sequenceStep
, size_t portIdx
) const
205 case EDocGraphSequenceStep::BeginInput
:
207 CompileInputs(compiler
);
210 case EDocGraphSequenceStep::EndInput
:
212 CompileEnd(compiler
);
215 case EDocGraphSequenceStep::BeginOutput
:
217 CompileCaseBegin(compiler
, portIdx
);
220 case EDocGraphSequenceStep::EndOutput
:
222 CompileCaseEnd(compiler
);
228 //////////////////////////////////////////////////////////////////////////
229 CDocGraphSwitchNode::SCase::SCase() {}
231 //////////////////////////////////////////////////////////////////////////
232 CDocGraphSwitchNode::SCase::SCase(const IAnyPtr
& _pValue
)
236 //////////////////////////////////////////////////////////////////////////
237 void CDocGraphSwitchNode::SCase::Serialize(Serialization::IArchive
& archive
)
239 CRY_PROFILE_FUNCTION(PROFILE_LOADING_ONLY
)
241 CDocGraphSwitchNode
* pSwitchNode
= archive
.context
<CDocGraphSwitchNode
>();
242 SCHEMATYC2_SYSTEM_ASSERT(pSwitchNode
);
247 pValue
= MakeScriptVariableValueShared(pSwitchNode
->GetFile(), pSwitchNode
->m_typeId
);
251 archive(*pValue
, "value", "^Value");
252 if(archive
.isValidation())
254 char stringBuffer
[512] = "";
255 ToString(*pValue
, stringBuffer
);
258 archive
.error(*this, "Empty case value!");
262 else if(archive
.isValidation())
264 archive
.error(*this, "Unable to instantiate value!");
269 //////////////////////////////////////////////////////////////////////////
270 CDocGraphSwitchNode::STypeVisitor::STypeVisitor(TypeIds
& _typeIds
, Serialization::StringList
& _typeNames
)
272 , typeNames(_typeNames
)
275 //////////////////////////////////////////////////////////////////////////
276 EVisitStatus
CDocGraphSwitchNode::STypeVisitor::VisitEnvTypeDesc(const IEnvTypeDesc
& typeDesc
)
278 if((typeDesc
.GetCategory() == EEnvTypeCategory::Enumeration
) || ((typeDesc
.GetFlags() & EEnvTypeFlags::Switchable
) != 0))
280 typeIds
.push_back(typeDesc
.GetTypeInfo().GetTypeId());
281 typeNames
.push_back(typeDesc
.GetName());
283 return EVisitStatus::Continue
;
286 //////////////////////////////////////////////////////////////////////////
287 void CDocGraphSwitchNode::STypeVisitor::VisitScriptEnumeration(const IScriptFile
& enumerationFile
, const IScriptEnumeration
& enumeration
)
289 typeIds
.push_back(enumeration
.GetTypeId());
290 typeNames
.push_back(enumeration
.GetName());
293 //////////////////////////////////////////////////////////////////////////
294 void CDocGraphSwitchNode::Validate(Serialization::IArchive
& archive
)
298 archive
.error(*this, "Unable to instantiate value!");
301 std::vector
<stack_string
> caseStrings
;
302 uint32 duplicateCaseValueCount
= 0;
303 for(const SCase
& _case
: m_cases
)
307 char stringBuffer
[512] = "";
308 ToString(*_case
.pValue
, stringBuffer
);
311 stack_string caseString
= stringBuffer
;
312 if(std::find(caseStrings
.begin(), caseStrings
.end(), caseString
) != caseStrings
.end())
314 ++ duplicateCaseValueCount
;
318 caseStrings
.push_back(caseString
);
323 if(duplicateCaseValueCount
)
325 archive
.error(*this, "Duplicate case values detected!");
329 //////////////////////////////////////////////////////////////////////////
330 void CDocGraphSwitchNode::SetType(const CAggregateTypeId
& typeId
)
332 if(typeId
!= m_typeId
)
337 m_pValue
= MakeScriptVariableValueShared(CDocGraphNodeBase::GetFile(), typeId
);
339 CDocGraphNodeBase::GetGraph().RemoveLinks(CDocGraphNodeBase::GetGUID());
343 //////////////////////////////////////////////////////////////////////////
344 void CDocGraphSwitchNode::CompileInputs(IDocGraphNodeCompiler
& compiler
) const
346 SCHEMATYC2_SYSTEM_ASSERT(m_pValue
);
349 compiler
.CreateStackFrame(*this, EStackFrame::Value
);
351 TVariantVector variants
;
352 CVariantVectorOutputArchive
archive(variants
);
354 const size_t typeSize
= variants
.size();
356 const size_t stackPos
= compiler
.FindInputOnStack(*this, EInputIdx::Value
);
357 if(stackPos
!= INVALID_INDEX
)
359 if(stackPos
!= (compiler
.GetStackSize() - typeSize
))
361 compiler
.Copy(stackPos
, INVALID_INDEX
, *m_pValue
, CDocGraphNodeBase::GetGUID(), GetInputName(EInputIdx::Value
));
365 compiler
.SetDebugInput(CDocGraphNodeBase::GetGUID(), GetInputName(EInputIdx::Value
));
370 compiler
.Push(*m_pValue
, CDocGraphNodeBase::GetGUID(), GetInputName(EInputIdx::Value
));
373 const size_t rhsPos
= compiler
.GetStackSize();
374 const size_t lhsPos
= rhsPos
- typeSize
;
375 for(size_t caseIdx
= 0, caseCount
= m_cases
.size(); caseIdx
< caseCount
; ++ caseIdx
)
377 compiler
.CreateStackFrame(*this, EStackFrame::Case
);
379 IAnyConstPtr pCaseValue
= m_cases
[caseIdx
].pValue
;
382 compiler
.Push(*pCaseValue
, SGUID(), "");
386 SCHEMATYC2_COMPILER_ERROR("Missing case value!");
387 compiler
.Push(*m_pValue
, SGUID(), "");
390 compiler
.Compare(lhsPos
, rhsPos
, typeSize
);
391 compiler
.BranchIfNotZero(*this, EBranchMarker::FirstCase
+ caseIdx
);
392 compiler
.CollapseStackFrame(*this, EStackFrame::Case
);
397 //////////////////////////////////////////////////////////////////////////
398 void CDocGraphSwitchNode::CompileCaseBegin(IDocGraphNodeCompiler
& compiler
, size_t portIdx
) const
400 if(portIdx
> EOutputIdx::Default
)
402 compiler
.CreateMarker(*this, EBranchMarker::FirstCase
+ (portIdx
- EOutputIdx::FirstCase
));
404 compiler
.CollapseStackFrame(*this, EStackFrame::Value
);
405 compiler
.CreateStackFrame(*this, EStackFrame::Value
);
408 //////////////////////////////////////////////////////////////////////////
409 void CDocGraphSwitchNode::CompileCaseEnd(IDocGraphNodeCompiler
& compiler
) const
411 compiler
.Branch(*this, EBranchMarker::End
);
414 //////////////////////////////////////////////////////////////////////////
415 void CDocGraphSwitchNode::CompileEnd(IDocGraphNodeCompiler
& compiler
) const
417 compiler
.CreateMarker(*this, EBranchMarker::End
);
418 compiler
.CollapseStackFrame(*this, EStackFrame::Value
);