OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
SimianAvatarServiceConnector.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
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  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections.Generic;
30 using System.Collections.Specialized;
31 // DEBUG ON
32 using System.Diagnostics;
33 // DEBUG OFF
34 using System.Reflection;
35 using log4net;
36 using Mono.Addins;
37 using Nini.Config;
38 using OpenSim.Framework;
39 using OpenSim.Region.Framework.Interfaces;
40 using OpenSim.Region.Framework.Scenes;
41 using OpenSim.Services.Interfaces;
42 using OpenMetaverse;
43 using OpenMetaverse.StructuredData;
44 
45 namespace OpenSim.Services.Connectors.SimianGrid
46 {
50  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianAvatarServiceConnector")]
52  {
53  private static readonly ILog m_log =
54  LogManager.GetLogger(
55  MethodBase.GetCurrentMethod().DeclaringType);
56 // private static string ZeroID = UUID.Zero.ToString();
57 
58  private string m_serverUrl = String.Empty;
59  private bool m_Enabled = false;
60 
61  #region ISharedRegionModule
62 
63  public Type ReplaceableInterface { get { return null; } }
64  public void RegionLoaded(Scene scene) { }
65  public void PostInitialise() { }
66  public void Close() { }
67 
69  public string Name { get { return "SimianAvatarServiceConnector"; } }
70  public void AddRegion(Scene scene) { if (m_Enabled) { scene.RegisterModuleInterface<IAvatarService>(this); } }
71  public void RemoveRegion(Scene scene) { if (m_Enabled) { scene.UnregisterModuleInterface<IAvatarService>(this); } }
72 
73  #endregion ISharedRegionModule
74 
75  public SimianAvatarServiceConnector(IConfigSource source)
76  {
77  CommonInit(source);
78  }
79 
80  public void Initialise(IConfigSource source)
81  {
82  IConfig moduleConfig = source.Configs["Modules"];
83  if (moduleConfig != null)
84  {
85  string name = moduleConfig.GetString("AvatarServices", "");
86  if (name == Name)
87  CommonInit(source);
88  }
89  }
90 
91  private void CommonInit(IConfigSource source)
92  {
93  IConfig gridConfig = source.Configs["AvatarService"];
94  if (gridConfig != null)
95  {
96  string serviceUrl = gridConfig.GetString("AvatarServerURI");
97  if (!String.IsNullOrEmpty(serviceUrl))
98  {
99  if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("="))
100  serviceUrl = serviceUrl + '/';
101  m_serverUrl = serviceUrl;
102  m_Enabled = true;
103  }
104  }
105 
106  if (String.IsNullOrEmpty(m_serverUrl))
107  m_log.Info("[SIMIAN AVATAR CONNECTOR]: No AvatarServerURI specified, disabling connector");
108  }
109 
110  #region IAvatarService
111 
112  // <summary>
113  // Retrieves the LLPackedAppearance field from user data and unpacks
114  // it into an AvatarAppearance structure
115  // </summary>
116  // <param name="userID"></param>
117  public AvatarAppearance GetAppearance(UUID userID)
118  {
119  NameValueCollection requestArgs = new NameValueCollection
120  {
121  { "RequestMethod", "GetUser" },
122  { "UserID", userID.ToString() }
123  };
124 
125  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
126  if (response["Success"].AsBoolean())
127  {
128  OSDMap map = null;
129  try { map = OSDParser.DeserializeJson(response["LLPackedAppearance"].AsString()) as OSDMap; }
130  catch { }
131 
132  if (map != null)
133  {
134  AvatarAppearance appearance = new AvatarAppearance(map);
135 // DEBUG ON
136  m_log.WarnFormat("[SIMIAN AVATAR CONNECTOR] retrieved appearance for {0}:\n{1}",userID,appearance.ToString());
137 // DEBUG OFF
138  return appearance;
139  }
140 
141  m_log.WarnFormat("[SIMIAN AVATAR CONNECTOR]: Failed to decode appearance for {0}",userID);
142  return null;
143  }
144 
145  m_log.WarnFormat("[SIMIAN AVATAR CONNECTOR]: Failed to get appearance for {0}: {1}",
146  userID,response["Message"].AsString());
147  return null;
148  }
149 
150  // <summary>
151  // </summary>
152  // <param name=""></param>
153  public bool SetAppearance(UUID userID, AvatarAppearance appearance)
154  {
156  OSDMap map = appearance.Pack(ctx);
157  if (map == null)
158  {
159  m_log.WarnFormat("[SIMIAN AVATAR CONNECTOR]: Failed to encode appearance for {0}",userID);
160  return false;
161  }
162 
163  // m_log.DebugFormat("[SIMIAN AVATAR CONNECTOR] save appearance for {0}",userID);
164 
165  NameValueCollection requestArgs = new NameValueCollection
166  {
167  { "RequestMethod", "AddUserData" },
168  { "UserID", userID.ToString() },
169  { "LLPackedAppearance", OSDParser.SerializeJsonString(map) }
170  };
171 
172  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
173  bool success = response["Success"].AsBoolean();
174 
175  if (! success)
176  m_log.WarnFormat("[SIMIAN AVATAR CONNECTOR]: Failed to save appearance for {0}: {1}",
177  userID,response["Message"].AsString());
178 
179  return success;
180  }
181 
182  // <summary>
183  // </summary>
184  // <param name=""></param>
185  public AvatarData GetAvatar(UUID userID)
186  {
187  NameValueCollection requestArgs = new NameValueCollection
188  {
189  { "RequestMethod", "GetUser" },
190  { "UserID", userID.ToString() }
191  };
192 
193  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
194  if (response["Success"].AsBoolean())
195  {
196  OSDMap map = null;
197  try { map = OSDParser.DeserializeJson(response["LLAppearance"].AsString()) as OSDMap; }
198  catch { }
199 
200  if (map != null)
201  {
202  AvatarWearable[] wearables = new AvatarWearable[13];
203  wearables[0] = new AvatarWearable(map["ShapeItem"].AsUUID(), map["ShapeAsset"].AsUUID());
204  wearables[1] = new AvatarWearable(map["SkinItem"].AsUUID(), map["SkinAsset"].AsUUID());
205  wearables[2] = new AvatarWearable(map["HairItem"].AsUUID(), map["HairAsset"].AsUUID());
206  wearables[3] = new AvatarWearable(map["EyesItem"].AsUUID(), map["EyesAsset"].AsUUID());
207  wearables[4] = new AvatarWearable(map["ShirtItem"].AsUUID(), map["ShirtAsset"].AsUUID());
208  wearables[5] = new AvatarWearable(map["PantsItem"].AsUUID(), map["PantsAsset"].AsUUID());
209  wearables[6] = new AvatarWearable(map["ShoesItem"].AsUUID(), map["ShoesAsset"].AsUUID());
210  wearables[7] = new AvatarWearable(map["SocksItem"].AsUUID(), map["SocksAsset"].AsUUID());
211  wearables[8] = new AvatarWearable(map["JacketItem"].AsUUID(), map["JacketAsset"].AsUUID());
212  wearables[9] = new AvatarWearable(map["GlovesItem"].AsUUID(), map["GlovesAsset"].AsUUID());
213  wearables[10] = new AvatarWearable(map["UndershirtItem"].AsUUID(), map["UndershirtAsset"].AsUUID());
214  wearables[11] = new AvatarWearable(map["UnderpantsItem"].AsUUID(), map["UnderpantsAsset"].AsUUID());
215  wearables[12] = new AvatarWearable(map["SkirtItem"].AsUUID(), map["SkirtAsset"].AsUUID());
216 
217  AvatarAppearance appearance = new AvatarAppearance();
218  appearance.Wearables = wearables;
219  appearance.AvatarHeight = (float)map["Height"].AsReal();
220 
221  AvatarData avatar = new AvatarData(appearance);
222 
223  // Get attachments
224  map = null;
225  try { map = OSDParser.DeserializeJson(response["LLAttachments"].AsString()) as OSDMap; }
226  catch { }
227 
228  if (map != null)
229  {
230  foreach (KeyValuePair<string, OSD> kvp in map)
231  avatar.Data[kvp.Key] = kvp.Value.AsString();
232  }
233 
234  return avatar;
235  }
236  else
237  {
238  m_log.Warn("[SIMIAN AVATAR CONNECTOR]: Failed to get user appearance for " + userID +
239  ", LLAppearance is missing or invalid");
240  return null;
241  }
242  }
243  else
244  {
245  m_log.Warn("[SIMIAN AVATAR CONNECTOR]: Failed to get user appearance for " + userID + ": " +
246  response["Message"].AsString());
247  }
248 
249  return null;
250  }
251 
252  // <summary>
253  // </summary>
254  // <param name=""></param>
255  public bool SetAvatar(UUID userID, AvatarData avatar)
256  {
257  m_log.Debug("[SIMIAN AVATAR CONNECTOR]: SetAvatar called for " + userID);
258 
259  if (avatar.AvatarType == 1) // LLAvatar
260  {
261  AvatarAppearance appearance = avatar.ToAvatarAppearance();
262 
263  OSDMap map = new OSDMap();
264 
265  map["Height"] = OSD.FromReal(appearance.AvatarHeight);
266 
267  map["BodyItem"] = appearance.Wearables[AvatarWearable.BODY][0].ItemID.ToString();
268  map["EyesItem"] = appearance.Wearables[AvatarWearable.EYES][0].ItemID.ToString();
269  map["GlovesItem"] = appearance.Wearables[AvatarWearable.GLOVES][0].ItemID.ToString();
270  map["HairItem"] = appearance.Wearables[AvatarWearable.HAIR][0].ItemID.ToString();
271  map["JacketItem"] = appearance.Wearables[AvatarWearable.JACKET][0].ItemID.ToString();
272  map["PantsItem"] = appearance.Wearables[AvatarWearable.PANTS][0].ItemID.ToString();
273  map["ShirtItem"] = appearance.Wearables[AvatarWearable.SHIRT][0].ItemID.ToString();
274  map["ShoesItem"] = appearance.Wearables[AvatarWearable.SHOES][0].ItemID.ToString();
275  map["SkinItem"] = appearance.Wearables[AvatarWearable.SKIN][0].ItemID.ToString();
276  map["SkirtItem"] = appearance.Wearables[AvatarWearable.SKIRT][0].ItemID.ToString();
277  map["SocksItem"] = appearance.Wearables[AvatarWearable.SOCKS][0].ItemID.ToString();
278  map["UnderPantsItem"] = appearance.Wearables[AvatarWearable.UNDERPANTS][0].ItemID.ToString();
279  map["UnderShirtItem"] = appearance.Wearables[AvatarWearable.UNDERSHIRT][0].ItemID.ToString();
280  map["BodyAsset"] = appearance.Wearables[AvatarWearable.BODY][0].AssetID.ToString();
281  map["EyesAsset"] = appearance.Wearables[AvatarWearable.EYES][0].AssetID.ToString();
282  map["GlovesAsset"] = appearance.Wearables[AvatarWearable.GLOVES][0].AssetID.ToString();
283  map["HairAsset"] = appearance.Wearables[AvatarWearable.HAIR][0].AssetID.ToString();
284  map["JacketAsset"] = appearance.Wearables[AvatarWearable.JACKET][0].AssetID.ToString();
285  map["PantsAsset"] = appearance.Wearables[AvatarWearable.PANTS][0].AssetID.ToString();
286  map["ShirtAsset"] = appearance.Wearables[AvatarWearable.SHIRT][0].AssetID.ToString();
287  map["ShoesAsset"] = appearance.Wearables[AvatarWearable.SHOES][0].AssetID.ToString();
288  map["SkinAsset"] = appearance.Wearables[AvatarWearable.SKIN][0].AssetID.ToString();
289  map["SkirtAsset"] = appearance.Wearables[AvatarWearable.SKIRT][0].AssetID.ToString();
290  map["SocksAsset"] = appearance.Wearables[AvatarWearable.SOCKS][0].AssetID.ToString();
291  map["UnderPantsAsset"] = appearance.Wearables[AvatarWearable.UNDERPANTS][0].AssetID.ToString();
292  map["UnderShirtAsset"] = appearance.Wearables[AvatarWearable.UNDERSHIRT][0].AssetID.ToString();
293 
294 
295  OSDMap items = new OSDMap();
296  foreach (KeyValuePair<string, string> kvp in avatar.Data)
297  {
298  if (kvp.Key.StartsWith("_ap_"))
299  items.Add(kvp.Key, OSD.FromString(kvp.Value));
300  }
301 
302  NameValueCollection requestArgs = new NameValueCollection
303  {
304  { "RequestMethod", "AddUserData" },
305  { "UserID", userID.ToString() },
306  { "LLAppearance", OSDParser.SerializeJsonString(map) },
307  { "LLAttachments", OSDParser.SerializeJsonString(items) }
308  };
309 
310  OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs);
311  bool success = response["Success"].AsBoolean();
312 
313  if (!success)
314  m_log.Warn("[SIMIAN AVATAR CONNECTOR]: Failed saving appearance for " + userID + ": " + response["Message"].AsString());
315 
316  return success;
317  }
318  else
319  {
320  m_log.Error("[SIMIAN AVATAR CONNECTOR]: Can't save appearance for " + userID + ". Unhandled avatar type " + avatar.AvatarType);
321  return false;
322  }
323  }
324 
325  public bool ResetAvatar(UUID userID)
326  {
327  m_log.Error("[SIMIAN AVATAR CONNECTOR]: ResetAvatar called for " + userID + ", implement this");
328  return false;
329  }
330 
331  public bool SetItems(UUID userID, string[] names, string[] values)
332  {
333  m_log.Error("[SIMIAN AVATAR CONNECTOR]: SetItems called for " + userID + " with " + names.Length + " names and " + values.Length + " values, implement this");
334  return false;
335  }
336 
337  public bool RemoveItems(UUID userID, string[] names)
338  {
339  m_log.Error("[SIMIAN AVATAR CONNECTOR]: RemoveItems called for " + userID + " with " + names.Length + " names, implement this");
340  return false;
341  }
342 
343  #endregion IAvatarService
344  }
345 }
Connects avatar appearance data to the SimianGrid backend
bool SetAppearance(UUID userID, AvatarAppearance appearance)
Called by everyone who can change the avatar data (so, regions)
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
bool SetAvatar(UUID userID, AvatarData avatar)
Called by everyone who can change the avatar data (so, regions)
Contains the Avatar's Appearance and methods to manipulate the appearance.
OpenMetaverse.StructuredData.OSDMap OSDMap
AvatarAppearance GetAppearance(UUID userID)
Called by the login service
OpenMetaverse.StructuredData.OSD OSD
bool SetItems(UUID userID, string[] names, string[] values)
These methods raison d'etre: No need to send the entire avatar data (SetAvatar) for changing attachme...
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
Each region/client that uses avatars will have a data structure of this type representing the avatars...
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
void PostInitialise()
This is called exactly once after all the shared region-modules have been instanciated and IRegionMod...
Dictionary< string, string > Data