OSDN Git Service

25d43f259d1e75629c260bba8c4ef919cc56f584
[radegast/radegast.git] / Radegast / Core / PrimDeserializer.cs
1 // 
2 // Radegast Metaverse Client
3 // Copyright (c) 2009-2013, Radegast Development Team
4 // All rights reserved.
5 // 
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 // 
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.
17 // 
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.
28 //
29 // $Id$
30 //
31 using System;
32 using System.Collections.Generic;
33 #if (COGBOT_LIBOMV || USE_STHREADS)
34 using ThreadPoolUtil;
35 using Thread = ThreadPoolUtil.Thread;
36 using ThreadPool = ThreadPoolUtil.ThreadPool;
37 using Monitor = ThreadPoolUtil.Monitor;
38 #endif
39 using System.Threading;
40 using System.Windows.Forms;
41 using OpenMetaverse;
42 using OpenMetaverse.StructuredData;
43 using ClientHelpers = OpenMetaverse.Helpers;
44
45 namespace Radegast
46 {
47     public class PrimDeserializer
48     {
49         public static void ImportFromFile(GridClient client)
50         {
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();
57
58             if (res == DialogResult.OK)
59             {
60
61                 Thread t = new Thread(new System.Threading.ThreadStart(delegate()
62                 {
63                     try
64                     {
65                         PrimDeserializer d = new PrimDeserializer(client);
66                         string primsXmls = System.IO.File.ReadAllText(dlg.FileName);
67                         d.CreateObjectFromXml(primsXmls);
68                         d.CleanUp();
69                         d = null;
70                         MessageBox.Show(mainWindow, "Successfully imported " + dlg.FileName, "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
71                     }
72                     catch (Exception excp)
73                     {
74                         MessageBox.Show(mainWindow, excp.Message, "Saving failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
75                     }
76                 }));
77
78                 t.IsBackground = true;
79                 t.Start();
80
81             }
82         }
83
84         private enum ImporterState
85         {
86             RezzingParent,
87             RezzingChildren,
88             Linking,
89             Idle
90         }
91
92         private class Linkset
93         {
94             public Primitive RootPrim;
95             public List<Primitive> Children = new List<Primitive>();
96
97             public Linkset()
98             {
99                 RootPrim = new Primitive();
100             }
101
102             public Linkset(Primitive rootPrim)
103             {
104                 RootPrim = rootPrim;
105             }
106         }
107
108         GridClient Client;
109         Primitive currentPrim;
110         Vector3 currentPosition;
111         AutoResetEvent primDone = new AutoResetEvent(false);
112         List<Primitive> primsCreated;
113         List<uint> linkQueue;
114         uint rootLocalID;
115         ImporterState state = ImporterState.Idle;
116
117         public PrimDeserializer(GridClient c)
118         {
119             Client = c;
120             Client.Objects.ObjectUpdate += new EventHandler<PrimEventArgs>(Objects_ObjectUpdate);
121         }
122
123         public void CleanUp()
124         {
125             Client.Objects.ObjectUpdate -= new EventHandler<PrimEventArgs>(Objects_ObjectUpdate);
126         }
127
128         public bool CreateObjectFromXml(string xml)
129         {
130             List<Primitive> prims = ClientHelpers.OSDToPrimList(OSDParser.DeserializeLLSDXml(xml));
131             return CreateObject(prims);
132         }
133
134         public bool CreateObject(List<Primitive> prims)
135         {
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++)
139             {
140                 Primitive prim = prims[i];
141
142                 if (prim.ParentID == 0)
143                 {
144                     if (linksets.ContainsKey(prim.LocalID))
145                         linksets[prim.LocalID].RootPrim = prim;
146                     else
147                         linksets[prim.LocalID] = new Linkset(prim);
148                 }
149                 else
150                 {
151                     if (!linksets.ContainsKey(prim.ParentID))
152                         linksets[prim.ParentID] = new Linkset();
153
154                     linksets[prim.ParentID].Children.Add(prim);
155                 }
156             }
157
158             primsCreated = new List<Primitive>();
159             Console.WriteLine("Importing " + linksets.Count + " structures.");
160
161             foreach (Linkset linkset in linksets.Values)
162             {
163                 if (linkset.RootPrim.LocalID != 0)
164                 {
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;
172
173                     // Rez the root prim with no rotation
174                     Quaternion rootRotation = linkset.RootPrim.Rotation;
175                     linkset.RootPrim.Rotation = Quaternion.Identity;
176
177                     Client.Objects.AddPrim(Client.Network.CurrentSim, linkset.RootPrim.PrimData, Client.Self.ActiveGroup,
178                         linkset.RootPrim.Position, linkset.RootPrim.Scale, linkset.RootPrim.Rotation);
179
180                     if (!primDone.WaitOne(25000, false))
181                     {
182                         throw new Exception("Rez failed, timed out while creating the root prim.");
183                     }
184                     Client.Objects.SetPosition(Client.Network.CurrentSim, primsCreated[primsCreated.Count - 1].LocalID, currentPosition);
185
186                     state = ImporterState.RezzingChildren;
187
188                     // Rez the child prims
189                     foreach (Primitive prim in linkset.Children)
190                     {
191                         currentPrim = prim;
192                         currentPosition = prim.Position + linkset.RootPrim.Position;
193
194                         Client.Objects.AddPrim(Client.Network.CurrentSim, prim.PrimData, UUID.Zero, currentPosition,
195                             prim.Scale, prim.Rotation);
196
197                         if (!primDone.WaitOne(25000, false))
198                         {
199                             throw new Exception("Rez failed, timed out while creating child prim.");
200                         }
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);
203                     }
204
205                     if (linkset.Children.Count != 0)
206                     {
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)
211                         {
212                             if (prim.LocalID != rootLocalID)
213                                 primIDs.Add(prim.LocalID);
214                         }
215                         linkQueue = new List<uint>(primIDs.Count);
216                         linkQueue.AddRange(primIDs);
217
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);
222
223                         if (!primDone.WaitOne(5000, false))
224                         {
225                             Logger.Log(String.Format("Warning: Failed to link {0} prims", linkQueue.Count), Helpers.LogLevel.Warning);
226                         }
227
228                         Client.Objects.SetPermissions(Client.Network.CurrentSim, primIDs,
229                             PermissionWho.NextOwner,
230                             PermissionMask.All, true);
231                     }
232                     else
233                     {
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);
240                     }
241                     state = ImporterState.Idle;
242                 }
243                 else
244                 {
245                     // Skip linksets with a missing root prim
246                     Logger.Log("WARNING: Skipping a linkset with a missing root prim", Helpers.LogLevel.Warning);
247                 }
248
249                 // Reset everything for the next linkset
250                 primsCreated.Clear();
251             }
252
253             return true;
254         }
255
256         void Objects_ObjectUpdate(object sender, PrimEventArgs e)
257         {
258             if ((e.Prim.Flags & PrimFlags.CreateSelected) == 0)
259                 return; // We received an update for an object we didn't create
260
261             switch (state)
262             {
263                 case ImporterState.RezzingParent:
264                     rootLocalID = e.Prim.LocalID;
265                     goto case ImporterState.RezzingChildren;
266                 case ImporterState.RezzingChildren:
267                     if (!primsCreated.Contains(e.Prim))
268                     {
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);
273
274                         if (currentPrim.Light != null && currentPrim.Light.Intensity > 0)
275                         {
276                             Client.Objects.SetLight(e.Simulator, e.Prim.LocalID, currentPrim.Light);
277                         }
278
279                         if (currentPrim.Flexible != null)
280                         {
281                             Client.Objects.SetFlexible(e.Simulator, e.Prim.LocalID, currentPrim.Flexible);
282                         }
283
284                         if (currentPrim.Sculpt != null && currentPrim.Sculpt.SculptTexture != UUID.Zero)
285                         {
286                             Client.Objects.SetSculpt(e.Simulator, e.Prim.LocalID, currentPrim.Sculpt);
287                         }
288
289                         if (currentPrim.Properties != null && !String.IsNullOrEmpty(currentPrim.Properties.Name))
290                         {
291                             Client.Objects.SetName(e.Simulator, e.Prim.LocalID, currentPrim.Properties.Name);
292                         }
293
294                         if (currentPrim.Properties != null && !String.IsNullOrEmpty(currentPrim.Properties.Description))
295                         {
296                             Client.Objects.SetDescription(e.Simulator, e.Prim.LocalID, currentPrim.Properties.Description);
297                         }
298
299                         primsCreated.Add(e.Prim);
300                         primDone.Set();
301                     }
302                     break;
303                 case ImporterState.Linking:
304                     lock (linkQueue)
305                     {
306                         int index = linkQueue.IndexOf(e.Prim.LocalID);
307                         if (index != -1)
308                         {
309                             linkQueue.RemoveAt(index);
310                             if (linkQueue.Count == 0)
311                                 primDone.Set();
312                         }
313                     }
314                     break;
315             }
316         }
317     }
318 }