Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_AiScriptGeneratorPlugin.c
Go to the documentation of this file.
1#ifdef WORKBENCH
2/*
3This plugin generates scripted behavior tree node classes.
4It parses files, searches for macros in comments and generates the code based on that.
5You can adjust parameters in a config file.
6If you have more files to generate code from, make sure you add them to the config file.
7*/
8[WorkbenchPluginAttribute(name: "AI Script Generator", description: "Generates scripted Behavior Tree node classes", wbModules: { "ScriptEditor" })]
9class SCR_AiScriptGeneratorPlugin : WorkbenchPlugin
10{
11 [Attribute(defvalue: "{6741D2D6C8EFBFF9}Configs/AI/AIScriptGeneratorConfig.conf", params: "conf class=SCR_AIScriptGeneratorConfig")]
12 ResourceName m_sConfig;
13
14 //------------------------------------------------------------------------------------------------
15 protected override void Run()
16 {
17 Workbench.ScriptDialog("AI Script Generator Plugin", "", this);
18 }
19
20 //------------------------------------------------------------------------------------------------
21 [ButtonAttribute("Run")]
22 protected void RunButton()
23 {
24 _print("Plugin started");
25
26 // Open config file
27 SCR_AIScriptGeneratorConfig config = SCR_ConfigHelperT<SCR_AIScriptGeneratorConfig>.GetConfigObject(m_sConfig);
28 if (!config)
29 {
30 _print(string.Format("Failed to open config file: %1", m_sConfig), LogLevel.ERROR);
31 return;
32 }
33
34 int nGeneratedClasses = 0;
35 int nGeneratedLines = 0;
36 SCR_AiScriptGenerator_Parser parser = new SCR_AiScriptGenerator_Parser();
37 SCR_AiScriptGenerator_OutputFormatBuffer bufferSendGoalMessage = new SCR_AiScriptGenerator_OutputFormatBuffer();
38 SCR_AiScriptGenerator_OutputFormatBuffer bufferSendInfoMessage = new SCR_AiScriptGenerator_OutputFormatBuffer();
39 SCR_AiScriptGenerator_OutputFormatBuffer bufferSendOrder = new SCR_AiScriptGenerator_OutputFormatBuffer();
40
41 // Read and parse all input files
42 array<string> fileLines;
43 foreach (string inputFilePath : config.m_aInputFiles)
44 {
45 FileHandle fHandle = FileIO.OpenFile(inputFilePath, FileMode.READ);
46 if (!fHandle)
47 {
48 _print(string.Format("Failed to open input file: %1", inputFilePath), LogLevel.ERROR);
49 continue;
50 }
51
52 // Read whole file by lines
53 fileLines = {};
54 string fLine;
55 while (fHandle.ReadLine(fLine) != -1)
56 {
57 fileLines.Insert(fLine);
58 }
59 fHandle.Close();
60
61 // Parse lines
62 parser.ParseLines(fileLines, inputFilePath);
63 }
64
65 // Finish parsing
66 parser.FindRelatedClasses();
67 parser.PrintListing();
68
69 // Run generators for parsed classes
70 foreach (SCR_AiScriptGenerator_Class parsedClass : parser.GetParsedClasses())
71 {
72 foreach (SCR_AiScriptGenerator_ClassGeneratorBase generator : parsedClass.m_aGenerators)
73 {
74 if (SCR_AiScriptGenerator_SendGoalMessageGenerator.Cast(generator))
75 generator.Generate(bufferSendGoalMessage);
76 else if (SCR_AiScriptGenerator_SendInfoMessageGenerator.Cast(generator))
77 generator.Generate(bufferSendInfoMessage);
78 else if (SCR_AiScriptGenerator_SendOrderGenerator.Cast(generator))
79 generator.Generate(bufferSendOrder);
80
81 nGeneratedClasses++;
82 }
83 }
84
85 // Write generated data to files
86 WriteLinesToFile(config.m_sSendGoalMessageOutputFile, bufferSendGoalMessage.GetLines());
87 WriteLinesToFile(config.m_sSendInfoMessageOutputFile, bufferSendInfoMessage.GetLines());
88 WriteLinesToFile(config.m_sSendOrderOutputFile, bufferSendOrder.GetLines());
89
90 // Write some statistics
91 nGeneratedLines += bufferSendGoalMessage.GetLines().Count();
92 nGeneratedLines += bufferSendInfoMessage.GetLines().Count();
93 nGeneratedLines += bufferSendOrder.GetLines().Count();
94 _print(string.Format("Generated %1 classes, %2 lines", nGeneratedClasses, nGeneratedLines));
95 }
96
97 //------------------------------------------------------------------------------------------------
98 protected void WriteLinesToFile(string fileName, array<string> lines)
99 {
100 FileHandle fHandleOut = FileIO.OpenFile(fileName, FileMode.WRITE);
101 if (!fHandleOut)
102 {
103 _print(string.Format("Error opening output file: %1", fileName));
104 }
105 else
106 {
107 foreach (string line : lines)
108 {
109 fHandleOut.WriteLine(line);
110 }
111 fHandleOut.Close();
112 _print(string.Format("Saved generated scripts to file: %1 (%2 lines)", fileName, lines.Count()));
113 }
114 }
115
116 //------------------------------------------------------------------------------------------------
120 static void _print(string str, LogLevel logLevel = LogLevel.NORMAL)
121 {
122 Print(string.Format("[AI Script Generator]: %1", str), logLevel);
123 }
124}
125
126class SCR_AiScriptGenerator_Parser
127{
128 const string COMMENT = "//";
129 const string CLASS = "class";
130
131 const string MACRO_VARIABLE = "VARIABLE";
132 const string NODE_PORT = "NodePort";
133 const string NODE_PROPERTY = "NodeProperty";
134 const string NODE_PROPERTY_ENUM = "NodePropertyEnum";
135
136 const string MACRO_MESSAGE_CLASS = "MESSAGE_CLASS";
137 const string GENERATE_SEND_GOAL_MESSAGE = "GenerateSendGoalMessage";
138 const string GENERATE_SEND_INFO_MESSAGE = "GenerateSendInfoMessage";
139 const string GENERATE_SEND_ORDER = "GenerateSendOrder";
140
141 // Current state
142 protected int m_iCurrentLineId;
143 protected string m_sCurrentLine;
144 protected string m_sCurrentFile;
145
146 // Current class while parsing
147 protected ref SCR_AiScriptGenerator_Class m_CurrentClass;
148
149 protected ref array<ref SCR_AiScriptGenerator_Class> m_aParsedClasses = {};
150
151 //------------------------------------------------------------------------------------------------
152 protected void ResetContext(string currentFile)
153 {
154 m_iCurrentLineId = 0;
155 m_sCurrentLine = string.Empty;
156 m_sCurrentFile = currentFile;
157 }
158
159 //------------------------------------------------------------------------------------------------
161 array<ref SCR_AiScriptGenerator_Class> GetParsedClasses()
162 {
163 return m_aParsedClasses;
164 }
165
166 //------------------------------------------------------------------------------------------------
170 void ParseLines(array<string> lines, string fileName)
171 {
172 ResetContext(fileName);
173 m_CurrentClass = null;
174
175 foreach (int lineId, string line : lines)
176 {
177 ParseLine(line, lineId);
178 }
179
180 // Finish current class, if we are in a class
181 if (m_CurrentClass)
182 m_aParsedClasses.Insert(m_CurrentClass);
183 }
184
185 //------------------------------------------------------------------------------------------------
188 void FindRelatedClasses()
189 {
190 // Iterate all parsed classes and link them to their parents
191 foreach (SCR_AiScriptGenerator_Class _class : m_aParsedClasses)
192 {
193 string parentClassName = _class.m_sParentClassName;
194 if (parentClassName.IsEmpty())
195 continue;
196
197 // Find a class with this name among classes we've parsed
198 foreach (SCR_AiScriptGenerator_Class c : m_aParsedClasses)
199 {
200 if (c.m_sName == parentClassName)
201 {
202 _class.m_ParentClass = c;
203 break;
204 }
205 }
206 }
207 }
208
209 //------------------------------------------------------------------------------------------------
211 void PrintListing()
212 {
213 _print("-----------------------------------------------------------------------------", printContext : false);
214 _print("Listing of parsed classes:", printContext : false);
215 foreach (SCR_AiScriptGenerator_Class _class : m_aParsedClasses)
216 {
217 _print(_class.GetListing(), printContext: false);
218 foreach (SCR_AiScriptGenerator_Variable _variable : _class.m_aVariables)
219 {
220 _print(" " + _variable.GetListing(), printContext: false);
221 }
222 _print("", printContext: false);
223 }
224 _print("-----------------------------------------------------------------------------", printContext : false);
225 _print("", printContext : false);
226 }
227
228 //------------------------------------------------------------------------------------------------
229 protected void ParseLine(inout string line, int lineId)
230 {
231 if (!line.Contains(COMMENT))
232 return;
233
234 m_iCurrentLineId = lineId;
235 m_sCurrentLine = line;
236
237 string comment = ExtractComment(line);
238 array<string> macroArgs = {};
239 if (ExtractMacro(comment, MACRO_MESSAGE_CLASS, macroArgs))
240 {
241 // Detected new class
242
243 // If we were already parsing a class, push it to array
244 if (m_CurrentClass)
245 m_aParsedClasses.Insert(m_CurrentClass);
246 m_CurrentClass = null;
247
248 if (!VerifyMacro_MessageClass(macroArgs))
249 return;
250
251 string className, parentClassName;
252 if (!ExtractClass(line, className, parentClassName))
253 return;
254
255 // Create entry for this class
256 m_CurrentClass = new SCR_AiScriptGenerator_Class();
257 m_CurrentClass.m_sLine = m_sCurrentLine;
258 m_CurrentClass.m_sName = className;
259 m_CurrentClass.m_sParentClassName = parentClassName;
260
261 if (!macroArgs.IsEmpty())
262 {
263 switch (macroArgs[0])
264 {
265 case GENERATE_SEND_GOAL_MESSAGE:
266 {
267 SCR_AiScriptGenerator_SendGoalMessageGenerator generator = new SCR_AiScriptGenerator_SendGoalMessageGenerator(m_CurrentClass);
268 generator.m_sGeneratedClassName = macroArgs[1];
269 m_CurrentClass.m_aGenerators.Insert(generator);
270 break;
271 }
272 case GENERATE_SEND_INFO_MESSAGE:
273 {
274 SCR_AiScriptGenerator_SendInfoMessageGenerator generator = new SCR_AiScriptGenerator_SendInfoMessageGenerator(m_CurrentClass);
275 generator.m_sGeneratedClassName = macroArgs[1];
276 m_CurrentClass.m_aGenerators.Insert(generator);
277 break;
278 }
279 case GENERATE_SEND_ORDER:
280 {
281 SCR_AiScriptGenerator_SendOrderGenerator generator = new SCR_AiScriptGenerator_SendOrderGenerator(m_CurrentClass);
282 generator.m_sGeneratedClassName = macroArgs[1];
283 m_CurrentClass.m_aGenerators.Insert(generator);
284 break;
285 }
286 }
287 }
288 }
289 else if (ExtractMacro(comment, MACRO_VARIABLE, macroArgs))
290 {
291 // Only makes sense within a class
292 if (!m_CurrentClass)
293 return;
294
295 if (!VerifyMacro_Variable(macroArgs))
296 return;
297
298 string varType, varName;
299 if (!ExtractVariable(line, varType, varName))
300 return;
301
302 SCR_AiScriptGenerator_Variable v = new SCR_AiScriptGenerator_Variable();
303 v.m_sLine = m_sCurrentLine;
304 v.m_sName = varName;
305 v.m_sType = varType;
306 array<int> _a = { 0, 2 };
307 foreach (int i : _a)
308 {
309 if (!macroArgs.IsIndexValid(i+ 1))
310 continue;
311
312 string arg = macroArgs[i];
313
314 if (arg == NODE_PORT)
315 v.m_sBindPortName = macroArgs[i+ 1];
316 else if (arg == NODE_PROPERTY)
317 v.m_sBindPropertyName = macroArgs[i+ 1];
318 else if (arg == NODE_PROPERTY_ENUM)
319 {
320 v.m_sBindPropertyName = macroArgs[i+ 1];
321 v.m_bBindPropertyIsEnum = true;
322 }
323 }
324 m_CurrentClass.m_aVariables.Insert(v);
325 }
326
327 }
328
329 //------------------------------------------------------------------------------------------------
330 // Parsing text
331
332 //------------------------------------------------------------------------------------------------
333 // Returns content of a comment. Example:
334 // "1234; //Something" -> "Something"
335 protected string ExtractComment(string str)
336 {
337 int commentId = str.IndexOf(COMMENT);
338 if (commentId == -1)
339 return string.Empty;
340 int strlen = str.Length();
341 int substrStart = commentId + COMMENT.Length();
342 int substrLen = strlen - substrStart;
343 string commentContent = str.Substring(substrStart, substrLen);
344 return commentContent;
345 }
346
347 //------------------------------------------------------------------------------------------------
348 // Extracts arguments from a macro. Example:
349 // "MACRO(1, 2, 3)" -> {"1", "2", "3"}
350 protected bool ExtractMacro(string str, string macroName, array<string> outMacroArguments)
351 {
352 int macroStartId = str.IndexOf(macroName);
353 if (macroStartId == -1)
354 return false;
355
356 int startBracketSearchId = macroStartId + macroName.Length();
357 int openBracketId = str.IndexOfFrom(startBracketSearchId, "(");
358 int closeBracketId = str.IndexOfFrom(startBracketSearchId, ")");
359
360 if (openBracketId == -1 || closeBracketId == -1 || openBracketId > closeBracketId)
361 {
362 _print(string.Format("ExtractMacro: failed to parse macro %1", macroName));
363 return false;
364 }
365
366 string strMacroArgs = str.Substring(openBracketId + 1, closeBracketId - openBracketId - 1);
367 if (strMacroArgs.IsEmpty())
368 {
369 // No macro arguments
370 outMacroArguments.Clear();
371 return true;
372 }
373 if (!strMacroArgs.Contains(","))
374 {
375 // One macro argument
376 strMacroArgs.TrimInPlace();
377 outMacroArguments.Clear();
378 outMacroArguments.Insert(strMacroArgs);
379 return true;
380 }
381 else
382 {
383 outMacroArguments.Clear();
384 strMacroArgs.Split(",", outMacroArguments, true);
385 int nMacroArgs = outMacroArguments.Count();
386 for (int i = 0; i < nMacroArgs; i++)
387 {
388 outMacroArguments[i] = outMacroArguments[i].Trim();
389 }
390 return true;
391 }
392 }
393
394 //------------------------------------------------------------------------------------------------
395 // Extracts variable type and name. Example:
396 // "protected const int m_iSize = 3;" -> "int", "m_iSize"
397 protected bool ExtractVariable(string str, out string varType, out string varName)
398 {
399 /*
400 smth smth type VarName;
401 smth smth type VarName = whatever();
402 smth smth type VarName=whatever();
403 */
404
405 // Remove ; and averything after it
406 int idDotComma = str.IndexOf(";");
407 if (idDotComma != -1)
408 str = str.Substring(0, idDotComma);
409
410 // Remove right side (after '=')
411 int idEquals = str.IndexOf("=");
412 if (idEquals != -1)
413 str = str.Substring(0, idEquals);
414
415 // Split by spaces
416 array<string> tokens = {};
417 str.Split(" ", tokens, true);
418
419 int nTokens = tokens.Count();
420 if (nTokens < 2)
421 {
422 _print("Failed to parse variable", LogLevel.ERROR);
423 return false;
424 }
425
426 varType = tokens[nTokens - 2].Trim();
427 varName = tokens[nTokens - 1].Trim();
428 return true;
429 }
430
431 //------------------------------------------------------------------------------------------------
432 // Extracts class name and parent class name. Example:
433 // class MyClass : MyParentClass -> "MyClass", "MyParentClass"
434 protected bool ExtractClass(string str, out string className, out string parentClassName)
435 {
436 className = string.Empty;
437 parentClassName = string.Empty;
438
439 // Split string by ' '
440 array<string> tokens = {};
441 str.Split(" ", tokens, true);
442
443 // Find where "class" is
444 int idClassToken = tokens.Find(CLASS);
445 if (idClassToken == -1)
446 return false;
447
448 // Extract class name and parent class name
449 for (int i = idClassToken + 1; i < tokens.Count(); i++)
450 {
451 string s = tokens[i];
452 if (s == ":" || s == "extends") // Ignore ":" or "extends"
453 continue;
454
455 if (s.StartsWith("/")) // Stop if it's start of comment
456 break;
457 else if (className.IsEmpty()) // Class name
458 className = s;
459 else if (parentClassName.IsEmpty())
460 {
461 parentClassName = s;
462 break;
463 }
464 }
465
466 // Success if we at least found class name
467 bool success = !className.IsEmpty();
468
469 if (!success)
470 _print("Failed to parse class", LogLevel.ERROR);
471
472 return success;
473 }
474
475 //------------------------------------------------------------------------------------------------
476 // Removes quotes from string. Example:
477 // ""123"" -> "123"
478 protected string Unquote(string str)
479 {
480 return str.Substring(1, str.Length() - 2);
481 }
482
483 //------------------------------------------------------------------------------------------------
484 // Prints message with current parsing context
485 protected void _print(string str, LogLevel logLevel = LogLevel.NORMAL, bool printContext = true)
486 {
487 // Print message
488 SCR_AiScriptGeneratorPlugin._print(str, logLevel);
489
490 // Print context
491 if (printContext)
492 {
493 SCR_AiScriptGeneratorPlugin._print(string.Format(" File: %1", m_sCurrentFile), logLevel);
494 SCR_AiScriptGeneratorPlugin._print(string.Format(" Line %1: %2", m_iCurrentLineId + 1, m_sCurrentLine), logLevel);
495 }
496 }
497
498 //------------------------------------------------------------------------------------------------
499 // Verification of macros
500
501 //------------------------------------------------------------------------------------------------
502 protected bool VerifyMacro_MessageClass(array<string> args)
503 {
504 if (args.IsEmpty())
505 return true;
506
507 if (args.Count() != 2)
508 {
509 _print(string.Format("Wrong argument count for macro %1", MACRO_MESSAGE_CLASS), logLevel: LogLevel.ERROR);
510 return false;
511 }
512
513 switch (args[0])
514 {
515 case GENERATE_SEND_GOAL_MESSAGE:
516 case GENERATE_SEND_INFO_MESSAGE:
517 case GENERATE_SEND_ORDER:
518 return true;
519 break;
520
521 default:
522 _print(string.Format("Unknown macro argument \"%1\"", args[0]), logLevel: LogLevel.ERROR);
523 return false;
524 }
525
526 return VerifyMacroArgumentCount(MACRO_MESSAGE_CLASS, args, 1);
527 }
528
529 //------------------------------------------------------------------------------------------------
530 protected bool VerifyMacro_Variable(array<string> args)
531 {
532 int nArgs = args.Count();
533 if (nArgs != 0 && nArgs != 2 && nArgs != 4)
534 {
535 _print(string.Format("Wrong argument count for macro: %1", MACRO_VARIABLE), logLevel: LogLevel.ERROR);
536 return false;
537 }
538
539 if (args.IsIndexValid(0) && args[0] != NODE_PORT && args[0] != NODE_PROPERTY && args[0] != NODE_PROPERTY_ENUM)
540 {
541 _print(string.Format("Unknown macro argument \"%1\"", args[0]), logLevel: LogLevel.ERROR);
542 return false;
543 }
544
545 if (args.IsIndexValid(2) && args[2] != NODE_PORT && args[2] != NODE_PROPERTY && args[2] != NODE_PROPERTY_ENUM)
546 {
547 _print(string.Format("Unknown macro argument \"%1\"", args[0]), logLevel: LogLevel.ERROR);
548 return false;
549 }
550
551 return VerifyMacroArgumentCount(MACRO_VARIABLE, args, 1);
552 }
553
554 //------------------------------------------------------------------------------------------------
555 protected bool VerifyMacroArgumentCount(string macroName, array<string> args, int n)
556 {
557 if (args.Count() < n)
558 {
559 _print(string.Format("Expected at least %1 arguments for macro: %2", n, macroName), logLevel: LogLevel.ERROR);
560 return false;
561 }
562
563 return true;
564 }
565}
566
567//------------------------------------------------------------------------------------------------
568// Buffer which handles tabs in generated text
569class SCR_AiScriptGenerator_OutputFormatBuffer
570{
571 protected int m_iIndentCount = 0;
572 protected ref array<string> m_aGeneratedLines = {};
573
574 //------------------------------------------------------------------------------------------------
576 array<string> GetLines() { return m_aGeneratedLines; }
577
578 //------------------------------------------------------------------------------------------------
581 void AddLine(string line)
582 {
583 if (line.StartsWith("}"))
584 m_iIndentCount--;
585
586 string strIndent;
587 for (int i = 0; i < m_iIndentCount; i++)
588 {
589 strIndent = strIndent + "\t";
590 }
591 m_aGeneratedLines.Insert(strIndent + line);
592
593 // Auto increase/decrease indent count
594 if (line.StartsWith("{"))
595 m_iIndentCount++;
596 }
597}
598
599// Base class which defines what to do with parsed data
600class SCR_AiScriptGenerator_ClassGeneratorBase
601{
602 SCR_AiScriptGenerator_Class m_Class; // Class this generator is attached to
603 string m_sGeneratedClassName;
604
605 //------------------------------------------------------------------------------------------------
608 void Generate(SCR_AiScriptGenerator_OutputFormatBuffer ctx);
609
610 //------------------------------------------------------------------------------------------------
615 void GenerateGetVariablesIn(SCR_AiScriptGenerator_OutputFormatBuffer ctx, array<string> extraPortNames, array<SCR_AiScriptGenerator_Variable> variables)
616 {
617 // Port names
618 array<string> aPortNames = {};
619 aPortNames.Copy(extraPortNames);
620 foreach (SCR_AiScriptGenerator_Variable v : variables)
621 {
622 if (!v.m_sBindPortName.IsEmpty())
623 aPortNames.Insert(string.Format("\"%1\"", v.m_sBindPortName));
624 }
625
626 ctx.AddLine("protected static ref TStringArray _s_aVarsIn =");
627 ctx.AddLine("{");
628 int nPorts = aPortNames.Count();
629 foreach (int varId, string portName : aPortNames)
630 {
631 string strPortName = portName;
632 if (varId != nPorts-1)
633 strPortName = strPortName + ",";
634 ctx.AddLine(strPortName);
635 }
636 ctx.AddLine("};");
637 ctx.AddLine("override TStringArray GetVariablesIn() { return _s_aVarsIn; }");
638 ctx.AddLine("");
639 }
640
641 //------------------------------------------------------------------------------------------------
645 void GenerateVariablesWithAttributes(SCR_AiScriptGenerator_OutputFormatBuffer ctx, array<SCR_AiScriptGenerator_Variable> variables)
646 {
647 foreach (SCR_AiScriptGenerator_Variable v : variables)
648 {
649 if (v.m_sBindPropertyName.IsEmpty())
650 continue;
651
652 if (!v.m_bBindPropertyIsEnum)
653 ctx.AddLine("[Attribute(\"" + "\")]");
654 else
655 ctx.AddLine(string.Format("[Attribute(\"" + "\", UIWidgets.ComboBox, enumType: %1)]", v.m_sType));
656
657 ctx.AddLine(string.Format("%1 %2;", v.m_sType, v.m_sBindPropertyName));
658 ctx.AddLine("");
659 }
660 }
661
662 //------------------------------------------------------------------------------------------------
666 void GenerateSetMessageVariables(SCR_AiScriptGenerator_OutputFormatBuffer ctx, array<SCR_AiScriptGenerator_Variable> variables)
667 {
668 ctx.AddLine(string.Format("msg.SetText(m_sText);"));
669 ctx.AddLine("");
670
671 foreach (SCR_AiScriptGenerator_Variable v : variables)
672 {
673 if (!v.m_sBindPortName.IsEmpty() && !v.m_sBindPropertyName.IsEmpty())
674 {
675 // Set from property or port
676 ctx.AddLine(string.Format("if(!GetVariableIn(\"%1\", msg.%2))", v.m_sBindPortName, v.m_sName));
677 ctx.AddLine(string.Format("\tmsg.%1 = %2;", v.m_sName, v.m_sBindPropertyName));
678 ctx.AddLine("");
679 }
680 else if (!v.m_sBindPortName.IsEmpty())
681 {
682 // Set from port
683 ctx.AddLine(string.Format("GetVariableIn(\"%1\", msg.%2);", v.m_sBindPortName, v.m_sName));
684 ctx.AddLine("");
685 }
686 else if (!v.m_sBindPropertyName.IsEmpty())
687 {
688 // Set from property
689 ctx.AddLine(string.Format("msg.%1 = %2;", v.m_sName, v.m_sBindPropertyName));
690 ctx.AddLine("");
691 }
692 }
693 }
694
695 //------------------------------------------------------------------------------------------------
699 void GenerateGetNodeMiddleText(SCR_AiScriptGenerator_OutputFormatBuffer ctx, array<SCR_AiScriptGenerator_Variable> variables)
700 {
701 array<SCR_AiScriptGenerator_Variable> properties = {};
702 foreach (SCR_AiScriptGenerator_Variable v : variables)
703 {
704 if (v.m_sBindPropertyName)
705 properties.Insert(v);
706 }
707
708 if (properties.IsEmpty())
709 return;
710
711 ctx.AddLine("override string GetNodeMiddleText()");
712 ctx.AddLine("{");
713 ctx.AddLine("string s;");
714 foreach (SCR_AiScriptGenerator_Variable v : properties)
715 {
716 if (v.m_bBindPropertyIsEnum)
717 ctx.AddLine(string.Format("s = s + string.Format(\"%1: %2\\n\", typename.EnumToString(%3, %4));", v.m_sBindPropertyName, "%1", v.m_sType, v.m_sBindPropertyName));
718 else
719 ctx.AddLine(string.Format("s = s + string.Format(\"%1: %2\\n\", %3);", v.m_sBindPropertyName, "%1", v.m_sBindPropertyName));
720 }
721 ctx.AddLine("return s;");
722 ctx.AddLine("}");
723 }
724
725 //------------------------------------------------------------------------------------------------
728 void GenerateCommentSeparator(SCR_AiScriptGenerator_OutputFormatBuffer ctx)
729 {
730 ctx.AddLine("//---------------------------------------------------------------------------------------");
731 }
732
733 //------------------------------------------------------------------------------------------------
736 // Returns all variables of a class, including variables of parent classes
737 array<SCR_AiScriptGenerator_Variable> GetClassVariables(SCR_AiScriptGenerator_Class _class)
738 {
739 // Find all parent classes
740 array<SCR_AiScriptGenerator_Class> parentClasses = {};
741 SCR_AiScriptGenerator_Class parentClass = _class;
742 while (parentClass)
743 {
744 parentClasses.Insert(parentClass);
745 parentClass = parentClass.m_ParentClass;
746 }
747
748 // Create array of variables, first declared variables first, parent classes first
749 array<SCR_AiScriptGenerator_Variable> variables = {};
750 for (int classId = parentClasses.Count() - 1; classId >= 0; classId--)
751 {
752 SCR_AiScriptGenerator_Class c = parentClasses[classId];
753 foreach (SCR_AiScriptGenerator_Variable v : c.m_aVariables)
754 {
755 variables.Insert(v);
756 }
757 }
758
759 return variables;
760 }
761
762 //------------------------------------------------------------------------------------------------
763 // constructor
764 void SCR_AiScriptGenerator_ClassGeneratorBase(SCR_AiScriptGenerator_Class attachedToClass)
765 {
766 m_Class = attachedToClass;
767 }
768}
769
770class SCR_AiScriptGenerator_SendInfoMessageGenerator : SCR_AiScriptGenerator_ClassGeneratorBase
771{
772 //------------------------------------------------------------------------------------------------
773 override void Generate(SCR_AiScriptGenerator_OutputFormatBuffer ctx)
774 {
775 // Create array of variables of this class and its parent classes
776 array<SCR_AiScriptGenerator_Variable> variables = GetClassVariables(m_Class);
777
778 GenerateCommentSeparator(ctx);
779 ctx.AddLine(string.Format("// Generated from class: %1", m_Class.m_sName));
780 ctx.AddLine(string.Format("class %1 : SCR_AISendMessageGenerated", m_sGeneratedClassName));
781 ctx.AddLine("{");
782
783 // Variables with attributes
784 GenerateVariablesWithAttributes(ctx, variables);
785
786 // GerVariablesIn
787 GenerateGetVariablesIn(ctx, { "SCR_AISendMessageGenerated.PORT_RECEIVER" }, variables);
788
789 // EOnTaskSimulate
790 ctx.AddLine("override ENodeResult EOnTaskSimulate(AIAgent owner, float dt)");
791 ctx.AddLine("{");
792 ctx.AddLine("AIAgent receiver = GetReceiverAgent(owner);");
793 ctx.AddLine(string.Format("%1 msg = new %1();", m_Class.m_sName));
794 ctx.AddLine("");
795
796 // Set message variables
797 GenerateSetMessageVariables(ctx, variables);
798
799 ctx.AddLine(string.Format("if (SendMessage(owner, receiver, msg))"));
800 ctx.AddLine("\treturn ENodeResult.SUCCESS;");
801 ctx.AddLine("else");
802 ctx.AddLine("\treturn ENodeResult.FAIL;");
803 ctx.AddLine("}");
804 ctx.AddLine("");
805
806 GenerateGetNodeMiddleText(ctx, variables);
807
808 ctx.AddLine("static override bool VisibleInPalette() { return true; }");
809
810 ctx.AddLine("}");
811 ctx.AddLine("");
812 }
813}
814
815class SCR_AiScriptGenerator_SendGoalMessageGenerator : SCR_AiScriptGenerator_ClassGeneratorBase
816{
817 //------------------------------------------------------------------------------------------------
818 override void Generate(SCR_AiScriptGenerator_OutputFormatBuffer ctx)
819 {
820 // Create array of variables of this class and its parent classes
821 array<SCR_AiScriptGenerator_Variable> variables = GetClassVariables(m_Class);
822
823 GenerateCommentSeparator(ctx);
824 ctx.AddLine(string.Format("// Generated from class: %1", m_Class.m_sName));
825 ctx.AddLine(string.Format("class %1 : SCR_AISendMessageGenerated", m_sGeneratedClassName));
826 ctx.AddLine("{");
827
828 // Variables with attributes
829 GenerateVariablesWithAttributes(ctx, variables);
830
831 // GetVariablesIn
832 GenerateGetVariablesIn(ctx, { "SCR_AISendMessageGenerated.PORT_RECEIVER" }, variables);
833
834 // EOnTaskSimulate
835 ctx.AddLine("override ENodeResult EOnTaskSimulate(AIAgent owner, float dt)");
836 ctx.AddLine("{");
837 ctx.AddLine("AIAgent receiver = GetReceiverAgent(owner);");
838 ctx.AddLine(string.Format("%1 msg = new %1();", m_Class.m_sName));
839 ctx.AddLine("");
840
841 // Set related activity
842 ctx.AddLine(string.Format("msg.m_RelatedGroupActivity = GetRelatedActivity(owner);"));
843 ctx.AddLine("");
844
845 // Set message variables
846 GenerateSetMessageVariables(ctx, variables);
847
848 // Set related waypoint
849 ctx.AddLine("if (msg.m_bIsWaypointRelated)");
850 ctx.AddLine("\tmsg.m_RelatedWaypoint = GetRelatedWaypoint(owner);");
851 ctx.AddLine("");
852
853 ctx.AddLine(string.Format("if (SendMessage(owner, receiver, msg))"));
854 ctx.AddLine("\treturn ENodeResult.SUCCESS;");
855 ctx.AddLine("else");
856 ctx.AddLine("\treturn ENodeResult.FAIL;");
857 ctx.AddLine("}");
858 ctx.AddLine("");
859
860 GenerateGetNodeMiddleText(ctx, variables);
861
862 ctx.AddLine("static override bool VisibleInPalette() { return true; }");
863
864 ctx.AddLine("}");
865 ctx.AddLine("");
866 }
867}
868
869class SCR_AiScriptGenerator_SendOrderGenerator : SCR_AiScriptGenerator_ClassGeneratorBase
870{
871 //------------------------------------------------------------------------------------------------
872 override void Generate(SCR_AiScriptGenerator_OutputFormatBuffer ctx)
873 {
874 // Create array of variables of this class and its parent classes
875 array<SCR_AiScriptGenerator_Variable> variables = GetClassVariables(m_Class);
876
877 GenerateCommentSeparator(ctx);
878 ctx.AddLine(string.Format("// Generated from class: %1", m_Class.m_sName));
879 ctx.AddLine(string.Format("class %1 : SCR_AISendMessageGenerated", m_sGeneratedClassName));
880 ctx.AddLine("{");
881
882 // Variables with attributes
883 GenerateVariablesWithAttributes(ctx, variables);
884
885 // GetVariablesIn
886 GenerateGetVariablesIn(ctx, { "SCR_AISendOrderGenerated.PORT_RECEIVER" }, variables);
887
888 // EOnTaskSimulate
889 ctx.AddLine("override ENodeResult EOnTaskSimulate(AIAgent owner, float dt)");
890 ctx.AddLine("{");
891 ctx.AddLine("AIAgent receiver = GetReceiverAgent(owner);");
892 ctx.AddLine(string.Format("%1 msg = new %1();", m_Class.m_sName));
893 ctx.AddLine("");
894
895 // Set message variables
896 GenerateSetMessageVariables(ctx, variables);
897
898 ctx.AddLine(string.Format("if (SendMessage(owner, receiver, msg))"));
899 ctx.AddLine("\treturn ENodeResult.SUCCESS;");
900 ctx.AddLine("else");
901 ctx.AddLine("\treturn ENodeResult.FAIL;");
902 ctx.AddLine("}");
903 ctx.AddLine("");
904
905 GenerateGetNodeMiddleText(ctx, variables);
906
907 ctx.AddLine("static override bool VisibleInPalette() { return true; }");
908
909 ctx.AddLine("}");
910 ctx.AddLine("");
911 }
912}
913
914class SCR_AiScriptGenerator_Class
915{
916 string m_sLine;
917 string m_sName;
918 string m_sParentClassName;
919 SCR_AiScriptGenerator_Class m_ParentClass;
920 ref array<ref SCR_AiScriptGenerator_Variable> m_aVariables = {};
921
922 // Defines what to do with this
923 ref array<ref SCR_AiScriptGenerator_ClassGeneratorBase> m_aGenerators = {};
924
925 //------------------------------------------------------------------------------------------------
927 string GetListing()
928 {
929 string strParentClassWarning;
930 if (!m_ParentClass)
931 strParentClassWarning = "(Not found!)";
932
933 return string.Format("Class: %1 : %2%3", m_sName, m_sParentClassName, strParentClassWarning);
934 }
935}
936
937class SCR_AiScriptGenerator_Variable
938{
939 string m_sLine;
940 string m_sName;
941 string m_sType;
942
943 string m_sBindPortName; // Which node port initializes this variable. Can be empty.
944
945 string m_sBindPropertyName; // Which node property initializes this variable. Can be empty.
946 bool m_bBindPropertyIsEnum; // True when the property must be an enum
947
948 //------------------------------------------------------------------------------------------------
950 string GetListing()
951 {
952 return string.Format("Variable: %1 %2 -> %3", m_sType, m_sName, m_sBindPortName);
953 }
954}
955#endif // WORKBENCH
GenerateFlowMaps WorkbenchPlugin WorkbenchPluginAttribute("Regenerate river flow-maps", "Generate and save/overwrite river flow-maps", "", "", {"WorldEditor"}, "", 0xf773)
Definition FlowmapTool.c:59
LocalizedString m_sName
override void Run()
void AddLine(string text)
void Generate()
void _print(string s)
ref array< ref SCR_ResourceGenerator > m_aGenerators
Refer to SCR_ResourceGenerator for documentation.
class WorkbenchDialog_AbortRetryIgnore ButtonAttribute("OK", true)
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
Definition LogLevel.c:14
SCR_FieldOfViewSettings Attribute
@ COMMENT
Comment visible only in the editor.
FileMode
Mode for opening file. See FileSystem::Open.
Definition FileMode.c:14