2 // Radegast Metaverse Client
3 // Copyright (c) 2009-2013, Radegast Development Team
4 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
9 // * Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 // * Neither the name of the application "Radegast", nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 using System.Collections.Generic;
33 #if (COGBOT_LIBOMV || USE_STHREADS)
35 using Thread = ThreadPoolUtil.Thread;
36 using ThreadPool = ThreadPoolUtil.ThreadPool;
37 using Monitor = ThreadPoolUtil.Monitor;
39 using System.Threading;
40 using System.Windows.Forms;
42 using OpenMetaverse.StructuredData;
43 using ClientHelpers = OpenMetaverse.Helpers;
47 public class PrimDeserializer
49 public static void ImportFromFile(GridClient client)
51 WindowWrapper mainWindow = new WindowWrapper(frmMain.ActiveForm.Handle);
52 System.Windows.Forms.OpenFileDialog dlg = new OpenFileDialog();
53 dlg.Title = "Open object file";
54 dlg.Filter = "XML file (*.xml)|*.xml";
55 dlg.Multiselect = false;
56 DialogResult res = dlg.ShowDialog();
58 if (res == DialogResult.OK)
61 Thread t = new Thread(new System.Threading.ThreadStart(delegate()
65 PrimDeserializer d = new PrimDeserializer(client);
66 string primsXmls = System.IO.File.ReadAllText(dlg.FileName);
67 d.CreateObjectFromXml(primsXmls);
70 MessageBox.Show(mainWindow, "Successfully imported " + dlg.FileName, "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
72 catch (Exception excp)
74 MessageBox.Show(mainWindow, excp.Message, "Saving failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
78 t.IsBackground = true;
84 private enum ImporterState
94 public Primitive RootPrim;
95 public List<Primitive> Children = new List<Primitive>();
99 RootPrim = new Primitive();
102 public Linkset(Primitive rootPrim)
109 Primitive currentPrim;
110 Vector3 currentPosition;
111 AutoResetEvent primDone = new AutoResetEvent(false);
112 List<Primitive> primsCreated;
113 List<uint> linkQueue;
115 ImporterState state = ImporterState.Idle;
117 public PrimDeserializer(GridClient c)
120 Client.Objects.ObjectUpdate += new EventHandler<PrimEventArgs>(Objects_ObjectUpdate);
123 public void CleanUp()
125 Client.Objects.ObjectUpdate -= new EventHandler<PrimEventArgs>(Objects_ObjectUpdate);
128 public bool CreateObjectFromXml(string xml)
130 List<Primitive> prims = ClientHelpers.OSDToPrimList(OSDParser.DeserializeLLSDXml(xml));
131 return CreateObject(prims);
134 public bool CreateObject(List<Primitive> prims)
136 // Build an organized structure from the imported prims
137 Dictionary<uint, Linkset> linksets = new Dictionary<uint, Linkset>();
138 for (int i = 0; i < prims.Count; i++)
140 Primitive prim = prims[i];
142 if (prim.ParentID == 0)
144 if (linksets.ContainsKey(prim.LocalID))
145 linksets[prim.LocalID].RootPrim = prim;
147 linksets[prim.LocalID] = new Linkset(prim);
151 if (!linksets.ContainsKey(prim.ParentID))
152 linksets[prim.ParentID] = new Linkset();
154 linksets[prim.ParentID].Children.Add(prim);
158 primsCreated = new List<Primitive>();
159 Console.WriteLine("Importing " + linksets.Count + " structures.");
161 foreach (Linkset linkset in linksets.Values)
163 if (linkset.RootPrim.LocalID != 0)
165 state = ImporterState.RezzingParent;
166 currentPrim = linkset.RootPrim;
167 // HACK: Import the structure just above our head
168 // We need a more elaborate solution for importing with relative or absolute offsets
169 linkset.RootPrim.Position = Client.Self.SimPosition;
170 linkset.RootPrim.Position.Z += 3.0f;
171 currentPosition = linkset.RootPrim.Position;
173 // Rez the root prim with no rotation
174 Quaternion rootRotation = linkset.RootPrim.Rotation;
175 linkset.RootPrim.Rotation = Quaternion.Identity;
177 Client.Objects.AddPrim(Client.Network.CurrentSim, linkset.RootPrim.PrimData, Client.Self.ActiveGroup,
178 linkset.RootPrim.Position, linkset.RootPrim.Scale, linkset.RootPrim.Rotation);
180 if (!primDone.WaitOne(25000, false))
182 throw new Exception("Rez failed, timed out while creating the root prim.");
184 Client.Objects.SetPosition(Client.Network.CurrentSim, primsCreated[primsCreated.Count - 1].LocalID, currentPosition);
186 state = ImporterState.RezzingChildren;
188 // Rez the child prims
189 foreach (Primitive prim in linkset.Children)
192 currentPosition = prim.Position + linkset.RootPrim.Position;
194 Client.Objects.AddPrim(Client.Network.CurrentSim, prim.PrimData, UUID.Zero, currentPosition,
195 prim.Scale, prim.Rotation);
197 if (!primDone.WaitOne(25000, false))
199 throw new Exception("Rez failed, timed out while creating child prim.");
201 Client.Objects.SetPosition(Client.Network.CurrentSim, primsCreated[primsCreated.Count - 1].LocalID, currentPosition);
202 // Client.Objects.SetRotation(Client.Network.CurrentSim, primsCreated[primsCreated.Count - 1].LocalID, prim.Rotation);
205 if (linkset.Children.Count != 0)
207 // Create a list of the local IDs of the newly created prims
208 List<uint> primIDs = new List<uint>(primsCreated.Count);
209 primIDs.Add(rootLocalID); // Root prim is first in list.
210 foreach (Primitive prim in primsCreated)
212 if (prim.LocalID != rootLocalID)
213 primIDs.Add(prim.LocalID);
215 linkQueue = new List<uint>(primIDs.Count);
216 linkQueue.AddRange(primIDs);
218 // Link and set the permissions + rotation
219 state = ImporterState.Linking;
220 Client.Objects.LinkPrims(Client.Network.CurrentSim, linkQueue);
221 Client.Objects.SetRotation(Client.Network.CurrentSim, rootLocalID, rootRotation);
223 if (!primDone.WaitOne(5000, false))
225 Logger.Log(String.Format("Warning: Failed to link {0} prims", linkQueue.Count), Helpers.LogLevel.Warning);
228 Client.Objects.SetPermissions(Client.Network.CurrentSim, primIDs,
229 PermissionWho.NextOwner,
230 PermissionMask.All, true);
234 List<uint> primsForPerms = new List<uint>();
235 primsForPerms.Add(rootLocalID);
236 Client.Objects.SetRotation(Client.Network.CurrentSim, rootLocalID, rootRotation);
237 Client.Objects.SetPermissions(Client.Network.CurrentSim, primsForPerms,
238 PermissionWho.NextOwner,
239 PermissionMask.All, true);
241 state = ImporterState.Idle;
245 // Skip linksets with a missing root prim
246 Logger.Log("WARNING: Skipping a linkset with a missing root prim", Helpers.LogLevel.Warning);
249 // Reset everything for the next linkset
250 primsCreated.Clear();
256 void Objects_ObjectUpdate(object sender, PrimEventArgs e)
258 if ((e.Prim.Flags & PrimFlags.CreateSelected) == 0)
259 return; // We received an update for an object we didn't create
263 case ImporterState.RezzingParent:
264 rootLocalID = e.Prim.LocalID;
265 goto case ImporterState.RezzingChildren;
266 case ImporterState.RezzingChildren:
267 if (!primsCreated.Contains(e.Prim))
269 Console.WriteLine("Setting properties for " + e.Prim.LocalID);
270 // TODO: Is there a way to set all of this at once, and update more ObjectProperties stuff?
271 Client.Objects.SetPosition(e.Simulator, e.Prim.LocalID, currentPosition);
272 Client.Objects.SetTextures(e.Simulator, e.Prim.LocalID, currentPrim.Textures);
274 if (currentPrim.Light != null && currentPrim.Light.Intensity > 0)
276 Client.Objects.SetLight(e.Simulator, e.Prim.LocalID, currentPrim.Light);
279 if (currentPrim.Flexible != null)
281 Client.Objects.SetFlexible(e.Simulator, e.Prim.LocalID, currentPrim.Flexible);
284 if (currentPrim.Sculpt != null && currentPrim.Sculpt.SculptTexture != UUID.Zero)
286 Client.Objects.SetSculpt(e.Simulator, e.Prim.LocalID, currentPrim.Sculpt);
289 if (currentPrim.Properties != null && !String.IsNullOrEmpty(currentPrim.Properties.Name))
291 Client.Objects.SetName(e.Simulator, e.Prim.LocalID, currentPrim.Properties.Name);
294 if (currentPrim.Properties != null && !String.IsNullOrEmpty(currentPrim.Properties.Description))
296 Client.Objects.SetDescription(e.Simulator, e.Prim.LocalID, currentPrim.Properties.Description);
299 primsCreated.Add(e.Prim);
303 case ImporterState.Linking:
306 int index = linkQueue.IndexOf(e.Prim.LocalID);
309 linkQueue.RemoveAt(index);
310 if (linkQueue.Count == 0)