corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
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 }