corrade-vassal – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 1 | using System; |
2 | using System.Collections.Generic; |
||
3 | using System.Threading; |
||
4 | using System.IO; |
||
5 | using System.Drawing; |
||
6 | using System.Globalization; |
||
7 | using OpenMetaverse; |
||
8 | using OpenMetaverse.Http; |
||
9 | using OpenMetaverse.Imaging; |
||
10 | |||
11 | namespace importprimscript |
||
12 | { |
||
13 | class Sculpt |
||
14 | { |
||
15 | public string Name; |
||
16 | public string TextureFile; |
||
17 | public UUID TextureID; |
||
18 | public string SculptFile; |
||
19 | public UUID SculptID; |
||
20 | public Vector3 Scale; |
||
21 | public Vector3 Offset; |
||
22 | } |
||
23 | |||
24 | class importprimscript |
||
25 | { |
||
26 | static GridClient Client = new GridClient(); |
||
27 | static Sculpt CurrentSculpt = null; |
||
28 | static AutoResetEvent RezzedEvent = new AutoResetEvent(false); |
||
29 | static Vector3 RootPosition = Vector3.Zero; |
||
30 | static List<uint> RezzedPrims = new List<uint>(); |
||
31 | static UUID UploadFolderID = UUID.Zero; |
||
32 | |||
33 | static void Main(string[] args) |
||
34 | { |
||
35 | if (args.Length != 8 && args.Length != 9) |
||
36 | { |
||
37 | Console.WriteLine("Usage: importprimscript.exe [firstname] [lastname] [password] " + |
||
38 | "[loginuri] [Simulator] [x] [y] [z] [input.primscript]" + |
||
39 | Environment.NewLine + "Example: importprimscript.exe My Bot password " + |
||
40 | "Hooper 128 128 40 maya-export" + Path.DirectorySeparatorChar + "ant.primscript" + |
||
41 | Environment.NewLine + "(the loginuri is optional and only used for logging in to another grid)"); |
||
42 | Environment.Exit(-1); |
||
43 | } |
||
44 | |||
45 | // Strip quotes from any arguments |
||
46 | for (int i = 0; i < args.Length; i++) |
||
47 | args[i] = args[i].Trim(new char[] { '"' }); |
||
48 | |||
49 | // Parse the primscript file |
||
50 | string scriptfilename = args[args.Length - 1]; |
||
51 | string error; |
||
52 | List<Sculpt> sculpties = ParsePrimscript(scriptfilename, out error); |
||
53 | scriptfilename = Path.GetFileNameWithoutExtension(scriptfilename); |
||
54 | |||
55 | // Check for parsing errors |
||
56 | if (error != String.Empty) |
||
57 | { |
||
58 | Console.WriteLine("An error was encountered reading the input file: " + error); |
||
59 | Environment.Exit(-2); |
||
60 | } |
||
61 | else if (sculpties.Count == 0) |
||
62 | { |
||
63 | Console.WriteLine("No primitives were read from the input file"); |
||
64 | Environment.Exit(-3); |
||
65 | } |
||
66 | |||
67 | // Add callback handlers for asset uploads finishing. new prims spotted, and logging |
||
68 | Client.Objects.ObjectUpdate += new EventHandler<PrimEventArgs>(Objects_OnNewPrim); |
||
69 | Logger.OnLogMessage += new Logger.LogCallback(Client_OnLogMessage); |
||
70 | |||
71 | // Optimize the connection for our purposes |
||
72 | Client.Self.Movement.Camera.Far = 64f; |
||
73 | Client.Settings.MULTIPLE_SIMS = false; |
||
74 | Client.Settings.SEND_AGENT_UPDATES = true; |
||
75 | Settings.LOG_LEVEL = Helpers.LogLevel.None; |
||
76 | Client.Settings.ALWAYS_REQUEST_OBJECTS = true; |
||
77 | Client.Settings.ALWAYS_DECODE_OBJECTS = true; |
||
78 | Client.Settings.THROTTLE_OUTGOING_PACKETS = false; |
||
79 | Client.Throttle.Land = 0; |
||
80 | Client.Throttle.Wind = 0; |
||
81 | Client.Throttle.Cloud = 0; |
||
82 | // Not sure if Asset or Texture will help with uploads, but it won't hurt |
||
83 | Client.Throttle.Asset = 220000.0f; |
||
84 | Client.Throttle.Texture = 446000.0f; |
||
85 | Client.Throttle.Task = 446000.0f; |
||
86 | |||
87 | // Create a handler for the event queue connecting, so we know when |
||
88 | // it is safe to start uploading |
||
89 | AutoResetEvent eventQueueEvent = new AutoResetEvent(false); |
||
90 | EventHandler<EventQueueRunningEventArgs> eventQueueCallback = |
||
91 | delegate(object sender, EventQueueRunningEventArgs e) |
||
92 | { |
||
93 | if (e.Simulator == Client.Network.CurrentSim) |
||
94 | eventQueueEvent.Set(); |
||
95 | }; |
||
96 | |||
97 | Client.Network.EventQueueRunning += eventQueueCallback; |
||
98 | |||
99 | int x = Int32.Parse(args[args.Length - 4]); |
||
100 | int y = Int32.Parse(args[args.Length - 3]); |
||
101 | int z = Int32.Parse(args[args.Length - 2]); |
||
102 | string start = NetworkManager.StartLocation(args[args.Length - 5], x, y, z); |
||
103 | |||
104 | LoginParams loginParams = Client.Network.DefaultLoginParams(args[0], args[1], args[2], |
||
105 | "importprimscript", "1.4.0"); |
||
106 | loginParams.Start = start; |
||
107 | if (args.Length == 9) loginParams.URI = args[3]; |
||
108 | |||
109 | // Attempt to login |
||
110 | if (!Client.Network.Login(loginParams)) |
||
111 | { |
||
112 | Console.WriteLine("Login failed: " + Client.Network.LoginMessage); |
||
113 | Environment.Exit(-4); |
||
114 | } |
||
115 | |||
116 | // Need to be connected to the event queue before we can upload |
||
117 | Console.WriteLine("Login succeeded, waiting for the event handler to connect..."); |
||
118 | if (!eventQueueEvent.WaitOne(1000 * 90, false)) |
||
119 | { |
||
120 | Console.WriteLine("Event queue connection timed out, disconnecting..."); |
||
121 | Client.Network.Logout(); |
||
122 | Environment.Exit(-5); |
||
123 | } |
||
124 | |||
125 | // Don't need this anymore |
||
126 | Client.Network.EventQueueRunning -= eventQueueCallback; |
||
127 | |||
128 | // Set the root position for the import |
||
129 | RootPosition = Client.Self.SimPosition; |
||
130 | RootPosition.Z += 3.0f; |
||
131 | |||
132 | // TODO: Check if our account balance is high enough to upload everything |
||
133 | // |
||
134 | |||
135 | // Create a folder to hold all of our texture uploads |
||
136 | UploadFolderID = Client.Inventory.CreateFolder(Client.Inventory.Store.RootFolder.UUID, scriptfilename); |
||
137 | |||
138 | // Loop through each sculpty and do what we need to do |
||
139 | for (int i = 0; i < sculpties.Count; i++) |
||
140 | { |
||
141 | // Upload the sculpt map and texture |
||
142 | sculpties[i].SculptID = UploadImage(sculpties[i].SculptFile, true); |
||
143 | sculpties[i].TextureID = UploadImage(sculpties[i].TextureFile, false); |
||
144 | |||
145 | // Check for failed uploads |
||
146 | if (sculpties[i].SculptID == UUID.Zero) |
||
147 | { |
||
148 | Console.WriteLine("Sculpt map " + sculpties[i].SculptFile + " failed to upload, skipping " + sculpties[i].Name); |
||
149 | continue; |
||
150 | } |
||
151 | else if (sculpties[i].TextureID == UUID.Zero) |
||
152 | { |
||
153 | Console.WriteLine("Texture " + sculpties[i].TextureFile + " failed to upload, skipping " + sculpties[i].Name); |
||
154 | continue; |
||
155 | } |
||
156 | |||
157 | // Create basic spherical volume parameters. It will be set to |
||
158 | // a scultpy in the callback for new objects being created |
||
159 | Primitive.ConstructionData volume = new Primitive.ConstructionData(); |
||
160 | volume.PCode = PCode.Prim; |
||
161 | volume.Material = Material.Wood; |
||
162 | volume.PathScaleY = 0.5f; |
||
163 | volume.PathCurve = PathCurve.Circle; |
||
164 | volume.ProfileCurve = ProfileCurve.Circle; |
||
165 | |||
166 | // Rez this prim |
||
167 | CurrentSculpt = sculpties[i]; |
||
168 | Client.Objects.AddPrim(Client.Network.CurrentSim, volume, UUID.Zero, |
||
169 | RootPosition + CurrentSculpt.Offset, CurrentSculpt.Scale, Quaternion.Identity); |
||
170 | |||
171 | // Wait for the prim to rez and the properties be set for it |
||
172 | if (!RezzedEvent.WaitOne(1000 * 10, false)) |
||
173 | { |
||
174 | Console.WriteLine("Timed out waiting for prim " + CurrentSculpt.Name + " to rez, skipping"); |
||
175 | continue; |
||
176 | } |
||
177 | } |
||
178 | |||
179 | CurrentSculpt = null; |
||
180 | |||
181 | lock (RezzedPrims) |
||
182 | { |
||
183 | // Set full permissions for all of the objects |
||
184 | Client.Objects.SetPermissions(Client.Network.CurrentSim, RezzedPrims, PermissionWho.All, |
||
185 | PermissionMask.All, true); |
||
186 | |||
187 | // Link the entire object together |
||
188 | Client.Objects.LinkPrims(Client.Network.CurrentSim, RezzedPrims); |
||
189 | } |
||
190 | |||
191 | Console.WriteLine("Rezzed, textured, and linked " + RezzedPrims.Count + " sculpted prims, logging out..."); |
||
192 | |||
193 | Client.Network.Logout(); |
||
194 | } |
||
195 | |||
196 | static void Client_OnLogMessage(object message, Helpers.LogLevel level) |
||
197 | { |
||
198 | if (level >= Helpers.LogLevel.Warning) |
||
199 | Console.WriteLine(level + ": " + message); |
||
200 | } |
||
201 | |||
202 | static UUID UploadImage(string filename, bool lossless) |
||
203 | { |
||
204 | UUID newAssetID = UUID.Zero; |
||
205 | byte[] jp2data = null; |
||
206 | |||
207 | try |
||
208 | { |
||
209 | Bitmap image = (Bitmap)Bitmap.FromFile(filename); |
||
210 | jp2data = OpenJPEG.EncodeFromImage(image, lossless); |
||
211 | } |
||
212 | catch (Exception ex) |
||
213 | { |
||
214 | Console.WriteLine("Failed to encode image file " + filename + ": " + ex.ToString()); |
||
215 | return UUID.Zero; |
||
216 | } |
||
217 | |||
218 | AutoResetEvent uploadEvent = new AutoResetEvent(false); |
||
219 | Client.Inventory.RequestCreateItemFromAsset(jp2data, Path.GetFileNameWithoutExtension(filename), |
||
220 | "Uploaded with importprimscript", AssetType.Texture, InventoryType.Texture, UploadFolderID, |
||
221 | delegate(bool success, string status, UUID itemID, UUID assetID) |
||
222 | { |
||
223 | if (success) |
||
224 | { |
||
225 | Console.WriteLine("Finished uploading image " + filename + ", AssetID: " + assetID.ToString()); |
||
226 | newAssetID = assetID; |
||
227 | } |
||
228 | else |
||
229 | { |
||
230 | Console.WriteLine("Failed to upload image file " + filename + ": " + status); |
||
231 | } |
||
232 | |||
233 | uploadEvent.Set(); |
||
234 | } |
||
235 | ); |
||
236 | |||
237 | // The images are small, 60 seconds should be plenty |
||
238 | uploadEvent.WaitOne(1000 * 60, false); |
||
239 | |||
240 | return newAssetID; |
||
241 | } |
||
242 | |||
243 | static void Objects_OnNewPrim(object sender, PrimEventArgs e) |
||
244 | { |
||
245 | Primitive prim = e.Prim; |
||
246 | if (CurrentSculpt != null && (prim.Flags & PrimFlags.CreateSelected) != 0 && |
||
247 | !RezzedPrims.Contains(prim.LocalID)) |
||
248 | { |
||
249 | lock (RezzedPrims) RezzedPrims.Add(prim.LocalID); |
||
250 | |||
251 | Console.WriteLine("Rezzed prim " + CurrentSculpt.Name + ", setting properties"); |
||
252 | |||
253 | // Deselect the prim |
||
254 | Client.Objects.DeselectObject(Client.Network.CurrentSim, prim.LocalID); |
||
255 | |||
256 | // Set the prim position |
||
257 | Client.Objects.SetPosition(Client.Network.CurrentSim, prim.LocalID, |
||
258 | RootPosition + CurrentSculpt.Offset); |
||
259 | |||
260 | // Set the texture |
||
261 | Primitive.TextureEntry textures = new Primitive.TextureEntry(CurrentSculpt.TextureID); |
||
262 | Client.Objects.SetTextures(Client.Network.CurrentSim, prim.LocalID, textures); |
||
263 | |||
264 | // Turn it in to a sculpted prim |
||
265 | Primitive.SculptData sculpt = new Primitive.SculptData(); |
||
266 | sculpt.SculptTexture = CurrentSculpt.SculptID; |
||
267 | sculpt.Type = SculptType.Sphere; |
||
268 | Client.Objects.SetSculpt(Client.Network.CurrentSim, prim.LocalID, sculpt); |
||
269 | |||
270 | // Set the prim name |
||
271 | if (!String.IsNullOrEmpty(CurrentSculpt.Name)) |
||
272 | Client.Objects.SetName(Client.Network.CurrentSim, prim.LocalID, CurrentSculpt.Name); |
||
273 | |||
274 | RezzedEvent.Set(); |
||
275 | } |
||
276 | } |
||
277 | |||
278 | static List<Sculpt> ParsePrimscript(string primscriptfile, out string error) |
||
279 | { |
||
280 | string line; |
||
281 | Sculpt current = null; |
||
282 | List<Sculpt> sculpties = new List<Sculpt>(); |
||
283 | error = String.Empty; |
||
284 | StreamReader primscript = null; |
||
285 | |||
286 | // Parse a directory out of the primscriptfile string, if one exists |
||
287 | string path = Path.GetDirectoryName(primscriptfile); |
||
288 | if (!String.IsNullOrEmpty(path)) |
||
289 | path += Path.DirectorySeparatorChar; |
||
290 | else |
||
291 | path = String.Empty; |
||
292 | |||
293 | try |
||
294 | { |
||
295 | primscript = File.OpenText(primscriptfile); |
||
296 | |||
297 | while ((line = primscript.ReadLine()) != null) |
||
298 | { |
||
299 | string[] words = line.Split(new char[] { ' ' }); |
||
300 | |||
301 | if (words.Length > 0) |
||
302 | { |
||
303 | if (current != null) |
||
304 | { |
||
305 | switch (words[0]) |
||
306 | { |
||
307 | case "newPrim": |
||
308 | if (current.Scale != Vector3.Zero && |
||
309 | !String.IsNullOrEmpty(current.SculptFile) && |
||
310 | !String.IsNullOrEmpty(current.TextureFile)) |
||
311 | { |
||
312 | // Add the previous prim to the list as it is now finalized |
||
313 | sculpties.Add(current); |
||
314 | } |
||
315 | |||
316 | // Start a new prim |
||
317 | current = new Sculpt(); |
||
318 | |||
319 | break; |
||
320 | case "prim": |
||
321 | // The only useful bit of information here is the prim name |
||
322 | if (words.Length >= 3) |
||
323 | current.Name = words[2]; |
||
324 | break; |
||
325 | case "shape": |
||
326 | // This line has the name of the sculpt texture |
||
327 | if (words.Length >= 3) |
||
328 | current.SculptFile = path + words[2] + ".bmp"; |
||
329 | break; |
||
330 | case "texture": |
||
331 | // This line has the name of the actual texture |
||
332 | if (words.Length >= 3) |
||
333 | current.TextureFile = path + words[2] + ".bmp"; |
||
334 | break; |
||
335 | case "transform": |
||
336 | // Get some primitive params |
||
337 | if (words.Length >= 9) |
||
338 | { |
||
339 | float x, y, z; |
||
340 | x = Single.Parse(words[2], CultureInfo.InvariantCulture); |
||
341 | y = Single.Parse(words[3], CultureInfo.InvariantCulture); |
||
342 | z = Single.Parse(words[4], CultureInfo.InvariantCulture); |
||
343 | current.Scale = new Vector3(x, y, z); |
||
344 | |||
345 | x = Single.Parse(words[6], CultureInfo.InvariantCulture); |
||
346 | y = Single.Parse(words[7], CultureInfo.InvariantCulture); |
||
347 | z = Single.Parse(words[8], CultureInfo.InvariantCulture); |
||
348 | current.Offset = new Vector3(x, y, z); |
||
349 | } |
||
350 | break; |
||
351 | } |
||
352 | } |
||
353 | else if (words[0] == "newPrim") |
||
354 | { |
||
355 | // Start a new prim |
||
356 | current = new Sculpt(); |
||
357 | } |
||
358 | } |
||
359 | } |
||
360 | |||
361 | // Add the final prim |
||
362 | if (current != null && current.Scale != Vector3.Zero && |
||
363 | !String.IsNullOrEmpty(current.SculptFile) && |
||
364 | !String.IsNullOrEmpty(current.TextureFile)) |
||
365 | { |
||
366 | // Add the previous prim to the list as it is now finalized |
||
367 | sculpties.Add(current); |
||
368 | } |
||
369 | } |
||
370 | catch (Exception ex) |
||
371 | { |
||
372 | error = ex.ToString(); |
||
373 | } |
||
374 | finally |
||
375 | { |
||
376 | if (primscript != null) |
||
377 | primscript.Close(); |
||
378 | } |
||
379 | |||
380 | return sculpties; |
||
381 | } |
||
382 | } |
||
383 | } |