This allows one to log the packets received by a particular bot that are not duplicates of already received packets. Similar to the OpenSimulator command at the same name but currently any positive level logs all received packets. No facility yet for logging outgoing packets. For debug purposes.
749 lines
28 KiB
C#
749 lines
28 KiB
C#
/*
|
|
* Copyright (c) Contributors, http://opensimulator.org/
|
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of the OpenSimulator Project nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Threading;
|
|
using System.Timers;
|
|
using log4net;
|
|
using OpenMetaverse;
|
|
using OpenMetaverse.Assets;
|
|
using OpenMetaverse.Packets;
|
|
using Nini.Config;
|
|
using OpenSim.Framework;
|
|
using OpenSim.Framework.Console;
|
|
using pCampBot.Interfaces;
|
|
using Timer = System.Timers.Timer;
|
|
using PermissionMask = OpenSim.Framework.PermissionMask;
|
|
|
|
namespace pCampBot
|
|
{
|
|
public enum ConnectionState
|
|
{
|
|
Disconnected,
|
|
Connecting,
|
|
Connected,
|
|
Disconnecting
|
|
}
|
|
|
|
public class Bot
|
|
{
|
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
|
|
|
public int PacketDebugLevel
|
|
{
|
|
get { return m_packetDebugLevel; }
|
|
set
|
|
{
|
|
if (value == m_packetDebugLevel)
|
|
return;
|
|
|
|
m_packetDebugLevel = value;
|
|
|
|
if (Client != null)
|
|
{
|
|
if (m_packetDebugLevel <= 0)
|
|
Client.Network.UnregisterCallback(PacketType.Default, PacketReceivedDebugHandler);
|
|
else
|
|
Client.Network.RegisterCallback(PacketType.Default, PacketReceivedDebugHandler, false);
|
|
}
|
|
}
|
|
}
|
|
private int m_packetDebugLevel;
|
|
|
|
public delegate void AnEvent(Bot callbot, EventType someevent); // event delegate for bot events
|
|
|
|
/// <summary>
|
|
/// Controls whether bots request textures for the object information they receive
|
|
/// </summary>
|
|
public bool RequestObjectTextures { get; set; }
|
|
|
|
/// <summary>
|
|
/// Bot manager.
|
|
/// </summary>
|
|
public BotManager Manager { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Behaviours implemented by this bot.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Indexed by abbreviated name. There can only be one instance of a particular behaviour.
|
|
/// Lock this structure before manipulating it.
|
|
/// </remarks>
|
|
public Dictionary<string, IBehaviour> Behaviours { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Objects that the bot has discovered.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Returns a list copy. Inserting new objects manually will have no effect.
|
|
/// </remarks>
|
|
public Dictionary<UUID, Primitive> Objects
|
|
{
|
|
get
|
|
{
|
|
lock (m_objects)
|
|
return new Dictionary<UUID, Primitive>(m_objects);
|
|
}
|
|
}
|
|
private Dictionary<UUID, Primitive> m_objects = new Dictionary<UUID, Primitive>();
|
|
|
|
/// <summary>
|
|
/// Is this bot connected to the grid?
|
|
/// </summary>
|
|
public ConnectionState ConnectionState { get; private set; }
|
|
|
|
public List<Simulator> Simulators
|
|
{
|
|
get
|
|
{
|
|
lock (Client.Network.Simulators)
|
|
return new List<Simulator>(Client.Network.Simulators);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The number of connections that this bot has to different simulators.
|
|
/// </summary>
|
|
/// <value>Includes both root and child connections.</value>
|
|
public int SimulatorsCount
|
|
{
|
|
get
|
|
{
|
|
lock (Client.Network.Simulators)
|
|
return Client.Network.Simulators.Count;
|
|
}
|
|
}
|
|
|
|
public string FirstName { get; private set; }
|
|
public string LastName { get; private set; }
|
|
public string Name { get; private set; }
|
|
public string Password { get; private set; }
|
|
public string LoginUri { get; private set; }
|
|
public string StartLocation { get; private set; }
|
|
|
|
public string saveDir;
|
|
public string wear;
|
|
|
|
public event AnEvent OnConnected;
|
|
public event AnEvent OnDisconnected;
|
|
|
|
/// <summary>
|
|
/// Keep a track of the continuously acting thread so that we can abort it.
|
|
/// </summary>
|
|
private Thread m_actionThread;
|
|
|
|
protected List<uint> objectIDs = new List<uint>();
|
|
|
|
/// <summary>
|
|
/// Random number generator.
|
|
/// </summary>
|
|
public Random Random { get; private set; }
|
|
|
|
/// <summary>
|
|
/// New instance of a SecondLife client
|
|
/// </summary>
|
|
public GridClient Client { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="bm"></param>
|
|
/// <param name="behaviours">Behaviours for this bot to perform</param>
|
|
/// <param name="firstName"></param>
|
|
/// <param name="lastName"></param>
|
|
/// <param name="password"></param>
|
|
/// <param name="loginUri"></param>
|
|
/// <param name="behaviours"></param>
|
|
public Bot(
|
|
BotManager bm, List<IBehaviour> behaviours,
|
|
string firstName, string lastName, string password, string startLocation, string loginUri)
|
|
{
|
|
ConnectionState = ConnectionState.Disconnected;
|
|
|
|
Random = new Random(bm.Rng.Next());
|
|
FirstName = firstName;
|
|
LastName = lastName;
|
|
Name = string.Format("{0} {1}", FirstName, LastName);
|
|
Password = password;
|
|
LoginUri = loginUri;
|
|
StartLocation = startLocation;
|
|
|
|
Manager = bm;
|
|
|
|
Behaviours = new Dictionary<string, IBehaviour>();
|
|
foreach (IBehaviour behaviour in behaviours)
|
|
AddBehaviour(behaviour);
|
|
|
|
// Only calling for use as a template.
|
|
CreateLibOmvClient();
|
|
}
|
|
|
|
public bool TryGetBehaviour(string abbreviatedName, out IBehaviour behaviour)
|
|
{
|
|
lock (Behaviours)
|
|
return Behaviours.TryGetValue(abbreviatedName, out behaviour);
|
|
}
|
|
|
|
public bool AddBehaviour(IBehaviour behaviour)
|
|
{
|
|
Dictionary<string, IBehaviour> updatedBehaviours = new Dictionary<string, IBehaviour>(Behaviours);
|
|
|
|
if (!updatedBehaviours.ContainsKey(behaviour.AbbreviatedName))
|
|
{
|
|
behaviour.Initialize(this);
|
|
updatedBehaviours.Add(behaviour.AbbreviatedName, behaviour);
|
|
Behaviours = updatedBehaviours;
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public bool RemoveBehaviour(string abbreviatedName)
|
|
{
|
|
if (Behaviours.Count <= 0)
|
|
return false;
|
|
|
|
Dictionary<string, IBehaviour> updatedBehaviours = new Dictionary<string, IBehaviour>(Behaviours);
|
|
IBehaviour behaviour;
|
|
|
|
if (!updatedBehaviours.TryGetValue(abbreviatedName, out behaviour))
|
|
return false;
|
|
|
|
updatedBehaviours.Remove(abbreviatedName);
|
|
Behaviours = updatedBehaviours;
|
|
|
|
behaviour.Close();
|
|
|
|
return true;
|
|
}
|
|
|
|
private void CreateLibOmvClient()
|
|
{
|
|
GridClient newClient = new GridClient();
|
|
|
|
if (Client != null)
|
|
{
|
|
// Remove any registered debug handlers
|
|
Client.Network.UnregisterCallback(PacketType.Default, PacketReceivedDebugHandler);
|
|
|
|
newClient.Settings.LOGIN_SERVER = Client.Settings.LOGIN_SERVER;
|
|
newClient.Settings.ALWAYS_DECODE_OBJECTS = Client.Settings.ALWAYS_DECODE_OBJECTS;
|
|
newClient.Settings.AVATAR_TRACKING = Client.Settings.AVATAR_TRACKING;
|
|
newClient.Settings.OBJECT_TRACKING = Client.Settings.OBJECT_TRACKING;
|
|
newClient.Settings.SEND_AGENT_THROTTLE = Client.Settings.SEND_AGENT_THROTTLE;
|
|
newClient.Settings.SEND_AGENT_UPDATES = Client.Settings.SEND_AGENT_UPDATES;
|
|
newClient.Settings.SEND_PINGS = Client.Settings.SEND_PINGS;
|
|
newClient.Settings.STORE_LAND_PATCHES = Client.Settings.STORE_LAND_PATCHES;
|
|
newClient.Settings.USE_ASSET_CACHE = Client.Settings.USE_ASSET_CACHE;
|
|
newClient.Settings.MULTIPLE_SIMS = Client.Settings.MULTIPLE_SIMS;
|
|
newClient.Throttle.Asset = Client.Throttle.Asset;
|
|
newClient.Throttle.Land = Client.Throttle.Land;
|
|
newClient.Throttle.Task = Client.Throttle.Task;
|
|
newClient.Throttle.Texture = Client.Throttle.Texture;
|
|
newClient.Throttle.Wind = Client.Throttle.Wind;
|
|
newClient.Throttle.Total = Client.Throttle.Total;
|
|
}
|
|
else
|
|
{
|
|
newClient.Settings.LOGIN_SERVER = LoginUri;
|
|
newClient.Settings.ALWAYS_DECODE_OBJECTS = false;
|
|
newClient.Settings.AVATAR_TRACKING = false;
|
|
newClient.Settings.OBJECT_TRACKING = false;
|
|
newClient.Settings.SEND_AGENT_THROTTLE = true;
|
|
newClient.Settings.SEND_PINGS = true;
|
|
newClient.Settings.STORE_LAND_PATCHES = false;
|
|
newClient.Settings.USE_ASSET_CACHE = false;
|
|
newClient.Settings.MULTIPLE_SIMS = true;
|
|
newClient.Throttle.Asset = 100000;
|
|
newClient.Throttle.Land = 100000;
|
|
newClient.Throttle.Task = 100000;
|
|
newClient.Throttle.Texture = 100000;
|
|
newClient.Throttle.Wind = 100000;
|
|
newClient.Throttle.Total = 400000;
|
|
}
|
|
|
|
newClient.Network.LoginProgress += Network_LoginProgress;
|
|
newClient.Network.SimConnected += Network_SimConnected;
|
|
newClient.Network.SimDisconnected += Network_SimDisconnected;
|
|
newClient.Network.Disconnected += Network_OnDisconnected;
|
|
newClient.Objects.ObjectUpdate += Objects_NewPrim;
|
|
|
|
if (m_packetDebugLevel > 0)
|
|
newClient.Network.RegisterCallback(PacketType.Default, PacketReceivedDebugHandler);
|
|
|
|
Client = newClient;
|
|
}
|
|
|
|
//We do our actions here. This is where one would
|
|
//add additional steps and/or things the bot should do
|
|
private void Action()
|
|
{
|
|
while (ConnectionState == ConnectionState.Connected)
|
|
{
|
|
foreach (IBehaviour behaviour in Behaviours.Values)
|
|
{
|
|
// Thread.Sleep(Random.Next(3000, 10000));
|
|
|
|
// m_log.DebugFormat("[pCAMPBOT]: For {0} performing action {1}", Name, b.GetType());
|
|
behaviour.Action();
|
|
}
|
|
}
|
|
|
|
foreach (IBehaviour b in Behaviours.Values)
|
|
b.Close();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tells LibSecondLife to logout and disconnect. Raises the disconnect events once it finishes.
|
|
/// </summary>
|
|
public void Disconnect()
|
|
{
|
|
ConnectionState = ConnectionState.Disconnecting;
|
|
|
|
foreach (IBehaviour behaviour in Behaviours.Values)
|
|
behaviour.Close();
|
|
|
|
Client.Network.Logout();
|
|
}
|
|
|
|
public void Connect()
|
|
{
|
|
Thread connectThread = new Thread(ConnectInternal);
|
|
connectThread.Name = Name;
|
|
connectThread.IsBackground = true;
|
|
|
|
connectThread.Start();
|
|
}
|
|
|
|
/// <summary>
|
|
/// This is the bot startup loop.
|
|
/// </summary>
|
|
private void ConnectInternal()
|
|
{
|
|
ConnectionState = ConnectionState.Connecting;
|
|
|
|
// Current create a new client on each connect. libomv doesn't seem to process new sim
|
|
// information (e.g. EstablishAgentCommunication events) if connecting after a disceonnect with the same
|
|
// client
|
|
CreateLibOmvClient();
|
|
|
|
if (Client.Network.Login(FirstName, LastName, Password, "pCampBot", StartLocation, "pCampBot"))
|
|
{
|
|
ConnectionState = ConnectionState.Connected;
|
|
|
|
Thread.Sleep(Random.Next(1000, 10000));
|
|
m_actionThread = new Thread(Action);
|
|
m_actionThread.Start();
|
|
|
|
// OnConnected(this, EventType.CONNECTED);
|
|
if (wear == "save")
|
|
{
|
|
SaveDefaultAppearance();
|
|
}
|
|
else if (wear != "no")
|
|
{
|
|
MakeDefaultAppearance(wear);
|
|
}
|
|
|
|
// Extract nearby region information.
|
|
Client.Grid.GridRegion += Manager.Grid_GridRegion;
|
|
uint xUint, yUint;
|
|
Utils.LongToUInts(Client.Network.CurrentSim.Handle, out xUint, out yUint);
|
|
ushort minX, minY, maxX, maxY;
|
|
minX = (ushort)Math.Min(0, xUint - 5);
|
|
minY = (ushort)Math.Min(0, yUint - 5);
|
|
maxX = (ushort)(xUint + 5);
|
|
maxY = (ushort)(yUint + 5);
|
|
Client.Grid.RequestMapBlocks(GridLayerType.Terrain, minX, minY, maxX, maxY, false);
|
|
}
|
|
else
|
|
{
|
|
ConnectionState = ConnectionState.Disconnected;
|
|
|
|
m_log.ErrorFormat(
|
|
"{0} {1} cannot login: {2}", FirstName, LastName, Client.Network.LoginMessage);
|
|
|
|
if (OnDisconnected != null)
|
|
{
|
|
OnDisconnected(this, EventType.DISCONNECTED);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sit this bot on the ground.
|
|
/// </summary>
|
|
public void SitOnGround()
|
|
{
|
|
if (ConnectionState == ConnectionState.Connected)
|
|
Client.Self.SitOnGround();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stand this bot
|
|
/// </summary>
|
|
public void Stand()
|
|
{
|
|
if (ConnectionState == ConnectionState.Connected)
|
|
{
|
|
// Unlike sit on ground, here libomv checks whether we have SEND_AGENT_UPDATES enabled.
|
|
bool prevUpdatesSetting = Client.Settings.SEND_AGENT_UPDATES;
|
|
Client.Settings.SEND_AGENT_UPDATES = true;
|
|
Client.Self.Stand();
|
|
Client.Settings.SEND_AGENT_UPDATES = prevUpdatesSetting;
|
|
}
|
|
}
|
|
|
|
public void SaveDefaultAppearance()
|
|
{
|
|
saveDir = "MyAppearance/" + FirstName + "_" + LastName;
|
|
if (!Directory.Exists(saveDir))
|
|
{
|
|
Directory.CreateDirectory(saveDir);
|
|
}
|
|
|
|
Array wtypes = Enum.GetValues(typeof(WearableType));
|
|
foreach (WearableType wtype in wtypes)
|
|
{
|
|
UUID wearable = Client.Appearance.GetWearableAsset(wtype);
|
|
if (wearable != UUID.Zero)
|
|
{
|
|
Client.Assets.RequestAsset(wearable, AssetType.Clothing, false, Asset_ReceivedCallback);
|
|
Client.Assets.RequestAsset(wearable, AssetType.Bodypart, false, Asset_ReceivedCallback);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SaveAsset(AssetWearable asset)
|
|
{
|
|
if (asset != null)
|
|
{
|
|
try
|
|
{
|
|
if (asset.Decode())
|
|
{
|
|
File.WriteAllBytes(Path.Combine(saveDir, String.Format("{1}.{0}",
|
|
asset.AssetType.ToString().ToLower(),
|
|
asset.WearableType)), asset.AssetData);
|
|
}
|
|
else
|
|
{
|
|
m_log.WarnFormat("Failed to decode {0} asset {1}", asset.AssetType, asset.AssetID);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
m_log.ErrorFormat("Exception: {0}{1}", e.Message, e.StackTrace);
|
|
}
|
|
}
|
|
}
|
|
|
|
public WearableType GetWearableType(string path)
|
|
{
|
|
string type = ((((path.Split('/'))[2]).Split('.'))[0]).Trim();
|
|
switch (type)
|
|
{
|
|
case "Eyes":
|
|
return WearableType.Eyes;
|
|
case "Hair":
|
|
return WearableType.Hair;
|
|
case "Pants":
|
|
return WearableType.Pants;
|
|
case "Shape":
|
|
return WearableType.Shape;
|
|
case "Shirt":
|
|
return WearableType.Shirt;
|
|
case "Skin":
|
|
return WearableType.Skin;
|
|
default:
|
|
return WearableType.Shape;
|
|
}
|
|
}
|
|
|
|
public void MakeDefaultAppearance(string wear)
|
|
{
|
|
try
|
|
{
|
|
if (wear == "yes")
|
|
{
|
|
//TODO: Implement random outfit picking
|
|
m_log.DebugFormat("Picks a random outfit. Not yet implemented.");
|
|
}
|
|
else if (wear != "save")
|
|
saveDir = "MyAppearance/" + wear;
|
|
saveDir = saveDir + "/";
|
|
|
|
string[] clothing = Directory.GetFiles(saveDir, "*.clothing", SearchOption.TopDirectoryOnly);
|
|
string[] bodyparts = Directory.GetFiles(saveDir, "*.bodypart", SearchOption.TopDirectoryOnly);
|
|
InventoryFolder clothfolder = FindClothingFolder();
|
|
UUID transid = UUID.Random();
|
|
List<InventoryBase> listwearables = new List<InventoryBase>();
|
|
|
|
for (int i = 0; i < clothing.Length; i++)
|
|
{
|
|
UUID assetID = UUID.Random();
|
|
AssetClothing asset = new AssetClothing(assetID, File.ReadAllBytes(clothing[i]));
|
|
asset.Decode();
|
|
asset.Owner = Client.Self.AgentID;
|
|
asset.WearableType = GetWearableType(clothing[i]);
|
|
asset.Encode();
|
|
transid = Client.Assets.RequestUpload(asset,true);
|
|
Client.Inventory.RequestCreateItem(clothfolder.UUID, "MyClothing" + i.ToString(), "MyClothing", AssetType.Clothing,
|
|
transid, InventoryType.Wearable, asset.WearableType, (OpenMetaverse.PermissionMask)PermissionMask.All, delegate(bool success, InventoryItem item)
|
|
{
|
|
if (success)
|
|
{
|
|
listwearables.Add(item);
|
|
}
|
|
else
|
|
{
|
|
m_log.WarnFormat("Failed to create item {0}", item.Name);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
for (int i = 0; i < bodyparts.Length; i++)
|
|
{
|
|
UUID assetID = UUID.Random();
|
|
AssetBodypart asset = new AssetBodypart(assetID, File.ReadAllBytes(bodyparts[i]));
|
|
asset.Decode();
|
|
asset.Owner = Client.Self.AgentID;
|
|
asset.WearableType = GetWearableType(bodyparts[i]);
|
|
asset.Encode();
|
|
transid = Client.Assets.RequestUpload(asset,true);
|
|
Client.Inventory.RequestCreateItem(clothfolder.UUID, "MyBodyPart" + i.ToString(), "MyBodyPart", AssetType.Bodypart,
|
|
transid, InventoryType.Wearable, asset.WearableType, (OpenMetaverse.PermissionMask)PermissionMask.All, delegate(bool success, InventoryItem item)
|
|
{
|
|
if (success)
|
|
{
|
|
listwearables.Add(item);
|
|
}
|
|
else
|
|
{
|
|
m_log.WarnFormat("Failed to create item {0}", item.Name);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
Thread.Sleep(1000);
|
|
|
|
if (listwearables == null || listwearables.Count == 0)
|
|
{
|
|
m_log.DebugFormat("Nothing to send on this folder!");
|
|
}
|
|
else
|
|
{
|
|
m_log.DebugFormat("Sending {0} wearables...", listwearables.Count);
|
|
Client.Appearance.WearOutfit(listwearables, false);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine(ex.ToString());
|
|
}
|
|
}
|
|
|
|
public InventoryFolder FindClothingFolder()
|
|
{
|
|
UUID rootfolder = Client.Inventory.Store.RootFolder.UUID;
|
|
List<InventoryBase> listfolders = Client.Inventory.Store.GetContents(rootfolder);
|
|
InventoryFolder clothfolder = new InventoryFolder(UUID.Random());
|
|
foreach (InventoryBase folder in listfolders)
|
|
{
|
|
if (folder.Name == "Clothing")
|
|
{
|
|
clothfolder = (InventoryFolder)folder;
|
|
break;
|
|
}
|
|
}
|
|
return clothfolder;
|
|
}
|
|
|
|
public void Network_LoginProgress(object sender, LoginProgressEventArgs args)
|
|
{
|
|
m_log.DebugFormat("[BOT]: Bot {0} {1} in Network_LoginProcess", Name, args.Status);
|
|
|
|
if (args.Status == LoginStatus.Success)
|
|
{
|
|
if (OnConnected != null)
|
|
{
|
|
OnConnected(this, EventType.CONNECTED);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Network_SimConnected(object sender, SimConnectedEventArgs args)
|
|
{
|
|
m_log.DebugFormat(
|
|
"[BOT]: Bot {0} connected to region {1} at {2}", Name, args.Simulator.Name, args.Simulator.IPEndPoint);
|
|
}
|
|
|
|
public void Network_SimDisconnected(object sender, SimDisconnectedEventArgs args)
|
|
{
|
|
m_log.DebugFormat(
|
|
"[BOT]: Bot {0} disconnected from region {1} at {2}", Name, args.Simulator.Name, args.Simulator.IPEndPoint);
|
|
}
|
|
|
|
public void Network_OnDisconnected(object sender, DisconnectedEventArgs args)
|
|
{
|
|
ConnectionState = ConnectionState.Disconnected;
|
|
|
|
m_log.DebugFormat(
|
|
"[BOT]: Bot {0} disconnected from grid, reason {1}, message {2}", Name, args.Reason, args.Message);
|
|
|
|
// m_log.ErrorFormat("Fired Network_OnDisconnected");
|
|
|
|
// if (
|
|
// (args.Reason == NetworkManager.DisconnectType.SimShutdown
|
|
// || args.Reason == NetworkManager.DisconnectType.NetworkTimeout)
|
|
// && OnDisconnected != null)
|
|
|
|
|
|
|
|
if (
|
|
(args.Reason == NetworkManager.DisconnectType.ClientInitiated
|
|
|| args.Reason == NetworkManager.DisconnectType.ServerInitiated
|
|
|| args.Reason == NetworkManager.DisconnectType.NetworkTimeout)
|
|
&& OnDisconnected != null)
|
|
// if (OnDisconnected != null)
|
|
{
|
|
OnDisconnected(this, EventType.DISCONNECTED);
|
|
}
|
|
}
|
|
|
|
public void Objects_NewPrim(object sender, PrimEventArgs args)
|
|
{
|
|
if (!RequestObjectTextures)
|
|
return;
|
|
|
|
Primitive prim = args.Prim;
|
|
|
|
if (prim != null)
|
|
{
|
|
lock (m_objects)
|
|
m_objects[prim.ID] = prim;
|
|
|
|
if (prim.Textures != null)
|
|
{
|
|
if (prim.Textures.DefaultTexture.TextureID != UUID.Zero)
|
|
{
|
|
GetTextureOrMesh(prim.Textures.DefaultTexture.TextureID, true);
|
|
}
|
|
|
|
for (int i = 0; i < prim.Textures.FaceTextures.Length; i++)
|
|
{
|
|
Primitive.TextureEntryFace face = prim.Textures.FaceTextures[i];
|
|
|
|
if (face != null)
|
|
{
|
|
UUID textureID = prim.Textures.FaceTextures[i].TextureID;
|
|
|
|
if (textureID != UUID.Zero)
|
|
GetTextureOrMesh(textureID, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (prim.Sculpt != null && prim.Sculpt.SculptTexture != UUID.Zero)
|
|
{
|
|
bool mesh = (prim.Sculpt.Type == SculptType.Mesh);
|
|
GetTextureOrMesh(prim.Sculpt.SculptTexture, !mesh);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void GetTextureOrMesh(UUID assetID, bool texture)
|
|
{
|
|
lock (Manager.AssetsReceived)
|
|
{
|
|
// Don't request assets more than once.
|
|
if (Manager.AssetsReceived.ContainsKey(assetID))
|
|
return;
|
|
|
|
Manager.AssetsReceived[assetID] = false;
|
|
}
|
|
|
|
try
|
|
{
|
|
if (texture)
|
|
Client.Assets.RequestImage(assetID, ImageType.Normal, Asset_TextureCallback_Texture);
|
|
else
|
|
Client.Assets.RequestMesh(assetID, Asset_MeshCallback);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
m_log.Warn(string.Format("Error requesting {0} {1}", texture ? "texture" : "mesh", assetID), e);
|
|
}
|
|
}
|
|
|
|
public void Asset_TextureCallback_Texture(TextureRequestState state, AssetTexture assetTexture)
|
|
{
|
|
if (state == TextureRequestState.Finished)
|
|
{
|
|
lock (Manager.AssetsReceived)
|
|
Manager.AssetsReceived[assetTexture.AssetID] = true;
|
|
}
|
|
}
|
|
|
|
private void Asset_MeshCallback(bool success, AssetMesh assetMesh)
|
|
{
|
|
lock (Manager.AssetsReceived)
|
|
Manager.AssetsReceived[assetMesh.AssetID] = success;
|
|
}
|
|
|
|
public void Asset_ReceivedCallback(AssetDownload transfer, Asset asset)
|
|
{
|
|
lock (Manager.AssetsReceived)
|
|
Manager.AssetsReceived[asset.AssetID] = true;
|
|
|
|
// if (wear == "save")
|
|
// {
|
|
// SaveAsset((AssetWearable) asset);
|
|
// }
|
|
}
|
|
|
|
private void PacketReceivedDebugHandler(object o, PacketReceivedEventArgs args)
|
|
{
|
|
Packet p = args.Packet;
|
|
Header h = p.Header;
|
|
Simulator s = args.Simulator;
|
|
|
|
m_log.DebugFormat(
|
|
"[BOT]: Bot {0} received from {1} packet {2} #{3}, rel {4}, res {5}",
|
|
Name, s.Name, p.Type, h.Sequence, h.Reliable, h.Resent);
|
|
}
|
|
}
|
|
}
|