corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28 using System.Collections.Generic;
29 using System.Text.RegularExpressions;
30 using System.IO;
31 using System.Xml;
32 using System.Xml.Serialization;
33 using OpenMetaverse.StructuredData;
34 using OpenMetaverse.Http;
35  
36 namespace OpenMetaverse.ImportExport
37 {
38 /// <summary>
39 /// Implements mesh upload communications with the simulator
40 /// </summary>
41 public class ModelUploader
42 {
43 /// <summary>
44 /// Inlcude stub convex hull physics, required for uploading to Second Life
45 /// </summary>
46 public bool IncludePhysicsStub;
47  
48 /// <summary>
49 /// Use the same mesh used for geometry as the physical mesh upload
50 /// </summary>
51 public bool UseModelAsPhysics;
52  
53 GridClient Client;
54 List<ModelPrim> Prims;
55  
56 /// <summary>
57 /// Callback for mesh upload operations
58 /// </summary>
59 /// <param name="result">null on failure, result from server on success</param>
60 public delegate void ModelUploadCallback(OSD result);
61  
62  
63 string InvName, InvDescription;
64  
65 /// <summary>
66 /// Creates instance of the mesh uploader
67 /// </summary>
68 /// <param name="client">GridClient instance to communicate with the simulator</param>
69 /// <param name="prims">List of ModelPrimitive objects to upload as a linkset</param>
70 /// <param name="newInvName">Inventory name for newly uploaded object</param>
71 /// <param name="newInvDesc">Inventory description for newly upload object</param>
72 public ModelUploader(GridClient client, List<ModelPrim> prims, string newInvName, string newInvDesc)
73 {
74 this.Client = client;
75 this.Prims = prims;
76 this.InvName = newInvName;
77 this.InvDescription = newInvDesc;
78 }
79  
80 List<byte[]> Images;
81 Dictionary<string, int> ImgIndex;
82  
83 OSD AssetResources(bool upload)
84 {
85 OSDArray instanceList = new OSDArray();
86 List<byte[]> meshes = new List<byte[]>();
87 List<byte[]> textures = new List<byte[]>();
88  
89 foreach (var prim in Prims)
90 {
91 OSDMap primMap = new OSDMap();
92  
93 OSDArray faceList = new OSDArray();
94  
95 foreach (var face in prim.Faces)
96 {
97 OSDMap faceMap = new OSDMap();
98  
99 faceMap["diffuse_color"] = face.Material.DiffuseColor;
100 faceMap["fullbright"] = false;
101  
102 if (face.Material.TextureData != null)
103 {
104 int index;
105 if (ImgIndex.ContainsKey(face.Material.Texture))
106 {
107 index = ImgIndex[face.Material.Texture];
108 }
109 else
110 {
111 index = Images.Count;
112 ImgIndex[face.Material.Texture] = index;
113 Images.Add(face.Material.TextureData);
114 }
115 faceMap["image"] = index;
116 faceMap["scales"] = 1.0f;
117 faceMap["scalet"] = 1.0f;
118 faceMap["offsets"] = 0.0f;
119 faceMap["offsett"] = 0.0f;
120 faceMap["imagerot"] = 0.0f;
121 }
122  
123 faceList.Add(faceMap);
124 }
125  
126 primMap["face_list"] = faceList;
127  
128 primMap["position"] = prim.Position;
129 primMap["rotation"] = prim.Rotation;
130 primMap["scale"] = prim.Scale;
131  
132 primMap["material"] = 3; // always sent as "wood" material
133 primMap["physics_shape_type"] = 2; // always sent as "convex hull";
134 primMap["mesh"] = meshes.Count;
135 meshes.Add(prim.Asset);
136  
137  
138 instanceList.Add(primMap);
139 }
140  
141 OSDMap resources = new OSDMap();
142 resources["instance_list"] = instanceList;
143  
144 OSDArray meshList = new OSDArray();
145 foreach (var mesh in meshes)
146 {
147 meshList.Add(OSD.FromBinary(mesh));
148 }
149 resources["mesh_list"] = meshList;
150  
151 OSDArray textureList = new OSDArray();
152 for (int i = 0; i < Images.Count; i++)
153 {
154 if (upload)
155 {
156 textureList.Add(new OSDBinary(Images[i]));
157 }
158 else
159 {
160 textureList.Add(new OSDBinary(Utils.EmptyBytes));
161 }
162 }
163  
164 resources["texture_list"] = textureList;
165  
166 resources["metric"] = "MUT_Unspecified";
167  
168 return resources;
169 }
170  
171 /// <summary>
172 /// Performs model upload in one go, without first checking for the price
173 /// </summary>
174 public void Upload()
175 {
176 Upload(null);
177 }
178  
179 /// <summary>
180 /// Performs model upload in one go, without first checking for the price
181 /// </summary>
182 /// <param name="callback">Callback that will be invoke upon completion of the upload. Null is sent on request failure</param>
183 public void Upload(ModelUploadCallback callback)
184 {
185 PrepareUpload((result =>
186 {
187 if (result == null && callback != null)
188 {
189 callback(null);
190 return;
191 }
192  
193 if (result is OSDMap)
194 {
195 var res = (OSDMap)result;
196 Uri uploader = new Uri(res["uploader"]);
197 PerformUpload(uploader, (contents =>
198 {
199 if (contents != null)
200 {
201 var reply = (OSDMap)contents;
202 if (reply.ContainsKey("new_inventory_item") && reply.ContainsKey("new_asset"))
203 {
204 // Request full update on the item in order to update the local store
205 Client.Inventory.RequestFetchInventory(reply["new_inventory_item"].AsUUID(), Client.Self.AgentID);
206 }
207 }
208 if (callback != null) callback(contents);
209 }));
210 }
211 }));
212  
213 }
214  
215 /// <summary>
216 /// Ask server for details of cost and impact of the mesh upload
217 /// </summary>
218 /// <param name="callback">Callback that will be invoke upon completion of the upload. Null is sent on request failure</param>
219 public void PrepareUpload(ModelUploadCallback callback)
220 {
221 Uri url = null;
222 if (Client.Network.CurrentSim == null ||
223 Client.Network.CurrentSim.Caps == null ||
224 null == (url = Client.Network.CurrentSim.Caps.CapabilityURI("NewFileAgentInventory")))
225 {
226 Logger.Log("Cannot upload mesh, no connection or NewFileAgentInventory not available", Helpers.LogLevel.Warning);
227 if (callback != null) callback(null);
228 return;
229 }
230  
231 Images = new List<byte[]>();
232 ImgIndex = new Dictionary<string, int>();
233  
234 OSDMap req = new OSDMap();
235 req["name"] = InvName;
236 req["description"] = InvDescription;
237  
238 req["asset_resources"] = AssetResources(false);
239 req["asset_type"] = "mesh";
240 req["inventory_type"] = "object";
241  
242 req["folder_id"] = Client.Inventory.FindFolderForType(AssetType.Object);
243 req["texture_folder_id"] = Client.Inventory.FindFolderForType(AssetType.Texture);
244  
245 req["everyone_mask"] = (int)PermissionMask.All;
246 req["group_mask"] = (int)PermissionMask.All; ;
247 req["next_owner_mask"] = (int)PermissionMask.All;
248  
249 CapsClient request = new CapsClient(url);
250 request.OnComplete += (client, result, error) =>
251 {
252 if (error != null || result == null || result.Type != OSDType.Map)
253 {
254 Logger.Log("Mesh upload request failure", Helpers.LogLevel.Error);
255 if (callback != null) callback(null);
256 return;
257 }
258 OSDMap res = (OSDMap)result;
259  
260 if (res["state"] != "upload")
261 {
262 Logger.Log("Mesh upload failure: " + res["message"], Helpers.LogLevel.Error);
263 if (callback != null) callback(null);
264 return;
265 }
266  
267 Logger.Log("Response from mesh upload prepare:\n" + OSDParser.SerializeLLSDNotationFormatted(result), Helpers.LogLevel.Debug);
268 if (callback != null) callback(result);
269 };
270  
271 request.BeginGetResponse(req, OSDFormat.Xml, 3 * 60 * 1000);
272  
273 }
274  
275 /// <summary>
276 /// Performas actual mesh and image upload
277 /// </summary>
278 /// <param name="uploader">Uri recieved in the upload prepare stage</param>
279 /// <param name="callback">Callback that will be invoke upon completion of the upload. Null is sent on request failure</param>
280 public void PerformUpload(Uri uploader, ModelUploadCallback callback)
281 {
282 CapsClient request = new CapsClient(uploader);
283 request.OnComplete += (client, result, error) =>
284 {
285 if (error != null || result == null || result.Type != OSDType.Map)
286 {
287 Logger.Log("Mesh upload request failure", Helpers.LogLevel.Error);
288 if (callback != null) callback(null);
289 return;
290 }
291 OSDMap res = (OSDMap)result;
292 Logger.Log("Response from mesh upload perform:\n" + OSDParser.SerializeLLSDNotationFormatted(result), Helpers.LogLevel.Debug);
293 if (callback != null) callback(res);
294 };
295  
296 request.BeginGetResponse(AssetResources(true), OSDFormat.Xml, 60 * 1000);
297 }
298  
299  
300 }
301 }