Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_ObjectImportPlugin.c
Go to the documentation of this file.
2 name: PLUGIN_NAME,
3 description: PLUGIN_DESCRIPTION,
4 wbModules: { "WorldEditor" },
5 category: SCR_PluginCategory.WORLDEDITOR_IMPORT_EXPORT,
6 awesomeFontCode: 0xF0D0)]
7class SCR_ObjectImportPlugin : WorldEditorPlugin
8{
9 [Attribute(desc: "CSV file containing objects information.\nExpected line format: Prefab, x, y, z, quatX, quatY, quatZ, quatW, scale\nBoth space and comma are accepted value separators", params: "csv")]
10 ResourceName m_sDataPath;
11
12 [Attribute("1", UIWidgets.CheckBox, "Makes Y coordinate relative to terrain vs absolute in world")]
13 bool m_bRelativeY;
14
15 protected static const int TOKENS_EXPECTED_COUNT = 9;
16 protected static const int RESOURCEHASH_INDEX = 0;
17 protected static const int POS_INDEX = 1; // 1, 2, 3
18 protected static const int QUAT_INDEX = 4; // 4, 5, 6, 7
19 protected static const int SCALE_INDEX = 8; // final index... for now!
20
21 protected static const string PLUGIN_NAME = "CSV Object Import";
22 protected static const string PLUGIN_DESCRIPTION = "Import entities from CSV file data";
23
24 //------------------------------------------------------------------------------------------------
25 override void Run()
26 {
27 if (Workbench.ScriptDialog(PLUGIN_NAME, PLUGIN_DESCRIPTION, this) == 0)
28 return;
29
30 if (!m_sDataPath) // .IsEmpty()
31 {
32 SCR_WorkbenchHelper.PrintDialog("No Data Path was provided - please provide a (valid) CSV file.", PLUGIN_NAME, LogLevel.WARNING);
33 Run();
34 return;
35 }
36
37 ImportData();
38 }
39
40 //------------------------------------------------------------------------------------------------
41 protected void ImportData()
42 {
43 Print("Importing entities", LogLevel.NORMAL);
44
45 WorldEditorAPI worldEditorAPI = SCR_WorldEditorToolHelper.GetWorldEditorAPI();
46 if (!worldEditorAPI)
47 {
48 Print("World Editor API is not available", LogLevel.ERROR);
49 return;
50 }
51
52 string dataPath = m_sDataPath.GetPath();
53 ParseHandle parser = FileIO.BeginParse(dataPath);
54 if (!parser)
55 {
56 SCR_WorkbenchHelper.PrintDialog("Cannot create parser from file: " + dataPath, PLUGIN_NAME, LogLevel.ERROR);
57 return;
58 }
59
60 array<string> lines;
61 int linesCount;
62
63 array<string> tokens = {};
64 array<string> tokensComma = {};
65 if (!worldEditorAPI.BeginEntityAction())
66 {
67 Print("Cannot begin action", LogLevel.ERROR);
68 return;
69 }
70
71 const int layerID = worldEditorAPI.GetCurrentEntityLayerId();
72
73 int i, totalCreated;
74
75 for (; true; ++i)
76 {
77 int numTokens = parser.ParseLine(i, tokens);
78 if (numTokens < 1)
79 break;
80
81 if (numTokens < TOKENS_EXPECTED_COUNT) // let's try and use commas - it is CSV after all
82 {
83 if (!lines)
84 {
85 lines = SCR_FileIOHelper.ReadFileContent(dataPath, false);
86 if (!lines)
87 {
88 worldEditorAPI.EndEntityAction();
89 parser.EndParse();
90
91 SCR_WorkbenchHelper.PrintDialog("Cannot open/read " + dataPath, PLUGIN_NAME, LogLevel.ERROR);
92 return;
93 }
94
95 linesCount = lines.Count();
96 }
97
98 if (i >= linesCount)
99 break;
100
101 lines[i].Split(",", tokensComma, false); // read CSV line
102
103 if (numTokens < TOKENS_EXPECTED_COUNT) // additional fields are ignored, allowing comments
104 {
105 if (tokens.Count() < tokensComma.Count()) // let's take the biggest split
106 tokens = tokensComma;
107
108 PrintFormat("Line %1: Invalid data format - expected at least %3 tokens, got %2:", i + 1, tokens.Count(), TOKENS_EXPECTED_COUNT, level: LogLevel.WARNING);
109 foreach (int tokenIndex, string token : tokens)
110 {
111 PrintFormat("#%1: %2", tokenIndex + 1, token, level: LogLevel.WARNING);
112 }
113
114 continue;
115 }
116
117 tokens = tokensComma;
118 }
119
120 string resourceHash = tokens[RESOURCEHASH_INDEX];
121 ResourceName resourceName = resourceHash;
122 if (!resourceName.GetPath()) // .IsEmpty()
123 {
124 PrintFormat("Line %1: Hash %2 does not correspond to any resource", i + 1, resourceHash, level: LogLevel.ERROR);
125 continue;
126 }
127
128 float scale = tokens[SCALE_INDEX].ToFloat();
129 if (scale <= 0)
130 {
131 PrintFormat("Line %1: Wrong scale provided (parsed \"%2\" as %3)", i + 1, tokens[SCALE_INDEX], scale, level: LogLevel.WARNING);
132 continue;
133 }
134
135 vector pos;
136 for (int j; j < 3; ++j)
137 {
138 pos[j] = tokens[POS_INDEX + j].ToFloat();
139 }
140
141 pos[2] = -pos[2]; // flip z
142
143 if (m_bRelativeY)
144 pos[1] = pos[1] + worldEditorAPI.GetTerrainSurfaceY(pos[0], pos[2]);
145
146 float quat[4];
147 for (int j; j < 4; ++j)
148 {
149 quat[j] = tokens[QUAT_INDEX + j].ToFloat();
150 }
151
152 quat[2] = -quat[2]; // flip z
153 quat[3] = -quat[3]; // flip rotation because of handiness
154 Math3D.QuatNormalize(quat);
155
156 vector angles = Math3D.QuatToAngles(quat);
157 // Convert angles from (yaw, pitch, roll) to (xRotate, yRotate, zRotate) as expected by `CreateEntity`
158 float tmp = angles[0];
159 angles[0] = angles[1];
160 angles[1] = tmp;
161
162 // all data collected, let's proceed
163
164 // PrintFormat("Creating %1 on pos %2 angles %3 scale %4", resourceName.GetPath(), pos, angles, scale, level: LogLevel.VERBOSE);
165 IEntitySource entitySource = worldEditorAPI.CreateEntity(resourceHash, "", layerID, null, pos, angles);
166 if (!entitySource)
167 {
168 PrintFormat("Line %1: Entity cannot be created (%2)", i + 1, resourceHash, level: LogLevel.ERROR);
169 continue;
170 }
171
172 if (!worldEditorAPI.SetVariableValue(entitySource, null, "scale", scale.ToString()))
173 PrintFormat("Line %1: Cannot set scale on created entity (scale %2)", i + 1, scale, level: LogLevel.WARNING);
174
175 ++totalCreated;
176 }
177
178 worldEditorAPI.EndEntityAction();
179
180 parser.EndParse();
181
182 SCR_WorkbenchHelper.PrintDialog(string.Format("CSV import done: %1 creations over %2 lines", totalCreated, i + 1), PLUGIN_NAME, LogLevel.NORMAL);
183 }
184
185 //------------------------------------------------------------------------------------------------
186 [ButtonAttribute("Import", true)]
187 protected int ButtonImport()
188 {
189 return 1;
190 }
191
192 //------------------------------------------------------------------------------------------------
193 [ButtonAttribute("Cancel")]
194 protected int ButtonCancel()
195 {
196 return 0;
197 }
198}
vector scale
GenerateFlowMaps WorkbenchPlugin WorkbenchPluginAttribute("Regenerate river flow-maps", "Generate and save/overwrite river flow-maps", "", "", {"WorldEditor"}, "", 0xf773)
Definition FlowmapTool.c:59
ref array< string > angles
ResourceName resourceName
Definition SCR_AIGroup.c:66
override void Run()
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
class WorkbenchDialog_AbortRetryIgnore ButtonAttribute("OK", true)
static array< string > ReadFileContent(string filePath, bool printWarning=true)
static const string PLUGIN_DESCRIPTION
static const string PLUGIN_NAME
static const int RESOURCEHASH_INDEX
static const int TOKENS_EXPECTED_COUNT
static void PrintDialog(string message, string caption="", LogLevel level=LogLevel.WARNING)
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
proto void PrintFormat(string fmt, void param1=NULL, void param2=NULL, void param3=NULL, void param4=NULL, void param5=NULL, void param6=NULL, void param7=NULL, void param8=NULL, void param9=NULL, LogLevel level=LogLevel.NORMAL)
SCR_FieldOfViewSettings Attribute