/Aurora/BotManager/BotManager.cs
C# | 517 lines | 364 code | 55 blank | 98 comment | 61 complexity | 9472a1739edf3caf5932489d228591c8 MD5 | raw file
1/* 2 * Copyright (c) Contributors, http://aurora-sim.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 Aurora-Sim 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 28using Aurora.Framework; 29using Aurora.Framework.ClientInterfaces; 30using Aurora.Framework.ConsoleFramework; 31using Aurora.Framework.Modules; 32using Aurora.Framework.PresenceInfo; 33using Aurora.Framework.SceneInfo; 34using Aurora.Framework.SceneInfo.Entities; 35using Aurora.Framework.Services.ClassHelpers.Inventory; 36using Aurora.Framework.Utilities; 37using Nini.Config; 38using OpenMetaverse; 39using System; 40using System.Collections.Generic; 41using System.Threading; 42 43namespace Aurora.BotManager 44{ 45 public class BotManager : INonSharedRegionModule, IBotManager 46 { 47 private readonly Dictionary<UUID, Bot> m_bots = new Dictionary<UUID, Bot>(); 48 49 #region INonSharedRegionModule Members 50 51 public void Initialise(IConfigSource source) 52 { 53 } 54 55 public void AddRegion(IScene scene) 56 { 57 scene.RegisterModuleInterface<IBotManager>(this); 58 scene.RegisterModuleInterface(this); 59 } 60 61 public void RemoveRegion(IScene scene) 62 { 63 } 64 65 public void RegionLoaded(IScene scene) 66 { 67 } 68 69 public void Close() 70 { 71 m_bots.Clear(); 72 } 73 74 public Type ReplaceableInterface 75 { 76 get { return null; } 77 } 78 79 public string Name 80 { 81 get { return GetType().AssemblyQualifiedName; } 82 } 83 84 #endregion 85 86 #region IBotManager 87 88 /// <summary> 89 /// Creates a new bot inworld 90 /// </summary> 91 /// <param name="firstName"></param> 92 /// <param name="lastName"></param> 93 /// <param name="scene"></param> 94 /// <param name="cloneAppearanceFrom">UUID of the avatar whos appearance will be copied to give this bot an appearance</param> 95 /// <param name="creatorID"></param> 96 /// <param name="startPos"></param> 97 /// <returns>ID of the bot</returns> 98 public UUID CreateAvatar(string firstName, string lastName, IScene scene, UUID cloneAppearanceFrom, 99 UUID creatorID, Vector3 startPos) 100 { 101 AgentCircuitData m_aCircuitData = new AgentCircuitData 102 { 103 child = false, 104 circuitcode = (uint) Util.RandomClass.Next(), 105 Appearance = GetAppearance(cloneAppearanceFrom, scene) 106 }; 107 108 //Add the circuit data so they can login 109 110 //Sets up appearance 111 if (m_aCircuitData.Appearance == null) 112 { 113 m_aCircuitData.Appearance = new AvatarAppearance {Wearables = AvatarWearable.DefaultWearables}; 114 } 115 //Create the new bot data 116 BotClientAPI m_character = new BotClientAPI(scene, m_aCircuitData) 117 { 118 FirstName = firstName, 119 LastName = lastName 120 }; 121 122 m_aCircuitData.AgentID = m_character.AgentId; 123 m_aCircuitData.Appearance.Owner = m_character.AgentId; 124 List<AvatarAttachment> attachments = m_aCircuitData.Appearance.GetAttachments(); 125 126 m_aCircuitData.Appearance.ClearAttachments(); 127 foreach (AvatarAttachment t in attachments) 128 { 129 InventoryItemBase item = scene.InventoryService.GetItem(UUID.Zero, t.ItemID); 130 if (item != null) 131 { 132 item.ID = UUID.Random(); 133 item.Owner = m_character.AgentId; 134 item.Folder = UUID.Zero; 135 scene.InventoryService.AddItemAsync(item, null); 136 //Now fix the ItemID 137 m_aCircuitData.Appearance.SetAttachment(t.AttachPoint, item.ID, t.AssetID); 138 } 139 } 140 141 scene.AuthenticateHandler.AgentCircuits.Add(m_character.CircuitCode, m_aCircuitData); 142 //This adds them to the scene and sets them inworld 143 AddAndWaitUntilAgentIsAdded(scene, m_character); 144 145 IScenePresence SP = scene.GetScenePresence(m_character.AgentId); 146 if (SP == null) 147 return UUID.Zero; //Failed! 148 Bot bot = new Bot(); 149 bot.Initialize(SP, creatorID); 150 SP.MakeRootAgent(startPos, false, true); 151 //Move them 152 SP.Teleport(startPos); 153 154 foreach (var presence in scene.GetScenePresences()) 155 presence.SceneViewer.QueuePresenceForUpdate(SP, PrimUpdateFlags.ForcedFullUpdate); 156 IAttachmentsModule attModule = SP.Scene.RequestModuleInterface<IAttachmentsModule>(); 157 if (attModule != null) 158 foreach (AvatarAttachment att in attachments) 159 attModule.RezSingleAttachmentFromInventory(SP.ControllingClient, att.ItemID, att.AssetID, 0, true); 160 161 IAvatarAppearanceModule appearance = SP.RequestModuleInterface<IAvatarAppearanceModule>(); 162 appearance.InitialHasWearablesBeenSent = true; 163 164 //Save them in the bots list 165 m_bots.Add(m_character.AgentId, bot); 166 AddTagToBot(m_character.AgentId, "AllBots", bot.AvatarCreatorID); 167 168 MainConsole.Instance.Info("[RexBotManager]: Added bot " + m_character.Name + " to scene."); 169 //Return their UUID 170 return m_character.AgentId; 171 } 172 173 private static void AddAndWaitUntilAgentIsAdded(IScene scene, BotClientAPI m_character) 174 { 175 bool done = false; 176 scene.AddNewClient(m_character, delegate { done = true; }); 177 while (!done) 178 Thread.Sleep(3); 179 } 180 181 public void RemoveAvatar(UUID avatarID, IScene scene, UUID userAttempting) 182 { 183 IEntity sp = scene.GetScenePresence(avatarID); 184 if (sp == null) 185 { 186 sp = scene.GetSceneObjectPart(avatarID); 187 if (sp == null) 188 return; 189 sp = ((ISceneChildEntity) sp).ParentEntity; 190 } 191 if (!CheckPermission(sp, userAttempting)) 192 return; 193 194 RemoveAllTagsFromBot(avatarID, userAttempting); 195 if (!m_bots.Remove(avatarID)) 196 return; 197 //Kill the agent 198 IEntityTransferModule module = scene.RequestModuleInterface<IEntityTransferModule>(); 199 module.IncomingCloseAgent(scene, avatarID); 200 } 201 202 public void PauseMovement(UUID botID, UUID userAttempting) 203 { 204 Bot bot; 205 //Find the bot 206 if (m_bots.TryGetValue(botID, out bot)) 207 { 208 if (!CheckPermission(bot, userAttempting)) 209 return; 210 bot.PauseMovement(); 211 } 212 } 213 214 public void ResumeMovement(UUID botID, UUID userAttempting) 215 { 216 Bot bot; 217 //Find the bot 218 if (m_bots.TryGetValue(botID, out bot)) 219 { 220 if (!CheckPermission(bot, userAttempting)) 221 return; 222 bot.ResumeMovement(); 223 } 224 } 225 226 /// <summary> 227 /// Sets up where the bot should be walking 228 /// </summary> 229 /// <param name="botID">ID of the bot</param> 230 /// <param name="positions">List of positions the bot will move to</param> 231 /// <param name="mode">List of what the bot should be doing inbetween the positions</param> 232 /// <param name="flags"></param> 233 /// <param name="userAttempting"></param> 234 public void SetBotMap(UUID botID, List<Vector3> positions, List<TravelMode> mode, int flags, UUID userAttempting) 235 { 236 Bot bot; 237 //Find the bot 238 if (m_bots.TryGetValue(botID, out bot)) 239 { 240 if (!CheckPermission(bot, userAttempting)) 241 return; 242 bot.SetPath(positions, mode, flags); 243 } 244 } 245 246 /// <summary> 247 /// Speed up or slow down the bot 248 /// </summary> 249 /// <param name="botID"></param> 250 /// <param name="modifier"></param> 251 /// <param name="userAttempting"></param> 252 public void SetMovementSpeedMod(UUID botID, float modifier, UUID userAttempting) 253 { 254 Bot bot; 255 if (m_bots.TryGetValue(botID, out bot)) 256 { 257 if (!CheckPermission(bot, userAttempting)) 258 return; 259 bot.SetMovementSpeedMod(modifier); 260 } 261 } 262 263 public void SetBotShouldFly(UUID botID, bool shouldFly, UUID userAttempting) 264 { 265 Bot bot; 266 if (m_bots.TryGetValue(botID, out bot)) 267 { 268 if (!CheckPermission(bot, userAttempting)) 269 return; 270 if (shouldFly) 271 bot.DisableWalk(); 272 else 273 bot.EnableWalk(); 274 } 275 } 276 277 #region Tag/Remove bots 278 279 private readonly Dictionary<string, List<UUID>> m_botTags = new Dictionary<string, List<UUID>>(); 280 281 public void AddTagToBot(UUID Bot, string tag, UUID userAttempting) 282 { 283 Bot bot; 284 if (m_bots.TryGetValue(Bot, out bot)) 285 { 286 if (!CheckPermission(bot, userAttempting)) 287 return; 288 } 289 if (!m_botTags.ContainsKey(tag)) 290 m_botTags.Add(tag, new List<UUID>()); 291 m_botTags[tag].Add(Bot); 292 } 293 294 public List<UUID> GetBotsWithTag(string tag) 295 { 296 if (!m_botTags.ContainsKey(tag)) 297 return new List<UUID>(); 298 return new List<UUID>(m_botTags[tag]); 299 } 300 301 public void RemoveBots(string tag, UUID userAttempting) 302 { 303 List<UUID> bots = GetBotsWithTag(tag); 304 foreach (UUID bot in bots) 305 { 306 Bot Bot; 307 if (m_bots.TryGetValue(bot, out Bot)) 308 { 309 if (!CheckPermission(Bot, userAttempting)) 310 continue; 311 RemoveTagFromBot(bot, tag, userAttempting); 312 RemoveAvatar(bot, Bot.Controller.GetScene(), userAttempting); 313 } 314 } 315 } 316 317 public void RemoveTagFromBot(UUID Bot, string tag, UUID userAttempting) 318 { 319 Bot bot; 320 if (m_bots.TryGetValue(Bot, out bot)) 321 { 322 if (!CheckPermission(bot, userAttempting)) 323 return; 324 } 325 if (m_botTags.ContainsKey(tag)) 326 m_botTags[tag].Remove(Bot); 327 } 328 329 public void RemoveAllTagsFromBot(UUID Bot, UUID userAttempting) 330 { 331 Bot bot; 332 if (m_bots.TryGetValue(Bot, out bot)) 333 { 334 if (!CheckPermission(bot, userAttempting)) 335 return; 336 } 337 List<string> tagsToRemove = new List<string>(); 338 foreach (KeyValuePair<string, List<UUID>> kvp in m_botTags) 339 { 340 if (kvp.Value.Contains(Bot)) 341 tagsToRemove.Add(kvp.Key); 342 } 343 foreach (string tag in tagsToRemove) 344 m_botTags[tag].Remove(Bot); 345 } 346 347 #endregion 348 349 /// <summary> 350 /// Finds the given users appearance 351 /// </summary> 352 /// <param name="target"></param> 353 /// <param name="scene"></param> 354 /// <returns></returns> 355 private AvatarAppearance GetAppearance(UUID target, IScene scene) 356 { 357 IScenePresence sp = scene.GetScenePresence(target); 358 if (sp != null) 359 { 360 IAvatarAppearanceModule aa = sp.RequestModuleInterface<IAvatarAppearanceModule>(); 361 if (aa != null) 362 return new AvatarAppearance(aa.Appearance); 363 } 364 return scene.AvatarService.GetAppearance(target); 365 } 366 367 private bool CheckPermission(IEntity sp, UUID userAttempting) 368 { 369 foreach (Bot bot in m_bots.Values) 370 { 371 if (bot.Controller.UUID == sp.UUID) 372 return bot.AvatarCreatorID == userAttempting; 373 } 374 return false; 375 } 376 377 private bool CheckPermission(Bot bot, UUID userAttempting) 378 { 379 if (userAttempting == UUID.Zero) 380 return true; //Forced override 381 if (bot != null) 382 return bot.AvatarCreatorID == userAttempting; 383 return false; 384 } 385 386 #endregion 387 388 #region IBotManager 389 390 /// <summary> 391 /// Begins to follow the given user 392 /// </summary> 393 /// <param name="botID"></param> 394 /// <param name="avatarName"></param> 395 /// <param name="startFollowDistance"></param> 396 /// <param name="endFollowDistance"></param> 397 /// <param name="requireLOS"></param> 398 /// <param name="offsetFromAvatar"></param> 399 /// <param name="userAttempting"></param> 400 public void FollowAvatar(UUID botID, string avatarName, float startFollowDistance, float endFollowDistance, 401 bool requireLOS, Vector3 offsetFromAvatar, UUID userAttempting) 402 { 403 Bot bot; 404 if (m_bots.TryGetValue(botID, out bot)) 405 { 406 if (!CheckPermission(bot, userAttempting)) 407 return; 408 bot.FollowAvatar(avatarName, startFollowDistance, endFollowDistance, offsetFromAvatar, requireLOS); 409 } 410 } 411 412 /// <summary> 413 /// Stops following the given user 414 /// </summary> 415 /// <param name="botID"></param> 416 /// <param name="userAttempting"></param> 417 public void StopFollowAvatar(UUID botID, UUID userAttempting) 418 { 419 Bot bot; 420 if (m_bots.TryGetValue(botID, out bot)) 421 { 422 if (!CheckPermission(bot, userAttempting)) 423 return; 424 bot.StopFollowAvatar(); 425 } 426 } 427 428 /// <summary> 429 /// Sends a chat message to all clients 430 /// </summary> 431 /// <param name="botID"></param> 432 /// <param name="message"></param> 433 /// <param name="sayType"></param> 434 /// <param name="channel"></param> 435 /// <param name="userAttempting"></param> 436 public void SendChatMessage(UUID botID, string message, int sayType, int channel, UUID userAttempting) 437 { 438 Bot bot; 439 if (m_bots.TryGetValue(botID, out bot)) 440 { 441 if (!CheckPermission(bot, userAttempting)) 442 return; 443 bot.SendChatMessage(sayType, message, channel); 444 } 445 } 446 447 /// <summary> 448 /// Sends a chat message to all clients 449 /// </summary> 450 /// <param name="botID"></param> 451 /// <param name="toUser"></param> 452 /// <param name="message"></param> 453 /// <param name="userAttempting"></param> 454 public void SendIM(UUID botID, UUID toUser, string message, UUID userAttempting) 455 { 456 Bot bot; 457 if (m_bots.TryGetValue(botID, out bot)) 458 { 459 if (!CheckPermission(bot, userAttempting)) 460 return; 461 bot.SendInstantMessage(new GridInstantMessage 462 { 463 binaryBucket = new byte[0], 464 dialog = (byte) InstantMessageDialog.MessageFromAgent, 465 message = message, 466 fromAgentID = botID, 467 fromAgentName = bot.Controller.Name, 468 fromGroup = false, 469 imSessionID = UUID.Random(), 470 offline = 0, 471 ParentEstateID = 0, 472 RegionID = bot.Controller.GetScene().RegionInfo.RegionID, 473 timestamp = (uint) Util.UnixTimeSinceEpoch(), 474 toAgentID = toUser 475 }); 476 } 477 } 478 479 #endregion 480 481 #region Character Management 482 483 public void CreateCharacter(UUID primID, IScene scene) 484 { 485 RemoveCharacter(primID); 486 ISceneEntity entity = scene.GetSceneObjectPart(primID).ParentEntity; 487 Bot bot = new Bot(); 488 bot.Initialize(entity); 489 490 m_bots.Add(primID, bot); 491 AddTagToBot(primID, "AllBots", bot.AvatarCreatorID); 492 } 493 494 public IBotController GetCharacterManager(UUID primID) 495 { 496 foreach (Bot bot in m_bots.Values) 497 { 498 if (bot.Controller.UUID == primID) 499 return bot.Controller; 500 } 501 return null; 502 } 503 504 public void RemoveCharacter(UUID primID) 505 { 506 if (m_bots.ContainsKey(primID)) 507 { 508 Bot b = m_bots[primID]; 509 b.Close(true); 510 RemoveAllTagsFromBot(primID, UUID.Zero); 511 m_bots.Remove(primID); 512 } 513 } 514 515 #endregion 516 } 517}