using System; using System.Collections.Generic; using System.Threading; using System.Reflection; using System.Xml; using OpenMetaverse; using OpenMetaverse.Packets; using OpenMetaverse.Utilities; namespace OpenMetaverse.TestClient { public class TestClient : GridClient { public UUID GroupID = UUID.Zero; public Dictionary GroupMembers; public Dictionary Appearances = new Dictionary(); public Dictionary Commands = new Dictionary(); public bool Running = true; public bool GroupCommands = false; public string MasterName = String.Empty; public UUID MasterKey = UUID.Zero; public bool AllowObjectMaster = false; public ClientManager ClientManager; public VoiceManager VoiceManager; // Shell-like inventory commands need to be aware of the 'current' inventory folder. public InventoryFolder CurrentDirectory = null; private System.Timers.Timer updateTimer; private UUID GroupMembersRequestID; public Dictionary GroupsCache = null; private ManualResetEvent GroupsEvent = new ManualResetEvent(false); /// /// /// public TestClient(ClientManager manager) { ClientManager = manager; updateTimer = new System.Timers.Timer(500); updateTimer.Elapsed += new System.Timers.ElapsedEventHandler(updateTimer_Elapsed); RegisterAllCommands(Assembly.GetExecutingAssembly()); Settings.LOG_LEVEL = Helpers.LogLevel.Debug; Settings.LOG_RESENDS = false; Settings.STORE_LAND_PATCHES = true; Settings.ALWAYS_DECODE_OBJECTS = true; Settings.ALWAYS_REQUEST_OBJECTS = true; Settings.SEND_AGENT_UPDATES = true; Settings.USE_ASSET_CACHE = true; Network.RegisterCallback(PacketType.AgentDataUpdate, AgentDataUpdateHandler); Network.LoginProgress += LoginHandler; Objects.AvatarUpdate += new EventHandler(Objects_AvatarUpdate); Objects.TerseObjectUpdate += new EventHandler(Objects_TerseObjectUpdate); Network.SimChanged += new EventHandler(Network_SimChanged); Self.IM += Self_IM; Groups.GroupMembersReply += GroupMembersHandler; Inventory.InventoryObjectOffered += Inventory_OnInventoryObjectReceived; Network.RegisterCallback(PacketType.AvatarAppearance, AvatarAppearanceHandler); Network.RegisterCallback(PacketType.AlertMessage, AlertMessageHandler); VoiceManager = new VoiceManager(this); updateTimer.Start(); } void Objects_TerseObjectUpdate(object sender, TerseObjectUpdateEventArgs e) { if (e.Prim.LocalID == Self.LocalID) { SetDefaultCamera(); } } void Objects_AvatarUpdate(object sender, AvatarUpdateEventArgs e) { if (e.Avatar.LocalID == Self.LocalID) { SetDefaultCamera(); } } void Network_SimChanged(object sender, SimChangedEventArgs e) { Self.Movement.SetFOVVerticalAngle(Utils.TWO_PI - 0.05f); } public void SetDefaultCamera() { // SetCamera 5m behind the avatar Self.Movement.Camera.LookAt( Self.SimPosition + new Vector3(-5, 0, 0) * Self.Movement.BodyRotation, Self.SimPosition ); } void Self_IM(object sender, InstantMessageEventArgs e) { bool groupIM = e.IM.GroupIM && GroupMembers != null && GroupMembers.ContainsKey(e.IM.FromAgentID) ? true : false; if (e.IM.FromAgentID == MasterKey || (GroupCommands && groupIM)) { // Received an IM from someone that is authenticated Console.WriteLine("<{0} ({1})> {2}: {3} (@{4}:{5})", e.IM.GroupIM ? "GroupIM" : "IM", e.IM.Dialog, e.IM.FromAgentName, e.IM.Message, e.IM.RegionID, e.IM.Position); if (e.IM.Dialog == InstantMessageDialog.RequestTeleport) { Console.WriteLine("Accepting teleport lure."); Self.TeleportLureRespond(e.IM.FromAgentID, e.IM.IMSessionID, true); } else if ( e.IM.Dialog == InstantMessageDialog.MessageFromAgent || e.IM.Dialog == InstantMessageDialog.MessageFromObject) { ClientManager.Instance.DoCommandAll(e.IM.Message, e.IM.FromAgentID); } } else { // Received an IM from someone that is not the bot's master, ignore Console.WriteLine("<{0} ({1})> {2} (not master): {3} (@{4}:{5})", e.IM.GroupIM ? "GroupIM" : "IM", e.IM.Dialog, e.IM.FromAgentName, e.IM.Message, e.IM.RegionID, e.IM.Position); return; } } /// /// Initialize everything that needs to be initialized once we're logged in. /// /// The status of the login /// Error message on failure, MOTD on success. public void LoginHandler(object sender, LoginProgressEventArgs e) { if (e.Status == LoginStatus.Success) { // Start in the inventory root folder. CurrentDirectory = Inventory.Store.RootFolder; } } public void RegisterAllCommands(Assembly assembly) { foreach (Type t in assembly.GetTypes()) { try { if (t.IsSubclassOf(typeof(Command))) { ConstructorInfo info = t.GetConstructor(new Type[] { typeof(TestClient) }); Command command = (Command)info.Invoke(new object[] { this }); RegisterCommand(command); } } catch (Exception e) { Console.WriteLine(e.ToString()); } } } public void RegisterCommand(Command command) { command.Client = this; if (!Commands.ContainsKey(command.Name.ToLower())) { Commands.Add(command.Name.ToLower(), command); } } public void ReloadGroupsCache() { Groups.CurrentGroups += Groups_CurrentGroups; Groups.RequestCurrentGroups(); GroupsEvent.WaitOne(10000, false); Groups.CurrentGroups -= Groups_CurrentGroups; GroupsEvent.Reset(); } void Groups_CurrentGroups(object sender, CurrentGroupsEventArgs e) { if (null == GroupsCache) GroupsCache = e.Groups; else lock (GroupsCache) { GroupsCache = e.Groups; } GroupsEvent.Set(); } public UUID GroupName2UUID(String groupName) { UUID tryUUID; if (UUID.TryParse(groupName,out tryUUID)) return tryUUID; if (null == GroupsCache) { ReloadGroupsCache(); if (null == GroupsCache) return UUID.Zero; } lock(GroupsCache) { if (GroupsCache.Count > 0) { foreach (Group currentGroup in GroupsCache.Values) if (currentGroup.Name.ToLower() == groupName.ToLower()) return currentGroup.ID; } } return UUID.Zero; } private void updateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { foreach (Command c in Commands.Values) if (c.Active) c.Think(); } private void AgentDataUpdateHandler(object sender, PacketReceivedEventArgs e) { AgentDataUpdatePacket p = (AgentDataUpdatePacket)e.Packet; if (p.AgentData.AgentID == e.Simulator.Client.Self.AgentID && p.AgentData.ActiveGroupID != UUID.Zero) { GroupID = p.AgentData.ActiveGroupID; GroupMembersRequestID = e.Simulator.Client.Groups.RequestGroupMembers(GroupID); } } private void GroupMembersHandler(object sender, GroupMembersReplyEventArgs e) { if (e.RequestID != GroupMembersRequestID) return; GroupMembers = e.Members; } private void AvatarAppearanceHandler(object sender, PacketReceivedEventArgs e) { Packet packet = e.Packet; AvatarAppearancePacket appearance = (AvatarAppearancePacket)packet; lock (Appearances) Appearances[appearance.Sender.ID] = appearance; } private void AlertMessageHandler(object sender, PacketReceivedEventArgs e) { Packet packet = e.Packet; AlertMessagePacket message = (AlertMessagePacket)packet; Logger.Log("[AlertMessage] " + Utils.BytesToString(message.AlertData.Message), Helpers.LogLevel.Info, this); } private void Inventory_OnInventoryObjectReceived(object sender, InventoryObjectOfferedEventArgs e) { if (MasterKey != UUID.Zero) { if (e.Offer.FromAgentID != MasterKey) return; } else if (GroupMembers != null && !GroupMembers.ContainsKey(e.Offer.FromAgentID)) { return; } e.Accept = true; return; } } }